1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
package gui
import (
"context"
"math/rand"
"time"
"codeberg.org/snonux/totalrecall/internal/audio"
)
// randomVoice picks a random voice from the provided list.
// Used by GenerationOrchestrator for both OpenAI and Gemini voice selection.
func randomVoice(voices []string) string {
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
return voices[rng.Intn(len(voices))]
}
// randomOpenAISpeed picks a random speed in [0.90, 1.00) for OpenAI TTS to
// add slight variation across generations.
func randomOpenAISpeed() float64 {
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
return 0.90 + rng.Float64()*0.10
}
// --- Application delegation methods ---
// Each method delegates to getOrchestrator() so tests that create Application
// directly (setting newAudioProvider / audioConfig / config) continue to work
// without modification, while production code uses the pre-built orchestrator.
// audioProviderName returns the lowercase TTS provider name.
func (a *Application) audioProviderName() string {
return a.getOrchestrator().audioProviderName()
}
// audioOutputFormat resolves the effective audio output format.
func (a *Application) audioOutputFormat() string {
return a.getOrchestrator().audioOutputFormat()
}
// translateWord translates a Bulgarian word to English.
func (a *Application) translateWord(word string) (string, error) {
return a.getOrchestrator().TranslateWord(word)
}
// translateEnglishToBulgarian translates an English word to Bulgarian.
func (a *Application) translateEnglishToBulgarian(word string) (string, error) {
return a.getOrchestrator().TranslateEnglishToBulgarian(word)
}
// generateAudio generates audio for an en-bg card's single audio file.
func (a *Application) generateAudio(ctx context.Context, word, cardDir string) (string, error) {
return a.getOrchestrator().GenerateAudio(ctx, word, cardDir)
}
// generateAudioFront generates the front audio file for a bg-bg card.
func (a *Application) generateAudioFront(ctx context.Context, word, cardDir string) (string, error) {
return a.getOrchestrator().GenerateAudioFront(ctx, word, cardDir)
}
// generateAudioBack generates the back audio file for a bg-bg card.
func (a *Application) generateAudioBack(ctx context.Context, text, cardDir string) (string, error) {
return a.getOrchestrator().GenerateAudioBack(ctx, text, cardDir)
}
// generateAudioBgBg generates audio for both sides of a bg-bg card.
func (a *Application) generateAudioBgBg(ctx context.Context, front, back, cardDir string) (string, string, error) {
return a.getOrchestrator().GenerateAudioBgBg(ctx, front, back, cardDir)
}
// generateAudioFile generates a single audio file using the given voice/speed.
// Kept as a thin wrapper so the fallback tests in generator_test.go can call it.
func (a *Application) generateAudioFile(ctx context.Context, text, outputFile, voice string, speed float64) error {
return a.getOrchestrator().generateAudioFile(ctx, text, outputFile, voice, speed)
}
// generateImagesWithPrompt downloads a single image for a word with optional
// custom prompt and translation hint.
func (a *Application) generateImagesWithPrompt(ctx context.Context, word, customPrompt, translation, cardDir string) (string, error) {
o := a.getOrchestrator()
// Wrap with a UI update callback for the current word's image prompt entry.
promptUI := func(prompt string) {
a.mu.Lock()
isCurrentWord := a.currentWord == word
a.mu.Unlock()
if isCurrentWord && a.imagePromptEntry != nil {
a.imagePromptEntry.SetText(prompt)
}
}
return o.generateImagesWithPromptAndNotify(ctx, word, customPrompt, translation, cardDir, promptUI)
}
// getPhoneticInfo fetches phonetic information for a Bulgarian word.
func (a *Application) getPhoneticInfo(word string) (string, error) {
return a.getOrchestrator().GetPhoneticInfo(word)
}
// saveAudioAttribution saves attribution metadata for a generated audio file.
func (a *Application) saveAudioAttribution(word, audioFile, voice string, speed float64) error {
return a.getOrchestrator().saveAudioAttribution(word, audioFile, voice, speed)
}
// saveAudioMetadata writes the sidecar metadata file for a generated audio file.
func (a *Application) saveAudioMetadata(cardDir string, audioCfg audio.Config, voice string, speed float64, cardType, audioFile, audioFileBack string) error {
return a.getOrchestrator().saveAudioMetadata(cardDir, audioCfg, voice, speed, cardType, audioFile, audioFileBack)
}
|