GASとOpenAIAPIで好きな人のものまねをしてくれるLINEBOTを作った話

# はじめに
この記事は3か月ほど前にお遊びで作ったLINEBOTについての概要と解説です。記憶を掘り返しながらの執筆になりますので、細かい部分が抜けている可能性もあります、ご了承ください。

一応下のリンクから追加できますのでよかったら遊んでみてください！トーク履歴ファイルを投げてもらうだけで、分析、会話ができます。

あんまし精度は高くないです^^

ちなみにトーク履歴の中身はこちらからは確認できないので安心してください、！（こうするとできちゃうよー！ってのがあれば教えてほしいです😢）
※筆者のOpenAIAPIの残高次第です。

https://lin.ee/SqFD5DmH

ソースコードもGithubに公開してあります。

https://github.com/tsuchidarikuto/monomanelinebot

## 経緯
何か実装の経験が欲しいなと思っていたある日、私のtwitterのタイムラインにこんな記事が流れてきました。

https://x.com/livedoornews/status/1806317222526361846

これを見て私は、「今ならLLMで簡単に作れるんじゃね？」と思い、開発を始めます。

とはいえ、開発の経験もなく、プログラミングの経験も浅い私にとって、仕組みは考えられても実装となるとまた高難易度なものでした。

ちょうど当時、研究のために[Claude](https://claude.ai/new)への課金をしていたところだったので、暗中模索だったところをかなり助けてもらいました。

## 使用技術
- Google Apps Script（以下GAS）
- OpenAI API
- LINE messaging API

## 概要

以下は作成したLINEBOTのシステム構成図になります。
ユーザから送信されたファイルやメッセージをGASを使って処理し、OpenAIAPIを叩いてトークデータの分析や応答の生成を行います。ユーザ情報の管理にはGoogleスプレッドシートを使いました。

![スライド1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3929797/14dc9bc7-3dc8-d5bb-30cd-d77f3226638c.png)

## 開発について
### はじめに
開発にあたり、一旦「linebot ai」の様なクエリで検索をしたところ、下記の様なサイトがヒットし、これを骨組みとすることにしました。LINE　Developersへの登録方法やGASとの連携、OpenAIAPIキーの発行など必要な情報は大体この記事で賄えるかと思います。

https://qiita.com/cog1t0/items/cc7779345a01192d8f01

### GASとLINEbot
上の記事でも紹介がありますが、個人開発でlinebotを作成するのであれば、次の理由でGASの使用を一番にお勧めします。

**1. 環境構築が不要**
JavaScript開発では必須のNode.jsのインストール等、ターミナルでこちょこちょする必要がなく、ブラウザさえあれば開発が可能。 

**2. デプロイが超簡単**
少し見にくいですが、下の画像のようにおおよそ4回のクリックでデプロイからwebhookURLのコピー、Lineとの連携、検証まで一気にできます。
　![スライド2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3929797/9bef660e-8f99-744f-95bb-7e9d6b89b587.png)

**3. サーバーの維持費が基本無料**
ある程度制限はあるものの無料でサーバーを立てることができる。

といった具合ですね。これを作る1か月くらい前にpythonのflaskを使ってバックエンドを実装し、ローカルでサーバを立てて1人で遊びましたが、環境構築~デプロイまでの流れが相当煩雑で、面倒だった記憶があります。

### Open AI API
今回はトーク分析から返答の生成まであらゆる場面でお世話になりました。APIの使用方法についてはあらゆるところで紹介されているので割愛します。公式のrefarenceと、作成したプロンプトだけ貼っておきます。

https://platform.openai.com/docs/api-reference/making-requests
<details><summary>分析用プロンプト</summary>

```javascript
`#命令
-あなたは優秀な言語分析AIです。{#作成したいアプリ}を作るために、{#inputessage}を分析し、{#抽出要素}に従ってJSON形式で出力してください。{#出力形式}に含まれる要素をすべて抽出しなさい。ただし、{#sampledata}はユーザとものまね対象者の会話サンプルです
-特に{#ものまね対象者}が使う一人称の抽出と二人称の抽出に力を注いで
-{#ユーザとの関係}の推測に一番尽力しなさい

#作成したいアプリ
-ユーザーから入力されたファイルをopenaiapiで分析し、その結果を使ってものまねをするlinebot

#抽出要素
-各パラメータの形式は{type}に従うこと.ただし{type}の部分は出力に含めない

＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝
 #全体的な特徴{text}:
 #{ものまね対象者}の一人称{text}:
 #{#ものまね対象者)がユーザを何と呼ぶか（特定できなかった場合はこの行ごと削除する）{text}:
 #1文の長さ{type:number}:
 #ユーザとの関係{text}:
 #特有の語彙{text}:
 #方言の有無、種類{text}:
 #特徴的な語尾{text}(5個):
 #使用するスラング{text}:
 #感情表現の強さ{type:number}:
 #よく使う絵文字、顔文字{type:emoji}:
 #絵文字の頻度(%){type:number}:
 #趣味{text}:
 #楽しいときに使う語尾("笑"or"w"or"(笑)"or null):
 #その他のペルソナ情報:
 #{#ものまね対象者)のセリフ、口調の例:
 #{#ものまね対象者)の行動指針:
＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝`
```
</details>
<details><summary>応答生成用プロンプト</summary>

```javascript
`あなたは${name}です. {#prompt}を参照し、${name}になりきって。
  -必ず#1文の長さ}を出力token数に反映させて。
  -{#使用するスラング}や{#特徴的な語尾}の無理な使用は避け、自然かつ流暢な会話を優先させて
  -{#ユーザとの関係}を十分に考慮した出力にして
  -"BOT:"の様な文字列は出力に含めないで`
   +
"#prompt"+上で作成したプロンプト
   +
会話履歴
```
</details>

### スプレッドシートとの連携
ユーザ別の処理をできるようにしたいなと思い、googleスプレッドシートにユーザの情報を保存する機能を追加しました。各カラムは下の画像のようになっています。
![スライド3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3929797/f101fb30-2a6c-28de-befd-a2109a84ad8e.png)

SQLを触ったことがなく、どうしようなと考えたいたところを助けてもらいました。Excelの様な使用感でやりやすかったです。実装には下の記事を参考にしました。

https://ex-ture.com/blog/2022/12/21/google-app-script%E3%81%A8google%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E3%82%B7%E3%83%BC%E3%83%88%E3%82%92%E9%80%A3%E6%90%BA%E3%81%95%E3%81%9B%E3%82%8B/

### APIキーの保存
GASでは
```javascript
const CHANNEL_ACCESS_TOKEN=PropertiesService.getScriptProperties().getProperty("LINE_TOKEN");
const OPENAI_API_KEY=PropertiesService.getScriptProperties().getProperty("OPENAI_APIKEY");
const SHEET_ID=PropertiesService.getScriptProperties().getProperty("spreadSheetId");
```
のようにすることで、APIキー等公開できない情報を安全に扱うことができます。

これらキーの情報については右側の歯車マークから「スクリプトプロパティ」として見ることができます。
## その他Tips
開発の時に躓いたり、便利だった部分を備忘録的にまとめます。誰かの役に立てたら嬉しいです。

### GASとGithubの連携
GASに拡張機能を入れることで、Githubとの連携が可能になります。私は個人開発だったので不要と言えば不要でしたが作ったものを自分のリポジトリに並べたいという欲があったので使用しました。

調べたらすぐ出てきますが、一応参考にした記事を貼っておきます。

https://sayjoyblog.com/gas_github_connection/

### ログの確認
GASにはコンソールにあたるものがないのでデバッグやエラーの確認が面倒です。私はGoogle Cloud Platform（GCP）のログエクスプローラ機能を使いました。

こんな感じで出力できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3929797/d58de7db-a40b-1802-5733-24335ea1dc6d.png)


当時参照した記事が見当たらなかったので大体同じことが書いてある記事を貼っておきます。

https://qiita.com/sa9ra4ma/items/1acb459fcc713728c03e

ファイルに出力することもできるみたいです。

https://qiita.com/seteen/items/2eb1081f0306b280b804
## 追加したい機能(未定)
- プロンプトインジェクションへの対応
- 分析結果のキャッシュ
- リッチメニュー等を使ったUI/UXの向上
- 返信にかかる時間も分析に含め、会話に反映させる
- 分析対象ごとのアイコン・名前の変更　(理論上多分むり)


## 感想
### LINEbot開発って、調度いい！
まあこの規模の開発だからということもあるのですが、個人的にはフロントエンド回りの実装が、ほぼ不要だったのがありがたかったです。超大手企業であるLINEヤフー様が作ってくださった洗練されたUIのおかげで、デザイン等に頭を抱える時間はゼロでした。おかげでhtmlやreact等の学習に時間を割かずに済みました。

APIに頼ってる分できることは限られるんですけどね。
### 生成AIの使用について
このプロジェクトでは体感6割くらい生成AIに頼りました。ただ、"実装の経験を積む"ことが目標ではあったため
1. Google検索で調べる
1. 生成AIをQiita的な使い方をする
1. それでもわからない部分はコードを書いてもらう

といった具合で生成AIを使いました。[v0](v0.dev/chat)や[cursor](https://www.cursor.com/)、[GithubCopilot](https://github.com/features/copilot)など色んな便利なツールが出てきていますが、「実装の学習」と「AIを使った実装の学習」はなんとなく切り分けた方がいいのかなと思っています。

ただ、「質問する相手」としての生成AIはとても優秀で学習の手助けになるなと感じています。ハルシネーション等の問題もありますが、こちらでファクトチェックをすることもできますし、RAGの進歩によりハルシネーションそのものが少なくなってきたと思っています。

↓　たくさんお世話になりました！

https://www.perplexity.ai/

## 最後に
ここまで読んでくださった方、ありがとうございます！

世の中の誰もがアクセスできるものを作ったのはこれが初めてでした。ですので、セキュリティや権利については、もしかすると「これどうや？」といった部分があるかもしれません。コメントで指摘していただけると幸いです。