Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import gradio as gr
|
| 3 |
+
import whisper
|
| 4 |
+
import re
|
| 5 |
+
import datetime
|
| 6 |
+
import pandas as pd
|
| 7 |
+
import google.generativeai as genai
|
| 8 |
+
|
| 9 |
+
# β
Configure Gemini API
|
| 10 |
+
genai.configure(api_key="AIzaSyAeNCjKJVCT0gmQRAPq4NltXkc-1zELH28")
|
| 11 |
+
model = genai.GenerativeModel("gemini-1.5-flash-latest")
|
| 12 |
+
asr_model = whisper.load_model("base")
|
| 13 |
+
|
| 14 |
+
# β
Global session state
|
| 15 |
+
session = {
|
| 16 |
+
"username": "",
|
| 17 |
+
"company": "",
|
| 18 |
+
"role": "",
|
| 19 |
+
"questions": [],
|
| 20 |
+
"index": 0,
|
| 21 |
+
"feedback": [],
|
| 22 |
+
"interview_done": False
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
# β
Dummy public data with full analysis
|
| 26 |
+
public_data = pd.DataFrame([
|
| 27 |
+
{"Username": "Flipkart employee", "Company": "amazon", "Role": "services", "Date": "2025-05-27", "Tone (%)": 60, "Vocabulary (%)": 50, "Grammar (%)": 40, "Technical (%)": 30},
|
| 28 |
+
{"Username": "NIELT", "Company": "Dmart", "Role": "Marketing and Sales Funnel", "Date": "2025-05-22", "Tone (%)": 74, "Vocabulary (%)": 70, "Grammar (%)": 76, "Technical (%)": 69},
|
| 29 |
+
{"Username": "AIML Saddi", "Company": "Nykaa", "Role": "Product Manager", "Date": "2025-05-27", "Tone (%)": 86, "Vocabulary (%)": 79, "Grammar (%)": 81, "Technical (%)": 88},
|
| 30 |
+
{"Username": "AIML Deepanshu", "Company": "Unilever", "Role": "Brand Manager", "Date": "2025-05-27", "Tone (%)": 80, "Vocabulary (%)": 78, "Grammar (%)": 83, "Technical (%)": 82},
|
| 31 |
+
{"Username": "Rahul Ropar", "Company": "Godrej", "Role": "B2B Sales", "Date": "2025-05-23", "Tone (%)": 72, "Vocabulary (%)": 75, "Grammar (%)": 69, "Technical (%)": 65},
|
| 32 |
+
{"Username": "Vidit789", "Company": "Amazon", "Role": "Cloud Security Analyst", "Date": "2025-05-23", "Tone (%)": 90, "Vocabulary (%)": 82, "Grammar (%)": 87, "Technical (%)": 91},
|
| 33 |
+
{"Username": "DSP Dev", "Company": "Tesla", "Role": "Autopilot QA", "Date": "2025-05-22", "Tone (%)": 84, "Vocabulary (%)": 77, "Grammar (%)": 81, "Technical (%)": 79}
|
| 34 |
+
])
|
| 35 |
+
|
| 36 |
+
# β
Start interview
|
| 37 |
+
def start_interview(username, company, role):
|
| 38 |
+
if not username or not company or not role:
|
| 39 |
+
return "β Please fill all fields first."
|
| 40 |
+
session.update({
|
| 41 |
+
"username": username,
|
| 42 |
+
"company": company,
|
| 43 |
+
"role": role,
|
| 44 |
+
"questions": [],
|
| 45 |
+
"index": 0,
|
| 46 |
+
"feedback": [],
|
| 47 |
+
"interview_done": False
|
| 48 |
+
})
|
| 49 |
+
greeting = (
|
| 50 |
+
"Hello, I am Mrinankush Dutta.\n\n"
|
| 51 |
+
"Welcome to your AI Mock interview session.\n\n"
|
| 52 |
+
"This Mock interview provides tailored support for interviewees in real time.\n\n"
|
| 53 |
+
"Just focus on being yourself. We will handle the rest."
|
| 54 |
+
)
|
| 55 |
+
return greeting
|
| 56 |
+
|
| 57 |
+
# β
Generate interview questions
|
| 58 |
+
def generate_questions():
|
| 59 |
+
if not session["company"] or not session["role"]:
|
| 60 |
+
return "β Please complete setup first."
|
| 61 |
+
prompt = f"Generate 13 internship interview questions (8 technical and 5 behavioral) for the role of {session['role']} at {session['company']}. Number them 1 to 13."
|
| 62 |
+
response = model.generate_content(prompt)
|
| 63 |
+
session["questions"] = re.findall(r"^\d+\.\s+.*", response.text.strip(), re.MULTILINE)
|
| 64 |
+
return next_question()
|
| 65 |
+
|
| 66 |
+
# β
Show next question
|
| 67 |
+
def next_question():
|
| 68 |
+
if session["index"] >= len(session["questions"]):
|
| 69 |
+
session["interview_done"] = True
|
| 70 |
+
return "Interview complete. Click 'Finish' to view feedback."
|
| 71 |
+
return session["questions"][session["index"]]
|
| 72 |
+
|
| 73 |
+
# β
Record and process answer
|
| 74 |
+
def process_answer(audio):
|
| 75 |
+
if audio is None:
|
| 76 |
+
return "β Please record your answer."
|
| 77 |
+
result = asr_model.transcribe(audio)
|
| 78 |
+
transcript = result["text"]
|
| 79 |
+
q = session["questions"][session["index"]]
|
| 80 |
+
session["index"] += 1
|
| 81 |
+
prompt = (
|
| 82 |
+
f"Interview Question: {q}\n"
|
| 83 |
+
f"Answer: {transcript}\n\n"
|
| 84 |
+
"Evaluate the following in percentage:\n"
|
| 85 |
+
"Tone, Grammar, Vocabulary, and Technical correctness.\n"
|
| 86 |
+
"Respond in this format:\n"
|
| 87 |
+
"Tone: %\nGrammar: %\nVocabulary: %\nTechnical: %"
|
| 88 |
+
)
|
| 89 |
+
feedback = model.generate_content(prompt).text.strip()
|
| 90 |
+
session["feedback"].append({"question": q, "answer": transcript, "feedback": feedback})
|
| 91 |
+
return "β
Answer recorded."
|
| 92 |
+
|
| 93 |
+
# β
Compile full feedback summary
|
| 94 |
+
def feedback_summary():
|
| 95 |
+
session["interview_done"] = True
|
| 96 |
+
summary = ""
|
| 97 |
+
for i, entry in enumerate(session["feedback"], 1):
|
| 98 |
+
summary += f"Q{i}: {entry['question']}\nAnswer: {entry['answer']}\n{entry['feedback']}\n{'-'*40}\n"
|
| 99 |
+
return summary
|
| 100 |
+
|
| 101 |
+
# β
Public sharing after confirmation
|
| 102 |
+
def make_public(share_decision):
|
| 103 |
+
if not session["interview_done"]:
|
| 104 |
+
return "β Complete interview first."
|
| 105 |
+
if share_decision.lower() != "yes":
|
| 106 |
+
return "β
Interview ended. Your data was not shared publicly."
|
| 107 |
+
last_feedback = session["feedback"][-1]["feedback"]
|
| 108 |
+
tone = re.search(r"Tone:\s*(\d+)%", last_feedback)
|
| 109 |
+
grammar = re.search(r"Grammar:\s*(\d+)%", last_feedback)
|
| 110 |
+
vocab = re.search(r"Vocabulary:\s*(\d+)%", last_feedback)
|
| 111 |
+
tech = re.search(r"Technical:\s*(\d+)%", last_feedback)
|
| 112 |
+
today = datetime.date.today().strftime("%Y-%m-%d")
|
| 113 |
+
new_row = {
|
| 114 |
+
"Username": session["username"],
|
| 115 |
+
"Company": session["company"],
|
| 116 |
+
"Role": session["role"],
|
| 117 |
+
"Date": today,
|
| 118 |
+
"Tone (%)": int(tone.group(1)) if tone else 70,
|
| 119 |
+
"Vocabulary (%)": int(vocab.group(1)) if vocab else 70,
|
| 120 |
+
"Grammar (%)": int(grammar.group(1)) if grammar else 70,
|
| 121 |
+
"Technical (%)": int(tech.group(1)) if tech else 70
|
| 122 |
+
}
|
| 123 |
+
global public_data
|
| 124 |
+
public_data.loc[len(public_data)] = new_row
|
| 125 |
+
return "β
Your analysis has been shared publicly."
|
| 126 |
+
|
| 127 |
+
# β
View public profiles as DataFrame
|
| 128 |
+
def show_public():
|
| 129 |
+
if not session["interview_done"]:
|
| 130 |
+
return public_data.iloc[0:0] # Empty table if not finished
|
| 131 |
+
return public_data
|
| 132 |
+
|
| 133 |
+
# β
Gradio UI
|
| 134 |
+
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
| 135 |
+
gr.Markdown("# π§ AI MOCK INTERVIEW BUDDY")
|
| 136 |
+
|
| 137 |
+
uname = gr.Textbox(label="π€ Unique Username")
|
| 138 |
+
comp = gr.Textbox(label="π’ Company")
|
| 139 |
+
role = gr.Textbox(label="π― Role")
|
| 140 |
+
start_btn = gr.Button("π Start Interview")
|
| 141 |
+
greet = gr.Textbox(label="Greeting")
|
| 142 |
+
start_btn.click(start_interview, inputs=[uname, comp, role], outputs=greet)
|
| 143 |
+
|
| 144 |
+
gen_btn = gr.Button("π Generate Questions")
|
| 145 |
+
qbox = gr.Textbox(label="Current Question")
|
| 146 |
+
gen_btn.click(generate_questions, outputs=qbox)
|
| 147 |
+
|
| 148 |
+
record = gr.Audio(sources=["microphone"], type="filepath", label="π€ Record Answer")
|
| 149 |
+
submit = gr.Button("β
Submit")
|
| 150 |
+
result = gr.Textbox(label="Status")
|
| 151 |
+
submit.click(process_answer, inputs=record, outputs=result)
|
| 152 |
+
|
| 153 |
+
next_btn = gr.Button("β‘ Next Question")
|
| 154 |
+
next_btn.click(next_question, outputs=qbox)
|
| 155 |
+
|
| 156 |
+
final = gr.Button("π End Interview")
|
| 157 |
+
fb = gr.Textbox(label="π Final Feedback", lines=15)
|
| 158 |
+
final.click(feedback_summary, outputs=fb)
|
| 159 |
+
|
| 160 |
+
confirm = gr.Textbox(label="Do you want to share publicly? (Yes/No)")
|
| 161 |
+
share_btn = gr.Button("β Share Final Results")
|
| 162 |
+
status = gr.Textbox(label="Sharing Status")
|
| 163 |
+
share_btn.click(make_public, inputs=confirm, outputs=status)
|
| 164 |
+
|
| 165 |
+
view = gr.Button("π£ View Public Profiles")
|
| 166 |
+
public_table = gr.Dataframe(label="π§ Public Summary Table", interactive=False)
|
| 167 |
+
view.click(show_public, outputs=public_table)
|
| 168 |
+
|
| 169 |
+
# β
Fixed launch block
|
| 170 |
+
if __name__ == "__main__":
|
| 171 |
+
demo.launch()
|