1
1

terminalでChatGPTを使いたい

Last updated at Posted at 2023-12-26

GoでChatGPT

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

main関数

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と入力したら終了します。

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"だけです。

go get "github.com/joho/godotenv"

実行

$ go run main.go
> おはよう
おはようございます!朝から元気ですか?何かお手伝いできることはありますか?

>

よさそうです。

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

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

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

   ```go
   import (
       "github.com/joho/godotenv"
       "log"
       "os"
   )
  1. .envファイルを読み込む前にgodotenv.Load()関数を呼び出します。

    err := godotenv.Load()
    if err != nil {
        log.Fatal("Error loading .env file")
    }
    
  2. 環境変数を使用したい場所でos.Getenv()関数を使用してアクセスします。

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

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

    DB_USER=your_db_user
    DB_PASSWORD=your_db_password
    

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

CLI化

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

$ go build -o gpt-client
$ mv gpt-client /usr/local/bin/
$ which gpt-client
/usr/local/bin/gpt-client
$ gpt-client
>

よさそうです。

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1