aboutsummaryrefslogtreecommitdiff
path: root/app/tests/test_hub.py
diff options
context:
space:
mode:
authorhistoria <historiavg@proton.me>2026-09-02 19:56:51 -0400
committerhistoria <historiavg@proton.me>2026-09-02 19:56:51 -0400
commit08e702700303f9bb5767f02a337b8b34be410df9 (patch)
treece87c27929c81a423e9a5fa27927576544856779 /app/tests/test_hub.py
parent0c6ab319b7fb9ec9c8afe9a43ad249cbfc1a126d (diff)
downloadtts-audiobook-generator-08e702700303f9bb5767f02a337b8b34be410df9.tar.gz
feat: move clone .wav directory to settings
Diffstat (limited to 'app/tests/test_hub.py')
-rw-r--r--app/tests/test_hub.py181
1 files changed, 82 insertions, 99 deletions
diff --git a/app/tests/test_hub.py b/app/tests/test_hub.py
index 94ea286..f49b8d1 100644
--- a/app/tests/test_hub.py
+++ b/app/tests/test_hub.py
@@ -375,11 +375,11 @@ class HubMenuTests(unittest.TestCase):
# ("input") rows; the numbered steps start at the margin and
# the indented rows carry a leading space of their own, so
# they line up with the step text after the "N. " prefixes.
- # They resolve live from the converter module, so a Settings
- # change this session is reflected.
+ # They resolve at call time, so a Settings change this session
+ # is reflected.
self.assertIn(([(" " + str(hub.converter_mod.BOOKS_FOLDER),
"input")], 1), items)
- self.assertIn(([(" " + str(hub.common.VOICES_DIR), "input")], 1),
+ self.assertIn(([(" " + str(hub._clone_wav_dir()), "input")], 1),
items)
self.assertIn(([(" " + str(hub.converter_mod.AUDIOBOOKS_FOLDER),
"input")], 1), items)
@@ -2314,7 +2314,7 @@ class ConvertFlowTests(unittest.TestCase):
fields = self.tui.forms_seen[0][1]
self.assertEqual([f["key"] for f in fields],
["backend", "qwen.mode", "qwen.speaker",
- "qwen.clone_dir", "qwen.clone",
+ "qwen.clone",
"qwen.qwen_instructions", "single_file"])
mode_field = self._field("mode")
# Model names are padded to the widest ("CustomVoice"/"VoiceDesign"
@@ -2331,25 +2331,18 @@ class ConvertFlowTests(unittest.TestCase):
# collapses its column padding back to the gutter.
self.assertTrue(mode_field["compact_label"])
speaker_field = self._field("speaker")
- clone_dir_field = self._field("clone_dir")
- # The .wav directory browser alerts on the .wavs it lists.
- self.assertIs(clone_dir_field["info"], hub.common.wav_dir_info)
- self.assertIs(clone_dir_field["preview"], hub.common.wav_dir_preview)
clone_field = self._field("clone")
design_field = self._field("qwen_instructions")
- # Speaker shows in custom mode; the .wav directory browser and
- # picker in clone mode and the instruction in design mode.
+ # Speaker shows in custom mode; the .wav picker in clone mode and
+ # the instruction in design mode.
self.assertTrue(speaker_field["visible"](fields))
- self.assertFalse(clone_dir_field["visible"](fields))
self.assertFalse(clone_field["visible"](fields))
self.assertFalse(design_field["visible"](fields))
mode_field["value"] = "clone"
self.assertFalse(speaker_field["visible"](fields))
- self.assertTrue(clone_dir_field["visible"](fields))
self.assertTrue(clone_field["visible"](fields))
mode_field["value"] = "design"
self.assertFalse(speaker_field["visible"](fields))
- self.assertFalse(clone_dir_field["visible"](fields))
self.assertFalse(clone_field["visible"](fields))
self.assertTrue(design_field["visible"](fields))
@@ -2394,10 +2387,10 @@ class ConvertFlowTests(unittest.TestCase):
self._convert(None, [self._ready("qwen", "qwen-tts")])
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
- # with the project's ./voices; the picker starts on its first .wav
- # (alphabetically), ignoring non-.wav files.
+ def test_qwen_clone_picker_lists_the_configured_directory(self):
+ # The Voice to clone picker lists the .wavs in the configured
+ # Clone .wav directory (the Settings entry), starting on the
+ # first one (alphabetically), ignoring non-.wav files.
with tempfile.TemporaryDirectory() as td:
root = Path(td)
(root / "narrator.wav").write_bytes(b"")
@@ -2407,7 +2400,7 @@ class ConvertFlowTests(unittest.TestCase):
("alice.wav", str(root / "alice.wav")),
("narrator.wav", str(root / "narrator.wav")),
]
- with patch.object(hub.common, "VOICES_DIR", root), \
+ with patch.object(hub.config, "CLONE_WAV_DIR", str(root)), \
patch.object(hub.qwen_backend, "QWEN_SPEAKERS", ["Vivian"]), \
patch.object(hub.common, "update_config_value"):
self._answer_form(backend="qwen", mode="custom",
@@ -2415,66 +2408,37 @@ class ConvertFlowTests(unittest.TestCase):
cmd = self._convert(None,
[self._ready("qwen", "qwen-tts")])
fields = self.tui.forms_seen[0][1]
- clone_dir_field = self._field("clone_dir")
clone_field = self._field("clone")
self.assertIsNone(cmd[2]["clone"]) # custom mode: no clone
- self.assertEqual(clone_dir_field["kind"], "dir")
- self.assertEqual(clone_dir_field["value"], root)
self.assertEqual(clone_field["kind"], "choice")
self.assertEqual(clone_field["choices"](fields),
expected_choices)
self.assertEqual(clone_field["value"],
expected_choices[0][1])
- def test_qwen_clone_picker_resets_when_the_directory_changes(self):
- # Changing the directory browser re-points the picker at the new
- # directory's first .wav; an empty directory clears the pick.
- with tempfile.TemporaryDirectory() as td, \
- tempfile.TemporaryDirectory() as other, \
- tempfile.TemporaryDirectory() as nowhere:
- root, other = Path(td), Path(other)
- (root / "one.wav").write_bytes(b"")
- (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.common, "update_config_value"):
- self._answer_form(backend="qwen", mode="clone", clone="")
- self._convert(None, [self._ready("qwen", "qwen-tts")])
- fields = self.tui.forms_seen[0][1]
- clone_dir_field = self._field("clone_dir")
- clone_field = self._field("clone")
- # The picker seeds itself with the default directory's first
- # .wav, and follows the directory browser from there.
- self.assertEqual(clone_field["value"], str(root / "one.wav"))
- clone_dir_field["value"] = other
- clone_dir_field["on_change"](fields)
- self.assertEqual(clone_field["value"], str(other / "alpha.wav"))
- clone_dir_field["value"] = Path(nowhere) / "no-such-dir"
- clone_dir_field["on_change"](fields)
- self.assertEqual(clone_field["value"], "")
-
def test_qwen_clone_picker_refuses_generate_without_wavs(self):
- # No .wav files in the directory: the picker stays empty, opening
- # it flashes the hint, and Generate! is refused with the same
- # message naming the directory.
+ # No .wav files in the configured directory: the picker stays
+ # empty, opening it flashes the hint, and Generate! is refused
+ # with the same message naming the directory.
with tempfile.TemporaryDirectory() as td:
empty = Path(td)
- with patch.object(hub.common, "VOICES_DIR", empty), \
+ with patch.object(hub.config, "CLONE_WAV_DIR", str(empty)), \
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,
[self._ready("qwen", "qwen-tts")])
- self.assertIsNone(cmd[2]["clone"])
- fields = self.tui.forms_seen[0][1]
- clone_field = self._field("clone")
- self.assertEqual(clone_field["choices"](fields), [])
- message = clone_field["on_empty_choices"](fields)
- self.assertIn(str(empty), message)
- self.assertIn("No .wav files", message)
- self.assertEqual(clone_field["validate"](""), message)
- self.assertIsNone(clone_field["validate"](str(empty / "x.wav")))
+ self.assertIsNone(cmd[2]["clone"])
+ fields = self.tui.forms_seen[0][1]
+ clone_field = self._field("clone")
+ self.assertEqual(clone_field["choices"](fields), [])
+ message = clone_field["on_empty_choices"](fields)
+ self.assertIn(str(empty), message)
+ self.assertIn("No .wav files", message)
+ self.assertIn("Check directory in Settings", message)
+ self.assertEqual(clone_field["validate"](""), message)
+ self.assertIsNone(clone_field["validate"](
+ str(empty / "x.wav")))
# ------------------------------------------------------------------
# faster: remote server (no local voices.json)
@@ -2598,7 +2562,7 @@ class ConvertFlowTests(unittest.TestCase):
[f["key"] for f in fields],
["backend", "audiocpp.model_id", "audiocpp.audiocpp_voice",
"audiocpp.instructions", "audiocpp.request_options",
- "qwen.mode", "qwen.speaker", "qwen.clone_dir",
+ "qwen.mode", "qwen.speaker",
"qwen.clone", "qwen.qwen_instructions", "single_file"])
# The form opens on the configured default (audio.cpp): its fields
# show, the other backend's hide. Instructions shows too (optional
@@ -2608,20 +2572,17 @@ class ConvertFlowTests(unittest.TestCase):
for key in ("model_id", "audiocpp_voice", "instructions"):
self.assertTrue(self._field(key)["visible"](fields))
self.assertFalse(self._field("request_options")["visible"](fields))
- for key in ("mode", "speaker", "clone_dir", "clone",
- "qwen_instructions"):
+ for key in ("mode", "speaker", "clone", "qwen_instructions"):
self.assertFalse(self._field(key)["visible"](fields))
# Picking qwen in the Backend field swaps which options show.
fields[0]["value"] = "qwen"
self.assertTrue(self._field("mode")["visible"](fields))
self.assertTrue(self._field("speaker")["visible"](fields))
- self.assertFalse(self._field("clone_dir")["visible"](fields))
self.assertFalse(self._field("clone")["visible"](fields))
- # qwen's clone mode hides the speaker and shows the .wav directory
- # browser and the picker of the .wavs inside it.
+ # qwen's clone mode hides the speaker and shows the picker of the
+ # configured clone directory's .wavs.
self._field("mode")["value"] = "clone"
self.assertFalse(self._field("speaker")["visible"](fields))
- self.assertTrue(self._field("clone_dir")["visible"](fields))
self.assertTrue(self._field("clone")["visible"](fields))
for key in ("model_id", "audiocpp_voice", "instructions",
"request_options"):
@@ -2630,8 +2591,7 @@ class ConvertFlowTests(unittest.TestCase):
fields[0]["value"] = "audiocpp"
for key in ("model_id", "audiocpp_voice"):
self.assertTrue(self._field(key)["visible"](fields))
- for key in ("mode", "speaker", "clone_dir", "clone",
- "qwen_instructions"):
+ for key in ("mode", "speaker", "clone", "qwen_instructions"):
self.assertFalse(self._field(key)["visible"](fields))
# ------------------------------------------------------------------
@@ -2654,8 +2614,7 @@ class ConvertFlowTests(unittest.TestCase):
patch.object(hub.config, "STOP_SERVER_AND_EXIT", True):
self._mock_preflight()
self._answer_form(backend="sglomni", model_id=entry.key,
- voice="Vivian", clone_dir="/tmp",
- instructions="")
+ voice="Vivian", instructions="")
cmd = self._convert(None, [self._ready("sglomni",
"SGLang-Omni")])
self.assertEqual(cmd[1], hub.BACKEND_SGLOMNI)
@@ -2671,21 +2630,19 @@ class ConvertFlowTests(unittest.TestCase):
with tempfile.TemporaryDirectory() as td:
ref = Path(td) / "ref.wav"
ref.write_bytes(b"RIFF")
- with patch.object(hub.config, "AUDIO_FORMAT", "m4b"), \
+ with patch.object(hub.config, "CLONE_WAV_DIR", str(td)), \
+ patch.object(hub.config, "AUDIO_FORMAT", "m4b"), \
patch.object(hub.config, "LANGUAGE", "English"), \
patch.object(hub.config, "SPEED", 1.0), \
patch.object(hub.config, "DEBUG", False), \
patch.object(hub.config, "STOP_SERVER_AND_EXIT", True):
self._mock_preflight()
self._answer_form(backend="sglomni", model_id=entry.key,
- voice=str(ref), clone_dir=td,
- instructions="")
+ voice=str(ref), instructions="")
cmd = self._convert(None, [self._ready("sglomni",
"SGLang-Omni")])
fields = self.tui.forms_seen[-1][1]
voice_field = self._field("voice")
- next(f for f in fields
- if f["key"] == "sglomni.clone_dir")["value"] = td
wav_labels = [label for label, _ in
voice_field["choices"](fields)]
kwargs = cmd[2]
@@ -2708,7 +2665,7 @@ class ConvertFlowTests(unittest.TestCase):
patch.object(hub.config, "STOP_SERVER_AND_EXIT", True):
self._mock_preflight()
self._answer_form(backend="sglomni", model_id=entry.key,
- voice="", clone_dir="/tmp", instructions="")
+ voice="", instructions="")
cmd = self._convert(None, [self._ready("sglomni",
"SGLang-Omni")])
kwargs = cmd[2]
@@ -2725,7 +2682,7 @@ class ConvertFlowTests(unittest.TestCase):
patch.object(hub.config, "STOP_SERVER_AND_EXIT", True):
self._mock_preflight()
self._answer_form(backend="sglomni", model_id=entry.key,
- voice="", clone_dir="/tmp",
+ voice="",
instructions="A warm narrator.")
cmd = self._convert(None, [self._ready("sglomni",
"SGLang-Omni")])
@@ -2750,8 +2707,7 @@ class ConvertFlowTests(unittest.TestCase):
self._mock_preflight()
self._answer_form(backend="sglomni-remote",
model_id="higgs_audio_v3_tts",
- voice="narrator", clone_dir="/tmp",
- instructions="")
+ voice="narrator", instructions="")
cmd = self._convert(
None, [self._remote("sglomni", "SGLang-Omni",
url="http://sgl.local:8100")])
@@ -2807,8 +2763,7 @@ class ConvertFlowTests(unittest.TestCase):
# built-in entry, no clone .wavs — those belong to the
# clone-capable models' combined menu).
self._answer_form(backend="sglomni", model_id="voxtral_tts",
- voice="casual_male", clone_dir="/tmp",
- instructions="")
+ voice="casual_male", instructions="")
cmd = self._convert(None, statuses)
fields = self.tui.forms_seen[-1][1]
# The captured fields carry the form's opening state (the
@@ -2846,9 +2801,8 @@ class ConvertFlowTests(unittest.TestCase):
speaker -> the preset Voice menu; clone -> the combined Voice
menu (the built-in default voice on top when the model can
- narrate without a reference, then the clone directory's .wavs)
- beside the Clone .wav directory browser; design -> the
- Instructions box.
+ narrate without a reference, then the configured clone
+ directory's .wavs); design -> the Instructions box.
"""
def fake_preset_voices(entry):
@@ -2864,7 +2818,8 @@ class ConvertFlowTests(unittest.TestCase):
with tempfile.TemporaryDirectory() as td:
ref = Path(td) / "ref.wav"
ref.write_bytes(b"RIFF")
- with patch.object(hub.config, "AUDIO_FORMAT", "m4b"), \
+ with patch.object(hub.config, "CLONE_WAV_DIR", str(td)), \
+ patch.object(hub.config, "AUDIO_FORMAT", "m4b"), \
patch.object(hub.config, "LANGUAGE", "English"), \
patch.object(hub.config, "SPEED", 1.0), \
patch.object(hub.config, "DEBUG", False), \
@@ -2874,7 +2829,7 @@ class ConvertFlowTests(unittest.TestCase):
with self.subTest(entry=entry.key):
overrides = {"backend": "sglomni",
"model_id": entry.key,
- "voice": "", "clone_dir": td,
+ "voice": "",
"instructions": ""}
if entry.capability == "speaker":
overrides["voice"] = \
@@ -2894,9 +2849,6 @@ class ConvertFlowTests(unittest.TestCase):
next(f for f in fields
if f["key"] == "sglomni.model_id")["value"] = \
entry.key
- next(f for f in fields
- if f["key"] == "sglomni.clone_dir")["value"] \
- = td
shown = {f["key"] for f in fields
if f["key"].startswith("sglomni.")
and f["visible"](fields)}
@@ -2913,8 +2865,7 @@ class ConvertFlowTests(unittest.TestCase):
self.assertEqual(kwargs.get("voice"), preset)
self.assertNotIn("clone", kwargs)
elif entry.capability == "clone":
- expected = {"sglomni.model_id", "sglomni.voice",
- "sglomni.clone_dir"}
+ expected = {"sglomni.model_id", "sglomni.voice"}
if entry.requires_reference:
# Cannot narrate without a reference: the
# menu is the clone directory's .wavs only.
@@ -3458,6 +3409,7 @@ class SettingsTests(unittest.TestCase):
# fake config write restores these afterwards.
_SETTING_KEYS = ("AUDIO_FORMAT", "AUDIO_BITRATE", "LANGUAGE",
"CHUNK_SIZE", "INPUT_DIR", "OUTPUT_DIR",
+ "CLONE_WAV_DIR",
"SPEED", "DEBUG", "STOP_SERVER_AND_EXIT",
"AUDIOCPP_UNLOAD_MODELS",
"QWEN_API_URL",
@@ -3532,6 +3484,7 @@ class SettingsTests(unittest.TestCase):
values = {"audio_format": "ogg", "audio_bitrate": " 192k ",
"language": "en", "chunk_size": "300",
"input_dir": " /books ", "output_dir": "/audiobooks",
+ "clone_wav_dir": " /refs/wavs ",
"speed": "1.5", "debug": True,
"stop_and_exit": False,
"unload_models": True,
@@ -3554,6 +3507,7 @@ class SettingsTests(unittest.TestCase):
"CHUNK_SIZE": 300,
"INPUT_DIR": "/books",
"OUTPUT_DIR": "/audiobooks",
+ "CLONE_WAV_DIR": "/refs/wavs",
"SPEED": 1.5,
"DEBUG": True,
"STOP_SERVER_AND_EXIT": False,
@@ -3579,6 +3533,7 @@ class SettingsTests(unittest.TestCase):
self.assertEqual(hub.config.CHUNK_SIZE, 300)
self.assertEqual(hub.config.INPUT_DIR, "/books")
self.assertEqual(hub.config.OUTPUT_DIR, "/audiobooks")
+ self.assertEqual(hub.config.CLONE_WAV_DIR, "/refs/wavs")
self.assertEqual(hub.config.SPEED, 1.5)
self.assertEqual(hub.config.DEBUG, True)
self.assertEqual(hub.config.STOP_SERVER_AND_EXIT, False)
@@ -3596,6 +3551,7 @@ class SettingsTests(unittest.TestCase):
base = {"audio_format": "m4b", "audio_bitrate": "128k",
"language": "English", "chunk_size": "250",
"input_dir": "./input", "output_dir": "./output",
+ "clone_wav_dir": "./voices",
"speed": "1.0", "debug": False,
"stop_and_exit": True,
"unload_models": True,
@@ -3616,6 +3572,8 @@ class SettingsTests(unittest.TestCase):
with self.assertRaises(ValueError):
hub._apply_settings({**base, "output_dir": ""})
with self.assertRaises(ValueError):
+ hub._apply_settings({**base, "clone_wav_dir": " "})
+ with self.assertRaises(ValueError):
hub._apply_settings({**base, "audiocpp_port": "70000"})
with self.assertRaises(ValueError):
hub._apply_settings({**base,
@@ -3671,27 +3629,42 @@ class SettingsTests(unittest.TestCase):
self.assertEqual(field["value"], hub.config.LANGUAGE)
def test_directory_fields_are_browsers(self):
- # The Input/Output Directory settings use the DOS-style directory
- # browser, seeded with the configured folder resolved against the
- # project root.
+ # The Input/Output/Clone .wav directory settings use the DOS-style
+ # directory browser, seeded with the configured folder resolved
+ # against the project root.
fields = hub._settings_fields()
for key, config_name in (("input_dir", "INPUT_DIR"),
- ("output_dir", "OUTPUT_DIR")):
+ ("output_dir", "OUTPUT_DIR"),
+ ("clone_wav_dir", "CLONE_WAV_DIR")):
field = next(f for f in fields if f["key"] == key)
self.assertEqual(field["kind"], "dir")
- self.assertTrue(field["label"].endswith("Directory"))
self.assertEqual(field["value"],
hub.converter_mod.resolve_dir(
getattr(hub.config, config_name),
key.removesuffix("_dir")))
self.assertIsNone(field["validate"](str(field["value"])))
self.assertIsNotNone(field["validate"](" "))
+ input_field = next(f for f in fields if f["key"] == "input_dir")
+ output_field = next(f for f in fields if f["key"] == "output_dir")
+ self.assertTrue(input_field["label"].endswith("Directory"))
+ self.assertTrue(output_field["label"].endswith("Directory"))
+ # The clone .wav browser alerts on the .wavs it lists.
+ clone_field = next(f for f in fields if f["key"] == "clone_wav_dir")
+ self.assertEqual(clone_field["label"], "Clone .wav directory")
+ self.assertIs(clone_field["info"], hub.common.wav_dir_info)
+ self.assertIs(clone_field["preview"], hub.common.wav_dir_preview)
with patch.object(hub.config, "INPUT_DIR", "books"):
fields = hub._settings_fields()
field = next(f for f in fields if f["key"] == "input_dir")
self.assertEqual(
field["value"],
hub.converter_mod.BASE_DIR / "books")
+ with patch.object(hub.config, "CLONE_WAV_DIR", "refs"):
+ fields = hub._settings_fields()
+ field = next(f for f in fields if f["key"] == "clone_wav_dir")
+ self.assertEqual(
+ field["value"],
+ hub.converter_mod.BASE_DIR / "refs")
def test_settings_menu_builds_form_and_saves(self):
captured = {}
@@ -3701,6 +3674,7 @@ class SettingsTests(unittest.TestCase):
return {"audio_format": "ogg", "audio_bitrate": "192k",
"language": "English", "chunk_size": "300",
"input_dir": "/books", "output_dir": "/audiobooks",
+ "clone_wav_dir": "/refs/wavs",
"speed": "1.0", "debug": False,
"stop_and_exit": True,
"unload_models": True,
@@ -3723,6 +3697,7 @@ class SettingsTests(unittest.TestCase):
self.assertEqual([f["key"] for f in captured["fields"]],
["audio_format", "audio_bitrate", "language",
"chunk_size", "input_dir", "output_dir",
+ "clone_wav_dir",
"speed", "debug", "stop_and_exit",
"unload_models",
"audiocpp_port",
@@ -3735,6 +3710,7 @@ class SettingsTests(unittest.TestCase):
self.assertEqual(kinds["audio_bitrate"], "text")
self.assertEqual(kinds["input_dir"], "dir")
self.assertEqual(kinds["output_dir"], "dir")
+ self.assertEqual(kinds["clone_wav_dir"], "dir")
self.assertEqual(kinds["speed"], "text")
self.assertEqual(kinds["debug"], "bool")
self.assertEqual(kinds["audiocpp_port"], "text")
@@ -3747,6 +3723,7 @@ class SettingsTests(unittest.TestCase):
"audio.cpp remote URL")
self.assertEqual(labels["input_dir"], "Input Directory")
self.assertEqual(labels["output_dir"], "Output Directory")
+ self.assertEqual(labels["clone_wav_dir"], "Clone .wav directory")
self.assertNotIn("(clone)", " ".join(labels.values()))
# The language setting is a picker labelled "Language".
self.assertEqual(labels["language"], "Language")
@@ -3756,6 +3733,7 @@ class SettingsTests(unittest.TestCase):
notes = {f["key"]: f.get("note") for f in captured["fields"]}
self.assertIsNone(notes["input_dir"])
self.assertIsNone(notes["output_dir"])
+ self.assertIsNone(notes["clone_wav_dir"])
self.assertIsNone(notes["debug"])
self.assertTrue(notes["stop_and_exit"])
self.assertTrue(notes["unload_models"])
@@ -3770,6 +3748,7 @@ class SettingsTests(unittest.TestCase):
"chunk_size": "300",
"input_dir": "/books",
"output_dir": "/audiobooks",
+ "clone_wav_dir": "/refs/wavs",
"speed": "1.0",
"debug": False,
"stop_and_exit": True,
@@ -3887,6 +3866,7 @@ class SettingsTests(unittest.TestCase):
return {"audio_format": "m4b", "audio_bitrate": "128k",
"language": "English", "chunk_size": "250",
"input_dir": "./input", "output_dir": "./output",
+ "clone_wav_dir": "./voices",
"speed": "1.0", "debug": False,
"stop_and_exit": True, "unload_models": True,
"qwen_port": "7860",
@@ -3920,6 +3900,7 @@ class SettingsTests(unittest.TestCase):
original = {name: getattr(hub.config, name) for name in
("AUDIO_FORMAT", "AUDIO_BITRATE", "LANGUAGE",
"CHUNK_SIZE", "INPUT_DIR", "OUTPUT_DIR",
+ "CLONE_WAV_DIR",
"SPEED", "DEBUG", "STOP_SERVER_AND_EXIT",
"AUDIOCPP_UNLOAD_MODELS",
"QWEN_API_URL",
@@ -3942,6 +3923,7 @@ class SettingsTests(unittest.TestCase):
"CHUNK_SIZE = 250\n"
'INPUT_DIR = "./input"\n'
'OUTPUT_DIR = "./output"\n'
+ 'CLONE_WAV_DIR = "./voices"\n'
"SPEED = 1.0\n"
"DEBUG = False\n"
"STOP_SERVER_AND_EXIT = True\n"
@@ -3970,6 +3952,7 @@ class SettingsTests(unittest.TestCase):
# The settings-only fields are written back unchanged.
self.assertIn('INPUT_DIR = "', text)
self.assertIn('OUTPUT_DIR = "', text)
+ self.assertIn('CLONE_WAV_DIR = "', text)
self.assertIn("SPEED = 1.0", text)
self.assertIn("DEBUG = False", text)
# The running session also picked up the change in-memory.