2023-02-13 02:01:59 +00:00
package main
import (
"bufio"
"bytes"
"fmt"
"os"
2023-02-13 04:02:53 +00:00
"runtime/debug"
2023-02-13 02:01:59 +00:00
2023-04-29 15:28:52 +00:00
"github.com/sashabaranov/go-openai"
2023-02-13 02:01:59 +00:00
"github.com/spf13/cobra"
)
var LongHelp = `
2023-04-30 20:27:35 +00:00
Work with ChatGPT in console .
2023-02-13 02:01:59 +00:00
Examples :
2023-04-30 20:27:35 +00:00
# start an interactive session with gpt - 3.5 or gpt - 4
2023-02-13 02:01:59 +00:00
chatgpt - i
# ask chatgpt for a one - time response
chatgpt - q "answer me this ChatGPT..."
# provide context to a question or conversation
chatgpt context . txt - i
chatgpt context . txt - q "answer me this ChatGPT..."
2023-02-13 03:04:45 +00:00
# read prompt from file and -- write response back
2023-02-13 02:01:59 +00:00
chatgpt convo . txt
2023-02-13 03:04:45 +00:00
chatgpt convo . txt -- write
2023-02-13 02:01:59 +00:00
# pipe content from another program , useful for ! in vim visual mode
cat convo . txt | chatgpt
2023-04-29 15:28:52 +00:00
# set the directory for custom prompts , defaults to "prompts"
chatgpt - P custom - prompts - p my - prompt - i
2023-03-21 07:38:28 +00:00
# inspect the predifined prompts , which set ChatGPT ' s mood
2023-02-13 02:01:59 +00:00
chatgpt - p list
chatgpt - p view : < name >
2023-03-21 07:38:28 +00:00
# use a prompts with any of the previous modes
2023-02-13 02:01:59 +00:00
chatgpt - p optimistic - i
chatgpt - p cynic - q "Is the world going to be ok?"
chatgpt - p teacher convo . txt
2023-02-13 02:44:25 +00:00
2023-02-13 06:30:35 +00:00
# edit mode
chatgpt - e ...
2023-02-13 05:14:46 +00:00
2023-02-13 06:30:35 +00:00
# code mode
chatgpt - c ...
2023-02-13 05:14:46 +00:00
2023-02-13 06:30:35 +00:00
# model options ( https : //platform.openai.com/docs/api-reference/completions/create)
2023-03-12 00:42:38 +00:00
chatgpt - T 4096 # set max tokens in reponse [ 0 , 4096 ]
chatgpt - C # clean whitespace before sending
chatgpt - E # echo back the prompt , useful for vim coding
chatgpt -- temp # set the temperature param [ 0.0 , 2.0 ]
chatgpt -- topp # set the TopP param [ 0.0 , 1.0 ]
chatgpt -- pres # set the Presence Penalty [ - 2.0 , 2.0 ]
chatgpt -- freq # set the Frequency Penalty [ - 2.0 , 2.0 ]
# change model selection , available models are listed here :
# https : //pkg.go.dev/github.com/sashabaranov/go-openai#Client.ListModels
chatgpt - m text - davinci - 003 # set the model to text - davinci - 003 ( the default )
chatgpt - m text - ada - 001 # set the model to text - ada - 001
2023-02-13 05:14:46 +00:00
2023-02-13 02:01:59 +00:00
`
2023-02-13 04:02:53 +00:00
var Version bool
2023-02-13 05:14:46 +00:00
// prompt vars
2023-02-13 02:01:59 +00:00
var Question string
2023-03-21 07:38:28 +00:00
var Prompt string
var PromptDir string
2023-02-13 02:01:59 +00:00
var PromptMode bool
2023-02-13 05:14:46 +00:00
var EditMode bool
var CodeMode bool
2023-02-13 02:41:18 +00:00
var CleanPrompt bool
2023-02-13 03:04:45 +00:00
var WriteBack bool
2023-02-13 02:01:59 +00:00
var PromptText string
2023-02-13 05:14:46 +00:00
// chatgpt vars
var MaxTokens int
var Count int
2023-02-13 06:30:35 +00:00
var Echo bool
2023-02-13 05:14:46 +00:00
var Temp float64
var TopP float64
var PresencePenalty float64
var FrequencyPenalty float64
2023-02-24 00:02:52 +00:00
var Model string
2023-02-13 04:02:53 +00:00
func printVersion ( ) {
info , _ := debug . ReadBuildInfo ( )
GoVersion := info . GoVersion
Commit := ""
BuildDate := ""
dirty := false
for _ , s := range info . Settings {
if s . Key == "vcs.revision" {
Commit = s . Value
}
if s . Key == "vcs.time" {
BuildDate = s . Value
}
if s . Key == "vcs.modified" {
if s . Value == "true" {
dirty = true
}
}
}
if dirty {
Commit += "+dirty"
}
fmt . Printf ( "%s %s %s\n" , Commit , BuildDate , GoVersion )
}
2023-02-13 02:01:59 +00:00
type NullWriter int
func ( NullWriter ) Write ( [ ] byte ) ( int , error ) { return 0 , nil }
func main ( ) {
2023-02-24 00:02:52 +00:00
2023-04-30 20:27:35 +00:00
apiKey := os . Getenv ( "OPENAI_API_KEY" )
2023-02-13 02:01:59 +00:00
if apiKey == "" {
2023-04-30 20:27:35 +00:00
fmt . Println ( "OPENAI_API_KEY environment var is missing\nVisit https://platform.openai.com/account/api-keys to get one\n" )
2023-02-13 02:01:59 +00:00
os . Exit ( 1 )
}
2023-03-21 07:38:28 +00:00
if PromptDir == "" {
if v := os . Getenv ( "CHATGPT_PROMPT_DIR" ) ; v != "" {
PromptDir = v
}
}
2023-04-29 15:28:52 +00:00
client := openai . NewClient ( apiKey )
2023-02-13 02:01:59 +00:00
rootCmd := & cobra . Command {
Use : "chatgpt [file]" ,
Short : "Chat with ChatGPT in console." ,
2023-02-13 02:12:32 +00:00
Long : LongHelp ,
2023-02-13 02:01:59 +00:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
2023-02-13 04:02:53 +00:00
if Version {
printVersion ( )
os . Exit ( 0 )
}
2023-02-13 02:01:59 +00:00
var err error
var filename string
2023-02-13 02:17:35 +00:00
// We build up PromptText as we go, based on flags
2023-03-21 07:38:28 +00:00
// Handle the prompt flag
if Prompt != "" {
2023-04-29 15:28:52 +00:00
p , err := handlePrompt ( Prompt )
2023-03-21 07:38:28 +00:00
if err != nil {
fmt . Println ( err )
os . Exit ( 1 )
}
2023-04-29 15:28:52 +00:00
if p == "" {
2023-03-21 07:38:28 +00:00
os . Exit ( 0 )
2023-02-13 02:01:59 +00:00
}
2023-02-13 02:17:35 +00:00
// prime prompt with custom pretext
2023-04-29 15:28:52 +00:00
PromptText = p
2023-02-13 02:01:59 +00:00
}
2023-04-05 22:35:19 +00:00
// no args, or interactive... read from stdin
2023-02-13 02:17:35 +00:00
// this is mainly for replacing text in vim
2023-04-05 22:35:19 +00:00
if len ( args ) == 0 && ! PromptMode {
2023-02-13 02:01:59 +00:00
reader := bufio . NewReader ( os . Stdin )
var buf bytes . Buffer
for {
2023-02-13 02:12:32 +00:00
b , err := reader . ReadByte ( )
if err != nil {
break
}
buf . WriteByte ( b )
2023-02-13 02:01:59 +00:00
}
PromptText += buf . String ( )
} else if len ( args ) == 1 {
2023-02-13 02:17:35 +00:00
// if we have an arg, add it to the prompt
2023-02-13 02:01:59 +00:00
filename = args [ 0 ]
content , err := os . ReadFile ( filename )
if err != nil {
fmt . Println ( err )
return
}
PromptText += string ( content )
}
2023-02-13 02:17:35 +00:00
// if there is a question, it comes last in the prompt
2023-02-13 05:14:46 +00:00
if Question != "" && ! EditMode {
2023-02-13 02:01:59 +00:00
PromptText += "\n" + Question
}
2023-02-13 02:17:35 +00:00
// interactive or file mode
2023-02-13 02:01:59 +00:00
if PromptMode {
2023-04-29 16:23:48 +00:00
err = RunInteractive ( client )
2023-02-13 02:01:59 +00:00
} else {
2023-02-13 02:17:35 +00:00
// empty filename (no args) prints to stdout
2023-02-13 02:01:59 +00:00
err = RunOnce ( client , filename )
}
if err != nil {
fmt . Println ( err )
os . Exit ( 1 )
}
} ,
}
2023-02-13 02:17:35 +00:00
// setup flags
2023-02-13 05:14:46 +00:00
rootCmd . Flags ( ) . BoolVarP ( & Version , "version" , "" , false , "print version information" )
// prompt releated
2023-02-13 02:01:59 +00:00
rootCmd . Flags ( ) . StringVarP ( & Question , "question" , "q" , "" , "ask a single question and print the response back" )
2023-03-21 07:38:28 +00:00
rootCmd . Flags ( ) . StringVarP ( & Prompt , "prompt" , "p" , "" , "prompt to add to ChatGPT input, use 'list' or 'view:<name>' to inspect predefined, '<name>' to use a prompt, or otherwise supply any custom text" )
2023-04-29 15:28:52 +00:00
rootCmd . Flags ( ) . StringVarP ( & PromptDir , "prompt-dir" , "P" , "prompts" , "directory containing custom prompts, if not set the embedded defaults are used" )
2023-02-13 02:01:59 +00:00
rootCmd . Flags ( ) . BoolVarP ( & PromptMode , "interactive" , "i" , false , "start an interactive session with ChatGPT" )
2023-02-13 05:14:46 +00:00
rootCmd . Flags ( ) . BoolVarP ( & EditMode , "edit" , "e" , false , "request an edit with ChatGPT" )
rootCmd . Flags ( ) . BoolVarP ( & CleanPrompt , "clean" , "x" , false , "remove excess whitespace from prompt before sending" )
2023-02-13 03:04:45 +00:00
rootCmd . Flags ( ) . BoolVarP ( & WriteBack , "write" , "w" , false , "write response to end of context file" )
2023-02-13 02:01:59 +00:00
2023-02-13 05:14:46 +00:00
// params related
rootCmd . Flags ( ) . IntVarP ( & MaxTokens , "tokens" , "T" , 1024 , "set the MaxTokens to generate per response" )
rootCmd . Flags ( ) . IntVarP ( & Count , "count" , "C" , 1 , "set the number of response options to create" )
2023-02-13 06:30:35 +00:00
rootCmd . Flags ( ) . BoolVarP ( & Echo , "echo" , "E" , false , "Echo back the prompt, useful for vim coding" )
2023-03-21 07:38:28 +00:00
rootCmd . Flags ( ) . Float64VarP ( & Temp , "temp" , "" , 0.7 , "set the temperature parameter" )
2023-02-13 05:14:46 +00:00
rootCmd . Flags ( ) . Float64VarP ( & TopP , "topp" , "" , 1.0 , "set the TopP parameter" )
rootCmd . Flags ( ) . Float64VarP ( & PresencePenalty , "pres" , "" , 0.0 , "set the Presence Penalty parameter" )
rootCmd . Flags ( ) . Float64VarP ( & FrequencyPenalty , "freq" , "" , 0.0 , "set the Frequency Penalty parameter" )
2023-04-29 15:28:52 +00:00
rootCmd . Flags ( ) . StringVarP ( & Model , "model" , "m" , openai . GPT3TextDavinci003 , "select the model to use with -q or -e" )
2023-02-13 05:14:46 +00:00
// run the command
2023-02-13 02:01:59 +00:00
rootCmd . Execute ( )
}