API&LINE BOTの組み合わせ

【API&LINE BOT】人工知能とチャットができるBOTを作ろう!

プログラムの概要

APIとLINE BOTの組み合わせの簡単なプログラム例として、外部APIを使ってAIとチャットができるLINE BOTを作成します。

上の記事で解説している改良サンプルコードを元にして今回のプログラムを作成しているので、まだ読んでいない方はそちらも参考にしてください。

  1. チャットAPIと通信を行うプログラムを作成
  2. 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

楽天APIを利用したホテルの空室検索ができるLINE BOTのプログラミング解説~API&LINE BOT~|みゃふのPythonプログラミング~応用編~|note
急な出張が入った時、ホテルの空き状況をすぐ調べたいと思ったことはありませんか?今は予約サイトやアプリまで充実しているので昔に比べれば随分楽になりましたが、それでもざっくり言って ①スマホを開く ②サイト(アプリ)にアクセスする ③地域や条件を選択し、検索する という3段階の作業が必要になります。特に③が面倒で時間...

レストラン検索LINE BOT

ホットペッパーAPIを利用したレストラン検索ができるLINE BOTのプログラム解説~API&LINE BOT②~|みゃふのPythonプログラミング~応用編~|note
友達とお店を探している時、近くにおいしいごはん屋さんがないかなぁと思ったことはありませんか?その際にスマホを取り出し、『新宿 イタリアン』といった言葉でググる方も多いと思います。が、繁華街だと密集してしまいますし、正直外でお店を検索すること自体、おっくうですよね。もっと直観的に見つけられればいいのですが… 今回ご紹...

顔偏差値判定LINE BOT

顔の偏差値を判定するLINE BOTのプログラミング解説~API&LINE BOT③~|みゃふのPythonプログラミング~応用編~|note
今回はLINEのトークで顔写真を送ると「顔の『偏差値』がわかっちゃう」アプリ(bot)を作ってみようと思います(^_-)-☆ いきなり言われると『?』ってなるかも知れませんが、仕組みとしては人工知能が最近話題の顔認識を自動で行うというものです。その為『美しさ』の精度は何とも言えないところですし、無論悪用は禁物ですが...
タイトルとURLをコピーしました