Skip to content

Commit 1247d6a

Browse files
committed
Add context to AI Chat
Made AI Chat aware of user's code and question
1 parent 2736aee commit 1247d6a

File tree

4 files changed

+94
-27
lines changed

4 files changed

+94
-27
lines changed

frontend/components/collab/chat.tsx

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { io, Socket } from "socket.io-client";
1111
import { useAuth } from "@/app/auth/auth-context";
1212
import LoadingScreen from "@/components/common/loading-screen";
1313
import { sendAiMessage } from "@/lib/api/openai/send-ai-message";
14+
import { Question } from "@/lib/schemas/question-schema";
1415

1516
export interface Message {
1617
id: string;
@@ -19,7 +20,15 @@ export interface Message {
1920
timestamp: Date;
2021
}
2122

22-
export default function Chat({ roomId }: { roomId: string }) {
23+
export default function Chat({
24+
roomId,
25+
question,
26+
code,
27+
}: {
28+
roomId: string;
29+
question: Question | null;
30+
code: string;
31+
}) {
2332
const auth = useAuth();
2433
const own_user_id = auth?.user?.id;
2534
const [socket, setSocket] = useState<Socket | null>(null);
@@ -30,6 +39,31 @@ export default function Chat({ roomId }: { roomId: string }) {
3039
const [isConnected, setIsConnected] = useState(false);
3140
const lastMessageRef = useRef<HTMLDivElement | null>(null);
3241

42+
useEffect(() => {
43+
const greeting =
44+
"Hello! I am your AI assistant! You can ask me for help with the question or any other programming related queries.";
45+
const greetingMessage = {
46+
id: crypto.randomUUID(),
47+
userId: "assistant",
48+
text: greeting,
49+
timestamp: new Date(),
50+
};
51+
setAiMessages((prev) => [...prev, greetingMessage]);
52+
}, []);
53+
54+
useEffect(() => {
55+
if (question) {
56+
const context = `${question.title}: ${question.description}. Your job is to assist a student who is solving this problem. Provide hints and guide them through the problem solving process if they ask for it. Do not answer irrelevant questions, try to keep the student focussed on the task.`;
57+
const systemMessage = {
58+
id: crypto.randomUUID(),
59+
userId: "system",
60+
text: context,
61+
timestamp: new Date(),
62+
};
63+
setAiMessages((prev) => [...prev, systemMessage]);
64+
}
65+
}, [question]);
66+
3367
useEffect(() => {
3468
if (!auth?.user?.id) return; // Avoid connecting if user is not authenticated
3569

@@ -93,14 +127,23 @@ export default function Chat({ roomId }: { roomId: string }) {
93127
} else {
94128
setAiMessages((prev) => [...prev, message]);
95129
setNewMessage("");
96-
const response = await sendAiMessage(aiMessages.concat(message));
130+
const attachedCode = {
131+
id: crypto.randomUUID(),
132+
userId: "system",
133+
text: `This is the student's current code now: ${code}. Take note of any changes and be prepared to explain, correct or fix any issues in the code if the student asks.`,
134+
timestamp: new Date(),
135+
};
136+
const response = await sendAiMessage(
137+
aiMessages.concat(attachedCode).concat(message)
138+
);
97139
const data = await response.json();
98140
const aiMessage = {
99141
id: crypto.randomUUID(),
100-
userId: "ai",
142+
userId: "assistant",
101143
text: data.data ? data.data : "An error occurred. Please try again.",
102144
timestamp: new Date(),
103145
};
146+
setAiMessages((prev) => [...prev, attachedCode]);
104147
setAiMessages((prev) => [...prev, aiMessage]);
105148
}
106149

@@ -114,23 +157,33 @@ export default function Chat({ roomId }: { roomId: string }) {
114157
});
115158
};
116159

117-
const renderMessage = (message: Message, isOwnMessage: boolean) => (
118-
<div
119-
key={message.id}
120-
className={`p-2 rounded-lg mb-2 max-w-[80%] ${
121-
isOwnMessage
122-
? "ml-auto bg-blue-500 text-white"
123-
: "bg-gray-100 dark:bg-gray-800"
124-
}`}
125-
>
126-
<div className="text-sm">{message.text}</div>
127-
<div
128-
className={`text-xs ${isOwnMessage ? "text-blue-100" : "text-gray-500"}`}
129-
>
130-
{formatTimestamp(message.timestamp)}
131-
</div>
132-
</div>
133-
);
160+
const renderMessage = (
161+
message: Message,
162+
isOwnMessage: boolean,
163+
isSystem: boolean
164+
) => {
165+
if (isSystem) {
166+
return null;
167+
} else {
168+
return (
169+
<div
170+
key={message.id}
171+
className={`p-2 rounded-lg mb-2 max-w-[80%] ${
172+
isOwnMessage
173+
? "ml-auto bg-blue-500 text-white"
174+
: "bg-gray-100 dark:bg-gray-800"
175+
}`}
176+
>
177+
<div className="text-sm">{message.text}</div>
178+
<div
179+
className={`text-xs ${isOwnMessage ? "text-blue-100" : "text-gray-500"}`}
180+
>
181+
{formatTimestamp(message.timestamp)}
182+
</div>
183+
</div>
184+
);
185+
}
186+
};
134187

135188
if (!own_user_id) {
136189
return <LoadingScreen />;
@@ -160,7 +213,7 @@ export default function Chat({ roomId }: { roomId: string }) {
160213
<ScrollArea className="h-[calc(70vh-280px)]">
161214
<div className="pr-4 space-y-2">
162215
{partnerMessages.map((msg) =>
163-
renderMessage(msg, msg.userId === own_user_id)
216+
renderMessage(msg, msg.userId === own_user_id, false)
164217
)}
165218
<div ref={lastMessageRef} />
166219
</div>
@@ -170,7 +223,11 @@ export default function Chat({ roomId }: { roomId: string }) {
170223
<ScrollArea className="h-[calc(70vh-280px)]">
171224
<div className="pr-4 space-y-2">
172225
{aiMessages.map((msg) =>
173-
renderMessage(msg, msg.userId === own_user_id)
226+
renderMessage(
227+
msg,
228+
msg.userId === own_user_id,
229+
msg.userId === "system"
230+
)
174231
)}
175232
<div ref={lastMessageRef} />
176233
</div>

frontend/components/collab/code-editor.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,13 @@ const languages: Record<string, LanguageEntry> = {
4040
},
4141
};
4242

43-
export default function CodeEditor({ roomId }: { roomId: string }) {
43+
export default function CodeEditor({
44+
roomId,
45+
setCode,
46+
}: {
47+
roomId: string;
48+
setCode: (value: string) => void;
49+
}) {
4450
const monaco = useMonaco();
4551
const [language, setLanguage] = useState<string>("Javascript");
4652
const [theme, setTheme] = useState<string>("light");
@@ -139,6 +145,9 @@ export default function CodeEditor({ roomId }: { roomId: string }) {
139145
onMount={(editor) => {
140146
setEditor(editor);
141147
}}
148+
onChange={(value) => {
149+
setCode(value);
150+
}}
142151
theme={theme === "dark" ? "vs-dark" : "light"}
143152
/>
144153
</div>

frontend/components/collab/collab-room.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default function CollabRoom({ roomId }: { roomId: string }) {
1818

1919
const [question, setQuestion] = useState<Question | null>(null);
2020
const [loading, setLoading] = useState(true);
21+
const [code, setCode] = useState<string>("");
2122

2223
useEffect(() => {
2324
async function fetchQuestion() {
@@ -60,11 +61,11 @@ export default function CollabRoom({ roomId }: { roomId: string }) {
6061
{loading ? (
6162
<LoadingScreen />
6263
) : (
63-
<QuestionDisplay question={question} />
64+
<QuestionDisplay question={question}/>
6465
)}
65-
<Chat roomId={roomId} />
66+
<Chat roomId={roomId} question={question} code={code}/>
6667
</div>
67-
<CodeEditor roomId={roomId} />
68+
<CodeEditor roomId={roomId} setCode={setCode}/>
6869
</div>
6970
</div>
7071
);

frontend/lib/api/openai/send-ai-message.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Message } from "@/components/collab/chat";
33

44
export const sendAiMessage = async (messages: Message[]) => {
55
const apiMessages = messages.map((msg) => ({
6-
role: `${msg.userId === "ai" ? "assistant" : "user"}`,
6+
role: `${(msg.userId === "assistant" || msg.userId === "system") ? msg.userId : "user"}`,
77
content: msg.text,
88
}));
99
const response = await fetch(

0 commit comments

Comments
 (0)