From ab4ae5ea1f64252203b499e3c7bc296e1477dff5 Mon Sep 17 00:00:00 2001 From: "Sidney J. Sherrill" Date: Thu, 27 Jul 2023 09:36:58 -0400 Subject: [PATCH 1/4] add -mode flag to original-command-structure, allowing for --- .vscode/launch.json | 22 +++++++- bot.go | 54 ++++++++++++++----- openai_adapter.go | 2 +- openai_adapter_test.go | 2 +- ...pt_prefix.txt => prompt_prefix_command.txt | 0 prompt_prefix_config.txt | 23 ++++++++ 6 files changed, 86 insertions(+), 17 deletions(-) rename prompt_prefix.txt => prompt_prefix_command.txt (100%) create mode 100644 prompt_prefix_config.txt diff --git a/.vscode/launch.json b/.vscode/launch.json index b427fbd..57872e1 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "version": "0.2.0", "configurations": [ { - "name": "Launch Package", + "name": "Debug `bot nc`", "type": "go", "request": "launch", "mode": "auto", @@ -13,6 +13,26 @@ "env": {"DEBUG": "1"}, "console": "integratedTerminal", "args": ["nc"] + }, + { + "name": "Debug `bot -mode config chron`", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${fileDirname}", + "env": {"DEBUG": "1"}, + "console": "integratedTerminal", + "args": ["-mode","config","cron"] + }, + { + "name": "Debug `bot i`", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${fileDirname}", + "env": {"DEBUG": "1"}, + "console": "integratedTerminal", + "args": ["-i"] } ] } \ No newline at end of file diff --git a/bot.go b/bot.go index 5d2ec26..6471c87 100644 --- a/bot.go +++ b/bot.go @@ -1,6 +1,7 @@ package main import ( + "embed" _ "embed" "flag" "fmt" @@ -11,31 +12,38 @@ import ( "sync" ) -//go:embed prompt_prefix.txt -var promptPrefix string +//go:embed prompt_prefix*.txt +var promptPrefixFS embed.FS const promptStartText = "\n[EXAMPLES]\n" +var err error + func main() { args := parseArgs() - if len(args.Prompt) == 0 { + if args.Usage || len(args.Prompt) == 0 { usage() os.Exit(1) } - homeDir, err := os.UserHomeDir() - if err != nil { - fmt.Fprintf(os.Stderr, "Error retrieving home directory: %v", err) - os.Exit(1) + var promptPrefix []byte + switch { + case args.Mode == "command": + promptPrefix, err = promptPrefixFS.ReadFile("prompt_prefix_command.txt") + errHandler(err, "Error reading prompt_prefix_command") + case args.Mode == "config": + promptPrefix, err = promptPrefixFS.ReadFile("prompt_prefix_config.txt") + errHandler(err, "Error reading prompt_prefix_config") } + homeDir, err := os.UserHomeDir() + errHandler(err, "Error retrieving home directory") + + // TODO: distinguish between config for bot program and config as a command flag configPath := filepath.Join(homeDir, configFilename) config, err := loadConfig(configPath) - if err != nil { - fmt.Fprintf(os.Stderr, "Error loading config: %v", err) - os.Exit(1) - } + errHandler(err, "Error loading config") respCh := make(chan string) @@ -45,7 +53,8 @@ func main() { client := &OpenAIAdapter{APIKey: config.APIKey} go func() { defer wg.Done() - err := client.FetchCompletionStream(CreateRequest(args.Prompt), respCh) + err := client.FetchCompletionStream(CreateRequest(string(promptPrefix), args.Prompt), respCh) + errHandler(err) if err != nil { fmt.Fprintf(os.Stderr, "%v", err) os.Exit(1) @@ -61,19 +70,24 @@ func main() { } type Args struct { + Help bool Interactive bool + Mode string Prompt string } func parseArgs() *Args { + help := flag.Bool("help", false, "Display usage options") interactive := flag.Bool("i", false, "Enter interactive mode (optional)") + mode := flag.String("mode", "command", "Query config file details") flag.Parse() prompt := strings.Join(flag.Args(), " ") - return &Args{Interactive: *interactive, Prompt: prompt} + return &Args{Help: *help, Interactive: *interactive, Mode: *mode, Prompt: prompt} } func usage() { - fmt.Fprintf(os.Stderr, "Usage: %s [prompt]", os.Args[0]) + fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s:\n", os.Args[0]) + flag.PrintDefaults() } func RenderCompletionStreamResponse(w io.Writer, respCh <-chan string) { @@ -82,3 +96,15 @@ func RenderCompletionStreamResponse(w io.Writer, respCh <-chan string) { } fmt.Fprintln(w, "") } + +func errHandler(err error, args ...string) { + errString := "Error" + if len(args) > 0 { + errString = args[0] + } + + if err != nil { + fmt.Fprintf(os.Stderr, "%s: %v", errString, err) + os.Exit(1) + } +} diff --git a/openai_adapter.go b/openai_adapter.go index 5740635..13805f5 100644 --- a/openai_adapter.go +++ b/openai_adapter.go @@ -13,7 +13,7 @@ type OpenAIAdapter struct { APIKey string } -func CreateRequest(prompt string) openai.CompletionRequest { +func CreateRequest(promptPrefix string, prompt string) openai.CompletionRequest { return openai.CompletionRequest{ Model: openai.GPT3TextDavinci003, MaxTokens: 1024, diff --git a/openai_adapter_test.go b/openai_adapter_test.go index 38d27e6..770dea8 100644 --- a/openai_adapter_test.go +++ b/openai_adapter_test.go @@ -27,7 +27,7 @@ func TestFetchCompletionStream(t *testing.T) { go func() { defer wg.Done() - err := client.FetchCompletionStream(CreateRequest("prompt"), respCh) + err := client.FetchCompletionStream(CreateRequest("promptPrefix", "prompt"), respCh) if err != nil { fmt.Println(err) } diff --git a/prompt_prefix.txt b/prompt_prefix_command.txt similarity index 100% rename from prompt_prefix.txt rename to prompt_prefix_command.txt diff --git a/prompt_prefix_config.txt b/prompt_prefix_config.txt new file mode 100644 index 0000000..1472835 --- /dev/null +++ b/prompt_prefix_config.txt @@ -0,0 +1,23 @@ +Provide example usage of configuraiton file information when the user provides the configuration file name or description. Use variable names in place of user-provided arguments. If the configuration file does not exist, respond with [NOT FOUND]. + +COMMAND>.ssh/config +[EXAMPLES] +# Basic use example +Host dev + HostName $HOSTNAME + User $USERNAME + Port $PORT + +# Advanced use example +Host dev + HostName $HOSTNAME + User $USERNAME + Port $PORT + IdentityFile $IDENTITYFILE + LogLevel $LOGLEVEL + Compression $COMPRESSION + +[REFERENCES] +- https://linuxize.com/post/using-the-ssh-config-file/ + +COMMAND> From 8434c962807419c0deb8da154be60834bd48620e Mon Sep 17 00:00:00 2001 From: "Sidney J. Sherrill" Date: Thu, 27 Jul 2023 09:41:09 -0400 Subject: [PATCH 2/4] fix bug --- bot.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot.go b/bot.go index 6471c87..09600bb 100644 --- a/bot.go +++ b/bot.go @@ -22,7 +22,7 @@ var err error func main() { args := parseArgs() - if args.Usage || len(args.Prompt) == 0 { + if len(args.Prompt) == 0 { usage() os.Exit(1) } From 40bdfb33e8a176cffc9196e3a78a69bb8a87d780 Mon Sep 17 00:00:00 2001 From: "Sidney J. Sherrill" Date: Mon, 21 Aug 2023 09:28:46 -0400 Subject: [PATCH 3/4] update config-named variables to differentiate between api config and bot config flag --- .vscode/launch.json | 9 +++++++++ bot.go | 41 ++++++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 57872e1..ac1d53f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,6 +4,15 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { + "name": "Debug `bot`", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${fileDirname}", + "env": {"DEBUG": "1"}, + "console": "integratedTerminal", + }, { "name": "Debug `bot nc`", "type": "go", diff --git a/bot.go b/bot.go index 09600bb..37ea1cb 100644 --- a/bot.go +++ b/bot.go @@ -22,17 +22,13 @@ var err error func main() { args := parseArgs() - if len(args.Prompt) == 0 { - usage() - os.Exit(1) - } var promptPrefix []byte - switch { - case args.Mode == "command": + switch args.Config { + case false: promptPrefix, err = promptPrefixFS.ReadFile("prompt_prefix_command.txt") errHandler(err, "Error reading prompt_prefix_command") - case args.Mode == "config": + case true: promptPrefix, err = promptPrefixFS.ReadFile("prompt_prefix_config.txt") errHandler(err, "Error reading prompt_prefix_config") } @@ -40,9 +36,8 @@ func main() { homeDir, err := os.UserHomeDir() errHandler(err, "Error retrieving home directory") - // TODO: distinguish between config for bot program and config as a command flag - configPath := filepath.Join(homeDir, configFilename) - config, err := loadConfig(configPath) + botConfigPath := filepath.Join(homeDir, configFilename) + botConfig, err := loadConfig(botConfigPath) errHandler(err, "Error loading config") respCh := make(chan string) @@ -50,7 +45,7 @@ func main() { var wg sync.WaitGroup wg.Add(2) - client := &OpenAIAdapter{APIKey: config.APIKey} + client := &OpenAIAdapter{APIKey: botConfig.APIKey} go func() { defer wg.Done() err := client.FetchCompletionStream(CreateRequest(string(promptPrefix), args.Prompt), respCh) @@ -72,22 +67,34 @@ func main() { type Args struct { Help bool Interactive bool - Mode string + Config bool Prompt string } func parseArgs() *Args { + help := flag.Bool("help", false, "Display usage options") - interactive := flag.Bool("i", false, "Enter interactive mode (optional)") - mode := flag.String("mode", "command", "Query config file details") + interactive := flag.Bool("i", false, "Enter interactive mode (coming soon!)") + config := flag.Bool("config", false, "Optional flag to operate as config bot") flag.Parse() prompt := strings.Join(flag.Args(), " ") - return &Args{Help: *help, Interactive: *interactive, Mode: *mode, Prompt: prompt} + + if *help || len(os.Args) < 2 || len(prompt) == 0 { + Usage() + } + + return &Args{Help: *help, Interactive: *interactive, Config: *config, Prompt: prompt} } -func usage() { - fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s:\n", os.Args[0]) +func Usage() { + fmt.Println("Simple command-line utility for looking up command usage or config file examples.") + fmt.Println("Flags:") flag.PrintDefaults() + fmt.Println("Example usage:") + fmt.Println(" bot nc") + fmt.Println(" bot -config cron") + fmt.Println(" bot -help") + os.Exit(1) } func RenderCompletionStreamResponse(w io.Writer, respCh <-chan string) { From bff38a8d129a95967de7f9aec4e35d63793d5596 Mon Sep 17 00:00:00 2001 From: "Sidney J. Sherrill" Date: Mon, 21 Aug 2023 09:47:01 -0400 Subject: [PATCH 4/4] update comments --- bot.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bot.go b/bot.go index 37ea1cb..941ce23 100644 --- a/bot.go +++ b/bot.go @@ -12,6 +12,13 @@ import ( "sync" ) +/* +- The "go:embed" directive must immediately precede a line containing the declaration of a single variable +- Therefore, this program embeds all files in the current folder that match prompt_prefix*.txt into a file system variable "promptPrefixFS" +- Then, depending on the flags passed to the command, the actual "promptPrefix" is defined by reading from "promptPrefixFS" +- This method makes use of the embed directive while allowing the final "promptPrefix" to be conditionally defined +*/ + //go:embed prompt_prefix*.txt var promptPrefixFS embed.FS