diff options
| author | Paul Buetow <paul@buetow.org> | 2026-04-01 13:15:13 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-04-01 13:15:13 +0300 |
| commit | d3fe3586f50545575978f8d73a649afabc915008 (patch) | |
| tree | df11fc9e4c684ccabe9cf3fb006fc5fb616d3eb0 | |
| parent | 5b88a045b29970a3cc057326b85eae58ab41fe02 (diff) | |
zr: preserve Gemini init errors and docs
| -rw-r--r-- | assets/config.yaml.example | 11 | ||||
| -rw-r--r-- | internal/processor/processor_test.go | 12 | ||||
| -rw-r--r-- | internal/translation/translator.go | 24 | ||||
| -rw-r--r-- | internal/translation/translator_test.go | 29 |
4 files changed, 62 insertions, 14 deletions
diff --git a/assets/config.yaml.example b/assets/config.yaml.example index 3988035..18d4513 100644 --- a/assets/config.yaml.example +++ b/assets/config.yaml.example @@ -23,6 +23,17 @@ audio: # 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." +# Translation configuration +translation: + # Translation backend used by internal/translation/translator.go + # Supported values: openai (default) or gemini + provider: openai + +# Google API settings +google: + # Used by Gemini translation when translation.provider is set to gemini + api_key: ${GOOGLE_API_KEY} + # Image configuration image: # Provider: currently only openai is supported diff --git a/internal/processor/processor_test.go b/internal/processor/processor_test.go index 9e6b5fc..d0a0070 100644 --- a/internal/processor/processor_test.go +++ b/internal/processor/processor_test.go @@ -110,9 +110,9 @@ func TestProcessSingleWord_InvalidWord(t *testing.T) { } func TestProcessSingleWord_ValidWord(t *testing.T) { - // Skip if no API key - if os.Getenv("OPENAI_API_KEY") == "" || os.Getenv("GOOGLE_API_KEY") == "" { - t.Skip("Skipping test: OPENAI_API_KEY and GOOGLE_API_KEY must be set") + // Skip if no OpenAI API key + if os.Getenv("OPENAI_API_KEY") == "" { + t.Skip("Skipping test: OPENAI_API_KEY must be set") } flags := cli.NewFlags() @@ -162,9 +162,9 @@ func TestProcessBatch_ValidFile(t *testing.T) { flags.SkipImages = true p := NewProcessor(flags) - // Skip if no API keys - if os.Getenv("OPENAI_API_KEY") == "" || os.Getenv("GOOGLE_API_KEY") == "" { - t.Skip("Skipping test: OPENAI_API_KEY and GOOGLE_API_KEY must be set") + // Skip if no OpenAI API key + if os.Getenv("OPENAI_API_KEY") == "" { + t.Skip("Skipping test: OPENAI_API_KEY must be set") } err = p.ProcessBatch() diff --git a/internal/translation/translator.go b/internal/translation/translator.go index 1a3d3b2..09a1e67 100644 --- a/internal/translation/translator.go +++ b/internal/translation/translator.go @@ -47,15 +47,18 @@ func DefaultConfig() *Config { // Translator handles Bulgarian and English translation using the configured backend. type Translator struct { - provider Provider - openAIKey string - googleAPIKey string - openAIClient *openai.Client - geminiClient *genai.Client - openAIModel string - geminiModel string + provider Provider + openAIKey string + googleAPIKey string + openAIClient *openai.Client + geminiClient *genai.Client + geminiInitErr error + openAIModel string + geminiModel string } +var newGeminiClient = genai.NewClient + // NewTranslator creates a new translator instance from the provided config. func NewTranslator(config *Config) *Translator { if config == nil { @@ -76,11 +79,13 @@ func NewTranslator(config *Config) *Translator { } if normalized.GoogleAPIKey != "" { - client, err := genai.NewClient(context.Background(), &genai.ClientConfig{ + client, err := newGeminiClient(context.Background(), &genai.ClientConfig{ APIKey: normalized.GoogleAPIKey, }) if err == nil { translator.geminiClient = client + } else { + translator.geminiInitErr = err } } @@ -169,6 +174,9 @@ func (t *Translator) translateWithGemini(prompt string) (string, error) { if t.googleAPIKey == "" { return "", fmt.Errorf("Google API key not found") } + if t.geminiInitErr != nil { + return "", fmt.Errorf("Gemini client initialization failed: %w", t.geminiInitErr) + } if t.geminiClient == nil { return "", fmt.Errorf("Gemini client not initialized") } diff --git a/internal/translation/translator_test.go b/internal/translation/translator_test.go index d506a1e..49f1f15 100644 --- a/internal/translation/translator_test.go +++ b/internal/translation/translator_test.go @@ -1,10 +1,14 @@ package translation import ( + "context" + "errors" "os" "path/filepath" "reflect" "testing" + + "google.golang.org/genai" ) func TestNewTranslator_DefaultsToOpenAI(t *testing.T) { @@ -90,6 +94,31 @@ func TestTranslateWord_ExplicitGeminiRequiresGoogleAPIKey(t *testing.T) { } } +func TestTranslateWord_GeminiClientInitError(t *testing.T) { + originalNewGeminiClient := newGeminiClient + defer func() { + newGeminiClient = originalNewGeminiClient + }() + + initErr := errors.New("boom") + newGeminiClient = func(context.Context, *genai.ClientConfig) (*genai.Client, error) { + return nil, initErr + } + + translator := NewTranslator(&Config{ + Provider: ProviderGemini, + GoogleAPIKey: "test-google-key", + }) + + _, err := translator.TranslateWord("ябълка") + if err == nil { + t.Fatal("Expected Gemini init error") + } + if !errors.Is(err, initErr) { + t.Fatalf("Expected wrapped init error, got: %v", err) + } +} + func TestTranslateWord_IntegrationGemini(t *testing.T) { apiKey := os.Getenv("GOOGLE_API_KEY") if apiKey == "" { |
