From 61529facc2c5321de9f0ab9123cb1de25bcab62c Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Tue, 15 Jul 2025 23:28:13 +0300 Subject: feat: remove espeak, add random voice/style selection, fix punctuation in TTS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Removed espeak audio provider completely, now only uses OpenAI TTS - Audio now uses random voice selection by default (can override with --openai-voice) - Added --all-voices flag to generate audio in all 11 OpenAI voices - Images now use random art styles (13 different styles including superhero, yoga, cat-themed) - Fixed TTS to remove punctuation marks before speaking - Updated Bulgarian pronunciation instructions to explicitly avoid Russian accent πŸ€– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- internal/image/openai.go | 26 ++++++++++++++++++++++++-- internal/image/openai_test.go | 23 +---------------------- 2 files changed, 25 insertions(+), 24 deletions(-) (limited to 'internal/image') diff --git a/internal/image/openai.go b/internal/image/openai.go index 839c735..ee05c80 100644 --- a/internal/image/openai.go +++ b/internal/image/openai.go @@ -6,6 +6,7 @@ import ( "encoding/hex" "fmt" "io" + "math/rand" "net/http" "os" "path/filepath" @@ -230,14 +231,35 @@ func (c *OpenAIClient) Name() string { // createEducationalPrompt generates a prompt optimized for language learning func (c *OpenAIClient) createEducationalPrompt(bulgarianWord, englishTranslation string) string { + // Define different art styles for variety + styles := []string{ + "photorealistic, high quality photograph", + "detailed digital illustration, clean vector art style", + "vibrant cartoon style, animated movie quality", + "minimalist flat design, modern graphic style", + "watercolor painting, soft artistic style", + "pencil sketch, detailed drawing style", + "3D rendered, pixar-style animation", + "oil painting, classical art style", + "paper cut art, layered craft style", + "isometric illustration, technical drawing style", + "superhero comic book style, dynamic action pose, bold colors", + "yoga/wellness illustration style, peaceful zen aesthetic", + "cute illustration with cats interacting with the subject, whimsical cat-themed", + } + + // Select a random style + selectedStyle := styles[rand.Intn(len(styles))] + fmt.Printf(" Using image style: %s\n", selectedStyle) + // Create a simple, clear prompt for educational images return fmt.Sprintf( - "Generate a simple, clear image of: %s. "+ + "Generate a %s of: %s. "+ "This is for the Bulgarian word '%s' which means %s. "+ "The image should be educational and suitable for language learning flashcards. "+ "Requirements: single main subject, plain background, clear and recognizable. "+ "No text, labels, or writing in the image.", - englishTranslation, bulgarianWord, englishTranslation, + selectedStyle, englishTranslation, bulgarianWord, englishTranslation, ) } diff --git a/internal/image/openai_test.go b/internal/image/openai_test.go index 8f42aeb..c096d11 100644 --- a/internal/image/openai_test.go +++ b/internal/image/openai_test.go @@ -123,28 +123,7 @@ func TestOpenAIClient_getCacheFilePath(t *testing.T) { } } -func TestOpenAIClient_translateBulgarianToEnglish(t *testing.T) { - tests := []struct { - input string - expected string - }{ - {"ябълка", "apple"}, - {"ΠΊΠΎΡ‚ΠΊΠ°", "cat"}, - {"ΠΊΡƒΡ‡Π΅", "dog"}, - {"хляб", "bread"}, - {"unknown", "unknown"}, // Should return original if not in dictionary - } - - for _, tt := range tests { - t.Run(tt.input, func(t *testing.T) { - result := translateBulgarianToEnglish(tt.input) - if result != tt.expected { - t.Errorf("translateBulgarianToEnglish(%s) = %s, want %s", - tt.input, result, tt.expected) - } - }) - } -} +// translateBulgarianToEnglish test removed - now uses OpenAI API func TestOpenAIClient_getSizeWidthHeight(t *testing.T) { tests := []struct { -- cgit v1.2.3