Skip to content

Commit f010925

Browse files
committed
done
1 parent 11e95c2 commit f010925

File tree

13 files changed

+371
-1
lines changed

13 files changed

+371
-1
lines changed

.env.local

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ COLLAB_SERVICE_NAME=collab-express
1212
COLLAB_EXPRESS_PORT=9003
1313
COLLAB_EXPRESS_DB_PORT=5434
1414
COLLAB_PGDATA="/data/collab-db"
15+
OPENAI_API_KEY=PUT_YOUR_OPENAI_API_KEY_HERE
16+
1517

1618
MATCHING_SERVICE_NAME=match-express
1719
MATCHING_EXPRESS_PORT=9004
@@ -22,3 +24,4 @@ MATCHING_DB_HOST_MGMT_PORT=3001
2224

2325
FRONTEND_SERVICE_NAME=frontend
2426
FRONTEND_PORT=3000
27+

backend/collaboration/.env.compose

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ POSTGRES_DB="collab"
88
POSTGRES_USER="peerprep-collab-express"
99
POSTGRES_PASSWORD="6rYE0nIzI2ThzDO"
1010
PGDATA="/data/collab-db"
11+
OPENAI_API_KEY="PUT_YOUR_OPENAI_API_KEY_HERE"

backend/collaboration/.env.docker

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ POSTGRES_DB=collab
77
POSTGRES_USER=peerprep-collab-express
88
POSTGRES_PASSWORD=6rYE0nIzI2ThzDO
99
PGDATA=/data/collab-db
10+
OPENAI_API_KEY=OPENAI_KEY_HERE

backend/collaboration/.env.local

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ EXPRESS_DB_PORT=5434
66
POSTGRES_DB="collab"
77
POSTGRES_USER="peerprep-collab-express"
88
POSTGRES_PASSWORD="6rYE0nIzI2ThzDO"
9-
PGDATA="/data/collab-db"
9+
PGDATA="/data/collab-db"
10+
OPENAI_API_KEY=PUT-YOUR-KEYS-HERE

backend/collaboration/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"env-cmd": "^10.1.0",
2222
"express": "^4.21.1",
2323
"http-status-codes": "^2.3.0",
24+
"openai": "^4.70.2",
2425
"pg": "^8.13.0",
2526
"pino": "^9.4.0",
2627
"pino-http": "^10.3.0",
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import type { Request, Response } from 'express';
2+
import { StatusCodes } from 'http-status-codes';
3+
4+
import { getOpenAIResponse } from '@/service/post/openai-service';
5+
6+
export async function queryOpenAI(req: Request, res: Response) {
7+
const { messages } = req.body;
8+
9+
// Ensure 'messages' array is provided
10+
if (!messages || !Array.isArray(messages)) {
11+
return res.status(StatusCodes.BAD_REQUEST).json({
12+
error: 'Invalid request: messages array is required.',
13+
});
14+
}
15+
16+
try {
17+
const result = await getOpenAIResponse(messages);
18+
19+
return res.status(StatusCodes.OK).json(result);
20+
} catch (err) {
21+
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
22+
success: false,
23+
message: 'An error occurred while querying OpenAI',
24+
error: err,
25+
});
26+
}
27+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import express from 'express';
2+
3+
import { queryOpenAI } from '@/controller/openai-controller';
4+
5+
const router = express.Router();
6+
7+
router.get('/chat', queryOpenAI);
8+
9+
export default router;

backend/collaboration/src/server.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import pino from 'pino-http';
99
import { UI_HOST } from '@/config';
1010
import { config, db } from '@/lib/db';
1111
import { logger } from '@/lib/utils';
12+
import aiChatRoutes from '@/routes/chat';
1213
import roomRoutes from '@/routes/room';
1314

1415
import { setUpWSServer } from './ws';
@@ -55,6 +56,8 @@ export const dbHealthCheck = async () => {
5556
}
5657
};
5758

59+
app.post('/ai', aiChatRoutes);
60+
5861
// Ensure DB service is up before running.
5962
app.get('/test-db', async (_req, res) => {
6063
await dbHealthCheck();
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import OpenAI from 'openai';
2+
3+
const openai = new OpenAI({
4+
apiKey: process.env.OPENAI_API_KEY,
5+
});
6+
7+
interface OpenAIMessage {
8+
role: 'system' | 'user' | 'assistant';
9+
content: string;
10+
}
11+
12+
export async function getOpenAIResponse(messages: OpenAIMessage[]) {
13+
try {
14+
const response = await openai.chat.completions.create({
15+
model: 'gpt-3.5-turbo', // or the desired model
16+
messages: [
17+
{
18+
role: 'system',
19+
content:
20+
'You are a helpful coding assistant. You are helping a user with a coding problem. Provide tips to the user on solving the problem but do not provide the solution directly.',
21+
},
22+
...messages,
23+
],
24+
});
25+
26+
if (response.choices && response.choices[0].message) {
27+
return {
28+
success: true,
29+
data: response.choices[0].message.content,
30+
};
31+
} else {
32+
throw new Error('No valid response from OpenAI');
33+
}
34+
} catch (error) {
35+
throw new Error((error as Error)?.message || 'Failed to query OpenAI');
36+
}
37+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import React, { useState } from 'react';
2+
3+
import { sendChatMessage } from '@/services/collab-service';
4+
5+
import { ChatLayout } from './chat/chat-layout';
6+
import { ChatMessageType } from './chat/chat-message';
7+
8+
// Types for OpenAI API
9+
// interface OpenAIMessage {
10+
// role: 'user' | 'assistant';
11+
// content: string;
12+
// }
13+
14+
interface AIChatProps {
15+
isOpen: boolean;
16+
onClose: () => void;
17+
}
18+
19+
// const API_URL = 'https://api.openai.com/v1/chat/completions';
20+
// const API_KEY = process.env.OPENAI_API_KEY;
21+
22+
export const AIChat: React.FC<AIChatProps> = ({ isOpen, onClose }) => {
23+
const [messages, setMessages] = useState<ChatMessageType[]>([]);
24+
const [isLoading, setIsLoading] = useState<boolean>(false);
25+
const [error, setError] = useState<string | null>(null);
26+
27+
const handleSend = async (userMessage: string): Promise<void> => {
28+
if (!userMessage.trim() || isLoading) return;
29+
30+
const updatedMessages = [
31+
...messages,
32+
{ text: userMessage, isUser: true, timestamp: new Date() },
33+
];
34+
35+
setMessages(updatedMessages);
36+
setIsLoading(true);
37+
setError(null);
38+
39+
const inputMessages = updatedMessages.map((message) => ({
40+
role: message.isUser ? 'user' : 'assistant',
41+
content: message.text,
42+
}));
43+
44+
try {
45+
const response = await sendChatMessage(inputMessages);
46+
setMessages((prev) => [
47+
...prev,
48+
{ text: response?.message, isUser: false, timestamp: new Date() },
49+
]);
50+
} catch (err) {
51+
setError(
52+
err instanceof Error ? err.message : 'An error occurred while fetching the response'
53+
);
54+
} finally {
55+
setIsLoading(false);
56+
}
57+
};
58+
59+
return (
60+
<ChatLayout
61+
isOpen={isOpen}
62+
onClose={onClose}
63+
messages={messages}
64+
onSend={handleSend}
65+
isLoading={isLoading}
66+
error={error}
67+
title='AI Assistant'
68+
/>
69+
);
70+
};

0 commit comments

Comments
 (0)