Refactor store and config handling

- Moved global `store` and `config` variables to cli.go
- Add Fatal() function for outputting an error and exiting
This commit is contained in:
Matt Low 2023-11-04 19:58:48 +00:00
parent 9f75be615e
commit 04478cbbd1
5 changed files with 42 additions and 39 deletions

14
pkg/cli/cli.go Normal file
View File

@ -0,0 +1,14 @@
package cli
import (
"fmt"
"os"
)
var config = InitializeConfig()
var store = InitializeStore()
func Fatal(format string, args ...any) {
fmt.Fprintf(os.Stderr, format, args...)
os.Exit(1)
}

View File

@ -7,22 +7,11 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
var config = LoadConfig()
var store, storeError = InitializeStore()
func checkStore() {
if storeError != nil {
fmt.Fprintf(os.Stderr, "Error establishing connection to store: %v\n", storeError)
os.Exit(1)
}
}
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Use: "lm", Use: "lm",
Short: "Interact with Large Language Models", Short: "Interact with Large Language Models",
Long: `lm is a CLI tool to interact with OpenAI's GPT 3.5 and GPT 4.`, Long: `lm is a CLI tool to interact with OpenAI's GPT 3.5 and GPT 4.`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
checkStore()
// execute `lm ls` by default // execute `lm ls` by default
}, },
} }
@ -83,13 +72,13 @@ var newCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
messageContents, err := InputFromEditor("# What would you like to say?", "message.*.md") messageContents, err := InputFromEditor("# What would you like to say?", "message.*.md")
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Error receiving message input: %v\n", err) Fatal("Failed to get input: %v\n", err)
os.Exit(1) return
} }
if messageContents == "" { if messageContents == "" {
fmt.Fprintf(os.Stderr, "No message was provided.\n") Fatal("No message was provided.\n")
os.Exit(1) return
} }
fmt.Printf("> %s\n", messageContents) fmt.Printf("> %s\n", messageContents)
@ -103,8 +92,8 @@ var newCmd = &cobra.Command{
err = CreateChatCompletionStream("You are a helpful assistant.", messages, os.Stdout) err = CreateChatCompletionStream("You are a helpful assistant.", messages, os.Stdout)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "An error occured: %v\n", err) Fatal("%v\n", err)
os.Exit(1) return
} }
fmt.Println() fmt.Println()
@ -125,8 +114,8 @@ var promptCmd = &cobra.Command{
err := CreateChatCompletionStream("You are a helpful assistant.", messages, os.Stdout) err := CreateChatCompletionStream("You are a helpful assistant.", messages, os.Stdout)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "An error occured: %v\n", err) Fatal("%v\n", err)
os.Exit(1) return
} }
fmt.Println() fmt.Println()

View File

@ -29,7 +29,7 @@ func getConfigDir() string {
return configDir return configDir
} }
func LoadConfig() *Config { func InitializeConfig() *Config {
configFile := filepath.Join(getConfigDir(), "config.yaml") configFile := filepath.Join(getConfigDir(), "config.yaml")
configBytes, err := os.ReadFile(configFile) configBytes, err := os.ReadFile(configFile)
@ -40,8 +40,8 @@ func LoadConfig() *Config {
file, err := os.Create(configFile) file, err := os.Create(configFile)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Could not open config file for writing: %v", err) Fatal("Could not open config file for writing: %v", err)
os.Exit(1) return nil
} }
fmt.Printf("Writing default configuration to: %s\n", configFile) fmt.Printf("Writing default configuration to: %s\n", configFile)
@ -50,12 +50,12 @@ func LoadConfig() *Config {
_, err = file.Write(bytes) _, err = file.Write(bytes)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Could not save default configuratoin: %v", err) Fatal("Could not save default configuratoin: %v", err)
os.Exit(1) return nil
} }
} else if err != nil { } else if err != nil {
fmt.Fprintf(os.Stderr, "Could not read config file: %v", err) Fatal("Could not read config file: %v", err)
os.Exit(1) return nil
} }
config := &Config{} config := &Config{}

View File

@ -44,11 +44,12 @@ func getDataDir() string {
return dataDir return dataDir
} }
func InitializeStore() (*Store, error) { func InitializeStore() *Store {
databaseFile := filepath.Join(getDataDir(), "conversations.db") databaseFile := filepath.Join(getDataDir(), "conversations.db")
db, err := gorm.Open(sqlite.Open(databaseFile), &gorm.Config{}) db, err := gorm.Open(sqlite.Open(databaseFile), &gorm.Config{})
if err != nil { if err != nil {
return nil, err Fatal("Error establishing connection to store: %v\n", err)
return nil
} }
models := []any{ models := []any{
@ -59,15 +60,13 @@ func InitializeStore() (*Store, error) {
for _, x := range(models) { for _, x := range(models) {
err := db.AutoMigrate(x) err := db.AutoMigrate(x)
if err != nil { if err != nil {
return nil, err Fatal("Could not perform database migrations: %v\n", err)
return nil
} }
} }
_sqids, _ := sqids.New(sqids.Options{ _sqids, _ := sqids.New(sqids.Options{MinLength: 4})
MinLength: 4, return &Store{db, _sqids}
})
return &Store{db: db, sqids: _sqids}, nil
} }
func (s *Store) SaveConversation(conversation *Conversation) error { func (s *Store) SaveConversation(conversation *Conversation) error {

View File

@ -5,11 +5,12 @@ import (
"os/exec" "os/exec"
) )
// InputFromEditor retrieves user input by opening an editor on a temporary // InputFromEditor retrieves user input by opening an editor (one specified by
// file. Once the editor closes, the contents of the temporary file are // $EDITOR or 'vim' if $EDITOR is not set) on a temporary file. Once the editor
// returned. If the contents exactly match the placeholder (no edits to the // closes, the contents of the file are read and the file is deleted. If the
// file were made), then an empty string is returned. // contents of the file exactly match the value of placeholder (no edits to the
// Example patten: message.*.md // file were made), then an empty string is returned. Otherwise, the contents
// are returned. Example patten: message.*.md
func InputFromEditor(placeholder string, pattern string) (string, error) { func InputFromEditor(placeholder string, pattern string) (string, error) {
msgFile, _ := os.CreateTemp("/tmp", pattern) msgFile, _ := os.CreateTemp("/tmp", pattern)
defer os.Remove(msgFile.Name()) defer os.Remove(msgFile.Name())