feat: remove legacy configuration

This commit is contained in:
leonardotrapani
2026-02-01 23:09:33 +01:00
parent 500b84caec
commit 2729882b9d
20 changed files with 272 additions and 622 deletions
+130 -203
View File
@@ -26,10 +26,12 @@ func createTestConfig() *Config {
},
Transcription: TranscriptionConfig{
Provider: "openai",
APIKey: "test-api-key",
Language: "",
Model: "whisper-1",
},
Providers: map[string]ProviderConfig{
"openai": {APIKey: "test-api-key"},
},
Injection: InjectionConfig{
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
WtypeTimeout: 5 * time.Second,
@@ -55,7 +57,6 @@ func createTestConfigWithInvalidValues() *Config {
},
Transcription: TranscriptionConfig{
Provider: "", // Invalid
APIKey: "", // Invalid
Model: "", // Invalid
},
Injection: InjectionConfig{
@@ -98,9 +99,11 @@ func TestConfig_Validate(t *testing.T) {
},
Transcription: TranscriptionConfig{
Provider: "openai",
APIKey: "test-key",
Model: "whisper-1",
},
Providers: map[string]ProviderConfig{
"openai": {APIKey: "test-key"},
},
Injection: InjectionConfig{
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
WtypeTimeout: time.Second,
@@ -125,9 +128,11 @@ func TestConfig_Validate(t *testing.T) {
},
Transcription: TranscriptionConfig{
Provider: "",
APIKey: "test-key",
Model: "whisper-1",
},
Providers: map[string]ProviderConfig{
"openai": {APIKey: "test-key"},
},
Injection: InjectionConfig{
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
WtypeTimeout: time.Second,
@@ -152,9 +157,11 @@ func TestConfig_Validate(t *testing.T) {
},
Transcription: TranscriptionConfig{
Provider: "openai",
APIKey: "test-key",
Model: "whisper-1",
},
Providers: map[string]ProviderConfig{
"openai": {APIKey: "test-key"},
},
Injection: InjectionConfig{
Backends: []string{"invalid"}, YdotoolTimeout: 5 * time.Second,
WtypeTimeout: time.Second,
@@ -179,9 +186,11 @@ func TestConfig_Validate(t *testing.T) {
},
Transcription: TranscriptionConfig{
Provider: "openai",
APIKey: "test-key",
Model: "whisper-1",
},
Providers: map[string]ProviderConfig{
"openai": {APIKey: "test-key"},
},
Injection: InjectionConfig{
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
WtypeTimeout: time.Second,
@@ -206,10 +215,12 @@ func TestConfig_Validate(t *testing.T) {
},
Transcription: TranscriptionConfig{
Provider: "openai",
APIKey: "test-key",
Language: "en",
Model: "whisper-1",
},
Providers: map[string]ProviderConfig{
"openai": {APIKey: "test-key"},
},
Injection: InjectionConfig{
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
WtypeTimeout: time.Second,
@@ -234,10 +245,12 @@ func TestConfig_Validate(t *testing.T) {
},
Transcription: TranscriptionConfig{
Provider: "openai",
APIKey: "test-key",
Language: "invalid",
Model: "whisper-1",
},
Providers: map[string]ProviderConfig{
"openai": {APIKey: "test-key"},
},
Injection: InjectionConfig{
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
WtypeTimeout: time.Second,
@@ -312,9 +325,11 @@ buffer_size = 8192
channel_buffer_size = 30
timeout = "5m"
[providers.openai]
api_key = "test-key"
[transcription]
provider = "openai"
api_key = "test-key"
model = "whisper-1"
[injection]
@@ -362,8 +377,8 @@ type = "log"`
}
})
// Test migration from legacy mode config
t.Run("migrates legacy mode=fallback to backends", func(t *testing.T) {
// Legacy configs should fail like missing config
t.Run("rejects legacy injection.mode", func(t *testing.T) {
tempDir := t.TempDir()
configPath := filepath.Join(tempDir, "hyprvoice", "config.toml")
@@ -382,17 +397,12 @@ timeout = "5m"
[transcription]
provider = "openai"
api_key = "test-key"
model = "whisper-1"
[injection]
mode = "fallback"
wtype_timeout = "5s"
clipboard_timeout = "3s"
[notifications]
enabled = true
type = "log"`
clipboard_timeout = "3s"`
err = os.WriteFile(configPath, []byte(legacyConfig), 0644)
if err != nil {
@@ -409,35 +419,70 @@ type = "log"`
}
}()
config, err := Load()
if err != nil {
t.Errorf("Load() error = %v", err)
return
_, err = Load()
if err == nil {
t.Fatalf("Load() should have failed for legacy injection.mode")
}
// Should have migrated to backends
expectedBackends := []string{"wtype", "clipboard"}
if len(config.Injection.Backends) != len(expectedBackends) {
t.Errorf("Expected %d backends, got %d", len(expectedBackends), len(config.Injection.Backends))
}
for i, b := range expectedBackends {
if i < len(config.Injection.Backends) && config.Injection.Backends[i] != b {
t.Errorf("Expected backend[%d]=%s, got %s", i, b, config.Injection.Backends[i])
}
}
// Should have set default ydotool timeout
if config.Injection.YdotoolTimeout != 5*time.Second {
t.Errorf("Expected YdotoolTimeout=5s, got %v", config.Injection.YdotoolTimeout)
}
// Verify it passes validation
if err := config.Validate(); err != nil {
t.Errorf("Migrated config is invalid: %v", err)
if !errors.Is(err, ErrConfigNotFound) {
t.Errorf("Load() error = %v, expected ErrConfigNotFound", err)
}
})
t.Run("migrates legacy mode=clipboard to backends", func(t *testing.T) {
t.Run("rejects legacy general.language", func(t *testing.T) {
tempDir := t.TempDir()
configPath := filepath.Join(tempDir, "hyprvoice", "config.toml")
err := os.MkdirAll(filepath.Dir(configPath), 0755)
if err != nil {
t.Fatalf("Failed to create config directory: %v", err)
}
legacyConfig := `[general]
language = "en"
[recording]
sample_rate = 16000
channels = 1
format = "s16"
buffer_size = 8192
channel_buffer_size = 30
timeout = "5m"
[transcription]
provider = "openai"
model = "whisper-1"
[injection]
backends = ["clipboard"]
ydotool_timeout = "5s"
wtype_timeout = "5s"
clipboard_timeout = "3s"`
err = os.WriteFile(configPath, []byte(legacyConfig), 0644)
if err != nil {
t.Fatalf("Failed to create config file: %v", err)
}
originalConfigDir := os.Getenv("XDG_CONFIG_HOME")
os.Setenv("XDG_CONFIG_HOME", tempDir)
defer func() {
if originalConfigDir == "" {
os.Unsetenv("XDG_CONFIG_HOME")
} else {
os.Setenv("XDG_CONFIG_HOME", originalConfigDir)
}
}()
_, err = Load()
if err == nil {
t.Fatalf("Load() should have failed for legacy general.language")
}
if !errors.Is(err, ErrConfigNotFound) {
t.Errorf("Load() error = %v, expected ErrConfigNotFound", err)
}
})
t.Run("rejects legacy transcription.api_key", func(t *testing.T) {
tempDir := t.TempDir()
configPath := filepath.Join(tempDir, "hyprvoice", "config.toml")
@@ -456,17 +501,14 @@ timeout = "5m"
[transcription]
provider = "openai"
api_key = "test-key"
api_key = "sk-old-style-key"
model = "whisper-1"
[injection]
mode = "clipboard"
backends = ["clipboard"]
ydotool_timeout = "5s"
wtype_timeout = "5s"
clipboard_timeout = "3s"
[notifications]
enabled = true
type = "log"`
clipboard_timeout = "3s"`
err = os.WriteFile(configPath, []byte(legacyConfig), 0644)
if err != nil {
@@ -483,23 +525,16 @@ type = "log"`
}
}()
config, err := Load()
if err != nil {
t.Errorf("Load() error = %v", err)
return
_, err = Load()
if err == nil {
t.Fatalf("Load() should have failed for legacy transcription.api_key")
}
expectedBackends := []string{"clipboard"}
if len(config.Injection.Backends) != len(expectedBackends) {
t.Errorf("Expected %d backends, got %d", len(expectedBackends), len(config.Injection.Backends))
}
if err := config.Validate(); err != nil {
t.Errorf("Migrated config is invalid: %v", err)
if !errors.Is(err, ErrConfigNotFound) {
t.Errorf("Load() error = %v, expected ErrConfigNotFound", err)
}
})
t.Run("migrates legacy mode=type to backends", func(t *testing.T) {
t.Run("rejects legacy groq-translation provider", func(t *testing.T) {
tempDir := t.TempDir()
configPath := filepath.Join(tempDir, "hyprvoice", "config.toml")
@@ -517,18 +552,14 @@ channel_buffer_size = 30
timeout = "5m"
[transcription]
provider = "openai"
api_key = "test-key"
model = "whisper-1"
provider = "groq-translation"
model = "whisper-large-v3"
[injection]
mode = "type"
backends = ["clipboard"]
ydotool_timeout = "5s"
wtype_timeout = "5s"
clipboard_timeout = "3s"
[notifications]
enabled = true
type = "log"`
clipboard_timeout = "3s"`
err = os.WriteFile(configPath, []byte(legacyConfig), 0644)
if err != nil {
@@ -545,19 +576,12 @@ type = "log"`
}
}()
config, err := Load()
if err != nil {
t.Errorf("Load() error = %v", err)
return
_, err = Load()
if err == nil {
t.Fatalf("Load() should have failed for legacy groq-translation provider")
}
expectedBackends := []string{"wtype"}
if len(config.Injection.Backends) != len(expectedBackends) {
t.Errorf("Expected %d backends, got %d", len(expectedBackends), len(config.Injection.Backends))
}
if err := config.Validate(); err != nil {
t.Errorf("Migrated config is invalid: %v", err)
if !errors.Is(err, ErrConfigNotFound) {
t.Errorf("Load() error = %v, expected ErrConfigNotFound", err)
}
})
}
@@ -643,8 +667,8 @@ func TestConfig_ConversionMethods(t *testing.T) {
if transcriberConfig.Provider != config.Transcription.Provider {
t.Errorf("Provider mismatch: got %s, want %s", transcriberConfig.Provider, config.Transcription.Provider)
}
if transcriberConfig.APIKey != config.Transcription.APIKey {
t.Errorf("APIKey mismatch: got %s, want %s", transcriberConfig.APIKey, config.Transcription.APIKey)
if transcriberConfig.APIKey != config.Providers["openai"].APIKey {
t.Errorf("APIKey mismatch: got %s, want %s", transcriberConfig.APIKey, config.Providers["openai"].APIKey)
}
if transcriberConfig.Language != config.Transcription.Language {
t.Errorf("Language mismatch: got %s, want %s", transcriberConfig.Language, config.Transcription.Language)
@@ -777,7 +801,6 @@ func TestConfig_ToTranscriberConfig_WithEnvVar(t *testing.T) {
config := &Config{
Transcription: TranscriptionConfig{
Provider: "openai",
APIKey: "", // Empty API key to test env var fallback
Language: "en",
Model: "whisper-1",
},
@@ -805,10 +828,12 @@ func TestConfig_ToTranscriberConfig_WithoutEnvVar(t *testing.T) {
config := &Config{
Transcription: TranscriptionConfig{
Provider: "openai",
APIKey: "config-api-key", // Config has API key
Language: "en",
Model: "whisper-1",
},
Providers: map[string]ProviderConfig{
"openai": {APIKey: "config-api-key"},
},
}
// Ensure environment variable is not set
@@ -873,7 +898,6 @@ func TestConfig_Validate_OpenAI_WithoutAPIKey(t *testing.T) {
},
Transcription: TranscriptionConfig{
Provider: "openai",
APIKey: "", // No API key
Model: "whisper-1",
},
Injection: InjectionConfig{
@@ -913,7 +937,6 @@ func TestConfig_Validate_OpenAI_WithEnvVarAPIKey(t *testing.T) {
},
Transcription: TranscriptionConfig{
Provider: "openai",
APIKey: "", // No API key in config
Model: "whisper-1",
},
Injection: InjectionConfig{
@@ -955,9 +978,11 @@ func TestConfig_Validate_RecordingTimeout(t *testing.T) {
},
Transcription: TranscriptionConfig{
Provider: "openai",
APIKey: "test-key",
Model: "whisper-1",
},
Providers: map[string]ProviderConfig{
"openai": {APIKey: "test-key"},
},
Injection: InjectionConfig{
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
WtypeTimeout: time.Second,
@@ -986,9 +1011,11 @@ func TestConfig_Validate_InjectionTimeouts(t *testing.T) {
},
Transcription: TranscriptionConfig{
Provider: "openai",
APIKey: "test-key",
Model: "whisper-1",
},
Providers: map[string]ProviderConfig{
"openai": {APIKey: "test-key"},
},
Injection: InjectionConfig{
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
WtypeTimeout: 0, // Invalid timeout
@@ -1017,9 +1044,11 @@ func TestConfig_Validate_RecordingBufferSizes(t *testing.T) {
},
Transcription: TranscriptionConfig{
Provider: "openai",
APIKey: "test-key",
Model: "whisper-1",
},
Providers: map[string]ProviderConfig{
"openai": {APIKey: "test-key"},
},
Injection: InjectionConfig{
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
WtypeTimeout: time.Second,
@@ -1048,10 +1077,12 @@ func TestConfig_Validate_GroqTranscription(t *testing.T) {
},
Transcription: TranscriptionConfig{
Provider: "groq-transcription",
APIKey: "gsk-test-key",
Language: "en",
Model: "whisper-large-v3",
},
Providers: map[string]ProviderConfig{
"groq": {APIKey: "gsk-test-key"},
},
Injection: InjectionConfig{
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
WtypeTimeout: time.Second,
@@ -1080,10 +1111,12 @@ func TestConfig_Validate_GroqInvalidModel(t *testing.T) {
},
Transcription: TranscriptionConfig{
Provider: "groq-transcription",
APIKey: "gsk-test-key",
Language: "en",
Model: "invalid-model",
},
Providers: map[string]ProviderConfig{
"groq": {APIKey: "gsk-test-key"},
},
Injection: InjectionConfig{
Backends: []string{"ydotool", "wtype", "clipboard"}, YdotoolTimeout: 5 * time.Second,
WtypeTimeout: time.Second,
@@ -1112,7 +1145,6 @@ func TestConfig_Validate_GroqWithoutAPIKey(t *testing.T) {
},
Transcription: TranscriptionConfig{
Provider: "groq-transcription",
APIKey: "", // No API key
Model: "whisper-large-v3",
},
Injection: InjectionConfig{
@@ -1152,7 +1184,6 @@ func TestConfig_Validate_GroqWithEnvVarAPIKey(t *testing.T) {
},
Transcription: TranscriptionConfig{
Provider: "groq-transcription",
APIKey: "", // No API key in config
Model: "whisper-large-v3",
},
Injection: InjectionConfig{
@@ -1186,7 +1217,6 @@ func TestConfig_ToTranscriberConfig_GroqWithEnvVar(t *testing.T) {
config := &Config{
Transcription: TranscriptionConfig{
Provider: "groq-transcription",
APIKey: "", // Empty API key to test env var fallback
Language: "en",
Model: "whisper-large-v3",
},
@@ -1300,38 +1330,6 @@ func TestConfig_ProvidersMap(t *testing.T) {
}
}
func TestConfig_ProvidersMapFallbackToLegacy(t *testing.T) {
config := &Config{
Recording: RecordingConfig{
SampleRate: 16000,
Channels: 1,
Format: "s16",
BufferSize: 8192,
ChannelBufferSize: 30,
Timeout: time.Minute,
},
Transcription: TranscriptionConfig{
Provider: "openai",
APIKey: "sk-legacy-key", // Legacy field
Model: "whisper-1",
},
Providers: map[string]ProviderConfig{}, // Empty providers map
Injection: InjectionConfig{
Backends: []string{"clipboard"},
YdotoolTimeout: 5 * time.Second,
WtypeTimeout: 5 * time.Second,
ClipboardTimeout: 3 * time.Second,
},
Notifications: NotificationsConfig{Type: "log"},
}
// Should fall back to legacy transcription.api_key
transcriberConfig := config.ToTranscriberConfig()
if transcriberConfig.APIKey != "sk-legacy-key" {
t.Errorf("Expected APIKey from legacy field, got %s", transcriberConfig.APIKey)
}
}
func TestConfig_LLMConfig(t *testing.T) {
config := &Config{
Recording: RecordingConfig{
@@ -1507,79 +1505,6 @@ func TestConfig_LLMValidation(t *testing.T) {
})
}
func TestConfig_MigrateTranscriptionAPIKey(t *testing.T) {
tempDir := t.TempDir()
configPath := filepath.Join(tempDir, "hyprvoice", "config.toml")
err := os.MkdirAll(filepath.Dir(configPath), 0755)
if err != nil {
t.Fatalf("Failed to create config directory: %v", err)
}
// Old-style config with api_key in transcription
oldConfig := `[recording]
sample_rate = 16000
channels = 1
format = "s16"
buffer_size = 8192
channel_buffer_size = 30
timeout = "5m"
[transcription]
provider = "openai"
api_key = "sk-old-style-key"
model = "whisper-1"
[injection]
backends = ["clipboard"]
ydotool_timeout = "5s"
wtype_timeout = "5s"
clipboard_timeout = "3s"
[notifications]
type = "log"`
err = os.WriteFile(configPath, []byte(oldConfig), 0644)
if err != nil {
t.Fatalf("Failed to create config file: %v", err)
}
originalConfigDir := os.Getenv("XDG_CONFIG_HOME")
os.Setenv("XDG_CONFIG_HOME", tempDir)
defer func() {
if originalConfigDir == "" {
os.Unsetenv("XDG_CONFIG_HOME")
} else {
os.Setenv("XDG_CONFIG_HOME", originalConfigDir)
}
}()
config, err := Load()
if err != nil {
t.Errorf("Load() error = %v", err)
return
}
// Should have migrated to providers map
if config.Providers == nil {
t.Fatal("Providers map should not be nil after migration")
}
if config.Providers["openai"].APIKey != "sk-old-style-key" {
t.Errorf("Expected migrated API key in providers.openai, got %s", config.Providers["openai"].APIKey)
}
// Validation should pass
if err := config.Validate(); err != nil {
t.Errorf("Validate() should pass after migration: %v", err)
}
// ToTranscriberConfig should resolve correctly
transcriberConfig := config.ToTranscriberConfig()
if transcriberConfig.APIKey != "sk-old-style-key" {
t.Errorf("Expected APIKey 'sk-old-style-key', got %s", transcriberConfig.APIKey)
}
}
func TestConfig_NewStyleConfig(t *testing.T) {
tempDir := t.TempDir()
configPath := filepath.Join(tempDir, "hyprvoice", "config.toml")
@@ -1956,9 +1881,11 @@ func TestConfig_Validate_TranscriptionLanguage(t *testing.T) {
},
Transcription: TranscriptionConfig{
Provider: "openai",
APIKey: "test-key",
Model: "whisper-1",
},
Providers: map[string]ProviderConfig{
"openai": {APIKey: "test-key"},
},
Injection: InjectionConfig{
Backends: []string{"clipboard"},
YdotoolTimeout: 5 * time.Second,
+1 -5
View File
@@ -41,7 +41,7 @@ func (c *Config) resolveEffectiveLanguage() string {
return c.Transcription.Language
}
// resolveAPIKeyForProvider returns the API key for a provider from multiple sources
// resolveAPIKeyForProvider returns the API key for a provider from config or env
func (c *Config) resolveAPIKeyForProvider(providerName string) string {
baseName := provider.BaseProviderName(providerName)
envVar := provider.EnvVarForProvider(providerName)
@@ -52,10 +52,6 @@ func (c *Config) resolveAPIKeyForProvider(providerName string) string {
}
}
if c.Transcription.APIKey != "" {
return c.Transcription.APIKey
}
if envVar != "" {
return os.Getenv(envVar)
}
+21 -85
View File
@@ -7,7 +7,6 @@ import (
"os"
"path/filepath"
"runtime"
"time"
"github.com/BurntSushi/toml"
)
@@ -28,21 +27,6 @@ func GetConfigPath() (string, error) {
return filepath.Join(hyprvoiceDir, "config.toml"), nil
}
// legacyInjectionConfig for migration from old mode-based config
type legacyInjectionConfig struct {
Mode string `toml:"mode"`
}
// legacyTranscriptionConfig for migration from old api_key in transcription
type legacyTranscriptionConfig struct {
APIKey string `toml:"api_key"`
}
type legacyConfig struct {
Injection legacyInjectionConfig `toml:"injection"`
Transcription legacyTranscriptionConfig `toml:"transcription"`
}
func Load() (*Config, error) {
configPath, err := GetConfigPath()
if err != nil {
@@ -57,30 +41,19 @@ func Load() (*Config, error) {
log.Printf("Config: loading configuration from %s", configPath)
var config Config
if _, err := toml.DecodeFile(configPath, &config); err != nil {
meta, err := toml.DecodeFile(configPath, &config)
if err != nil {
return nil, fmt.Errorf("failed to parse config file %s: %w", configPath, err)
}
var legacy legacyConfig
toml.DecodeFile(configPath, &legacy)
if len(config.Injection.Backends) == 0 {
config.migrateInjectionMode(legacy.Injection.Mode)
}
if legacy.Transcription.APIKey != "" && config.Providers == nil {
config.migrateTranscriptionAPIKey(legacy.Transcription.APIKey)
if isLegacyConfig(meta, &config) {
log.Printf("Config: legacy configuration detected - run hyprvoice onboarding")
return nil, fmt.Errorf("%w: run hyprvoice onboarding", ErrConfigNotFound)
}
if config.Providers == nil {
config.Providers = make(map[string]ProviderConfig)
}
if config.Transcription.Provider == "groq-translation" {
log.Printf("Config: deprecated transcription.provider 'groq-translation' detected - using 'groq-transcription' instead")
config.Transcription.Provider = "groq-transcription"
}
config.applyLLMDefaults()
config.applyThreadsDefault()
@@ -88,6 +61,22 @@ func Load() (*Config, error) {
return &config, nil
}
func isLegacyConfig(meta toml.MetaData, config *Config) bool {
if meta.IsDefined("transcription", "api_key") {
return true
}
if meta.IsDefined("injection", "mode") {
return true
}
if meta.IsDefined("general", "language") {
return true
}
if config.Transcription.Provider == "groq-translation" {
return true
}
return false
}
// applyThreadsDefault sets default threads for local transcription if not explicitly set
func (c *Config) applyThreadsDefault() {
if c.Transcription.Threads == 0 {
@@ -99,33 +88,6 @@ func (c *Config) applyThreadsDefault() {
}
}
// migrateTranscriptionAPIKey migrates old transcription.api_key to providers map
func (c *Config) migrateTranscriptionAPIKey(apiKey string) {
if c.Providers == nil {
c.Providers = make(map[string]ProviderConfig)
}
providerName := c.Transcription.Provider
switch providerName {
case "openai":
c.Providers["openai"] = ProviderConfig{APIKey: apiKey}
case "groq-transcription":
c.Providers["groq"] = ProviderConfig{APIKey: apiKey}
case "mistral-transcription":
c.Providers["mistral"] = ProviderConfig{APIKey: apiKey}
case "elevenlabs":
c.Providers["elevenlabs"] = ProviderConfig{APIKey: apiKey}
default:
if len(apiKey) > 3 && apiKey[:3] == "sk-" {
c.Providers["openai"] = ProviderConfig{APIKey: apiKey}
} else if len(apiKey) > 4 && apiKey[:4] == "gsk_" {
c.Providers["groq"] = ProviderConfig{APIKey: apiKey}
}
}
log.Printf("Config: migrated transcription.api_key to providers map. Run 'hyprvoice configure' to update config format.")
}
// applyLLMDefaults sets default values for LLM config
func (c *Config) applyLLMDefaults() {
pp := &c.LLM.PostProcessing
@@ -136,29 +98,3 @@ func (c *Config) applyLLMDefaults() {
pp.RemoveFillerWords = true
}
}
// migrateInjectionMode converts old mode field to new backends array
func (c *Config) migrateInjectionMode(mode string) {
switch mode {
case "clipboard":
c.Injection.Backends = []string{"clipboard"}
log.Printf("Config: migrated injection.mode='clipboard' to backends=['clipboard']")
case "type":
c.Injection.Backends = []string{"wtype"}
log.Printf("Config: migrated injection.mode='type' to backends=['wtype']")
case "fallback":
c.Injection.Backends = []string{"wtype", "clipboard"}
log.Printf("Config: migrated injection.mode='fallback' to backends=['wtype', 'clipboard']")
default:
c.Injection.Backends = []string{"ydotool", "wtype", "clipboard"}
if mode != "" {
log.Printf("Config: unknown injection.mode='%s', using default backends", mode)
}
}
if c.Injection.YdotoolTimeout == 0 {
c.Injection.YdotoolTimeout = 5 * time.Second
}
log.Printf("Config: legacy 'mode' config detected - please update your config.toml to use 'backends' instead")
}
-5
View File
@@ -198,11 +198,6 @@ func SaveDefaultConfig() error {
configContent := `# Hyprvoice Configuration
# This file is automatically generated with defaults.
# Edit values as needed - changes are applied immediately without daemon restart.
#
# MIGRATION NOTE: If upgrading from an older version, your transcription.api_key
# will be automatically migrated to the new [providers.X] format. Run 'hyprvoice configure'
# to update your config file structure.
# Keywords help both transcription and LLM understand domain-specific terms
# Add names, technical terms, or brand names that might be misheard
keywords = []
-1
View File
@@ -63,7 +63,6 @@ type RecordingConfig struct {
type TranscriptionConfig struct {
Provider string `toml:"provider"`
APIKey string `toml:"api_key"`
Language string `toml:"language"`
Model string `toml:"model"`
Streaming bool `toml:"streaming"` // use streaming mode if model supports it
+1 -1
View File
@@ -78,7 +78,7 @@ func (c *Config) Validate() error {
apiKey := c.resolveAPIKeyForProvider(c.Transcription.Provider)
if apiKey == "" {
envVar := envVarForProvider(registryName)
return fmt.Errorf("%s API key required: not found in config (providers.%s.api_key, transcription.api_key) or environment variable (%s)",
return fmt.Errorf("%s API key required: not found in config (providers.%s.api_key) or environment variable (%s)",
strings.Title(registryName), registryName, envVar)
}
}