aboutsummaryrefslogtreecommitdiff
path: root/tests/test_tts.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_tts.py')
-rw-r--r--tests/test_tts.py85
1 files changed, 82 insertions, 3 deletions
diff --git a/tests/test_tts.py b/tests/test_tts.py
index 9ca6f0d..ec357c1 100644
--- a/tests/test_tts.py
+++ b/tests/test_tts.py
@@ -703,7 +703,8 @@ class AudioCppTTSClientRequestTests(unittest.TestCase):
self._tmp.cleanup()
@staticmethod
- def _make_client(preset_mode=False, voice="Vivian", language="English", seed=-1):
+ def _make_client(preset_mode=False, voice="Vivian", language="English", seed=-1,
+ chunk_text=True):
client = AudioCppTTSClient.__new__(AudioCppTTSClient)
client.api_url = "http://127.0.0.1:8080"
client.model_id = config.AUDIOCPP_MODEL_ID
@@ -711,6 +712,7 @@ class AudioCppTTSClientRequestTests(unittest.TestCase):
client.voice = voice
client.language = language
client._seed = seed
+ client.chunk_text = chunk_text
return client
@staticmethod
@@ -746,6 +748,45 @@ class AudioCppTTSClientRequestTests(unittest.TestCase):
self.assertEqual(payload["seed"], 1234)
self.assertNotIn("instructions", payload)
+ def test_negative_seed_omitted_from_payload(self):
+ client = self._make_client(preset_mode=True, voice="narrator", seed=-1)
+ with patch("converter.tts.urllib.request.urlopen",
+ return_value=self._post_response(self._wav_bytes())) as mock_urlopen:
+ client._request_wav("Hello world.")
+ payload = json.loads(mock_urlopen.call_args[0][0].data.decode("utf-8"))
+ self.assertNotIn("seed", payload)
+
+ def test_whole_text_sent_as_one_request_without_client_chunking(self):
+ client = self._make_client(chunk_text=False)
+ # 9 words with CHUNK_SIZE=5 would split in two if client chunking
+ # were on; kept under the 10-word truncation-check threshold.
+ text = " ".join(f"word{i}" for i in range(9))
+ with patch.object(config, "CHUNK_SIZE", 5), \
+ patch.object(client, "_request_wav",
+ return_value=self._wav_bytes()) as mock_request:
+ result = client.generate_chunk(text, 1)
+ self.assertIsNotNone(result)
+ self.assertEqual(mock_request.call_count, 1)
+ self.assertEqual(mock_request.call_args[0][0], text)
+
+ def test_single_request_timeout_scales_with_text_length(self):
+ client = self._make_client(chunk_text=False)
+ long_text = " ".join(f"word{i}" for i in range(1500)) # ~10 min of audio
+ with patch("converter.tts.urllib.request.urlopen",
+ return_value=self._post_response(self._wav_bytes())) as mock_urlopen:
+ client._request_wav(long_text)
+ timeout = mock_urlopen.call_args[1]["timeout"]
+ self.assertGreater(timeout, config.API_TIMEOUT)
+
+ def test_client_chunking_keeps_configured_timeout(self):
+ client = self._make_client(chunk_text=True)
+ long_text = " ".join(f"word{i}" for i in range(1500))
+ with patch("converter.tts.urllib.request.urlopen",
+ return_value=self._post_response(self._wav_bytes())) as mock_urlopen:
+ client._request_wav(long_text)
+ timeout = mock_urlopen.call_args[1]["timeout"]
+ self.assertEqual(timeout, config.API_TIMEOUT)
+
def test_speaker_mode_sends_instruct(self):
client = self._make_client(preset_mode=False)
with patch("converter.tts.urllib.request.urlopen",
@@ -857,6 +898,7 @@ class AudioCppTTSClientTruncationTests(unittest.TestCase):
client.voice = "narrator"
client.language = "English"
client._seed = -1
+ client.chunk_text = True
return client
@staticmethod
@@ -909,7 +951,8 @@ class BackendWiringTests(unittest.TestCase):
AudiobookConverter(voice_mode=tts.VOICE_MODE_CLONE,
backend=tts.BACKEND_AUDIOCPP, voice="narrator",
language="ja")
- mock_audiocpp.assert_called_once_with(voice="narrator", language="Japanese")
+ mock_audiocpp.assert_called_once_with(voice="narrator", language="Japanese",
+ chunk_text=False)
mock_faster.assert_not_called()
mock_qwen.assert_not_called()
@@ -917,7 +960,18 @@ class BackendWiringTests(unittest.TestCase):
with patch("converter.converter.AudioCppTTSClient") as mock_audiocpp:
AudiobookConverter(voice_mode=tts.VOICE_MODE_CUSTOM,
backend=tts.BACKEND_AUDIOCPP)
- mock_audiocpp.assert_called_once_with(voice=None, language=config.LANGUAGE)
+ mock_audiocpp.assert_called_once_with(voice=None, language=config.LANGUAGE,
+ chunk_text=False)
+
+ def test_audiocpp_backend_chunk_flag_forces_client_chunking(self):
+ with patch("converter.converter.AudioCppTTSClient") as mock_audiocpp:
+ converter = AudiobookConverter(voice_mode=tts.VOICE_MODE_CLONE,
+ backend=tts.BACKEND_AUDIOCPP,
+ voice="narrator", chunk=True)
+ mock_audiocpp.assert_called_once_with(voice="narrator",
+ language=config.LANGUAGE,
+ chunk_text=True)
+ self.assertTrue(converter.client_chunks)
def test_gradio_backend_uses_qwen_client(self):
with patch("converter.converter.FasterTTSClient") as mock_faster, \
@@ -942,6 +996,31 @@ class BackendWiringTests(unittest.TestCase):
voice="narrator")
self.assertIsNone(converter.voice_clone_ref_audio)
+ def test_chapter_chunks_audiocpp_default_is_one_request(self):
+ converter = self._audiocpp_converter(voice="narrator")
+ text = " ".join(f"word{i}" for i in range(50))
+ with patch.object(config, "CHUNK_SIZE", 10):
+ self.assertEqual(converter._chapter_chunks(text), [text])
+
+ def test_chapter_chunks_audiocpp_chunk_flag_splits(self):
+ with patch("converter.converter.AudioCppTTSClient"):
+ converter = AudiobookConverter(voice_mode=tts.VOICE_MODE_CLONE,
+ backend=tts.BACKEND_AUDIOCPP,
+ voice="narrator", chunk=True)
+ text = " ".join(f"word{i}" for i in range(50))
+ with patch.object(config, "CHUNK_SIZE", 10):
+ chunks = converter._chapter_chunks(text)
+ self.assertGreater(len(chunks), 1)
+ self.assertTrue(all(len(chunk.split()) <= 10 for chunk in chunks))
+
+ def test_chapter_chunks_gradio_always_splits(self):
+ with patch("converter.converter.QwenTTSClient"):
+ converter = AudiobookConverter(voice_mode=tts.VOICE_MODE_CUSTOM)
+ text = " ".join(f"word{i}" for i in range(50))
+ with patch.object(config, "CHUNK_SIZE", 10):
+ chunks = converter._chapter_chunks(text)
+ self.assertGreater(len(chunks), 1)
+
def test_faster_backend_still_validates_other_settings(self):
with patch("converter.converter.FasterTTSClient"):
with self.assertRaises(ValueError):