2023年3月2日 に OpenAI から ChatGPT の API モデル gpt-3.5-turbo が公開されました。
今回は弊社の Mattermost に ChatGPT Bot 専用チャンネル を作成し、適当な会話を楽しんでいこうと思います!
使用するAPIの概要
https://platform.openai.com/docs/api-reference/chat
ChatAPI の gpt-3.5-turbo は、以前までの 4つの自然言語モデルAPI よりも使いやすくなっており、インプットするパラメータが少なく、手軽に使えるものとなっていました。
{
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "user",
"content": "Hello!"
}
]
}
モデルを指定し、メッセージのリストを設定することで、過去の文脈を踏まえた文章を生成してくれます。
ChatAPI モデルには gpt-3.5-turbo-0301 と gpt-3.5-turbo がありますが、今回は gpt-3.5-turbo を使って実装しました。
role にはいくつか種類がありますが、投稿者を user に Bot が生成した文章を assistant とすることで一般的な会話が楽しめます。
実装構成
今回実装した Bot の構成図です。
各手順としては以下の通りです。
1. Mattermost のチャンネルからメッセージを投稿
2. Mattermost の 外向きwebhook で Google App Script(GAS) へ送信
3. GAS で履歴を読み込み
4. 履歴と送信メッセージをもので ChatGPT のAPIを実行
5. 実行結果を GoogleSpreadsheet に保存
6. GAS から 内向きWebhook で Mattermost に返却
実装
Mattermost で Bot 用チャンネルを作成し、 内向きWebhook を作成します
BOT用のチャンネルを用意したら 統合機能 から 内向きWebhook を選択し、各種設定を行います
内向きWebhook の設定では以下を求められるので、それぞれ入力します。
- タイトル: 任意のタイトル
- 説明: 任意
- チャンネル: チャンネルは Bot 用に作ったものを選択します
- このチャンネルに固定する: 任意
- ユーザー名: Bot が投稿する際の名前の設定
- プロフィール画像: Bot が投稿する際の Icon の設定
入力を保存すると URL が発行されますが、GAS のコード内でこの URL を使います。
※システムコンソールから統合機能管理を開き「内向きのウェブフックを有効にする」と「外向きのウェブフックを有効にする」を有効にしてください。
※システムコンソールから統合機能管理を開き「統合機能によるユーザー名の上書きを許可する」と「統合機能によるプロフィール画像アイコンの上書きを許可する」を有効にしてください。
GAS から コールバックURL を発行します
GAS に以下のコードを書き込みます。
OpenAI の APIキー 等は以下を参考に取得出来ます。
OpenAPI の APIキー と 内向きWebhook の URL を各変数に割り当てます。
// openAIApi.gs
class OpenAIAPI {
constructor (api_key, organization){
this.api_key = api_key;
this.organization = organization;
}
getModels(){
const url = "https://api.openai.com/v1/models";
const options = {
"headers": {
'Authorization': 'Bearer ' + this.api_key,
'OpenAI-Organization': this.organization
}
}
return UrlFetchApp.fetch(url,options);
}
textChatCompletions(messages){
const url="https://api.openai.com/v1/chat/completions"
const payload = {
"model": "gpt-3.5-turbo",
"messages": messages,
}
const options = {
"headers": {
'Authorization': 'Bearer ' + this.api_key,
'Content-Type': 'application/json',
},
"payload": JSON.stringify(payload)
}
return UrlFetchApp.fetch(url, options);
}
}
// main.gs
// OpenAiのApi情報その他
const API_KEY = 'OpenAIのAPIkey';
const ORGANIZATION = 'OpenAIのORGANIZATION';
function chatHistoryWriter(role, content){
const id = "スプレッドシートのID";
const spreadSheet = SpreadsheetApp.openById(id);
const sheetName = "履歴シートの名前";
spreadSheet.getSheetByName(sheetName).appendRow(
[new Date(), role, content]
);
}
function chatHistoryReader(){
const id = "スプレッドシートのID";
const spreadSheet = SpreadsheetApp.openById(id);
const sheetName = "履歴シートの名前";
const sheetChatHistory = spreadSheet.getSheetByName(sheetName)
try{
const range = sheetChatHistory.getRange(1, 2, sheetChatHistory.getLastRow(), sheetChatHistory.getLastColumn());
return range.getValues()
}catch{
return []
}
}
function mattermostSendMessage(text, url){
const payload = {
"text": text,
}
const options = {
"headers": {
'Content-Type': 'application/json',
},
"payload": JSON.stringify(payload)
}
UrlFetchApp.fetch(url, options);
}
function jpChat(text){
// 内向きhookURL日本語
const jpURL = "内向きWebhookのurl"
// 履歴読み込み
const chatHistory = chatHistoryReader()
const inputText = {"role": "user", "content": text}
const messages = []
chatHistory.forEach(v=>{
messages.push({"role": v[0], "content": v[1]})
})
messages.push(inputText)
// openai初期化
const openAIAPI = new OpenAIAPI(API_KEY, ORGANIZATION);
// chatApi実行
const response = openAIAPI.textChatCompletions(messages)
const responseJson = JSON.parse(response.getContentText())
const responseMessage = responseJson["choices"][0]["message"]
// 履歴書き込み
chatHistoryWriter(inputText["role"], inputText["content"])
chatHistoryWriter(responseMessage["role"], responseMessage["content"])
// mattermostへの送信
mattermostSendMessage(responseMessage["content"], jpURL)
}
// コールバックで呼び出される関数
function doPost(e) {
const params = JSON.stringify(e);
const json = JSON.parse(params)
const contents = json["parameters"]
const text = contents["text"][0]
const channel_name = contents["channel_name"][0]
// 会話処理実行
jpChat(text)
}
GAS にて上記のコードを入力した後、デプロイボタンを押すことでURLが発行されます
※デプロイ時、「アクセスできるユーザー」を「全員」としなければ Mattermost 側からのコールバックを受け取れないので注意してください
Mattermost で 外向きWebhook の設定をします。
外向きWebhook の設定では以下を求められるので、それぞれ入力します
- タイトル: 任意のタイトル
- 説明: 任意
- チャンネル: チャンネルは Bot 用に作ったものを選択します
- コンテントタイプ: application/json
- トリガーワード(1つにつき1行): なし
- トリガーとなる条件: 最初の単語がトリガーワードと正確に一致する
- このチャンネルに固定する: 任意
- コールバックURL(1つにつき1行): GAS のコードデプロイ時の URL を記入
- ユーザー名: なし
- プロフィール画像: なし
上記入力後保存します、以上で実装は完了です。
Mattermost で Bot と会話を楽しむ
「卵を使った料理」について聞いてみました。
2回目の「魚と組み合わせた料理」のオススメを聞いたのは、「卵と組み合わせて」という意味だったのですが、そこは察してくれませんでした。
3回目は「魚と卵を組み合わせた料理」と指定して聞きました。
魚と卵を組み合わせた料理ってあまり聞かないのですが、しっかり答えてくれました。
フィズバズのコードを書いてもらいました。
噂通りコードも書けるんですね、ChatGPT すごい!
まとめ
ChatGPT Bot を Mattermost に実装してみました。
GAS と ChatGPT だけで優秀な Bot が簡単に実装できました、コードは GAS のみで後は設定を行うだけ!
Mattermost への ChatGPT Bot 実装はこの記事だけでも完結するので、興味のある方は是非試して見てください!