From 1ff9a635bd9b033b631a6b525891b7eb44e189d3 Mon Sep 17 00:00:00 2001 From: historia Date: Mon, 24 Aug 2026 16:08:33 -0400 Subject: feat: clearer split between local (managed) and remote URLs and server status --- app/tests/test_hub.py | 273 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 217 insertions(+), 56 deletions(-) (limited to 'app/tests/test_hub.py') diff --git a/app/tests/test_hub.py b/app/tests/test_hub.py index f40b72d..725f4f6 100644 --- a/app/tests/test_hub.py +++ b/app/tests/test_hub.py @@ -75,29 +75,33 @@ class HubHelperTests(unittest.TestCase): def test_status_mark(self): from backends import BackendStatus - running = BackendStatus("k", "l", installed=True, configured=True, - running=True, managed=True) + local = BackendStatus("k", "l", installed=True, configured=True, + running=True, managed=True) remote = BackendStatus("k", "l", installed=True, configured=True, - running=True) + running=True, remote=True) + both = BackendStatus("k", "l", installed=True, configured=True, + running=True, managed=True, remote=True) models = BackendStatus("k", "l", installed=True, configured=True, running=True, managed=True, running_models=["Base", "CustomVoice"]) remote_models = BackendStatus("k", "l", installed=True, configured=True, running=True, - running_models=["Base"]) + remote=True, running_models=["Base"]) installed = BackendStatus("k", "l", installed=True, configured=False) none = BackendStatus("k", "l", installed=False, configured=False) # running beats installed (a server is up even if not configured); # only a backend that is neither installed nor running is dimmed. - self.assertEqual(hub._status_mark(running), - ("running", "ok", "body")) - # A server without a live recorded pid was started externally. + self.assertEqual(hub._status_mark(local), + ("running [local]", "ok", "body")) + # A server this tool did not start, found at the remote URL. self.assertEqual(hub._status_mark(remote), ("running [remote]", "ok", "body")) + self.assertEqual(hub._status_mark(both), + ("running [local, remote]", "ok", "body")) # Multi-model backends name the models that answered. self.assertEqual(hub._status_mark(models), - ("running (Base, CustomVoice)", "ok", "body")) + ("running [local] (Base, CustomVoice)", "ok", "body")) self.assertEqual(hub._status_mark(remote_models), ("running [remote] (Base)", "ok", "body")) self.assertEqual(hub._status_mark(installed), @@ -183,12 +187,13 @@ class HubMenuTests(unittest.TestCase): dead = self._none_status("audiocpp", "audio.cpp") external = self._none_status("qwen", "qwen-tts") external.running = True + external.remote = True with patch.object(hub.tui, "menu", fake_menu), \ patch.object(hub, "detect_all", return_value=[dead, external]): hub._hub_menu(screen) # Unusable backend: dim name. Running-but-not-installed stays - # bright and is tagged remote (no pid file → not started by us). + # bright and is tagged remote (found at its remote URL). self.assertEqual( captured["rows"], [("audio.cpp", "unavailable", "err", "dim"), @@ -308,7 +313,7 @@ class SubmenuStatusTableTests(unittest.TestCase): BackendStatus("audiocpp", "audio.cpp", installed=True, configured=True), BackendStatus("qwen", "qwen-tts", installed=False, - configured=False, running=True), + configured=False, running=True, remote=True), ] with patch.object(hub, "REGISTRY", infos), \ patch.object(hub.tui, "menu", @@ -468,35 +473,45 @@ class ConvertFlowTests(unittest.TestCase): # ------------------------------------------------------------------ def _patch_remote(self, models, voices=None): - """No local checkout; fetch helpers return MODELS/VOICES.""" - checkout = patch.object(hub.audiocpp_backend, "find_local_checkout", - return_value=None) + """Fetch helpers return MODELS/VOICES for a remote audio.cpp server.""" fetched_models = patch.object(hub.audiocpp_backend, "fetch_server_models", lambda url: models) fetched_voices = patch.object(hub.audiocpp_backend, "fetch_server_voices", lambda url, model_id: voices) - for patcher in (checkout, fetched_models, fetched_voices): + for patcher in (fetched_models, fetched_voices): patcher.start() self.addCleanup(patcher.stop) + def _remote(self, key, label, spec_name=None, url=None, + remote_urls=None, remote_models=None): + """A running remote backend status (not installed on this machine).""" + if remote_urls is None: + remote_urls = {spec_name or key: + url or f"http://{key}.local:8080"} + return BackendStatus(key, label, installed=False, configured=False, + running=True, remote=True, + remote_urls=remote_urls, + remote_models=list(remote_models or [])) + def test_audiocpp_remote_builds_one_form(self): 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", model_id="higgs", + self._answer_form(backend="audiocpp-remote", model_id="higgs", audiocpp_voice="narrator", instructions="", speed="1.5") - cmd = hub._convert_menu(None, - [self._ready("audiocpp", "audio.cpp")]) + cmd = hub._convert_menu( + None, [self._remote("audiocpp", "audio.cpp")]) self.assertEqual(cmd[0], "convert") self.assertEqual(cmd[1], hub.BACKEND_AUDIOCPP) kwargs = cmd[2] self.assertEqual(kwargs["model_id"], "higgs") self.assertEqual(kwargs["voice"], "narrator") self.assertIsNone(kwargs["instructions"]) + self.assertEqual(kwargs["api_url"], "http://audiocpp.local:8080") self.assertEqual(kwargs["output_format"], "m4b") self.assertEqual(kwargs["speed"], 1.5) self.assertFalse(kwargs["single_file"]) @@ -511,8 +526,9 @@ class ConvertFlowTests(unittest.TestCase): "single_file", "debug"]) self.assertEqual(form_kwargs["buttons"], ("Generate!", "Cancel")) self.assertTrue(form_kwargs["start_on_buttons"]) - # The backend field offers the ready backend. - self.assertEqual(fields[0]["choices"], [("audio.cpp", "audiocpp")]) + # The backend field offers the remote entry under a [remote] label. + self.assertEqual(fields[0]["choices"], + [("audio.cpp [remote]", "audiocpp-remote")]) # The model menu was fed from the live query (label, id). self.assertEqual(self._field("model_id")["choices"], [("higgs (higgs_audio_tts, tts)", "higgs")]) @@ -522,11 +538,11 @@ class ConvertFlowTests(unittest.TestCase): [{"id": "qwen", "family": "qwen3_tts", "task": "tts"}], voices=["narrator"]) with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp", model_id="qwen", + self._answer_form(backend="audiocpp-remote", model_id="qwen", audiocpp_voice="(built-in speaker)", instructions="") - cmd = hub._convert_menu(None, - [self._ready("audiocpp", "audio.cpp")]) + cmd = hub._convert_menu( + None, [self._remote("audiocpp", "audio.cpp")]) # The sentinel maps to "no voice" (built-in speaker). self.assertIsNone(cmd[2]["voice"]) fields = self.tui.forms_seen[0][1] @@ -542,11 +558,11 @@ class ConvertFlowTests(unittest.TestCase): self._patch_remote([{"id": "legacy", "family": "", "task": ""}], voices=[]) with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp", model_id="legacy", + self._answer_form(backend="audiocpp-remote", model_id="legacy", audiocpp_voice="(built-in speaker)", instructions="") - cmd = hub._convert_menu(None, - [self._ready("audiocpp", "audio.cpp")]) + cmd = hub._convert_menu( + None, [self._remote("audiocpp", "audio.cpp")]) self.assertIsNotNone(cmd) self.assertIsNone(cmd[2]["voice"]) @@ -554,11 +570,11 @@ class ConvertFlowTests(unittest.TestCase): self._patch_remote( [{"id": "design", "family": "qwen3_tts", "task": "vdes"}]) with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp", model_id="design", + self._answer_form(backend="audiocpp-remote", model_id="design", audiocpp_voice=None, instructions="A warm British narrator") - cmd = hub._convert_menu(None, - [self._ready("audiocpp", "audio.cpp")]) + cmd = hub._convert_menu( + 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] @@ -574,25 +590,25 @@ class ConvertFlowTests(unittest.TestCase): [{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}], voices=["narrator"]) with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp", model_id="higgs", + self._answer_form(backend="audiocpp-remote", model_id="higgs", audiocpp_voice="narrator", instructions="") hub._convert_menu(None, - [self._ready("audiocpp", "audio.cpp")]) + [self._remote("audiocpp", "audio.cpp")]) voice_field = self._field("audiocpp_voice") self.assertIsNotNone(voice_field["validate"]("")) self.assertIsNone(voice_field["validate"]("narrator")) def test_audiocpp_remote_unreachable_models_flash_and_abort(self): self._patch_remote(None) # endpoint did not answer valid JSON - cmd = hub._convert_menu(None, - [self._ready("audiocpp", "audio.cpp")]) + cmd = hub._convert_menu( + None, [self._remote("audiocpp", "audio.cpp")]) self.assertIsNone(cmd) self.assertIn("Could not list models", self.tui.flashes[0]) def test_audiocpp_remote_empty_models_flash_and_abort(self): self._patch_remote([]) - cmd = hub._convert_menu(None, - [self._ready("audiocpp", "audio.cpp")]) + cmd = hub._convert_menu( + None, [self._remote("audiocpp", "audio.cpp")]) self.assertIsNone(cmd) self.assertIn("hosts no model entries", self.tui.flashes[0]) @@ -603,10 +619,10 @@ class ConvertFlowTests(unittest.TestCase): [{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}], voices=[]) with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="audiocpp", model_id="higgs", + self._answer_form(backend="audiocpp-remote", model_id="higgs", audiocpp_voice="", instructions="") - cmd = hub._convert_menu(None, - [self._ready("audiocpp", "audio.cpp")]) + cmd = hub._convert_menu( + None, [self._remote("audiocpp", "audio.cpp")]) self.assertIsNotNone(cmd) self.assertIsNone(cmd[2]["voice"]) fields = self.tui.forms_seen[0][1] @@ -646,6 +662,50 @@ class ConvertFlowTests(unittest.TestCase): self.assertEqual(cmd[2]["model_id"], "qwen") self.assertEqual(cmd[2]["voice"], "Narrator") + def test_managed_and_remote_both_offered(self): + # A ready managed audio.cpp (server.json) AND a running remote + # audio.cpp: both entries appear. The managed entry reads server.json + # (no api_url), the remote entry live-queries (api_url set). + self._patch_remote( + [{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}], + voices=["narrator"]) + with tempfile.TemporaryDirectory() as td: + root = Path(td) + (root / "server.json").write_text(json.dumps({ + "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", ""): + self._answer_form(backend="audiocpp", model_id="qwen", + audiocpp_voice="(built-in speaker)", + instructions="") + cmd = hub._convert_menu(None, [ + self._ready("audiocpp", "audio.cpp"), + self._remote("audiocpp", "audio.cpp")]) + self.assertEqual(cmd[0], "convert") + self.assertEqual(cmd[1], hub.BACKEND_AUDIOCPP) + # Managed entry: no api_url override (uses the configured local URL). + self.assertNotIn("api_url", cmd[2]) + self.assertEqual(cmd[2]["model_id"], "qwen") + fields = self.tui.forms_seen[0][1] + self.assertEqual(fields[0]["choices"], + [("audio.cpp", "audiocpp"), + ("audio.cpp [remote]", "audiocpp-remote")]) + + def test_audiocpp_remote_mapper_adds_api_url(self): + 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 = hub._convert_menu( + 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") + # ------------------------------------------------------------------ # common fields: output format, speed, single-file, debug # ------------------------------------------------------------------ @@ -740,6 +800,36 @@ class ConvertFlowTests(unittest.TestCase): self.assertEqual(voice_field["choices"], [("default", "default"), ("obama", "obama")]) + def test_faster_remote_uses_text_voice_and_api_url(self): + st = self._remote("faster", "faster-qwen3-tts", + url="http://10.0.0.5:8000") + self._answer_form(backend="faster-remote", faster_voice="obama") + cmd = hub._convert_menu(None, [st]) + self.assertEqual(cmd[0], "convert") + self.assertEqual(cmd[1], "faster") + self.assertEqual(cmd[2]["voice"], "obama") + self.assertEqual(cmd[2]["api_url"], "http://10.0.0.5:8000") + self.assertEqual(self._field("faster_voice")["kind"], "text") + + def test_qwen_remote_limited_modes_and_api_url(self): + # A remote qwen with only the Base (clone) demo answering: the form + # offers only clone mode and targets the clone remote URL. + st = self._remote( + "qwen", "qwen-tts", + remote_urls={"qwen-clone": "http://10.0.0.5:7861"}, + remote_models=["Base"]) + with patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian"]), \ + patch.object(hub.config, "SPEAKER", "Vivian"): + self._answer_form(backend="qwen-remote", mode="clone", + speaker="Vivian", clone="/tmp/ref.wav") + cmd = hub._convert_menu(None, [st]) + self.assertEqual(cmd[1], hub.BACKEND_QWEN) + self.assertEqual(cmd[2]["clone"], "/tmp/ref.wav") + self.assertEqual(cmd[2]["api_url"], "http://10.0.0.5:7861") + fields = self.tui.forms_seen[0][1] + self.assertEqual(self._field("mode")["choices"], + [("Clone from a .wav file", "clone")]) + # ------------------------------------------------------------------ # multiple backends: the Backend picker gates which options show # ------------------------------------------------------------------ @@ -747,15 +837,20 @@ class ConvertFlowTests(unittest.TestCase): def test_multiple_backends_gate_options_on_backend_value(self): # Two ready backends: the form leads with a Backend picker and the # per-backend fields are hidden/shown by its value. - self._patch_remote( - [{"id": "higgs", "family": "higgs_audio_tts", "task": "tts"}], - voices=["narrator"]) - with patch.object(hub.config, "AUDIOCPP_INSTRUCTIONS", ""): - self._answer_form(backend="qwen", mode="custom", speaker="Vivian", - clone="") - cmd = hub._convert_menu(None, [ - self._ready("audiocpp", "audio.cpp"), - self._ready("qwen", "qwen-tts")]) + with tempfile.TemporaryDirectory() as td: + root = Path(td) + (root / "server.json").write_text(json.dumps({ + "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", ""): + self._answer_form(backend="qwen", mode="custom", + speaker="Vivian", clone="") + cmd = hub._convert_menu(None, [ + self._ready("audiocpp", "audio.cpp"), + self._ready("qwen", "qwen-tts")]) self.assertEqual(cmd[0], "convert") self.assertEqual(cmd[1], hub.BACKEND_QWEN) fields = self.tui.forms_seen[0][1] @@ -882,6 +977,33 @@ class RunConversionTests(unittest.TestCase): hub._run_conversion("qwen", {}) mk_conv.assert_called_once() + def test_remote_conversion_skips_setup_checks(self): + # A remote conversion targets an external server: no autostart, no + # "not fully set up" warning, no launch hint — just convert. + with patch.object(hub, "detect_all", return_value=[]) as mk_detect, \ + patch.object(hub.audiobook, "convert", return_value=0) as mk_conv: + hub._run_conversion("audiocpp", {"api_url": "http://10.0.0.5:8080"}) + mk_conv.assert_called_once_with( + backend="audiocpp", api_url="http://10.0.0.5:8080") + # The remote path never re-detects or touches managed-instance state. + mk_detect.assert_not_called() + + def test_managed_conversion_warns_when_port_occupied_by_other_server(self): + spec = ServerSpec("audiocpp", "http://127.0.0.1:8080", ["x"]) + status = BackendStatus("audiocpp", "audio.cpp", installed=True, + configured=True, running=False, + servers=[spec]) + with patch.object(hub, "detect_all", return_value=[status]), \ + patch.object(hub, "_select_spec", return_value=spec), \ + patch("backends.common.server_running", return_value=True), \ + patch.object(hub.servers, "alive", return_value=False), \ + patch.object(hub.audiobook, "convert", return_value=0) as mk_conv, \ + patch("builtins.print") as mk_print: + hub._run_conversion("audiocpp", {}) + mk_conv.assert_called_once() + printed = " ".join(str(call.args[0]) for call in mk_print.call_args_list) + self.assertIn("did not start", printed) + class AddAutostartTests(unittest.TestCase): """_add_autostart: always starts the server when it isn't running.""" @@ -906,6 +1028,13 @@ class AddAutostartTests(unittest.TestCase): hub._add_autostart(cmd, [self._status()]) self.assertNotIn("autostart", cmd[2]) + def test_no_autostart_for_remote_conversion(self): + # A remote conversion (api_url set) never autostarts: the server is + # external to this tool, so there is nothing to start/stop here. + cmd = ("convert", "audiocpp", {"api_url": "http://10.0.0.5:8080"}) + hub._add_autostart(cmd, []) + self.assertNotIn("autostart", cmd[2]) + class SettingsTests(unittest.TestCase): """Settings menu: field collection, validation, config.py writing.""" @@ -955,17 +1084,24 @@ class SettingsTests(unittest.TestCase): original = {name: getattr(hub.config, name) for name in ("AUDIO_FORMAT", "AUDIO_BITRATE", "LANGUAGE", "CHUNK_SIZE", "QWEN_API_URL", "CLONE_API_URL", - "FASTER_API_URL", "AUDIOCPP_API_URL")} + "FASTER_API_URL", "AUDIOCPP_API_URL", + "QWEN_REMOTE_URL", "CLONE_REMOTE_URL", + "FASTER_REMOTE_URL", "AUDIOCPP_REMOTE_URL")} self.addCleanup(lambda: [setattr(hub.config, name, value) for name, value in original.items()]) values = {"audio_format": "ogg", "audio_bitrate": " 192k ", "language": "en", "chunk_size": "300", "qwen_custom_port": "7862", "qwen_clone_port": "7863", - "faster_port": "8001", "audiocpp_port": "8081"} + "faster_port": "8001", "audiocpp_port": "8081", + "audiocpp_remote_url": "10.0.0.5:8080", + "faster_remote_url": "http://10.0.0.6:8000", + "qwen_custom_remote_url": "", + "qwen_clone_remote_url": ""} with patch.object(hub, "_write_config", fake_write), \ patch.object(hub, "_sync_audiocpp_server_port"): hub._apply_settings(values) - # Values are trimmed and language normalized to a display name. + # Values are trimmed and language normalized to a display name; + # remote URLs are normalized to full http(s) URLs (empty = off). self.assertEqual(written, {"AUDIO_FORMAT": "ogg", "AUDIO_BITRATE": "192k", "LANGUAGE": "English", @@ -974,7 +1110,13 @@ class SettingsTests(unittest.TestCase): "CLONE_API_URL": "http://127.0.0.1:7863", "FASTER_API_URL": "http://127.0.0.1:8001", "AUDIOCPP_API_URL": - "http://127.0.0.1:8081"}) + "http://127.0.0.1:8081", + "QWEN_REMOTE_URL": "", + "CLONE_REMOTE_URL": "", + "FASTER_REMOTE_URL": + "http://10.0.0.6:8000", + "AUDIOCPP_REMOTE_URL": + "http://10.0.0.5:8080"}) # In-memory config is reloaded so this session sees the change. self.assertEqual(hub.config.AUDIO_FORMAT, "ogg") self.assertEqual(hub.config.AUDIO_BITRATE, "192k") @@ -982,12 +1124,16 @@ class SettingsTests(unittest.TestCase): self.assertEqual(hub.config.CHUNK_SIZE, 300) self.assertEqual(hub.config.QWEN_API_URL, "http://127.0.0.1:7862") self.assertEqual(hub.config.FASTER_API_URL, "http://127.0.0.1:8001") + self.assertEqual(hub.config.AUDIOCPP_REMOTE_URL, + "http://10.0.0.5:8080") def test_apply_settings_rejects_bad_values(self): original = {name: getattr(hub.config, name) for name in ("AUDIO_FORMAT", "AUDIO_BITRATE", "LANGUAGE", "CHUNK_SIZE", "QWEN_API_URL", "CLONE_API_URL", - "FASTER_API_URL", "AUDIOCPP_API_URL")} + "FASTER_API_URL", "AUDIOCPP_API_URL", + "QWEN_REMOTE_URL", "CLONE_REMOTE_URL", + "FASTER_REMOTE_URL", "AUDIOCPP_REMOTE_URL")} self.addCleanup(lambda: [setattr(hub.config, name, value) for name, value in original.items()]) base = {"audio_format": "m4b", "audio_bitrate": "128k", @@ -1001,6 +1147,9 @@ class SettingsTests(unittest.TestCase): hub._apply_settings({**base, "chunk_size": "0"}) with self.assertRaises(ValueError): hub._apply_settings({**base, "audiocpp_port": "70000"}) + with self.assertRaises(ValueError): + hub._apply_settings({**base, + "audiocpp_remote_url": "not a url"}) mk_write.assert_not_called() def test_field_validators(self): @@ -1044,18 +1193,24 @@ class SettingsTests(unittest.TestCase): self.assertEqual([f["key"] for f in captured["fields"]], ["audio_format", "audio_bitrate", "language", "chunk_size", "audiocpp_port", "faster_port", - "qwen_custom_port", "qwen_clone_port"]) + "qwen_custom_port", "qwen_clone_port", + "audiocpp_remote_url", "faster_remote_url", + "qwen_custom_remote_url", "qwen_clone_remote_url"]) kinds = {f["key"]: f["kind"] for f in captured["fields"]} self.assertEqual(kinds["audio_format"], "choice") self.assertEqual(kinds["audio_bitrate"], "text") self.assertEqual(kinds["audiocpp_port"], "text") + self.assertEqual(kinds["audiocpp_remote_url"], "text") labels = {f["key"]: f["label"] for f in captured["fields"]} self.assertEqual(labels["qwen_clone_port"], "qwen-tts Base port") + self.assertEqual(labels["audiocpp_remote_url"], + "audio.cpp remote URL") self.assertNotIn("(clone)", " ".join(labels.values())) - # The ports section note hangs off the first port field so it - # renders between the output settings and the ports. + # The ports section note hangs off the first port field, the remote + # section note off the first remote URL field. notes = {f["key"]: f.get("note") for f in captured["fields"]} self.assertTrue(notes["audiocpp_port"]) + self.assertTrue(notes["audiocpp_remote_url"]) self.assertIsNone(notes["audio_format"]) self.assertIsNone(notes["qwen_custom_port"]) self.assertEqual(applied, [{"audio_format": "ogg", @@ -1094,7 +1249,9 @@ class SettingsTests(unittest.TestCase): original = {name: getattr(hub.config, name) for name in ("AUDIO_FORMAT", "AUDIO_BITRATE", "LANGUAGE", "CHUNK_SIZE", "QWEN_API_URL", "CLONE_API_URL", - "FASTER_API_URL", "AUDIOCPP_API_URL")} + "FASTER_API_URL", "AUDIOCPP_API_URL", + "QWEN_REMOTE_URL", "CLONE_REMOTE_URL", + "FASTER_REMOTE_URL", "AUDIOCPP_REMOTE_URL")} self.addCleanup(lambda: [setattr(hub.config, name, value) for name, value in original.items()]) @@ -1110,7 +1267,11 @@ class SettingsTests(unittest.TestCase): 'QWEN_API_URL = "http://127.0.0.1:7860"\n' 'CLONE_API_URL = "http://127.0.0.1:7861"\n' 'FASTER_API_URL = "http://127.0.0.1:8000"\n' - 'AUDIOCPP_API_URL = "http://127.0.0.1:8080"\n', + 'AUDIOCPP_API_URL = "http://127.0.0.1:8080"\n' + 'QWEN_REMOTE_URL = "http://127.0.0.1:7860"\n' + 'CLONE_REMOTE_URL = "http://127.0.0.1:7861"\n' + 'FASTER_REMOTE_URL = "http://127.0.0.1:8000"\n' + 'AUDIOCPP_REMOTE_URL = "http://127.0.0.1:8080"\n', encoding="utf-8") with patch.object(hub.config, "__file__", str(path)): # Down to Chunk size, Enter -> editor, Ctrl-U + '300', -- cgit v1.2.3