Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/config/manager.go
2649 views
1
package config
2
3
import (
4
"fmt"
5
"gopkg.in/yaml.v3"
6
"os"
7
"reflect"
8
"strconv"
9
"strings"
10
)
11
12
type Manager struct {
13
configStore Store
14
Config Config
15
}
16
17
func NewManager(cs Store) *Manager {
18
configuration := cs.ReadDefaults()
19
20
userConfig, err := cs.Read()
21
if err == nil {
22
configuration = replaceByConfigFile(configuration, userConfig)
23
}
24
25
return &Manager{configStore: cs, Config: configuration}
26
}
27
28
func (c *Manager) WithEnvironment() *Manager {
29
c.Config = replaceByEnvironment(c.Config)
30
return c
31
}
32
33
func (c *Manager) APIKeyEnvVarName() string {
34
return strings.ToUpper(c.Config.Name) + "_" + "API_KEY"
35
}
36
37
// DeleteThread removes the specified thread from the configuration store.
38
// This operation is idempotent; non-existent threads do not cause errors.
39
func (c *Manager) DeleteThread(thread string) error {
40
return c.configStore.Delete(thread)
41
}
42
43
// ListThreads retrieves a list of all threads stored in the configuration.
44
// It marks the current thread with an asterisk (*) and returns the list sorted alphabetically.
45
// If an error occurs while retrieving the threads from the config store, it returns the error.
46
func (c *Manager) ListThreads() ([]string, error) {
47
var result []string
48
49
threads, err := c.configStore.List()
50
if err != nil {
51
return nil, err
52
}
53
54
for _, thread := range threads {
55
thread = strings.ReplaceAll(thread, ".json", "")
56
if thread != c.Config.Thread {
57
result = append(result, fmt.Sprintf("- %s", thread))
58
continue
59
}
60
result = append(result, fmt.Sprintf("* %s (current)", thread))
61
}
62
63
return result, nil
64
}
65
66
// ShowConfig serializes the current configuration to a YAML string.
67
// It returns the serialized string or an error if the serialization fails.
68
func (c *Manager) ShowConfig() (string, error) {
69
data, err := yaml.Marshal(c.Config)
70
if err != nil {
71
return "", err
72
}
73
74
return string(data), nil
75
}
76
77
func replaceByConfigFile(defaultConfig, userConfig Config) Config {
78
t := reflect.TypeOf(defaultConfig)
79
vDefault := reflect.ValueOf(&defaultConfig).Elem()
80
vUser := reflect.ValueOf(userConfig)
81
82
for i := 0; i < t.NumField(); i++ {
83
defaultField := vDefault.Field(i)
84
userField := vUser.Field(i)
85
86
switch defaultField.Kind() {
87
case reflect.String:
88
if userStr := userField.String(); userStr != "" {
89
defaultField.SetString(userStr)
90
}
91
case reflect.Int:
92
if userInt := int(userField.Int()); userInt != 0 {
93
defaultField.SetInt(int64(userInt))
94
}
95
case reflect.Bool:
96
defaultField.SetBool(userField.Bool())
97
case reflect.Float64:
98
if userFloat := userField.Float(); userFloat != 0.0 {
99
defaultField.SetFloat(userFloat)
100
}
101
}
102
}
103
104
return defaultConfig
105
}
106
107
func replaceByEnvironment(configuration Config) Config {
108
t := reflect.TypeOf(configuration)
109
v := reflect.ValueOf(&configuration).Elem()
110
111
prefix := strings.ToUpper(configuration.Name) + "_"
112
for i := 0; i < t.NumField(); i++ {
113
tag := t.Field(i).Tag.Get("yaml")
114
if tag == "name" {
115
continue
116
}
117
118
if value := os.Getenv(prefix + strings.ToUpper(tag)); value != "" {
119
field := v.Field(i)
120
121
switch field.Kind() {
122
case reflect.String:
123
field.SetString(value)
124
case reflect.Int:
125
intValue, _ := strconv.Atoi(value)
126
field.SetInt(int64(intValue))
127
case reflect.Bool:
128
boolValue, _ := strconv.ParseBool(value)
129
field.SetBool(boolValue)
130
case reflect.Float64:
131
floatValue, _ := strconv.ParseFloat(value, 64)
132
field.SetFloat(floatValue)
133
}
134
}
135
}
136
137
return configuration
138
}
139
140