CoolFace
Apppublic

Prathmesh0001/interview-system

sourceHugging Faceupdated 8mo agoView on Hugging Face
0likes
app_fixed.py431 linesDownload Raw Back to root
1"""2AI Mock Interview System - Enhanced with Advanced Metrics35 personalized resume-based questions with 40+ evaluation metrics4"""5 6from flask import Flask, render_template, request, jsonify, send_file, redirect, url_for7from flask_cors import CORS8import os9from datetime import datetime10from werkzeug.utils import secure_filename11import uuid12import traceback13 14# Import modules15from document_parser import DocumentParser16from question_generator import QuestionGenerator17from answer_analyzer import AnswerAnalyzer  # Now uses EnhancedAnswerAnalyzer18from report_generator import ReportGenerator19 20app = Flask(__name__)21app.secret_key = os.urandom(24)22CORS(app)23 24# Config25UPLOAD_FOLDER = 'uploads'26REPORTS_FOLDER = 'reports'27ALLOWED_EXTENSIONS = {'pdf', 'docx', 'txt'}28 29os.makedirs(UPLOAD_FOLDER, exist_ok=True)30os.makedirs(REPORTS_FOLDER, exist_ok=True)31os.makedirs('templates', exist_ok=True)32os.makedirs('static/css', exist_ok=True)33 34app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER35app.config['REPORTS_FOLDER'] = REPORTS_FOLDER36app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 102437 38# Initialize39doc_parser = DocumentParser()40question_generator = QuestionGenerator()41answer_analyzer = AnswerAnalyzer()42report_generator = ReportGenerator()43 44# Sessions storage45interview_sessions = {}46 47 48def allowed_file(filename):49    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS50 51 52@app.route('/')53def index():54    """Upload page"""55    print("\n๐Ÿ  Homepage accessed")56    return render_template('index.html')57 58 59@app.route('/upload', methods=['POST'])60def upload_documents():61    """Handle file upload and question generation"""62    try:63        print("\n๐Ÿ“ค Upload request received")64        65        # Validate files66        if 'resume' not in request.files or 'job_description' not in request.files:67            print("โŒ Missing files in request")68            return jsonify({'success': False, 'error': 'Both files required'}), 40069        70        resume_file = request.files['resume']71        jd_file = request.files['job_description']72        73        print(f"๐Ÿ“„ Resume: {resume_file.filename}")74        print(f"๐Ÿ“„ JD: {jd_file.filename}")75        76        if resume_file.filename == '' or jd_file.filename == '':77            return jsonify({'success': False, 'error': 'No file selected'}), 40078        79        if not (allowed_file(resume_file.filename) and allowed_file(jd_file.filename)):80            return jsonify({'success': False, 'error': 'Invalid format'}), 40081        82        # Save files83        resume_path = os.path.join(app.config['UPLOAD_FOLDER'], 84                                   secure_filename(resume_file.filename))85        jd_path = os.path.join(app.config['UPLOAD_FOLDER'], 86                              secure_filename(jd_file.filename))87        88        resume_file.save(resume_path)89        jd_file.save(jd_path)90        print("โœ… Files saved")91        92        # Parse93        print("๐Ÿ“– Parsing documents...")94        resume_text = doc_parser.parse_document(resume_path)95        jd_text = doc_parser.parse_document(jd_path)96        97        if not resume_text or not jd_text:98            return jsonify({'success': False, 'error': 'Failed to parse documents'}), 40099        100        print(f"โœ… Resume: {len(resume_text)} chars")101        print(f"โœ… JD: {len(jd_text)} chars")102        103        # Generate session104        session_id = str(uuid.uuid4())105        print(f"๐Ÿ†” Session: {session_id}")106        107        # Generate questions108        print("๐ŸŽฏ Generating 5 resume-based questions...")109        all_questions = question_generator.generate_resume_specific_questions(110            resume_text, jd_text, 5111        )112        113        print(f"โœ… Generated {len(all_questions)} questions:")114        for i, q in enumerate(all_questions, 1):115            print(f"   {i}. {q['question'][:60]}...")116        117        # Store session118        interview_sessions[session_id] = {119            'resume_text': resume_text,120            'jd_text': jd_text,121            'questions': all_questions,122            'answers': [],123            'current_question': 0,124            'created_at': datetime.now().isoformat()125        }126        127        print(f"๐Ÿ’พ Session stored. Total sessions: {len(interview_sessions)}")128        print(f"   Session keys: {list(interview_sessions.keys())}")129        130        return jsonify({131            'success': True,132            'session_id': session_id,133            'total_questions': len(all_questions)134        })135        136    except Exception as e:137        print(f"\nโŒ Upload error: {e}")138        traceback.print_exc()139        return jsonify({'success': False, 'error': str(e)}), 500140 141 142@app.route('/interview/<session_id>')143def interview_page(session_id):144    """Interview page with video"""145    print(f"\n๐ŸŽฅ Interview page requested: {session_id}")146    print(f"   Available sessions: {list(interview_sessions.keys())}")147    148    if session_id not in interview_sessions:149        print(f"โŒ Invalid session: {session_id}")150        return redirect(url_for('index'))151    152    print(f"โœ… Session found. Questions: {len(interview_sessions[session_id]['questions'])}")153    return render_template('interview.html', session_id=session_id)154 155 156@app.route('/api/get-question/<session_id>', methods=['GET'])157def get_question(session_id):158    """Get current question"""159    try:160        print(f"\n๐Ÿ“ Question request for session: {session_id}")161        print(f"   Available sessions: {list(interview_sessions.keys())}")162        163        if not session_id or session_id == '':164            print("โŒ Empty session ID")165            return jsonify({'error': 'No session ID provided'}), 400166        167        if session_id not in interview_sessions:168            print(f"โŒ Invalid session: {session_id}")169            print(f"   Session not found in: {list(interview_sessions.keys())}")170            return jsonify({'error': 'Invalid session. Please upload files again.'}), 404171        172        session_data = interview_sessions[session_id]173        current_idx = session_data['current_question']174        questions = session_data['questions']175        176        print(f"   Current: {current_idx + 1}/{len(questions)}")177        178        if current_idx >= len(questions):179            print("โœ… Interview complete")180            return jsonify({181                'completed': True,182                'message': 'Interview completed'183            })184        185        question = questions[current_idx]186        187        print(f"   Question: {question['question'][:50]}...")188        189        response_data = {190            'completed': False,191            'question_number': current_idx + 1,192            'total_questions': len(questions),193            'question': question['question'],194            'category': question.get('category', 'Resume-Based'),195            'difficulty': question.get('difficulty', 'intermediate'),196            'focus_area': question.get('focus_area', '')197        }198        199        print(f"   Sending response: {response_data}")200        return jsonify(response_data)201        202    except Exception as e:203        print(f"โŒ Get question error: {e}")204        traceback.print_exc()205        return jsonify({'error': str(e)}), 500206 207 208@app.route('/api/submit-answer/<session_id>', methods=['POST'])209def submit_answer(session_id):210    """Submit answer and get feedback"""211    try:212        print(f"\nโœ๏ธ  Answer submission for session: {session_id}")213        214        if session_id not in interview_sessions:215            print(f"โŒ Invalid session")216            return jsonify({'success': False, 'error': 'Invalid session'}), 404217        218        data = request.get_json()219        answer_text = data.get('answer', '')220        duration = data.get('duration', 0)221        222        print(f"   Answer length: {len(answer_text)} chars")223        print(f"   Duration: {duration}s")224        225        session_data = interview_sessions[session_id]226        current_idx = session_data['current_question']227        question = session_data['questions'][current_idx]228        229        # ========== ENHANCED METRICS INTEGRATION ==========230        # Analyze answer with ENHANCED metrics231        print("๐Ÿ” Analyzing answer with enhanced metrics...")232        job_description = session_data.get('jd_text', '')233        234        analysis = answer_analyzer.analyze_answer(235            answer_text,236            question['question'],237            job_description=job_description,238            audio_duration=duration239        )240        # ==================================================241        242        # Generate feedback243        feedback = answer_analyzer.get_feedback(analysis)244        245        # Display enhanced metrics in terminal246        print(f"   ๐Ÿ“Š Overall Score: {analysis['overall_score']:.1f}")247        if 'composite_scores' in analysis:248            composite = analysis['composite_scores']249            print(f"   ๐Ÿ“ˆ Composite Scores:")250            print(f"      - Communication: {composite.get('communication_effectiveness_score', 0):.1f}")251            print(f"      - Confidence: {composite.get('confidence_score', 0):.1f}")252            print(f"      - Professionalism: {composite.get('professionalism_score', 0):.1f}")253        254        if 'content_quality' in analysis:255            print(f"   ๐Ÿ“ Content Quality: {analysis['content_quality'].get('quality_score', 0):.1f}")256        257        if 'speech_analysis' in analysis:258            speech = analysis['speech_analysis']259            print(f"   ๐Ÿ—ฃ๏ธ  Speech Rate: {speech.get('speech_rate_wpm', 0):.0f} WPM")260            print(f"   ๐Ÿ’ฌ Filler Words: {speech.get('filler_word_count', 0)}")261        262        # Store answer263        session_data['answers'].append({264            'question': question['question'],265            'answer': answer_text,266            'duration': duration,267            'analysis': analysis,268            'feedback': feedback,269            'timestamp': datetime.now().isoformat()270        })271        272        # Move to next question273        session_data['current_question'] += 1274        is_complete = session_data['current_question'] >= len(session_data['questions'])275        276        print(f"   Progress: {session_data['current_question']}/{len(session_data['questions'])}")277        print(f"   Complete: {is_complete}")278        279        return jsonify({280            'success': True,281            'score': analysis['overall_score'],282            'feedback': feedback[:3],  # Return top 3 feedback points283            'is_complete': is_complete284        })285        286    except Exception as e:287        print(f"โŒ Submit answer error: {e}")288        traceback.print_exc()289        return jsonify({'success': False, 'error': str(e)}), 500290 291 292@app.route('/results/<session_id>')293def results_page(session_id):294    """Results page"""295    print(f"\n๐Ÿ“Š Results page requested: {session_id}")296    297    if session_id not in interview_sessions:298        print(f"โŒ Invalid session")299        return redirect(url_for('index'))300    301    print(f"โœ… Session found")302    return render_template('results.html', session_id=session_id)303 304 305@app.route('/api/generate-report/<session_id>', methods=['POST'])306def generate_report(session_id):307    """Generate final report"""308    try:309        print(f"\n๐Ÿ“„ Report generation for session: {session_id}")310        311        if session_id not in interview_sessions:312            return jsonify({'success': False, 'error': 'Invalid session'}), 404313        314        session_data = interview_sessions[session_id]315        316        print("๐Ÿ“Š Generating comprehensive report...")317        318        # Prepare interview data for report319        interview_data = {320            'answers': session_data['answers'],321            'resume_text': session_data['resume_text'],322            'jd_text': session_data['jd_text'],323            'timestamp': session_data['created_at']324        }325        326        # Generate report path327        report_filename = f'interview_report_{session_id}.pdf'328        report_path = os.path.join(app.config['REPORTS_FOLDER'], report_filename)329        330        # Generate the report331        success = report_generator.generate_report(interview_data, report_path)332        333        if not success:334            return jsonify({'success': False, 'error': 'Failed to generate report'}), 500335        336        print(f"โœ… Report generated: {report_path}")337        338        # Calculate metrics using enhanced analysis339        scores = [ans['analysis']['overall_score'] for ans in session_data['answers']]340        overall_score = sum(scores) / len(scores) if scores else 0341        342        # Extract individual metric scores from enhanced analyzer343        content_scores = [ans['analysis']['content_quality']['quality_score'] for ans in session_data['answers']]344        345        # Try to get composite scores if available (enhanced metrics)346        if 'composite_scores' in session_data['answers'][0]['analysis']:347            clarity_scores = [ans['analysis']['composite_scores']['clarity_score'] for ans in session_data['answers']]348            confidence_scores = [ans['analysis']['composite_scores']['confidence_score'] for ans in session_data['answers']]349            professional_scores = [ans['analysis']['composite_scores']['professionalism_score'] for ans in session_data['answers']]350        else:351            # Fallback to old metrics structure352            clarity_scores = [ans['analysis']['clarity']['clarity_score'] for ans in session_data['answers']]353            confidence_scores = [ans['analysis']['sentiment']['confidence_level'] for ans in session_data['answers']]354            professional_scores = [ans['analysis']['professionalism']['professionalism_score'] for ans in session_data['answers']]355        356        metrics = {357            'content_score': sum(content_scores) / len(content_scores) if content_scores else 70,358            'clarity_score': sum(clarity_scores) / len(clarity_scores) if clarity_scores else 70,359            'confidence_score': sum(confidence_scores) / len(confidence_scores) if confidence_scores else 70,360            'professionalism_score': sum(professional_scores) / len(professional_scores) if professional_scores else 70361        }362        363        print(f"   Overall: {overall_score:.1f}")364        print(f"   Metrics: {metrics}")365        366        return jsonify({367            'success': True,368            'overall_score': overall_score,369            'metrics': metrics,370            'report_url': f'/download-report/{session_id}'371        })372        373    except Exception as e:374        print(f"โŒ Report generation error: {e}")375        traceback.print_exc()376        return jsonify({'success': False, 'error': str(e)}), 500377 378 379@app.route('/download-report/<session_id>')380def download_report(session_id):381    """Download PDF report"""382    try:383        report_path = os.path.join(app.config['REPORTS_FOLDER'], f'interview_report_{session_id}.pdf')384        385        if not os.path.exists(report_path):386            return "Report not found", 404387        388        return send_file(389            report_path,390            as_attachment=True,391            download_name=f'interview_report_{datetime.now().strftime("%Y%m%d")}.pdf'392        )393    except Exception as e:394        print(f"โŒ Download error: {e}")395        return str(e), 500396 397 398# Debug route to check sessions399@app.route('/api/debug/sessions')400def debug_sessions():401    """Debug endpoint to check active sessions"""402    return jsonify({403        'total_sessions': len(interview_sessions),404        'session_ids': list(interview_sessions.keys()),405        'sessions': {406            sid: {407                'questions': len(data['questions']),408                'answers': len(data['answers']),409                'current': data['current_question'],410                'created': data['created_at']411            }412            for sid, data in interview_sessions.items()413        }414    })415 416 417if __name__ == '__main__':418    print("\n" + "="*70)419    print("๐Ÿš€ AI MOCK INTERVIEW - ENHANCED METRICS SYSTEM")420    print("="*70)421    print(f"๐Ÿ“ Upload folder: {UPLOAD_FOLDER}")422    print(f"๐Ÿ“ Reports folder: {REPORTS_FOLDER}")423    print(f"๐ŸŒ Access at: http://localhost:5000")424    print("\nโœจ Features:")425    print("   โ€ข 5 personalized resume-based questions")426    print("   โ€ข 40+ advanced evaluation metrics")427    print("   โ€ข Real-time comprehensive feedback")428    print("   โ€ข Detailed PDF performance reports")429    print("="*70 + "\n")430    431    app.run(host="0.0.0.0", port=7860)