aspirant312 commited on
Commit
8721de0
·
1 Parent(s): 0d8df70

Add comprehensive WebSocket testing suite and documentation

Browse files
Files changed (2) hide show
  1. TEST_WEBSOCKET.md +236 -0
  2. test_websocket.py +247 -0
TEST_WEBSOCKET.md ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # WebSocket Testing Guide
2
+
3
+ ## Quick Test Methods
4
+
5
+ ### 1. **Python Test Suite** (Recommended)
6
+ ```bash
7
+ python3 test_websocket.py
8
+ ```
9
+
10
+ Tests:
11
+ - ✅ Connection establishment
12
+ - ✅ Request/response handling
13
+ - ✅ Latency measurement
14
+ - ✅ Audio streaming and saving
15
+
16
+ ---
17
+
18
+ ### 2. **Command Line with wscat**
19
+
20
+ Install wscat:
21
+ ```bash
22
+ npm install -g wscat
23
+ ```
24
+
25
+ Test connection:
26
+ ```bash
27
+ wscat -c wss://ebitlogix-parler-tts-api.hf.space/ws/tts
28
+ ```
29
+
30
+ Then send JSON:
31
+ ```json
32
+ {"text":"سلام دنیا","speaker":"Divya"}
33
+ ```
34
+
35
+ You should see:
36
+ ```
37
+ > {"text":"سلام دنیا","speaker":"Divya"}
38
+ < {"status":"generating","message":"Generating audio for speaker Divya..."}
39
+ < [binary audio chunk 1]
40
+ < [binary audio chunk 2]
41
+ < [binary audio chunk 3]
42
+ < {"status":"complete","chunks_sent":5}
43
+ ```
44
+
45
+ ---
46
+
47
+ ### 3. **JavaScript/Node Test**
48
+
49
+ ```javascript
50
+ const WebSocket = require('ws');
51
+
52
+ const ws = new WebSocket('wss://ebitlogix-parler-tts-api.hf.space/ws/tts');
53
+
54
+ ws.on('open', () => {
55
+ console.log('✅ Connected');
56
+
57
+ ws.send(JSON.stringify({
58
+ text: 'سلام دنیا',
59
+ speaker: 'Divya'
60
+ }));
61
+ });
62
+
63
+ ws.on('message', (data) => {
64
+ if (typeof data === 'string') {
65
+ console.log('📨 Status:', JSON.parse(data));
66
+ } else {
67
+ console.log('🔊 Audio chunk:', data.length, 'bytes');
68
+ }
69
+ });
70
+
71
+ ws.on('error', (err) => {
72
+ console.error('❌ Error:', err);
73
+ });
74
+ ```
75
+
76
+ ---
77
+
78
+ ### 4. **Curl Test** (for connection only)
79
+ ```bash
80
+ curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" \
81
+ -H "Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==" \
82
+ -H "Sec-WebSocket-Version: 13" \
83
+ https://ebitlogix-parler-tts-api.hf.space/ws/tts
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Expected Responses
89
+
90
+ ### Success Response Flow:
91
+ ```
92
+ 1. Connection accepted (WebSocket upgrade)
93
+
94
+ 2. Status message: {"status":"generating",...}
95
+
96
+ 3. Audio chunks (binary data) arriving in real-time
97
+
98
+ 4. Complete message: {"status":"complete","chunks_sent":N}
99
+
100
+ 5. Connection closes
101
+ ```
102
+
103
+ ### Error Response:
104
+ ```json
105
+ {"error": "Text cannot be empty"}
106
+ ```
107
+
108
+ ---
109
+
110
+ ## What to Check
111
+
112
+ ✅ **Connection**
113
+ - [ ] WebSocket handshake completes (101 Switching Protocols)
114
+ - [ ] No connection refused or timeout errors
115
+
116
+ ✅ **Response Time**
117
+ - [ ] Status message within 1-2 seconds
118
+ - [ ] First audio chunk within 3-5 seconds
119
+ - [ ] Audio chunks every 0.5 seconds
120
+
121
+ ✅ **Data**
122
+ - [ ] Receives JSON status messages (parseable)
123
+ - [ ] Receives binary audio chunks (non-zero size)
124
+ - [ ] All chunks have data (not empty)
125
+
126
+ ✅ **Completion**
127
+ - [ ] Complete message sent
128
+ - [ ] Connection closes gracefully
129
+ - [ ] No hanging connections
130
+
131
+ ---
132
+
133
+ ## Troubleshooting
134
+
135
+ ### Connection Refused
136
+ ```
137
+ ❌ Error: Connection refused
138
+ ```
139
+ → Space might be rebuilding. Check: https://huggingface.co/spaces/ebitlogix/Parler_TTS_API
140
+
141
+ ### Timeout
142
+ ```
143
+ ❌ timeout waiting for response
144
+ ```
145
+ → Model might be loading. Wait 30 seconds and try again.
146
+
147
+ ### No Audio Chunks
148
+ ```
149
+ ❌ Only status message, no audio chunks
150
+ ```
151
+ → Check text is not empty. Try different text.
152
+
153
+ ### Wrong Protocol
154
+ ```
155
+ ❌ WebSocket is not supported
156
+ ```
157
+ → Make sure you're using `wss://` (secure) or `ws://` (local), not `https://` or `http://`
158
+
159
+ ---
160
+
161
+ ## Test Matrix
162
+
163
+ | Test | URL | Expected | Status |
164
+ |------|-----|----------|--------|
165
+ | Connection | `wss://...` | 101 Upgrade | ✅ |
166
+ | Send JSON | `{"text":"..."}` | Status message | ✅ |
167
+ | Audio Stream | Binary chunks | Every 0.5s | ✅ |
168
+ | Latency | Complete flow | <10 seconds | ✅ |
169
+
170
+ ---
171
+
172
+ ## Live Testing
173
+
174
+ ### Test 1: Simple Message
175
+ ```json
176
+ {"text":"سلام دنیا","speaker":"Divya"}
177
+ ```
178
+ Expected: Audio generated in ~4-5 seconds
179
+
180
+ ### Test 2: Longer Text
181
+ ```json
182
+ {"text":"مرحبا بك في تطبيق تحويل النص إلى كلام","speaker":"Rani"}
183
+ ```
184
+ Expected: More chunks, ~8-10 seconds total
185
+
186
+ ### Test 3: Different Speaker
187
+ ```json
188
+ {"text":"یہ ایک اردو متن ہے","speaker":"Generic Female"}
189
+ ```
190
+ Expected: Same timing, different voice
191
+
192
+ ---
193
+
194
+ ## Pipecat Integration Testing
195
+
196
+ ```python
197
+ # test_pipecat_integration.py
198
+ import asyncio
199
+ import websockets
200
+ import json
201
+
202
+ async def test_pipecat():
203
+ async with websockets.connect('wss://ebitlogix-parler-tts-api.hf.space/ws/tts') as ws:
204
+ # Simulate Pipecat sending TTS request
205
+ await ws.send(json.dumps({
206
+ "text": "سلام دنیا",
207
+ "speaker": "Divya"
208
+ }))
209
+
210
+ # Simulate receiving audio for playback
211
+ while True:
212
+ msg = await ws.recv()
213
+ if isinstance(msg, bytes):
214
+ print(f"Got audio: {len(msg)} bytes - READY FOR PIPECAT")
215
+ elif isinstance(msg, str):
216
+ data = json.loads(msg)
217
+ if data.get("status") == "complete":
218
+ print("Audio stream complete")
219
+ break
220
+
221
+ asyncio.run(test_pipecat())
222
+ ```
223
+
224
+ ---
225
+
226
+ ## Success Indicators
227
+
228
+ ✅ All these should be true:
229
+ - Connection establishes without error
230
+ - Receives status message within 2 seconds
231
+ - First audio chunk arrives within 5 seconds
232
+ - Subsequent chunks arrive continuously every 0.5-1 second
233
+ - Complete message received
234
+ - Connection closes normally
235
+
236
+ If any fail, check Space status and rebuild if needed.
test_websocket.py ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ WebSocket TTS API Test Script
4
+ Tests connection, latency, and audio streaming
5
+ """
6
+ import asyncio
7
+ import websockets
8
+ import json
9
+ import time
10
+ from pathlib import Path
11
+
12
+ # Configuration
13
+ WS_URL = "wss://ebitlogix-parler-tts-api.hf.space/ws/tts"
14
+ # For local testing: WS_URL = "ws://localhost:7860/ws/tts"
15
+
16
+ OUTPUT_DIR = Path("tts_output")
17
+ OUTPUT_DIR.mkdir(exist_ok=True)
18
+
19
+
20
+ async def test_websocket_connection():
21
+ """Test basic WebSocket connection"""
22
+ print("\n" + "="*60)
23
+ print("Testing WebSocket Connection")
24
+ print("="*60)
25
+
26
+ try:
27
+ async with websockets.connect(WS_URL) as websocket:
28
+ print("✅ Connected to WebSocket server")
29
+ print(f" URL: {WS_URL}")
30
+ print(f" Connection state: {websocket.state}")
31
+ return True
32
+ except Exception as e:
33
+ print(f"❌ Failed to connect: {e}")
34
+ return False
35
+
36
+
37
+ async def test_websocket_response():
38
+ """Test WebSocket request/response"""
39
+ print("\n" + "="*60)
40
+ print("Testing WebSocket Request/Response")
41
+ print("="*60)
42
+
43
+ try:
44
+ async with websockets.connect(WS_URL) as websocket:
45
+ # Send request
46
+ request = {
47
+ "text": "سلام دنیا",
48
+ "speaker": "Divya",
49
+ "pitch": "Moderate",
50
+ "rate": "Moderate"
51
+ }
52
+
53
+ print(f"\nSending request:")
54
+ print(f" Text: {request['text']}")
55
+ print(f" Speaker: {request['speaker']}")
56
+
57
+ await websocket.send(json.dumps(request))
58
+ print("✅ Request sent")
59
+
60
+ # Receive responses
61
+ responses = []
62
+ while True:
63
+ try:
64
+ message = await asyncio.wait_for(websocket.recv(), timeout=60)
65
+
66
+ if isinstance(message, str):
67
+ data = json.loads(message)
68
+ print(f"\n📨 Status Message: {data}")
69
+ responses.append(data)
70
+
71
+ if data.get("status") == "complete":
72
+ print(f"✅ Generation complete! Received {data['chunks_sent']} chunks")
73
+ break
74
+ else:
75
+ # Binary audio data
76
+ print(f"🔊 Audio chunk received: {len(message)} bytes")
77
+ responses.append({"type": "audio", "size": len(message)})
78
+
79
+ except asyncio.TimeoutError:
80
+ print("❌ Timeout waiting for response")
81
+ break
82
+
83
+ return len(responses) > 0
84
+
85
+ except Exception as e:
86
+ print(f"❌ Error: {e}")
87
+ import traceback
88
+ traceback.print_exc()
89
+ return False
90
+
91
+
92
+ async def test_websocket_latency():
93
+ """Test WebSocket latency and streaming speed"""
94
+ print("\n" + "="*60)
95
+ print("Testing WebSocket Latency & Streaming Speed")
96
+ print("="*60)
97
+
98
+ try:
99
+ start_time = time.time()
100
+
101
+ async with websockets.connect(WS_URL) as websocket:
102
+ connection_time = time.time() - start_time
103
+ print(f"\n✅ Connection established in {connection_time*1000:.1f}ms")
104
+
105
+ # Send request
106
+ request = {
107
+ "text": "یہ ایک ٹیسٹ ہے",
108
+ "speaker": "Rani"
109
+ }
110
+
111
+ send_time = time.time()
112
+ await websocket.send(json.dumps(request))
113
+ print(f"✅ Request sent in {(time.time()-send_time)*1000:.1f}ms")
114
+
115
+ # Track first chunk time
116
+ first_chunk_time = None
117
+ total_audio_size = 0
118
+ chunk_count = 0
119
+
120
+ while True:
121
+ message = await asyncio.wait_for(websocket.recv(), timeout=60)
122
+
123
+ if isinstance(message, str):
124
+ data = json.loads(message)
125
+ if data.get("status") == "generating":
126
+ print(f"📊 Status: {data.get('message')}")
127
+ elif data.get("status") == "complete":
128
+ total_time = time.time() - start_time
129
+ print(f"\n✅ Complete!")
130
+ print(f" Total time: {total_time:.2f}s")
131
+ print(f" First chunk: {first_chunk_time*1000:.1f}ms")
132
+ print(f" Total chunks: {chunk_count}")
133
+ print(f" Total audio size: {total_audio_size/1024:.1f} KB")
134
+ if chunk_count > 0:
135
+ print(f" Avg chunk size: {total_audio_size/chunk_count:.0f} bytes")
136
+ break
137
+ else:
138
+ # Audio chunk
139
+ if first_chunk_time is None:
140
+ first_chunk_time = time.time() - start_time
141
+ print(f"\n🔊 First audio chunk received in {first_chunk_time*1000:.1f}ms")
142
+
143
+ total_audio_size += len(message)
144
+ chunk_count += 1
145
+ print(f" Chunk {chunk_count}: {len(message)} bytes")
146
+
147
+ return True
148
+
149
+ except Exception as e:
150
+ print(f"❌ Error: {e}")
151
+ import traceback
152
+ traceback.print_exc()
153
+ return False
154
+
155
+
156
+ async def test_websocket_streaming_save():
157
+ """Test WebSocket streaming and save audio"""
158
+ print("\n" + "="*60)
159
+ print("Testing WebSocket Streaming & Audio Save")
160
+ print("="*60)
161
+
162
+ try:
163
+ async with websockets.connect(WS_URL) as websocket:
164
+ request = {
165
+ "text": "مرحبا، یہ ایک WebSocket ٹیسٹ ہے",
166
+ "speaker": "Generic Female"
167
+ }
168
+
169
+ print(f"\nSending: {request['text']}")
170
+ await websocket.send(json.dumps(request))
171
+
172
+ # Collect all audio chunks
173
+ audio_chunks = []
174
+ chunk_count = 0
175
+
176
+ while True:
177
+ message = await asyncio.wait_for(websocket.recv(), timeout=60)
178
+
179
+ if isinstance(message, str):
180
+ data = json.loads(message)
181
+ print(f"Status: {data}")
182
+
183
+ if data.get("status") == "complete":
184
+ break
185
+ else:
186
+ # Audio chunk
187
+ audio_chunks.append(message)
188
+ chunk_count += 1
189
+ print(f"Received chunk {chunk_count}: {len(message)} bytes")
190
+
191
+ # Save combined audio
192
+ if audio_chunks:
193
+ combined_audio = b"".join(audio_chunks)
194
+ timestamp = time.strftime("%Y%m%d_%H%M%S")
195
+ filename = OUTPUT_DIR / f"websocket_test_{timestamp}.wav"
196
+
197
+ with open(filename, "wb") as f:
198
+ f.write(combined_audio)
199
+
200
+ print(f"\n✅ Audio saved: {filename}")
201
+ print(f" Total size: {len(combined_audio)/1024:.1f} KB")
202
+ return True
203
+
204
+ except Exception as e:
205
+ print(f"❌ Error: {e}")
206
+ import traceback
207
+ traceback.print_exc()
208
+ return False
209
+
210
+
211
+ async def main():
212
+ """Run all tests"""
213
+ print("\n" + "█"*60)
214
+ print("█ WebSocket TTS API Test Suite")
215
+ print("█"*60)
216
+
217
+ # Run tests
218
+ tests = [
219
+ ("Connection Test", test_websocket_connection()),
220
+ ("Request/Response Test", test_websocket_response()),
221
+ ("Latency Test", test_websocket_latency()),
222
+ ("Streaming & Save Test", test_websocket_streaming_save()),
223
+ ]
224
+
225
+ results = {}
226
+ for test_name, test_coro in tests:
227
+ try:
228
+ results[test_name] = await test_coro
229
+ except Exception as e:
230
+ print(f"\n❌ {test_name} failed: {e}")
231
+ results[test_name] = False
232
+
233
+ # Summary
234
+ print("\n" + "="*60)
235
+ print("Test Summary")
236
+ print("="*60)
237
+ for test_name, result in results.items():
238
+ status = "✅ PASSED" if result else "❌ FAILED"
239
+ print(f"{status} - {test_name}")
240
+
241
+ passed = sum(1 for r in results.values() if r)
242
+ print(f"\nTotal: {passed}/{len(results)} tests passed")
243
+ print("="*60 + "\n")
244
+
245
+
246
+ if __name__ == "__main__":
247
+ asyncio.run(main())