From 8170354b76566840d81a3e12b47333ea88f21e16 Mon Sep 17 00:00:00 2001 From: sumerc Date: Thu, 30 Jul 2026 14:22:03 +0300 Subject: [PATCH] fix(transcriber): fall back to engine default on a foreign model ID A local provider read its model ID from config.json and hard-errored when that ID belonged to a different engine, which is the normal state right after any provider switch: the persisted ID is whatever the PREVIOUS provider had selected, and it reaches the new provider via SetModel before the tray ever offers this engine's model list. The result was that every recording failed with `unknown model ""` until the user happened to open the model menu and pick something. Fall back to the provider's own default instead. Falling back is safe because the default is by construction the right engine's file. What must never happen is loading another engine's weights, and that is still rejected. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 4 ++++ transcriber/local.go | 37 +++++++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ddc686..574b77d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog ## Unreleased + +- Local providers no longer fail every recording when the model saved in + config.json belongs to a different engine; they fall back to their own default + ## v0.4.0 - Recording overlay wnd diff --git a/transcriber/local.go b/transcriber/local.go index a1bc8f5..5ad8c02 100644 --- a/transcriber/local.go +++ b/transcriber/local.go @@ -38,10 +38,11 @@ type localProvider struct { loadErr error lang string - name string // provider name, e.g. "parakeet" - hints bool // engine can bias decoding toward a vocabulary - open func(localmodel.Model) (localEngine, error) // load a model with this engine - langsFor func(localmodel.Model) []Language + name string // provider name, e.g. "parakeet" + defaultID string // this engine's model, used when modelID belongs to another + hints bool // engine can bias decoding toward a vocabulary + open func(localmodel.Model) (localEngine, error) // load a model with this engine + langsFor func(localmodel.Model) []Language } // newLocalProvider builds a provider around one engine and warms its default @@ -54,12 +55,13 @@ func newLocalProvider(name, defaultID, defaultLang string, hints bool, langsFor func(localmodel.Model) []Language) *localProvider { p := &localProvider{ - modelID: defaultID, - lang: defaultLang, - name: name, - hints: hints, - open: open, - langsFor: langsFor, + modelID: defaultID, + defaultID: defaultID, + lang: defaultLang, + name: name, + hints: hints, + open: open, + langsFor: langsFor, } go p.load() return p @@ -156,6 +158,21 @@ func (p *localProvider) load() { eng localEngine err error ) + // A model ID belonging to another engine is not an error, it is the normal + // state right after a provider switch: the ID persisted in config.json is + // whatever the PREVIOUS provider had selected, and it arrives here via + // SetModel before the tray ever offers this engine's own list. Fall back to + // this engine's default instead of failing every recording until the user + // happens to open the model menu. Falling back is safe because the default + // is by construction the right engine's file — what must never happen is + // loading another engine's weights, which is a hang, not an error. + if m, ok := localmodel.ByID(want); !ok || m.Engine != p.name { + want = p.defaultID + p.mu.Lock() + p.modelID = want + p.mu.Unlock() + } + if m, ok := localmodel.ByID(want); !ok || m.Engine != p.name { err = fmt.Errorf("unknown %s model %q", p.name, want) } else if !localmodel.Present(m) {