aboutsummaryrefslogtreecommitdiff
path: root/app/tests/test_hub.py
diff options
context:
space:
mode:
authorhistoria <historiavg@proton.me>2026-09-02 20:33:44 -0400
committerhistoria <historiavg@proton.me>2026-09-02 20:33:44 -0400
commitdfce6c38a9a67ea2760fedae73ee9f5989d52f13 (patch)
tree4212258c63908201c9720d016f0ea86d7f209aae /app/tests/test_hub.py
parent08e702700303f9bb5767f02a337b8b34be410df9 (diff)
downloadtts-audiobook-generator-dfce6c38a9a67ea2760fedae73ee9f5989d52f13.tar.gz
feat: add model and voice labels to generate audiobooks status tui
Diffstat (limited to 'app/tests/test_hub.py')
-rw-r--r--app/tests/test_hub.py57
1 files changed, 56 insertions, 1 deletions
diff --git a/app/tests/test_hub.py b/app/tests/test_hub.py
index f49b8d1..e38acbe 100644
--- a/app/tests/test_hub.py
+++ b/app/tests/test_hub.py
@@ -1445,6 +1445,9 @@ class ConvertFlowTests(unittest.TestCase):
{"alpha": "narrator", "beta": "narrator"})
self.assertNotIn("model_id", kwargs)
self.assertNotIn("voice", kwargs)
+ # The run view's header rows: an "All" summary plus the picked voice.
+ self.assertEqual(kwargs["run_model"], "All (2 models)")
+ self.assertEqual(kwargs["run_voice"], "narrator")
self.assertEqual(kwargs["api_url"], "http://audiocpp.local:8080")
self.assertEqual(mk_pre.call_count, 2)
self.assertEqual(mk_pre.call_args_list[0].kwargs["name_tag"],
@@ -1824,6 +1827,9 @@ class ConvertFlowTests(unittest.TestCase):
cmd = self._convert(
None, [self._remote("audiocpp", "audio.cpp")])
self.assertEqual(cmd[2]["instructions"], "stale description")
+ # The single pick's model and voice name the run view's rows.
+ self.assertEqual(cmd[2]["run_model"], "higgs")
+ self.assertEqual(cmd[2]["run_voice"], "narrator")
def test_audiocpp_required_voice_validates(self):
# A clone-only family (Chatterbox) needs a --voice; a blank value
@@ -2311,6 +2317,9 @@ class ConvertFlowTests(unittest.TestCase):
self.assertIsNone(cmd[2].get("instructions"))
# The picked speaker travels with the run; nothing is persisted.
self.assertEqual(cmd[2]["voice"], "Serena")
+ # The run view's rows show the mode word and the speaker.
+ self.assertEqual(cmd[2]["run_model"], "CustomVoice")
+ self.assertEqual(cmd[2]["run_voice"], "Serena")
fields = self.tui.forms_seen[0][1]
self.assertEqual([f["key"] for f in fields],
["backend", "qwen.mode", "qwen.speaker",
@@ -2355,6 +2364,9 @@ class ConvertFlowTests(unittest.TestCase):
[self._ready("qwen", "qwen-tts")])
self.assertEqual(cmd[2]["clone"], None)
self.assertEqual(cmd[2]["instructions"], "A warm narrator")
+ # VoiceDesign designs the voice: a mode word, but no voice row.
+ self.assertEqual(cmd[2]["run_model"], "VoiceDesign")
+ self.assertEqual(cmd[2]["run_voice"], "")
# Per-run choices are not persisted to the config file.
mk_update.assert_not_called()
@@ -2366,6 +2378,10 @@ class ConvertFlowTests(unittest.TestCase):
cmd = self._convert(None,
[self._ready("qwen", "qwen-tts")])
self.assertEqual(cmd[2]["clone"], "/tmp/ref.wav")
+ # The run view's rows: the mode word and the reference .wav's
+ # file name (no extension).
+ self.assertEqual(cmd[2]["run_model"], "Base")
+ self.assertEqual(cmd[2]["run_voice"], "ref")
mk_update.assert_not_called()
def test_qwen_custom_mode_passes_the_speaker(self):
@@ -2503,6 +2519,9 @@ class ConvertFlowTests(unittest.TestCase):
cmd = self._convert(None, [st])
self.assertIsNotNone(cmd)
self.assertIs(self.nav, hub.tui.Wizard.BACK)
+ # faster has no model pick: the run view shows the voice only.
+ self.assertNotIn("run_model", cmd[2])
+ self.assertEqual(cmd[2]["run_voice"], "obama")
def test_settings_default_feeds_the_stop_and_exit_toggle(self):
# The Settings menu's "Stop server and exit" value decides the
@@ -2621,6 +2640,9 @@ class ConvertFlowTests(unittest.TestCase):
kwargs = cmd[2]
self.assertEqual(kwargs["model_id"], entry.key)
self.assertEqual(kwargs["voice"], "Vivian")
+ # The run view's rows: the catalog label and the preset voice.
+ self.assertEqual(kwargs["run_model"], entry.label)
+ self.assertEqual(kwargs["run_voice"], "Vivian")
self.assertNotIn("clone", kwargs)
self.assertNotIn("api_url", kwargs)
@@ -2649,6 +2671,9 @@ class ConvertFlowTests(unittest.TestCase):
self.assertEqual(kwargs["clone"], str(ref))
# The .wav pick rides the clone kwarg; no named voice is sent.
self.assertNotIn("voice", kwargs)
+ # The run view's voice row names the reference (no extension).
+ self.assertEqual(kwargs["run_model"], entry.label)
+ self.assertEqual(kwargs["run_voice"], "ref")
# The combined Voice menu opens on the built-in default voice,
# with the built-in entry above the clone directory's .wavs.
self.assertEqual(voice_field["value"], "")
@@ -2671,6 +2696,8 @@ class ConvertFlowTests(unittest.TestCase):
kwargs = cmd[2]
self.assertNotIn("clone", kwargs)
self.assertNotIn("voice", kwargs)
+ # A blank pick is the model's own default: no voice row either.
+ self.assertEqual(kwargs["run_voice"], "")
def test_sglomni_managed_design_model_sends_instructions(self):
entry = hub.sglomni_backend.entry_by_key("qwen3_tts_1_7b_voicedesign")
@@ -2690,6 +2717,9 @@ class ConvertFlowTests(unittest.TestCase):
self.assertEqual(kwargs["instructions"], "A warm narrator.")
self.assertNotIn("clone", kwargs)
self.assertNotIn("voice", kwargs)
+ # Design models describe the voice: a model row, no voice row.
+ self.assertEqual(kwargs["run_model"], entry.label)
+ self.assertEqual(kwargs["run_voice"], "")
def test_sglomni_remote_offers_the_hosted_model_and_uploaded_voices(self):
served = patch.object(hub.backend_probe, "sglomni_served_model",
@@ -2927,11 +2957,16 @@ class PrepareRunConfigTests(unittest.TestCase):
def test_remote_targets_the_api_url(self):
with patch.object(hub, "detect_all", return_value=[]) as mk_detect:
cfg = hub._prepare_run_config(
- "audiocpp", {"api_url": "http://10.0.0.5:8080"})
+ "audiocpp", {"api_url": "http://10.0.0.5:8080",
+ "run_model": "alpha", "run_voice": "narrator"})
self.assertEqual(cfg.server_url, "http://10.0.0.5:8080")
self.assertIsNone(cfg.autostart_spec)
self.assertEqual(cfg.server_identity, "audiocpp")
self.assertIn("remote", cfg.backend_label)
+ # The display picks reach the remote config too (the run view's
+ # Model/Voice rows draw there as well).
+ self.assertEqual(cfg.model_label, "alpha")
+ self.assertEqual(cfg.voice_label, "narrator")
# The remote path never re-detects or touches managed-instance state.
mk_detect.assert_not_called()
@@ -3015,6 +3050,26 @@ class PrepareRunConfigTests(unittest.TestCase):
self.assertIn("skipped non-TTS model(s): plex", cfg.notice)
self.assertIn("re-hosted clone-only", cfg.notice)
+ def test_run_model_and_voice_picks_move_onto_the_config(self):
+ # The form's display picks (the run view's Model/Voice rows) ride
+ # along like run_notice: popped from the converter kwargs and
+ # stored on the config, never passed to convert().
+ kwargs = {"run_model": "qwen3_tts", "run_voice": "Vivian"}
+ with patch.object(hub, "detect_all", return_value=[]):
+ cfg = hub._prepare_run_config("audiocpp", kwargs)
+ self.assertEqual(cfg.model_label, "qwen3_tts")
+ self.assertEqual(cfg.voice_label, "Vivian")
+ self.assertNotIn("run_model", kwargs)
+ self.assertNotIn("run_voice", kwargs)
+
+ def test_missing_run_picks_default_to_blank_labels(self):
+ # No picks recorded (faster, or a backend the form could not
+ # name): blank labels keep both header rows hidden.
+ with patch.object(hub, "detect_all", return_value=[]):
+ cfg = hub._prepare_run_config("faster", {})
+ self.assertEqual(cfg.model_label, "")
+ self.assertEqual(cfg.voice_label, "")
+
def test_stop_and_exit_travels_on_the_config_not_the_kwargs(self):
# The run-view toggle is not a converter kwarg: it moves onto the
# config (and defaults to off when the form did not send it).