CoolFace
Apppublic

MOSES3377/ai-interview-app

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
app.py137 linesDownload Raw Back to root
1import gradio as gr2import time3import logging4import os5 6# Import utility functions from other modules7from llm_utils import generate_questions, evaluate_answer, get_interview_summary8from stt_utils import transcribe_audio9from tts_utils import speak_text10 11# Configure logging12logging.basicConfig(level=logging.INFO)13 14# --- State Management ---15def initialize_state():16    """Returns the initial state for the interview session."""17    return {18        "candidate_name": "", "role": "", "questions": [],19        "evaluations": [], "current_question_index": 0,20    }21 22# --- Core Interview Logic ---23 24def start_interview(name, role, num_questions):25    """Initializes the interview, generates questions, and returns the first question UI."""26    if not name or not role:27        gr.Warning("Please enter both your name and the job role to begin.")28        return None, gr.update(visible=True), gr.update(visible=False), "", "", None, gr.update(interactive=True)29        30    logging.info(f"Starting interview for {name} for the role of {role}.")31    32    state = initialize_state()33    state["candidate_name"] = name34    state["role"] = role35    36    questions = generate_questions(role, int(num_questions))37    if not questions:38        gr.Error("Failed to generate interview questions. Please check your API key or try again.")39        return None, gr.update(visible=True), gr.update(visible=False), "", "", None, gr.update(interactive=True)40 41    state["questions"] = questions42    first_question_text = questions[0]['text']43    audio_path = speak_text(first_question_text)44    progress_text = f"Question 1 of {len(questions)}"45 46    # Hide setup, show interview, and provide all initial values47    return state, gr.update(visible=False), gr.update(visible=True), progress_text, first_question_text, audio_path, gr.update(interactive=True)48 49# FINAL VERSION: This is the most robust and simple function for processing.50def process_answer(state, audio_input):51    """52    Handles audio submission directly, performs AI tasks, and returns all UI updates at once.53    This is the most stable design.54    """55    # 1. Validate the audio input immediately56    if audio_input is None or not os.path.exists(audio_input):57        logging.warning("Submission failed: Audio input is missing or file path is invalid.")58        gr.Warning("Your audio was not recorded or sent correctly. Please try recording again.")59        # Return updates that re-enable the UI without changing the question60        return state, gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update(interactive=True)61 62    # 2. Process the valid audio file63    logging.info(f"Processing audio file: {audio_input}")64    transcribed_answer = transcribe_audio(audio_input)65    if not transcribed_answer:66        transcribed_answer = "(Audio was unclear or could not be transcribed)"67 68    current_question = state["questions"][state["current_question_index"]]['text']69    evaluation = evaluate_answer(current_question, transcribed_answer)70 71    state["evaluations"].append({"question": current_question, "answer": transcribed_answer, **evaluation})72    state["current_question_index"] += 173 74    # 3. Decide what to show next: another question or the final results75    if state["current_question_index"] >= len(state["questions"]):76        # FINISH: Show the results screen77        summary_data = get_interview_summary(state["evaluations"])78        final_score = f"Final Score: {summary_data.get('final_score', 'N/A')} / 10"79        summary_text = summary_data.get('summary', 'Could not generate a summary.')80        return state, gr.update(visible=False), gr.update(visible=True), "", "", final_score, summary_text, gr.update(value=None), gr.update(interactive=False)81    else:82        # NEXT QUESTION: Prepare UI for the next question83        next_q_index = state["current_question_index"]84        next_q_text = state["questions"][next_q_index]['text']85        progress_text = f"Question {next_q_index + 1} of {len(state['questions'])}"86        next_q_audio = speak_text(next_q_text)87        return state, gr.update(visible=True), gr.update(visible=False), progress_text, next_q_text, "", "", next_q_audio, gr.update(interactive=True)88 89# --- Gradio UI Definition ---90with gr.Blocks(theme=gr.themes.Soft(), title="AI Interviewer") as demo:91    state = gr.State(value=initialize_state())92    93    gr.Markdown("# 🤖 AI Interviewer")94    gr.Markdown("Welcome! Please set up your interview, and the AI will guide you through the questions.")95 96    with gr.Row(visible=True) as setup_screen:97        candidate_name_input = gr.Textbox(label="Your Name")98        role_input = gr.Textbox(label="Job Role You're Applying For")99        num_questions_slider = gr.Slider(minimum=3, maximum=10, value=5, step=1, label="Number of Questions")100        start_button = gr.Button("Start Interview", variant="primary")101 102    with gr.Row(visible=False) as interview_screen:103        with gr.Column(scale=2):104            progress_label = gr.Label()105            # Use gr.Video for better compatibility106            webcam_feed = gr.Video(sources=["webcam"], label="Live Monitoring")107            question_audio = gr.Audio(autoplay=True, interactive=False, label="AI Interviewer")108        with gr.Column(scale=3):109            question_display = gr.Textbox(label="Current Question", interactive=False, lines=4)110            audio_answer_input = gr.Audio(sources=["microphone"], type="filepath", label="Record Your Answer Here")111            submit_answer_button = gr.Button("Submit Answer", variant="primary", interactive=False)112            113    with gr.Column(visible=False) as results_screen:114        final_score_display = gr.Label(label="Overall Performance")115        summary_display = gr.Textbox(label="Interview Summary", interactive=False, lines=10)116 117    # --- Event Handling Logic ---118    start_button.click(119        fn=start_interview,120        inputs=[candidate_name_input, role_input, num_questions_slider],121        outputs=[state, setup_screen, interview_screen, progress_label, question_display, question_audio, submit_answer_button]122    )123 124    submit_answer_button.click(125        fn=lambda: gr.Button("Processing...", interactive=False),126        outputs=[submit_answer_button]127    ).then(128        fn=process_answer,129        inputs=[state, audio_answer_input],130        outputs=[state, interview_screen, results_screen, progress_label, question_display, final_score_display, summary_display, question_audio, submit_answer_button]131    ).then(132        fn=lambda: gr.update(value=None),133        outputs=[audio_answer_input]134    )135 136if __name__ == "__main__":137    demo.launch(debug=True)