summaryrefslogtreecommitdiff
path: root/internal/gui/audio_config_resolver.go
blob: c9dd9e60b0b272bb646ed6971184d926a90206b3 (plain)
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
package gui

import (
	"strings"

	"codeberg.org/snonux/totalrecall/internal/audio"
)

// AudioConfigResolver derives effective TTS provider settings from the GUI
// config and the shared audio.Config. It centralizes provider name, voice list,
// output format, and per-run audio.Config construction so orchestration code
// does not repeat string handling and defaults.
type AudioConfigResolver struct {
	guiConfig   *Config
	audioConfig *audio.Config
}

// NewAudioConfigResolver builds a resolver for the given GUI and audio
// settings. Either pointer may be nil; defaults match the previous
// GenerationOrchestrator behaviour.
func NewAudioConfigResolver(guiConfig *Config, audioConfig *audio.Config) *AudioConfigResolver {
	return &AudioConfigResolver{
		guiConfig:   guiConfig,
		audioConfig: audioConfig,
	}
}

// ProviderName returns the lowercase provider name from config, defaulting to
// the shared audio default when none is set.
func (r *AudioConfigResolver) ProviderName() string {
	if r.audioConfig != nil {
		if provider := strings.ToLower(strings.TrimSpace(r.audioConfig.Provider)); provider != "" {
			return provider
		}
	}
	return audio.DefaultProviderConfig().Provider
}

// Voices returns the configured provider's voice list.
func (r *AudioConfigResolver) Voices() []string {
	return audio.VoicesFor(r.ProviderName())
}

// OutputFormat resolves the effective output format (e.g. "mp3" or "wav").
func (r *AudioConfigResolver) OutputFormat() string {
	if r.guiConfig != nil && strings.TrimSpace(r.guiConfig.AudioFormat) != "" {
		return r.guiConfig.AudioFormat
	}

	if r.audioConfig != nil && strings.TrimSpace(r.audioConfig.OutputFormat) != "" {
		return r.audioConfig.OutputFormat
	}

	return audio.DefaultProviderConfig().OutputFormat
}

// ConfigForGeneration builds an audio.Config for a single generation call,
// overriding the voice and speed with the values selected for this run.
func (r *AudioConfigResolver) ConfigForGeneration(voice string, speed float64) audio.Config {
	audioConfig := audio.Config{}
	if r.audioConfig != nil {
		audioConfig = *r.audioConfig
	}

	audioConfig.Provider = r.ProviderName()
	if r.guiConfig != nil {
		audioConfig.OutputDir = r.guiConfig.OutputDir
	}
	audioConfig.OutputFormat = r.OutputFormat()

	switch audioConfig.Provider {
	case "gemini":
		audioConfig.GeminiVoice = voice
		audioConfig.GeminiSpeed = speed
		if strings.TrimSpace(audioConfig.GeminiTTSModel) == "" {
			audioConfig.GeminiTTSModel = audio.DefaultProviderConfig().GeminiTTSModel
		}
	default:
		audioConfig.OpenAIVoice = voice
		audioConfig.OpenAISpeed = speed
	}

	return audioConfig
}

// BaseConfigForAttribution returns the configured audio.Config pointer, or the
// package default when unset — matching how attribution sidecars resolve the
// base parameters before per-run voice/speed overrides.
func (r *AudioConfigResolver) BaseConfigForAttribution() *audio.Config {
	if r.audioConfig != nil {
		return r.audioConfig
	}
	return audio.DefaultProviderConfig()
}