Skip to content

Commit

Permalink
Merge pull request #71 from CS3219-AY2425S1/dev
Browse files Browse the repository at this point in the history
push final changes dev to main
  • Loading branch information
bhnuka authored Nov 14, 2024
2 parents d175ef3 + 5d46cf7 commit 3b54cad
Show file tree
Hide file tree
Showing 49 changed files with 3,165 additions and 2,197 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
125 changes: 125 additions & 0 deletions peerprep/backend/collab-service/src/controller/gptController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
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. " +
"Always ensure to not divulge the solution to the question, or any hints that will spoil the solution. " +
"\n" +
"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, while ensuring to not expose the solution details." +
"\n" +
"\t5. Correctness – 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." +
"\n" +
"\n" +
"Here are some few shot exmples of inputs and the expected repsonses you hsould produce:" +
"\n" +
"Example 1:\n" +
"1: Question - Two Sum\n" +
"2: DescriptionGiven an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.\n" +
"3: Code attempt in - javascript\n" +
"const nums = [2, 7, 11, 15];\n" +
"const target = 9;\n" +
"let result = [];\n" +
"for (let i = 0; i < nums.length; i++) {\n" +
" for (let j = i + 1; j < nums.length; j++) {\n" +
" if (nums[i] + nums[j] === target) {\n" +
" result = [i, j];\n" +
" }\n" +
" }\n" +
"}\n" +
"console.log(result);\n\n" +
"Expected response 1: \n" +
"1. Time Complexity: The time complexity of the code is O(n^2), where n is the length of the array. This is because of the nested loops that iterate over the array.\n\n" +
"2. Space Complexity: The space complexity of the code is O(1), as no additional space is used apart from a single array to store the result.\n\n" +
"3. Code Style: The code style is basic but functional. Variable names like `nums`, `target`, and `result` are descriptive enough. However, the use of nested loops reduces readability and efficiency. Adding comments to describe the algorithm would improve clarity.\n\n" +
"4. Optimization Hints: Try using a data structure to track the numbers you’ve seen so far. It’ll help you quickly check if the matching number for the target is already there, saving a lot of extra work!\n\n" +
"5. Correctness: The code works for small inputs but is inefficient for large arrays. It also does not handle cases where no two numbers add up to the target. Adding an edge case check would make the solution more robust.\n" +
"\n" +
"\n" +
"Example 2:\n" +
"1: Question - Roman to Integer\n" +
"2: DescriptionGiven a roman numeral, convert it to an integer.\n" +
"3: Code attempt in - python\n" +
"I = 1\n" +
"V = 5\n" +
"X = 10\n" +
"L = 50\n" +
"C = 100\n" +
"D = 500\n" +
"M = 1000\n" +
's = "LVIII"\n' +
"length = len(s)\n" +
"numbers = list(map(list, s))\n" +
"x = 0\n" +
"while x < length:\n" +
" print(numbers[x])\n" +
" x = x + 1\n\n" +
"Expected response 2:\n" +
"1. Time Complexity: The time complexity of the code is O(n), where n is the length of the string. This is because the code iterates over the string once.\n\n" +
"2. Space Complexity: The space complexity of the code is also O(n), where n is the length of the string. This is because the code creates a list of characters from the string.\n\n" +
"3. Code Style: The code style is not very good. The variable names are not descriptive, which makes the code hard to understand. The code also lacks comments, which would help explain what each part of the code is doing. The use of a while loop instead of a for loop also makes the code less readable.\n\n" +
"4. Optimization Hints: Try using a data structure to answer this question, maybe something to store your mappings?\n\n" +
"5. Correctness: The code does not actually convert the roman numeral to an integer, it just prints out the characters in the string. The code does not handle many example cases as well, try to think about more basic testcases and handle them.\n" +
"\n" +
"Example 3:\n" +
"1: Question - Roman to Integer\n" +
"2: DescriptionGiven a roman numeral, convert it to an integer.\n" +
"3: Code attempt in - python\n" +
"test\n" +
"Expected response 3: \n" +
"Without the code attempt, it's impossible to provide a detailed analysis. Please provide the code you want to be analyzed.";

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
110 changes: 48 additions & 62 deletions peerprep/backend/matching-service/src/controllers/requestController.ts
Original file line number Diff line number Diff line change
@@ -1,75 +1,61 @@
import { Request, Response } from 'express';
import { addToQueue, findMatchInQueue } from '../services/queueManager';
//import { redisDelete } from '../utils/redisUtils';
import { addToQueue, removeFromQueue, cancelSession} from '../services/queueManager';
import ReqObj from '../models/ReqObj';

// new request
export const createRequest = async (req: Request, res: Response): Promise<void> => {
const { userId, topic, difficulty } = req.body;

const newRequest: ReqObj = {
userId,
topic,
difficulty,
status: 'pending',
createdAt: new Date(),
userId,
topic,
difficulty,
status: 'pending',
createdAt: new Date(),
};


await addToQueue(userId, topic, difficulty);

// find within 30 seconds
let matchedUser = null;
const timeout = 30000;
const startTime = Date.now();

while (!matchedUser && Date.now() - startTime < timeout) {
matchedUser = await findMatchInQueue(userId);

if (matchedUser) {
break;
}
// Wait one second before checking againe
await new Promise((resolve) => setTimeout(resolve, 1000));
}

if (matchedUser) {
res.status(200).json({ message: 'Match found', data: matchedUser });
} else {
//await redisDelete(newRequest.userId); // Remove request if no match
res.status(408).json({ message: 'No match found, request timed out' });

try {
// Try to add the user to the queue
await addToQueue(userId, topic, difficulty);
res.status(200).json({ message: 'Request successfully added to the queue' });
// Match user

} catch (error) {
const err = error as Error;
if (err.name === "UserInQueueError") {
res.status(409).json({ message: 'User is already in the queue' });
} else if (err.name === "UserInSessionError") {
res.status(409).json({ message: 'User is already in an active session' });
} else {
console.error("Error in createRequest:", err);
res.status(500).json({ message: 'Failed to add request to the queue due to an unknown error' });
}
}
};
/*
import { Request, Response } from 'express';
import { addToQueue } from '../services/queueManager';
import ReqObj from '../models/ReqObj';
// Create a new matching request
export const createRequest = async (req: Request, res: Response): Promise<void> => {
const { userId, topic, difficulty } = req.body;

// Construct request object
const newRequest: ReqObj = {
userId,
topic,
difficulty,
status: 'pending',
createdAt: new Date(),
};
console.log("FROM CONTROLLER: USER ID IS" + userId);
console.log("FROM CONTROLLER: TOPIC IS" + topic);
console.log("FROM CONTROLLER: DIFFICULTY IS" + difficulty);
// Add the user to the queue
export const deleteRequest = async (req: Request, res: Response): Promise<void> => {
const userId = req.params.userId as string; // Get userId from URL parameters

try {
await addToQueue(userId, topic, difficulty);
res.status(201).json({ message: 'Match request created successfully', data: newRequest });
// Try to remove the user from the queue
console.log("Attempting to remove user from queue");
await removeFromQueue(userId);
res.status(200).json({ message: 'Request successfully removed from the queue' });
} catch (error) {
console.error('Error adding to queue:', error);
res.status(500).json({ message: 'Internal Server Error' });
console.error("Error in deleteRequest:", error);
res.status(500).json({ message: 'Failed to remove request from the queue due to an unknown error' });
}
};
*/

}

// API to delete a session
export const deleteSession = async (req: Request, res: Response): Promise<void> => {
const sessionId = req.params.sessionId as string; // Get userId from URL parameters

try {
// Cancel the timeout and remove session from Redis
await cancelSession(sessionId);
res.status(200).json({ message: 'Session successfully deleted' });
} catch (error) {
console.error("Error in deleteSession:", error);
res.status(500).json({ message: 'Failed to delete session due to an unknown error' });
}
};
Loading

0 comments on commit 3b54cad

Please sign in to comment.