From de3ab8ae368326af19158b42ddb8d0faf9c530fb Mon Sep 17 00:00:00 2001 From: rainu Date: Fri, 3 Jan 2025 16:03:11 +0100 Subject: [PATCH] implement possibility to read configuration from yaml files --- README.md | 1 + config/config_test.go | 12 +- config/default.go | 4 +- config/expression.go | 4 +- config/general.go | 10 +- config/help.go | 18 +++ config/llm/anthropic.go | 6 +- config/llm/anythingllm.go | 6 +- config/llm/calloptions.go | 14 +-- config/llm/general.go | 16 +-- config/llm/localai.go | 13 +- config/llm/mistral.go | 13 +- config/llm/ollama.go | 10 +- config/llm/openai.go | 22 +--- config/parser.go | 49 +++++--- config/parser_yaml.go | 67 +++++++++++ config/parser_yaml_test.go | 220 ++++++++++++++++++++++++++++++++++ config/print.go | 8 +- config/shortcut.go | 10 +- config/ui_dialog.go | 14 +-- config/ui_general.go | 16 +-- config/ui_prompt.go | 10 +- config/ui_window.go | 32 ++--- controller/dialog.go | 2 +- frontend/wailsjs/go/models.ts | 6 +- go.mod | 2 +- 26 files changed, 439 insertions(+), 146 deletions(-) create mode 100644 config/parser_yaml.go create mode 100644 config/parser_yaml_test.go diff --git a/README.md b/README.md index 261e377..5b0c190 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ https://github.com/user-attachments/assets/a6d16332-55a1-4866-9f3e-31490a488935 * [Anthropic](https://www.anthropic.com/) * Scriptable * All settings can be set via: + * yaml configuration file * environment variables * command line arguments * The users questions and models answers will be printed out in the terminal diff --git a/config/config_test.go b/config/config_test.go index 1ab484c..7ec74e5 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -113,7 +113,7 @@ func TestConfig_Parse(t *testing.T) { name: "Set UI file dialog resolves aliases", args: []string{"--ui-file-dialog-resolves-aliases=true"}, expected: modifiedConfig(func(c *Config) { - c.UI.FileDialog.ResolvesAliases = true + c.UI.FileDialog.ResolveAliases = true }), }, { @@ -257,8 +257,8 @@ func TestConfig_Parse(t *testing.T) { { name: "Set UI quit shortcut", args: []string{ - "--ui-quit-shortcut-key", "q", - "--ui-quit-shortcut-ctrl", + "--ui-quit-key", "q", + "--ui-quit-ctrl", }, expected: modifiedConfig(func(c *Config) { c.UI.QuitShortcut = Shortcut{Code: "q", Ctrl: true} @@ -435,7 +435,7 @@ func TestConfig_Parse(t *testing.T) { name: "Set environment variable for UI file dialog resolves aliases", env: []string{EnvironmentPrefix + "UI_FILE_DIALOG_RESOLVES_ALIASES=true"}, expected: modifiedConfig(func(c *Config) { - c.UI.FileDialog.ResolvesAliases = true + c.UI.FileDialog.ResolveAliases = true }), }, { @@ -544,8 +544,8 @@ func TestConfig_Parse(t *testing.T) { { name: "Set environment variable for UI quit shortcut", env: []string{ - EnvironmentPrefix + "UI_QUIT_SHORTCUT_KEY=q", - EnvironmentPrefix + "UI_QUIT_SHORTCUT_CTRL=true", + EnvironmentPrefix + "UI_QUIT_KEY=q", + EnvironmentPrefix + "UI_QUIT_CTRL=true", }, expected: modifiedConfig(func(c *Config) { c.UI.QuitShortcut = Shortcut{Code: "q", Ctrl: true} diff --git a/config/default.go b/config/default.go index 7cb504b..606c8b6 100644 --- a/config/default.go +++ b/config/default.go @@ -33,7 +33,7 @@ func defaultConfig() *Config { }, FileDialog: FileDialogConfig{ ShowHiddenFiles: true, - ResolvesAliases: true, + ResolveAliases: true, TreatPackagesAsDirectories: true, FilterDisplay: []string{}, FilterPattern: []string{}, @@ -60,7 +60,7 @@ func defaultConfig() *Config { Printer: PrinterConfig{ Format: PrinterFormatJSON, Targets: []io.WriteCloser{os.Stdout}, - TargetsRaw: PrinterTargetOut, + TargetsRaw: []string{PrinterTargetOut}, }, } } diff --git a/config/expression.go b/config/expression.go index 0e5b5f1..c1656c4 100644 --- a/config/expression.go +++ b/config/expression.go @@ -9,8 +9,8 @@ import ( ) type ExpressionContainer struct { - Expression string `config:""` - Value float64 `config:"-"` + Expression string `config:"" yaml:"expression"` + Value float64 `config:"-" yaml:"value"` } type Expression string diff --git a/config/general.go b/config/general.go index 6fad8d7..ce6833d 100644 --- a/config/general.go +++ b/config/general.go @@ -7,14 +7,14 @@ import ( ) type Config struct { - UI UIConfig `config:"ui"` + UI UIConfig `yaml:"ui"` - LLM llm.LLMConfig `config:""` + LLM llm.LLMConfig `config:"" yaml:"llm"` - Printer PrinterConfig `config:"print"` + Printer PrinterConfig `yaml:"print"` - LogLevel int `config:"log-level"` - PrintVersion bool `config:"version" short:"v" usage:"Show the version"` + LogLevel int `yaml:"log-level"` + PrintVersion bool `config:"version" yaml:"-" short:"v" usage:"Show the version"` } func (c *Config) GetUsage(field string) string { diff --git a/config/help.go b/config/help.go index 097e4aa..7573a3b 100644 --- a/config/help.go +++ b/config/help.go @@ -63,6 +63,24 @@ func printUsage(output io.Writer, fields resolvedFieldInfos) { fmt.Fprintf(output, " %s%s\t%s\n", env, strings.Repeat(" ", maxLen-len(env)), field.Usage) } + sort.Slice(fields, func(i, j int) bool { + return strings.Join(fields[i].YamlPath, "") < strings.Join(fields[j].YamlPath, "") + }) + + fmt.Fprintf(output, "\nYaml keys:\n") + for _, field := range fields { + yamlKey := strings.TrimLeft(strings.Join(field.YamlPath, "."), ".") + if strings.HasSuffix(yamlKey, "-") { + continue + } + fmt.Fprintf(output, " %s%s\t%s\n", yamlKey, strings.Repeat(" ", maxLen-len(yamlKey)), field.Usage) + } + + fmt.Fprintf(output, "\nYaml lookup file locations:\n") + for _, location := range yamlLookupLocations() { + fmt.Fprintf(output, " - %s\n", location) + } + fmt.Fprintf(output, "\nAvailable code styles:\n") for _, style := range availableCodeStyles { fmt.Fprintf(output, " - %s\n", style) diff --git a/config/llm/anthropic.go b/config/llm/anthropic.go index 298acf0..88ad72d 100644 --- a/config/llm/anthropic.go +++ b/config/llm/anthropic.go @@ -6,9 +6,9 @@ import ( ) type AnthropicConfig struct { - Token string `config:"api-key" usage:"API Key"` - BaseUrl string `config:"base-url" usage:"BaseUrl"` - Model string `config:"model" usage:"Model"` + Token string `yaml:"api-key" usage:"API Key"` + BaseUrl string `yaml:"base-url" usage:"BaseUrl"` + Model string `yaml:"model" usage:"Model"` } func (c *AnthropicConfig) AsOptions() (opts []anthropic.Option) { diff --git a/config/llm/anythingllm.go b/config/llm/anythingllm.go index da5c429..0fe7b7c 100644 --- a/config/llm/anythingllm.go +++ b/config/llm/anythingllm.go @@ -5,9 +5,9 @@ import ( ) type AnythingLLMConfig struct { - BaseURL string `config:"base-url" usage:"Base URL"` - Token string `config:"token" usage:"Token"` - Workspace string `config:"workspace" usage:"Workspace"` + BaseURL string `yaml:"base-url" usage:"Base URL"` + Token string `yaml:"token" usage:"Token"` + Workspace string `yaml:"workspace" usage:"Workspace"` } func (c *AnythingLLMConfig) Validate() error { diff --git a/config/llm/calloptions.go b/config/llm/calloptions.go index a0d7193..63c4d28 100644 --- a/config/llm/calloptions.go +++ b/config/llm/calloptions.go @@ -6,13 +6,13 @@ import ( ) type CallOptionsConfig struct { - SystemPrompt string `config:"system-prompt" short:"S" usage:"System Prompt"` - MaxToken int `config:"max-token" usage:"Max Token"` - Temperature float64 `config:"temperature" usage:"Temperature"` - TopK int `config:"top-k" usage:"Top-K"` - TopP float64 `config:"top-p" usage:"Top-P"` - MinLength int `config:"min-length" usage:"Min Length"` - MaxLength int `config:"max-length" usage:"Max Length"` + SystemPrompt string `yaml:"system-prompt" short:"S" usage:"System Prompt"` + MaxToken int `yaml:"max-token" usage:"Max Token"` + Temperature float64 `yaml:"temperature" usage:"Temperature"` + TopK int `yaml:"top-k" usage:"Top-K"` + TopP float64 `yaml:"top-p" usage:"Top-P"` + MinLength int `yaml:"min-length" usage:"Min Length"` + MaxLength int `yaml:"max-length" usage:"Max Length"` } func (c *CallOptionsConfig) AsOptions() (opts []llms.CallOption) { diff --git a/config/llm/general.go b/config/llm/general.go index 0a7cc9d..847b839 100644 --- a/config/llm/general.go +++ b/config/llm/general.go @@ -16,15 +16,15 @@ const ( ) type LLMConfig struct { - Backend string `config:"backend" short:"b"` + Backend string `yaml:"backend" short:"b"` - LocalAI LocalAIConfig `config:"localai" usage:"LocalAI: "` - OpenAI OpenAIConfig `config:"openai" usage:"OpenAI: "` - AnythingLLM AnythingLLMConfig `config:"anythingllm" usage:"AnythingLLM: "` - Ollama OllamaConfig `config:"ollama" usage:"Ollama: "` - Mistral MistralConfig `config:"mistral" usage:"Mistral: "` - Anthropic AnthropicConfig `config:"anthropic" usage:"Anthropic: "` - CallOptions CallOptionsConfig `config:"call" usage:"LLM-CALL: "` + LocalAI LocalAIConfig `yaml:"localai" usage:"LocalAI: "` + OpenAI OpenAIConfig `yaml:"openai" usage:"OpenAI: "` + AnythingLLM AnythingLLMConfig `yaml:"anythingllm" usage:"AnythingLLM: "` + Ollama OllamaConfig `yaml:"ollama" usage:"Ollama: "` + Mistral MistralConfig `yaml:"mistral" usage:"Mistral: "` + Anthropic AnthropicConfig `yaml:"anthropic" usage:"Anthropic: "` + CallOptions CallOptionsConfig `yaml:"call" usage:"LLM-CALL: "` } func (c *LLMConfig) GetUsage(field string) string { diff --git a/config/llm/localai.go b/config/llm/localai.go index fae65fc..ab1f6bc 100644 --- a/config/llm/localai.go +++ b/config/llm/localai.go @@ -2,20 +2,13 @@ package llm import ( "fmt" - flag "github.com/spf13/pflag" "github.com/tmc/langchaingo/llms/openai" ) type LocalAIConfig struct { - APIKey string `config:"api-key" usage:"API Key"` - Model string `config:"model" usage:"Model"` - BaseUrl string `config:"base-url" usage:"BaseUrl"` -} - -func configureLocalai(c *LocalAIConfig) { - flag.StringVar(&c.APIKey, "localai-api-key", "", "LocalAI API Key") - flag.StringVar(&c.Model, "localai-model", "", "LocalAI chat model") - flag.StringVar(&c.BaseUrl, "localai-base-url", "", "LocalAI API Base-URL") + APIKey string `yaml:"api-key" usage:"API Key"` + Model string `yaml:"model" usage:"Model"` + BaseUrl string `yaml:"base-url" usage:"BaseUrl"` } func (c *LocalAIConfig) AsOptions() (opts []openai.Option) { diff --git a/config/llm/mistral.go b/config/llm/mistral.go index 96ed0ec..da0f086 100644 --- a/config/llm/mistral.go +++ b/config/llm/mistral.go @@ -2,20 +2,13 @@ package llm import ( "fmt" - flag "github.com/spf13/pflag" "github.com/tmc/langchaingo/llms/mistral" ) type MistralConfig struct { - ApiKey string `config:"api-key" usage:"API Key"` - Endpoint string `config:"endpoint" usage:"Endpoint"` - Model string `config:"model" usage:"Model"` -} - -func configureMistral(c *MistralConfig) { - flag.StringVar(&c.ApiKey, "mistral-api-key", "", "API Key for Mistral") - flag.StringVar(&c.Endpoint, "mistral-endpoint", "", "Endpoint for Mistral") - flag.StringVar(&c.Model, "mistral-model", "", "Model for Mistral") + ApiKey string `yaml:"api-key" usage:"API Key"` + Endpoint string `yaml:"endpoint" usage:"Endpoint"` + Model string `yaml:"model" usage:"Model"` } func (c *MistralConfig) AsOptions() (opts []mistral.Option) { diff --git a/config/llm/ollama.go b/config/llm/ollama.go index 086e0ef..319cbc3 100644 --- a/config/llm/ollama.go +++ b/config/llm/ollama.go @@ -2,18 +2,12 @@ package llm import ( "fmt" - flag "github.com/spf13/pflag" "github.com/tmc/langchaingo/llms/ollama" ) type OllamaConfig struct { - ServerURL string `config:"server-url" usage:"Server URL"` - Model string `config:"model" usage:"Model"` -} - -func configureOllama(c *OllamaConfig) { - flag.StringVar(&c.ServerURL, "ollama-server-url", "", "Server URL for Ollama") - flag.StringVar(&c.Model, "ollama-model", "", "Model for Ollama") + ServerURL string `yaml:"server-url" usage:"Server URL"` + Model string `yaml:"model" usage:"Model"` } func (c *OllamaConfig) AsOptions() (opts []ollama.Option) { diff --git a/config/llm/openai.go b/config/llm/openai.go index d163488..ea7dd94 100644 --- a/config/llm/openai.go +++ b/config/llm/openai.go @@ -2,18 +2,17 @@ package llm import ( "fmt" - flag "github.com/spf13/pflag" "github.com/tmc/langchaingo/llms/openai" ) type OpenAIConfig struct { - APIKey string `config:"api-key" usage:"API Key"` - APIType string `config:"api-type"` - APIVersion string `config:"api-version" usage:"API Version"` + APIKey string `yaml:"api-key" usage:"API Key"` + APIType string `yaml:"api-type"` + APIVersion string `yaml:"api-version" usage:"API Version"` - Model string `config:"model" usage:"Model"` - BaseUrl string `config:"base-url" usage:"BaseUrl"` - Organization string `config:"organization" usage:"Organization"` + Model string `yaml:"model" usage:"Model"` + BaseUrl string `yaml:"base-url" usage:"BaseUrl"` + Organization string `yaml:"organization" usage:"Organization"` } func (c *OpenAIConfig) GetUsage(field string) string { @@ -24,15 +23,6 @@ func (c *OpenAIConfig) GetUsage(field string) string { return "" } -func configureOpenai(c *OpenAIConfig) { - flag.StringVar(&c.APIKey, "openai-api-key", "", "OpenAI API Key") - flag.StringVar(&c.APIType, "openai-api-type", string(openai.APITypeOpenAI), fmt.Sprintf("OpenAI API Type (%s, %s, %s)", openai.APITypeOpenAI, openai.APITypeAzure, openai.APITypeAzureAD)) - flag.StringVar(&c.APIVersion, "openai-api-version", "", "OpenAI API Version") - flag.StringVar(&c.Model, "openai-model", "gpt-4o-mini", "OpenAI chat model") - flag.StringVar(&c.BaseUrl, "openai-base-url", "", "OpenAI API Base-URL") - flag.StringVar(&c.Organization, "openai-organization", "", "OpenAI Organization") -} - func (c *OpenAIConfig) AsOptions() (opts []openai.Option) { if c.APIKey != "" { opts = append(opts, openai.WithToken(c.APIKey)) diff --git a/config/parser.go b/config/parser.go index 0fe77df..ba9d2f2 100644 --- a/config/parser.go +++ b/config/parser.go @@ -15,11 +15,12 @@ func Parse(arguments []string, env []string) *Config { fields := scanConfigTags(nil, c) + processYamlFiles(c) processEnvironment(env, fields) processArguments(arguments, fields) c.Printer.Targets = nil - for _, target := range strings.Split(c.Printer.TargetsRaw, ",") { + for _, target := range c.Printer.TargetsRaw { target = strings.TrimSpace(target) if target == PrinterTargetOut { @@ -39,9 +40,10 @@ func Parse(arguments []string, env []string) *Config { } type fieldTagInfo struct { - Name string - Short string - Usage string + Name string + YamlKey string + Short string + Usage string } func scanConfigTags(parent []fieldTagInfo, v interface{}) (result resolvedFieldInfos) { @@ -66,9 +68,10 @@ func scanConfigTags(parent []fieldTagInfo, v interface{}) (result resolvedFieldI path := slices.Clone(parent) path = append(path, fieldTagInfo{ - Name: getName(field), - Short: getShort(field), - Usage: getUsage(usageProvider, field), + Name: getName(field), + YamlKey: getYamlKey(field), + Short: getShort(field), + Usage: getUsage(usageProvider, field), }) fieldValue := val.Field(i) @@ -90,6 +93,16 @@ func getName(field reflect.StructField) string { if ct, ok := field.Tag.Lookup("config"); ok { return ct } + if ct, ok := field.Tag.Lookup("yaml"); ok { + return ct + } + return strings.ToLower(field.Name) +} + +func getYamlKey(field reflect.StructField) string { + if ct, ok := field.Tag.Lookup("yaml"); ok { + return ct + } return strings.ToLower(field.Name) } @@ -110,10 +123,11 @@ func getUsage(up UsageProvider, field reflect.StructField) string { } type resolvedFieldInfo struct { - Flag string - Short string - Env string - Usage string + YamlPath []string + Flag string + Short string + Env string + Usage string Value reflect.Value } @@ -125,7 +139,9 @@ func extractFieldInfo(path []fieldTagInfo, val reflect.Value) resolvedFieldInfo sbShort := strings.Builder{} sbUsage := strings.Builder{} + var sPath []string for i, p := range path { + sPath = append(sPath, p.YamlKey) if i > 0 && p.Name != "" { sbFlag.WriteString("-") sbEnv.WriteString("_") @@ -136,10 +152,11 @@ func extractFieldInfo(path []fieldTagInfo, val reflect.Value) resolvedFieldInfo sbUsage.WriteString(p.Usage) } return resolvedFieldInfo{ - Flag: strings.TrimLeft(sbFlag.String(), "-"), - Short: sbShort.String(), - Env: EnvironmentPrefix + strings.TrimLeft(strings.ToUpper(sbEnv.String()), "_"), - Usage: strings.Trim(sbUsage.String(), " "), - Value: val, + YamlPath: sPath, + Flag: strings.TrimLeft(sbFlag.String(), "-"), + Short: sbShort.String(), + Env: EnvironmentPrefix + strings.TrimLeft(strings.ToUpper(sbEnv.String()), "_"), + Usage: strings.Trim(sbUsage.String(), " "), + Value: val, } } diff --git a/config/parser_yaml.go b/config/parser_yaml.go new file mode 100644 index 0000000..6c9dff9 --- /dev/null +++ b/config/parser_yaml.go @@ -0,0 +1,67 @@ +package config + +import ( + "fmt" + "gopkg.in/yaml.v3" + "io" + "os" + "path" +) + +func yamlLookupLocations() (result []string) { + result = append(result, "/"+path.Join("etc", ".ask-mai.yml")) + result = append(result, "/"+path.Join("etc", ".ask-mai.yaml")) + result = append(result, "/"+path.Join("etc", "ask-mai", "config.yml")) + result = append(result, "/"+path.Join("etc", "ask-mai", "config.yaml")) + result = append(result, "/"+path.Join("usr", "local", "etc", ".ask-mai.yml")) + result = append(result, "/"+path.Join("usr", "local", "etc", ".ask-mai.yaml")) + result = append(result, "/"+path.Join("usr", "local", "etc", "ask-mai", "config.yml")) + result = append(result, "/"+path.Join("usr", "local", "etc", "ask-mai", "config.yaml")) + + if home, err := os.UserHomeDir(); err == nil { + result = append(result, path.Join(home, ".ask-mai.yml")) + result = append(result, path.Join(home, ".ask-mai.yaml")) + result = append(result, path.Join(home, ".config", ".ask-mai.yml")) + result = append(result, path.Join(home, ".config", ".ask-mai.yaml")) + result = append(result, path.Join(home, ".config", "ask-mai", "config.yml")) + result = append(result, path.Join(home, ".config", "ask-mai", "config.yaml")) + } + + binDir := path.Dir(os.Args[0]) + result = append(result, path.Join(binDir, ".ask-mai.yml")) + result = append(result, path.Join(binDir, ".ask-mai.yaml")) + + if wd, err := os.Getwd(); err == nil { + result = append(result, path.Join(wd, ".ask-mai.yml")) + result = append(result, path.Join(wd, ".ask-mai.yaml")) + } + + return +} + +func processYamlFiles(c *Config) { + for _, location := range yamlLookupLocations() { + processYamlFile(location, c) + } +} + +func processYamlFile(path string, c *Config) { + f, err := os.Open(path) + if err != nil { + return + } + defer f.Close() + + err = processYaml(f, c) + if err != nil { + panic(fmt.Errorf("unable to process yaml file %s: %w", path, err)) + } +} + +func processYaml(source io.Reader, c *Config) error { + err := yaml.NewDecoder(source).Decode(c) + if err != nil { + return fmt.Errorf("error while decoding yaml: %w", err) + } + return nil +} diff --git a/config/parser_yaml_test.go b/config/parser_yaml_test.go new file mode 100644 index 0000000..f838658 --- /dev/null +++ b/config/parser_yaml_test.go @@ -0,0 +1,220 @@ +package config + +import ( + "github.com/rainu/ask-mai/config/llm" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "strings" + "testing" +) + +func Test_processYaml(t *testing.T) { + c := &Config{} + + sr := strings.NewReader(` +ui: + window: + title: Test Window + init-width: + expression: "800" + value: 0 + max-height: + expression: "600" + value: 0 + init-pos-x: + expression: "100" + value: 0 + init-pos-y: + expression: "100" + value: 0 + init-zoom: + expression: "1.0" + value: 0 + bg-color: + r: 255 + g: 255 + b: 255 + a: 255 + start-state: 1 + always-on-top: true + frameless: true + resizeable: true + translucent: never + prompt: + value: Initial Prompt + attachments: + - attachment1 + - attachment2 + min-rows: 1 + max-rows: 10 + submit: + key: enter + alt: true + ctrl: true + meta: true + shift: true + file-dialog: + default-dir: /root + show-hidden: true + can-create-dirs: true + resolve-aliases: true + treat-packages-as-dirs: true + filter-display: + - Image + filter-pattern: + - '*.png' + stream: true + quit: + key: escape + alt: true + ctrl: true + meta: true + shift: true + theme: dark + code-style: default + lang: en +llm: + backend: anthropic + localai: + api-key: APIKey + model: model + base-url: baseurl + openai: + api-key: APIKey + api-type: APIType + api-version: APIVersion + model: Model + base-url: BaseUrl + organization: Organization + anythingllm: + base-url: BaseURL + token: Token + workspace: Workspace + ollama: + server-url: ServerURL + model: Model + mistral: + api-key: ApiKey + endpoint: Endpoint + model: Model + anthropic: + api-key: Token + base-url: BaseUrl + model: Model + call: + system-prompt: Your system prompt + max-token: 1000 + temperature: 0.7 + top-k: 50 + top-p: 0.9 + min-length: 10 + max-length: 200 +print: + format: json + targets: + - stdout +log-level: 1 +`) + + require.NoError(t, processYaml(sr, c)) + assert.Equal(t, &Config{ + UI: UIConfig{ + Window: WindowConfig{ + Title: "Test Window", + InitialWidth: ExpressionContainer{Expression: "800"}, + MaxHeight: ExpressionContainer{Expression: "600"}, + InitialPositionX: ExpressionContainer{Expression: "100"}, + InitialPositionY: ExpressionContainer{Expression: "100"}, + InitialZoom: ExpressionContainer{Expression: "1.0"}, + BackgroundColor: WindowBackgroundColor{R: 255, G: 255, B: 255, A: 255}, + StartState: 1, + AlwaysOnTop: true, + Frameless: true, + Resizeable: true, + Translucent: "never", + }, + Prompt: PromptConfig{ + InitValue: "Initial Prompt", + InitAttachments: []string{"attachment1", "attachment2"}, + MinRows: 1, + MaxRows: 10, + SubmitShortcut: Shortcut{ + Code: "enter", + Alt: true, + Ctrl: true, + Meta: true, + Shift: true, + }, + }, + FileDialog: FileDialogConfig{ + DefaultDirectory: "/root", + ShowHiddenFiles: true, + CanCreateDirectories: true, + ResolveAliases: true, + TreatPackagesAsDirectories: true, + FilterDisplay: []string{"Image"}, + FilterPattern: []string{"*.png"}, + }, + Stream: true, + QuitShortcut: Shortcut{ + Code: "escape", + Alt: true, + Ctrl: true, + Meta: true, + Shift: true, + }, + Theme: "dark", + CodeStyle: "default", + Language: "en", + }, + LLM: llm.LLMConfig{ + Backend: "anthropic", + LocalAI: llm.LocalAIConfig{ + APIKey: "APIKey", + Model: "model", + BaseUrl: "baseurl", + }, + OpenAI: llm.OpenAIConfig{ + APIKey: "APIKey", + APIType: "APIType", + APIVersion: "APIVersion", + Model: "Model", + BaseUrl: "BaseUrl", + Organization: "Organization", + }, + AnythingLLM: llm.AnythingLLMConfig{ + BaseURL: "BaseURL", + Token: "Token", + Workspace: "Workspace", + }, + Ollama: llm.OllamaConfig{ + ServerURL: "ServerURL", + Model: "Model", + }, + Mistral: llm.MistralConfig{ + ApiKey: "ApiKey", + Endpoint: "Endpoint", + Model: "Model", + }, + Anthropic: llm.AnthropicConfig{ + Token: "Token", + BaseUrl: "BaseUrl", + Model: "Model", + }, + CallOptions: llm.CallOptionsConfig{ + SystemPrompt: "Your system prompt", + MaxToken: 1000, + Temperature: 0.7, + TopK: 50, + TopP: 0.9, + MinLength: 10, + MaxLength: 200, + }, + }, + Printer: PrinterConfig{ + Format: "json", + TargetsRaw: []string{"stdout"}, + }, + LogLevel: 1, + }, c) +} diff --git a/config/print.go b/config/print.go index bffcf86..0eb9d77 100644 --- a/config/print.go +++ b/config/print.go @@ -13,9 +13,9 @@ const ( ) type PrinterConfig struct { - Format string `config:"format" short:"f"` - Targets []io.WriteCloser `config:"-"` - TargetsRaw string `config:"TargetsRaw"` + Format string `yaml:"format" short:"f"` + Targets []io.WriteCloser `yaml:"-"` + TargetsRaw []string `yaml:"targets"` } func (p *PrinterConfig) GetUsage(field string) string { @@ -23,7 +23,7 @@ func (p *PrinterConfig) GetUsage(field string) string { case "Format": return fmt.Sprintf("Response printer format (%s, %s)", PrinterFormatPlain, PrinterFormatJSON) case "TargetsRaw": - return fmt.Sprintf("Comma seperated response printer targets (%s, %s, )", PrinterTargetOut, PrinterTargetErr) + return fmt.Sprintf("Response printer targets (%s, %s, )", PrinterTargetOut, PrinterTargetErr) } return "" } diff --git a/config/shortcut.go b/config/shortcut.go index dab024d..42a3fc0 100644 --- a/config/shortcut.go +++ b/config/shortcut.go @@ -1,9 +1,9 @@ package config type Shortcut struct { - Code string `config:"key" usage:"key-code"` - Alt bool `config:"alt" usage:"alt-key must be pressed"` - Ctrl bool `config:"ctrl" usage:"control-key must be pressed"` - Meta bool `config:"meta" usage:"meta-key must be pressed"` - Shift bool `config:"shift" usage:"shift-key must be pressed"` + Code string `yaml:"key" usage:"key-code"` + Alt bool `yaml:"alt" usage:"alt-key must be pressed"` + Ctrl bool `yaml:"ctrl" usage:"control-key must be pressed"` + Meta bool `yaml:"meta" usage:"meta-key must be pressed"` + Shift bool `yaml:"shift" usage:"shift-key must be pressed"` } diff --git a/config/ui_dialog.go b/config/ui_dialog.go index 3efd97d..fa79e46 100644 --- a/config/ui_dialog.go +++ b/config/ui_dialog.go @@ -3,14 +3,14 @@ package config import "fmt" type FileDialogConfig struct { - DefaultDirectory string `config:"default-dir" usage:"The default directory for the file dialog"` - ShowHiddenFiles bool `config:"show-hidden" usage:"Should the file dialog show hidden files"` - CanCreateDirectories bool `config:"can-create-dirs" usage:"Should the file dialog be able to create directories"` - ResolvesAliases bool `config:"resolves-aliases" usage:"Should the file dialog resolve aliases"` - TreatPackagesAsDirectories bool `config:"treat-packages-as-dirs" usage:"Should the file dialog treat packages as directories"` + DefaultDirectory string `yaml:"default-dir" usage:"The default directory for the file dialog"` + ShowHiddenFiles bool `yaml:"show-hidden" usage:"Should the file dialog show hidden files"` + CanCreateDirectories bool `yaml:"can-create-dirs" usage:"Should the file dialog be able to create directories"` + ResolveAliases bool `yaml:"resolve-aliases" usage:"Should the file dialog resolve aliases"` + TreatPackagesAsDirectories bool `yaml:"treat-packages-as-dirs" usage:"Should the file dialog treat packages as directories"` - FilterDisplay []string `config:"filter-display" usage:"The filter display names for the file dialog. For example: \"Image Files (*.jpg, *.png)\""` - FilterPattern []string `config:"filter-pattern" usage:"The filter patterns for the file dialog. For example: \"*.jpg;*.png\""` + FilterDisplay []string `yaml:"filter-display" usage:"The filter display names for the file dialog. For example: \"Image Files (*.jpg, *.png)\""` + FilterPattern []string `yaml:"filter-pattern" usage:"The filter patterns for the file dialog. For example: \"*.jpg;*.png\""` } func (c *FileDialogConfig) Validate() error { diff --git a/config/ui_general.go b/config/ui_general.go index 0792a0b..9e4e268 100644 --- a/config/ui_general.go +++ b/config/ui_general.go @@ -11,14 +11,14 @@ const ( ) type UIConfig struct { - Window WindowConfig `config:"window"` - Prompt PromptConfig `config:"prompt"` - FileDialog FileDialogConfig `config:"file-dialog"` - Stream bool `config:"stream" short:"s" usage:"Should the output be streamed"` - QuitShortcut Shortcut `config:"quit-shortcut" usage:"The shortcut for quitting the application: "` - Theme string `config:"theme"` - CodeStyle string `config:"code-style" usage:"The code style to use"` - Language string `config:"lang" usage:"The language to use"` + Window WindowConfig `yaml:"window"` + Prompt PromptConfig `yaml:"prompt"` + FileDialog FileDialogConfig `yaml:"file-dialog"` + Stream bool `yaml:"stream" short:"s" usage:"Should the output be streamed"` + QuitShortcut Shortcut `yaml:"quit" usage:"The shortcut for quitting the application: "` + Theme string `yaml:"theme"` + CodeStyle string `yaml:"code-style" usage:"The code style to use"` + Language string `yaml:"lang" usage:"The language to use"` } func (u *UIConfig) GetUsage(field string) string { diff --git a/config/ui_prompt.go b/config/ui_prompt.go index 4a800ca..319ecf8 100644 --- a/config/ui_prompt.go +++ b/config/ui_prompt.go @@ -1,9 +1,9 @@ package config type PromptConfig struct { - InitValue string `config:"value" short:"p" usage:"The (initial) prompt to use"` - InitAttachments []string `config:"attachments" short:"a" usage:"The (initial) attachments to use"` - MinRows uint `config:"min-rows" usage:"The minimal number of rows the prompt should have"` - MaxRows uint `config:"max-rows" usage:"The maximal number of rows the prompt should have"` - SubmitShortcut Shortcut `config:"submit" usage:"The shortcut for submit the prompt: "` + InitValue string `yaml:"value" short:"p" usage:"The (initial) prompt to use"` + InitAttachments []string `yaml:"attachments" short:"a" usage:"The (initial) attachments to use"` + MinRows uint `yaml:"min-rows" usage:"The minimal number of rows the prompt should have"` + MaxRows uint `yaml:"max-rows" usage:"The maximal number of rows the prompt should have"` + SubmitShortcut Shortcut `yaml:"submit" usage:"The shortcut for submit the prompt: "` } diff --git a/config/ui_window.go b/config/ui_window.go index 49cb13b..ab7c1f6 100644 --- a/config/ui_window.go +++ b/config/ui_window.go @@ -12,25 +12,25 @@ const ( ) type WindowConfig struct { - Title string `config:"title" usage:"The window title"` - InitialWidth ExpressionContainer `config:"init-width" usage:"Expression: The (initial) width of the window"` - MaxHeight ExpressionContainer `config:"max-height" usage:"Expression: The maximal height of the chat response area"` - InitialPositionX ExpressionContainer `config:"init-pos-x" usage:"Expression: The (initial) x-position of the window"` - InitialPositionY ExpressionContainer `config:"init-pos-y" usage:"Expression: The (initial) y-position of the window"` - InitialZoom ExpressionContainer `config:"init-zoom" usage:"Expression: The (initial) zoom level of the window"` - BackgroundColor WindowBackgroundColor `config:"bg-color"` - StartState int `config:"start-state"` - AlwaysOnTop bool `config:"always-on-top" usage:"Should the window be always on top"` - Frameless bool `config:"frameless" usage:"Should the window be frameless"` - Resizeable bool `config:"resizeable" usage:"Should the window be resizeable"` - Translucent string `config:"translucent"` + Title string `yaml:"title" usage:"The window title"` + InitialWidth ExpressionContainer `yaml:"init-width" usage:"Expression: The (initial) width of the window"` + MaxHeight ExpressionContainer `yaml:"max-height" usage:"Expression: The maximal height of the chat response area"` + InitialPositionX ExpressionContainer `yaml:"init-pos-x" usage:"Expression: The (initial) x-position of the window"` + InitialPositionY ExpressionContainer `yaml:"init-pos-y" usage:"Expression: The (initial) y-position of the window"` + InitialZoom ExpressionContainer `yaml:"init-zoom" usage:"Expression: The (initial) zoom level of the window"` + BackgroundColor WindowBackgroundColor `yaml:"bg-color"` + StartState int `yaml:"start-state"` + AlwaysOnTop bool `yaml:"always-on-top" usage:"Should the window be always on top"` + Frameless bool `yaml:"frameless" usage:"Should the window be frameless"` + Resizeable bool `yaml:"resizeable" usage:"Should the window be resizeable"` + Translucent string `yaml:"translucent"` } type WindowBackgroundColor struct { - R uint `config:"r" usage:"red value"` - G uint `config:"g" usage:"green value"` - B uint `config:"b" usage:"blue value"` - A uint `config:"a" usage:"alpha value"` + R uint `yaml:"r" usage:"red value"` + G uint `yaml:"g" usage:"green value"` + B uint `yaml:"b" usage:"blue value"` + A uint `yaml:"a" usage:"alpha value"` } func (w *WindowConfig) GetUsage(field string) string { diff --git a/controller/dialog.go b/controller/dialog.go index c98927a..57b3899 100644 --- a/controller/dialog.go +++ b/controller/dialog.go @@ -23,7 +23,7 @@ func (c *Controller) OpenFileDialog(args OpenFileDialogArgs) ([]string, error) { DefaultDirectory: c.appConfig.UI.FileDialog.DefaultDirectory, ShowHiddenFiles: c.appConfig.UI.FileDialog.ShowHiddenFiles, CanCreateDirectories: c.appConfig.UI.FileDialog.CanCreateDirectories, - ResolvesAliases: c.appConfig.UI.FileDialog.ResolvesAliases, + ResolvesAliases: c.appConfig.UI.FileDialog.ResolveAliases, TreatPackagesAsDirectories: c.appConfig.UI.FileDialog.TreatPackagesAsDirectories, }) } diff --git a/frontend/wailsjs/go/models.ts b/frontend/wailsjs/go/models.ts index 3d129e6..6df4688 100755 --- a/frontend/wailsjs/go/models.ts +++ b/frontend/wailsjs/go/models.ts @@ -3,7 +3,7 @@ export namespace config { export class PrinterConfig { Format: string; Targets: any[]; - TargetsRaw: string; + TargetsRaw: string[]; static createFrom(source: any = {}) { return new PrinterConfig(source); @@ -20,7 +20,7 @@ export namespace config { DefaultDirectory: string; ShowHiddenFiles: boolean; CanCreateDirectories: boolean; - ResolvesAliases: boolean; + ResolveAliases: boolean; TreatPackagesAsDirectories: boolean; FilterDisplay: string[]; FilterPattern: string[]; @@ -34,7 +34,7 @@ export namespace config { this.DefaultDirectory = source["DefaultDirectory"]; this.ShowHiddenFiles = source["ShowHiddenFiles"]; this.CanCreateDirectories = source["CanCreateDirectories"]; - this.ResolvesAliases = source["ResolvesAliases"]; + this.ResolveAliases = source["ResolveAliases"]; this.TreatPackagesAsDirectories = source["TreatPackagesAsDirectories"]; this.FilterDisplay = source["FilterDisplay"]; this.FilterPattern = source["FilterPattern"]; diff --git a/go.mod b/go.mod index 245c4fb..a228540 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/tmc/langchaingo v0.1.12 github.com/wailsapp/wails/v2 v2.9.2 + gopkg.in/yaml.v3 v3.0.1 ) require ( @@ -48,7 +49,6 @@ require ( golang.org/x/sys v0.27.0 // indirect golang.org/x/text v0.20.0 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) // replace github.com/wailsapp/wails/v2 v2.9.2 => /tmp