Skip to content

Commit 9e95a7c

Browse files
committed
feat(ui): integrate Helpmate-AI chatbot with improved UX
This commit improves the integration of the Helpmate-AI chatbot into the CoderAI application with several key enhancements: - fix(launch): prevent multiple browser windows by adding --server.headless=true flag to Streamlit - feat(ui): implement popup chatbot interface accessible from dashboard and chat tab - fix(ui): remove success notification message for Helpmate-AI initialization - refactor(ui): simplify chatbot implementation using Streamlit session state - fix(ui): implement reliable close button using page refresh - style(ui): improve chatbot popup styling with header bar and proper dimensions - perf(ui): remove complex JavaScript that caused TypeError with html() component The chatbot now appears as a popup window when triggered by buttons in the UI rather than opening in a separate browser window, providing a more seamless user experience.
1 parent 6decc8f commit 9e95a7c

File tree

544 files changed

+79096
-145
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

544 files changed

+79096
-145
lines changed

Helpmate-AI/package-lock.json

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Helpmate-AI/src/App.jsx

Lines changed: 90 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import axios from "axios";
44
import ReactMarkdown from "react-markdown";
55
import Footer from "./Footer";
66
import ShareButtons from "./components/ShareButtons";
7+
import CodeAnalysis from "./components/CodeAnalysis";
78
import { FaMicrophone, FaPaperPlane, FaVolumeUp } from "react-icons/fa";
89

910
const cache = new Map();
@@ -15,8 +16,13 @@ function App() {
1516
const [isListening, setIsListening] = useState(false);
1617
const [recognition, setRecognition] = useState(null);
1718
const [isSpeaking, setIsSpeaking] = useState(false);
19+
const [mode, setMode] = useState("chat"); // "chat" or "code"
20+
const [isEmbedded, setIsEmbedded] = useState(false);
1821

1922
useEffect(() => {
23+
// Check if running in an iframe
24+
setIsEmbedded(window.self !== window.top);
25+
2026
if ("webkitSpeechRecognition" in window) {
2127
const recognition = new window.webkitSpeechRecognition();
2228
recognition.continuous = false;
@@ -149,71 +155,95 @@ function App() {
149155
}
150156

151157
return (
152-
<div className="flex flex-col min-h-screen bg-gray-950 text-white">
153-
<nav className="p-4 bg-[#040E23]">
154-
<h1 className="text-2xl font-bold text-center">Helpmate AI</h1>
155-
</nav>
156-
<div className="flex-grow p-4">
157-
<div className="chat-display space-y-4">
158-
{chatHistory.map((chat, index) => (
159-
<div
160-
key={index}
161-
className={`p-3 rounded-lg ${
162-
chat.type === "question"
163-
? "bg-blue-600 text-white self-end text-right w-fit max-w-[90%] ml-auto"
164-
: "bg-gray-800 text-white self-start text-left w-fit max-w-[90%]"
165-
}`}
158+
<div className={`flex flex-col ${isEmbedded ? 'h-screen' : 'min-h-screen'} bg-gray-950 text-white`}>
159+
<nav className="p-2 bg-[#040E23]">
160+
<div className="flex justify-between items-center max-w-4xl mx-auto">
161+
<h1 className="text-xl font-bold">Helpmate AI</h1>
162+
<div className="flex gap-2">
163+
<button
164+
onClick={() => setMode("chat")}
165+
className={`px-3 py-1 rounded-lg ${mode === "chat" ? "bg-blue-600" : "bg-gray-700"} text-white transition-colors text-sm`}
166166
>
167-
<ReactMarkdown className="markdown-body">{chat.text}</ReactMarkdown>
168-
{chat.type === "answer" && (
169-
<div className="flex flex-wrap justify-end mt-2 space-x-2">
170-
<button onClick={() => toggleSpeaking(chat.text)} className="flex items-center text-gray-300 mt-2 mr-2">
171-
<FaVolumeUp className="mr-1" />
172-
</button>
173-
<ShareButtons answer={chat.text} />
174-
</div>
175-
)}
176-
</div>
177-
))}
178-
{generatingAnswer && (
179-
<div className="p-3 rounded-lg bg-gray-900 animate-pulse">
180-
<div className="h-4 bg-gray-700 rounded w-3/4 mb-2"></div>
181-
<div className="h-4 bg-gray-700 rounded w-2/3 mb-2"></div>
182-
<div className="h-4 bg-gray-700 rounded w-1/2"></div>
183-
</div>
184-
)}
185-
</div>
186-
</div>
187-
<form onSubmit={generateAnswer} className="flex items-center w-full bg-gray-900 p-3">
188-
<textarea
189-
required
190-
className="border border-gray-800 bg-gray-800 text-white rounded-lg w-full p-2 h-12 resize-none focus:border-blue-500 outline-none"
191-
value={question}
192-
onChange={(e) => setQuestion(e.target.value)}
193-
placeholder="Your AI mate is here to help!"
194-
/>
195-
<div className="flex items-center space-x-2 ml-4">
196-
{recognition && (
167+
Chat
168+
</button>
197169
<button
198-
type="button"
199-
onClick={toggleListening}
200-
className={`p-2 rounded-full transition-transform duration-300 ease-in-out ${
201-
isListening ? "bg-red-500" : "bg-blue-500"
202-
} hover:opacity-80`}
170+
onClick={() => setMode("code")}
171+
className={`px-3 py-1 rounded-lg ${mode === "code" ? "bg-blue-600" : "bg-gray-700"} text-white transition-colors text-sm`}
203172
>
204-
<FaMicrophone className="text-white" />
173+
Code Analysis
205174
</button>
206-
)}
207-
<button
208-
type="submit"
209-
className="p-2 rounded-full bg-blue-600 hover:bg-blue-700"
210-
disabled={generatingAnswer}
211-
>
212-
<FaPaperPlane className={`text-white ${generatingAnswer ? "send-animation" : ""}`} />
213-
</button>
175+
</div>
176+
</div>
177+
</nav>
178+
<div className="flex-grow p-2">
179+
{mode === "chat" ? (
180+
<div className="chat-display space-y-2">
181+
{chatHistory.map((chat, index) => (
182+
<div
183+
key={index}
184+
className={`p-2 rounded-lg ${
185+
chat.type === "question"
186+
? "bg-blue-600 text-white self-end text-right w-fit max-w-[90%] ml-auto"
187+
: "bg-gray-800 text-white self-start text-left w-fit max-w-[90%]"
188+
}`}
189+
>
190+
<ReactMarkdown className="markdown-body">{chat.text}</ReactMarkdown>
191+
{chat.type === "answer" && (
192+
<div className="flex flex-wrap justify-end mt-1 space-x-1">
193+
<button onClick={() => toggleSpeaking(chat.text)} className="flex items-center text-gray-300 mt-1 mr-1">
194+
<FaVolumeUp className="mr-1" />
195+
</button>
196+
<ShareButtons answer={chat.text} />
197+
</div>
198+
)}
199+
</div>
200+
))}
201+
{generatingAnswer && (
202+
<div className="p-2 rounded-lg bg-gray-900 animate-pulse">
203+
<div className="h-3 bg-gray-700 rounded w-3/4 mb-1"></div>
204+
<div className="h-3 bg-gray-700 rounded w-2/3 mb-1"></div>
205+
<div className="h-3 bg-gray-700 rounded w-1/2"></div>
206+
</div>
207+
)}
208+
</div>
209+
) : (
210+
<CodeAnalysis />
211+
)}
212+
</div>
213+
{mode === "chat" && (
214+
<div>
215+
<form onSubmit={generateAnswer} className="flex items-center w-full bg-gray-900 p-2">
216+
<textarea
217+
required
218+
className="border border-gray-800 bg-gray-800 text-white rounded-lg w-full p-1 h-10 resize-none focus:border-blue-500 outline-none"
219+
value={question}
220+
onChange={(e) => setQuestion(e.target.value)}
221+
placeholder="Your AI mate is here to help!"
222+
/>
223+
<div className="flex items-center space-x-1 ml-2">
224+
{recognition && (
225+
<button
226+
type="button"
227+
onClick={toggleListening}
228+
className={`p-1 rounded-full transition-transform duration-300 ease-in-out ${
229+
isListening ? "bg-red-500" : "bg-blue-500"
230+
} hover:opacity-80`}
231+
>
232+
<FaMicrophone className="text-white" />
233+
</button>
234+
)}
235+
<button
236+
type="submit"
237+
className="p-1 rounded-full bg-blue-600 hover:bg-blue-700"
238+
disabled={generatingAnswer}
239+
>
240+
<FaPaperPlane className={`text-white ${generatingAnswer ? "send-animation" : ""}`} />
241+
</button>
242+
</div>
243+
</form>
244+
<Footer />
214245
</div>
215-
</form>
216-
<Footer />
246+
)}
217247
</div>
218248
);
219249
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { useState } from 'react';
2+
import coderAIService from '../services/coderAIService';
3+
import ReactMarkdown from 'react-markdown';
4+
5+
const CodeAnalysis = () => {
6+
const [code, setCode] = useState('');
7+
const [analysis, setAnalysis] = useState(null);
8+
const [loading, setLoading] = useState(false);
9+
const [error, setError] = useState(null);
10+
11+
const handleAnalyze = async () => {
12+
if (!code.trim()) return;
13+
14+
setLoading(true);
15+
setError(null);
16+
17+
try {
18+
const result = await coderAIService.analyzeCode(code);
19+
setAnalysis(result);
20+
} catch (err) {
21+
setError('Failed to analyze code. Please try again.');
22+
console.error('Analysis error:', err);
23+
} finally {
24+
setLoading(false);
25+
}
26+
};
27+
28+
return (
29+
<div className="w-full max-w-4xl mx-auto p-4">
30+
<h2 className="text-2xl font-bold mb-4 text-white">Code Analysis</h2>
31+
<div className="mb-4">
32+
<textarea
33+
className="w-full h-48 p-3 bg-gray-800 text-white rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
34+
value={code}
35+
onChange={(e) => setCode(e.target.value)}
36+
placeholder="Paste your code here..."
37+
/>
38+
</div>
39+
<button
40+
onClick={handleAnalyze}
41+
disabled={loading}
42+
className={`px-4 py-2 rounded-lg ${loading ? 'bg-gray-600' : 'bg-blue-600 hover:bg-blue-700'} text-white font-medium transition-colors`}
43+
>
44+
{loading ? 'Analyzing...' : 'Analyze Code'}
45+
</button>
46+
47+
{error && (
48+
<div className="mt-4 p-3 bg-red-500 bg-opacity-20 border border-red-500 rounded-lg text-red-500">
49+
{error}
50+
</div>
51+
)}
52+
53+
{analysis && (
54+
<div className="mt-6 p-4 bg-gray-800 rounded-lg">
55+
<h3 className="text-xl font-semibold mb-3 text-white">Analysis Results</h3>
56+
<div className="prose prose-invert">
57+
<ReactMarkdown>{analysis.result}</ReactMarkdown>
58+
</div>
59+
</div>
60+
)}
61+
</div>
62+
);
63+
};
64+
65+
export default CodeAnalysis;
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import axios from 'axios';
2+
3+
const CODER_AI_BASE_URL = 'http://localhost:5000';
4+
5+
class CoderAIService {
6+
constructor() {
7+
this.client = axios.create({
8+
baseURL: CODER_AI_BASE_URL,
9+
headers: {
10+
'Content-Type': 'application/json',
11+
},
12+
});
13+
}
14+
15+
async analyzeCode(code) {
16+
try {
17+
const response = await this.client.post('/analyze', { code });
18+
return response.data;
19+
} catch (error) {
20+
console.error('Error analyzing code:', error);
21+
throw error;
22+
}
23+
}
24+
25+
async getProjectSuggestions() {
26+
try {
27+
const response = await this.client.get('/suggestions');
28+
return response.data;
29+
} catch (error) {
30+
console.error('Error getting project suggestions:', error);
31+
throw error;
32+
}
33+
}
34+
35+
async reviewCode(codeSnippet) {
36+
try {
37+
const response = await this.client.post('/review', { code: codeSnippet });
38+
return response.data;
39+
} catch (error) {
40+
console.error('Error reviewing code:', error);
41+
throw error;
42+
}
43+
}
44+
45+
async getGitHubIntegration() {
46+
try {
47+
const response = await this.client.get('/github/status');
48+
return response.data;
49+
} catch (error) {
50+
console.error('Error getting GitHub integration status:', error);
51+
throw error;
52+
}
53+
}
54+
}
55+
56+
export default new CoderAIService();

0 commit comments

Comments
 (0)