diff options
| author | Paul Buetow <paul@buetow.org> | 2026-04-02 08:16:57 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-04-02 08:16:57 +0300 |
| commit | e905d0d7435a827825017c5612b6e61d1f1f5da7 (patch) | |
| tree | 26d9bef15305895c0b1703c629f042800367fb04 /internal/gui | |
| parent | 0349a83743f8b8c8125a35b93b2271e402352b99 (diff) | |
Centralize audio sidecar generation
Diffstat (limited to 'internal/gui')
| -rw-r--r-- | internal/gui/generator.go | 74 | ||||
| -rw-r--r-- | internal/gui/generator_test.go | 34 |
2 files changed, 64 insertions, 44 deletions
diff --git a/internal/gui/generator.go b/internal/gui/generator.go index 7143cff..45cd7bc 100644 --- a/internal/gui/generator.go +++ b/internal/gui/generator.go @@ -421,6 +421,7 @@ func (a *Application) imagePromptCallback(cardDir, word string) func(prompt stri // saveAudioAttribution saves attribution info for generated audio func (a *Application) saveAudioAttribution(word, audioFile, voice string, speed float64) error { + processedText := audio.ProcessedTextForWord(word) var attribution string switch a.audioProviderName() { case "gemini": @@ -429,11 +430,12 @@ func (a *Application) saveAudioAttribution(word, audioFile, voice string, speed model = a.audioConfig.GeminiTTSModel } attribution = audio.BuildGeminiAttribution(audio.AttributionParams{ - Word: word, - Model: model, - Voice: voice, - Speed: speed, - GeneratedAt: time.Now(), + Word: word, + Model: model, + Voice: voice, + Speed: speed, + ProcessedText: processedText, + GeneratedAt: time.Now(), }) default: model := audio.DefaultProviderConfig().OpenAIModel @@ -447,12 +449,13 @@ func (a *Application) saveAudioAttribution(word, audioFile, voice string, speed } } attribution = audio.BuildOpenAIAttribution(audio.AttributionParams{ - Word: word, - Model: model, - Voice: voice, - Speed: speed, - Instruction: instruction, - GeneratedAt: time.Now(), + Word: word, + Model: model, + Voice: voice, + Speed: speed, + Instruction: instruction, + ProcessedText: processedText, + GeneratedAt: time.Now(), }) } @@ -476,39 +479,22 @@ func (a *Application) saveAudioMetadata(cardDir string, audioConfig audio.Config } } - metadata := strings.Builder{} - - fmt.Fprintf(&metadata, "provider=%s\n", audioConfig.Provider) - switch strings.ToLower(strings.TrimSpace(audioConfig.Provider)) { - case "gemini": - model := strings.TrimSpace(audioConfig.GeminiTTSModel) - if model == "" { - model = audio.DefaultProviderConfig().GeminiTTSModel - } - fmt.Fprintf(&metadata, "model=%s\n", model) - default: - model := strings.TrimSpace(audioConfig.OpenAIModel) - if model == "" { - model = audio.DefaultProviderConfig().OpenAIModel - } - fmt.Fprintf(&metadata, "model=%s\n", model) - } - voiceLine := strings.TrimSpace(voice) - if voiceLine == "" && strings.ToLower(strings.TrimSpace(audioConfig.Provider)) == "gemini" { - voiceLine = "model-default" - } - fmt.Fprintf(&metadata, "voice=%s\n", voiceLine) - fmt.Fprintf(&metadata, "speed=%.2f\n", speed) - fmt.Fprintf(&metadata, "format=%s\n", audioConfig.OutputFormat) - fmt.Fprintf(&metadata, "cardtype=%s\n", cardType) - if audioFile != "" { - fmt.Fprintf(&metadata, "audio_file=%s\n", filepath.Base(audioFile)) - } - if audioFileBack != "" { - fmt.Fprintf(&metadata, "audio_file_back=%s\n", filepath.Base(audioFileBack)) - } - - if err := os.WriteFile(metadataFile, []byte(metadata.String()), 0644); err != nil { + metadata := audio.BuildSidecarMetadata(audio.SidecarMetadataParams{ + Provider: audioConfig.Provider, + OutputFormat: audioConfig.OutputFormat, + CardType: cardType, + AudioFile: audioFile, + AudioFileBack: audioFileBack, + OpenAIModel: audioConfig.OpenAIModel, + OpenAIVoice: voice, + OpenAISpeed: speed, + OpenAIInstruction: audioConfig.OpenAIInstruction, + GeminiTTSModel: audioConfig.GeminiTTSModel, + GeminiVoice: voice, + GeminiSpeed: speed, + }) + + if err := os.WriteFile(metadataFile, []byte(metadata), 0644); err != nil { return fmt.Errorf("failed to write audio metadata file: %w", err) } diff --git a/internal/gui/generator_test.go b/internal/gui/generator_test.go index 31b4aa2..0c1ac41 100644 --- a/internal/gui/generator_test.go +++ b/internal/gui/generator_test.go @@ -239,6 +239,19 @@ func TestGenerateAudioUsesSharedOpenAIVoices(t *testing.T) { if strings.Contains(metadata, "sentinel-gemini-model") { t.Fatalf("openai metadata should not use Gemini model when provider is OpenAI: %q", metadata) } + if !strings.Contains(metadata, "cardtype=en-bg") { + t.Fatalf("openai metadata missing card type: %q", metadata) + } + + attrPath := audio.AttributionPath(outputPath) + attributionData, err := os.ReadFile(attrPath) + if err != nil { + t.Fatalf("expected attribution file %q: %v", attrPath, err) + } + attribution := string(attributionData) + if !strings.Contains(attribution, "Processed text sent to TTS: ябълка...") { + t.Fatalf("openai attribution missing processed text: %q", attribution) + } } func TestGenerateAudioUsesGeminiModelDefaultVoiceAndAttribution(t *testing.T) { @@ -318,6 +331,9 @@ func TestGenerateAudioUsesGeminiModelDefaultVoiceAndAttribution(t *testing.T) { if strings.Contains(attribution, "sentinel-gemini-voice") { t.Fatalf("gemini attribution should not use the shared voice list when voice is unset: %q", attribution) } + if !strings.Contains(attribution, "Processed text sent to TTS: ябълка...") { + t.Fatalf("gemini attribution missing processed text: %q", attribution) + } metadataData, err := os.ReadFile(filepath.Join(cardDir, "audio_metadata.txt")) if err != nil { @@ -422,6 +438,24 @@ func TestGenerateAudioBgBgUsesSharedOpenAIVoices(t *testing.T) { if !strings.Contains(metadata, "cardtype=bg-bg") { t.Fatalf("bg-bg metadata missing card type: %q", metadata) } + + for _, tc := range []struct { + audioPath string + wantText string + }{ + {audioPath: frontPath, wantText: "ябълка..."}, + {audioPath: backPath, wantText: "круша..."}, + } { + attrPath := audio.AttributionPath(tc.audioPath) + attributionData, err := os.ReadFile(attrPath) + if err != nil { + t.Fatalf("expected attribution file %q: %v", attrPath, err) + } + attribution := string(attributionData) + if !strings.Contains(attribution, "Processed text sent to TTS: "+tc.wantText) { + t.Fatalf("bg-bg attribution missing processed text %q: %q", tc.wantText, attribution) + } + } } func TestGenerateAudioFrontUsesSharedOpenAIVoices(t *testing.T) { |
