terminalでChatGPTを使いたい

# GoでChatGPT
terminalから呼び出せるGPTクライアントをgolangで作成します。


## main関数
```go:main.go
package main

import (
	"bufio"
	"fmt"
	"os"

	"./gpt"
)

func main() {
	for {
		fmt.Print("> ")
		scanner := bufio.NewScanner(os.Stdin)
		if scanner.Scan() {
			input := scanner.Text()
			if input == "exit" {
				fmt.Println("exit!")
				break
			}
			gpt.Call(input)
		}
	}
}
```

exitと入力したら終了します。

```go:gpt/call.go
package gpt

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"

	"github.com/joho/godotenv"
)

var messages []Message

type GPT struct {
	apiKey   string
	endpoint string
}

func NewGPT() *GPT {
	err := godotenv.Load()
	if err != nil {
		log.Fatal("Error loading .env file")
	}
	return &GPT{
		apiKey:   os.Getenv("OPENAI_API_KEY"),
		endpoint: "https://api.openai.com/v1/chat/completions",
	}
}

func Call(question string) string {
	g := NewGPT()
	messages = append(messages, Message{
		Role:    "user",
		Content: question,
	})
	response := g.getOpenAIResponse(g.apiKey)
	fmt.Println(response.Choices[0].Messages.Content)
	print("\n")
	return response.Choices[0].Messages.Content
}

func (g GPT) getOpenAIResponse(apiKey string) OpenaiResponse {
	requestBody := OpenaiRequest{
		Model:    "gpt-3.5-turbo",
		Messages: messages,
	}

	requestJSON, _ := json.Marshal(requestBody)

	req, err := http.NewRequest("POST", g.endpoint, bytes.NewBuffer(requestJSON))
	if err != nil {
		panic(err)
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+apiKey)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer func(Body io.ReadCloser) {
		err := Body.Close()
		if err != nil {
			panic(err)
		}
	}(resp.Body)

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}

	var response OpenaiResponse
	err = json.Unmarshal(body, &response)
	if err != nil {
		println("Error: ", err.Error())
		return OpenaiResponse{}
	}

	messages = append(messages, Message{
		Role:    "assistant",
		Content: response.Choices[0].Messages.Content,
	})

	return response
}

type OpenaiRequest struct {
	Model    string    `json:"model"`
	Messages []Message `json:"messages"`
}

type OpenaiResponse struct {
	ID      string   `json:"id"`
	Object  string   `json:"object"`
	Created int      `json:"created"`
	Choices []Choice `json:"choices"`
	Usages  Usage    `json:"usage"`
}

type Choice struct {
	Index        int     `json:"index"`
	Messages     Message `json:"message"`
	FinishReason string  `json:"finish_reason"`
}

type Message struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

type Usage struct {
	PromptTokens     int `json:"prompt_tokens"`
	CompletionTokens int `json:"completion_tokens"`
	TotalTokens      int `json:"total_tokens"`
}

```

過去のやり取りを与えるといった実装はしていません。
あまり良いライブラリがなかったので、標準の`net/http`でAPIを叩くようにしました。

使用しているサードパーティ製ライブラリは環境変数を`.env`から取得するための
`"github.com/joho/godotenv"`だけです。
```bash
go get "github.com/joho/godotenv"
```

## 実行
```bash
$ go run main.go
> おはよう
おはようございます！朝から元気ですか？何かお手伝いできることはありますか？

>
```
よさそうです。
```bash
> golangで.envファイルから環境変数を取得するにはどうしたらいいですか？
golangで.envファイルから環境変数を取得するには、`godotenv`というパッケージを使用するのが一般的です。以下の手順に従って実装してみてください。

1. `go get github.com/joho/godotenv`コマンドを実行して、`godotenv`パッケージをインストールします。

2. コード内で`godotenv`パッケージをインポートします。

   ```go
   import (
       "github.com/joho/godotenv"
       "log"
       "os"
   )
   ```

3. `.env`ファイルを読み込む前に`godotenv.Load()`関数を呼び出します。

   ```go
   err := godotenv.Load()
   if err != nil {
       log.Fatal("Error loading .env file")
   }
   ```

4. 環境変数を使用したい場所で`os.Getenv()`関数を使用してアクセスします。

   ```go
   dbUser := os.Getenv("DB_USER")
   dbPassword := os.Getenv("DB_PASSWORD")
   ```

   `.env`ファイルには以下のように環境変数と値を設定します。

   ```
   DB_USER=your_db_user
   DB_PASSWORD=your_db_password
   ```

このようにすることで、`.env`ファイルから環境変数を取得できます。ただし、`godotenv`は開発時に便利ですが、本番環境ではセキュリティリスクとなる可能性があるため、適切に管理する必要があります。

>


## CLI化
どこのディレクトリからでも使いたいので、ビルドして、パスが通ったディレクトリへ移動させます。

```bash
$ go build -o gpt-client
$ mv gpt-client /usr/local/bin/
$ which gpt-client
/usr/local/bin/gpt-client
$ gpt-client
>
```
よさそうです。

### 参考
https://qiita.com/bluewolfali/items/9031cd56f1743aec3e9a