Create a golang cli using openAI-chatgpt API
Tags: chatgpt, go, cli, tutorial
Published: 2023-03-05 06:54:24


In this tutorial we are going to create a simple golang command line program that uses the openAI API to recreate a similar funcionality of the chatgpt web.
https://chat.openai.com/chat


We will see this

- OpenAI apikey setup
- Setup base golang project
- Get input from terminal
- Send question to openAI API
- Show the results



This is the final result of the app

![alt text](https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExNDFkNjQ1MzIyNTQwZDY1MjU3MjUxMmE3ODExZGJiMTRlZWU4N2ExOSZjdD1n/bjMGxJMINyTzUCmzgt/giphy.gif)


This gif was created using the vhs amazing tool.
https://github.com/charmbracelet/vhs



The funcionality is pretty simple.

- Execute a binary program.
- Ask a question, then press enter.
- The program send a questions to the openAI API and show the response, all on the terminal.

## OpenAI apikey
In order to complete this tutorial you must obtain a apikey,
go to openAI and get a new one

https://platform.openai.com/account/api-keys

Be sure that you save the apikey in some place,  because they will show you it only once time.

## Setup project

Go to your terminal,  and run this command in order to create a folder and go inside

```
mkdir chatgptcli && cd chatgptcli
```

After that, init a go module 

```
go mod init chatgptcli
```

Create a main.go file 

```
touch main.go
```


## Get input from on terminal
In the main.go file add this code.

```go
func main() {
	reader := bufio.NewReader(os.Stdin)
	fmt.Print("Ask to chat gpt: ")
	text, err := reader.ReadString('\n')
	if err != nil {
		panic(err)
	}

	fmt.Println("User input:", text)
}
```

We created a reader object passing the os.Stdin as parameter in order to obtain the input from the command line.
After we use the ReadString that reads the input until a break line ( Enter key pressed ) is found, this is defined by the parameter '\n'.

If we have an error we finish the programa using a call to a panic function,  this is not the most elegant way to manage this but for the purpose of the tutorial is enough.

After that we only print on console the user input text.



## Send question to openAI API

We will use this great library to connect to the openAPI API 
https://github.com/sashabaranov/go-openai

That bring us a nice interface to connect to the api without the need to know all the params, configurations, etc, that the openAI required for work. 

This is the official documentation if you want to take a look.
https://platform.openai.com/docs/api-reference/chat

Add the library to the project

```
go get github.com/sashabaranov/go-openai
```

Add this code to main function on file main.go

```go
func main() {
        // previous code
        // [...] 

	c := openai.NewClient("youropenaitoken"))

	resp, err := c.CreateChatCompletion(
		context.Background(),
		openai.ChatCompletionRequest{
			Model: openai.GPT3Dot5Turbo,
			Messages: []openai.ChatCompletionMessage{
				{
					Role:    "user",
					Content: text,
				},
			},
		},
	)

	if err != nil {
		panic(err)
	}

	fmt.Println(resp.Choices[0].Message.Content)
	fmt.Println()

}
```

This block of code create a newClient using the openAI token,  in this project we hardcode this value but if you use this in a project ṕlease consider to use an environment variable instead of this.

We use the method createChatCompletion and the model openai.GPT3Dot5Turbo as our configuration.

The official definition for this model is the following

> A set of models that improve on GPT-3 and can understand as well as generate natural language or code


There are more options to choose 
- DALL-E
- Whisper 
- Codex 
- etc

https://platform.openai.com/docs/models/overview

All of them or at least most of them are available to use with the library.

Run program with this command

```
go run main.go
```


That works fine but we have a problem,  after the response for the API appears in the terminal, the programs finish and if we want to ask another question we have to open the program again.
We can change this behaviour and prevent that,  adding a little change.

Add a "for" that wraps all main code.

``` go
func main() {

	for {
		reader := bufio.NewReader(os.Stdin)
		fmt.Print("Ask to chat gpt: ")
		text, err := reader.ReadString('\n')
		if err != nil {
			fmt.Println("Error reading input:", err)
			return
		}

		fmt.Println("Input text:", text)

		c := openai.NewClient("youropenaitoken")

		resp, err := c.CreateChatCompletion(
			context.Background(),
			openai.ChatCompletionRequest{
				Model: openai.GPT3Dot5Turbo,
				Messages: []openai.ChatCompletionMessage{
					{
						Role:    "user",
						Content: text,
					},
				},
			},
		)

		if err != nil {
			panic(err)
		}

		fmt.Println(resp.Choices[0].Message.Content)
		fmt.Println()
	}
}
```

The for loops run infinitely ( like a "while true" in other languages ) and the promp to enter text will appears after see the results from the API, with than change now we have to close the program using CTRL+C.



So, that is all for now, you can see all the code in this gist.

https://gist.github.com/ernesto27/6aadbb2ed8169294c375505733381f16

This program works fine, but we can make some improvements for future tutorials, for example.


- The conversation starts from scratch always, i am not sure if is possible to mantain a conversation with the API.
- We can improve how the text looks in the terminal.
- We can configure the program to use a env variable instead of hardcode token.

> You also can find a more complete version of this program on this repository.
> https://github.com/ernesto27/chatgpt-cli