feat: new readme
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
@@ -261,41 +262,34 @@ func TestConfig_Validate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConfig_Load(t *testing.T) {
|
||||
// Test that Load creates default config when none exists
|
||||
t.Run("creates default config when none exists", func(t *testing.T) {
|
||||
// Test that Load errors when no config exists
|
||||
t.Run("errors when config missing", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
originalConfigDir := os.Getenv("XDG_CONFIG_HOME")
|
||||
originalAPIKey := os.Getenv("OPENAI_API_KEY")
|
||||
os.Setenv("XDG_CONFIG_HOME", tempDir)
|
||||
os.Setenv("OPENAI_API_KEY", "test-api-key") // Set test API key for validation
|
||||
defer func() {
|
||||
if originalConfigDir == "" {
|
||||
os.Unsetenv("XDG_CONFIG_HOME")
|
||||
} else {
|
||||
os.Setenv("XDG_CONFIG_HOME", originalConfigDir)
|
||||
}
|
||||
if originalAPIKey == "" {
|
||||
os.Unsetenv("OPENAI_API_KEY")
|
||||
} else {
|
||||
os.Setenv("OPENAI_API_KEY", originalAPIKey)
|
||||
}
|
||||
}()
|
||||
|
||||
config, err := Load()
|
||||
if err != nil {
|
||||
t.Errorf("Load() error = %v", err)
|
||||
_, err := Load()
|
||||
if err == nil {
|
||||
t.Errorf("Load() expected error when config is missing")
|
||||
return
|
||||
}
|
||||
|
||||
// Verify the loaded config is valid
|
||||
if err := config.Validate(); err != nil {
|
||||
t.Errorf("Loaded config is invalid: %v", err)
|
||||
if !errors.Is(err, ErrConfigNotFound) {
|
||||
t.Errorf("Load() error = %v, expected ErrConfigNotFound", err)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "hyprvoice onboarding") {
|
||||
t.Errorf("Load() error should mention onboarding: %v", err)
|
||||
}
|
||||
|
||||
// Verify config file was created
|
||||
configPath := filepath.Join(tempDir, "hyprvoice", "config.toml")
|
||||
if _, err := os.Stat(configPath); os.IsNotExist(err) {
|
||||
t.Errorf("Load() did not create config file")
|
||||
if _, statErr := os.Stat(configPath); !os.IsNotExist(statErr) {
|
||||
t.Errorf("Load() should not create config file when missing")
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package config
|
||||
|
||||
import "time"
|
||||
|
||||
// DefaultConfig returns the initial configuration used for onboarding.
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
Recording: RecordingConfig{
|
||||
SampleRate: 16000,
|
||||
Channels: 1,
|
||||
Format: "s16",
|
||||
BufferSize: 8192,
|
||||
Device: "",
|
||||
ChannelBufferSize: 30,
|
||||
Timeout: 5 * time.Minute,
|
||||
},
|
||||
Transcription: TranscriptionConfig{
|
||||
Language: "",
|
||||
Streaming: false,
|
||||
Threads: 0,
|
||||
},
|
||||
Injection: InjectionConfig{
|
||||
Backends: []string{"ydotool", "wtype", "clipboard"},
|
||||
YdotoolTimeout: 5 * time.Second,
|
||||
WtypeTimeout: 5 * time.Second,
|
||||
ClipboardTimeout: 3 * time.Second,
|
||||
},
|
||||
Notifications: NotificationsConfig{
|
||||
Enabled: false,
|
||||
Type: "",
|
||||
},
|
||||
Providers: make(map[string]ProviderConfig),
|
||||
Keywords: nil,
|
||||
LLM: LLMConfig{
|
||||
Enabled: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
+11
-6
@@ -1,6 +1,7 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
@@ -11,6 +12,8 @@ import (
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
|
||||
var ErrConfigNotFound = errors.New("config not found")
|
||||
|
||||
func GetConfigPath() (string, error) {
|
||||
configDir, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
@@ -47,12 +50,9 @@ func Load() (*Config, error) {
|
||||
}
|
||||
|
||||
if _, err := os.Stat(configPath); os.IsNotExist(err) {
|
||||
log.Printf("Config: no config file found at %s, creating with defaults", configPath)
|
||||
if err := SaveDefaultConfig(); err != nil {
|
||||
return nil, fmt.Errorf("failed to create default config: %w", err)
|
||||
}
|
||||
log.Printf("Config: default configuration created successfully")
|
||||
return Load()
|
||||
return nil, fmt.Errorf("%w: run hyprvoice onboarding", ErrConfigNotFound)
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("failed to stat config file %s: %w", configPath, err)
|
||||
}
|
||||
|
||||
log.Printf("Config: loading configuration from %s", configPath)
|
||||
@@ -76,6 +76,11 @@ func Load() (*Config, error) {
|
||||
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()
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ func Save(cfg *Config) error {
|
||||
|
||||
// Header
|
||||
sb.WriteString(`# Hyprvoice Configuration
|
||||
# Generated by hyprvoice configure
|
||||
# Generated by hyprvoice onboarding or configure
|
||||
# Changes are applied immediately without daemon restart.
|
||||
|
||||
`)
|
||||
|
||||
Reference in New Issue
Block a user