読者です 読者をやめる 読者になる 読者になる
pixiv insideは移転しました! ≫ http://inside.pixiv.blog/

LINE Botをサーバーレスで開発!Google Apps ScriptとLINE Messaging APIを使ってチャットボットを作ってみた

f:id:tamanobi:20161110224848p:plain

こんにちは、今年4月に入社した新卒エンジニアのyasuです。pixivのメンテナンスチームでPHPを書いています。好きな言語はLispです。

本記事では、最近大流行中の人工知能を利用したチャットボットの開発について紹介します。

チャットボットが作れるAPIをLINEが提供

最近は機械学習の分野の進展が目まぐるしく、人との会話から任務を遂行するチャットボットが徐々に増えてきています。FacebookやSlackだけでなく、LINEがチャットボットを開発できるAPIを提供し始めました。

LINEは以前から、LINE@やLINE Bot APIを提供しており、事業者向けサービスを拡充しています。総務省の調査(総務省|平成27年版 情報通信白書|SNSの利用率)によると、10代と20代のLINE利用率は約63%と非常に高いです。LINE@のような事業者向けサービスが浸透しつつあることにも納得できます。

LINE@を利用すると、ビジネスアカウントとしてユーザと手動で会話することができます。たくさんのユーザがいる場合には、手動で対応できません。これをプログラムによって自動返信できるAPIが今回利用するLINE Messaging APIです*1

開発した簡単なチャットボットとの会話

開発したチャットボットは、雑談機能と「***って何?」って聞くとWikipediaを検索して記事を紹介する機能を持っています。

LINE Botを作るために必要なもの

f:id:tamanobi:20161110204133p:plain

最低限、LINEで動くチャットボットを作るには、以下の3つが必要です。

BusinessアカウントはMessaging APIのご紹介 | LINE Business Centerから登録して作成できます。登録解説ページ(英)があるので、そちらを参考に作成してください。

今回は、Google Apps Script(GAS)を利用してサーバとプログラムを用意します。Googleアカウントを持っていれば簡単にサーバが用意できるので、おすすめです。

Google Apps Script(GAS)でサーバーレスな開発

GASはいくつか関数を用意すると、PaaSのようにウェブサーバとして利用することができます。LINE Messaging APIを利用するには、ユーザからのメッセージを受け取るサーバーを用意する必要があります。このサーバを、GASで用意してWebhook URLとして設定していきます。

超簡単なウェブサーバを作ってみる

GASを使うと3行でウェブサーバを立てることができます。Google Driveから、Google Apps Scriptを作成します。エディタが立ち上がるので、GETリクエストを受け付けるために次のコードを書きます。 f:id:tamanobi:20161110131519p:plain

function doGet() {  
    return ContentService.createTextOutput('ハロー');
}

このサーバーへリクエストを投げるには、「公開」メニューから「Webアプリケーションとして公開」を選択して、表示されるURIをコピーしておきます。 URIへアクセスすると、ハローと気さくにGASがレスポンスを返してくれることが確認できます。

f:id:tamanobi:20161110203458p:plain

ここでコピーしたURIは、LINE Messaging APIに登録する必要があるのでどこかに保存しておいて下さい。

さっそくチャットボットを作ってみる

用意したサーバ(GAS)と、LINE Messaging APIを連携させて、実際にチャットボットを開発していきます。

LINE Messaging APIとGASの連携

LINE Business Centerから、アカウントリストを開いてLINE Messaging APIを有効にします。用意したサーバのURIをWebhook URLとして登録します。これで連携は完了です。

加えて、設定画面にあるQRコードを使って友達になっておいてください。

チャットボットの基礎:オウム返しをさせてみる

f:id:tamanobi:20161110212218p:plain

最も簡単なチャットボットは、ユーザのメッセージをそのままオウム返しする実装です。これはLINE Messaging APIの返すレスポンスさえわかっていれば、30行ほどで簡単に実装できます。

サーバ側のGASを以下のように変更してオウム返しを試してみます。LINE Messaging APIは、POSTメソッドでデータを送ってくるのでdoGetではなくdoPostを使います。CHANNEL_ACCESS_TOKENには、LINE Messaging APIのChannel Access Tokenをそのまま貼り付けて下さい。

var CHANNEL_ACCESS_TOKEN = 'YOUR_CHANNEL_ACCESS_TOKEN';


function doPost(e) {
  var reply_token= JSON.parse(e.postData.contents).events[0].replyToken;
  if (typeof reply_token === 'undefined') {
    return;
  }
  var user_message = JSON.parse(e.postData.contents).events[0].message.text;
  
  var url = 'https://api.line.me/v2/bot/message/reply';
  UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'replyToken': reply_token,
      'messages': [{
        'type': 'text',
        'text': user_message,
      }],
    }),
  });
  return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}

このプログラムをサーバに反映させるために、設定します。次の動画を参考にしてください。

チャットボットとオウム返しを楽しんでみる

これで、チャットボットの基礎ができました。

チャットボットともっと楽しく会話するために、いろんな機能を追加してみる

オウム返しボットはあまり興味が長続きしないので、簡単に使える人工知能ボットAPIを使ってみます。

f:id:tamanobi:20161110224848p:plain

簡単に扱える全自動会話APIを使って雑談してみる

続いて、Botと会話するために人工知能ボットAPIを活用します。このAPIは、株式会社ユーザーローカルが提供していて、利用申請をすることで利用できます。利用申請後に届くメールにCHAT_BOT_ACCESS_TOKENが載っています。

下のコードをGASに貼り付けて、さきほどの動画のようにデプロイ作業をすることで、全自動会話APIを試すことができます。

var CHANNEL_ACCESS_TOKEN = 'YOUR_CHANNEL_ACCESS_TOKEN';
var CHAT_BOT_ACCESS_TOKEN = 'YOUR_CHAT_BOT_ACCESS_TOKEN';
var chat_endpoint = 'https://chatbot-api.userlocal.jp/api/chat';
var line_endpoint = 'https://api.line.me/v2/bot/message/reply';


function doPost(e) {
  var reply_token = JSON.parse(e.postData.contents).events[0].replyToken;
  if (typeof reply_token === 'undefined') {
    return;
  }
  var user_message = JSON.parse(e.postData.contents).events[0].message.text;
  
  var res = UrlFetchApp.fetch(
    chat_endpoint + '?key=' + encodeURIComponent(CHAT_BOT_ACCESS_TOKEN) + '&message=' + encodeURIComponent(user_message)
  );
  var replay_text = JSON.parse(res).result;
  
  UrlFetchApp.fetch(line_endpoint, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'replyToken': reply_token,
      'messages': [
        {'type': 'text', 'text': replay_text},
      ],
    }),
  });
  return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}

チャットボットを少し便利に!Wikpedia検索機能を追加してみる

会話に飽きてきたので、チャットボットをもっと便利にしてみます。「***って何?」って聞くと答えてくれたら便利ですね。ここでは、質問に対して該当するWikipediaの記事を拾ってきて紹介してくれるように改造してみます。 f:id:tamanobi:20161110232840p:plain

ユーザーローカルWikipedia API

株式会社ユーザーローカルが提供しているユーザーローカルWikipedia API - ウィキペディア情報をサイトで利用できるAPIを使います。このAPIは認証や登録が必要なく便利です。レスポンス形式もXMLやJSONほか多くの形式に対応しているため、ちょっとした開発に重宝します。例えば、http://wikipedia.simpleapi.net/api?keyword=Wikipedia&output=xmlへアクセスすると、「Wikipedia」という記事データがXMLで返ってきます。

このチャットボット開発では、扱いが簡単なJSON形式でレスポンスを受け取っています。下のコードをGASに貼り付けてデプロイ作業をすると、Wikipedia検索機能を使うことができます。

var CHANNEL_ACCESS_TOKEN = 'YOUR_CHANNEL_ACCESS_TOKEN';
var CHAT_BOT_ACCESS_TOKEN = 'YOUR_CHAT_BOT_ACCESS_TOKEN';
var chat_endpoint = 'https://chatbot-api.userlocal.jp/api/chat';
var line_endpoint = 'https://api.line.me/v2/bot/message/reply';
var simple_wikipedia_api = 'http://wikipedia.simpleapi.net/api';

function doPost(e) {
  var reply_token= JSON.parse(e.postData.contents).events[0].replyToken;
  if (typeof reply_token === 'undefined') {
    return;
  }
  var user_message = JSON.parse(e.postData.contents).events[0].message.text;
  
  var reply_messages = ['ごめん。わからなかった…'];
  if (/って(なに|何)??$/.test(user_message)) {
    var q = user_message.match(/(.*)って(なに|何)??$/)[1];
    var url_and_body = getWikipediaUrlAndBody(q);
    if (url_and_body !== null) {
      reply_messages = [
        '説明しよう! ' + q + 'とは!',
        url_and_body.body.substr(0, 140) + '...',
        '続きは',
        url_and_body.url,
      ];
    }
  } else {
    var res = UrlFetchApp.fetch(
      chat_endpoint + '?key=' + encodeURIComponent(CHAT_BOT_ACCESS_TOKEN) + '&message=' + encodeURIComponent(user_message)
    );
    reply_messages = [JSON.parse(res).result];
  }
  
  var messages = reply_messages.map(function (v) {
    return {'type': 'text', 'text': v};
  });
  
  UrlFetchApp.fetch(line_endpoint, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'replyToken': reply_token,
      'messages': messages,
    }),
  });
  return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}

function getWikipediaUrlAndBody(q) {
  var url = simple_wikipedia_api + '?keyword=' + encodeURIComponent(q) + '&output=json';
  var res = JSON.parse(UrlFetchApp.fetch(url));
  if (res !== null) {
    return {‘url’: res[0].url, ‘body’: res[0].body};
  } else {
    return null;
  }
}

まとめ

f:id:tamanobi:20161111001907p:plain

GASとLINE Messaging APIを利用したサーバーレスなチャットボット開発の流れを紹介しました。ここまでの工程で冒頭で紹介したチャットボットと同じ機能が実装できています。この記事では、詳細は立ち入りませんでしたが、興味のある人は、以下のGoogle Apps ScriptやLINE Messaging APIのリファレンスを参照してみてください。

宣伝

WEB+DB PRESS Vol.95に「PHPの静的解析」という記事を8ページ書きました。コードを解析してメンテナンスに利用する内容となっています。書店でみかけたら手にとってみてください!