Imarticuslearning commited on
Commit
d32f3a2
Β·
verified Β·
1 Parent(s): f1606ad

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +80 -75
app.py CHANGED
@@ -19,7 +19,6 @@ from twilio.rest import Client
19
  import logging
20
  import whisper
21
  import speech_recognition as sr
22
- from gtts import gTTS
23
  #model = whisper.load_model("base")
24
 
25
 
@@ -87,33 +86,12 @@ def get_questions(prompt, input_text, num_questions=3, max_retries=10):
87
 
88
  return new_questions
89
 
90
- async def generate_question_audio(question, voice="en-US-AriaNeural"):
91
  clean_question = re.sub(r'[^A-Za-z0-9.,?! ]+', '', question)
92
  tts = edge_tts.Communicate(text=clean_question, voice=voice)
93
  with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp_file:
94
- try:
95
- # πŸ”Ή Try Edge-TTS first
96
- tts = edge_tts.Communicate(text=clean_question, voice=voice)
97
- await tts.save(tmp_file.name)
98
- print("βœ… Edge-TTS audio generated successfully.")
99
- return tmp_file.name
100
-
101
- except Exception as e:
102
- print(f"⚠️ Edge-TTS failed: {e}")
103
- print("βͺ Falling back to Google TTS...")
104
-
105
- try:
106
- # πŸ”Ή Fallback: Google TTS (works inside Hugging Face)
107
- tts = gTTS(text=clean_question, lang="en")
108
- tts.save(tmp_file.name)
109
- print("βœ… gTTS fallback audio generated successfully.")
110
- return tmp_file.name
111
-
112
- except Exception as e2:
113
- print(f"❌ gTTS also failed: {e2}")
114
- return None
115
-
116
-
117
 
118
  ########################################///////////////////////////////////////////////////#########################################
119
 
@@ -413,41 +391,91 @@ def evaluate_answers():
413
  base_assessment_criteria_qualitative_non_hr = """
414
  For the OVERALL qualitative summary, assess responses based on:
415
  - Conceptual Understanding (effort and relevance more than perfect accuracy for the level)
416
- - Communication Clarity (can the core idea be understood?)
417
  - Depth of Explanation (relative to expected level)
418
- - Use of Examples (if any, and if appropriate for the level)
419
- - Logical Flow (is there a basic structure or train of thought?)
 
 
420
  """
421
  per_question_scoring_guidelines_non_hr = f"""
422
- For EACH question and its answer, provide a score from 0 to 5 points.
423
  The candidate is at a {level_string} level.
424
- Consider the following when assigning the per-question score:
425
- - Effort: Did the candidate attempt a meaningful answer, even if partially incorrect?
426
- - Relevance: Is the response at least partially related to the question topic?
427
- - Clarity of thought for the candidate's level.
428
- - Basic logical structure.
429
- - Use of examples, if any were given and appropriate.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
430
  """
431
  if level_string == "beginner":
432
  level_specific_instructions_non_hr = """
433
- You are an **extremely understanding, encouraging, and supportive** interview evaluator for a **BEGINNER/FRESHER**. Your primary goal is to **build confidence**.
434
- **Scoring Guidelines for Beginners (0-5 points per question):**
435
- - **5 points:** Accurate, clear, and well-structured answer. Shows clear effort and basic understanding.
436
- - **4 points:** Mostly correct with minor gaps or unclear phrasing.Good attempt, relevant, shows some understanding or key terms (e.g., one/two relevant words).
437
- - **3 points:** Partially correct with evident effort, but lacks clarity or completeness.
438
- - **1-2 points:** Minimal effort, mostly irrelevant, but an attempt beyond silence.
439
- - **0 points:** Candidate explicitly says "I don’t know", "I'm not sure", or provides placeholder/non-answers. No relevant effort or understanding shown.Incorrect or unrelated.
440
- Provide VERY positive feedback.
 
 
 
 
441
  """
442
  elif level_string == "intermediate":
443
- level_specific_instructions_non_hr = """Supportive evaluator for **INTERMEDIATE**. Scoring (0-5): 5=Correct/Clear; 3-4=Mostly correct; 1-2=Partial/Gaps; 0=Incorrect."""
 
 
 
 
 
 
 
 
 
 
 
 
444
  else: # Advanced
445
- level_specific_instructions_non_hr = """Discerning evaluator for **ADVANCED**. Scoring (0-5): 5=Accurate/Comprehensive; 3-4=Correct lacks nuance; 1-2=Inaccurate; 0=Fundamentally incorrect."""
 
 
 
 
 
 
 
 
 
 
 
 
446
 
447
  evaluation_prompt_template_non_hr = f"""
448
  {level_specific_instructions_non_hr}
449
  {per_question_scoring_guidelines_non_hr}
450
  {base_assessment_criteria_qualitative_non_hr}
 
 
 
 
 
451
  **YOUR RESPONSE MUST STRICTLY FOLLOW THIS FORMAT. PROVIDE SCORES FOR EACH QUESTION.**
452
  Output format:
453
 
@@ -461,7 +489,10 @@ def evaluate_answers():
461
  - Depth of Explanation: [Overall qualitative feedback here]
462
  - Examples: [Overall qualitative feedback here]
463
  - Logical Flow: [Overall qualitative feedback here]
 
464
  [Any additional overall encouraging remarks can optionally follow here]
 
 
465
  """
466
  candidate_responses_formatted_non_hr = "\n\n".join(
467
  [f"Question {i+1}: {entry['question']}\nAnswer {i+1}: {str(entry.get('response', '[No response provided]'))}" for i, entry in enumerate(st.session_state["answers"])]
@@ -966,7 +997,7 @@ if st.session_state.get("generated_questions"):
966
 
967
  # Phase 2: Waiting to Start Recording
968
  elif st.session_state["record_phase"] == "waiting_to_start":
969
- remaining = 20 - int(elapsed)
970
  if remaining > 0:
971
  st.markdown(f"<h4 class='timer-text'>⏳ {remaining} seconds to click 'Start Recording'...</h4>", unsafe_allow_html=True)
972
  if st.button("πŸŽ™οΈ Start Recording"):
@@ -1078,23 +1109,6 @@ if st.session_state.get("show_summary", False):
1078
  current_percentage_score = st.session_state.get('percentage_score', 0.0)
1079
  current_overall_score = st.session_state.get('overall_score', 0.0)
1080
 
1081
- # --- Retrieve stored configuration info ---
1082
- selected_domain = st.session_state.get("selected_domain", "N/A")
1083
- input_type = st.session_state.get("section_choice", st.session_state.get("soft_skill_mode", "N/A"))
1084
- difficulty_level = st.session_state.get("difficulty_level_select", "N/A")
1085
- total_questions_selected = st.session_state.get("num_qs", num_qs_in_session)
1086
- selected_company = st.session_state.get("selected_company")
1087
- selected_job_role = st.session_state.get("selected_job_role")
1088
-
1089
- # --- Display configuration summary ---
1090
- st.markdown("### βš™οΈ Test Configuration Summary")
1091
- st.markdown(f"""
1092
- - **Domain Selected:** {selected_domain}
1093
- - **Input Type / Mode:** {section_choice}
1094
- - **Difficulty Level / Job Role:** {difficulty_level if selected_domain != "Finance" else job_roles}
1095
- - **Total Questions Selected:** {total_questions_selected}
1096
- """)
1097
-
1098
  if st.session_state["selected_domain"] == "Soft Skills":
1099
  hr_table_data = []
1100
  for param, config in HR_PARAMETERS_CONFIG.items():
@@ -1181,19 +1195,10 @@ if st.session_state.get("show_summary", False):
1181
 
1182
  # Helper function to prepare summary text for download
1183
  def prepare_summary_for_download():
1184
- #download_text = f"# GrillMaster Mock Interview Summary\n\n"
1185
- #download_text += f"**Selected Domain:** {st.session_state.get('selected_domain', 'N/A')}\n"
1186
- #dl_difficulty = st.session_state.get('difficulty_level_select', 'N/A')
1187
- #download_text += f"**Difficulty Level:** {dl_difficulty}\n"
1188
  download_text = f"# GrillMaster Mock Interview Summary\n\n"
1189
- download_text += f"**Selected Domain:** {selected_domain}\n"
1190
- download_text += f"**Input Type** {section_choice}\n"
1191
- download_text += f"**Difficulty Level / Job Role:** {difficulty_level if selected_domain != 'Finance' else job_roles}\n"
1192
- download_text += f"**Total Questions Selected:** {total_questions_selected}\n"
1193
- download_text += f"**Company Selected:** {selected_company}\n"
1194
- download_text += f"**Job Role:** {selected_job_role}\n"
1195
- #download_text += f"**Calculated Overall Score:** {current_overall_score:.1f} / {max_score_possible_for_session:.1f} ({current_percentage_score:.1f}%)\n\n"
1196
- download_text += "## Questions & Candidate's Answers:\n"
1197
 
1198
  num_q_for_max_score = len(st.session_state.get("generated_questions", st.session_state.get("answers",[])))
1199
  max_s_for_dl = num_q_for_max_score * 5.0
 
19
  import logging
20
  import whisper
21
  import speech_recognition as sr
 
22
  #model = whisper.load_model("base")
23
 
24
 
 
86
 
87
  return new_questions
88
 
89
+ async def generate_question_audio(question, voice="en-IE-EmilyNeural"):
90
  clean_question = re.sub(r'[^A-Za-z0-9.,?! ]+', '', question)
91
  tts = edge_tts.Communicate(text=clean_question, voice=voice)
92
  with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp_file:
93
+ await tts.save(tmp_file.name)
94
+ return tmp_file.name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
  ########################################///////////////////////////////////////////////////#########################################
97
 
 
391
  base_assessment_criteria_qualitative_non_hr = """
392
  For the OVERALL qualitative summary, assess responses based on:
393
  - Conceptual Understanding (effort and relevance more than perfect accuracy for the level)
394
+ - Communication Clarity (is the idea understandable and logically stated?)
395
  - Depth of Explanation (relative to expected level)
396
+ - Use of Examples (if any, and appropriate for the level)
397
+ - Logical Flow (basic structure or reasoning flow)
398
+
399
+ Focus on both understanding and reasoning. Responses should demonstrate thinking, not memorization.
400
  """
401
  per_question_scoring_guidelines_non_hr = f"""
402
+ For EACH question and its answer, assign a score from 0 to 5 points.
403
  The candidate is at a {level_string} level.
404
+ Use the numeric scale and notes below for calibration.
405
+
406
+ **Scoring Scale (per question):**
407
+ - **5 (Excellent / 90–100%)** β†’ Comprehensive, accurate, and well-structured. Includes reasoning or an example. Rare and well-deserved.
408
+ - **4 (Good / 75–89%)** β†’ Mostly correct, relevant, and clear. Minor conceptual gaps but good structure.
409
+ - **3 (Fair / 60–74%)** β†’ Partially correct or lacks depth, but shows understanding and effort.
410
+ - **2 (Basic / 45–59%)** β†’ One-line or short answer with minimal reasoning; incomplete or overly generic.
411
+ - **1 (Poor / 30–44%)** β†’ Attempted but largely irrelevant or unclear.
412
+ - **0 (No Effort / <30%)** β†’ Incorrect, off-topic, or explicitly β€œI don’t know”.
413
+
414
+ **Important Rules:**
415
+ - *One-word or one-line answers* (e.g., just definitions or keywords) must NOT score more than **2 out of 5**, regardless of correctness, because they lack reasoning and depth.
416
+ - Encourage clarity, structure, and explanation over memorized phrases.
417
+ """
418
+ scoring_tightness_guidelines = """
419
+ **Scoring Calibration (Strictness Guidance):**
420
+ - Maintain a slightly tight scoring approach.
421
+ - Incomplete or short one-line answers score **below 60% (1–2 out of 5)**.
422
+ - Scores of **5/5 (100%)** should be **rare** β€” reserved for comprehensive, insightful, and well-reasoned answers.
423
+ - Most competent answers should fall between **3 and 4**.
424
+ - When unsure, choose the **lower score** to maintain scoring consistency.
425
  """
426
  if level_string == "beginner":
427
  level_specific_instructions_non_hr = """
428
+ You are a **supportive, understanding evaluator** for a **BEGINNER/FRESHER**.
429
+ Focus on clarity, effort, and attempt β€” not perfection.
430
+ Encourage learning through feedback, but ensure fair scoring.
431
+
432
+ **Scoring Guidelines (0–5):**
433
+ - **5** β†’ Accurate, clear, well-structured, and shows strong effort and reasoning. Rare.
434
+ - **4** β†’ Mostly correct, relevant, and shows basic reasoning or understanding.
435
+ - **3** β†’ Partial correctness with effort; may lack completeness or flow.
436
+ - **1–2** β†’ One-line or definition-only answers; minimal reasoning. (Below 60%)
437
+ - **0** β†’ No effort or irrelevant response.
438
+ Avoid giving high scores to short, memorized, or definition-only responses.
439
+ Provide motivating feedback that highlights areas of improvement.
440
  """
441
  elif level_string == "intermediate":
442
+ level_specific_instructions_non_hr = """
443
+ You are a **balanced and fair evaluator** for an **INTERMEDIATE** candidate.
444
+ Expect conceptual clarity, structured reasoning, and relevant examples.
445
+ Be encouraging yet objective in scoring.
446
+
447
+ **Scoring Guidelines (0–5):**
448
+ - **5** β†’ Clear, accurate, structured response with reasoning and relevance. Rare.
449
+ - **4** β†’ Mostly correct with some logical structure and explanation.
450
+ - **3** β†’ Some understanding; missing clarity or key detail.
451
+ - **1–2** β†’ Short, definition-like, or minimal response. (Below 60%)
452
+ - **0** β†’ Irrelevant or incorrect.
453
+ Never assign high scores to one-line or superficial answers.
454
+ """
455
  else: # Advanced
456
+ level_specific_instructions_non_hr = """
457
+ You are a **discerning but fair evaluator** for an **ADVANCED** professional.
458
+ Expect precision, applied understanding, and structured reasoning.
459
+ Maintain fairness without excessive strictness.
460
+
461
+ **Scoring Guidelines (0–5):**
462
+ - **5** β†’ Exceptionally comprehensive, insightful, and accurate. (Rare)
463
+ - **4** β†’ Correct and well-reasoned; may lack minor nuance or application.
464
+ - **3** β†’ Adequate but missing depth, structure, or examples.
465
+ - **1–2** β†’ Generic, incomplete, or one-line responses without reasoning. (Below 60%)
466
+ - **0** β†’ Fundamentally incorrect or irrelevant.
467
+ Be concise and consistent in judgment; reward depth, not brevity.
468
+ """
469
 
470
  evaluation_prompt_template_non_hr = f"""
471
  {level_specific_instructions_non_hr}
472
  {per_question_scoring_guidelines_non_hr}
473
  {base_assessment_criteria_qualitative_non_hr}
474
+ {scoring_tightness_guidelines}
475
+
476
+ When evaluating, be supportive yet fair. Encourage clarity and effort but avoid over-rewarding shallow or memorized answers.
477
+ Maintain a balanced tone β€” neither too strict nor too lenient.
478
+
479
  **YOUR RESPONSE MUST STRICTLY FOLLOW THIS FORMAT. PROVIDE SCORES FOR EACH QUESTION.**
480
  Output format:
481
 
 
489
  - Depth of Explanation: [Overall qualitative feedback here]
490
  - Examples: [Overall qualitative feedback here]
491
  - Logical Flow: [Overall qualitative feedback here]
492
+ - Final Remarks: [Brief encouraging but fair closing note]
493
  [Any additional overall encouraging remarks can optionally follow here]
494
+
495
+ Provide the final tone as **professional, balanced, and confidence-building**.
496
  """
497
  candidate_responses_formatted_non_hr = "\n\n".join(
498
  [f"Question {i+1}: {entry['question']}\nAnswer {i+1}: {str(entry.get('response', '[No response provided]'))}" for i, entry in enumerate(st.session_state["answers"])]
 
997
 
998
  # Phase 2: Waiting to Start Recording
999
  elif st.session_state["record_phase"] == "waiting_to_start":
1000
+ remaining = 15 - int(elapsed)
1001
  if remaining > 0:
1002
  st.markdown(f"<h4 class='timer-text'>⏳ {remaining} seconds to click 'Start Recording'...</h4>", unsafe_allow_html=True)
1003
  if st.button("πŸŽ™οΈ Start Recording"):
 
1109
  current_percentage_score = st.session_state.get('percentage_score', 0.0)
1110
  current_overall_score = st.session_state.get('overall_score', 0.0)
1111
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1112
  if st.session_state["selected_domain"] == "Soft Skills":
1113
  hr_table_data = []
1114
  for param, config in HR_PARAMETERS_CONFIG.items():
 
1195
 
1196
  # Helper function to prepare summary text for download
1197
  def prepare_summary_for_download():
 
 
 
 
1198
  download_text = f"# GrillMaster Mock Interview Summary\n\n"
1199
+ download_text += f"**Selected Domain:** {st.session_state.get('selected_domain', 'N/A')}\n"
1200
+ dl_difficulty = st.session_state.get('difficulty_level_select', 'N/A')
1201
+ download_text += f"**Difficulty Level:** {dl_difficulty}\n"
 
 
 
 
 
1202
 
1203
  num_q_for_max_score = len(st.session_state.get("generated_questions", st.session_state.get("answers",[])))
1204
  max_s_for_dl = num_q_for_max_score * 5.0