Skip to content

Commit

Permalink
Merge pull request #63 from CS3219-AY2425S1/collab-bug-fixes
Browse files Browse the repository at this point in the history
Collab Bug Fixes
  • Loading branch information
bhnuka authored Nov 10, 2024
2 parents 9af261c + 855769a commit 4cac919
Show file tree
Hide file tree
Showing 12 changed files with 154 additions and 97 deletions.
6 changes: 0 additions & 6 deletions peerprep/backend/collab-service/.env

This file was deleted.

3 changes: 3 additions & 0 deletions peerprep/backend/collab-service/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.env

node_modules
1 change: 1 addition & 0 deletions peerprep/backend/collab-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
]
},
"dependencies": {
"axios": "^1.7.7",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.21.1",
Expand Down
57 changes: 57 additions & 0 deletions peerprep/backend/collab-service/src/controller/gptController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const axios = require('axios');

const assessCode = async (req, res) => {
console.log('assessCode controller activated');
try {
const { codeDetails } = req.body;
if (!codeDetails) {
res.status(400).json({ error: 'Code content is required' });
return;
}

const instructionalPrompt =
"Analyze the following: 1: Question, and its 2: Description, and 3: The code attempt. " + "\n" +
"Assess the code, focusing on its efficiency and style. Determine the correctness of the code, given the language and question specified. " +
"Your response should include:" + "\n" +
"\n" +
"\t1. Time Complexity – Provide the Big-O notation." + "\n" +
"\t2. Space Complexity – Provide the Big-O notation." + "\n" +
"\t3. Code Style – Briefly assess readability, naming conventions, and formatting." + "\n" +
"\t4. Optimization Hints – Suggest improvements if the time or space complexity could be reduced." + "\n" +
"\t5. General Comments – Summarize any other relevant observations and assess correctness to question requirements " +
"(e.g., potential edge cases, overall structure)." + "\n" +
"\n" +
"Keep each response concise but comprehensive.";

console.log('Submitting code to OpenAI API:', instructionalPrompt, codeDetails);

// API request to OpenAI for code assessment
const response = await axios.post(
'https://api.openai.com/v1/chat/completions',
{
model: 'gpt-4',
messages: [
{ role: 'system', content: "You are a coding assistant." },
{ role: 'user', content: `${instructionalPrompt}\n\n${codeDetails}` }
],
temperature: 0
},
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`
}
}
);

const feedback = response.data.choices[0].message.content;
res.json({ feedback });
} catch (error) {
console.error('Error in assessCode controller:', error);
res.status(500).json({ error: 'Failed to process code assessment' });
}
};

module.exports = {
assessCode
};
9 changes: 9 additions & 0 deletions peerprep/backend/collab-service/src/routes/gptRoutes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const { Router } = require('express');
const { assessCode } = require('../controller/gptController');

const router = Router();

// Route for handling code assessment with GPT
router.post('/gpt/assess', assessCode);

module.exports = router;
35 changes: 29 additions & 6 deletions peerprep/backend/collab-service/src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,21 @@ const connectDB = require('../config/db');
const { storeDocument, getDocument } = require('./controller/collab-controller');
const { Server } = require("socket.io");
const cors = require("cors");
const gptRoutes = require('./routes/gptRoutes');
const dotenv = require('dotenv');

const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
const wss = new WebSocket.Server({ noServer: true });

app.use(cors());
app.use(express.json());

// Connect to MongoDB
connectDB();

app.use('/api', gptRoutes);

// Endpoint to save a document to MongoDB
app.post('/api/saveDocument', async (req, res) => {
try {
Expand Down Expand Up @@ -62,19 +66,38 @@ const io = new Server(server, {
io.on("connection", (socket) => {
console.log(`User Connected: ${socket.id}`);

socket.on("join_room", (data) => {
socket.join(data);
socket.on("join_room", (room) => {
try {
socket.join(room);
console.log(`User ${socket.id} joined room ${room}`);
} catch (error) {
console.error(`Error joining room: ${error.message}`);
socket.emit("error_message", { message: "Failed to join room. Try again later." });
}
});

socket.on("send_message", (data) => {
socket.in(data.room).emit("receive_message", data); // Send to all clients except sender
try {
socket.in(data.room).emit("receive_message", data);
} catch (error) {
console.error(`Error sending message: ${error.message}`);
socket.emit("error_message", { message: "Failed to send message. Try again later." });
}
});

socket.on("disconnect", (reason) => {
console.log(`User Disconnected: ${socket.id} - Reason: ${reason}`);
if (reason === "io server disconnect") {
socket.connect(); // Reconnect on server-side disconnect
}
});

socket.on("disconnect", () => {
console.log(`User Disconnected: ${socket.id}`);
socket.on("error", (error) => {
console.error(`Socket error: ${error.message}`);
});
});


const PORT = process.env.PORT || 1234;
server.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}`);
Expand Down
54 changes: 0 additions & 54 deletions peerprep/backend/question-service/src/controllers/gptController.ts

This file was deleted.

9 changes: 0 additions & 9 deletions peerprep/backend/question-service/src/routes/gptRoutes.ts

This file was deleted.

3 changes: 0 additions & 3 deletions peerprep/backend/question-service/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ dotenv.config();
import connectDB from '../config/db';
import questionRoutes from './routes/questionRoutes';
import databaseRoutes from './routes/databaseRoutes';
import gptRoutes from './routes/gptRoutes';
import testcaseRoutes from './routes/testcaseRoutes';
import loadSampleData from './sampleData';
import { normalizeQuestionData } from './middleware/normalizationMiddleware';
Expand Down Expand Up @@ -56,8 +55,6 @@ app.use('/api', questionRoutes);
// Database routes
app.use('/api', databaseRoutes);

app.use('/api', gptRoutes);

app.use('/api', testcaseRoutes);

// Health check route
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import axios, { AxiosError } from 'axios';

const API_URL = 'http://localhost:8080/api/gpt/asses';
const API_URL = 'http://localhost:1234/api/gpt/assess';

// Define a custom error class for API errors
export class ApiError extends Error {
Expand All @@ -25,16 +25,16 @@ const handleApiError = (error: unknown): never => {
}
};

export const assesCode = async (currentCode: string): Promise<string> => {
export const assessCode = async (currentCode: string): Promise<string> => {
try {
console.log('Submitting code to backend API:');

// Call the backend API instead of OpenAI directly
const response = await axios.post(API_URL, { currentCode });
const response = await axios.post(API_URL, { codeDetails: currentCode });

// Extract and display the response content from the backend
const feedback = response.data.feedback;
//console.log('Backend API response:', feedback);
console.log('Backend API response:', feedback);
return feedback;
} catch (error) {
console.error('Error executing backend API call:', error);
Expand Down
41 changes: 34 additions & 7 deletions peerprep/frontend/src/components/Chat.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import React, { useState, useEffect } from 'react';
import io from 'socket.io-client';

const socket = io('http://localhost:1234');
const socket = io('http://localhost:1234', {
reconnectionAttempts: 3, // attempt reconnection 3 times
timeout: 5000, // connection timeout
});

interface ChatProps {
sessionId: string;
}

const Chat: React.FC<ChatProps> = ({ sessionId }) => {
// Room State
const [room, setRoom] = useState<string>(sessionId);

// Messages States
const [message, setMessage] = useState<string>('');
const [messages, setMessages] = useState<{ text: string; sender: boolean }[]>([]);
const [connectionError, setConnectionError] = useState<string | null>(null);

const joinRoom = () => {
if (room !== '') {
Expand All @@ -22,15 +23,37 @@ const Chat: React.FC<ChatProps> = ({ sessionId }) => {
};

const sendMessage = () => {
if (!message) return; // Checking if there's a message to send

const messageData = { message, room, senderId: socket.id };
socket.emit('send_message', messageData);

setMessages((prevMessages) => [...prevMessages, { text: message, sender: true }]);
setMessage(''); // Clear the input field after sending the message
setMessage('');

socket.emit('send_message', messageData, (ackError: string | null) => {
if (ackError) {
setConnectionError("Failed to send message. Please try again.");
console.error("Message not sent:", ackError);
}
});
};


useEffect(() => {
joinRoom(); // Automatically join the room based on sessionId

socket.on('connect_error', (err) => {
setConnectionError('Connection error. Please try again.');
});

socket.on('connect_timeout', () => {
setConnectionError('Connection timed out. Retrying...');
});

socket.on('reconnect_failed', () => {
setConnectionError('Reconnection failed. Please check your network.');
});

socket.on('receive_message', (data) => {
if (data.senderId !== socket.id) {
setMessages((prevMessages) => [...prevMessages, { text: data.message, sender: false }]);
Expand All @@ -39,12 +62,16 @@ const Chat: React.FC<ChatProps> = ({ sessionId }) => {

return () => {
socket.off('receive_message');
socket.off('connect_error');
socket.off('connect_timeout');
socket.off('reconnect_failed');
};
}, [room]);

return (
<div className="chat-box">
<h4 className='chat-heading'>Chat</h4>
{connectionError && <div className="error-message">{connectionError}</div>}
<div className="messages">
{messages.map((msg, index) => (
<div key={index} className={`message ${msg.sender ? 'sent' : 'received'}`}>
Expand All @@ -66,4 +93,4 @@ const Chat: React.FC<ChatProps> = ({ sessionId }) => {
);
};

export default Chat;
export default Chat;
Loading

0 comments on commit 4cac919

Please sign in to comment.