diff options
| author | Paul Buetow <paul@buetow.org> | 2026-04-08 09:55:02 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-04-08 09:55:02 +0300 |
| commit | f486e9c677c72a409df8696104661847354286df (patch) | |
| tree | 8f1b9aef0a74d33a65f1f47f2bdf3c9705fc8474 /internal/gui/orchestrator.go | |
| parent | cd4265b8f87811db758c89bab5e62daa6c39337a (diff) | |
refactor: registry pattern for audio and image provider factories
Add internal/registry generic Registry[K,T] for keyed factory registration.
Wire audio.NewProvider via registered per-provider constructors; GUI and
processor newImageSearcher use registries of *Orchestrator/*Processor methods.
Export image.ImageProviderOpenAI and ImageProviderNanoBanana from search.go
and use them across gui to avoid duplicate string constants.
Made-with: Cursor
Diffstat (limited to 'internal/gui/orchestrator.go')
| -rw-r--r-- | internal/gui/orchestrator.go | 83 |
1 files changed, 49 insertions, 34 deletions
diff --git a/internal/gui/orchestrator.go b/internal/gui/orchestrator.go index 191e919..ef4a167 100644 --- a/internal/gui/orchestrator.go +++ b/internal/gui/orchestrator.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "time" "fyne.io/fyne/v2" @@ -12,6 +13,7 @@ import ( "codeberg.org/snonux/totalrecall/internal/audio" "codeberg.org/snonux/totalrecall/internal/image" "codeberg.org/snonux/totalrecall/internal/phonetic" + "codeberg.org/snonux/totalrecall/internal/registry" "codeberg.org/snonux/totalrecall/internal/translation" ) @@ -410,48 +412,61 @@ func (o *GenerationOrchestrator) imagePromptCallback(cardDir, word string) func( } } -// newImageSearcher constructs the appropriate image client based on the -// configured image provider. Returns image.PromptAwareClient so callers can -// call SetPromptCallback directly without a type-assertion. The factory -// functions are sourced from imageFactories (the shared image.ClientFactories -// value) to avoid duplicating the factory signatures in this package. -func (o *GenerationOrchestrator) newImageSearcher() (image.PromptAwareClient, error) { - switch o.config.ImageProvider { - case imageProviderOpenAI: - if o.config.OpenAIKey == "" { - return nil, fmt.Errorf("OpenAI API key is required for image generation") - } +// guiImageClientFactories maps provider name to image client builder. Add new +// providers by registering here instead of extending a switch in newImageSearcher. +var guiImageClientFactories = func() *registry.Registry[string, func(*GenerationOrchestrator) (image.PromptAwareClient, error)] { + r := registry.New[string, func(*GenerationOrchestrator) (image.PromptAwareClient, error)]() + r.Register(image.ImageProviderOpenAI, (*GenerationOrchestrator).buildOpenAIImageClient) + r.Register(image.ImageProviderNanoBanana, (*GenerationOrchestrator).buildNanoBananaImageClient) + return r +}() - openaiConfig := &image.OpenAIConfig{ - APIKey: o.config.OpenAIKey, - Model: "dall-e-2", // DALL-E 2 supports 512×512 - Size: "512x512", - Quality: "standard", - Style: "natural", - } +func (o *GenerationOrchestrator) buildOpenAIImageClient() (image.PromptAwareClient, error) { + if o.config.OpenAIKey == "" { + return nil, fmt.Errorf("OpenAI API key is required for image generation") + } - return o.imageFactories.NewOpenAIClient(openaiConfig), nil + openaiConfig := &image.OpenAIConfig{ + APIKey: o.config.OpenAIKey, + Model: "dall-e-2", // DALL-E 2 supports 512×512 + Size: "512x512", + Quality: "standard", + Style: "natural", + } - case imageProviderNanoBanana: - cfg := o.config - if cfg == nil { - cfg = DefaultConfig() - } - if cfg.GoogleAPIKey == "" { - return nil, fmt.Errorf("google API key is required for image generation") - } + return o.imageFactories.NewOpenAIClient(openaiConfig), nil +} - nanoBananaConfig := &image.NanoBananaConfig{ - APIKey: cfg.GoogleAPIKey, - Model: cfg.NanoBananaModel, - TextModel: cfg.NanoBananaTextModel, - } +func (o *GenerationOrchestrator) buildNanoBananaImageClient() (image.PromptAwareClient, error) { + cfg := o.config + if cfg == nil { + cfg = DefaultConfig() + } + if cfg.GoogleAPIKey == "" { + return nil, fmt.Errorf("google API key is required for image generation") + } - return o.imageFactories.NewNanoBananaClient(nanoBananaConfig), nil + nanoBananaConfig := &image.NanoBananaConfig{ + APIKey: cfg.GoogleAPIKey, + Model: cfg.NanoBananaModel, + TextModel: cfg.NanoBananaTextModel, + } + + return o.imageFactories.NewNanoBananaClient(nanoBananaConfig), nil +} - default: +// newImageSearcher constructs the appropriate image client based on the +// configured image provider. Returns image.PromptAwareClient so callers can +// call SetPromptCallback directly without a type-assertion. The factory +// functions are sourced from imageFactories (the shared image.ClientFactories +// value) to avoid duplicating the factory signatures in this package. +func (o *GenerationOrchestrator) newImageSearcher() (image.PromptAwareClient, error) { + key := strings.ToLower(strings.TrimSpace(o.config.ImageProvider)) + fn, ok := guiImageClientFactories.Get(key) + if !ok { return nil, fmt.Errorf("unknown image provider: %s", o.config.ImageProvider) } + return fn(o) } // --- Phonetics --- |
