Imarticuslearning commited on
Commit
aa2bc5c
Β·
verified Β·
1 Parent(s): d4b6667

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +250 -0
app.py ADDED
@@ -0,0 +1,250 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import re
3
+ import time
4
+ import asyncio
5
+ import tempfile
6
+ import streamlit as st
7
+ import google.generativeai as genai
8
+ import edge_tts
9
+ import speech_recognition as sr
10
+ from dotenv import load_dotenv
11
+ import pandas as pd
12
+
13
+ # βœ… Streamlit page config
14
+ st.set_page_config(page_title="GrillMaster", layout="wide")
15
+
16
+ # Load API key
17
+ load_dotenv()
18
+ genai.configure(api_key=os.getenv("GOOGLE_api"))
19
+
20
+ # -----------------------------
21
+ # SESSION STATE DEFAULTS
22
+ # -----------------------------
23
+ defaults = {
24
+ "generated_questions": [],
25
+ "current_question_index": 0,
26
+ "answers": [],
27
+ "evaluations": [],
28
+ "evaluation_feedback": "",
29
+ "overall_score": 0,
30
+ "percentage_score": 0,
31
+ "is_recording": False,
32
+ "question_played": False,
33
+ "selected_domain": "",
34
+ "response_captured": False,
35
+ "timer_start": None,
36
+ "show_intro": False,
37
+ "recorded_text": "",
38
+ "recording_complete": False,
39
+ "recording_started": False,
40
+ "audio_played": False,
41
+ "question_start_time": 0.0,
42
+ "record_phase": "",
43
+ "improvement_suggestions_generated": False,
44
+ "improvement_suggestions": ""
45
+ }
46
+ for key, value in defaults.items():
47
+ if key not in st.session_state:
48
+ st.session_state[key] = value
49
+
50
+ # -----------------------------
51
+ # QUESTIONS
52
+ # -----------------------------
53
+ CANDIDATE_QUESTIONS = [
54
+ {"text": "Can you introduce yourself?", "type": "introduction"},
55
+ {"text": "Why do you want to be a part of Analytics domain?", "type": "introduction"},
56
+ {"text": "Can you try to explain any project of yours in detail?", "type": "project"},
57
+ {"text": "Any challenges faced while working on the project?", "type": "project"},
58
+ {"text": "What could be the business impact of the project?", "type": "project"}
59
+ ]
60
+
61
+ # -----------------------------
62
+ # AUDIO GENERATION
63
+ # -----------------------------
64
+ async def generate_question_audio(question, voice="en-IE-EmilyNeural"):
65
+ clean_question = re.sub(r'[^A-Za-z0-9.,?! ]+', '', question)
66
+ tts = edge_tts.Communicate(text=clean_question, voice=voice)
67
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp_file:
68
+ await tts.save(tmp_file.name)
69
+ return tmp_file.name
70
+
71
+ # -----------------------------
72
+ # EVALUATION FUNCTION
73
+ # -----------------------------
74
+ def evaluate_answer(question_text, answer_text, q_type):
75
+ model = genai.GenerativeModel("gemini-pro")
76
+
77
+ if q_type == "introduction":
78
+ prompt = f"""
79
+ You are an expert interviewer evaluating a candidate's introduction. Assess the response based on:
80
+ - Clarity & Fluency
81
+ - Confidence & Professionalism
82
+ - Relevance & Structure
83
+ - Conciseness
84
+
85
+ Provide an evaluation summary with a score out of 10.
86
+
87
+ Candidate Introduction:
88
+ {answer_text}
89
+ """
90
+ else: # project explanation
91
+ prompt = f"""
92
+ You are an expert interviewer evaluating a candidate's project explanation. Assess the response based on:
93
+ - Technical Understanding
94
+ - Communication Clarity
95
+ - Problem-Solving & Impact
96
+ - Use of Examples
97
+ - Logical Flow & Structure
98
+
99
+ Provide an evaluation summary with a score out of 10.
100
+
101
+ Candidate Project Explanation:
102
+ {answer_text}
103
+ """
104
+ response = model.generate_content(prompt)
105
+ text = response.text.strip()
106
+ score_match = re.search(r"\*\*Overall Score:\*\* (\d+)/10", text)
107
+ score = int(score_match.group(1)) if score_match else 0
108
+ return {"score": score, "feedback": text}
109
+
110
+ # -----------------------------
111
+ # IMPROVEMENT SUGGESTIONS
112
+ # -----------------------------
113
+ def generate_improvement_suggestions():
114
+ model = genai.GenerativeModel('gemini-pro')
115
+ if not st.session_state.get("answers"):
116
+ st.session_state.improvement_suggestions = "No answers were recorded to generate improvement suggestions."
117
+ return
118
+
119
+ qa_context = []
120
+ for i, entry in enumerate(st.session_state["answers"]):
121
+ qa_context.append(
122
+ f"Question {i+1}: {entry['question']}\nCandidate's Answer {i+1}: {entry.get('response','[No response]')}"
123
+ )
124
+ full_qa_context = "\n\n".join(qa_context)
125
+
126
+ prompt = f"""
127
+ You are an interview coach. Based on these Q&A:
128
+ {full_qa_context}
129
+
130
+ Provide detailed improvement suggestions for each answer. Be constructive and supportive.
131
+ """
132
+ try:
133
+ st.info("πŸ€– Generating detailed improvement suggestions...")
134
+ response = model.generate_content(prompt)
135
+ st.session_state.improvement_suggestions = response.text.strip()
136
+ st.session_state.improvement_suggestions_generated = True
137
+ st.success("Detailed suggestions generated!")
138
+ except Exception as e:
139
+ st.error(f"Error generating suggestions: {e}")
140
+ st.session_state.improvement_suggestions_generated = False
141
+
142
+ # -----------------------------
143
+ # START PAGE: Candidate Intro Button
144
+ # -----------------------------
145
+ if not st.session_state["show_intro"]:
146
+ st.title("πŸ”₯🎯 Welcome to GrillMaster Mock Interview")
147
+ st.markdown("Click the button below to start the Candidate Introduction + Project mock interview:")
148
+ if st.button("🎀 Candidate Intro + Project"):
149
+ st.session_state.update({
150
+ "show_intro": True,
151
+ "selected_domain": "Candidate Intro + Project",
152
+ "current_question_index": 0,
153
+ "answers": [],
154
+ "evaluations": [],
155
+ "question_played": False
156
+ })
157
+ st.rerun()
158
+
159
+ # -----------------------------
160
+ # CANDIDATE INTRO WORKFLOW
161
+ # -----------------------------
162
+ if st.session_state.get("show_intro"):
163
+ st.header("🎯 Candidate Introduction + Project")
164
+
165
+ q_index = st.session_state["current_question_index"]
166
+ if q_index < len(CANDIDATE_QUESTIONS):
167
+ question = CANDIDATE_QUESTIONS[q_index]
168
+ st.subheader(f"Q{q_index+1}: {question['text']}")
169
+
170
+ # Generate audio
171
+ if not st.session_state["question_played"]:
172
+ audio_file = asyncio.run(generate_question_audio(question["text"]))
173
+ st.audio(audio_file, format="audio/mp3")
174
+ st.session_state["question_played"] = True
175
+
176
+ # Record answer
177
+ audio_data = st.audio_input("🎀 Record your answer here")
178
+ if audio_data:
179
+ audio_bytes = audio_data.read()
180
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as f:
181
+ f.write(audio_bytes)
182
+ wav_path = f.name
183
+ recognizer = sr.Recognizer()
184
+ with sr.AudioFile(wav_path) as source:
185
+ recorded_audio = recognizer.record(source)
186
+ try:
187
+ response_text = recognizer.recognize_google(recorded_audio)
188
+ st.session_state["current_response"] = response_text
189
+ st.success("βœ… Answer recorded. You can re-record or move to next question.")
190
+ except sr.UnknownValueError:
191
+ st.error("⚠️ Could not understand audio.")
192
+
193
+ # Buttons
194
+ col1, col2 = st.columns(2)
195
+ with col1:
196
+ if st.button("πŸ”„ Re-record Answer"):
197
+ st.session_state.pop("current_response", None)
198
+ st.session_state["question_played"] = False
199
+ st.experimental_rerun()
200
+ with col2:
201
+ if "current_response" in st.session_state and st.button("➑️ Next Question"):
202
+ st.session_state["answers"].append({
203
+ "question": question["text"],
204
+ "response": st.session_state.pop("current_response"),
205
+ "type": question["type"]
206
+ })
207
+ st.session_state["question_played"] = False
208
+ st.session_state["current_question_index"] += 1
209
+ st.rerun()
210
+
211
+ else:
212
+ # Evaluate all answers
213
+ if not st.session_state["evaluations"]:
214
+ for ans in st.session_state["answers"]:
215
+ st.session_state["evaluations"].append(evaluate_answer(ans["question"], ans["response"], ans["type"]))
216
+
217
+ st.subheader("πŸ“Š Mock Interview Completed")
218
+ total_score = sum([ev["score"] for ev in st.session_state["evaluations"]])
219
+ overall_score = round(total_score / len(st.session_state["evaluations"]), 2)
220
+ st.write(f"**Overall Average Score:** {overall_score}/10")
221
+ st.progress(overall_score / 10)
222
+
223
+ # Show answers & feedback
224
+ for i, ev in enumerate(st.session_state["evaluations"]):
225
+ st.write(f"**Q{i+1}: {ev['question']}**")
226
+ st.write(f"**A:** {ev['response']}")
227
+ st.write(f"**Score:** {ev['score']}/10")
228
+ st.write(ev["feedback"])
229
+ st.write("---")
230
+
231
+ # Improvement suggestions
232
+ if st.button("πŸ’‘ Generate Improvement Suggestions"):
233
+ generate_improvement_suggestions()
234
+ st.rerun()
235
+ if st.session_state.get("improvement_suggestions_generated"):
236
+ with st.expander("πŸ” Improvement Suggestions", expanded=True):
237
+ st.markdown(st.session_state["improvement_suggestions"])
238
+
239
+ # Download summary
240
+ def prepare_summary():
241
+ text = "# GrillMaster Candidate Intro Summary\n\n"
242
+ for i, ans in enumerate(st.session_state["answers"]):
243
+ text += f"**Q{i+1}: {ans['question']}**\n**A:** {ans['response']}\n**Score:** {st.session_state['evaluations'][i]['score']}/10\n\n"
244
+ if st.session_state.get("improvement_suggestions_generated"):
245
+ text += "## Improvement Suggestions:\n" + st.session_state["improvement_suggestions"]
246
+ return text.encode("utf-8")
247
+
248
+ st.download_button("πŸ’Ύ Download Summary", data=prepare_summary(),
249
+ file_name=f"GrillMaster_Summary_{time.strftime('%Y%m%d_%H%M')}.md",
250
+ mime="text/markdown")