aboutsummaryrefslogtreecommitdiff
path: root/app/ui
diff options
context:
space:
mode:
authorhistoria <historiavg@proton.me>2026-08-28 14:57:48 -0400
committerhistoria <historiavg@proton.me>2026-08-28 14:57:48 -0400
commitdb38085d07ce75f8961eecdc1919e98748254c53 (patch)
treebeaea2ba84de05bfc2fa90e9b92a24568d3b4cb9 /app/ui
parentafb2c2d5b297c5aa28bcced0e3f90e207d799c2a (diff)
downloadtts-audiobook-generator-db38085d07ce75f8961eecdc1919e98748254c53.tar.gz
refactor: overhaul config.py, remove cli default options
Diffstat (limited to 'app/ui')
-rw-r--r--app/ui/hub.py72
1 files changed, 29 insertions, 43 deletions
diff --git a/app/ui/hub.py b/app/ui/hub.py
index 8a6fda7..f63ff99 100644
--- a/app/ui/hub.py
+++ b/app/ui/hub.py
@@ -390,9 +390,9 @@ class _Hub:
cmd = mapper(result)
if cmd is None:
return tui.Wizard.BACK
- # The mapper may have persisted settings (qwen model/speaker),
- # making the form-time statuses stale — the autostart plan
- # must read the freshly-configured server argv/model.
+ # Nothing is persisted anymore, but server state may have
+ # changed since the form opened — the autostart plan must
+ # read fresh statuses.
invalidate_detect_cache()
statuses = detect_all(refresh=True)
autostart_error = _add_autostart(cmd, statuses)
@@ -500,7 +500,8 @@ class _Hub:
without an extra action menu. The state lives in the table, not on
the entries, because the menu's selection bar would cover inline
colors. Each server is labelled by its backend's name; qwen hosts
- one model at a time (config.QWEN_MODEL decides which).
+ one model at a time (its default start runs CustomVoice — a
+ Generate-audiobooks run needing another model restarts it).
"""
statuses = detect_all()
candidates = [st for st in statuses if st.installed]
@@ -915,11 +916,9 @@ def _convert_form(stdscr) -> Optional[tuple]:
return None
choices = [(label, key) for key, label, _st, _remote in entries
if key in builders]
- default = config.BACKEND if config.BACKEND in builders \
- else choices[0][1]
fields = [{
"key": "backend", "label": "Backend", "kind": "choice",
- "value": default, "choices": choices,
+ "value": choices[0][1], "choices": choices,
}]
for key, _label, _st, _remote in entries:
if key not in builders:
@@ -1174,9 +1173,7 @@ def _audiocpp_fields(stdscr, api_url: Optional[str] = None,
if capability == AUDIOCPP_VOICE_DESIGN:
voice_field["value"] = None
elif capability == AUDIOCPP_VOICE_SPEAKER:
- voice_field["value"] = (config.SPEAKER
- if config.SPEAKER in QWEN3_TTS_SPEAKERS
- else QWEN3_TTS_SPEAKERS[0])
+ voice_field["value"] = QWEN3_TTS_SPEAKERS[0]
else: # clone
voices = voices_for(_field_value(fields, prefix + "model_id"))
voice_field["value"] = voices[0] if voices else ""
@@ -1223,8 +1220,7 @@ def _audiocpp_fields(stdscr, api_url: Optional[str] = None,
else "This model needs a voice — pick one or switch models"
model_ids = [m.get("id") for m in models]
- default_model = config.AUDIOCPP_MODEL_ID \
- if config.AUDIOCPP_MODEL_ID in model_ids else model_ids[0]
+ default_model = model_ids[0]
default_entry = next((m for m in models if m.get("id") == default_model),
models[0])
default_capability = audiocpp_entry_voice_capability(
@@ -1232,8 +1228,7 @@ def _audiocpp_fields(stdscr, api_url: Optional[str] = None,
default_entry.get("id") or "")
initial_voice = None
if default_capability == AUDIOCPP_VOICE_SPEAKER:
- initial_voice = (config.SPEAKER if config.SPEAKER in QWEN3_TTS_SPEAKERS
- else QWEN3_TTS_SPEAKERS[0])
+ initial_voice = QWEN3_TTS_SPEAKERS[0]
elif default_capability == AUDIOCPP_VOICE_CLONE:
initial = voices_for(default_model)
initial_voice = initial[0] if initial else ""
@@ -1295,7 +1290,7 @@ def _audiocpp_fields(stdscr, api_url: Optional[str] = None,
# delivery instruction — or, on families without built-in speakers
# that read instructions, the voice itself (instruction-voice mode).
{"key": prefix + "instructions", "label": "Instructions", "kind": "text",
- "value": config.AUDIOCPP_INSTRUCTIONS,
+ "value": "",
"help": INSTRUCTIONS_HELP,
"validate": lambda value: None
if (model_capability(fields) != AUDIOCPP_VOICE_DESIGN or str(value).strip())
@@ -1356,12 +1351,11 @@ def _qwen_fields(remote_modes: Optional[list] = None,
One demo server hosts one model at a time, so the picked model decides
which server must be up. For the managed entry REMOTE_MODES/URLS are
- None: the picker offers every model and the choice (plus any changed
- speaker) is persisted to app/converter/config.py so the autostart boots
- the same model again later. For a "[remote]" entry REMOTE_MODES names
- which demos answered remotely ("Base", "CustomVoice" and/or
- "VoiceDesign") and URLS maps "qwen" to its URL: the picker is limited to
- the available models and the mapper passes the URL as ``api_url``.
+ None: the picker offers every model and the autostart/restart plan
+ boots exactly the picked model. For a "[remote]" entry REMOTE_MODES
+ names which demos answered remotely ("Base", "CustomVoice" and/or
+ "VoiceDesign") and URLS maps "qwen" to its URL: the picker is limited
+ to the available models and the mapper passes the URL as ``api_url``.
"""
remote_modes = list(remote_modes or [])
urls = dict(urls or {})
@@ -1380,13 +1374,9 @@ def _qwen_fields(remote_modes: Optional[list] = None,
model_choices = [(label, value) for (label, value) in model_choices
if dict(mode_keys)[value] in available]
by_value = {value: label for label, value in model_choices}
- configured_mode = {model: mode for mode, model in mode_keys}.get(
- qwen_backend.current_model(), model_choices[0][1])
- default_mode = configured_mode if configured_mode in by_value \
- else model_choices[0][1]
+ default_mode = "custom" if "custom" in by_value else model_choices[0][1]
speakers = list(qwen_backend.QWEN_SPEAKERS)
- default_speaker = config.SPEAKER if config.SPEAKER in speakers \
- else speakers[0]
+ default_speaker = speakers[0]
# Voice cloning references: the directory the .wavs live in — browsed
# with the directory widget, defaulting to the project's ./voices (the
@@ -1437,7 +1427,7 @@ def _qwen_fields(remote_modes: Optional[list] = None,
"validate": clone_wav_validate,
"visible": lambda fs: _field_value(fs, prefix + "mode") == "clone"},
{"key": prefix + "qwen_instructions", "label": "Instructions",
- "kind": "text", "value": config.INSTRUCT,
+ "kind": "text", "value": "",
"help": ["Describe the voice to design, e.g.",
'"A warm adult female narrator with a British accent".'],
"validate": lambda s: None if s.strip() else
@@ -1451,19 +1441,10 @@ def _qwen_fields(remote_modes: Optional[list] = None,
if mode == "clone":
clone = str(result[prefix + "clone"] or "").strip() or None
kwargs = {"clone": clone, **_common_kwargs(result)}
+ if mode == "custom":
+ kwargs["voice"] = result[prefix + "speaker"]
if mode == "design":
kwargs["instructions"] = result[prefix + "qwen_instructions"]
- if not urls:
- # Managed entry: persist the choices for this and future runs,
- # so the server autostart boots the same model again
- # (update_config_value keeps both the file and the imported
- # module in sync).
- model = dict(mode_keys)[mode]
- if model != qwen_backend.current_model():
- common.update_config_value("QWEN_MODEL", model)
- speaker = result.get(prefix + "speaker", config.SPEAKER)
- if mode == "custom" and speaker != config.SPEAKER:
- common.update_config_value("SPEAKER", speaker)
if urls:
api_url = urls.get("qwen")
if api_url:
@@ -1510,12 +1491,11 @@ def _faster_fields(stdscr, api_url: Optional[str] = None,
fields = [
{"key": prefix + "faster_voice", "label": "Voice to clone",
"kind": "text",
- "value": config.FASTER_VOICE,
+ "value": "",
"validate": lambda s: None if s.strip() else "Enter a voice name"},
]
else:
- default = config.FASTER_VOICE if config.FASTER_VOICE in voices else \
- next(iter(voices))
+ default = next(iter(voices))
fields = [
{"key": prefix + "faster_voice", "label": "Voice to clone",
"kind": "choice",
@@ -1847,7 +1827,7 @@ def _prepare_run_config(backend: str, kwargs: dict
log_path=log_path, stop_and_exit=stop_and_exit)
status = next((s for s in detect_all(refresh=True)
- if s.key == backend), None)
+ if s.key == backend), None)
notice = ""
spec: Optional[ServerSpec] = None
if autostart:
@@ -1867,6 +1847,12 @@ def _prepare_run_config(backend: str, kwargs: dict
if spec is None:
notice = (f"no server named '{restart_name}' — the model "
"switch restart was skipped")
+ if spec is not None and backend == BACKEND_QWEN:
+ # One demo server hosts one model: aim the spec at the model this
+ # run selected (same URL/port, matching probe identity), so an
+ # autostart or model-switch restart boots exactly what the run
+ # needs instead of the Start/Stop menu's default model.
+ spec = qwen_backend._build_spec(_qwen_wanted_model(kwargs))
return runview.RunConfig(
backend=backend, backend_label=label, kwargs=kwargs,
book_files=book_files, planned=planned,