Skip to content

Commit

Permalink
Merge pull request #31 from SLIIT-24-25J-047-Research/IT21319792-Bosh…
Browse files Browse the repository at this point in the history
…itha_Gunarathna

It21319792 boshitha gunarathna
  • Loading branch information
BoshithaMGunarathna authored Nov 19, 2024
2 parents 8af35de + 123140e commit bf2420a
Show file tree
Hide file tree
Showing 16 changed files with 395 additions and 58 deletions.
6 changes: 4 additions & 2 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
# Base image
FROM node:18

# Set working directory
# working directory
WORKDIR /app

# Install ffmpeg dependencies
# Install ffmpeg
RUN apt-get update && apt-get install -y \
ffmpeg \
&& rm -rf /var/lib/apt/lists/*



# Copy package.json and install dependencies
COPY package*.json ./
RUN npm install
Expand Down
148 changes: 148 additions & 0 deletions backend/controllers/audioController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
const FormData = require('form-data');
const fs = require('fs');
const ffmpeg = require('fluent-ffmpeg');
const axios = require('axios');
const path = require('path');
const Question = require('../models/employer/Question');


exports.processAudio = async (req, res) => {
try {
// Check if audio file is provided
if (!req.file) {
console.error('No audio file provided.');
return res.status(400).json({
success: false,
message: 'Audio file not provided',
});
}

console.log('Audio file received:', {
originalname: req.file.originalname,
mimetype: req.file.mimetype,
size: req.file.size,
path: req.file.path,
});

// Check if questionId is provided
if (!req.body.questionId) {
console.error('No question ID provided.');
return res.status(400).json({
success: false,
message: 'Question ID not provided',
});
}

const questionId = req.body.questionId;

// Fetch the question to get the actual answer
const question = await Question.findById(questionId);

if (!question) {
console.error(`Question not found for ID: ${questionId}`);
return res.status(404).json({
success: false,
message: 'Question not found',
});
}

console.log('Question retrieved successfully:', question);


const filePath = req.file.path;
const tempFilePath = path.join(__dirname, 'temp_audio.wav');


ffmpeg(filePath)
.toFormat('wav')
.on('start', (commandLine) => {
console.log('FFmpeg command:', commandLine);
})
.on('progress', (progress) => {
console.log('Conversion progress:', progress);
})
.on('end', async () => {
console.log('Audio conversion completed.');


const form = new FormData();
form.append('audio', fs.createReadStream(tempFilePath));

console.log('FormData prepared for microservice.');

try {
// transcription
const response = await axios.post('http://voice-confidence:3000/transcribe', form, {
headers: {
...form.getHeaders(),
},
});


const transcription = response.data.candidate_answer;

console.log('Transcription result:', transcription);

fs.unlink(tempFilePath, (err) => {
if (err) {
console.error('Error deleting converted file:', err.message);
} else {
console.log('Converted file deleted.');
}
});


fs.unlink(filePath, (err) => {
if (err) {
console.error('Error deleting uploaded file:', err.message);
} else {
console.log('Uploaded file deleted.');
}
});

// compare the transcribed answer with the actual answers
const actualAnswers = question.answers;
const comparisonResponse = await axios.post('http://voice-confidence:3000/compare', {
candidate_answer: transcription,
actual_answer: question.answers,
});


const { similarity_scores, is_correct } = comparisonResponse.data;

console.log('Similarity Scores:', similarity_scores);
console.log('Is the answer correct?', is_correct);


return res.status(200).json({
success: true,
transcription: transcription,
similarity: similarity_scores,
isCorrect: is_correct,
});
} catch (error) {
console.error('Error in Flask response:', error.message);
return res.status(500).json({
success: false,
message: 'Error in processing transcription',
});
}
})
.on('error', (err) => {
console.error('Error during conversion:', err.message);
return res.status(500).json({
success: false,
message: 'Error in converting audio file',
error: err.message,
});
})
.save(tempFilePath);
} catch (error) {
console.error('Unexpected error:', error.message);
return res.status(500).json({
success: false,
message: 'An unexpected error occurred',
error: error.message,
});
}
};
33 changes: 25 additions & 8 deletions backend/controllers/employer/questionController.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// controllers/questionController.js
const Question = require('../../models/employer/Question');
const SkillGroup = require('../../models/employer/SkillGroup');


exports.createQuestion = async (req, res) => {
Expand Down Expand Up @@ -39,22 +40,38 @@ exports.getAllQuestions = async (req, res) => {

exports.updateQuestion = async (req, res) => {
try {
const { text, answers } = req.body;
const question = await Question.findByIdAndUpdate(
req.params.id,
{ text, answers },
{ new: true }
);
const { skillGroupId, text, answers } = req.body;

// Find the existing question
const question = await Question.findById(req.params.id);
if (!question) {
return res.status(404).json({ error: 'Question not found' });
}
res.status(200).json(question);

// If the skillGroupId has changed, ensure the new skill group exists
if (skillGroupId && skillGroupId !== question.skillGroupId.toString()) {
const newSkillGroup = await SkillGroup.findById(skillGroupId);
if (!newSkillGroup) {
return res.status(404).json({ error: 'Skill Group not found' });
}

// Update only the skillGroupId in the question
question.skillGroupId = skillGroupId;
}

// Update other fields (text, answers)
question.text = text || question.text;
question.answers = answers || question.answers;

// Save the updated question
const updatedQuestion = await question.save();
res.status(200).json(updatedQuestion);

} catch (error) {
res.status(400).json({ error: error.message });
}
};


exports.deleteQuestion = async (req, res) => {
try {
const question = await Question.findByIdAndDelete(req.params.id);
Expand Down
31 changes: 17 additions & 14 deletions backend/controllers/predictController.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');
const path = require('path');
const ffmpeg = require('fluent-ffmpeg'); // Import fluent-ffmpeg
const ffmpeg = require('fluent-ffmpeg');

exports.predictConfidence = async (req, res) => {
try {
console.log('Request body:', req.body); // Log the full request body
console.log('Uploaded file:', req.file); // Log the uploaded file

// Check for text input
console.log('Request body:', req.body);
console.log('Uploaded file:', req.file);
if (req.body.text) {
const flaskResponse = await axios.post('http://voice-confidence:3000/predict', {
text: req.body.text
Expand All @@ -22,14 +20,13 @@ exports.predictConfidence = async (req, res) => {
});
}

// Check for audio file input

if (req.file) {
const filePath = req.file.path; // Path to the uploaded audio file
const tempFilePath = path.join(__dirname, 'temp_audio.wav'); // Temporary path for the converted file

// Convert the uploaded audio file to WAV format using fluent-ffmpeg
const filePath = req.file.path;
const tempFilePath = path.join(__dirname, 'temp_audio.wav');

ffmpeg(filePath)
.toFormat('wav') // Set the desired format
.toFormat('wav')
.on('end', async () => {
console.log('Conversion completed');
const form = new FormData();
Expand All @@ -41,10 +38,16 @@ exports.predictConfidence = async (req, res) => {
...form.getHeaders()
}
});
// const flaskResponse = await axios.post('http://127.0.0.1:3000/predict', form, {
// headers: {
// ...form.getHeaders()
// }
// });

// http://127.0.0.1:3000

console.log('Flask response:', flaskResponse.data); // Log Flask response

// Clean up the temporary converted audio file
fs.unlink(tempFilePath, (err) => {
if (err) {
console.error(`Error deleting converted file: ${err}`);
Expand Down Expand Up @@ -72,7 +75,7 @@ exports.predictConfidence = async (req, res) => {
message: 'Error in converting audio file'
});
})
.save(tempFilePath); // Save the converted file
.save(tempFilePath);
} else {
return res.status(400).json({
success: false,
Expand All @@ -86,4 +89,4 @@ exports.predictConfidence = async (req, res) => {
message: 'Error in processing prediction'
});
}
};
};
7 changes: 7 additions & 0 deletions backend/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ services:
context: ./voice-confidence-service # Path to the voice-confidence-service folder
ports:
- "3000:3000"
volumes:
- ./voice-confidence-service/uploads:/app/uploads # Mount uploads folder
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"]
interval: 10s
timeout: 5s
retries: 5

# service-2:
# build:
Expand Down
4 changes: 4 additions & 0 deletions backend/models/employer/Question.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ const questionSchema = new mongoose.Schema({
type: String,
required: true
},
answers: {
type: [String],
required: true,
},
createdAt: {
type: Date,
default: Date.now
Expand Down
14 changes: 14 additions & 0 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.21.0",
"ffmpeg": "^0.0.4",
"fluent-ffmpeg": "^2.1.3",
"jsonwebtoken": "^9.0.2",
"mongoose": "^8.6.3",
Expand Down
22 changes: 22 additions & 0 deletions backend/routes/audioRoutes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const express = require('express');
const multer = require('multer');
const path = require('path');
const { processAudio } = require('../controllers/audioController');

const router = express.Router();

const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads');
},
filename: function (req, file, cb) {
cb(null, Date.now() + path.extname(file.originalname));
}
});

const upload = multer({ storage: storage });


router.post('/audio', upload.single('audio'), processAudio);

module.exports = router;
Loading

0 comments on commit bf2420a

Please sign in to comment.