Skip to content

Commit 93ea113

Browse files
committed
keep chat history
1 parent 51756e2 commit 93ea113

File tree

3 files changed

+112
-11
lines changed

3 files changed

+112
-11
lines changed

backend/collaboration/src/service/post/openai-service.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,16 @@ interface OpenAIRequest {
2222
const createSystemMessage = (editorCode?: string, language?: string, questionDetails?: string) => {
2323
return {
2424
role: 'system' as const,
25-
content: `You are a helpful coding assistant.
25+
content: `You are a mentor in a coding interview.
2626
You are helping a user with a coding problem.
2727
${questionDetails ? `\nQuestion Context:\n${JSON.stringify(questionDetails, null, 2)}` : ''}
28-
${editorCode ? `\nCurrent Code (${language || 'unknown'}):\n${editorCode}` : ''}
29-
Provide detailed help while referring to their specific code and question context when available.`,
28+
29+
${editorCode ? `\nCurrent Code in the Editor written by the user in language: (${language || 'unknown'}):\n${editorCode}` : ''}
30+
31+
32+
If they do not ask for questions related to their code or the question context, you can provide general coding advice anyways. Be very concise and conversational in your responses.
33+
34+
Your response should only be max 4-5 sentences. Do NOT provide code in your answers, but instead try to guide them and give tips for how to solve it. YOU MUST NOT SOLVE THE PROBLEM FOR THEM, OR WRITE ANY CODE. Guide the user towards the solution, don't just give the solution. MAX 4-5 SENTENCES. Ask questions instead of giving answers. Be conversational and friendly.`,
3035
};
3136
};
3237

@@ -36,8 +41,16 @@ export async function getOpenAIResponse(request: OpenAIRequest) {
3641

3742
try {
3843
const response = await openai.chat.completions.create({
39-
model: 'gpt-3.5-turbo',
40-
messages: [createSystemMessage(editorCode, language, questionDetails), ...messages],
44+
model: 'gpt-4o',
45+
messages: [
46+
createSystemMessage(editorCode, language, questionDetails),
47+
...messages,
48+
{
49+
role: 'assistant',
50+
content:
51+
'<This is an internal reminder to the assistant to not provide code solutions, but to guide the user towards the solution. Max 4-5 sentences responses please.>',
52+
},
53+
],
4154
});
4255

4356
if (response.choices && response.choices[0].message) {
@@ -60,7 +73,7 @@ export async function getOpenAIStreamResponse(request: OpenAIRequest): Promise<E
6073

6174
try {
6275
const response = await openai.chat.completions.create({
63-
model: 'gpt-3.5-turbo',
76+
model: 'gpt-4o',
6477
messages: [createSystemMessage(editorCode, language, questionDetails), ...messages],
6578
stream: true,
6679
});

frontend/src/components/blocks/interview/ai-chat.tsx

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { type LanguageName } from '@uiw/codemirror-extensions-langs';
2-
import React, { useRef,useState } from 'react';
2+
import React, { useEffect,useRef, useState } from 'react';
33

44
import { sendChatMessage } from '@/services/collab-service';
55

@@ -14,6 +14,13 @@ interface AIChatProps {
1414
questionDetails?: string;
1515
}
1616

17+
const STORAGE_KEY = 'ai_chat_history';
18+
19+
interface StoredChat {
20+
messages: ChatMessageType[];
21+
questionDetails: string;
22+
}
23+
1724
export const AIChat: React.FC<AIChatProps> = ({
1825
isOpen,
1926
onClose,
@@ -25,6 +32,50 @@ export const AIChat: React.FC<AIChatProps> = ({
2532
const [isLoading, setIsLoading] = useState<boolean>(false);
2633
const [error, setError] = useState<string | null>(null);
2734
const streamingTextRef = useRef<string>('');
35+
const prevQuestionRef = useRef<string>(questionDetails);
36+
37+
useEffect(() => {
38+
const loadMessages = () => {
39+
const stored = localStorage.getItem(STORAGE_KEY);
40+
41+
if (stored) {
42+
const { messages: storedMessages, questionDetails: storedQuestion } = JSON.parse(
43+
stored
44+
) as StoredChat;
45+
46+
// If question has changed, clear the history
47+
if (storedQuestion !== questionDetails) {
48+
localStorage.removeItem(STORAGE_KEY);
49+
setMessages([]);
50+
} else {
51+
// Convert stored timestamps back to Date objects
52+
const messagesWithDates = storedMessages.map((msg) => ({
53+
...msg,
54+
timestamp: new Date(msg.timestamp),
55+
}));
56+
setMessages(messagesWithDates);
57+
}
58+
}
59+
};
60+
61+
loadMessages();
62+
prevQuestionRef.current = questionDetails;
63+
}, [questionDetails]);
64+
65+
const handleClearHistory = () => {
66+
localStorage.removeItem(STORAGE_KEY);
67+
setMessages([]);
68+
};
69+
70+
useEffect(() => {
71+
if (messages.length > 0) {
72+
const dataToStore: StoredChat = {
73+
messages,
74+
questionDetails,
75+
};
76+
localStorage.setItem(STORAGE_KEY, JSON.stringify(dataToStore));
77+
}
78+
}, [messages, questionDetails]);
2879

2980
const handleSend = async (userMessage: string): Promise<void> => {
3081
if (!userMessage.trim() || isLoading) return;
@@ -119,6 +170,7 @@ export const AIChat: React.FC<AIChatProps> = ({
119170
isLoading={isLoading}
120171
error={error}
121172
title='AI Assistant'
173+
onClearHistory={handleClearHistory}
122174
/>
123175
);
124176
};

frontend/src/components/blocks/interview/chat/chat-layout.tsx

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
1-
import { Loader2, MessageSquare, Send, X } from 'lucide-react';
1+
import { Loader2, MessageSquare, Send, Trash2, X } from 'lucide-react';
22
import React, { ChangeEvent, KeyboardEvent, useEffect, useRef, useState } from 'react';
33

44
import { Alert, AlertDescription } from '@/components/ui/alert';
5+
import {
6+
AlertDialog,
7+
AlertDialogAction,
8+
AlertDialogCancel,
9+
AlertDialogContent,
10+
AlertDialogDescription,
11+
AlertDialogFooter,
12+
AlertDialogHeader,
13+
AlertDialogTitle,
14+
AlertDialogTrigger,
15+
} from '@/components/ui/alert-dialog';
516
import { Button } from '@/components/ui/button';
617
import { ScrollArea } from '@/components/ui/scroll-area';
718
import { Textarea } from '@/components/ui/textarea';
@@ -16,6 +27,7 @@ interface ChatLayoutProps {
1627
isLoading: boolean;
1728
error: string | null;
1829
title: string;
30+
onClearHistory?: () => void;
1931
}
2032

2133
export const ChatLayout: React.FC<ChatLayoutProps> = ({
@@ -26,6 +38,7 @@ export const ChatLayout: React.FC<ChatLayoutProps> = ({
2638
isLoading,
2739
error,
2840
title,
41+
onClearHistory,
2942
}) => {
3043
const [input, setInput] = useState<string>('');
3144
const inputRef = useRef<HTMLTextAreaElement>(null);
@@ -35,20 +48,17 @@ export const ChatLayout: React.FC<ChatLayoutProps> = ({
3548
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
3649
};
3750

38-
// Focus and scroll to bottom on window open
3951
useEffect(() => {
4052
if (isOpen) {
4153
inputRef.current?.focus();
4254
scrollToBottom();
4355
}
4456
}, [isOpen]);
4557

46-
// Scroll to bottom on reception of messages
4758
useEffect(() => {
4859
scrollToBottom();
4960
}, [messages, isLoading]);
5061

51-
// Resize textarea on input, up to a maximum height
5262
useEffect(() => {
5363
const textAreaEl = inputRef.current;
5464

@@ -82,6 +92,32 @@ export const ChatLayout: React.FC<ChatLayoutProps> = ({
8292
<h2 className='font-semibold'>{title}</h2>
8393
</div>
8494
<div className='flex items-center gap-2'>
95+
{onClearHistory && (
96+
<AlertDialog>
97+
<AlertDialogTrigger asChild>
98+
<Button
99+
variant='ghost'
100+
size='icon'
101+
className='hover:bg-secondary rounded-full'
102+
disabled={messages.length === 0}
103+
>
104+
<Trash2 className='size-4' />
105+
</Button>
106+
</AlertDialogTrigger>
107+
<AlertDialogContent>
108+
<AlertDialogHeader>
109+
<AlertDialogTitle>Clear Chat History</AlertDialogTitle>
110+
<AlertDialogDescription>
111+
Are you sure you want to clear the chat history? This action cannot be undone.
112+
</AlertDialogDescription>
113+
</AlertDialogHeader>
114+
<AlertDialogFooter>
115+
<AlertDialogCancel>Cancel</AlertDialogCancel>
116+
<AlertDialogAction onClick={onClearHistory}>Clear History</AlertDialogAction>
117+
</AlertDialogFooter>
118+
</AlertDialogContent>
119+
</AlertDialog>
120+
)}
85121
<Button
86122
variant='ghost'
87123
size='icon'

0 commit comments

Comments
 (0)