diff options
Diffstat (limited to 'app/tests/test_hub.py')
| -rw-r--r-- | app/tests/test_hub.py | 323 |
1 files changed, 127 insertions, 196 deletions
diff --git a/app/tests/test_hub.py b/app/tests/test_hub.py index ee1425d..86dd9e3 100644 --- a/app/tests/test_hub.py +++ b/app/tests/test_hub.py @@ -916,8 +916,7 @@ class ConvertFlowTests(unittest.TestCase): patch.object(hub.config, "AUDIO_FORMAT", "m4b"), \ patch.object(hub.config, "LANGUAGE", "English"), \ patch.object(hub.config, "SPEED", 1.25), \ - patch.object(hub.config, "DEBUG", False), \ - patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): + patch.object(hub.config, "DEBUG", False): self._answer_form(backend="audiocpp-remote", model_id="higgs", audiocpp_voice="narrator", instructions="") cmd = self._convert( @@ -964,11 +963,10 @@ class ConvertFlowTests(unittest.TestCase): [{"id": "short", "family": "higgs_audio_tts", "task": "tts"}, {"id": "a-much-longer-model-id", "family": "qwen3_tts", "task": "tts"}]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp-remote", model_id="short", - audiocpp_voice="", instructions="") - cmd = self._convert( - None, [self._remote("audiocpp", "audio.cpp")]) + self._answer_form(backend="audiocpp-remote", model_id="short", + audiocpp_voice="", instructions="") + cmd = self._convert( + None, [self._remote("audiocpp", "audio.cpp")]) self.assertIsNotNone(cmd) choices = self._field("model_id")["choices"] # "a-much-longer-model-id" is 22 columns wide; both types open at @@ -990,13 +988,12 @@ class ConvertFlowTests(unittest.TestCase): self._patch_remote( [{"id": "Qwen3-TTS-12Hz-1.7B-CustomVoice-GGUF", "family": "qwen3_tts", "task": "tts"}]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form( - backend="audiocpp-remote", - model_id="Qwen3-TTS-12Hz-1.7B-CustomVoice-GGUF", - audiocpp_voice="Ryan", instructions="") - cmd = self._convert( - None, [self._remote("audiocpp", "audio.cpp")]) + self._answer_form( + backend="audiocpp-remote", + model_id="Qwen3-TTS-12Hz-1.7B-CustomVoice-GGUF", + audiocpp_voice="Ryan", instructions="") + cmd = self._convert( + None, [self._remote("audiocpp", "audio.cpp")]) # The picked speaker is passed as --voice; no separate speaker kwarg. self.assertEqual(cmd[2]["voice"], "Ryan") self.assertNotIn("speaker", cmd[2]) @@ -1016,13 +1013,12 @@ class ConvertFlowTests(unittest.TestCase): [{"id": "Qwen3-TTS-12Hz-1.7B-Base-GGUF", "family": "qwen3_tts", "task": "tts"}], voices=["narrator"]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form( - backend="audiocpp-remote", - model_id="Qwen3-TTS-12Hz-1.7B-Base-GGUF", - audiocpp_voice="narrator", instructions="") - cmd = self._convert( - None, [self._remote("audiocpp", "audio.cpp")]) + self._answer_form( + backend="audiocpp-remote", + model_id="Qwen3-TTS-12Hz-1.7B-Base-GGUF", + audiocpp_voice="narrator", instructions="") + cmd = self._convert( + None, [self._remote("audiocpp", "audio.cpp")]) self.assertEqual(cmd[2]["voice"], "narrator") self.assertNotIn("speaker", cmd[2]) self.assertIsNone(cmd[2]["instructions"]) @@ -1044,12 +1040,11 @@ class ConvertFlowTests(unittest.TestCase): [{"id": "Qwen3-TTS-12Hz-1.7B-Base-GGUF", "family": "qwen3_tts", "task": "tts"}], voices=[]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form( - backend="audiocpp-remote", - model_id="Qwen3-TTS-12Hz-1.7B-Base-GGUF", - audiocpp_voice="", instructions="") - self._convert(None, [self._remote("audiocpp", "audio.cpp")]) + self._answer_form( + backend="audiocpp-remote", + model_id="Qwen3-TTS-12Hz-1.7B-Base-GGUF", + audiocpp_voice="", instructions="") + self._convert(None, [self._remote("audiocpp", "audio.cpp")]) fields = self.tui.forms_seen[0][1] voice_field = self._field("audiocpp_voice") self.assertTrue(voice_field["visible"](fields)) @@ -1069,9 +1064,7 @@ class ConvertFlowTests(unittest.TestCase): "models": [{"id": "qwen", "family": "qwen3_tts", "task": "tts"}], }), encoding="utf-8") - with patch.object(hub.audiocpp_backend, "find_local_checkout", - return_value=root), \ - patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): + with patch.object(hub.audiocpp_backend, "find_local_checkout", return_value=root): self._answer_form(backend="audiocpp", model_id="qwen", audiocpp_voice="", instructions="") self._convert(None, @@ -1091,11 +1084,10 @@ class ConvertFlowTests(unittest.TestCase): # built-in speaker. self._patch_remote([{"id": "legacy", "family": "", "task": ""}], voices=[]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp-remote", model_id="legacy", - audiocpp_voice="", instructions="") - cmd = self._convert( - None, [self._remote("audiocpp", "audio.cpp")]) + self._answer_form(backend="audiocpp-remote", model_id="legacy", + audiocpp_voice="", instructions="") + cmd = self._convert( + None, [self._remote("audiocpp", "audio.cpp")]) self.assertIsNotNone(cmd) self.assertIsNone(cmd[2]["voice"]) self.assertNotIn("speaker", cmd[2]) @@ -1106,12 +1098,11 @@ class ConvertFlowTests(unittest.TestCase): def test_audiocpp_vdes_hides_voice_and_requires_instructions(self): self._patch_remote( [{"id": "design", "family": "qwen3_tts", "task": "vdes"}]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp-remote", model_id="design", - audiocpp_voice=None, - instructions="A warm British narrator") - cmd = self._convert( - None, [self._remote("audiocpp", "audio.cpp")]) + self._answer_form(backend="audiocpp-remote", model_id="design", + audiocpp_voice=None, + instructions="A warm British narrator") + cmd = self._convert( + None, [self._remote("audiocpp", "audio.cpp")]) self.assertIsNone(cmd[2]["voice"]) self.assertEqual(cmd[2]["instructions"], "A warm British narrator") fields = self.tui.forms_seen[0][1] @@ -1129,12 +1120,11 @@ class ConvertFlowTests(unittest.TestCase): self._patch_remote( [{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}], voices=["narrator"]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp-remote", model_id="higgs", - audiocpp_voice="narrator", - instructions="stale description") - cmd = self._convert( - None, [self._remote("audiocpp", "audio.cpp")]) + self._answer_form(backend="audiocpp-remote", model_id="higgs", + audiocpp_voice="narrator", + instructions="stale description") + cmd = self._convert( + None, [self._remote("audiocpp", "audio.cpp")]) self.assertEqual(cmd[2]["instructions"], "stale description") def test_audiocpp_required_voice_validates(self): @@ -1142,11 +1132,10 @@ class ConvertFlowTests(unittest.TestCase): self._patch_remote( [{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}], voices=["narrator"]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp-remote", model_id="higgs", - audiocpp_voice="narrator", instructions="") - self._convert(None, - [self._remote("audiocpp", "audio.cpp")]) + self._answer_form(backend="audiocpp-remote", model_id="higgs", + audiocpp_voice="narrator", instructions="") + self._convert(None, + [self._remote("audiocpp", "audio.cpp")]) voice_field = self._field("audiocpp_voice") self.assertIsNotNone(voice_field["validate"]("")) self.assertIsNone(voice_field["validate"]("narrator")) @@ -1157,14 +1146,12 @@ class ConvertFlowTests(unittest.TestCase): self._patch_remote( [{"id": "Qwen3-TTS-CustomVoice-GGUF", "family": "qwen3_tts", "task": "tts"}]) - with patch.object(hub.config, "SPEAKER", "Vivian"), \ - patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form( - backend="audiocpp-remote", - model_id="Qwen3-TTS-CustomVoice-GGUF", - audiocpp_voice="Vivian", instructions="") - self._convert(None, - [self._remote("audiocpp", "audio.cpp")]) + self._answer_form( + backend="audiocpp-remote", + model_id="Qwen3-TTS-CustomVoice-GGUF", + audiocpp_voice="Vivian", instructions="") + self._convert(None, + [self._remote("audiocpp", "audio.cpp")]) fields = self.tui.forms_seen[0][1] label = self._field("audiocpp_voice")["label"] self.assertEqual(label(fields), "Built-in voice") @@ -1175,12 +1162,11 @@ class ConvertFlowTests(unittest.TestCase): [{"id": "Qwen3-TTS-Base-GGUF", "family": "qwen3_tts", "task": "tts"}], voices=["narrator"]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp-remote", - model_id="Qwen3-TTS-Base-GGUF", - audiocpp_voice="narrator", instructions="") - self._convert(None, - [self._remote("audiocpp", "audio.cpp")]) + self._answer_form(backend="audiocpp-remote", + model_id="Qwen3-TTS-Base-GGUF", + audiocpp_voice="narrator", instructions="") + self._convert(None, + [self._remote("audiocpp", "audio.cpp")]) fields = self.tui.forms_seen[0][1] label = self._field("audiocpp_voice")["label"] self.assertEqual(label(fields), "Voice to clone") @@ -1192,11 +1178,10 @@ class ConvertFlowTests(unittest.TestCase): self._patch_remote( [{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}], voices=["narrator"]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp-remote", model_id="higgs", - audiocpp_voice="", instructions="") - self._convert(None, - [self._remote("audiocpp", "audio.cpp")]) + self._answer_form(backend="audiocpp-remote", model_id="higgs", + audiocpp_voice="", instructions="") + self._convert(None, + [self._remote("audiocpp", "audio.cpp")]) fields = self.tui.forms_seen[0][1] voice = self._field("audiocpp_voice") instr = self._field("instructions") @@ -1211,11 +1196,10 @@ class ConvertFlowTests(unittest.TestCase): self._patch_remote( [{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}], voices=[]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp-remote", model_id="higgs", - audiocpp_voice="", instructions="") - cmd = self._convert( - None, [self._remote("audiocpp", "audio.cpp")]) + self._answer_form(backend="audiocpp-remote", model_id="higgs", + audiocpp_voice="", instructions="") + cmd = self._convert( + None, [self._remote("audiocpp", "audio.cpp")]) fields = self.tui.forms_seen[0][1] voice = self._field("audiocpp_voice") instr = self._field("instructions") @@ -1230,13 +1214,12 @@ class ConvertFlowTests(unittest.TestCase): self._patch_remote( [{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}], voices=["narrator"]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form( - backend="audiocpp-remote", model_id="higgs", - audiocpp_voice="narrator", instructions="", - request_options="emotion=neutral, speed=1.1") - cmd = self._convert( - None, [self._remote("audiocpp", "audio.cpp")]) + self._answer_form( + backend="audiocpp-remote", model_id="higgs", + audiocpp_voice="narrator", instructions="", + request_options="emotion=neutral, speed=1.1") + cmd = self._convert( + None, [self._remote("audiocpp", "audio.cpp")]) self.assertEqual(cmd[2]["request_options"], {"emotion": "neutral", "speed": "1.1"}) @@ -1244,12 +1227,11 @@ class ConvertFlowTests(unittest.TestCase): self._patch_remote( [{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}], voices=["narrator"]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp-remote", model_id="higgs", - audiocpp_voice="narrator", instructions="", - request_options="oops") - cmd = self._convert( - None, [self._remote("audiocpp", "audio.cpp")]) + self._answer_form(backend="audiocpp-remote", model_id="higgs", + audiocpp_voice="narrator", instructions="", + request_options="oops") + cmd = self._convert( + None, [self._remote("audiocpp", "audio.cpp")]) options_field = self._field("request_options") self.assertIsNone(options_field["validate"]("emotion=neutral")) self.assertIsNotNone(options_field["validate"]("oops")) @@ -1284,9 +1266,7 @@ class ConvertFlowTests(unittest.TestCase): [{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}], voices=["narrator"]) with patch.object(hub.audiocpp_backend, "find_local_checkout", - return_value=self._specs_checkout( - ("higgs_audio_tts",))), \ - patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): + return_value=self._specs_checkout(("higgs_audio_tts",))): self._answer_form(backend="audiocpp-remote", model_id="higgs", audiocpp_voice="narrator", instructions="") cmd = self._convert( @@ -1302,9 +1282,7 @@ class ConvertFlowTests(unittest.TestCase): # A checkout exists but only qwen3_tts declares request options: # higgs is provably unsupported -> hidden. with patch.object(hub.audiocpp_backend, "find_local_checkout", - return_value=self._specs_checkout( - ("qwen3_tts",))), \ - patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): + return_value=self._specs_checkout(("qwen3_tts",))): self._answer_form(backend="audiocpp-remote", model_id="higgs", audiocpp_voice="narrator", instructions="") self._convert(None, @@ -1317,9 +1295,7 @@ class ConvertFlowTests(unittest.TestCase): self._patch_remote( [{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}], voices=["narrator"]) - with patch.object(hub.audiocpp_backend, "find_local_checkout", - return_value=None), \ - patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): + with patch.object(hub.audiocpp_backend, "find_local_checkout", return_value=None): self._answer_form(backend="audiocpp-remote", model_id="higgs", audiocpp_voice="narrator", instructions="") self._convert(None, @@ -1335,12 +1311,11 @@ class ConvertFlowTests(unittest.TestCase): {"id": "design", "family": "qwen3_tts", "task": "vdes"}, {"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}, ], voices=["narrator"]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp-remote", model_id="design", - audiocpp_voice=None, - instructions="A warm British narrator") - self._convert(None, - [self._remote("audiocpp", "audio.cpp")]) + self._answer_form(backend="audiocpp-remote", model_id="design", + audiocpp_voice=None, + instructions="A warm British narrator") + self._convert(None, + [self._remote("audiocpp", "audio.cpp")]) instr = self._field("instructions") self.assertEqual(instr["help"], [ "TTS style instructions. Supported by some clone models. Example:", @@ -1352,9 +1327,7 @@ class ConvertFlowTests(unittest.TestCase): [{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}], voices=["narrator"]) with patch.object(hub.audiocpp_backend, "find_local_checkout", - return_value=self._specs_checkout( - ("qwen3_tts", "higgs_audio_tts"))), \ - patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): + return_value=self._specs_checkout(("qwen3_tts", "higgs_audio_tts"))): self._answer_form(backend="audiocpp-remote", model_id="higgs", audiocpp_voice="narrator", instructions="") self._convert(None, @@ -1371,7 +1344,6 @@ class ConvertFlowTests(unittest.TestCase): # The Settings Language setting travels on the run kwargs as-is; # the converter normalizes it (short codes included). with patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian"]), \ - patch.object(hub.config, "SPEAKER", "Vivian"), \ patch.object(hub.config, "LANGUAGE", "en"): self._answer_form(backend="qwen", mode="custom", speaker="Vivian", clone="") @@ -1399,11 +1371,10 @@ class ConvertFlowTests(unittest.TestCase): self._patch_remote( [{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}], voices=[]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp-remote", model_id="higgs", - audiocpp_voice="", instructions="") - cmd = self._convert( - None, [self._remote("audiocpp", "audio.cpp")]) + self._answer_form(backend="audiocpp-remote", model_id="higgs", + audiocpp_voice="", instructions="") + cmd = self._convert( + None, [self._remote("audiocpp", "audio.cpp")]) self.assertIsNotNone(cmd) self.assertIsNone(cmd[2]["voice"]) fields = self.tui.forms_seen[0][1] @@ -1429,11 +1400,8 @@ class ConvertFlowTests(unittest.TestCase): "voice_dir": str(root), }), encoding="utf-8") (root / "Narrator.wav").write_bytes(b"x") - with patch.object(hub.audiocpp_backend, "find_local_checkout", - return_value=root), \ - patch.object(hub.audiocpp_backend, "fetch_server_models", - must_not_query), \ - patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): + with patch.object(hub.audiocpp_backend, "find_local_checkout", return_value=root), \ + patch.object(hub.audiocpp_backend, "fetch_server_models", must_not_query): self._answer_form(backend="audiocpp", model_id="qwen", audiocpp_voice="Narrator", instructions="") cmd = self._convert(None, @@ -1456,9 +1424,7 @@ class ConvertFlowTests(unittest.TestCase): "models": [{"id": "qwen", "family": "qwen3_tts", "task": "tts"}], }), encoding="utf-8") - with patch.object(hub.audiocpp_backend, "find_local_checkout", - return_value=root), \ - patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): + with patch.object(hub.audiocpp_backend, "find_local_checkout", return_value=root): self._answer_form(backend="audiocpp", model_id="qwen", audiocpp_voice="", instructions="") cmd = self._convert(None, [ @@ -1496,9 +1462,7 @@ class ConvertFlowTests(unittest.TestCase): "models": [{"id": "qwen", "family": "qwen3_tts", "task": "tts"}], }), encoding="utf-8") - with patch.object(hub.audiocpp_backend, "find_local_checkout", - return_value=root), \ - patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): + with patch.object(hub.audiocpp_backend, "find_local_checkout", return_value=root): # Managed selected: its picks must survive next to the # remote entry's same-shaped fields. self.tui.form_script.append({ @@ -1529,12 +1493,11 @@ class ConvertFlowTests(unittest.TestCase): self._patch_remote( [{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}], voices=["narrator"]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp-remote", model_id="higgs", - audiocpp_voice="narrator", instructions="") - cmd = self._convert( - None, [self._remote("audiocpp", "audio.cpp", - url="http://10.0.0.5:8080")]) + self._answer_form(backend="audiocpp-remote", model_id="higgs", + audiocpp_voice="narrator", instructions="") + cmd = self._convert( + None, [self._remote("audiocpp", "audio.cpp", + url="http://10.0.0.5:8080")]) self.assertEqual(cmd[2]["api_url"], "http://10.0.0.5:8080") # ------------------------------------------------------------------ @@ -1556,29 +1519,17 @@ class ConvertFlowTests(unittest.TestCase): # ------------------------------------------------------------------ def test_qwen_builds_speaker_and_clone_form(self): - with patch.object(hub.qwen_backend, "QWEN_SPEAKERS", - ["Vivian", "Serena"]), \ - patch.object(hub.config, "SPEAKER", "Vivian"), \ - patch.object(hub.qwen_backend.config, "QWEN_MODEL", - "CustomVoice"): + with patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian", "Serena"]): self._answer_form(backend="qwen", mode="custom", speaker="Serena", clone="") - # The fake mirrors the real update_config_value contract: - # persisting a value also lands it on the imported module. - def fake_update(key, value, config_path=None): - setattr(hub.config, key, value) - return True - - with patch.object(hub.common, "update_config_value", - fake_update): - cmd = self._convert(None, - [self._ready("qwen", "qwen-tts")]) - speaker_in_memory = hub.config.SPEAKER + cmd = self._convert(None, + [self._ready("qwen", "qwen-tts")]) self.assertEqual(cmd[0], "convert") self.assertEqual(cmd[1], hub.BACKEND_QWEN) self.assertIsNone(cmd[2]["clone"]) self.assertIsNone(cmd[2].get("instructions")) - self.assertEqual(speaker_in_memory, "Serena") + # The picked speaker travels with the run; nothing is persisted. + self.assertEqual(cmd[2]["voice"], "Serena") fields = self.tui.forms_seen[0][1] self.assertEqual([f["key"] for f in fields], ["backend", "mode", "speaker", "clone_dir", @@ -1617,11 +1568,8 @@ class ConvertFlowTests(unittest.TestCase): self.assertFalse(clone_field["visible"](fields)) self.assertTrue(design_field["visible"](fields)) - def test_qwen_design_mode_passes_instructions_and_persists_model(self): - with patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian"]), \ - patch.object(hub.config, "SPEAKER", "Vivian"), \ - patch.object(hub.qwen_backend.config, "QWEN_MODEL", - "CustomVoice"): + def test_qwen_design_mode_passes_instructions(self): + with patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian"]): self._answer_form(backend="qwen", mode="design", qwen_instructions="A warm narrator") with patch.object(hub.common, "update_config_value") as mk_update: @@ -1629,51 +1577,37 @@ class ConvertFlowTests(unittest.TestCase): [self._ready("qwen", "qwen-tts")]) self.assertEqual(cmd[2]["clone"], None) self.assertEqual(cmd[2]["instructions"], "A warm narrator") - # The model switch is persisted (CustomVoice -> VoiceDesign). - mk_update.assert_called_once_with("QWEN_MODEL", "VoiceDesign") + # Per-run choices are not persisted to the config file. + mk_update.assert_not_called() - def test_qwen_clone_mode_passes_path_and_persists_model(self): - with patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian"]), \ - patch.object(hub.config, "SPEAKER", "Vivian"), \ - patch.object(hub.qwen_backend.config, "QWEN_MODEL", - "CustomVoice"): + def test_qwen_clone_mode_passes_path(self): + with patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian"]): self._answer_form(backend="qwen", mode="clone", speaker="Vivian", clone="/tmp/ref.wav") with patch.object(hub.common, "update_config_value") as mk_update: cmd = self._convert(None, - [self._ready("qwen", "qwen-tts")]) + [self._ready("qwen", "qwen-tts")]) self.assertEqual(cmd[2]["clone"], "/tmp/ref.wav") - # Clone mode does not touch the global speaker. - keys = [c.args[0] for c in mk_update.call_args_list] - self.assertNotIn("SPEAKER", keys) - # ...but remembers the switch to the Base model. - self.assertEqual(keys, ["QWEN_MODEL"]) - self.assertEqual(mk_update.call_args.args[1], "Base") - - def test_qwen_same_model_run_persists_nothing_new(self): - with patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian"]), \ - patch.object(hub.config, "SPEAKER", "Vivian"), \ - patch.object(hub.qwen_backend.config, "QWEN_MODEL", - "CustomVoice"): + mk_update.assert_not_called() + + def test_qwen_custom_mode_passes_the_speaker(self): + with patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian"]): self._answer_form(backend="qwen", mode="custom", speaker="Vivian") with patch.object(hub.common, "update_config_value") as mk_update: cmd = self._convert(None, [self._ready("qwen", "qwen-tts")]) self.assertIsNotNone(cmd) + self.assertEqual(cmd[2]["voice"], "Vivian") mk_update.assert_not_called() - def test_qwen_form_opens_on_the_configured_model(self): - # The persisted QWEN_MODEL seeds the Model picker's default, so the - # form opens on what the last run chose (not always the first row). + def test_qwen_form_defaults_to_the_first_model(self): + # No persisted default: the Model picker opens on CustomVoice. with patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian"]), \ - patch.object(hub.config, "SPEAKER", "Vivian"), \ - patch.object(hub.qwen_backend.config, "QWEN_MODEL", - "VoiceDesign"), \ patch.object(hub.common, "update_config_value"): self._answer_form(backend="qwen", mode="design", qwen_instructions="A warm narrator") self._convert(None, [self._ready("qwen", "qwen-tts")]) - self.assertEqual(self._field("mode")["value"], "design") + self.assertEqual(self._field("mode")["value"], "custom") def test_qwen_clone_dir_defaults_to_the_project_voices(self): # The Clone .wav directory is the shared directory widget, seeded @@ -1689,9 +1623,7 @@ class ConvertFlowTests(unittest.TestCase): ("narrator.wav", str(root / "narrator.wav")), ] with patch.object(hub.common, "VOICES_DIR", root), \ - patch.object(hub.qwen_backend, "QWEN_SPEAKERS", - ["Vivian"]), \ - patch.object(hub.config, "SPEAKER", "Vivian"), \ + patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian"]), \ patch.object(hub.common, "update_config_value"): self._answer_form(backend="qwen", mode="custom", speaker="Vivian") @@ -1720,9 +1652,7 @@ class ConvertFlowTests(unittest.TestCase): (other / "beta.wav").write_bytes(b"") (other / "alpha.wav").write_bytes(b"") with patch.object(hub.common, "VOICES_DIR", root), \ - patch.object(hub.qwen_backend, "QWEN_SPEAKERS", - ["Vivian"]), \ - patch.object(hub.config, "SPEAKER", "Vivian"), \ + patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian"]), \ patch.object(hub.common, "update_config_value"): self._answer_form(backend="qwen", mode="clone", clone="") self._convert(None, [self._ready("qwen", "qwen-tts")]) @@ -1746,9 +1676,7 @@ class ConvertFlowTests(unittest.TestCase): with tempfile.TemporaryDirectory() as td: empty = Path(td) with patch.object(hub.common, "VOICES_DIR", empty), \ - patch.object(hub.qwen_backend, "QWEN_SPEAKERS", - ["Vivian"]), \ - patch.object(hub.config, "SPEAKER", "Vivian"), \ + patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian"]), \ patch.object(hub.common, "update_config_value"): self._answer_form(backend="qwen", mode="clone", clone="") cmd = self._convert(None, @@ -1846,8 +1774,7 @@ class ConvertFlowTests(unittest.TestCase): "qwen", "qwen-tts", remote_urls={"qwen": "http://10.0.0.5:7861"}, remote_models=["Base"]) - with patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian"]), \ - patch.object(hub.config, "SPEAKER", "Vivian"): + with patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian"]): self._answer_form(backend="qwen-remote", mode="clone", speaker="Vivian", clone="/tmp/ref.wav") cmd = self._convert(None, [st]) @@ -1870,9 +1797,7 @@ class ConvertFlowTests(unittest.TestCase): "models": [{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}], }), encoding="utf-8") - with patch.object(hub.audiocpp_backend, "find_local_checkout", - return_value=root), \ - patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): + with patch.object(hub.audiocpp_backend, "find_local_checkout", return_value=root): self._answer_form(backend="qwen", mode="custom", speaker="Vivian", clone="") cmd = self._convert(None, [ @@ -1974,7 +1899,11 @@ class PrepareRunConfigTests(unittest.TestCase): with patch.object(hub, "detect_all", return_value=[]), \ patch.object(hub, "_find_spec", return_value=spec): cfg = hub._prepare_run_config("qwen", kwargs) - self.assertIs(cfg.autostart_spec, spec) + # The qwen spec is rebuilt for the model this run selected, so an + # autostart boots exactly what the conversion needs. + self.assertEqual(cfg.autostart_spec.name, "qwen") + self.assertEqual(cfg.autostart_spec.identity, "qwen-custom") + self.assertEqual(cfg.autostart_spec.url, spec.url) self.assertFalse(cfg.restart_first) self.assertEqual(cfg.server_name, "qwen") self.assertNotIn("autostart", kwargs) @@ -1985,13 +1914,15 @@ class PrepareRunConfigTests(unittest.TestCase): spec = self._spec() status = BackendStatus("qwen", "qwen-tts", installed=True, configured=True, servers=[spec]) - kwargs = {"restart_server": "qwen"} + kwargs = {"restart_server": "qwen", "clone": "/tmp/ref.wav"} with patch.object(hub, "detect_all", return_value=[status]), \ patch("backends.common.server_running", return_value=True), \ patch.object(hub.servers, "alive", return_value=True): cfg = hub._prepare_run_config("qwen", kwargs) - self.assertIs(cfg.autostart_spec, spec) + self.assertEqual(cfg.autostart_spec.name, spec.name) + # The restart spec hosts the Base model (the run clones a voice). + self.assertEqual(cfg.autostart_spec.identity, "qwen-clone") self.assertTrue(cfg.restart_first) self.assertNotIn("restart_server", kwargs) self.assertEqual(cfg.server_url, spec.url) |
