Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -17,7 +17,8 @@ import traceback
|
|
| 17 |
from streamlit_webrtc import webrtc_streamer, WebRtcMode
|
| 18 |
from twilio.rest import Client
|
| 19 |
import logging
|
| 20 |
-
|
|
|
|
| 21 |
|
| 22 |
|
| 23 |
# ✅ MUST be the first Streamlit command
|
|
@@ -182,24 +183,17 @@ def generate_improvement_suggestions():
|
|
| 182 |
---
|
| 183 |
{cleaned_initial_evaluation}
|
| 184 |
---
|
| 185 |
-
|
| 186 |
Based on all this information, your task is to provide DETAILED and CONSTRUCTIVE suggestions for each question to help the candidate improve. Be supportive and encouraging.
|
| 187 |
-
|
| 188 |
For EACH question, please provide:
|
| 189 |
1. **How to Improve This Answer:** Specific, actionable advice on what the candidate could have added, clarified, or approached differently to make their answer better for their {level_string} level. Focus on 1-2 key improvement points.
|
| 190 |
2. **Hints for an Ideal Answer:** Briefly mention 2-3 key concepts, terms, or elements that a strong answer (appropriate for their {level_string} level) would typically include. DO NOT provide a full model answer, just hints and pointers.
|
| 191 |
-
|
| 192 |
Keep the tone positive and focused on learning.
|
| 193 |
-
|
| 194 |
Structure your response clearly for each question. Example for one question:
|
| 195 |
-
|
| 196 |
---
|
| 197 |
**Regarding Question X: "[Original Question Text Here]"**
|
| 198 |
-
|
| 199 |
*How to Improve This Answer:*
|
| 200 |
[Your specific suggestion 1 for improvement...]
|
| 201 |
[Your specific suggestion 2 for improvement...]
|
| 202 |
-
|
| 203 |
*Hints for an Ideal Answer (Key Points to Consider):*
|
| 204 |
- Hint 1 or Key concept 1
|
| 205 |
- Hint 2 or Key concept 2
|
|
@@ -289,15 +283,11 @@ def evaluate_answers():
|
|
| 289 |
hr_prompt_template = f"""
|
| 290 |
You are an experienced HR interview evaluator assessing a candidate's soft skills based on their answers to interview questions.
|
| 291 |
The candidate's performance across ALL answers should inform your scores for the following parameters.
|
| 292 |
-
|
| 293 |
**Parameters to Score (Assign a score from 1 to 5 for each):**
|
| 294 |
{hr_prompt_parameter_list}
|
| 295 |
-
|
| 296 |
After providing a score (1-5) for each of the above parameters, also write an **Overall Qualitative Feedback** section.
|
| 297 |
This section should summarize the candidate's general soft skill strengths and areas for improvement, based on their communication, engagement, and professionalism throughout the interview.
|
| 298 |
-
|
| 299 |
**REQUIRED OUTPUT FORMAT (Strictly Adhere):**
|
| 300 |
-
|
| 301 |
**Parameter Scores (1-5):**
|
| 302 |
Voice Modulation: [score]
|
| 303 |
Confidence: [score]
|
|
@@ -308,7 +298,6 @@ def evaluate_answers():
|
|
| 308 |
Basics of Grammar + SVA: [score]
|
| 309 |
Persuasiveness: [score]
|
| 310 |
Quality of Answers: [score]
|
| 311 |
-
|
| 312 |
**Overall Qualitative Feedback:**
|
| 313 |
[Your holistic qualitative feedback here. Be encouraging and constructive.]
|
| 314 |
"""
|
|
@@ -418,11 +407,9 @@ def evaluate_answers():
|
|
| 418 |
{base_assessment_criteria_qualitative_non_hr}
|
| 419 |
**YOUR RESPONSE MUST STRICTLY FOLLOW THIS FORMAT. PROVIDE SCORES FOR EACH QUESTION.**
|
| 420 |
Output format:
|
| 421 |
-
|
| 422 |
**Per-Question Scores:**
|
| 423 |
Question 1 Score: [Score for Q1 out of 5]
|
| 424 |
... (repeat for all {num_answered_questions} questions provided)
|
| 425 |
-
|
| 426 |
**Overall Evaluation Summary:**
|
| 427 |
- Concept Understanding: [Overall qualitative feedback here]
|
| 428 |
- Communication: [Overall qualitative feedback here]
|
|
@@ -502,7 +489,6 @@ def evaluate_answers():
|
|
| 502 |
BEGINNER_PROMPT = """
|
| 503 |
You are a friendly mock interview trainer conducting a **Beginner-level** spoken interview in the domain of **{domain}**.
|
| 504 |
Ask basic verbal interview questions based on the candidate's input: **{input_text}**.
|
| 505 |
-
|
| 506 |
Guidelines:
|
| 507 |
- Ask simple conceptual questions.
|
| 508 |
- Avoid jargon and complex examples.
|
|
@@ -511,7 +497,6 @@ Guidelines:
|
|
| 511 |
Ensure the questions are clear, to the point, and suitable for a {difficulty_level}-level interview in {selected_domain}.
|
| 512 |
**New Requirement:**
|
| 513 |
🚫 **Do NOT repeat any questions from previous generations again and again.** Ensure all generated questions are unique and different from past sessions.
|
| 514 |
-
|
| 515 |
**Guidelines:**
|
| 516 |
✅ Questions should focus on key concepts, best practices, and problem-solving within {selected_domain}.
|
| 517 |
✅ Ensure questions are direct, structured, and relevant to real-world applications.
|
|
@@ -522,7 +507,6 @@ Ensure the questions are clear, to the point, and suitable for a {difficulty_lev
|
|
| 522 |
INTERMEDIATE_PROMPT = """
|
| 523 |
You are a professional mock interviewer conducting an **Intermediate-level** spoken interview in the domain of **{domain}**.
|
| 524 |
Ask moderately challenging verbal interview questions based on the candidate's input: **{input_text}**.
|
| 525 |
-
|
| 526 |
Guidelines:
|
| 527 |
- Use a mix of conceptual and real-world scenario questions.
|
| 528 |
- Include light critical thinking.
|
|
@@ -530,7 +514,6 @@ Guidelines:
|
|
| 530 |
Ensure the questions are clear, to the point, and suitable for a {difficulty_level}-level interview in {selected_domain}.
|
| 531 |
**New Requirement:**
|
| 532 |
🚫 **Do NOT repeat any questions from previous generations again and again.** Ensure all generated questions are unique and different from past sessions.
|
| 533 |
-
|
| 534 |
**Guidelines:**
|
| 535 |
✅ Questions should focus on key concepts, best practices, and problem-solving within {selected_domain}.
|
| 536 |
✅ Ensure questions are direct, structured, and relevant to real-world applications.
|
|
@@ -541,15 +524,13 @@ Ensure the questions are clear, to the point, and suitable for a {difficulty_lev
|
|
| 541 |
ADVANCED_PROMPT = """
|
| 542 |
You are a strict mock interviewer conducting an **Advanced-level** spoken interview in the domain of **{domain}**.
|
| 543 |
Ask deep, analytical, real-world scenario-based questions from the candidate's input: **{input_text}**.
|
| 544 |
-
|
| 545 |
Guidelines:
|
| 546 |
- Expect detailed, logical, well-structured answers.
|
| 547 |
-
- Include challenging
|
| 548 |
- No need for code, but assume candidate has high expertise.
|
| 549 |
Ensure the questions are clear, to the point, and suitable for a {difficulty_level}-level interview in {selected_domain}.
|
| 550 |
**New Requirement:**
|
| 551 |
🚫 **Do NOT repeat any questions from previous generations again and again.** Ensure all generated questions are unique and different from past sessions.
|
| 552 |
-
|
| 553 |
**Guidelines:**
|
| 554 |
✅ Questions should focus on key concepts, best practices, and problem-solving within {selected_domain}.
|
| 555 |
✅ Ensure questions are direct, structured, and relevant to real-world applications.
|
|
@@ -588,7 +569,6 @@ st.markdown("""
|
|
| 588 |
box-shadow: 0 0 0 0.2rem rgba(0,123,255,.5) !important;
|
| 589 |
outline: none !important;
|
| 590 |
}
|
| 591 |
-
|
| 592 |
.timer-text {
|
| 593 |
font-size: 1.3rem;
|
| 594 |
font-weight: 600;
|
|
@@ -600,7 +580,6 @@ st.markdown("""
|
|
| 600 |
50% {opacity: 0.4;}
|
| 601 |
100% {opacity: 1;}
|
| 602 |
}
|
| 603 |
-
|
| 604 |
.summary-card {
|
| 605 |
background-color: #f9f9f9;
|
| 606 |
padding: 20px;
|
|
@@ -795,8 +774,8 @@ def get_ice_servers():
|
|
| 795 |
account_sid = os.environ["TWILIO_ACCOUNT_SID"]
|
| 796 |
auth_token = os.environ["TWILIO_AUTH_TOKEN"]
|
| 797 |
except KeyError:
|
| 798 |
-
|
| 799 |
-
"Twilio credentials are not set. Fallback to a free STUN server from Google."
|
| 800 |
)
|
| 801 |
return [{"urls": ["stun:stun.l.google.com:19302"]}]
|
| 802 |
|
|
@@ -870,39 +849,101 @@ if st.session_state["generated_questions"]:
|
|
| 870 |
if remaining > 0:
|
| 871 |
st.markdown(f"<h4 class='timer-text'>🎙️ {remaining} seconds to answer...</h4>", unsafe_allow_html=True)
|
| 872 |
|
| 873 |
-
|
| 874 |
-
|
| 875 |
-
|
| 876 |
-
|
| 877 |
-
|
| 878 |
-
|
| 879 |
-
|
| 880 |
-
|
| 881 |
-
|
| 882 |
-
|
| 883 |
-
|
| 884 |
-
|
| 885 |
-
|
| 886 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 887 |
|
| 888 |
-
|
| 889 |
-
|
| 890 |
-
|
| 891 |
-
|
| 892 |
-
"response": "[No response]"
|
| 893 |
-
})
|
| 894 |
-
|
| 895 |
-
st.session_state.update({
|
| 896 |
-
"record_phase": "idle",
|
| 897 |
-
"question_played": False,
|
| 898 |
-
"current_question_index": idx + 1
|
| 899 |
})
|
| 900 |
|
| 901 |
-
|
| 902 |
-
|
| 903 |
-
|
| 904 |
|
| 905 |
-
|
| 906 |
|
| 907 |
else:
|
| 908 |
st.markdown("<div style='padding:10px; background:#fff3e0; border-left:5px solid orange;'>⚠️ <strong>No response detected.</strong> Moving to next question...</div>", unsafe_allow_html=True)
|
|
@@ -920,23 +961,17 @@ if st.session_state["generated_questions"]:
|
|
| 920 |
st.rerun()
|
| 921 |
|
| 922 |
elif st.session_state["record_phase"] == "listening":
|
| 923 |
-
st.success("🎧
|
| 924 |
-
st.
|
| 925 |
-
|
| 926 |
-
st.session_state["answers"].append({
|
| 927 |
-
"question": question,
|
| 928 |
-
"response_file": st.session_state["response_file"],
|
| 929 |
-
"response_text": st.session_state.get("recorded_text", "")
|
| 930 |
-
})
|
| 931 |
-
|
| 932 |
st.session_state.update({
|
| 933 |
"record_phase": "idle",
|
|
|
|
| 934 |
"recording_started": False,
|
| 935 |
"question_played": False,
|
| 936 |
"question_start_time": 0.0,
|
| 937 |
"current_question_index": idx + 1
|
| 938 |
})
|
| 939 |
-
|
| 940 |
if st.session_state["current_question_index"] == len(st.session_state["generated_questions"]):
|
| 941 |
evaluate_answers()
|
| 942 |
st.session_state["show_summary"] = True
|
|
@@ -1083,4 +1118,4 @@ if st.session_state.get("show_summary", False):
|
|
| 1083 |
keys_to_fully_clear = list(st.session_state.keys())
|
| 1084 |
for key_to_del_full in keys_to_fully_clear:
|
| 1085 |
del st.session_state[key_to_del_full]
|
| 1086 |
-
|
|
|
|
| 17 |
from streamlit_webrtc import webrtc_streamer, WebRtcMode
|
| 18 |
from twilio.rest import Client
|
| 19 |
import logging
|
| 20 |
+
import numpy as np
|
| 21 |
+
import soundfile as sf
|
| 22 |
|
| 23 |
|
| 24 |
# ✅ MUST be the first Streamlit command
|
|
|
|
| 183 |
---
|
| 184 |
{cleaned_initial_evaluation}
|
| 185 |
---
|
|
|
|
| 186 |
Based on all this information, your task is to provide DETAILED and CONSTRUCTIVE suggestions for each question to help the candidate improve. Be supportive and encouraging.
|
|
|
|
| 187 |
For EACH question, please provide:
|
| 188 |
1. **How to Improve This Answer:** Specific, actionable advice on what the candidate could have added, clarified, or approached differently to make their answer better for their {level_string} level. Focus on 1-2 key improvement points.
|
| 189 |
2. **Hints for an Ideal Answer:** Briefly mention 2-3 key concepts, terms, or elements that a strong answer (appropriate for their {level_string} level) would typically include. DO NOT provide a full model answer, just hints and pointers.
|
|
|
|
| 190 |
Keep the tone positive and focused on learning.
|
|
|
|
| 191 |
Structure your response clearly for each question. Example for one question:
|
|
|
|
| 192 |
---
|
| 193 |
**Regarding Question X: "[Original Question Text Here]"**
|
|
|
|
| 194 |
*How to Improve This Answer:*
|
| 195 |
[Your specific suggestion 1 for improvement...]
|
| 196 |
[Your specific suggestion 2 for improvement...]
|
|
|
|
| 197 |
*Hints for an Ideal Answer (Key Points to Consider):*
|
| 198 |
- Hint 1 or Key concept 1
|
| 199 |
- Hint 2 or Key concept 2
|
|
|
|
| 283 |
hr_prompt_template = f"""
|
| 284 |
You are an experienced HR interview evaluator assessing a candidate's soft skills based on their answers to interview questions.
|
| 285 |
The candidate's performance across ALL answers should inform your scores for the following parameters.
|
|
|
|
| 286 |
**Parameters to Score (Assign a score from 1 to 5 for each):**
|
| 287 |
{hr_prompt_parameter_list}
|
|
|
|
| 288 |
After providing a score (1-5) for each of the above parameters, also write an **Overall Qualitative Feedback** section.
|
| 289 |
This section should summarize the candidate's general soft skill strengths and areas for improvement, based on their communication, engagement, and professionalism throughout the interview.
|
|
|
|
| 290 |
**REQUIRED OUTPUT FORMAT (Strictly Adhere):**
|
|
|
|
| 291 |
**Parameter Scores (1-5):**
|
| 292 |
Voice Modulation: [score]
|
| 293 |
Confidence: [score]
|
|
|
|
| 298 |
Basics of Grammar + SVA: [score]
|
| 299 |
Persuasiveness: [score]
|
| 300 |
Quality of Answers: [score]
|
|
|
|
| 301 |
**Overall Qualitative Feedback:**
|
| 302 |
[Your holistic qualitative feedback here. Be encouraging and constructive.]
|
| 303 |
"""
|
|
|
|
| 407 |
{base_assessment_criteria_qualitative_non_hr}
|
| 408 |
**YOUR RESPONSE MUST STRICTLY FOLLOW THIS FORMAT. PROVIDE SCORES FOR EACH QUESTION.**
|
| 409 |
Output format:
|
|
|
|
| 410 |
**Per-Question Scores:**
|
| 411 |
Question 1 Score: [Score for Q1 out of 5]
|
| 412 |
... (repeat for all {num_answered_questions} questions provided)
|
|
|
|
| 413 |
**Overall Evaluation Summary:**
|
| 414 |
- Concept Understanding: [Overall qualitative feedback here]
|
| 415 |
- Communication: [Overall qualitative feedback here]
|
|
|
|
| 489 |
BEGINNER_PROMPT = """
|
| 490 |
You are a friendly mock interview trainer conducting a **Beginner-level** spoken interview in the domain of **{domain}**.
|
| 491 |
Ask basic verbal interview questions based on the candidate's input: **{input_text}**.
|
|
|
|
| 492 |
Guidelines:
|
| 493 |
- Ask simple conceptual questions.
|
| 494 |
- Avoid jargon and complex examples.
|
|
|
|
| 497 |
Ensure the questions are clear, to the point, and suitable for a {difficulty_level}-level interview in {selected_domain}.
|
| 498 |
**New Requirement:**
|
| 499 |
🚫 **Do NOT repeat any questions from previous generations again and again.** Ensure all generated questions are unique and different from past sessions.
|
|
|
|
| 500 |
**Guidelines:**
|
| 501 |
✅ Questions should focus on key concepts, best practices, and problem-solving within {selected_domain}.
|
| 502 |
✅ Ensure questions are direct, structured, and relevant to real-world applications.
|
|
|
|
| 507 |
INTERMEDIATE_PROMPT = """
|
| 508 |
You are a professional mock interviewer conducting an **Intermediate-level** spoken interview in the domain of **{domain}**.
|
| 509 |
Ask moderately challenging verbal interview questions based on the candidate's input: **{input_text}**.
|
|
|
|
| 510 |
Guidelines:
|
| 511 |
- Use a mix of conceptual and real-world scenario questions.
|
| 512 |
- Include light critical thinking.
|
|
|
|
| 514 |
Ensure the questions are clear, to the point, and suitable for a {difficulty_level}-level interview in {selected_domain}.
|
| 515 |
**New Requirement:**
|
| 516 |
🚫 **Do NOT repeat any questions from previous generations again and again.** Ensure all generated questions are unique and different from past sessions.
|
|
|
|
| 517 |
**Guidelines:**
|
| 518 |
✅ Questions should focus on key concepts, best practices, and problem-solving within {selected_domain}.
|
| 519 |
✅ Ensure questions are direct, structured, and relevant to real-world applications.
|
|
|
|
| 524 |
ADVANCED_PROMPT = """
|
| 525 |
You are a strict mock interviewer conducting an **Advanced-level** spoken interview in the domain of **{domain}**.
|
| 526 |
Ask deep, analytical, real-world scenario-based questions from the candidate's input: **{input_text}**.
|
|
|
|
| 527 |
Guidelines:
|
| 528 |
- Expect detailed, logical, well-structured answers.
|
| 529 |
+
- Include challenging "why" and "how" based questions.
|
| 530 |
- No need for code, but assume candidate has high expertise.
|
| 531 |
Ensure the questions are clear, to the point, and suitable for a {difficulty_level}-level interview in {selected_domain}.
|
| 532 |
**New Requirement:**
|
| 533 |
🚫 **Do NOT repeat any questions from previous generations again and again.** Ensure all generated questions are unique and different from past sessions.
|
|
|
|
| 534 |
**Guidelines:**
|
| 535 |
✅ Questions should focus on key concepts, best practices, and problem-solving within {selected_domain}.
|
| 536 |
✅ Ensure questions are direct, structured, and relevant to real-world applications.
|
|
|
|
| 569 |
box-shadow: 0 0 0 0.2rem rgba(0,123,255,.5) !important;
|
| 570 |
outline: none !important;
|
| 571 |
}
|
|
|
|
| 572 |
.timer-text {
|
| 573 |
font-size: 1.3rem;
|
| 574 |
font-weight: 600;
|
|
|
|
| 580 |
50% {opacity: 0.4;}
|
| 581 |
100% {opacity: 1;}
|
| 582 |
}
|
|
|
|
| 583 |
.summary-card {
|
| 584 |
background-color: #f9f9f9;
|
| 585 |
padding: 20px;
|
|
|
|
| 774 |
account_sid = os.environ["TWILIO_ACCOUNT_SID"]
|
| 775 |
auth_token = os.environ["TWILIO_AUTH_TOKEN"]
|
| 776 |
except KeyError:
|
| 777 |
+
st.warning(
|
| 778 |
+
"Twilio credentials are not set. Fallback to a free STUN server from Google."
|
| 779 |
)
|
| 780 |
return [{"urls": ["stun:stun.l.google.com:19302"]}]
|
| 781 |
|
|
|
|
| 849 |
if remaining > 0:
|
| 850 |
st.markdown(f"<h4 class='timer-text'>🎙️ {remaining} seconds to answer...</h4>", unsafe_allow_html=True)
|
| 851 |
|
| 852 |
+
# Create two columns for recording options
|
| 853 |
+
col1, col2 = st.columns(2)
|
| 854 |
+
|
| 855 |
+
with col1:
|
| 856 |
+
st.markdown("**🎤 Voice Recording (WebRTC):**")
|
| 857 |
+
# Try WebRTC recording
|
| 858 |
+
try:
|
| 859 |
+
webrtc_ctx = webrtc_streamer(
|
| 860 |
+
key = f"webrtc_{idx}",
|
| 861 |
+
mode=WebRtcMode.SENDONLY,
|
| 862 |
+
audio_receiver_size=1024,
|
| 863 |
+
media_stream_constraints={"audio": True, "video": False},
|
| 864 |
+
rtc_configuration={"iceServers": get_ice_servers()},
|
| 865 |
+
)
|
| 866 |
+
|
| 867 |
+
if webrtc_ctx.state.playing:
|
| 868 |
+
if st.button("⏹️ Stop Voice Recording", key=f"stop_voice_{idx}"):
|
| 869 |
+
wav_path = f"response_{idx}.wav"
|
| 870 |
+
try:
|
| 871 |
+
frames = webrtc_ctx.audio_receiver.get_frames(timeout=1)
|
| 872 |
+
except Exception as e:
|
| 873 |
+
st.error(f"⚠️ Audio capture error: {e}")
|
| 874 |
+
frames = []
|
| 875 |
+
|
| 876 |
+
if frames:
|
| 877 |
+
try:
|
| 878 |
+
pcm = np.concatenate([f.to_ndarray() for f in frames], axis=0)
|
| 879 |
+
sample_rate = frames[0].sample_rate
|
| 880 |
+
sf.write(wav_path, pcm, sample_rate)
|
| 881 |
+
st.audio(wav_path)
|
| 882 |
+
st.session_state["answers"].append({
|
| 883 |
+
"question": question,
|
| 884 |
+
"response_file": wav_path
|
| 885 |
+
})
|
| 886 |
+
except Exception as e:
|
| 887 |
+
st.error(f"⚠��� Error saving recording: {e}")
|
| 888 |
+
st.session_state["answers"].append({
|
| 889 |
+
"question": question,
|
| 890 |
+
"response": "[Error saving recording]"
|
| 891 |
+
})
|
| 892 |
+
else:
|
| 893 |
+
st.warning("⚠️ No audio captured.")
|
| 894 |
+
st.session_state["answers"].append({
|
| 895 |
+
"question": question,
|
| 896 |
+
"response": "[No response]"
|
| 897 |
+
})
|
| 898 |
+
|
| 899 |
+
st.session_state.update({
|
| 900 |
+
"record_phase": "idle",
|
| 901 |
+
"question_played": False,
|
| 902 |
+
"current_question_index": idx + 1
|
| 903 |
+
})
|
| 904 |
+
|
| 905 |
+
if st.session_state["current_question_index"] == len(st.session_state["generated_questions"]):
|
| 906 |
+
evaluate_answers()
|
| 907 |
+
st.session_state["show_summary"] = True
|
| 908 |
+
|
| 909 |
+
st.experimental_rerun()
|
| 910 |
+
except Exception as webrtc_error:
|
| 911 |
+
st.warning("⚠️ Voice recording not available")
|
| 912 |
+
st.info("This is common on Hugging Face Spaces")
|
| 913 |
+
|
| 914 |
+
with col2:
|
| 915 |
+
st.markdown("**✍️ Text Input (Alternative):**")
|
| 916 |
+
# Always show text input as alternative
|
| 917 |
+
text_response = st.text_area(
|
| 918 |
+
f"Type your answer:",
|
| 919 |
+
key=f"text_response_{idx}",
|
| 920 |
+
height=150,
|
| 921 |
+
placeholder="Enter your response here..."
|
| 922 |
+
)
|
| 923 |
+
|
| 924 |
+
if st.button("✅ Submit Text Answer", key=f"submit_text_{idx}"):
|
| 925 |
+
if text_response.strip():
|
| 926 |
+
st.session_state["answers"].append({
|
| 927 |
+
"question": question,
|
| 928 |
+
"response": text_response.strip()
|
| 929 |
+
})
|
| 930 |
+
else:
|
| 931 |
+
st.session_state["answers"].append({
|
| 932 |
+
"question": question,
|
| 933 |
+
"response": "[No text response provided]"
|
| 934 |
+
})
|
| 935 |
|
| 936 |
+
st.session_state.update({
|
| 937 |
+
"record_phase": "idle",
|
| 938 |
+
"question_played": False,
|
| 939 |
+
"current_question_index": idx + 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 940 |
})
|
| 941 |
|
| 942 |
+
if st.session_state["current_question_index"] == len(st.session_state["generated_questions"]):
|
| 943 |
+
evaluate_answers()
|
| 944 |
+
st.session_state["show_summary"] = True
|
| 945 |
|
| 946 |
+
st.rerun()
|
| 947 |
|
| 948 |
else:
|
| 949 |
st.markdown("<div style='padding:10px; background:#fff3e0; border-left:5px solid orange;'>⚠️ <strong>No response detected.</strong> Moving to next question...</div>", unsafe_allow_html=True)
|
|
|
|
| 961 |
st.rerun()
|
| 962 |
|
| 963 |
elif st.session_state["record_phase"] == "listening":
|
| 964 |
+
st.success("🎧 Listening... You may stop when ready.")
|
| 965 |
+
if st.button("⏹️ Stop Recording"):
|
| 966 |
+
st.session_state["answers"].append({"question": question, "response": st.session_state["recorded_text"]})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 967 |
st.session_state.update({
|
| 968 |
"record_phase": "idle",
|
| 969 |
+
"recorded_text": "",
|
| 970 |
"recording_started": False,
|
| 971 |
"question_played": False,
|
| 972 |
"question_start_time": 0.0,
|
| 973 |
"current_question_index": idx + 1
|
| 974 |
})
|
|
|
|
| 975 |
if st.session_state["current_question_index"] == len(st.session_state["generated_questions"]):
|
| 976 |
evaluate_answers()
|
| 977 |
st.session_state["show_summary"] = True
|
|
|
|
| 1118 |
keys_to_fully_clear = list(st.session_state.keys())
|
| 1119 |
for key_to_del_full in keys_to_fully_clear:
|
| 1120 |
del st.session_state[key_to_del_full]
|
| 1121 |
+
|