生成AIの活用方法として脚光を浴びているのが「文書校正」です。これまでも機械的に誤字脱字を指摘してくれる校正ツールはありましたが、生成AIを利用することで文脈を考慮した高度な指摘が可能です。そんなAI文書校正ツールをGo言語で作ってみましょう。
生成AIで文書校正やるとかなり良い感じ
「ChatGPT」は、2022年11月に登場し世界中に生成AIブームを巻き起こしました。この原稿執筆時点で約2年が経過しました。どんな分野で利用したら良いのか、いろいろと実験が進み、さまざまな現場で利用されるようになりました。読者の皆さんの中にも、積極的に利用している方がいるでしょう。
最近、筆者がよく生成AIを活用している分野が「プログラミング」と「文書校正」です。プログラミングの能力については、既にいろいろなところで言及されているので、今回は、文書校正に注目しましょう。
実際に、文書校正させてみると分かりますが、かなり良い感じです。生成AIは、これまでの辞書ベースの校正ツールでは指摘できないようなタイプの誤字脱字も指摘してくれます。例えば、文法的には合っているものの漢字が間違っているものだったり、たまたまカーソル位置がずれて本来入れたい所とは異なる場所に入力してしまった単語などを、不自然として指摘してくれるのです。
そこで、今回は、Go言語からChatGPTのAPIを呼び出して、簡単な文書校正ツールを作ってみましょう。
ChatGPT APIを使うにはAPIキーが必要
ChatGPTが便利なのが、Webアプリとして利用するだけでなく、自作アプリに組み込むために、Web APIを提供している点にあります。
ChatGPTを自作アプリに組み込むために、OpenAIのAPIキーを取得しましょう。ChatGPTのAPIを使うために、こちらのOpenAIの開発者プラットフォームにアクセスしましょう。
はじめての場合は、画面右上の「Sign up」ボタンをクリックしてアカウントを作成しましょう。最初は無料枠があるので、気軽に始めることができます。
開発者プラットフォームにログインしたら、APIキーを取得するには、画面上部のダッシュボード(Dashboard)をクリックし、画面左側の「API Keys」をクリックします。そして、画面上部にある「+ Create new secret key」をクリックします。すると、「sk-xxxxx」のようなAPIキーが生成されます。なお、APIキーは作成後一度しか表示されないので、必ず、このAPIキーを控えておきましょう。
環境変数にAPIキーを登録しよう
ChatGPTのAPIを呼び出す際、APIキーを指定する必要があるのですが、プログラムの中に直接APIキーを埋め込むのは、セキュリティ的にあまりよくありません。そこで、APIキーを環境変数に登録して利用しましょう。
取得したAPIキーを環境変数「OPENAI_API_KEY」に登録しましょう。
【Windowsの場合】
Windowsであれば、Windowsメニューにある検索ボックスに「システム環境変数の編集」と入力して表示される「システムのプラパティ」で「環境変数」ボタンを押します。そして、「新規」ボタンをクリックし、変数名に「OPENAI_API_KEY」、変数値に「sk-xxxxxxxx」のようなAPIキーを指定します。
【macOSの場合】
macOSであれば、利用しているシェル(デフォルトではZSH)の設定ファイル「.zshrc」などに、以下のような内容を追加します。そして、ターミナルで「source ~/.zshrc」を実行して環境変数を有効にします。
export OPENAI_API_KEY="sk-xxxxxxxxxx"
Go言語のプロジェクトを作成しよう
それでは、プロジェクトを作ってインストールしましょう。OpenAIが公式のGo言語用モジュール「openai-go」を公開しているので、今回利用するモジュールと一緒にインストールします。ただし、「openai-go」は本稿執筆時点のバージョンはv0.1.0-alpha.32です。今後APIに変更があるかもしれないので細かくバージョンを指定しました。
ターミナル(WindowsならPowerShell、macOSならターミナル.app)を起動して、次のコマンドを実行しましょう。
# プロジェクトのフォルダを作成
mkdir go_proof
cd go_proof
# 必要なモジュールをインストール
go mod init go_proof
go get github.com/openai/openai-go@v0.1.0-alpha.32
go get github.com/gin-gonic/gin
go get github.com/yuin/goldmark
今回のプロジェクトでは、次のファイル構造にします。
.
├── go.mod ... (自動で作成される) Goのモジュール管理ファイル
├── go.sum ... (自動で作成される) 同上
├── main.go ... メインプログラム
├── prompt_template.txt ... ChatGPTに指示するテンプレート
└── templates
└── index.html ... HTMLのテンプレート
今回作成したプログラムの一式は、こちらからダウンロードできるようにしています。
プログラムを実行するには、ターミナルで次のコマンドを実行します。
go run .
するとターミナルが起動して、サーバーのURLが表示されます。そこで、ブラウザを起動して、指定されたURL「http://127.0.0.1:8888/」にアクセスします。文章をテキストボックスに入力して、「文章をチェック」ボタンをクリックします。少し待つと、校正内容が表示されます。
なお、ターミナルで下記のコマンドを実行すると、実行ファイルが生成されます。このファイルとプロジェクト一式を配付すれば、Go言語がインストールされていない環境でもプログラムを動かすことができます。
go build
メインプログラム - ChatGPT APIの呼び出し方
最初にメインプログラム「main.go」を作成しましょう。プログラム全体は、上記からダウンロードしたソースをご利用ください。
以下のコードは、ChatGPTのAPIを呼び出す部分です。環境変数として登録した「OPENAI_API_KEY」というキーを読み込んで、APIにアクセスするクライアントを作成します。そして、Chat.Completions.Newメソッドを使ってAPIにアクセスを行います。
// OpenAI APIキーを環境変数か取得する
var apiKey = os.Getenv("OPENAI_API_KEY") // APIキーを読み出す
var aiClient = openai.NewClient(option.WithAPIKey(apiKey)) // APIクライアントを作成
var aiModel = openai.ChatModelGPT4oMini // モデルを指定
// ChatGPTのAPIを呼び出す処理
func askAI(prompt string) string {
ctx := context.Background()
completion, err := aiClient.Chat.Completions.New(ctx, openai.ChatCompletionNewParams{
Messages: openai.F([]openai.ChatCompletionMessageParamUnion{
openai.UserMessage(prompt), // --- ここにユーザープロンプトを指定
}),
Model: openai.F(aiModel), // --- モデルを指定
})
if err != nil {
return "[エラー] " + err.Error()
}
return completion.Choices[0].Message.Content
}
メソッドの名前が長いのでちょっと複雑にも見えますが、APIクライアントのChat.Completions.Newメソッドを一つ呼び出しているだけです。APIに与えるパラメータとして、ChatCompletionNewParamsを与えます。そのパラメータにユーザーのプロンプト(指示文)や利用したいモデルを指定します。
ここでは、openai.ChatModelGPT4oMiniを指定しますが、これは、ChatGPTのモデル「gpt-4o-mini」です。APIの利用料金がこちらに書かれています。本コラム執筆時点で、1000出力トークンあたり0.0006米ドル(≒0.09円)であり非常にリーズナブルです。
メインプログラム - 「gin」でWebサーバーを起動する
次に、Webサーバーを起動するmain関数のコードを見てみましょう。今回は、Go言語のWebフレームワーク「gin」を利用します。このWebサーバーでは、ルートにアクセスがあった時、templatesフォルダ以下にある「index.html」を表示します。
func main() {
// サーバーの設定
router := gin.Default()
// テンプレートファイルをロード
router.LoadHTMLGlob("templates/*")
// ルートにアクセスした時の処理
router.GET("/", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "index.html", nil)
})
…省略…
// サーバーを起動
println("サーバーを起動します: http://" + SERVER_ADDR)
err = router.Run(SERVER_ADDR)
if err != nil {
log.Fatal("サーバー起動に失敗", err)
}
}
メインプログラム - ChatGPTで文書校正を行う
そして、以下のプログラムは、上記のプログラムの「…省略…」にあたる部分のものです。JavaScriptから校正したい文章が送信されてきたときに、JSONで校正内容のテキストを返信している部分です。
// プロンプトテンプレートを読み込む
prompt_tpl := "以下の文章の問題点を指摘してください。\n\n"
prompt_tpl_b, err := os.ReadFile(PROMPT_TEMPLATE_FILE)
if err == nil {
prompt_tpl = string(prompt_tpl_b)
}
prompt := prompt_tpl + "```\n" + requestBody.Text + "\n```\n"
// AIに質問
responseText := askAI(prompt)
print(responseText)
// HTMLに変換する
var html bytes.Buffer
if err := goldmark.Convert([]byte(responseText), &html); err != nil {
panic(err)
}
ctx.JSON(http.StatusOK, gin.H{"result": html.String()})
上記のコードでは、単に文章をChatGPTに送信するのではなく、文章の問題点を指摘するように、テンプレートとなるプロンプトをファイルから読み込んで、校正したい文章をその下にくっつけて送信します。
HTMLファイル「index.html」
templatesフォルダの下に、index.htmlというHTMLファイルを用意しました。このファイルには、テキストボックスを配置して、送信ボタンを押すと、Go言語で起動したローカルサーバーの「/check」に文章をポストして、校正結果をHTMLに表示するというものです。
<h1>AI文書校正ツール</h1>
<div>
<textarea id="edit" name="text" rows="10" cols="50"></textarea>
<br><button id="checkButton">文章をチェック</button>
</div>
<div id="ai"></div>
<script>
…省略…
const edit = document.getElementById("edit")
const aiDiv = document.getElementById("ai")
…省略…
fetch("/check", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({ text: edit.value })
})
.then(response => response.json())
.then(data => {
aiDiv.innerHTML = data.result
})
…省略…
</script>
ChatGPTに与えるプロンプト「prompt_template.txt」
そして、ChatGPTに送信するプロンプトですが、校正を依頼する指示文をテキストファイル「prompt_template.txt」に用意しました。このテンプレートに文章をくっつけて送信します。次のような内容となっています。
### 指示: