From f1c9f1a6294033e859641c0b82537aeb2866c69a Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Wed, 1 Apr 2026 21:35:24 +0300 Subject: Honor config audio format for OpenAI --- internal/processor/processor.go | 6 ++++ internal/processor/processor_test.go | 64 ++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) (limited to 'internal/processor') diff --git a/internal/processor/processor.go b/internal/processor/processor.go index a3fc64b..66b975e 100644 --- a/internal/processor/processor.go +++ b/internal/processor/processor.go @@ -256,6 +256,12 @@ func (p *Processor) effectiveAudioFormat() string { return "wav" } + if viper.IsSet("audio.format") { + if format := strings.ToLower(strings.TrimSpace(viper.GetString("audio.format"))); format != "" { + return format + } + } + if p != nil && p.flags != nil { if format := strings.ToLower(strings.TrimSpace(p.flags.AudioFormat)); format != "" { return format diff --git a/internal/processor/processor_test.go b/internal/processor/processor_test.go index aa932e5..35ceb9b 100644 --- a/internal/processor/processor_test.go +++ b/internal/processor/processor_test.go @@ -471,6 +471,70 @@ func TestGenerateAudioUsesConfiguredGeminiVoiceAndModel(t *testing.T) { } } +func TestGenerateAudioUsesConfiguredAudioFormatWhenOpenAIConfigIsSetOnly(t *testing.T) { + originalFactory := newAudioProvider + t.Cleanup(func() { + newAudioProvider = originalFactory + }) + + fakeProvider := &fakeAudioProvider{} + var capturedConfig *audio.Config + newAudioProvider = func(config *audio.Config) (audio.Provider, error) { + copyConfig := *config + capturedConfig = ©Config + return fakeProvider, nil + } + + originalConfig := viper.New() + *originalConfig = *viper.GetViper() + defer func() { + *viper.GetViper() = *originalConfig + }() + viper.Reset() + viper.Set("audio.provider", "openai") + viper.Set("audio.format", "mp3") + + flags := cli.NewFlags() + flags.OutputDir = t.TempDir() + flags.AudioProvider = "openai" + flags.AudioFormat = "wav" + + p := NewProcessor(flags) + wordDir := p.findOrCreateWordDirectory("ябълка") + if err := p.generateAudioWithVoiceAndFilenameInDir("ябълка", "alloy", "audio", wordDir); err != nil { + t.Fatalf("generateAudioWithVoiceAndFilenameInDir() unexpected error: %v", err) + } + + if capturedConfig == nil { + t.Fatal("expected audio provider config to be captured") + } + if capturedConfig.OutputFormat != "mp3" { + t.Fatalf("captured OutputFormat = %q, want %q", capturedConfig.OutputFormat, "mp3") + } + if fakeProvider.generateCalls != 1 { + t.Fatalf("GenerateAudio() calls = %d, want %d", fakeProvider.generateCalls, 1) + } + if !strings.HasSuffix(fakeProvider.lastOutputFile, "audio.mp3") { + t.Fatalf("GenerateAudio() output file = %q, want mp3 output", fakeProvider.lastOutputFile) + } + + metadataData, err := os.ReadFile(filepath.Join(wordDir, "audio_metadata.txt")) + if err != nil { + t.Fatalf("expected metadata file: %v", err) + } + metadata := string(metadataData) + for _, want := range []string{ + "provider=openai", + "model=gpt-4o-mini-tts", + "voice=alloy", + "format=mp3", + } { + if !strings.Contains(metadata, want) { + t.Fatalf("metadata = %q, missing %q", metadata, want) + } + } +} + func TestGenerateAnkiFileUsesEffectiveAudioFormatForGemini(t *testing.T) { originalConfig := viper.New() *originalConfig = *viper.GetViper() -- cgit v1.2.3