LINE Botと雑談APIを使って、会話Botを作ってみました。
##雑談対話APIとは
docomoさんが提供している自然な会話・雑談を実現するためのAPIです。
ユーザが入力した発言に対して、APIから返事がレスポンスされます。
https://dev.smt.docomo.ne.jp/?p=docs.api.page&api_name=dialogue&p_name=api_usage_scenario
ユーザの何気ない一言にバリエーション豊富な応答を返す、コンピュータと雑談を楽しむことができるAPIです。雑談対話APIはユーザのどんな発話に対しても必ず応答します。
##docomo Developer supportへの登録
雑談対話APIを使用するために、開発者登録を行います。
- docomo Developer support へようこそ
https://dev.smt.docomo.ne.jp/?p=login
登録完了後、APIの利用申請を行いますが、申請後即使用可能になりました。とても便利
(ちなみに法人情報の入力を勧められますが、入力しなくても問題なく使えました。APIリクエスト数が個人ユーズの範囲を越える(Botを一般公開する、など)する時は、入力したほうが良いのかも・・・と思っています。)
##Heroku環境のセットアップ
先にBotを動かすインフラをセットアップします。今回はHerokuにPHPの環境を作りました。
- PHP on Heroku
https://devcenter.heroku.com/categories/php
アプリを作成したら、「Fixie」というアドオンをインストールします。
$ heroku addons:create fixie:tricycle
Static IP addresses for outbound requests
##BOT API Trial Accountへの登録
LINE Bot APIの開発者登録をします。先着10,000名とのことですが、4/11時点では問題なく登録可能でした。
https://business.line.me/ja/products/4/introduction
特に審査期間もなく、登録後はすぐにAPIを使用することができます。
##BOT APIの設定
###Basic information
callback URL
は、https://(HerokuアプリのURL):443/callback
を設定します。
###Server IP Whitelist
先ほどセットアップしたHerokuアプリに戻ります。ダッシュボードからFixieをクリック。
Outbound IPsの値を、LINE BotのServer IP Whitelistに転記します。
##環境変数の設定
Herokuアプリに戻って、LINE Botのパラメータを設定します。
##ソースコード
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Symfony\Component\HttpFoundation\Request;
$app = new Silex\Application();
$app->post('/callback', function (Request $request) use ($app) {
$client = new GuzzleHttp\Client();
$body = json_decode($request->getContent(), true);
foreach ($body['result'] as $msg) {
$reply_message = chat($msg['content']['text']);
$resContent = $msg['content'];
$resContent['text'] = $reply_message;
$requestOptions = [
'body' => json_encode([
'to' => [$msg['content']['from']],
'toChannel' => 1383378250, #Fixed value
'eventType' => '138311608800106203', #Fixed value
'content' => $resContent,
]),
'headers' => [
'Content-Type' => 'application/json; charset=UTF-8',
'X-Line-ChannelID' => getenv('LINE_CHANNEL_ID'),
'X-Line-ChannelSecret' => getenv('LINE_CHANNEL_SECRET'),
'X-Line-Trusted-User-With-ACL' => getenv('LINE_CHANNEL_MID'),
],
'proxy' => [
'https' => getenv('FIXIE_URL'),
],
];
try {
$client->request('post', 'https://trialbot-api.line.me/v1/events', $requestOptions);
} catch (Exception $e) {
error_log($e->getMessage());
}
}
return 'OK';
});
$app->run();
function chat($send_message) {
// docomo chatAPI
$api_key = 'your docomoAPI key';
$api_url = sprintf('https://api.apigw.smt.docomo.ne.jp/dialogue/v1/dialogue?APIKEY=%s', $api_key);
$req_body = array('utt' => $text);
$req_body['context'] = $send_message;
$headers = array(
'Content-Type: application/json; charset=UTF-8',
);
$options = array(
'http'=>array(
'method' => 'POST',
'header' => implode("\r\n", $headers),
'content' => json_encode($req_body),
)
);
$stream = stream_context_create($options);
$res = json_decode(file_get_contents($api_url, false, $stream));
return $res->utt;
}
##動作結果
_人人人人人人人人人_
> 会話にならない <
 ̄Y^Y^Y^Y^Y^Y^Y^Y ̄
##実装修正(2016.05.10追記)
2回目以降の会話にはcontext
をリクエスト指定しないといけないとご指摘頂きました。
雑談会話APIからレスポンスされるcontext
をRedisに保存して使用します。
(参考記事: LINE Botとおしゃべりする。http://qiita.com/tkitauji/items/0e1d25bc55c7ea6dcfed )
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Symfony\Component\HttpFoundation\Request;
$app = new Silex\Application();
$app->post('/callback', function (Request $request) use ($app) {
$client = new GuzzleHttp\Client();
$body = json_decode($request->getContent(), true);
foreach ($body['result'] as $msg) {
// get from and message
$from = $msg['content']['from'];
$message = $msg['content']['text'];
// get context from Redis
$redis = new Predis\Client(getenv('REDISTOGO_URL'));
$context = $redis->get($from);
// chat API
$response = chat($message, $context);
// save context to Redis
$redis->set($from, $response->context);
$res_content = $msg['content'];
$res_content['text'] = $response;
$requestOptions = [
'body' => json_encode([
'to' => [$from],
'toChannel' => 1383378250, #Fixed value
'eventType' => '138311608800106203', #Fixed value
"content" => $res_content,
]),
'headers' => [
'Content-Type' => 'application/json; charset=UTF-8',
'X-Line-ChannelID' => getenv('LINE_CHANNEL_ID'),
'X-Line-ChannelSecret' => getenv('LINE_CHANNEL_SECRET'),
'X-Line-Trusted-User-With-ACL' => getenv('LINE_CHANNEL_MID'),
],
'proxy' => [
'https' => getenv('FIXIE_URL'),
],
];
try {
$client->request('post', 'https://trialbot-api.line.me/v1/events', $requestOptions);
} catch (Exception $e) {
error_log($e->getMessage());
}
}
return 'OK';
});
$app->run();
function chat($message, $context) {
$api_key = 'your docomoAPI key';
$api_url = sprintf('https://api.apigw.smt.docomo.ne.jp/dialogue/v1/dialogue?APIKEY=%s', $api_key);
$req_body = array(
'utt' => $message,
'context' => $context,
);
$req_body['context'] = $message;
$headers = array(
'Content-Type: application/json; charset=UTF-8',
);
$options = array(
'http'=>array(
'method' => 'POST',
'header' => implode("\r\n", $headers),
'content' => json_encode($req_body),
)
);
$stream = stream_context_create($options);
$res = json_decode(file_get_contents($api_url, false, $stream));
return $res->utt;
}
会話できました!!
結構たのしい。
##その他改善策
- 雑談対話(認証あり)を使う
https://dev.smt.docomo.ne.jp/?p=docs.api.page&api_name=dialogue&p_name=api_2#tag01
アカウント認証をすることで、より精度の高い対話をすることができるようです。
雑談対話APIにdアカウントによるユーザ認証・許可を実施することで、よりユーザの趣味嗜好に基づいた応答が可能となります。
- シナリオ対話APIを使用する
https://dev.smt.docomo.ne.jp/?p=docs.api.page&api_name=scenario_dialogue&p_name=api_usage_scenario
あらかじめ用意したシナリオに沿って対話ができるようです。(パターン考えるの大変そう・・・)
##Fixieについて
tricycleプランだと、500req/月まで無料のようです。
たくさん会話したい時は課金しないとですね...
##まとめ
今回は半分ネタで会話Botを作ってみましたが、LINE BotとREST APIの相性は抜群で、アイディア次第でいろんなことができそうだなーと手応えを感じました。
##参考URL
先人のみなさま、大変参考になりました。ありがとうございました。。!
- LINE BOT をとりあえずタダで Heroku で動かす
http://qiita.com/yuya_takeyama/items/0660a59d13e2cd0b2516 - PHP+HerokuでLINE BOT作ってみた
http://qiita.com/qckanemoto/items/7c148fcc595cec4aa59a - docomo 雑談対話 API をさくっと php で使う
https://gist.github.com/wokamoto/c0195e0edc9abbac584b#file-docomo_dialogue_api-php