Spaces:
Paused
Paused
Commit Β·
df70548
1
Parent(s): 97b533c
fix: remove trigger word, always auto-submit on recording stop
Browse files- Remove trigger phrase logic (answer me, etc.)
- Wire both .stop_recording() and .change() for reliability
- Answer generates automatically when user stops talking
- No manual button click needed for voice questions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
app.py
CHANGED
|
@@ -542,7 +542,7 @@ with gr.Blocks(title="MomsVoice", css=css_code) as demo:
|
|
| 542 |
with gr.Group(visible=False) as qa_input_group:
|
| 543 |
question_audio = gr.Audio(
|
| 544 |
sources=["microphone"], type="filepath",
|
| 545 |
-
label="π€ Ask your question
|
| 546 |
show_label=True, streaming=False,
|
| 547 |
elem_id="qa_audio_input",
|
| 548 |
)
|
|
@@ -1019,10 +1019,7 @@ with gr.Blocks(title="MomsVoice", css=css_code) as demo:
|
|
| 1019 |
}"""
|
| 1020 |
)
|
| 1021 |
|
| 1022 |
-
# 9. Submit question
|
| 1023 |
-
# Trigger phrase: user says "answer me" to signal end of question
|
| 1024 |
-
_TRIGGER_PHRASES = ["answer me", "answer this", "tell me"]
|
| 1025 |
-
|
| 1026 |
def handle_question_submit(question_txt, question_audio_path, paragraphs, slider_val, profile_id):
|
| 1027 |
q_txt = (question_txt or "").strip()
|
| 1028 |
has_audio = question_audio_path is not None and question_audio_path != ""
|
|
@@ -1046,27 +1043,6 @@ with gr.Blocks(title="MomsVoice", css=css_code) as demo:
|
|
| 1046 |
except Exception as e:
|
| 1047 |
q_text = f"(transcription failed: {e})"
|
| 1048 |
|
| 1049 |
-
# Check for trigger phrase β if not found in voice input, wait for it
|
| 1050 |
-
q_lower = q_text.lower().strip()
|
| 1051 |
-
has_trigger = any(trigger in q_lower for trigger in _TRIGGER_PHRASES)
|
| 1052 |
-
|
| 1053 |
-
if has_audio and not q_txt and not has_trigger:
|
| 1054 |
-
# No trigger phrase detected β show transcription and wait
|
| 1055 |
-
safe_q = html.escape(q_text)
|
| 1056 |
-
waiting_html = f"""
|
| 1057 |
-
<div style="padding: 12px; background: rgba(245,132,31,0.1); border: 1px solid rgba(245,132,31,0.3); border-radius: 10px; font-size: 12px; color: #f5841f;">
|
| 1058 |
-
π€ Heard: “<em>{safe_q}</em>”<br>
|
| 1059 |
-
<span style="font-size: 11px; color: #94a3b8;">Say <strong>“answer me”</strong> to get the answer, or keep recording.</span>
|
| 1060 |
-
</div>
|
| 1061 |
-
"""
|
| 1062 |
-
return gr.HTML(value=waiting_html, visible=True), gr.Audio(visible=False)
|
| 1063 |
-
|
| 1064 |
-
# Strip trigger phrase from the question text
|
| 1065 |
-
for trigger in _TRIGGER_PHRASES:
|
| 1066 |
-
q_text = re.sub(rf'\b{trigger}\b[.!?,\s]*', '', q_text, flags=re.IGNORECASE).strip()
|
| 1067 |
-
if not q_text:
|
| 1068 |
-
q_text = "What happens next in the story?"
|
| 1069 |
-
|
| 1070 |
# Step 10: Generate grounded answer from story context using Qwen
|
| 1071 |
current_idx = int(slider_val) if slider_val else 0
|
| 1072 |
try:
|
|
@@ -1124,17 +1100,23 @@ with gr.Blocks(title="MomsVoice", css=css_code) as demo:
|
|
| 1124 |
outputs=[answer_display, answer_audio]
|
| 1125 |
)
|
| 1126 |
|
| 1127 |
-
# Auto-submit when voice recording completes
|
| 1128 |
-
|
| 1129 |
-
|
| 1130 |
-
def auto_submit_on_audio_change(audio_path, question_txt, paragraphs, slider_val, profile_id):
|
| 1131 |
-
"""Auto-submit only when a new recording is available (not on clear)."""
|
| 1132 |
if not audio_path:
|
| 1133 |
return gr.update(), gr.update()
|
| 1134 |
return handle_question_submit(question_txt, audio_path, paragraphs, slider_val, profile_id)
|
| 1135 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1136 |
question_audio.change(
|
| 1137 |
-
|
| 1138 |
inputs=[question_audio, question_text, paragraphs_state, timeline_slider, voice_profile_state],
|
| 1139 |
outputs=[answer_display, answer_audio]
|
| 1140 |
)
|
|
|
|
| 542 |
with gr.Group(visible=False) as qa_input_group:
|
| 543 |
question_audio = gr.Audio(
|
| 544 |
sources=["microphone"], type="filepath",
|
| 545 |
+
label="π€ Ask your question β answer generates automatically when you stop",
|
| 546 |
show_label=True, streaming=False,
|
| 547 |
elem_id="qa_audio_input",
|
| 548 |
)
|
|
|
|
| 1019 |
}"""
|
| 1020 |
)
|
| 1021 |
|
| 1022 |
+
# 9. Submit question β always auto-submits when recording stops
|
|
|
|
|
|
|
|
|
|
| 1023 |
def handle_question_submit(question_txt, question_audio_path, paragraphs, slider_val, profile_id):
|
| 1024 |
q_txt = (question_txt or "").strip()
|
| 1025 |
has_audio = question_audio_path is not None and question_audio_path != ""
|
|
|
|
| 1043 |
except Exception as e:
|
| 1044 |
q_text = f"(transcription failed: {e})"
|
| 1045 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1046 |
# Step 10: Generate grounded answer from story context using Qwen
|
| 1047 |
current_idx = int(slider_val) if slider_val else 0
|
| 1048 |
try:
|
|
|
|
| 1100 |
outputs=[answer_display, answer_audio]
|
| 1101 |
)
|
| 1102 |
|
| 1103 |
+
# Auto-submit when voice recording completes β use BOTH events for reliability
|
| 1104 |
+
def auto_submit_on_audio(audio_path, question_txt, paragraphs, slider_val, profile_id):
|
| 1105 |
+
"""Auto-submit when a recording is available."""
|
|
|
|
|
|
|
| 1106 |
if not audio_path:
|
| 1107 |
return gr.update(), gr.update()
|
| 1108 |
return handle_question_submit(question_txt, audio_path, paragraphs, slider_val, profile_id)
|
| 1109 |
|
| 1110 |
+
# .stop_recording fires when user clicks stop or silence detected
|
| 1111 |
+
question_audio.stop_recording(
|
| 1112 |
+
auto_submit_on_audio,
|
| 1113 |
+
inputs=[question_audio, question_text, paragraphs_state, timeline_slider, voice_profile_state],
|
| 1114 |
+
outputs=[answer_display, answer_audio]
|
| 1115 |
+
)
|
| 1116 |
+
|
| 1117 |
+
# .change fires after audio value is committed β backup in case stop_recording misses
|
| 1118 |
question_audio.change(
|
| 1119 |
+
auto_submit_on_audio,
|
| 1120 |
inputs=[question_audio, question_text, paragraphs_state, timeline_slider, voice_profile_state],
|
| 1121 |
outputs=[answer_display, answer_audio]
|
| 1122 |
)
|