Files
audiobook/backend/test_segment_based_generation.py
Paul Bailey cea97d3cd4 Task 19: Update TTS generation endpoint to accept edited scripts
- Modified TTSRequest to accept optional segments array
- Updated generate_audiobook endpoint to use segments if provided
- Added generate_audiobook_from_segments method to TTSService
- Ensured backward compatibility with text-based generation
- Added comprehensive tests for segment-based generation
- All tests passing (7/7)

Requirements: 15.7
2025-12-09 11:46:10 +00:00

165 lines
5.0 KiB
Python

"""
Test for segment-based audiobook generation (Task 19).
Tests that the TTS endpoint can accept edited script segments
and generate audio from them, while maintaining backward compatibility
with text-based generation.
"""
import pytest
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_generate_audiobook_with_segments():
"""Test that audiobook can be generated from edited script segments."""
# Prepare request with segments
request_data = {
"segments": [
{"id": "seg_0", "speaker": "Alice", "text": "Hello, how are you?"},
{"id": "seg_1", "speaker": "Bob", "text": "I'm doing great, thanks!"},
{"id": "seg_2", "speaker": "Narrator", "text": "They continued their conversation."}
],
"lang": "a",
"roles": [
{"id": "Alice", "voice": "af_bella"},
{"id": "Bob", "voice": "am_adam"},
{"id": "Narrator", "voice": "af_sarah"}
],
"speed": 1.0
}
response = client.post("/api/tts", json=request_data)
# Should succeed
assert response.status_code == 200
assert response.headers["content-type"] == "audio/wav"
assert "audiobook.wav" in response.headers.get("content-disposition", "")
assert len(response.content) > 0
def test_generate_audiobook_with_text_backward_compatibility():
"""Test that audiobook generation still works with text (backward compatibility)."""
# Prepare request with text (old format)
request_data = {
"text": "Alice: Hello there!\nBob: Hi Alice!",
"lang": "a",
"roles": [
{"id": "Alice", "voice": "af_bella"},
{"id": "Bob", "voice": "am_adam"}
],
"speed": 1.0
}
response = client.post("/api/tts", json=request_data)
# Should succeed
assert response.status_code == 200
assert response.headers["content-type"] == "audio/wav"
assert len(response.content) > 0
def test_generate_audiobook_segments_take_precedence():
"""Test that segments are used when both segments and text are provided."""
# Prepare request with both segments and text
request_data = {
"segments": [
{"id": "seg_0", "speaker": "Alice", "text": "From segments"}
],
"text": "Alice: From text",
"lang": "a",
"roles": [
{"id": "Alice", "voice": "af_bella"}
],
"speed": 1.0
}
response = client.post("/api/tts", json=request_data)
# Should succeed and use segments
assert response.status_code == 200
assert response.headers["content-type"] == "audio/wav"
def test_generate_audiobook_missing_both_segments_and_text():
"""Test that request fails when neither segments nor text is provided."""
request_data = {
"lang": "a",
"roles": [
{"id": "Alice", "voice": "af_bella"}
],
"speed": 1.0
}
response = client.post("/api/tts", json=request_data)
# Should fail with validation error
assert response.status_code == 400
assert "ValidationError" in response.json()["error"]
def test_generate_audiobook_empty_segments():
"""Test that request fails when segments array is empty."""
request_data = {
"segments": [],
"lang": "a",
"roles": [
{"id": "Alice", "voice": "af_bella"}
],
"speed": 1.0
}
response = client.post("/api/tts", json=request_data)
# Should fail - empty segments should be treated as not provided
assert response.status_code == 400
def test_edited_script_preserves_speaker_assignments():
"""Test that edited speaker assignments in segments are preserved."""
# Segments where user has changed speaker assignments
request_data = {
"segments": [
{"id": "seg_0", "speaker": "Bob", "text": "This was originally Alice's line"},
{"id": "seg_1", "speaker": "Alice", "text": "This was originally Bob's line"}
],
"lang": "a",
"roles": [
{"id": "Alice", "voice": "af_bella"},
{"id": "Bob", "voice": "am_adam"}
],
"speed": 1.0
}
response = client.post("/api/tts", json=request_data)
# Should succeed with edited assignments
assert response.status_code == 200
assert response.headers["content-type"] == "audio/wav"
assert len(response.content) > 0
def test_segment_with_unmapped_speaker_uses_default():
"""Test that segments with unmapped speakers fall back to default voice."""
request_data = {
"segments": [
{"id": "seg_0", "speaker": "UnknownSpeaker", "text": "Hello from unknown"}
],
"lang": "a",
"roles": [
{"id": "Alice", "voice": "af_bella"}
],
"speed": 1.0
}
response = client.post("/api/tts", json=request_data)
# Should succeed using default voice
assert response.status_code == 200
assert response.headers["content-type"] == "audio/wav"
if __name__ == "__main__":
pytest.main([__file__, "-v"])