|
|
|
|
|
|
|
|
import os |
|
|
import gradio as gr |
|
|
import whisper |
|
|
import tempfile |
|
|
import re |
|
|
from dotenv import load_dotenv |
|
|
from TTS.api import TTS |
|
|
import google.generativeai as genai |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
genai.configure(api_key="AIzaSyAeNCjKJVCT0gmQRAPq4NltXkc-1zELH28") |
|
|
model = genai.GenerativeModel("gemini-1.5-flash-latest") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
asr_model = whisper.load_model("base") |
|
|
jason_tts = TTS(model_name="tts_models/en/ljspeech/tacotron2-DDC", progress_bar=False, gpu=False) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
candidate_name = "" |
|
|
field = "" |
|
|
interview_questions = [] |
|
|
current_question_index = 0 |
|
|
feedback_summary = [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def save_user_info(name, user_field): |
|
|
global candidate_name, field |
|
|
candidate_name = name |
|
|
field = user_field |
|
|
greeting = f"Welcome {name}! Jason will conduct your mock interview for the {field} internship." |
|
|
return greeting |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_questions(): |
|
|
global field, interview_questions, current_question_index, feedback_summary |
|
|
current_question_index = 0 |
|
|
feedback_summary = [] |
|
|
|
|
|
prompt = ( |
|
|
f"You are a professional interviewer. Generate exactly 12 internship questions (7 technical + 5 behavioral) for the field of {field}.\n" |
|
|
f"Output only the questions, each starting with a number (e.g., 1. ..., 2. ..., ..., 12.). Do not include headings or explanations." |
|
|
) |
|
|
try: |
|
|
response = model.generate_content(prompt) |
|
|
raw_output = response.text.strip() |
|
|
lines = re.findall(r"^\d+\.\s+.*", raw_output, re.MULTILINE) |
|
|
interview_questions = [line.strip() for line in lines] |
|
|
|
|
|
if len(interview_questions) != 12: |
|
|
return "β οΈ Gemini did not return exactly 12 questions. Please try again.", "" |
|
|
|
|
|
return "β
Questions generated successfully!", interview_questions[0] |
|
|
except Exception as e: |
|
|
return f"Error: {str(e)}", "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def speak_current_question(): |
|
|
if not interview_questions or current_question_index >= len(interview_questions): |
|
|
return "No more questions.", None |
|
|
|
|
|
question = interview_questions[current_question_index] |
|
|
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".wav") |
|
|
jason_tts.tts_to_file(text=question, file_path=temp_file.name) |
|
|
return question, temp_file.name |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def record_answer(audio_file): |
|
|
global current_question_index |
|
|
if not interview_questions: |
|
|
return "β Generate questions first.", "" |
|
|
if audio_file is None: |
|
|
return "β Please record your answer.", "" |
|
|
|
|
|
try: |
|
|
result = asr_model.transcribe(audio_file) |
|
|
transcript = result["text"] |
|
|
question = interview_questions[current_question_index] |
|
|
feedback_summary.append({"question": question, "answer": transcript, "feedback": None}) |
|
|
|
|
|
current_question_index += 1 |
|
|
next_q = interview_questions[current_question_index] if current_question_index < len(interview_questions) else "β
Interview complete. Click SUBMIT for feedback." |
|
|
return f"β
Answer recorded for Q{current_question_index}.", next_q |
|
|
except Exception as e: |
|
|
return f"Error: {str(e)}", "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def analyze_all(): |
|
|
if not feedback_summary: |
|
|
return "β No answers recorded." |
|
|
|
|
|
final_summary = "" |
|
|
for i, item in enumerate(feedback_summary, 1): |
|
|
prompt = ( |
|
|
f"Interview Question: {item['question']}\n" |
|
|
f"Candidate's Answer: {item['answer']}\n" |
|
|
"Evaluate the answer:\n" |
|
|
"- Overall Rating: Weak/Average/Good/Excellent\n" |
|
|
"- Score: out of 100\n" |
|
|
"- Suggestions:" |
|
|
) |
|
|
try: |
|
|
response = model.generate_content(prompt) |
|
|
feedback = response.text.strip() |
|
|
item['feedback'] = feedback |
|
|
final_summary += f"Q{i}: {item['question']}\nAnswer: {item['answer']}\n{feedback}\n{'-'*50}\n" |
|
|
except Exception as e: |
|
|
final_summary += f"Q{i}: {item['question']}\nAnswer: {item['answer']}\nError: {str(e)}\n{'-'*50}\n" |
|
|
return final_summary |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with gr.Blocks(theme=gr.themes.Soft(primary_hue="violet")) as demo: |
|
|
gr.Markdown(""" |
|
|
<div style='text-align: center; font-size: 28px; font-weight: bold;'>ποΈ AI Mock Interview Bot</div> |
|
|
<div style='text-align: center; font-size: 16px;'>Choose your field and get started. Jason will guide you through your interview.</div> |
|
|
""") |
|
|
|
|
|
with gr.Row(): |
|
|
name = gr.Textbox(label="π€ Your Name") |
|
|
field = gr.Textbox(label="π― Interview Field (e.g. Software, Marketing, HR)") |
|
|
start_btn = gr.Button("π Begin Interview") |
|
|
greet = gr.Textbox(label="Welcome Message", interactive=False) |
|
|
start_btn.click(save_user_info, inputs=[name, field], outputs=greet) |
|
|
|
|
|
with gr.Row(): |
|
|
gen_btn = gr.Button("π Generate Questions") |
|
|
status = gr.Textbox(label="Status") |
|
|
current_q = gr.Textbox(label="π Current Question", lines=2) |
|
|
gen_btn.click(generate_questions, outputs=[status, current_q]) |
|
|
|
|
|
speak = gr.Button("π Hear Question", elem_classes="speak-btn") |
|
|
audio = gr.Audio(label="π Jason's Voice") |
|
|
speak.click(fn=speak_current_question, outputs=[current_q, audio]) |
|
|
|
|
|
record = gr.Audio(sources=["microphone"], type="filepath", label="π€ Record Your Answer") |
|
|
submit_ans = gr.Button("β
Submit This Answer") |
|
|
rec_status = gr.Textbox(label="Answer Status") |
|
|
next_q = gr.Textbox(label="Next Question") |
|
|
submit_ans.click(fn=record_answer, inputs=record, outputs=[rec_status, current_q]) |
|
|
|
|
|
submit_all = gr.Button("π Submit All & Get Feedback") |
|
|
analysis = gr.Textbox(label="π Final Feedback Summary", lines=20) |
|
|
submit_all.click(fn=analyze_all, outputs=analysis) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch() |
|
|
|