ChatGPTで学習させた人格に公式LINEの返答をさせてみた

# 今回の要望
今回この開発を行った経緯は、寿司屋の大将である愛宕大将さん@shotaatago(Twitter)が、自分のキャラクターを寿司屋の公式LINEの返答に組み込みたいという要望から始まりました。

現在公式LINEを用いて寿司屋の予約などの対応を行なっているが、そのラインの返答をより人間味があり、多様な回答パターンにすることで公式LINEに欠けていた面白さを増そうということになりました。

# 開発の流れ
今回使用するのは主に**OpenAI API**と**LINE Messaging API**です。
OpenAI API: 複雑な顧客からのメッセージにも対応でき、かつより人間味があり多様な回答パターンをAIが生成するため
LINE Messaging API: LINEで送られてきた返答をOpenAI APIに渡し、作成した返答をLINEに返すため

ChatGPTで学習させた人格に公式LINEの返答をさせるための3stepは
1.OpenAI APIを用いて人格を模倣した返答を生成できるようにする。
2.LINE公式アカウントで受信したメッセージをPythonで受け取り、Pythonからの返答をLINE公式アカウントから送信できるようにする。
3.HerokuにPythonファイルをアップロードし、公式LINEとOpenAI APIを連携させる。

## 1. OpenAI APIを用いて人格を模倣した返答の生成
会話の生成に関するコードは以下の方を参考にしました。ここのSettingsを上手く調整し、限りなく本人に近い人格を形成するのが大事です。そのコツなどはまた別で...

https://qiita.com/sakasegawa/items/db2cff79bd14faf2c8e0?utm_source=Qiita%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%B9&utm_campaign=dc32590542-Qiita_newsletter_557_03_15_2023&utm_medium=email&utm_term=0_e44feaa081-dc32590542-34369149#%E4%BC%9A%E8%A9%B1%E3%82%92%E8%A1%8C%E3%81%86

ここで調整ができたら次のステップに行きます。

## 2. LINE公式アカウントの設定
LINE Messaging APIを用いるためにLINE Developers Consoleにログインします。アカウントを作成していない方はここでアカウントを作成する必要があります。

https://developers.line.biz/console/

そして今回はMessaging APIを用いるので、LINE Developersでプロバイダー作成をしてください。わかりやすい紹介をしてくださっている方がいたので以下を参考にしてみてください。

https://qiita.com/kuma_ssss/items/71ed5ffb3596abffbb29#%E6%96%B0%E8%A6%8F%E7%99%BB%E9%8C%B2%E3%81%8B%E3%82%89%E8%A8%AD%E5%AE%9A%E3%81%BE%E3%81%A7%E3%81%AE%E6%B5%81%E3%82%8C

このLINE Developersから必要となってくるのは、**CHANNEL_ACCESS_TOKEN**と**CHANNEL_SECRET**なのでこれらがどこにあるか確認しておいてください。

Message APIの仕組みは、LINE公式アカウントでメッセージを貰うと設定したURLに対して、JSONデータをPOSTで送ってくれることになっています。そのJSONデータ内に、どのユーザーから来たどのようなメッセージかなどのデータが保管されています。

https://developers.line.biz/ja/reference/messaging-api/

## 3.公式ラインとOpenAIを繋ぐために
あとは公式ラインで送られたメッセージを、ステップ１で作成したOpenAIの関数に渡し、出てきたアウトプットを公式ラインで返答させるだけです！

ここで非常に役立ったのが以下の方のQittaです！(マジで感謝)

https://qiita.com/yuu-eguci/items/1a572d83d3faf306ed08

Herokuに作成したPythonファイルを置き、公式ラインからはそこへPOSTリクエストをするように設定させます。その設定はLINE Developers Consoleでします。Webhook URLという欄にHerokuで作成したURLを記載します。

## コード

```Python:ailinebot.py
from flask import Flask, request, abort

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)

import openai

# 環境変数取得のため。
import os

# ログを出力するため。
import logging
import sys

app = Flask(__name__)

# ログを標準出力へ。heroku logs --tail で確認するためです。
# app.logger.info で出力するため、レベルは INFO にする。
app.logger.addHandler(logging.StreamHandler(sys.stdout))
app.logger.setLevel(logging.INFO)

# 大事な情報は環境変数から取得。
# CHANNEL_ACCESS_TOKEN = os.environ['']
# CHANNEL_SECRET = os.environ['']

CHANNEL_ACCESS_TOKEN = ''
CHANNEL_SECRET = ''
openai_key = ""

line_bot_api = LineBotApi(CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(CHANNEL_SECRET)

openai.api_key = openai_key
def completion(new_message_text:str, settings_text:str = '', past_messages:list = []):
    """
    This function generates a response message using OpenAI's GPT-3 model by taking in a new message text, 
    optional settings text and a list of past messages as inputs.

    Args:
    new_message_text (str): The new message text which the model will use to generate a response message.
    settings_text (str, optional): The optional settings text that will be added as a system message to the past_messages list. Defaults to ''.
    past_messages (list, optional): The optional list of past messages that the model will use to generate a response message. Defaults to [].

    Returns:
    tuple: A tuple containing the response message text and the updated list of past messages after appending the new and response messages.
    """
    if len(past_messages) == 0 and len(settings_text) != 0:
        system = {"role": "system", "content": settings_text}
        past_messages.append(system)
    new_message = {"role": "user", "content": new_message_text}
    past_messages.append(new_message)

    result = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=past_messages
    )
    response_message = {"role": "assistant", "content": result.choices[0].message.content}
    past_messages.append(response_message)
    response_message_text = result.choices[0].message.content
    return response_message_text, past_messages

system_settings = """ここに人格形成のために設定を組み込む"""

# 必須ではないけれど、サーバに上がったとき確認するためにトップページを追加しておきます。
@app.route('/')
def top_page():
    return 'Here is root page.'


# ユーザがメッセージを送信したとき、この URL へアクセスが行われます。
@app.route('/callback', methods=['POST'])
def callback_post():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info('Request body: ' + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)

    return 'OK'

#メッセージを送る
@handler.add(MessageEvent, message=TextMessage)
def reply_message(event):
    new_message, messages = completion(event.message.text, system_settings, [])
    # reply のテスト。
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=new_message))


if __name__ == '__main__':
    app.run()

```

と、かなり雑になってしまいましたが、どなたかの参考になれば幸いです。基本的に自分がどうやったかのメモ程度に残すようなのでわかりづらいところは申し訳ありません。

### 詰まったところメモ
・Herokuにアップロードした際にアプリケーションエラーが発生した
・AI人格形成の際の細かいニュアンスの伝え方はかなり器用にする必要がある

### さらにやりたいこと
・会話履歴を踏まえた会話
・リアルタイム情報を含めた会話
・よりビジネスに繋げるための会話の流れ等の構築
・さらにリアルな返答の構築
・このモデルのニーズのある場所の模索