| Age | Commit message (Collapse) | Author |
|
FindCardDirectory, FindOrCreateCardDirectory, GenerateCardID and the
ScanWords helper previously existed in both internal/utils.go (as
standalone functions) and were partially duplicated in
internal/gui/card_service.go (readWordFromDir, ScanExistingWords).
Introduce internal/store.CardStore as the single source of truth for
all on-disk card-directory operations. Both internal/processor and
internal/gui now hold a *store.CardStore field and delegate to it,
removing the last copy of the directory-scanning loop from
card_service.go. internal/utils.go keeps thin forwarding wrappers for
callers that import the root internal package.
Also adds table-driven unit tests for the new package covering
FindCardDirectory (including legacy _word.txt fallback),
FindOrCreateCardDirectory, and CardStore.ScanWords.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Define audio.ProviderFactory, image.PromptAwareClient,
image.OpenAIClientFactory, image.NanoBananaClientFactory, and
image.ClientFactories as the single source of truth for the three injectable
factory signatures that were previously duplicated across processor.Processor,
gui.Application, and gui.GenerationOrchestrator. Replace all three separate
function-type fields with imageFactories image.ClientFactories +
newAudioProvider audio.ProviderFactory, eliminating the parallel field
declarations and the local promptAwareImageClient interface in gui/generator.go.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Resolve all Viper config values once at startup in cmd/totalrecall/main.go
via the new newProcessorConfig() helper. The exported processor.Config struct
replaces the internal viperConfig type, and NewProcessor now accepts *Config
instead of querying Viper internally. The processor package no longer imports
Viper at all. Tests are updated to pass Config values directly, eliminating
the viper.Set/Reset boilerplate that coupled tests to the global singleton.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Extract audio coordination (voice selection, config assembly, attribution
writing) into audio_coordinator.go, card directory management into
card_store.go, and image downloading/searcher construction into
image_downloader.go. processor.go shrinks from ~1119 to ~575 lines,
each file now has a single clear responsibility. Also apply go fmt to
all touched files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
- audio/fallbacks.go: lowercase error string per Go convention
- gui/app.go: remove empty else branch in keyboard shortcut handler
- audio/provider_test.go: remove unused mockProvider type
- update test assertions in voices_test.go and processor_test.go to match
the corrected lowercase error string
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
config, extract shared card-dir logic
task 00d: remove package-level var test seams from processor and gui packages;
factory functions (newAudioProvider, newOpenAIImageClient, newNanoBananaImageClient)
are now struct fields on Processor and Application, initialized with production
defaults in constructors and replaced in tests without global mutation.
task 006: add viperConfig struct captured once in NewProcessor; no method body
calls viper.GetString/IsSet/GetFloat64 directly any more — all config-file values
are accessed via p.viperCfg fields.
task 007: extract FindCardDirectory and FindOrCreateCardDirectory into
internal/utils.go; both Processor.findCardDirectory and
Application.findCardDirectory now delegate to the shared implementation,
which also handles the legacy _word.txt backward-compat fallback.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Extend audio.Provider with Voices() []string and BuildAttribution() string
so all provider-specific behaviour is encapsulated in the implementation
rather than scattered as switch-cases across callers.
Add package-level VoicesFor(name) and BuildAttributionFor(name, params)
for callers (processor, GUI) that need these before constructing a
Provider instance. Add AttributionParamsFrom(config, word, ...) so
callers can build AttributionParams from the flat Config without a manual
provider switch. Implement both new interface methods in OpenAIProvider
and GeminiProvider. Update all Provider mock/fake types in tests.
Migrate audioVoicesForProvider() and saveAudioAttribution() in both
processor.go and gui/generator.go to use the new package-level helpers,
replacing the 10+ duplicated switch blocks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Replace Processor.RunGUIMode() with a standalone runGUIMode() function in
the composition root (cmd/main.go) that calls proc.GUIConfig() to get the
GUI settings and then owns the gui.New()/Run() lifecycle. The processor
package still imports gui for the gui.Config return type; complete removal
of that import is deferred to task 000 (god-object decomposition) where
the Processor itself will be split up.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
Add PhoneticFetcher and Translator fields to gui.Config so callers can
inject ready-to-use instances. gui.New() uses the injected values when
non-nil and falls back to constructing from provider/key fields otherwise.
The processor composition root now builds both dependencies and sets them
on gui.Config, keeping construction logic out of gui.New().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
batch timeout
- Thread ctx context.Context through generateAudio, generateAudioBgBg,
generateAudioWithVoice, generateAudioWithVoiceAndFilename,
generateAudioWithVoiceAndFilenameInDir, and downloadImagesWithTranslation.
Also add ctx to ProcessWordWithTranslationAndType so callers can control
the deadline for the full word-processing pipeline.
- In ProcessBatch, create a context.WithTimeout(5 * time.Minute) per word
so a single hung TTS or image API call cannot block the whole batch run.
Previously both functions created context.Background() internally, making
cancellation impossible.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- Fix critical bug where generateAudioBgBg() was creating two separate
card directories (one for front audio, one for back audio)
- Root cause: generateAudioWithVoiceAndFilename() calls findOrCreateWordDirectory()
with both the front word AND the back word, creating separate directories
- Solution: Pass wordDir to both audio generation calls
- Create new generateAudioWithVoiceAndFilenameInDir() function
- Refactor generateAudioWithVoiceAndFilename() to use new function
- generateAudioBgBg() now finds directory ONCE and passes it to both calls
This fixes the issue where opening a bg-bg card showed 'no audio loaded'
because audio_front.mp3 and audio_back.mp3 were in different directories.
|
|
- Add debug logging to navigation.go to diagnose audio file loading issues
Prints paths being checked and whether files are found
- Improve AudioPlayer UI for Bulgarian-Bulgarian cards:
- Add labels showing 'Front' and 'Back' for bg-bg audio buttons
- Labels only show when audio files are actually loaded
- Better visual distinction between the two playable audios
- Reorganized button layout with VBox for cleaner appearance
- Track bg-bg state in AudioPlayer (isBgBg field)
- Automatically set when back audio file is loaded
- Used to determine when to show labels
This makes it clearer that Bulgarian-Bulgarian cards have two independently
playable audio outputs, and helps debug why audio isn't being loaded.
|
|
|
|
|
|
🤖 Generated with [opencode](https://opencode.ai)
Co-Authored-By: opencode <noreply@opencode.ai>
|