feat: refactor
This commit is contained in:
@@ -3,8 +3,193 @@ package config
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Save writes the config to the config file with formatted TOML output
|
||||
func Save(cfg *Config) error {
|
||||
configPath, err := GetConfigPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file, err := os.Create(configPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create config file: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var sb strings.Builder
|
||||
|
||||
// Header
|
||||
sb.WriteString(`# Hyprvoice Configuration
|
||||
# Generated by hyprvoice configure
|
||||
# Changes are applied immediately without daemon restart.
|
||||
|
||||
`)
|
||||
|
||||
// Keywords (must be before any table definitions in TOML)
|
||||
if len(cfg.Keywords) > 0 {
|
||||
sb.WriteString("# Keywords help transcription and LLM spell names/terms correctly\n")
|
||||
sb.WriteString("keywords = [")
|
||||
for i, kw := range cfg.Keywords {
|
||||
if i > 0 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
sb.WriteString(fmt.Sprintf("%q", kw))
|
||||
}
|
||||
sb.WriteString("]\n\n")
|
||||
}
|
||||
|
||||
// General section
|
||||
sb.WriteString(`# General Settings
|
||||
[general]
|
||||
`)
|
||||
sb.WriteString(fmt.Sprintf(" language = %q\n", cfg.General.Language))
|
||||
sb.WriteString("\n")
|
||||
|
||||
// Providers section
|
||||
if len(cfg.Providers) > 0 {
|
||||
sb.WriteString("# API Keys for providers\n")
|
||||
for name, pc := range cfg.Providers {
|
||||
sb.WriteString(fmt.Sprintf("[providers.%s]\n", name))
|
||||
sb.WriteString(fmt.Sprintf(" api_key = %q\n", pc.APIKey))
|
||||
sb.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
// Recording
|
||||
sb.WriteString(`# Audio Recording Configuration
|
||||
[recording]
|
||||
`)
|
||||
sb.WriteString(fmt.Sprintf(" sample_rate = %d\n", cfg.Recording.SampleRate))
|
||||
sb.WriteString(fmt.Sprintf(" channels = %d\n", cfg.Recording.Channels))
|
||||
sb.WriteString(fmt.Sprintf(" format = %q\n", cfg.Recording.Format))
|
||||
sb.WriteString(fmt.Sprintf(" buffer_size = %d\n", cfg.Recording.BufferSize))
|
||||
sb.WriteString(fmt.Sprintf(" device = %q\n", cfg.Recording.Device))
|
||||
sb.WriteString(fmt.Sprintf(" channel_buffer_size = %d\n", cfg.Recording.ChannelBufferSize))
|
||||
sb.WriteString(fmt.Sprintf(" timeout = %q\n", cfg.Recording.Timeout.String()))
|
||||
sb.WriteString("\n")
|
||||
|
||||
// Transcription
|
||||
sb.WriteString(`# Speech Transcription Configuration
|
||||
[transcription]
|
||||
`)
|
||||
sb.WriteString(fmt.Sprintf(" provider = %q\n", cfg.Transcription.Provider))
|
||||
sb.WriteString(fmt.Sprintf(" language = %q\n", cfg.Transcription.Language))
|
||||
sb.WriteString(fmt.Sprintf(" model = %q\n", cfg.Transcription.Model))
|
||||
sb.WriteString(fmt.Sprintf(" streaming = %v\n", cfg.Transcription.Streaming))
|
||||
sb.WriteString(fmt.Sprintf(" threads = %d\n", cfg.Transcription.Threads))
|
||||
sb.WriteString("\n")
|
||||
|
||||
// LLM
|
||||
sb.WriteString(`# LLM Post-Processing Configuration
|
||||
[llm]
|
||||
`)
|
||||
sb.WriteString(fmt.Sprintf(" enabled = %v\n", cfg.LLM.Enabled))
|
||||
if cfg.LLM.Provider != "" {
|
||||
sb.WriteString(fmt.Sprintf(" provider = %q\n", cfg.LLM.Provider))
|
||||
}
|
||||
if cfg.LLM.Model != "" {
|
||||
sb.WriteString(fmt.Sprintf(" model = %q\n", cfg.LLM.Model))
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
|
||||
sb.WriteString(" [llm.post_processing]\n")
|
||||
sb.WriteString(fmt.Sprintf(" remove_stutters = %v\n", cfg.LLM.PostProcessing.RemoveStutters))
|
||||
sb.WriteString(fmt.Sprintf(" add_punctuation = %v\n", cfg.LLM.PostProcessing.AddPunctuation))
|
||||
sb.WriteString(fmt.Sprintf(" fix_grammar = %v\n", cfg.LLM.PostProcessing.FixGrammar))
|
||||
sb.WriteString(fmt.Sprintf(" remove_filler_words = %v\n", cfg.LLM.PostProcessing.RemoveFillerWords))
|
||||
sb.WriteString("\n")
|
||||
|
||||
sb.WriteString(" [llm.custom_prompt]\n")
|
||||
sb.WriteString(fmt.Sprintf(" enabled = %v\n", cfg.LLM.CustomPrompt.Enabled))
|
||||
if cfg.LLM.CustomPrompt.Prompt != "" {
|
||||
sb.WriteString(fmt.Sprintf(" prompt = %q\n", cfg.LLM.CustomPrompt.Prompt))
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
|
||||
// Injection
|
||||
sb.WriteString(`# Text Injection Configuration
|
||||
[injection]
|
||||
`)
|
||||
sb.WriteString(" backends = [")
|
||||
for i, b := range cfg.Injection.Backends {
|
||||
if i > 0 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
sb.WriteString(fmt.Sprintf("%q", b))
|
||||
}
|
||||
sb.WriteString("]\n")
|
||||
sb.WriteString(fmt.Sprintf(" ydotool_timeout = %q\n", cfg.Injection.YdotoolTimeout.String()))
|
||||
sb.WriteString(fmt.Sprintf(" wtype_timeout = %q\n", cfg.Injection.WtypeTimeout.String()))
|
||||
sb.WriteString(fmt.Sprintf(" clipboard_timeout = %q\n", cfg.Injection.ClipboardTimeout.String()))
|
||||
sb.WriteString("\n")
|
||||
|
||||
// Notifications
|
||||
sb.WriteString(`# Desktop Notification Configuration
|
||||
[notifications]
|
||||
`)
|
||||
sb.WriteString(fmt.Sprintf(" enabled = %v\n", cfg.Notifications.Enabled))
|
||||
sb.WriteString(fmt.Sprintf(" type = %q\n", cfg.Notifications.Type))
|
||||
|
||||
// Write custom messages if any
|
||||
msgs := cfg.Notifications.Messages
|
||||
if hasCustomMessages(msgs) {
|
||||
sb.WriteString("\n [notifications.messages]\n")
|
||||
if msgs.RecordingStarted.Title != "" || msgs.RecordingStarted.Body != "" {
|
||||
sb.WriteString(" [notifications.messages.recording_started]\n")
|
||||
sb.WriteString(fmt.Sprintf(" title = %q\n", msgs.RecordingStarted.Title))
|
||||
sb.WriteString(fmt.Sprintf(" body = %q\n", msgs.RecordingStarted.Body))
|
||||
}
|
||||
if msgs.Transcribing.Title != "" || msgs.Transcribing.Body != "" {
|
||||
sb.WriteString(" [notifications.messages.transcribing]\n")
|
||||
sb.WriteString(fmt.Sprintf(" title = %q\n", msgs.Transcribing.Title))
|
||||
sb.WriteString(fmt.Sprintf(" body = %q\n", msgs.Transcribing.Body))
|
||||
}
|
||||
if msgs.LLMProcessing.Title != "" || msgs.LLMProcessing.Body != "" {
|
||||
sb.WriteString(" [notifications.messages.llm_processing]\n")
|
||||
sb.WriteString(fmt.Sprintf(" title = %q\n", msgs.LLMProcessing.Title))
|
||||
sb.WriteString(fmt.Sprintf(" body = %q\n", msgs.LLMProcessing.Body))
|
||||
}
|
||||
if msgs.ConfigReloaded.Title != "" || msgs.ConfigReloaded.Body != "" {
|
||||
sb.WriteString(" [notifications.messages.config_reloaded]\n")
|
||||
sb.WriteString(fmt.Sprintf(" title = %q\n", msgs.ConfigReloaded.Title))
|
||||
sb.WriteString(fmt.Sprintf(" body = %q\n", msgs.ConfigReloaded.Body))
|
||||
}
|
||||
if msgs.OperationCancelled.Title != "" || msgs.OperationCancelled.Body != "" {
|
||||
sb.WriteString(" [notifications.messages.operation_cancelled]\n")
|
||||
sb.WriteString(fmt.Sprintf(" title = %q\n", msgs.OperationCancelled.Title))
|
||||
sb.WriteString(fmt.Sprintf(" body = %q\n", msgs.OperationCancelled.Body))
|
||||
}
|
||||
if msgs.RecordingAborted.Body != "" {
|
||||
sb.WriteString(" [notifications.messages.recording_aborted]\n")
|
||||
sb.WriteString(fmt.Sprintf(" body = %q\n", msgs.RecordingAborted.Body))
|
||||
}
|
||||
if msgs.InjectionAborted.Body != "" {
|
||||
sb.WriteString(" [notifications.messages.injection_aborted]\n")
|
||||
sb.WriteString(fmt.Sprintf(" body = %q\n", msgs.InjectionAborted.Body))
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := file.WriteString(sb.String()); err != nil {
|
||||
return fmt.Errorf("failed to write config content: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func hasCustomMessages(msgs MessagesConfig) bool {
|
||||
return msgs.RecordingStarted.Title != "" || msgs.RecordingStarted.Body != "" ||
|
||||
msgs.Transcribing.Title != "" || msgs.Transcribing.Body != "" ||
|
||||
msgs.LLMProcessing.Title != "" || msgs.LLMProcessing.Body != "" ||
|
||||
msgs.ConfigReloaded.Title != "" || msgs.ConfigReloaded.Body != "" ||
|
||||
msgs.OperationCancelled.Title != "" || msgs.OperationCancelled.Body != "" ||
|
||||
msgs.RecordingAborted.Body != "" ||
|
||||
msgs.InjectionAborted.Body != ""
|
||||
}
|
||||
|
||||
// SaveDefaultConfig writes the default config template to the config file
|
||||
func SaveDefaultConfig() error {
|
||||
configPath, err := GetConfigPath()
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user