Peter Michael Gits Claude commited on
Commit
ae83ce7
Β·
1 Parent(s): ef88eec

debug: Simplify VoiceCal to isolate restart issue cause

Browse files

- Remove complex JavaScript WebRTC integration temporarily
- Create minimal Streamlit interface for startup debugging
- Backup original version as streamlit_websocket_app.py.backup
- Add test_streamlit_simple.py for isolated testing
- Focus on basic Streamlit functionality first
- Will re-add WebRTC after confirming basic startup works

πŸ€– Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

streamlit_websocket_app.py CHANGED
@@ -1,16 +1,10 @@
1
  #!/usr/bin/env python3
2
  """
3
  Streamlit app with embedded WebSocket server for VoiceCal WebRTC
4
- Single-service approach for HuggingFace Spaces compatibility
5
  """
6
 
7
  import streamlit as st
8
- import asyncio
9
- import threading
10
- import json
11
- import sys
12
- from datetime import datetime
13
- import os
14
 
15
  # Configure Streamlit page
16
  st.set_page_config(
@@ -45,325 +39,12 @@ def main():
45
  st.markdown("---")
46
  st.header("🌐 WebRTC Voice Interface")
47
 
48
- # Simplified WebRTC interface that connects directly to STT service
49
- webrtc_html = """
50
- <div id="voice-interface" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 20px; border-radius: 10px; margin: 20px 0;">
51
- <h3 style="color: white; margin-top: 0;">🎀 Voice Interface (Direct STT Connection)</h3>
52
-
53
- <div style="display: flex; gap: 10px; margin: 20px 0;">
54
- <button id="start-recording" style="background: #ff4757; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer;">
55
- πŸŽ™οΈ Start Recording
56
- </button>
57
- <button id="stop-recording" style="background: #2f3542; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer;" disabled>
58
- ⏹️ Stop Recording
59
- </button>
60
- <button id="test-connection" style="background: #5352ed; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer;">
61
- πŸ”— Test STT Connection
62
- </button>
63
- </div>
64
-
65
- <div id="status" style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 5px; color: white; font-family: monospace;">
66
- Status: Ready to connect to STT service...
67
- </div>
68
-
69
- <div id="transcription" style="background: rgba(255,255,255,0.9); padding: 15px; border-radius: 5px; margin-top: 10px; min-height: 50px;">
70
- <strong>Transcription:</strong> <span id="transcription-text">Ready for voice input...</span>
71
- </div>
72
- </div>
73
-
74
- <script>
75
- // Direct STT WebSocket Connection (unmute.sh Pattern)
76
- class VoiceCalDirectSTT {
77
- constructor() {
78
- this.sttWebSocket = null;
79
- this.mediaRecorder = null;
80
- this.audioChunks = [];
81
- this.isRecording = false;
82
- this.clientId = 'voicecal-' + Math.random().toString(36).substr(2, 9);
83
- // Connect to standalone WebSocket STT service v1.0.0
84
- this.sttWebSocketUrl = 'wss://pgits-stt-gpu-service.hf.space/ws/stt';
85
-
86
- this.setupEventListeners();
87
- }
88
-
89
- setupEventListeners() {
90
- document.getElementById('start-recording').addEventListener('click', () => {
91
- this.startRecording();
92
- });
93
-
94
- document.getElementById('stop-recording').addEventListener('click', () => {
95
- this.stopRecording();
96
- });
97
-
98
- document.getElementById('test-connection').addEventListener('click', () => {
99
- this.testSTTConnection();
100
- });
101
- }
102
-
103
- async testSTTConnection() {
104
- this.updateStatus('πŸ”— Testing WebSocket STT service connection...');
105
-
106
- try {
107
- // Test WebSocket connection to standalone STT service v1.0.0
108
- const testSocket = new WebSocket(this.sttWebSocketUrl);
109
-
110
- testSocket.onopen = () => {
111
- this.updateStatus('βœ… STT WebSocket connection successful!');
112
- console.log('STT service WebSocket is ready');
113
- testSocket.close();
114
- };
115
-
116
- testSocket.onerror = (error) => {
117
- this.updateStatus('❌ STT WebSocket connection failed');
118
- console.error('STT WebSocket error:', error);
119
- };
120
-
121
- } catch (error) {
122
- this.updateStatus('❌ Failed to test STT WebSocket connection');
123
- console.error('STT connection test error:', error);
124
- }
125
- }
126
-
127
- async connectToSTT() {
128
- this.updateStatus('πŸ”Œ Connecting to STT service...');
129
-
130
- try {
131
- this.sttWebSocket = new WebSocket(this.sttWebSocketUrl);
132
-
133
- this.sttWebSocket.onopen = () => {
134
- this.updateStatus('βœ… Connected to STT service - Ready for audio');
135
- };
136
-
137
- this.sttWebSocket.onmessage = (event) => {
138
- const data = JSON.parse(event.data);
139
- this.handleSTTResponse(data);
140
- };
141
-
142
- this.sttWebSocket.onclose = () => {
143
- this.updateStatus('πŸ”Œ STT connection closed');
144
- };
145
-
146
- this.sttWebSocket.onerror = (error) => {
147
- this.updateStatus('❌ STT connection error');
148
- console.error('STT WebSocket error:', error);
149
- };
150
-
151
- return true;
152
- } catch (error) {
153
- this.updateStatus('❌ Failed to connect to STT service');
154
- console.error('STT connection failed:', error);
155
- return false;
156
- }
157
- }
158
-
159
- handleSTTResponse(data) {
160
- console.log('STT WebSocket Response:', data);
161
-
162
- switch(data.type) {
163
- case 'stt_connection_confirmed':
164
- this.updateStatus(`βœ… ${data.service} v${data.version} connected - ${data.model} ready`);
165
- break;
166
-
167
- case 'stt_transcription_complete':
168
- this.updateTranscription(data.transcription);
169
- const processingTime = data.timing?.processing_time || 'unknown';
170
- this.updateStatus(`βœ… Transcription completed (${processingTime}s)`);
171
- break;
172
-
173
- case 'stt_transcription_error':
174
- this.updateStatus(`❌ Transcription error: ${data.error}`);
175
- break;
176
-
177
- case 'pong':
178
- console.log('STT service pong received');
179
- break;
180
-
181
- default:
182
- console.log('Unknown STT response type:', data.type);
183
- }
184
- }
185
-
186
- async startRecording() {
187
- // Connect to STT service first
188
- const connected = await this.connectToSTT();
189
- if (!connected) {
190
- return;
191
- }
192
-
193
- try {
194
- const stream = await navigator.mediaDevices.getUserMedia({
195
- audio: {
196
- sampleRate: 16000,
197
- channelCount: 1,
198
- echoCancellation: true,
199
- noiseSuppression: true
200
- }
201
- });
202
-
203
- // unmute.sh pattern: WebM format with small chunks
204
- this.mediaRecorder = new MediaRecorder(stream, {
205
- mimeType: 'audio/webm;codecs=opus'
206
- });
207
-
208
- this.audioChunks = [];
209
-
210
- this.mediaRecorder.ondataavailable = (event) => {
211
- if (event.data.size > 0) {
212
- this.audioChunks.push(event.data);
213
- }
214
- };
215
-
216
- this.mediaRecorder.onstop = () => {
217
- this.processRecordedAudio();
218
- stream.getTracks().forEach(track => track.stop());
219
- };
220
-
221
- // Start recording
222
- this.mediaRecorder.start();
223
- this.isRecording = true;
224
-
225
- // Update UI
226
- document.getElementById('start-recording').disabled = true;
227
- document.getElementById('stop-recording').disabled = false;
228
- this.updateStatus('πŸŽ™οΈ Recording audio - Speak now...');
229
-
230
- } catch (error) {
231
- console.error('Recording failed:', error);
232
- this.updateStatus('❌ Microphone access failed');
233
- }
234
- }
235
-
236
- stopRecording() {
237
- if (this.mediaRecorder && this.isRecording) {
238
- this.mediaRecorder.stop();
239
- this.isRecording = false;
240
-
241
- // Update UI
242
- document.getElementById('start-recording').disabled = false;
243
- document.getElementById('stop-recording').disabled = true;
244
- this.updateStatus('⏹️ Recording stopped - Processing audio...');
245
- }
246
- }
247
-
248
- async processRecordedAudio() {
249
- if (this.audioChunks.length === 0) {
250
- this.updateStatus('❌ No audio data recorded');
251
- return;
252
- }
253
-
254
- try {
255
- this.updateStatus('βš™οΈ Processing audio with WebSocket STT...');
256
-
257
- // Combine all audio chunks (unmute.sh pattern)
258
- const audioBlob = new Blob(this.audioChunks, { type: 'audio/webm' });
259
-
260
- // Send to STT service via WebSocket
261
- await this.sendAudioViaWebSocket(audioBlob);
262
-
263
- } catch (error) {
264
- console.error('Audio processing failed:', error);
265
- this.updateStatus('❌ Audio processing failed');
266
- }
267
- }
268
-
269
- async sendAudioViaWebSocket(audioBlob) {
270
- try {
271
- if (!this.sttWebSocket || this.sttWebSocket.readyState !== WebSocket.OPEN) {
272
- this.updateStatus('❌ WebSocket not connected');
273
- return;
274
- }
275
-
276
- this.updateStatus('πŸ“€ Sending audio to STT via WebSocket...');
277
-
278
- // Convert audio blob to base64 for WebSocket transmission
279
- const arrayBuffer = await audioBlob.arrayBuffer();
280
- const base64Audio = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
281
-
282
- // Send audio data via WebSocket to standalone STT service v1.0.0
283
- this.sttWebSocket.send(JSON.stringify({
284
- type: "stt_audio_chunk",
285
- audio_data: base64Audio,
286
- language: "auto",
287
- model_size: "base",
288
- client_id: this.clientId
289
- }));
290
-
291
- console.log('Audio sent via WebSocket:', base64Audio.length, 'bytes');
292
-
293
- } catch (error) {
294
- console.error('WebSocket audio transmission failed:', error);
295
- this.updateStatus('❌ WebSocket transmission failed: ' + error.message);
296
- }
297
- }
298
-
299
- /* COMMENTED OUT: HTTP API fallback - focusing on WebSocket-only connectivity
300
- async sendAudioToSTTAPI(audioBlob) {
301
- try {
302
- this.updateStatus('πŸ“€ Sending audio to STT via Gradio API...');
303
-
304
- // Create FormData for Gradio API
305
- const formData = new FormData();
306
- formData.append('data', audioBlob, 'audio.webm');
307
-
308
- // Gradio API expects this format: data: ["auto", "base", true]
309
- formData.append('data', JSON.stringify(["auto", "base", true]));
310
-
311
- // Send to Gradio API
312
- const response = await fetch('https://pgits-stt-gpu-service.hf.space/api/predict', {
313
- method: 'POST',
314
- body: formData
315
- });
316
-
317
- if (response.ok) {
318
- const result = await response.json();
319
- console.log('STT API Response:', result);
320
-
321
- // Extract transcription from Gradio response format
322
- if (result && result.data && result.data.length > 1) {
323
- const transcription = result.data[1]; // [status, transcription, timestamps]
324
- if (transcription && transcription.trim()) {
325
- this.updateTranscription(transcription);
326
- this.updateStatus('βœ… Transcription completed via Gradio API');
327
- } else {
328
- this.updateStatus('⚠️ No transcription received');
329
- }
330
- } else {
331
- this.updateStatus('❌ Unexpected API response format');
332
- console.error('Unexpected response:', result);
333
- }
334
- } else {
335
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
336
- }
337
-
338
- } catch (error) {
339
- console.error('STT API request failed:', error);
340
- this.updateStatus('❌ STT API request failed: ' + error.message);
341
- }
342
- }
343
- */ // END COMMENTED OUT HTTP API fallback
344
-
345
- updateStatus(message) {
346
- document.getElementById('status').innerHTML = `Status: ${message}`;
347
- }
348
-
349
- updateTranscription(text) {
350
- document.getElementById('transcription-text').innerHTML = text;
351
- }
352
- }
353
-
354
- // Initialize when DOM is ready
355
- if (document.readyState === 'loading') {
356
- document.addEventListener('DOMContentLoaded', () => {
357
- window.voiceCalDirectSTT = new VoiceCalDirectSTT();
358
- });
359
- } else {
360
- window.voiceCalDirectSTT = new VoiceCalDirectSTT();
361
- }
362
- </script>
363
- """
364
-
365
- # Render the WebRTC interface
366
- st.components.v1.html(webrtc_html, height=500)
367
 
368
  # Technical Information
369
  st.markdown("---")
@@ -391,19 +72,6 @@ Connection: Pure WebSocket (no fallbacks)
391
  st.write("βœ… No HTTP API fallbacks")
392
  st.write("βœ… Base64 audio transmission")
393
 
394
- # Connection Status
395
- st.subheader("πŸ”— Service Status")
396
- st.json({
397
- "stt_websocket": "wss://pgits-stt-gpu-service.hf.space/ws/stt",
398
- "stt_service": "Standalone WebSocket STT v1.0.0",
399
- "connection_type": "pure_websocket",
400
- "audio_format": "WebM/Opus 16kHz",
401
- "transmission": "Base64 encoded",
402
- "pattern": "unmute.sh WebSocket methodology",
403
- "fallbacks": "disabled",
404
- "status": "Ready for WebSocket voice interaction"
405
- })
406
-
407
  # Footer
408
  st.markdown("---")
409
  st.markdown("πŸš€ **VoiceCal WebSocket STT** - Pure WebSocket WebRTC with standalone STT service v1.0.0")
 
1
  #!/usr/bin/env python3
2
  """
3
  Streamlit app with embedded WebSocket server for VoiceCal WebRTC
4
+ Simplified version for debugging startup issues
5
  """
6
 
7
  import streamlit as st
 
 
 
 
 
 
8
 
9
  # Configure Streamlit page
10
  st.set_page_config(
 
39
  st.markdown("---")
40
  st.header("🌐 WebRTC Voice Interface")
41
 
42
+ # Simplified message while we debug
43
+ st.info("WebRTC interface temporarily simplified for debugging startup issues.")
44
+ st.markdown("**Next steps:**")
45
+ st.markdown("1. Verify basic Streamlit functionality βœ…")
46
+ st.markdown("2. Test WebSocket connectivity")
47
+ st.markdown("3. Add WebRTC JavaScript integration")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
  # Technical Information
50
  st.markdown("---")
 
72
  st.write("βœ… No HTTP API fallbacks")
73
  st.write("βœ… Base64 audio transmission")
74
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  # Footer
76
  st.markdown("---")
77
  st.markdown("πŸš€ **VoiceCal WebSocket STT** - Pure WebSocket WebRTC with standalone STT service v1.0.0")
streamlit_websocket_app.py.backup ADDED
@@ -0,0 +1,412 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Streamlit app with embedded WebSocket server for VoiceCal WebRTC
4
+ Single-service approach for HuggingFace Spaces compatibility
5
+ """
6
+
7
+ import streamlit as st
8
+ import asyncio
9
+ import threading
10
+ import json
11
+ import sys
12
+ from datetime import datetime
13
+ import os
14
+
15
+ # Configure Streamlit page
16
+ st.set_page_config(
17
+ page_title="VoiceCal - Voice Assistant",
18
+ page_icon="🎀",
19
+ layout="wide"
20
+ )
21
+
22
+ def main():
23
+ st.title("πŸŽ€πŸ“… VoiceCal - Voice-Enabled AI Assistant")
24
+ st.markdown("**WebRTC Voice Integration Following unmute.sh Pattern**")
25
+
26
+ # Service status dashboard
27
+ col1, col2, col3 = st.columns(3)
28
+
29
+ with col1:
30
+ st.metric("🎀 VoiceCal", "Online", "βœ…")
31
+ st.metric("πŸ“‘ WebSocket", "Embedded", "πŸ”§")
32
+
33
+ with col2:
34
+ st.metric("🧠 STT Service", "Ready", "βœ…")
35
+ st.metric("πŸ”Š TTS Service", "Ready", "βœ…")
36
+
37
+ with col3:
38
+ st.metric("🌐 Connection", "Direct", "⚑")
39
+ st.metric("πŸ“± Pattern", "unmute.sh", "🎯")
40
+
41
+ # Connection Status
42
+ st.success("🎯 **STT Service Connected**: `wss://pgits-stt-gpu-service.hf.space/ws/stt`")
43
+
44
+ # WebRTC Integration Section
45
+ st.markdown("---")
46
+ st.header("🌐 WebRTC Voice Interface")
47
+
48
+ # Simplified WebRTC interface that connects directly to STT service
49
+ webrtc_html = """
50
+ <div id="voice-interface" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 20px; border-radius: 10px; margin: 20px 0;">
51
+ <h3 style="color: white; margin-top: 0;">🎀 Voice Interface (Direct STT Connection)</h3>
52
+
53
+ <div style="display: flex; gap: 10px; margin: 20px 0;">
54
+ <button id="start-recording" style="background: #ff4757; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer;">
55
+ πŸŽ™οΈ Start Recording
56
+ </button>
57
+ <button id="stop-recording" style="background: #2f3542; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer;" disabled>
58
+ ⏹️ Stop Recording
59
+ </button>
60
+ <button id="test-connection" style="background: #5352ed; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer;">
61
+ πŸ”— Test STT Connection
62
+ </button>
63
+ </div>
64
+
65
+ <div id="status" style="background: rgba(0,0,0,0.2); padding: 10px; border-radius: 5px; color: white; font-family: monospace;">
66
+ Status: Ready to connect to STT service...
67
+ </div>
68
+
69
+ <div id="transcription" style="background: rgba(255,255,255,0.9); padding: 15px; border-radius: 5px; margin-top: 10px; min-height: 50px;">
70
+ <strong>Transcription:</strong> <span id="transcription-text">Ready for voice input...</span>
71
+ </div>
72
+ </div>
73
+
74
+ <script>
75
+ // Direct STT WebSocket Connection (unmute.sh Pattern)
76
+ class VoiceCalDirectSTT {
77
+ constructor() {
78
+ this.sttWebSocket = null;
79
+ this.mediaRecorder = null;
80
+ this.audioChunks = [];
81
+ this.isRecording = false;
82
+ this.clientId = 'voicecal-' + Math.random().toString(36).substr(2, 9);
83
+ // Connect to standalone WebSocket STT service v1.0.0
84
+ this.sttWebSocketUrl = 'wss://pgits-stt-gpu-service.hf.space/ws/stt';
85
+
86
+ this.setupEventListeners();
87
+ }
88
+
89
+ setupEventListeners() {
90
+ document.getElementById('start-recording').addEventListener('click', () => {
91
+ this.startRecording();
92
+ });
93
+
94
+ document.getElementById('stop-recording').addEventListener('click', () => {
95
+ this.stopRecording();
96
+ });
97
+
98
+ document.getElementById('test-connection').addEventListener('click', () => {
99
+ this.testSTTConnection();
100
+ });
101
+ }
102
+
103
+ async testSTTConnection() {
104
+ this.updateStatus('πŸ”— Testing WebSocket STT service connection...');
105
+
106
+ try {
107
+ // Test WebSocket connection to standalone STT service v1.0.0
108
+ const testSocket = new WebSocket(this.sttWebSocketUrl);
109
+
110
+ testSocket.onopen = () => {
111
+ this.updateStatus('βœ… STT WebSocket connection successful!');
112
+ console.log('STT service WebSocket is ready');
113
+ testSocket.close();
114
+ };
115
+
116
+ testSocket.onerror = (error) => {
117
+ this.updateStatus('❌ STT WebSocket connection failed');
118
+ console.error('STT WebSocket error:', error);
119
+ };
120
+
121
+ } catch (error) {
122
+ this.updateStatus('❌ Failed to test STT WebSocket connection');
123
+ console.error('STT connection test error:', error);
124
+ }
125
+ }
126
+
127
+ async connectToSTT() {
128
+ this.updateStatus('πŸ”Œ Connecting to STT service...');
129
+
130
+ try {
131
+ this.sttWebSocket = new WebSocket(this.sttWebSocketUrl);
132
+
133
+ this.sttWebSocket.onopen = () => {
134
+ this.updateStatus('βœ… Connected to STT service - Ready for audio');
135
+ };
136
+
137
+ this.sttWebSocket.onmessage = (event) => {
138
+ const data = JSON.parse(event.data);
139
+ this.handleSTTResponse(data);
140
+ };
141
+
142
+ this.sttWebSocket.onclose = () => {
143
+ this.updateStatus('πŸ”Œ STT connection closed');
144
+ };
145
+
146
+ this.sttWebSocket.onerror = (error) => {
147
+ this.updateStatus('❌ STT connection error');
148
+ console.error('STT WebSocket error:', error);
149
+ };
150
+
151
+ return true;
152
+ } catch (error) {
153
+ this.updateStatus('❌ Failed to connect to STT service');
154
+ console.error('STT connection failed:', error);
155
+ return false;
156
+ }
157
+ }
158
+
159
+ handleSTTResponse(data) {
160
+ console.log('STT WebSocket Response:', data);
161
+
162
+ switch(data.type) {
163
+ case 'stt_connection_confirmed':
164
+ this.updateStatus(`βœ… ${data.service} v${data.version} connected - ${data.model} ready`);
165
+ break;
166
+
167
+ case 'stt_transcription_complete':
168
+ this.updateTranscription(data.transcription);
169
+ const processingTime = data.timing?.processing_time || 'unknown';
170
+ this.updateStatus(`βœ… Transcription completed (${processingTime}s)`);
171
+ break;
172
+
173
+ case 'stt_transcription_error':
174
+ this.updateStatus(`❌ Transcription error: ${data.error}`);
175
+ break;
176
+
177
+ case 'pong':
178
+ console.log('STT service pong received');
179
+ break;
180
+
181
+ default:
182
+ console.log('Unknown STT response type:', data.type);
183
+ }
184
+ }
185
+
186
+ async startRecording() {
187
+ // Connect to STT service first
188
+ const connected = await this.connectToSTT();
189
+ if (!connected) {
190
+ return;
191
+ }
192
+
193
+ try {
194
+ const stream = await navigator.mediaDevices.getUserMedia({
195
+ audio: {
196
+ sampleRate: 16000,
197
+ channelCount: 1,
198
+ echoCancellation: true,
199
+ noiseSuppression: true
200
+ }
201
+ });
202
+
203
+ // unmute.sh pattern: WebM format with small chunks
204
+ this.mediaRecorder = new MediaRecorder(stream, {
205
+ mimeType: 'audio/webm;codecs=opus'
206
+ });
207
+
208
+ this.audioChunks = [];
209
+
210
+ this.mediaRecorder.ondataavailable = (event) => {
211
+ if (event.data.size > 0) {
212
+ this.audioChunks.push(event.data);
213
+ }
214
+ };
215
+
216
+ this.mediaRecorder.onstop = () => {
217
+ this.processRecordedAudio();
218
+ stream.getTracks().forEach(track => track.stop());
219
+ };
220
+
221
+ // Start recording
222
+ this.mediaRecorder.start();
223
+ this.isRecording = true;
224
+
225
+ // Update UI
226
+ document.getElementById('start-recording').disabled = true;
227
+ document.getElementById('stop-recording').disabled = false;
228
+ this.updateStatus('πŸŽ™οΈ Recording audio - Speak now...');
229
+
230
+ } catch (error) {
231
+ console.error('Recording failed:', error);
232
+ this.updateStatus('❌ Microphone access failed');
233
+ }
234
+ }
235
+
236
+ stopRecording() {
237
+ if (this.mediaRecorder && this.isRecording) {
238
+ this.mediaRecorder.stop();
239
+ this.isRecording = false;
240
+
241
+ // Update UI
242
+ document.getElementById('start-recording').disabled = false;
243
+ document.getElementById('stop-recording').disabled = true;
244
+ this.updateStatus('⏹️ Recording stopped - Processing audio...');
245
+ }
246
+ }
247
+
248
+ async processRecordedAudio() {
249
+ if (this.audioChunks.length === 0) {
250
+ this.updateStatus('❌ No audio data recorded');
251
+ return;
252
+ }
253
+
254
+ try {
255
+ this.updateStatus('βš™οΈ Processing audio with WebSocket STT...');
256
+
257
+ // Combine all audio chunks (unmute.sh pattern)
258
+ const audioBlob = new Blob(this.audioChunks, { type: 'audio/webm' });
259
+
260
+ // Send to STT service via WebSocket
261
+ await this.sendAudioViaWebSocket(audioBlob);
262
+
263
+ } catch (error) {
264
+ console.error('Audio processing failed:', error);
265
+ this.updateStatus('❌ Audio processing failed');
266
+ }
267
+ }
268
+
269
+ async sendAudioViaWebSocket(audioBlob) {
270
+ try {
271
+ if (!this.sttWebSocket || this.sttWebSocket.readyState !== WebSocket.OPEN) {
272
+ this.updateStatus('❌ WebSocket not connected');
273
+ return;
274
+ }
275
+
276
+ this.updateStatus('πŸ“€ Sending audio to STT via WebSocket...');
277
+
278
+ // Convert audio blob to base64 for WebSocket transmission
279
+ const arrayBuffer = await audioBlob.arrayBuffer();
280
+ const base64Audio = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
281
+
282
+ // Send audio data via WebSocket to standalone STT service v1.0.0
283
+ this.sttWebSocket.send(JSON.stringify({
284
+ type: "stt_audio_chunk",
285
+ audio_data: base64Audio,
286
+ language: "auto",
287
+ model_size: "base",
288
+ client_id: this.clientId
289
+ }));
290
+
291
+ console.log('Audio sent via WebSocket:', base64Audio.length, 'bytes');
292
+
293
+ } catch (error) {
294
+ console.error('WebSocket audio transmission failed:', error);
295
+ this.updateStatus('❌ WebSocket transmission failed: ' + error.message);
296
+ }
297
+ }
298
+
299
+ /* COMMENTED OUT: HTTP API fallback - focusing on WebSocket-only connectivity
300
+ async sendAudioToSTTAPI(audioBlob) {
301
+ try {
302
+ this.updateStatus('πŸ“€ Sending audio to STT via Gradio API...');
303
+
304
+ // Create FormData for Gradio API
305
+ const formData = new FormData();
306
+ formData.append('data', audioBlob, 'audio.webm');
307
+
308
+ // Gradio API expects this format: data: ["auto", "base", true]
309
+ formData.append('data', JSON.stringify(["auto", "base", true]));
310
+
311
+ // Send to Gradio API
312
+ const response = await fetch('https://pgits-stt-gpu-service.hf.space/api/predict', {
313
+ method: 'POST',
314
+ body: formData
315
+ });
316
+
317
+ if (response.ok) {
318
+ const result = await response.json();
319
+ console.log('STT API Response:', result);
320
+
321
+ // Extract transcription from Gradio response format
322
+ if (result && result.data && result.data.length > 1) {
323
+ const transcription = result.data[1]; // [status, transcription, timestamps]
324
+ if (transcription && transcription.trim()) {
325
+ this.updateTranscription(transcription);
326
+ this.updateStatus('βœ… Transcription completed via Gradio API');
327
+ } else {
328
+ this.updateStatus('⚠️ No transcription received');
329
+ }
330
+ } else {
331
+ this.updateStatus('❌ Unexpected API response format');
332
+ console.error('Unexpected response:', result);
333
+ }
334
+ } else {
335
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
336
+ }
337
+
338
+ } catch (error) {
339
+ console.error('STT API request failed:', error);
340
+ this.updateStatus('❌ STT API request failed: ' + error.message);
341
+ }
342
+ }
343
+ */ // END COMMENTED OUT HTTP API fallback
344
+
345
+ updateStatus(message) {
346
+ document.getElementById('status').innerHTML = `Status: ${message}`;
347
+ }
348
+
349
+ updateTranscription(text) {
350
+ document.getElementById('transcription-text').innerHTML = text;
351
+ }
352
+ }
353
+
354
+ // Initialize when DOM is ready
355
+ if (document.readyState === 'loading') {
356
+ document.addEventListener('DOMContentLoaded', () => {
357
+ window.voiceCalDirectSTT = new VoiceCalDirectSTT();
358
+ });
359
+ } else {
360
+ window.voiceCalDirectSTT = new VoiceCalDirectSTT();
361
+ }
362
+ </script>
363
+ """
364
+
365
+ # Render the WebRTC interface
366
+ st.components.v1.html(webrtc_html, height=500)
367
+
368
+ # Technical Information
369
+ st.markdown("---")
370
+ st.header("πŸ”§ Technical Details")
371
+
372
+ col1, col2 = st.columns(2)
373
+
374
+ with col1:
375
+ st.subheader("πŸ“‘ WebSocket Connection")
376
+ st.code("""
377
+ STT WebSocket: wss://pgits-stt-gpu-service.hf.space/ws/stt
378
+ Audio Format: WebM/Opus (16kHz, Mono)
379
+ Service: Standalone STT v1.0.0
380
+ Pattern: unmute.sh methodology
381
+ Connection: Pure WebSocket (no fallbacks)
382
+ """)
383
+
384
+ with col2:
385
+ st.subheader("🎯 Features")
386
+ st.write("βœ… Pure WebSocket STT connection")
387
+ st.write("βœ… WebRTC MediaRecorder integration")
388
+ st.write("βœ… unmute.sh audio processing")
389
+ st.write("βœ… Real-time voice transcription")
390
+ st.write("βœ… Standalone STT service v1.0.0")
391
+ st.write("βœ… No HTTP API fallbacks")
392
+ st.write("βœ… Base64 audio transmission")
393
+
394
+ # Connection Status
395
+ st.subheader("πŸ”— Service Status")
396
+ st.json({
397
+ "stt_websocket": "wss://pgits-stt-gpu-service.hf.space/ws/stt",
398
+ "stt_service": "Standalone WebSocket STT v1.0.0",
399
+ "connection_type": "pure_websocket",
400
+ "audio_format": "WebM/Opus 16kHz",
401
+ "transmission": "Base64 encoded",
402
+ "pattern": "unmute.sh WebSocket methodology",
403
+ "fallbacks": "disabled",
404
+ "status": "Ready for WebSocket voice interaction"
405
+ })
406
+
407
+ # Footer
408
+ st.markdown("---")
409
+ st.markdown("πŸš€ **VoiceCal WebSocket STT** - Pure WebSocket WebRTC with standalone STT service v1.0.0")
410
+
411
+ if __name__ == "__main__":
412
+ main()
test_streamlit_simple.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Simple test Streamlit app to verify basic functionality
4
+ """
5
+
6
+ import streamlit as st
7
+
8
+ # Configure Streamlit page
9
+ st.set_page_config(
10
+ page_title="VoiceCal Test",
11
+ page_icon="🎀",
12
+ layout="wide"
13
+ )
14
+
15
+ def main():
16
+ st.title("πŸŽ€πŸ“… VoiceCal - Voice-Enabled AI Assistant (Test)")
17
+ st.markdown("**Testing basic Streamlit functionality**")
18
+
19
+ # Simple content without JavaScript
20
+ st.success("βœ… Basic Streamlit is working!")
21
+
22
+ st.markdown("### Service Status")
23
+ col1, col2 = st.columns(2)
24
+
25
+ with col1:
26
+ st.metric("🎀 VoiceCal", "Online", "βœ…")
27
+ st.metric("🧠 STT Service", "Ready", "βœ…")
28
+
29
+ with col2:
30
+ st.metric("πŸ”Š TTS Service", "Ready", "βœ…")
31
+ st.metric("πŸ“± Pattern", "unmute.sh", "🎯")
32
+
33
+ st.markdown("---")
34
+ st.markdown("🎯 **Ready for WebSocket integration testing**")
35
+
36
+ # Add simple HTML without complex JavaScript
37
+ simple_html = """
38
+ <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 20px; border-radius: 10px; margin: 20px 0;">
39
+ <h3 style="color: white; margin-top: 0;">🎀 Simple Voice Interface Test</h3>
40
+ <p style="color: white;">JavaScript functionality will be added after basic test passes.</p>
41
+ </div>
42
+ """
43
+
44
+ st.components.v1.html(simple_html, height=150)
45
+
46
+ if __name__ == "__main__":
47
+ main()