So I've been wanting to try out Golang for a while now and I had a YouTube video about Cobra and how easy it is to make a CLI with it, so I decided to give it a try but instead of making a simple CLI I wanted to use an API to make it more interesting.
What is Cobra ?
Cobra is a CLI library for Go, it provides a simple interface to create powerful CLI interfaces with flags, arguments, and subcommands.
Getting Started
I started by creating a new project with
go mod init
then I followed the instruction to install Cobra
go get github.com/spf13/cobra/cobra
After reading a bit about Golang and it's project structure and package system I went ahead and created a couple files and folders.
▾ cligpt/
▾ cmd/
version.go
ask.go
root.go
main.go
Creating our first command
We first have to create the root command which will be the parent of all the other commands, edit the root.go
file and add the following code.
var rootCmd = &cobra.Command{
Use: "cligpt",
Short: "CLI for GPT-3.5",
Long: "CLI for GPT-3.5 - OpenAI's API for natural language processing",
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
Then we need our entry point, edit the main.go
file and add the following code.
package main
import "cligpt/cmd/command"
func main() {
command.Execute()
}
At this point we can run our program and see the help message.
go run main.go
CLI for GPT-3.5 - OpenAI's API for natural language processing
Adding subcomands
Seeing the help message is nice but we want to add some subcommands, edit the version.go
file and add the following code.
var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version number of CLI-GPT.",
Long: "Print the version number of CLI-GPT.",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("CLI-GPT v0.0.1")
},
}
func init() {
rootCmd.AddCommand(versionCmd)
}
To add a subcommand we first have to declare a variable of type cobra.Command
with the Use
, Short
, Long
and Run
fields, then we can add it to the rootCmd in its init()
function.
Use
defines the name of the command, Short
and Long
are used to display the help message, Run
is the function that will be executed when the command is called.
This command will print the version of our CLI, we can now run it and see the result.
go run main.go version
>> CLI-GPT v0.0.1
Adding the main command
Now that we have a working version command we can add the main command, we'll have to edit the ask.go
to add call OpenAI's API, we will use a library called go-openai made by Sasha Baranov for this.
Start by installing the library with
go get github.com/sashabaranov/go-openai
Then edit the ask.go
file and we'll do the same thing as we did for the version command.
var askCmd = &cobra.Command{
Use: "ask",
Short: "Ask GPT-3.5 a question.",
Long: "Ask GPT-3.5 a question.",
Run: func(cmd *cobra.Command, args []string) {
client := openai.NewClient(os.Getenv("OPENAI_API_KEY"))
messages := make([]openai.ChatCompletionMessage, 0)
text, _ := cmd.Flags().GetString("prompt")
text = strings.Replace(text, "\n", "", -1)
messages = append(messages, openai.ChatCompletionMessage{
Role: openai.ChatMessageRoleUser,
Content: text,
})
resp, err := client.CreateChatCompletion(
context.Background(),
openai.ChatCompletionRequest{
Model: openai.GPT3Dot5Turbo,
Messages: messages,
},
)
if err != nil {
fmt.Printf("ChatCompletion error: %v\n", err)
return
}
content := resp.Choices[0].Message.Content
messages = append(messages, openai.ChatCompletionMessage{
Role: openai.ChatMessageRoleAssistant,
Content: content,
})
fmt.Println(content)
},
}
func init() {
rootCmd.AddCommand(askCmd)
askCmd.Flags().StringP("prompt", "p", "", "Prompt for GPT-3.5 to complete.")
askCmd.MarkFlagRequired("prompt")
}
I simply copy pasted the code from the README.md
example and modified it a bit to fit our needs.
Bascially what this code does is :
-
First, we create the command variable that we'll add to the root command as we did before.
-
This time we add a flag to the command and make it required, this flag will be used to pass the prompt to the API call.
-
Then in the
Run
function, create a new client with the API key retrieved from theOPENAI_API_KEY
environment variable. -
Create a new request with the prompt passed as a flag and the model we want to use.
-
Send the request to the API and print the result.
Everything should be working now, we can run the command and see the result.
go run main.go ask -p "What is golang ?"
Golang is a programming language that was created by Google in 2009.
It is a general-purpose language that can be used for a variety of tasks, including
web development, mobile development, and data science.
It is also used for machine learning and artificial intelligence applications.
Conclusion
When I started this project I didn't know that OpenAI's API wasn't free, I thought it was like any other API and that you could use it for free as long as you didn't use it too much so I was a bit disappointed when I found out that it wasn't the case. For this, I agree that using a paid API for this use case is a bit overkill so I'll probably try to find a free alternative later on.