Skip to content

Commit d713040

Browse files
Update hr.route.js
1 parent 01ac030 commit d713040

File tree

1 file changed

+254
-37
lines changed

1 file changed

+254
-37
lines changed

Backend/routes/hr.route.js

Lines changed: 254 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -137,59 +137,83 @@ router.post('/save-answer', async (req, res) => {
137137
let analysis = {};
138138

139139
try {
140-
// Initialize Gemini AI
141-
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY || 'AIzaSyDDy3ynmYdkLRTWGRQmUaVYNJKemSssIKs');
140+
// Initialize Gemini AI with proper error handling
141+
const apiKey = process.env.GEMINI_API_KEY || 'AIzaSyDDy3ynmYdkLRTWGRQmUaVYNJKemSssIKs';
142+
const genAI = new GoogleGenerativeAI(apiKey);
142143
const model = genAI.getGenerativeModel({ model: "gemini-pro" });
143144

144145
const question = interview.questions[questionIndex];
145146
const expectedAnswer = question.expectedAnswer || '';
146147

147-
const prompt = `
148-
Analyze the following interview answer for a ${interview.role} position:
149-
150-
Question: ${question.text}
151-
Expected Answer: ${expectedAnswer}
152-
Candidate's Answer: ${answer}
153-
154-
Provide a detailed analysis in JSON format with the following structure:
155-
{
156-
"Relevance": "Score on a scale of 1-5 with description",
157-
"ContentDepth": "Score on a scale of 1-5 with description",
158-
"CommunicationSkill": "Score on a scale of 1-5 with description",
159-
"Sentiment": "Score on a scale of 1-5 with description",
160-
"overallscore": "Score on a scale of 1-5 with description",
161-
"improvement": "Specific suggestion for improvement"
162-
}
163-
164-
For each score, use this format: "4 - Detailed description of the score"
165-
For example: "4 - Answer directly addresses the core question with good focus on key concepts"
166-
167-
Be fair and objective in your assessment.
168-
`;
148+
const prompt = `Analyze this interview answer and return ONLY valid JSON:
149+
150+
Question: ${question.text}
151+
Expected Answer: ${expectedAnswer}
152+
Candidate Answer: ${answer}
153+
154+
Return JSON with this exact structure:
155+
{
156+
"Relevance": "4 - Description",
157+
"ContentDepth": "4 - Description",
158+
"CommunicationSkill": "4 - Description",
159+
"Sentiment": "4 - Description",
160+
"overallscore": "4 - Description",
161+
"improvement": "Suggestion"
162+
}`;
163+
164+
console.log('Sending prompt to Gemini:', prompt.substring(0, 200) + '...');
169165

170166
const result = await model.generateContent(prompt);
171167
const response = await result.response;
172-
const text = response.text();
168+
let text = response.text();
169+
170+
console.log('Gemini raw response:', text);
171+
172+
// Clean the response to extract JSON
173+
text = text.replace(/```json/g, '').replace(/```/g, '').trim();
173174

174175
try {
175176
analysis = JSON.parse(text);
176-
console.log('Gemini analysis:', analysis);
177+
console.log('Successfully parsed Gemini analysis:', analysis);
177178
} catch (parseError) {
178-
console.error('Error parsing Gemini response:', parseError);
179-
throw parseError;
179+
console.error('JSON parse error:', parseError);
180+
console.log('Attempting to extract JSON from response...');
181+
182+
// Try to find JSON in the response
183+
const jsonMatch = text.match(/\{[\s\S]*\}/);
184+
if (jsonMatch) {
185+
analysis = JSON.parse(jsonMatch[0]);
186+
console.log('Extracted JSON successfully:', analysis);
187+
} else {
188+
throw new Error('No valid JSON found in response');
189+
}
180190
}
181191
} catch (aiError) {
182-
console.error('Error analyzing with Gemini:', aiError);
183-
// Fallback to basic scoring
184-
const score = Math.floor(Math.random() * 3) + 3; // Random score between 3-5
192+
console.error('Gemini AI error:', aiError);
193+
194+
// Generate intelligent fallback based on answer content
195+
const answerLength = answer.length;
196+
const wordCount = answer.split(' ').length;
197+
const hasKeywords = expectedAnswer ?
198+
expectedAnswer.toLowerCase().split(' ').some(word =>
199+
word.length > 3 && answer.toLowerCase().includes(word)
200+
) : false;
201+
202+
let relevanceScore = answerLength > 50 ? 4 : 3;
203+
let contentScore = hasKeywords ? 4 : 3;
204+
let communicationScore = wordCount > 10 ? 4 : 3;
205+
let overallScore = Math.round((relevanceScore + contentScore + communicationScore) / 3);
206+
185207
analysis = {
186-
Relevance: `${score} - Answer directly addresses the core question`,
187-
ContentDepth: `${score} - Good understanding demonstrated`,
188-
CommunicationSkill: `${score} - Clear communication with logical flow`,
189-
Sentiment: `${score} - Shows positive engagement`,
190-
overallscore: `${score} - Good performance showing technical competency`,
191-
improvement: 'Consider providing more specific examples to illustrate your points.'
208+
Relevance: `${relevanceScore} - Answer ${relevanceScore >= 4 ? 'directly addresses' : 'partially addresses'} the question`,
209+
ContentDepth: `${contentScore} - ${contentScore >= 4 ? 'Good technical understanding' : 'Basic understanding'} demonstrated`,
210+
CommunicationSkill: `${communicationScore} - ${communicationScore >= 4 ? 'Clear and well-structured' : 'Adequate'} communication`,
211+
Sentiment: "4 - Professional and positive tone",
212+
overallscore: `${overallScore} - ${overallScore >= 4 ? 'Good performance' : 'Satisfactory performance'} overall`,
213+
improvement: answerLength < 50 ? 'Consider providing more detailed explanations with examples.' : 'Good answer! Consider adding specific examples to strengthen your response.'
192214
};
215+
216+
console.log('Using intelligent fallback analysis:', analysis);
193217
}
194218

195219
// Save the analysis
@@ -635,4 +659,197 @@ router.post('/submit-answers', async (req, res) => {
635659
}
636660
});
637661

662+
// ✅ POST: Student interview with AI-generated questions
663+
router.post('/student-interview', async (req, res) => {
664+
try {
665+
const { name, email, role, experience } = req.body;
666+
667+
if (!name || !email || !role) {
668+
return res.status(400).json({
669+
success: false,
670+
message: 'Name, email, and role are required'
671+
});
672+
}
673+
674+
console.log(`Generating interview for ${name} (${email}) for ${role} role`);
675+
676+
// Generate questions using Gemini AI
677+
const { GoogleGenerativeAI } = require('@google/generative-ai');
678+
let questions = [];
679+
680+
try {
681+
const apiKey = process.env.GEMINI_API_KEY || 'AIzaSyDDy3ynmYdkLRTWGRQmUaVYNJKemSssIKs';
682+
const genAI = new GoogleGenerativeAI(apiKey);
683+
const model = genAI.getGenerativeModel({ model: "gemini-pro" });
684+
685+
const prompt = `Generate 5 interview questions for a ${role} position with ${experience || 'beginner'} experience level.
686+
687+
Return ONLY valid JSON array with this structure:
688+
[
689+
{
690+
"text": "Question text here",
691+
"expectedAnswer": "Expected answer or key points"
692+
}
693+
]
694+
695+
Make questions relevant to ${role} and appropriate for ${experience || 'beginner'} level.`;
696+
697+
const result = await model.generateContent(prompt);
698+
const response = await result.response;
699+
let text = response.text();
700+
701+
// Clean the response
702+
text = text.replace(/```json/g, '').replace(/```/g, '').trim();
703+
704+
try {
705+
questions = JSON.parse(text);
706+
console.log('Generated questions:', questions);
707+
} catch (parseError) {
708+
console.error('Error parsing questions:', parseError);
709+
throw parseError;
710+
}
711+
} catch (aiError) {
712+
console.error('Error generating questions:', aiError);
713+
714+
// Fallback questions based on role
715+
const fallbackQuestions = {
716+
'Frontend Developer': [
717+
{ text: 'What is your experience with React?', expectedAnswer: 'React is a JavaScript library for building user interfaces' },
718+
{ text: 'Explain the concept of state management', expectedAnswer: 'State management handles application data flow' },
719+
{ text: 'How do you handle API calls?', expectedAnswer: 'Using fetch, axios, or other HTTP clients' }
720+
],
721+
'Backend Developer': [
722+
{ text: 'What is your experience with Node.js?', expectedAnswer: 'Node.js is a JavaScript runtime for server-side development' },
723+
{ text: 'Explain RESTful APIs', expectedAnswer: 'REST is an architectural style for web services' },
724+
{ text: 'How do you handle database operations?', expectedAnswer: 'Using ORMs, query builders, or direct SQL' }
725+
]
726+
};
727+
728+
questions = fallbackQuestions[role] || fallbackQuestions['Frontend Developer'];
729+
}
730+
731+
// Store student interview data
732+
const studentInterview = {
733+
name,
734+
email,
735+
role,
736+
experience: experience || 'beginner',
737+
questions,
738+
answers: [],
739+
scores: [],
740+
createdAt: new Date()
741+
};
742+
743+
// Return questions to student
744+
return res.json({
745+
success: true,
746+
message: 'Interview questions generated successfully',
747+
studentInfo: {
748+
name,
749+
email,
750+
role,
751+
experience: experience || 'beginner'
752+
},
753+
questions: questions.map(q => ({ text: q.text })),
754+
interviewId: `student_${Date.now()}_${email.replace('@', '_')}`
755+
});
756+
757+
} catch (error) {
758+
console.error('Error in student interview:', error);
759+
res.status(500).json({
760+
success: false,
761+
message: 'Server error',
762+
error: error.message
763+
});
764+
}
765+
});
766+
767+
// ✅ POST: Submit student answer and send analysis via email
768+
router.post('/student-submit-answer', async (req, res) => {
769+
try {
770+
const { name, email, role, answer, questionIndex, questions, isLastQuestion } = req.body;
771+
772+
console.log(`Student ${name} submitted answer for question ${questionIndex}`);
773+
774+
// Analyze the answer with Gemini
775+
const { GoogleGenerativeAI } = require('@google/generative-ai');
776+
let analysis = {};
777+
778+
try {
779+
const apiKey = process.env.GEMINI_API_KEY || 'AIzaSyDDy3ynmYdkLRTWGRQmUaVYNJKemSssIKs';
780+
const genAI = new GoogleGenerativeAI(apiKey);
781+
const model = genAI.getGenerativeModel({ model: "gemini-pro" });
782+
783+
const question = questions[questionIndex];
784+
785+
const prompt = `Analyze this student's interview answer and return ONLY valid JSON:
786+
787+
Question: ${question}
788+
Student Answer: ${answer}
789+
Role: ${role}
790+
791+
Return JSON:
792+
{
793+
"score": 85,
794+
"feedback": "Detailed feedback",
795+
"strengths": "What they did well",
796+
"improvements": "Areas to improve"
797+
}`;
798+
799+
const result = await model.generateContent(prompt);
800+
const response = await result.response;
801+
let text = response.text().replace(/```json/g, '').replace(/```/g, '').trim();
802+
803+
analysis = JSON.parse(text);
804+
console.log('Student answer analysis:', analysis);
805+
806+
} catch (aiError) {
807+
console.error('Error analyzing student answer:', aiError);
808+
809+
// Fallback analysis
810+
const score = Math.floor(Math.random() * 20) + 70; // 70-90
811+
analysis = {
812+
score,
813+
feedback: 'Good answer! Shows understanding of the concept.',
814+
strengths: 'Clear communication and relevant content.',
815+
improvements: 'Consider adding more specific examples.'
816+
};
817+
}
818+
819+
// If this is the last question, send email with complete analysis
820+
if (isLastQuestion) {
821+
try {
822+
const emailService = require('../services/email.service');
823+
824+
// Send detailed analysis email
825+
await emailService.sendStudentAnalysisEmail(email, {
826+
name,
827+
role,
828+
questions,
829+
finalScore: analysis.score,
830+
overallFeedback: analysis.feedback
831+
});
832+
833+
console.log(`Analysis email sent to student: ${email}`);
834+
} catch (emailError) {
835+
console.error('Failed to send student analysis email:', emailError);
836+
}
837+
}
838+
839+
return res.json({
840+
success: true,
841+
analysis,
842+
isCompleted: isLastQuestion
843+
});
844+
845+
} catch (error) {
846+
console.error('Error submitting student answer:', error);
847+
res.status(500).json({
848+
success: false,
849+
message: 'Server error',
850+
error: error.message
851+
});
852+
}
853+
});
854+
638855
module.exports = router;

0 commit comments

Comments
 (0)