Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
"axios": "^1.9.0",
"code-editor": "file:",
"framer-motion": "^12.12.2",
"groq-sdk": "^0.37.0",
"install": "^0.13.0",
"npm": "^11.4.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-icons": "^5.5.0"
"react-icons": "^5.5.0",
"react-markdown": "^10.1.0",
"react-syntax-highlighter": "^16.1.0"
},
"devDependencies": {
"@eslint/js": "^9.21.0",
Expand Down
40 changes: 40 additions & 0 deletions src/components/ChatBot/ChatBubble.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// src/components/ChatBot/ChatBubble.jsx
import React from "react";
import ReactMarkdown from "react-markdown";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { materialDark } from "react-syntax-highlighter/dist/esm/styles/prism";

export default function ChatBubble({ message }) {
return (
<div
className={`chat-bubble ${message.role} break-words`}
style={{ marginBottom: "12px" }}
>
<ReactMarkdown
components={{
code({ node, inline, className, children, ...props }) {
return !inline ? (
<SyntaxHighlighter
style={materialDark}
language={className?.replace("language-", "") || "javascript"}
{...props}
>
{children}
</SyntaxHighlighter>
) : (
<code
className="inline-code"
style={{ backgroundColor: "#2b2b3b", padding: "2px 4px", borderRadius: "4px" }}
{...props}
>
{children}
</code>
);
},
}}
>
{message.content}
</ReactMarkdown>
</div>
);
}
32 changes: 32 additions & 0 deletions src/components/ChatBot/ChatInput.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// src/components/ChatBot/ChatInput.jsx
import React, { useState } from "react";

export default function ChatInput({ onSend }) {
const [text, setText] = useState("");

const handleSend = () => {
if (text.trim()) {
onSend(text);
setText("");
}
};

const handleKeyDown = (e) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
handleSend();
}
};

return (
<div className="chat-input">
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="Ask CodeMate..."
/>
<button onClick={handleSend}>Send</button>
</div>
);
}
124 changes: 124 additions & 0 deletions src/components/ChatBot/CodeMate.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import React, { useState } from "react";
import ChatBubble from "./ChatBubble";
import ChatInput from "./ChatInput";
import { askCodeMate } from "./chatApi";
import "./chatbot.css";

const LANGUAGES = ["javascript", "python", "cpp", "java"]; // add more if needed

export default function CodeMate() {
const [open, setOpen] = useState(false);
const [fullScreen, setFullScreen] = useState(false);
const [selectedLang, setSelectedLang] = useState("javascript");

const [messages, setMessages] = useState([
{
role: "system",
content: `
You are CodeMate, an AI coding assistant inside an online compiler.

Strict rules:
1. Always provide **three approaches** for every logic question:
1. Brute Force
2. Better Approach
3. Optimal Approach
2. Always explain **time and space complexity** for each approach.
3. Always write code in the **programming language selected by the user** (use the variable "selectedLang").
4. Respond in simple, beginner-friendly language.
5. Use Markdown formatting with numbered lists and code blocks.

Example:
1. Brute Force
\`\`\`${selectedLang}
// code here
\`\`\`
Time Complexity: O(...)
Space Complexity: O(...)

2. Better Approach
\`\`\`${selectedLang}
// code here
\`\`\`
Time Complexity: O(...)
Space Complexity: O(...)

3. Optimal Approach
\`\`\`${selectedLang}
// code here
\`\`\`
Time Complexity: O(...)
Space Complexity: O(...)
`
},
{
role: "assistant",
content: "Hi 👋 I'm CodeMate. Ask me about logic, optimization, or errors."
}
]);

const sendMessage = async (text) => {
if (!text.trim()) return;

const userMsg = { role: "user", content: text };
const updated = [...messages, userMsg];
setMessages(updated);

try {
// Always pass the language to the prompt
const reply = await askCodeMate([
...updated,
{ role: "system", content: `Use ${selectedLang} for all code.` }
]);

setMessages((prev) => [...prev, { role: "assistant", content: reply }]);
} catch (err) {
setMessages((prev) => [
...prev,
{ role: "assistant", content: "⚠️ Error connecting to Groq API." },
]);
}
};

return (
<>
<button className="chat-toggle" onClick={() => setOpen(!open)}>
💬
</button>

{open && (
<div className={`chat-container ${fullScreen ? "fullscreen" : ""}`}>
<div className="chat-header">
<span>CodeMate AI</span>
<div className="chat-header-buttons">
<select
value={selectedLang}
onChange={(e) => setSelectedLang(e.target.value)}
className="language-select"
>
{LANGUAGES.map((lang) => (
<option key={lang} value={lang}>
{lang.toUpperCase()}
</option>
))}
</select>
<button onClick={() => setFullScreen(!fullScreen)}>
{fullScreen ? "🗗" : "🗖"}
</button>
<button onClick={() => setOpen(false)}>✖</button>
</div>
</div>

<div className="chat-body">
{messages
.filter((m) => m.role !== "system")
.map((msg, i) => (
<ChatBubble key={i} message={msg} />
))}
</div>

<ChatInput onSend={sendMessage} />
</div>
)}
</>
);
}
28 changes: 28 additions & 0 deletions src/components/ChatBot/chatApi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// src/components/ChatBot/chatApi.js
import Groq from "groq-sdk";

// Initialize Groq with your API key
const groq = new Groq({
apiKey: import.meta.env.VITE_GROQ_API_KEY,
dangerouslyAllowBrowser: true, // required to call from frontend
});

// Set your model
const MODEL_NAME = "llama-3.3-70b-versatile";

// Function to send messages to Groq
export async function askCodeMate(messages) {
try {
const chat = await groq.chat.completions.create({
model: MODEL_NAME,
messages: messages,
temperature: 0.3, // Adjust creativity
});

// Return the assistant's reply
return chat.choices[0].message.content;
} catch (err) {
console.error("Groq API Error:", err);
throw new Error("Error connecting to Groq API.");
}
}
Loading