【個人開発】ChatGPTをchatworkに連携。メッセージ自動返信ツールを作る


# 制作物
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2519192/b052c7b9-3c3f-11dc-ddbd-0e465ba4c72a.png)
画像のように、質問したら自動で回答してくれるメッセージツールを作ります。

# 技術スタック
- chatGPT
- chatwork
- Google App Script

## 関係図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2519192/406197a1-7ec8-d3eb-36ed-a2257fd52ad2.png)
1. webhookで自分宛メッセージが来たら、Google App Scriptに通知する。
2. Google App Scriptは受け取ったデータを、chatGPTに送信
3. chatGPTが回答を生成
4. chatGPTからGoogle App Scriptへレスポンスを送信
5. Google App ScriptからChatworkへ回答を送信

# Open AI のAPIを使って文章を自動生成

APIキーを発行し、エンドポイントにPOSTメソッドでBearer認証をリクエストする。

### APIキーの発行
https://platform.openai.com/account/api-keys
「Create new secret key」で発行される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2519192/adc03506-ef7e-65c5-0ca4-0db7021e0fe1.png)



```javascript: useOpenAiApi.gs
function requestCompletion(_prompt) {
  //スクリプトプロパティに設定したOpenAIのAPIキーを取得
  const apiKey = ScriptProperties.getProperty('APIKEY');
  //文章生成AIのAPIのエンドポイントを設定
  const apiUrl = 'https://api.openai.com/v1/completions';
  //文章生成AIに投げるテキスト(プロンプト)を定義
  const prompt = _prompt;
  //OpenAIのAPIリクエストに必要なヘッダー情報を設定
  let headers = {
    'Authorization': 'Bearer ' + apiKey,
    'Content-type': 'application/json',
    'X-Slack-No-Retry': 1
  };
  //文章生成で利用するモデルやトークン上限、プロンプトをオプションに設定
  let options = {
    'muteHttpExceptions': true,
    'headers': headers,
    'method': 'POST',
    'payload': JSON.stringify({
      'model': 'text-davinci-003',
      'max_tokens': 1024,
      'temperature': 0.5,
      'prompt': prompt
    })
  };
  //OpenAIの文章生成(Completion)にAPIリクエストを送り、結果を変数に格納
  const response = JSON.parse(UrlFetchApp.fetch(apiUrl, options).getContentText());
  //OpenAIのAPIレスポンスをログ出力
  console.log(response.choices[0].text);
  return response.choices[0].text;
}
```

# chatwork側の設定

## ①chatwork APIトークンの取得
https://www.chatwork.com/service/packages/chatwork/subpackages/api/token.php
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2519192/efa01ff6-a1bf-0736-16d1-40896fa4a757.png)

## ②Google App Script と Chatworkの連携
**Chatwork Client**というライブラリを使用
https://github.com/cw-shibuya/chatwork-client-gas
Google App Script スクリプト ID: `1nf253qsOnZ-RcdcFu1Y2v4pGwTuuDxN5EbuvKEZprBWg764tjwA5fLav` 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2519192/f7f3b7dc-99a8-b7aa-3aa5-deaf37aae3a5.png)


```javascript:sendMessage.gs
function sendChatworkMessage(_message, _room_id) {
  //Chatwork API Tokenを定数として定義(自分のAPIトークンをセット)
  const token = '自分のAPIトークン';

  //メッセージを取得したいルームIDを定数として定義
  const room_id = _room_id;
  // ChatworkAPIクライアント作成
  const client = ChatWorkClient.factory({ token: token });
  //チャットワークAPIで投稿するメッセージを設定
  const message = _message;
  //ChatworkAPIクライアントからメッセージ投稿
  client.sendMessage({
    room_id: room_id,
    body: message
  });
}
```

## ③Webhookを設定して、自分宛メッセージを通知する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2519192/59144c21-46bf-99e8-bed3-d598bc19b1d0.png)

Webhookで取得したデータをもとに、回答メッセージを送信。
今回は`room_id` `body`を使用する
|フィールド名|タイプ|必須|説明|
| ---- | ---- | ---- |----|
|from_account_id|数値|◯|メンション元のアカウントID|
|to_account_id	|数値	|◯	|メンション先のアカウントID|
|**room_id**	    |数値	|◯	|**メンションが発生したチャットルームID**|
|message_id	    |文字列	|◯	|メンションが発生したメッセージID|
|**body**	        |文字列	|◯	|**メンションメッセージ本文**|
|send_time	    |数値	|◯	|メッセージの送信時刻（エポック秒）|
|update_time	|数値	|◯	|メッセージの最終編集時刻（エポック秒）|


`doPost.gs` (POSTメソッドで呼び出される)に以下を記述
```javascript:doPost.gs
function doPost(e) {

  try {
    var json = JSON.parse(e.postData.contents);
    var msg_body = json.webhook_event.body;
    var send_time = json.webhook_event.send_time;
    var room_id = json.webhook_event.room_id;
    var from_account_id = json.webhook_event.from_account_id;
    var to_account_id = json.webhook_event.to_account_id;
    var message_id = json.webhook_event.message_id;

    writeSpreadSheet([msg_body, send_time, room_id, from_account_id, to_account_id, message_id]);

    // messageを渡す
    main(msg_body, room_id);

  } catch (error) {
    writeSpreadSheet([error]);
  }

}
```

# 完成！
最後に、`requestCompletion`メソッドと`sendMessage`メソッドをつなげれば
完成！！
```javascript: main.gs
/**
 * @param message, room_id
 */

function main(message, room_id) {
  const createMsg = requestCompletion(message);
  sendChatworkMessage(createMsg, room_id);
}
```

# アレンジ方法
chatGPTに送信するメッセージの先頭に、「カジュアルに答えて:」など追加すると、回答させるメッセージが変わります！


# 参考記事
- [Google Apps Script（GAS）で業務効率化](https://help.chatwork.com/hc/ja/articles/900006202423-Google-Apps-Script-GAS-%E3%81%A7%E6%A5%AD%E5%8B%99%E5%8A%B9%E7%8E%87%E5%8C%96)
- [GASでOpenAIのAPIを利用してChatGPTライクな文章生成する方法を解説](https://auto-worker.com/blog/?p=7007)