diff options
Diffstat (limited to 'app/tests')
| -rw-r--r-- | app/tests/test_tts.py | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/app/tests/test_tts.py b/app/tests/test_tts.py index 7170262..c0ba666 100644 --- a/app/tests/test_tts.py +++ b/app/tests/test_tts.py @@ -1042,6 +1042,14 @@ class AudioCppFamilyDetectionTests(unittest.TestCase): self.assertIs(client.profile, AUDIOCPP_DEFAULT_FAMILY_PROFILE) self.assertEqual(client.profile.language_style, AUDIOCPP_LANG_OMIT) + def test_breeze_tts_uses_the_option_instruction_channel(self): + # BreezeTTS 2 reads its instruction from the request options, not + # the OpenAI-style "instructions" field. + profile = AUDIOCPP_FAMILY_PROFILES["breeze_tts"] + self.assertEqual(profile.instruction_channel, + audiocpp_client.AUDIOCPP_INSTRUCTION_OPTION) + self.assertEqual(profile.language_style, AUDIOCPP_LANG_OMIT) + def test_speech_to_speech_only_family_rejected_at_connect(self): # A family whose model spec has no text-synthesis task # (PersonaPlex, s2s-only) cannot narrate regardless of its hosted @@ -1612,6 +1620,54 @@ class AudioCppTTSClientRequestTests(unittest.TestCase): payload = json.loads(mock_urlopen.call_args[0][0].data.decode("utf-8")) self.assertEqual(payload["instructions"], "Read whisper quiet.") + def test_option_channel_family_sends_the_instruction_as_a_request_option(self): + # BreezeTTS 2 ignores the top-level OpenAI "instructions" field; + # the instruction goes inside "options" for those families. + client = self._make_client( + family="breeze_tts", preset_mode=True, voice="narrator", + instructions="Speak slowly with a restrained tone.") + with patch("converter.clients.faster.urllib.request.urlopen", + return_value=self._post_response(self._wav_bytes())) as mock_urlopen: + client._request_wav("Hello.") + payload = json.loads(mock_urlopen.call_args[0][0].data.decode("utf-8")) + self.assertNotIn("instructions", payload) + self.assertEqual(payload["voice"], "narrator") + self.assertEqual(payload["options"], + {"instruction": "Speak slowly with a restrained tone."}) + + def test_option_channel_family_keeps_other_request_options(self): + client = self._make_client( + family="breeze_tts", instructions="Calm and steady.", + request_options={"guidance_scale": "2.5"}) + with patch("converter.clients.faster.urllib.request.urlopen", + return_value=self._post_response(self._wav_bytes())) as mock_urlopen: + client._request_wav("Hello.") + payload = json.loads(mock_urlopen.call_args[0][0].data.decode("utf-8")) + self.assertEqual(payload["options"], + {"guidance_scale": "2.5", "instruction": "Calm and steady."}) + + def test_option_channel_family_respects_the_callers_instruction_option(self): + # An explicit --option instruction=... is the caller's instruction + # and is not overwritten by the --instructions value. + client = self._make_client( + family="breeze_tts", instructions="from the flag", + request_options={"instruction": "from the option"}) + with patch("converter.clients.faster.urllib.request.urlopen", + return_value=self._post_response(self._wav_bytes())) as mock_urlopen: + client._request_wav("Hello.") + payload = json.loads(mock_urlopen.call_args[0][0].data.decode("utf-8")) + self.assertEqual(payload["options"]["instruction"], "from the option") + + def test_option_channel_family_omits_options_when_no_instruction(self): + client = self._make_client(family="breeze_tts", preset_mode=True, + voice="narrator") + with patch("converter.clients.faster.urllib.request.urlopen", + return_value=self._post_response(self._wav_bytes())) as mock_urlopen: + client._request_wav("Hello.") + payload = json.loads(mock_urlopen.call_args[0][0].data.decode("utf-8")) + self.assertNotIn("options", payload) + self.assertNotIn("instructions", payload) + def test_preset_mode_sends_instructions_alongside_voice(self): # Clone + style control: both the server-side voice and the # instruction reach the model. |
