プログラムの概要
APIとLINE BOTの組み合わせの簡単なプログラム例として、外部APIを使ってAIとチャットができるLINE BOTを作成します。
上の記事で解説している改良サンプルコードを元にして今回のプログラムを作成しているので、まだ読んでいない方はそちらも参考にしてください。
- チャットAPIと通信を行うプログラムを作成
- 1のプログラムをサンプルコードに組み込み
という流れで作ることになります。
AIとチャットをするプログラムを作成する
LINE BOTのことはひとまず置いといて、まずはAIとチャットをするプログラムを作成します。この部分は今回の解説の本筋ではないので、説明を省略をしている部分があります。APIの基本については、以下の解説も参考にしてください。
APIの仕様を確認する
今回はA3RT(アート)というリクルートが運営しているAIプロジェクトの一つであるTalk APIを利用しています。
仕様を確認すると、
- 認証あり(APIキーによる認証)
- POST通信
であることがわかります。さらに、
https://api.a3rt.recruit-tech.co.jp/talk/v1/smalltalk
というURLにアクセスすれば入力されたテキストに対して応答が返却されることがわかります。
パラメータとして必須なのは、
- apikey(APIキー)
- query(入力テキスト)
の2点のみです。
APIにアクセスするプログラムを作る
それでは早速コードを書いていきましょう。なお、APIにアクセスすると以下のような結果が返ってくることを念頭に置いて作成します。
{'status': 0, 'message': 'ok', 'results': [{'perplexity': 0.06766985185966182, 'reply': 'こんにちは'}]}
※エラーが発生したとき、'results'は存在しません。
import requests
TALKAPI_KEY = 'your-api'
def talkapi(text):
url = 'https://api.a3rt.recruit-tech.co.jp/talk/v1/smalltalk'
req = requests.post(url, {'apikey':TALKAPI_KEY,'query':text}, timeout=5)
data = req.json()
if data['status'] != 0:
return data['message']
msg = data['results'][0]['reply']
return msg
1行目で、サードパーティのHTTPライブラリであるrequestsをimportします。pip等によりインストールもしておきましょう。
3行目でAPIキーを代入します。なお、まだテスト段階ということでAPIキーはコードに直接書いています。セキュリティ上、本番環境では環境変数に設定するなどしてコードには直接書かないのが望ましいので、後半の解説で修正することになります。
5行目から、テキストを入力するとチャットAPIからの返答メッセージを返す関数talkapi()を定義します。
6行目でAPIのURLを設定、
7行目でrequestsライブラリによるPOST通信、
8行目で返ってきたJSON形式のデータを辞書として変換し、変数dataに代入しています。
10~11行目はエラー処理です。今回利用しているTalkAPIでは、エラーが発生したとき返ってくるデータのstatusキーが0以外となるようなので、if文によってmessageキーの値(エラー文)を取得、それをBOTからの返却メッセージとし、そこで処理を終了させます。
requestsライブラリのエラー処理では、try~except文を利用して
try:
req = requests.post(url,data=params)
req.raise_for_status()
except:
...
と書いたり、ステータスコードを取得した上で、
if req.status_code != 200:
return
のように書いて、エラーのときの処理を書くことが多いです。
しかし、今回利用するTalkAPIではステータスコードが200であっても応答テキストが空という場合(ステータスコードは200だがJSON内のstatusキーが0ではなく2000になる)があるようなので、APIから返ってきたデータ内容を元にエラー処理を行っています。
なお、今回は省略しますが、そもそもサーバーダウンによりAPIに繋がらない場合もあると考えられるので、さらにtry~except文などにより
try:
req = requests.post(url, {'apikey':TALKAPI_KEY,'query':text}, timeout=5)
except requests.exceptions.RequestException as e:
return e
と、処理を行うとより丁寧になります。
エラーが発生しなかった場合は、13行目で返却テキストを変数msgに代入し、14行目のreturnにより返り値とします。
Talk APIと通信を行うプログラムとしては、これで完成になります。
APIとの通信プログラムをLINE BOTのサンプルコードに組み込む
では、先ほど作ったプログラムを、以下の記事でも解説しているLINE BOTのオウム返しの改良サンプルコードに組み込んでみましょう。
from flask import Flask, request, abort
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage,
)
import os
import requests
app = Flask(__name__)
TALKAPI_KEY = os.environ['YOUR_API']
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]
line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)
def talkapi(text):
url = 'https://api.a3rt.recruit-tech.co.jp/talk/v1/smalltalk'
req = requests.post(url, {'apikey':TALKAPI_KEY,'query':text}, timeout=5)
data = req.json()
if data['status'] != 0:
return data['message']
msg = data['results'][0]['reply']
return msg
@app.route("/")
def hello_world():
return "hello world!"
@app.route("/callback", methods=['POST'])
def callback():
# 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:
print("Invalid signature. Please check your channel access token/channel secret.")
abort(400)
return 'OK'
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
push_text = event.message.text
msg = talkapi(push_text)
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=msg))
if __name__ == "__main__":
port = int(os.getenv("PORT"))
app.run(host="0.0.0.0", port=port)
追加している行は以下のとおりです。
14行目でrequestsライブラリのimport、
18行目でTalk APIのAPIキーを環境変数として取得・代入(コードとは別にサーバーの環境変数として実際のAPIキーの文字列を設定する必要がある点に注意)、
25行目から34行目にかけて先ほど作った関数talkapi()をそのままコピペ、
58行目からテキストメッセージをユーザーから受け取ったときの処理を書いています。
60行目で、event.message.textによってユーザーから送られたメッセージを取得、変数push_textに代入、
61行目で、関数talk_api()に変数push_textを引数として渡し、APIから返ってきた値をmsgに代入し、
62行目から64行目にかけてのline_bot_api.replay_message()により返却メッセージをBOTからの返信メッセージとして送信します。
これで、APIとLINE BOTを組み合わせてAIとチャットができるLINE BOTのコードが完成しました。
今回は比較的シンプルなコードであったため一つのファイルだけでLINE BOTを作成しましたが、APIとLINE BOTを組み合わせて作るときなど、明確にプログラムが二つ以上の部分に分けられるようなときは、二つ以上のファイルに分けてプログラムを作る方がデバッグやメンテナンスを考えて楽なことが多いです。
例えば、前半に作った以下のコードをapitalk.pyというファイルの中に書いたとき、
import requests
TALKAPI_KEY = 'your-api'
def talkapi(text):
url = 'https://api.a3rt.recruit-tech.co.jp/talk/v1/smalltalk'
req = requests.post(url, {'apikey':TALKAPI_KEY,'query':text}, timeout=5)
data = req.json()
if data['status'] != 0:
return data['message']
msg = data['results'][0]['reply']
return msg
上のコードはそのままで、
from flask import Flask, request, abort
from linebot import (
LineBotApi, WebhookHandler
)
from linebot.exceptions import (
InvalidSignatureError
)
from linebot.models import (
MessageEvent, TextMessage, TextSendMessage,
)
import os
import apitalk
app = Flask(__name__)
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]
line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)
@app.route("/")
def hello_world():
return "hello world!"
@app.route("/callback", methods=['POST'])
def callback():
# 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:
print("Invalid signature. Please check your channel access token/channel secret.")
abort(400)
return 'OK'
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
push_text = event.message.text
msg = apitalk.talkapi(push_text)
line_bot_api.reply_message(
event.reply_token,
TextSendMessage(text=msg))
if __name__ == "__main__":
port = int(os.getenv("PORT"))
app.run(host="0.0.0.0", port=port)
と、LINE BOTの動作部分のPythonファイルを書くことになります。
※14行目でapitalk.pyをインポート
※49行目でapitalk.py内の関数talkapi()を呼び出し
さらに実用的なプログラムへの応用
noteでは、APIとLINE BOTを組み合わせたプロダクトの解説をしております。
今回よりも少し難しい応用編ではありますが、ぜひご覧ください。
ホテル空室検索LINE BOT
レストラン検索LINE BOT
顔偏差値判定LINE BOT