fix(startup): resolve model size per engine instead of the legacy key (#684)

* fix(startup): resolve model size per engine instead of the legacy key

Startup read the generic "model_size" key, which always holds whichever
engine was saved last, so it initialized the configured engine with
another engine's model. With engine=whisper_cpp and a config left at
model_size=medium by a VOSK save, startup looked for ggml-medium.bin,
reported the model as missing and offered a fresh download while the
working ggml-small.bin named by whisper_cpp_model_size sat on disk.

Use ConfigManager.get_model_size_for_engine(), the resolver the settings
dialog already uses, so the generic key stays a write-only compatibility
shim. It falls back to the generic key when no per-engine key exists, so
older configs keep working.

* fix(config): migrate model_size into whisper_cpp_model_size

Review follow-up on #684.

get_model_size_for_engine() only falls back to the generic model_size key
when the engine key is missing from the in-memory dict, and DEFAULT_CONFIG
already ships whisper_cpp_model_size. After the merge in load_config() the
key is therefore always present, so a user file holding only
{engine: whisper_cpp, model_size: small} used to start on small and would
now start on the default tiny — the older-config path from #681.

_migrate_config already copies the model into vosk_model_size and
whisper_model_size; do the same for whisper_cpp so the resolver change is
behaviour-preserving for those files, and widen the migration trigger to
notice a missing whisper_cpp key.

Tests run against a real ConfigManager on a temp config, not a mocked
resolver: the migration case fails without this change, and the two
resolver cases pin the engine key winning over the generic one.
This commit is contained in:
Kacper Paczos
2026-08-26 23:58:42 -07:00
committed by GitHub
parent f4e9fcb0ee
commit 5e3265f87b
4 changed files with 132 additions and 3 deletions
+5 -2
View File
@@ -397,8 +397,11 @@ def main():
model_size = args.model
logger.info(f"Using model={model_size} (from command line)")
else:
model_size = saved_settings.get("model_size", args.model)
logger.info(f"Using model={model_size} (from saved config)")
# Resolve per engine: the generic "model_size" key always holds the
# model of whichever engine was saved last, so reading it directly
# loads the wrong model whenever the two disagree.
model_size = config_manager.get_model_size_for_engine(engine)
logger.info(f"Using model={model_size} (saved for engine {engine})")
vad_sensitivity = saved_settings.get("vad_sensitivity", 3)
silence_timeout = saved_settings.get("silence_timeout", 2.0)
+15 -1
View File
@@ -189,7 +189,9 @@ class ConfigManager:
sr_config = user_config.get("speech_recognition", {})
# Need migration if we have model_size but not the per-engine keys
return "model_size" in sr_config and (
"vosk_model_size" not in sr_config or "whisper_model_size" not in sr_config
"vosk_model_size" not in sr_config
or "whisper_model_size" not in sr_config
or "whisper_cpp_model_size" not in sr_config
)
def _migrate_config(self, user_config: dict):
@@ -214,6 +216,18 @@ class ConfigManager:
)
logger.info(f"Migrated whisper_model_size to: {sr_config['whisper_model_size']}")
if "whisper_cpp_model_size" not in user_sr_config:
# DEFAULT_CONFIG already carries whisper_cpp_model_size, so the
# generic fallback in get_model_size_for_engine() never fires for
# this engine. Without this copy a config that only stores
# model_size would silently start on the default instead.
sr_config["whisper_cpp_model_size"] = (
current_model if current_engine == "whisper_cpp" else "tiny"
)
logger.info(
f"Migrated whisper_cpp_model_size to: {sr_config['whisper_cpp_model_size']}"
)
self.save_config()
logger.info("Config migrated to new per-engine model format")