Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -113,44 +113,50 @@ if user_input:
|
|
113 |
messages_response = client.beta.threads.messages.list(thread_id=thread_id)
|
114 |
latest_response = sorted(messages_response.data, key=lambda x: x.created_at)[-1]
|
115 |
assistant_message = latest_response.content[0].text.value
|
116 |
-
save_message("assistant", assistant_message)
|
117 |
-
|
118 |
-
# π Voice controls (after displaying the message)
|
119 |
-
st.components.v1.html(f"""
|
120 |
-
<div id="voice-controls" style="margin: 10px 0;">
|
121 |
-
<button id="speak-btn" style="margin-right:10px;">π Speak</button>
|
122 |
-
<button id="mute-btn">π Mute</button>
|
123 |
-
</div>
|
124 |
-
<script>
|
125 |
-
var utterance;
|
126 |
-
var isSpeaking = false;
|
127 |
-
var synth = window.speechSynthesis;
|
128 |
-
var text = `{assistant_message.replace("`", "\\`")}`;
|
129 |
-
var voices = [];
|
130 |
-
function getFemaleVoice() {{
|
131 |
-
voices = synth.getVoices();
|
132 |
-
let female = voices.find(v => v.name.includes("Female") || (v.name.includes("en") && v.gender !== "male"));
|
133 |
-
return female || voices.find(v => v.lang.startsWith('en') && v.name.toLowerCase().includes('female')) || voices[0];
|
134 |
-
}}
|
135 |
-
|
136 |
-
document.getElementById('speak-btn').onclick = function() {{
|
137 |
-
if (isSpeaking) return;
|
138 |
-
utterance = new SpeechSynthesisUtterance(text);
|
139 |
-
utterance.voice = getFemaleVoice();
|
140 |
-
utterance.rate = 1;
|
141 |
-
utterance.pitch = 1.1;
|
142 |
-
synth.speak(utterance);
|
143 |
-
isSpeaking = true;
|
144 |
-
utterance.onend = function() {{ isSpeaking = false; }};
|
145 |
-
}};
|
146 |
-
|
147 |
-
document.getElementById('mute-btn').onclick = function() {{
|
148 |
-
synth.cancel();
|
149 |
-
isSpeaking = false;
|
150 |
-
}};
|
151 |
-
</script>
|
152 |
-
""", height=60)
|
153 |
-
|
154 |
-
time.sleep(0.5)
|
155 |
-
st.rerun()
|
156 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
messages_response = client.beta.threads.messages.list(thread_id=thread_id)
|
114 |
latest_response = sorted(messages_response.data, key=lambda x: x.created_at)[-1]
|
115 |
assistant_message = latest_response.content[0].text.value
|
116 |
+
save_message("assistant", assistant_message)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
|
118 |
+
# Prepare the message for JavaScript safely
|
119 |
+
safe_message = assistant_message.replace("\\", "\\\\").replace("`", "\\`").replace("\n", "\\n").replace("'", "\\'")
|
120 |
+
|
121 |
+
# π Voice controls (auto-speak enabled)
|
122 |
+
st.components.v1.html(f"""
|
123 |
+
<div id="voice-controls" style="margin: 10px 0;">
|
124 |
+
<button id="speak-btn" style="margin-right:10px;">π Speak</button>
|
125 |
+
<button id="mute-btn">π Mute</button>
|
126 |
+
</div>
|
127 |
+
<script>
|
128 |
+
var utterance;
|
129 |
+
var isSpeaking = false;
|
130 |
+
var synth = window.speechSynthesis;
|
131 |
+
var text = `{safe_message}`;
|
132 |
+
var voices = [];
|
133 |
+
function getFemaleVoice() {{
|
134 |
+
voices = synth.getVoices();
|
135 |
+
let female = voices.find(v => (v.name && v.name.toLowerCase().includes("female")) || (v.lang && v.lang.startsWith("en") && v.gender !== "male"));
|
136 |
+
// Fallback: any en female, then any en, then first
|
137 |
+
return female || voices.find(v => v.lang && v.lang.startsWith('en') && v.name && v.name.toLowerCase().includes('female')) || voices.find(v => v.lang && v.lang.startsWith('en')) || voices[0];
|
138 |
+
}}
|
139 |
+
function speakText() {{
|
140 |
+
if (isSpeaking) return;
|
141 |
+
utterance = new SpeechSynthesisUtterance(text);
|
142 |
+
utterance.voice = getFemaleVoice();
|
143 |
+
utterance.rate = 1;
|
144 |
+
utterance.pitch = 1.1;
|
145 |
+
synth.speak(utterance);
|
146 |
+
isSpeaking = true;
|
147 |
+
utterance.onend = function() {{ isSpeaking = false; }};
|
148 |
+
}}
|
149 |
+
document.getElementById('speak-btn').onclick = function() {{
|
150 |
+
speakText();
|
151 |
+
}};
|
152 |
+
document.getElementById('mute-btn').onclick = function() {{
|
153 |
+
synth.cancel();
|
154 |
+
isSpeaking = false;
|
155 |
+
}};
|
156 |
+
// Auto-speak on load
|
157 |
+
setTimeout(speakText, 500);
|
158 |
+
</script>
|
159 |
+
""", height=80)
|
160 |
+
|
161 |
+
time.sleep(0.5)
|
162 |
+
st.rerun()
|