diff options
| author | Paul Buetow <paul@buetow.org> | 2025-07-22 07:54:57 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-07-22 07:54:57 +0300 |
| commit | 1cc15cfbd68d45ae6d561e5659422e72bf9ecd1d (patch) | |
| tree | 92bd29d34fed9c4d28cfe4d94e35b040c0b505bc | |
| parent | 1365dde5c25e1865b82fbfea50208327d5e3a51c (diff) | |
Remove audio cache feature to simplify codebase and avoid cache-related issues
π€ Generated with [opencode](https://opencode.ai)
Co-Authored-By: opencode <noreply@opencode.ai>
| -rw-r--r-- | config.yaml.example | 4 | ||||
| -rw-r--r-- | internal/audio/openai_provider.go | 111 | ||||
| -rw-r--r-- | internal/audio/openai_provider_test.go | 195 | ||||
| -rw-r--r-- | internal/audio/provider.go | 5 | ||||
| -rw-r--r-- | internal/audio/provider_test.go | 7 | ||||
| -rw-r--r-- | internal/gui/app.go | 2 | ||||
| -rw-r--r-- | internal/processor/processor.go | 9 |
7 files changed, 6 insertions, 327 deletions
diff --git a/config.yaml.example b/config.yaml.example index b5c7cbd..3988035 100644 --- a/config.yaml.example +++ b/config.yaml.example @@ -22,10 +22,6 @@ audio: # openai_instruction: "Speak in Bulgarian (not Russian!). Use native Bulgarian pronunciation with clear articulation for each syllable." # openai_instruction: "You are a Bulgarian language teacher. Pronounce the Bulgarian words slowly with authentic Bulgarian accent and phonetics." # openai_instruction: "Speak Bulgarian text with proper Bulgarian pronunciation. Avoid Russian accent. Speak clearly at a pace suitable for beginners." - - # Caching - enable_cache: true - cache_dir: ./.audio_cache # Image configuration image: diff --git a/internal/audio/openai_provider.go b/internal/audio/openai_provider.go index 0f3a0ad..3c2a22d 100644 --- a/internal/audio/openai_provider.go +++ b/internal/audio/openai_provider.go @@ -2,8 +2,6 @@ package audio import ( "context" - "crypto/md5" - "encoding/hex" "fmt" "io" "os" @@ -15,10 +13,8 @@ import ( // OpenAIProvider implements Provider interface for OpenAI TTS type OpenAIProvider struct { - client *openai.Client - config *Config - cacheDir string - enableCache bool + client *openai.Client + config *Config } // NewOpenAIProvider creates a new OpenAI TTS provider @@ -30,17 +26,8 @@ func NewOpenAIProvider(config *Config) (Provider, error) { client := openai.NewClient(config.OpenAIKey) provider := &OpenAIProvider{ - client: client, - config: config, - cacheDir: config.CacheDir, - enableCache: config.EnableCache, - } - - // Create cache directory if caching is enabled - if provider.enableCache && provider.cacheDir != "" { - if err := os.MkdirAll(provider.cacheDir, 0755); err != nil { - return nil, fmt.Errorf("failed to create cache directory: %w", err) - } + client: client, + config: config, } return provider, nil @@ -53,15 +40,6 @@ func (p *OpenAIProvider) GenerateAudio(ctx context.Context, text string, outputF return err } - // Check cache first - if p.enableCache { - cacheFile := p.getCacheFilePath(text) - if _, err := os.Stat(cacheFile); err == nil { - // Cache hit - copy cached file - return p.copyFile(cacheFile, outputFile) - } - } - // Preprocess text for clearer Bulgarian pronunciation processedText := p.preprocessBulgarianText(text) @@ -142,12 +120,6 @@ func (p *OpenAIProvider) GenerateAudio(ctx context.Context, text string, outputF return fmt.Errorf("no audio data received from OpenAI") } - // Cache the result if caching is enabled - if p.enableCache { - cacheFile := p.getCacheFilePath(text) - _ = p.copyFile(outputFile, cacheFile) // Ignore cache errors - } - return nil } @@ -187,78 +159,3 @@ func (p *OpenAIProvider) preprocessBulgarianText(text string) string { return processedText } - -// getCacheFilePath generates a cache file path for the given text -func (p *OpenAIProvider) getCacheFilePath(text string) string { - // Create a hash of the text and settings - h := md5.New() - h.Write([]byte(text)) - h.Write([]byte(p.config.OpenAIModel)) - h.Write([]byte(p.config.OpenAIVoice)) - h.Write([]byte(fmt.Sprintf("%.2f", p.config.OpenAISpeed))) - // Include instruction in cache key for gpt-4o-mini-tts - if p.config.OpenAIModel == "gpt-4o-mini-tts" && p.config.OpenAIInstruction != "" { - h.Write([]byte(p.config.OpenAIInstruction)) - } - hash := hex.EncodeToString(h.Sum(nil)) - - // Use first 2 chars as subdirectory for better file system performance - subdir := hash[:2] - filename := hash[2:] + ".mp3" - - return filepath.Join(p.cacheDir, subdir, filename) -} - -// copyFile copies a file from src to dst -func (p *OpenAIProvider) copyFile(src, dst string) error { - // Ensure destination directory exists - dir := filepath.Dir(dst) - if dir != "" && dir != "." { - if err := os.MkdirAll(dir, 0755); err != nil { - return err - } - } - - source, err := os.Open(src) - if err != nil { - return err - } - defer source.Close() - - destination, err := os.Create(dst) - if err != nil { - return err - } - defer destination.Close() - - _, err = io.Copy(destination, source) - return err -} - -// ClearCache removes all cached audio files -func (p *OpenAIProvider) ClearCache() error { - if p.cacheDir == "" { - return nil - } - return os.RemoveAll(p.cacheDir) -} - -// GetCacheStats returns cache statistics -func (p *OpenAIProvider) GetCacheStats() (fileCount int, totalSize int64, err error) { - if !p.enableCache || p.cacheDir == "" { - return 0, 0, nil - } - - err = filepath.Walk(p.cacheDir, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if !info.IsDir() { - fileCount++ - totalSize += info.Size() - } - return nil - }) - - return fileCount, totalSize, err -} diff --git a/internal/audio/openai_provider_test.go b/internal/audio/openai_provider_test.go index 7e3f9e5..ae16ca0 100644 --- a/internal/audio/openai_provider_test.go +++ b/internal/audio/openai_provider_test.go @@ -2,8 +2,6 @@ package audio import ( "context" - "os" - "path/filepath" "strings" "testing" ) @@ -24,19 +22,9 @@ func TestNewOpenAIProvider(t *testing.T) { errMsg: "OpenAI API key is required", }, { - name: "valid config with cache", + name: "valid config", config: &Config{ - OpenAIKey: "test-key", - EnableCache: true, - CacheDir: "./test_cache", - }, - wantErr: false, - }, - { - name: "valid config without cache", - config: &Config{ - OpenAIKey: "test-key", - EnableCache: false, + OpenAIKey: "test-key", }, wantErr: false, }, @@ -52,11 +40,6 @@ func TestNewOpenAIProvider(t *testing.T) { t.Errorf("NewOpenAIProvider() error = %v, want %v", err.Error(), tt.errMsg) } - // Cleanup cache dir if created - if !tt.wantErr && tt.config.EnableCache && tt.config.CacheDir != "" { - os.RemoveAll(tt.config.CacheDir) - } - // Check provider properties if !tt.wantErr && provider != nil { if provider.Name() != "openai" { @@ -149,180 +132,6 @@ func TestPreprocessBulgarianText(t *testing.T) { } } -func TestGetCacheFilePath(t *testing.T) { - provider := &OpenAIProvider{ - config: &Config{ - OpenAIModel: "tts-1", - OpenAIVoice: "alloy", - OpenAISpeed: 1.0, - }, - cacheDir: "./test_cache", - } - - // Test basic cache path generation - path1 := provider.getCacheFilePath("ΡΠ±ΡΠ»ΠΊΠ°") - if !strings.HasPrefix(path1, "test_cache/") { - t.Errorf("Cache path should start with cache dir, got %s", path1) - } - if !strings.HasSuffix(path1, ".mp3") { - t.Errorf("Cache path should end with .mp3, got %s", path1) - } - - // Test that same input produces same path - path2 := provider.getCacheFilePath("ΡΠ±ΡΠ»ΠΊΠ°") - if path1 != path2 { - t.Errorf("Same input should produce same cache path, got %s and %s", path1, path2) - } - - // Test that different input produces different path - path3 := provider.getCacheFilePath("ΠΊΠΎΡΠΊΠ°") - if path1 == path3 { - t.Errorf("Different input should produce different cache path") - } - - // Test that different settings produce different paths - provider.config.OpenAIVoice = "nova" - path4 := provider.getCacheFilePath("ΡΠ±ΡΠ»ΠΊΠ°") - if path1 == path4 { - t.Errorf("Different voice should produce different cache path") - } - - // Test with instruction for gpt-4o-mini-tts - provider.config.OpenAIModel = "gpt-4o-mini-tts" - provider.config.OpenAIInstruction = "Test instruction" - path5 := provider.getCacheFilePath("ΡΠ±ΡΠ»ΠΊΠ°") - - provider.config.OpenAIInstruction = "Different instruction" - path6 := provider.getCacheFilePath("ΡΠ±ΡΠ»ΠΊΠ°") - if path5 == path6 { - t.Errorf("Different instruction should produce different cache path for gpt-4o-mini-tts") - } -} - -func TestCopyFile(t *testing.T) { - // Create a temporary directory for testing - tempDir := t.TempDir() - - provider := &OpenAIProvider{} - - // Create source file - srcPath := filepath.Join(tempDir, "source.txt") - srcContent := []byte("test content") - if err := os.WriteFile(srcPath, srcContent, 0644); err != nil { - t.Fatalf("Failed to create source file: %v", err) - } - - // Test copying to new file - dstPath := filepath.Join(tempDir, "dest.txt") - err := provider.copyFile(srcPath, dstPath) - if err != nil { - t.Errorf("copyFile() error = %v", err) - } - - // Verify content - dstContent, err := os.ReadFile(dstPath) - if err != nil { - t.Fatalf("Failed to read destination file: %v", err) - } - if string(dstContent) != string(srcContent) { - t.Errorf("Copied content doesn't match: got %q, want %q", dstContent, srcContent) - } - - // Test copying to subdirectory - dstPath2 := filepath.Join(tempDir, "subdir", "dest2.txt") - err = provider.copyFile(srcPath, dstPath2) - if err != nil { - t.Errorf("copyFile() to subdirectory error = %v", err) - } - - // Test copying non-existent file - err = provider.copyFile(filepath.Join(tempDir, "nonexistent.txt"), dstPath) - if err == nil { - t.Error("copyFile() expected error for non-existent source") - } -} - -func TestClearCache(t *testing.T) { - tempDir := t.TempDir() - - provider := &OpenAIProvider{ - cacheDir: filepath.Join(tempDir, "cache"), - } - - // Create cache directory with some files - os.MkdirAll(filepath.Join(provider.cacheDir, "ab"), 0755) - os.WriteFile(filepath.Join(provider.cacheDir, "ab", "test1.mp3"), []byte("data1"), 0644) - os.WriteFile(filepath.Join(provider.cacheDir, "ab", "test2.mp3"), []byte("data2"), 0644) - - // Clear cache - err := provider.ClearCache() - if err != nil { - t.Errorf("ClearCache() error = %v", err) - } - - // Verify cache directory is gone - if _, err := os.Stat(provider.cacheDir); !os.IsNotExist(err) { - t.Error("Cache directory should be removed") - } - - // Test clearing with empty cache dir - provider.cacheDir = "" - err = provider.ClearCache() - if err != nil { - t.Errorf("ClearCache() with empty dir should not error: %v", err) - } -} - -func TestGetCacheStats(t *testing.T) { - tempDir := t.TempDir() - - provider := &OpenAIProvider{ - enableCache: true, - cacheDir: filepath.Join(tempDir, "cache"), - } - - // Create the cache directory first - os.MkdirAll(provider.cacheDir, 0755) - - // Test with no cache files - count, size, err := provider.GetCacheStats() - if err != nil { - t.Errorf("GetCacheStats() error = %v", err) - } - if count != 0 || size != 0 { - t.Errorf("Expected empty cache stats, got count=%d, size=%d", count, size) - } - // Create cache files - os.MkdirAll(filepath.Join(provider.cacheDir, "ab"), 0755) - data1 := []byte("test data 1") - data2 := []byte("test data 22") - os.WriteFile(filepath.Join(provider.cacheDir, "ab", "test1.mp3"), data1, 0644) - os.WriteFile(filepath.Join(provider.cacheDir, "ab", "test2.mp3"), data2, 0644) - - // Get stats - count, size, err = provider.GetCacheStats() - if err != nil { - t.Errorf("GetCacheStats() error = %v", err) - } - if count != 2 { - t.Errorf("Expected 2 files, got %d", count) - } - expectedSize := int64(len(data1) + len(data2)) - if size != expectedSize { - t.Errorf("Expected size %d, got %d", expectedSize, size) - } - - // Test with cache disabled - provider.enableCache = false - count, size, err = provider.GetCacheStats() - if err != nil { - t.Errorf("GetCacheStats() with cache disabled error = %v", err) - } - if count != 0 || size != 0 { - t.Errorf("Expected zero stats with cache disabled, got count=%d, size=%d", count, size) - } -} - func TestGenerateAudioValidation(t *testing.T) { provider := &OpenAIProvider{ config: &Config{ diff --git a/internal/audio/provider.go b/internal/audio/provider.go index 0142fb3..06894bf 100644 --- a/internal/audio/provider.go +++ b/internal/audio/provider.go @@ -30,9 +30,6 @@ type Config struct { OpenAISpeed float64 // 0.25 to 4.0 OpenAIInstruction string // Voice instructions for gpt-4o-mini-tts model - // Caching settings - EnableCache bool - CacheDir string } // DefaultConfig returns default configuration @@ -46,8 +43,6 @@ func DefaultProviderConfig() *Config { OpenAISpeed: 1.0, // OpenAISpeed: 0.98, // Default speed for clarity OpenAIInstruction: "You are speaking Bulgarian language (Π±ΡΠ»Π³Π°ΡΡΠΊΠΈ Π΅Π·ΠΈΠΊ). Pronounce the Bulgarian text with authentic Bulgarian phonetics, not Russian. Speak slowly and clearly for language learners.", - EnableCache: true, - CacheDir: "./.audio_cache", } } diff --git a/internal/audio/provider_test.go b/internal/audio/provider_test.go index 7fda932..97d3e9c 100644 --- a/internal/audio/provider_test.go +++ b/internal/audio/provider_test.go @@ -50,13 +50,6 @@ func TestDefaultProviderConfig(t *testing.T) { t.Errorf("Expected OpenAI speed 1.0, got %f", config.OpenAISpeed) } - if !config.EnableCache { - t.Error("Expected cache to be enabled by default") - } - - if config.CacheDir != "./.audio_cache" { - t.Errorf("Expected cache dir './.audio_cache', got '%s'", config.CacheDir) - } } func TestNewProvider(t *testing.T) { diff --git a/internal/gui/app.go b/internal/gui/app.go index cd4b711..6a58286 100644 --- a/internal/gui/app.go +++ b/internal/gui/app.go @@ -170,8 +170,6 @@ func New(config *Config) *Application { OpenAIVoice: "nova", OpenAISpeed: 0.9, OpenAIInstruction: "You are speaking Bulgarian language (Π±ΡΠ»Π³Π°ΡΡΠΊΠΈ Π΅Π·ΠΈΠΊ). Pronounce the Bulgarian text with authentic Bulgarian phonetics, not Russian. Speak slowly and clearly for language learners.", - EnableCache: true, - CacheDir: "./.audio_cache", } app.setupUI() diff --git a/internal/processor/processor.go b/internal/processor/processor.go index 43e75ca..1e1c20f 100644 --- a/internal/processor/processor.go +++ b/internal/processor/processor.go @@ -263,15 +263,6 @@ func (p *Processor) generateAudioWithVoice(word, voice string) error { OpenAIVoice: voice, OpenAISpeed: speed, OpenAIInstruction: p.flags.OpenAIInstruction, - - // Caching - EnableCache: viper.GetBool("audio.enable_cache"), - CacheDir: viper.GetString("audio.cache_dir"), - } - - // Set defaults - if providerConfig.CacheDir == "" { - providerConfig.CacheDir = "./.audio_cache" } // Use config file values if not overridden by flags |
