@@ -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 ( / ` ` ` j s o n / 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 ( / ` ` ` j s o n / 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 ( / ` ` ` j s o n / 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+
638855module . exports = router ;
0 commit comments