Files
audiobook/backend/test_generation_endpoint.py
Paul Bailey 271a127167 Implement audio generation endpoint
- Add POST /api/tts endpoint with full request validation
- Validate text, language code, speed range, and roles list
- Integrate TTSService to generate multi-voice audiobooks
- Fix Kokoro pipeline generator handling to properly collect audio
- Stream audio response with correct Content-Type (audio/wav)
- Add Content-Disposition header with filename (audiobook.wav)
- Handle errors gracefully with appropriate HTTP status codes
- Add comprehensive test suite for endpoint validation

Requirements: 6.1, 6.7, 6.8, 9.5
2025-12-09 01:21:39 +00:00

175 lines
5.6 KiB
Python

#!/usr/bin/env python3
"""Test script for audio generation endpoint."""
import urllib.request
import json
import sys
BASE_URL = 'http://localhost:8001'
def test_generation_endpoint_validation():
"""Test validation of generation endpoint."""
print("Testing audio generation endpoint validation...")
# Test 1: Missing text field
print("\n1. Testing empty text validation...")
try:
data = json.dumps({
"text": "",
"lang": "a",
"roles": [{"id": "Narrator", "voice": "af_bella"}],
"speed": 1.0
}).encode('utf-8')
req = urllib.request.Request(
f'{BASE_URL}/api/tts',
data=data,
headers={'Content-Type': 'application/json'}
)
urllib.request.urlopen(req)
print("✗ Should have rejected empty text")
return False
except urllib.error.HTTPError as e:
if e.code == 400:
error_data = json.loads(e.read().decode())
print(f"✓ Correctly rejected empty text: {error_data['message']}")
else:
print(f"✗ Unexpected error code: {e.code}")
return False
# Test 2: Invalid language code
print("\n2. Testing invalid language code...")
try:
data = json.dumps({
"text": "Hello world",
"lang": "invalid",
"roles": [{"id": "Narrator", "voice": "af_bella"}],
"speed": 1.0
}).encode('utf-8')
req = urllib.request.Request(
f'{BASE_URL}/api/tts',
data=data,
headers={'Content-Type': 'application/json'}
)
urllib.request.urlopen(req)
print("✗ Should have rejected invalid language code")
return False
except urllib.error.HTTPError as e:
if e.code == 400:
error_data = json.loads(e.read().decode())
print(f"✓ Correctly rejected invalid language: {error_data['message']}")
else:
print(f"✗ Unexpected error code: {e.code}")
return False
# Test 3: Invalid speed value
print("\n3. Testing invalid speed value...")
try:
data = json.dumps({
"text": "Hello world",
"lang": "a",
"roles": [{"id": "Narrator", "voice": "af_bella"}],
"speed": 2.0 # Out of range
}).encode('utf-8')
req = urllib.request.Request(
f'{BASE_URL}/api/tts',
data=data,
headers={'Content-Type': 'application/json'}
)
urllib.request.urlopen(req)
print("✗ Should have rejected invalid speed")
return False
except urllib.error.HTTPError as e:
if e.code == 400:
error_data = json.loads(e.read().decode())
print(f"✓ Correctly rejected invalid speed: {error_data['message']}")
else:
print(f"✗ Unexpected error code: {e.code}")
return False
# Test 4: Empty roles list
print("\n4. Testing empty roles list...")
try:
data = json.dumps({
"text": "Hello world",
"lang": "a",
"roles": [],
"speed": 1.0
}).encode('utf-8')
req = urllib.request.Request(
f'{BASE_URL}/api/tts',
data=data,
headers={'Content-Type': 'application/json'}
)
urllib.request.urlopen(req)
print("✗ Should have rejected empty roles list")
return False
except urllib.error.HTTPError as e:
if e.code == 400:
error_data = json.loads(e.read().decode())
print(f"✓ Correctly rejected empty roles: {error_data['message']}")
else:
print(f"✗ Unexpected error code: {e.code}")
return False
# Test 5: Valid request with simple text
print("\n5. Testing valid request...")
try:
data = json.dumps({
"text": "Hello, this is a test.",
"lang": "a",
"roles": [{"id": "Narrator", "voice": "af_bella"}],
"speed": 1.0
}).encode('utf-8')
req = urllib.request.Request(
f'{BASE_URL}/api/tts',
data=data,
headers={'Content-Type': 'application/json'}
)
response = urllib.request.urlopen(req)
# Check Content-Type header
content_type = response.headers.get('Content-Type')
if content_type != 'audio/wav':
print(f"✗ Wrong Content-Type: {content_type}")
return False
print(f"✓ Correct Content-Type: {content_type}")
# Check Content-Disposition header
content_disposition = response.headers.get('Content-Disposition')
if 'audiobook.wav' not in content_disposition:
print(f"✗ Wrong Content-Disposition: {content_disposition}")
return False
print(f"✓ Correct Content-Disposition: {content_disposition}")
# Check that we got audio data
audio_data = response.read()
if len(audio_data) == 0:
print("✗ No audio data received")
return False
print(f"✓ Received audio data: {len(audio_data)} bytes")
except Exception as e:
print(f"✗ Valid request failed: {e}")
return False
return True
if __name__ == '__main__':
print("=" * 60)
print("Audio Generation Endpoint Tests")
print("=" * 60)
success = test_generation_endpoint_validation()
print("\n" + "=" * 60)
if success:
print("✓ All tests passed!")
sys.exit(0)
else:
print("✗ Some tests failed")
sys.exit(1)