Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
7
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

Organization

雑談APIを何個か試してみた(Hubot + Chatwork + UserLocal, CotoGoto, Docomo)

はじめに

ChatOpsの手始めとして、ChatBotで会話APIを実装してみました。
・UserLocal 人工知能ボットAPI
・CotoGoto::Noby API
・Docomo 雑談会話API
ChatworkでもSlackでも手順は同じで、hubotのオプションでどちらかを選べばよいだけです。

事前準備

Chat側

  • Chatwork
    bot用のユーザを新規作成し、API申請をする。 APIキーとルームIDを取得
  • Slack登録
    Apps & IntegrationでhubotをインストールしてAPIキーを取得

会話API側

  • UserLocal
    無料登録してAPI Key取得
  • CotoGoto
    無料登録してAPI Key取得
  • Docomo
    色々な機能があるので、最低限の会話APIであれば即API Key発行されますが、
    追加の機能によってはサイトの審査や法人登録が必要です。

サーバ設定(EC2で構築)

モジュール

// 最新のNode.jsを入れるためにNVMから
$ git clone https://github.com/creationix/nvm.git ~/.nvm
$ source ~/.nvm/nvm.sh
$ vi .bash_profile
  # nvm
    if [[ -s ~/.nvm/nvm.sh ]] ; then
      source ~/.nvm/nvm.sh ;
    fi
$ nvm ls-remote
$ nvm install 7.4.0
$ nvm use v7.4.0
$ node -v

$ sudo yum install -y npm redis
$ sudo npm install -g hubot coffee-script yo generator-hubot

$ cd /var/www/bot
$ mkdir hubot-cw
$ cd hubot-cw
$ yo hubot
  全てEnterでOK
$ npm install hubot-chatwork --save
$ npm install forever request --save

./scripts以下へ新規作成

  • hubot.coffee
module.exports = (robot) ->
    status  = {}

    robot.respond /(.*)/i, (res) ->
        message = res.match[1]
        if message.length == 0
            res.reply "What?"

    lunch = ['コンビニ', '中華', 'イタリアン', '和食', 'カレー', '昨日と同じ']
    robot.respond /お昼/i, (res) ->
        res.reply res.random lunch

    robot.respond /site (.*)/i, (msg) ->
      url = msg.match[1]
      options =
        url: url
        timeout: 2000
        headers: {'user-agent': 'node title fetcher'}

      request = require 'request'
      cheerio = require 'cheerio'

      request options, (error, response, body) ->
        $ = cheerio.load body
        title = $('title').text().replace(/\n/g, '')
        msg.reply(title)
  • api_userlocal.coffee
module.exports = (robot) ->
    robot.respond /ul (.*)/i, (res) ->
        url = "https://chatbot-api.userlocal.jp/api/chat"
        api_key = process.env.HUBOT_UL_API_KEY
        message = res.match[1]
        params = {
          "message": message,
          "key": api_key
        }
        robot.http(url).query(params).get() (err, response, body) ->
          return response.send "Encountered an error :( #{err}" if err
          body = JSON.parse(body)
          res.reply "#{body.result}"
  • api_cotogoto.coffee
module.exports = (robot) ->
      robot.respond /cg (.*)/i, (res) ->
          url = "https://www.cotogoto.ai/webapi/noby.json"
          api_key = process.env.HUBOT_CG_API_KEY
          message = res.match[1]
          params = {
            "text": message,
            "app_key": api_key
          }
          robot.http(url).query(params).get() (err, response, body) ->
            return response.send "Encountered an error :( #{err}" if err
            body = JSON.parse(body)
            res.reply "#{body.text}"
  • api_docomo.coffee
getTimeDiffAsMinutes = (old_msec) ->
  now = new Date()
  old = new Date(old_msec)
  diff_msec = now.getTime() - old.getTime()
  diff_minutes = parseInt( diff_msec / (60*1000), 10 )
  return diff_minutes

module.exports = (robot) ->
  robot.respond /d (.*)/i, (msg) ->
    HUBOT_D_API_KEY = process.env.HUBOT_D_API_KEY
    message = msg.match[1]
    return unless HUBOT_D_API_KEY && message

    ## ContextIDを読み込む
    KEY_DOCOMO_CONTEXT = 'docomo-talk-context'
    context = robot.brain.get KEY_DOCOMO_CONTEXT || ''

    ## 前回会話してからの経過時間調べる
    KEY_DOCOMO_CONTEXT_TTL = 'docomo-talk-context-ttl'
    TTL_MINUTES = 20
    old_msec = robot.brain.get KEY_DOCOMO_CONTEXT_TTL
    diff_minutes = getTimeDiffAsMinutes old_msec

    ## 前回会話してから一定時間経っていたらコンテキストを破棄
    if diff_minutes > TTL_MINUTES
      context = ''

    url = 'https://api.apigw.smt.docomo.ne.jp/dialogue/v1/dialogue?APIKEY=' + HUBOT_D_API_KEY
    user_name = msg.message.user.name

    request = require('request');
    request.post
      url: url
      json:
        utt: message
        nickname: user_name if user_name
        context: context if context
      , (err, response, body) ->
        ## ContextIDの保存
        robot.brain.set KEY_DOCOMO_CONTEXT, body.context

        ## 会話発生時間の保存
        now_msec = new Date().getTime()
        robot.brain.set KEY_DOCOMO_CONTEXT_TTL, now_msec

        msg.send body.utt

起動設定(常駐化、環境変数設定)

  • ./bin/hubotを編集
#!/bin/sh

set -e

ARG1=$1

export PATH="node_modules/.bin:node_modules/hubot/node_modules/.bin:$PATH"
export HUBOT_SLACK_TOKEN=xoxb-xxx
export HUBOT_CHATWORK_TOKEN="xxx"
export HUBOT_CHATWORK_ROOMS="xxx"
export HUBOT_CHATWORK_API_RATE="900" #時間あたりのポーリング回数(4秒に1回)
export HUBOT_UL_API_KEY=xxx
export HUBOT_CG_API_KEY=xxx
export HUBOT_D_API_KEY=xxx

#exec node_modules/.bin/hubot -a chatwork -n mohi

start() {
        forever start -c coffee node_modules/.bin/hubot -a chatwork -n mohi
}
stop () {
        forever stop -c coffee node_modules/.bin/hubot
}
status() {
        forever list
}
restart() {
        forever restartall
}

case "$ARG1" in
        "stop" )
                stop
                ;;
        "restart" )
                restart
                ;;
        "start" )
                start
                ;;
        "status" )
                status
                ;;
esac
  • 起動
$ bin/hubot start

最後に

使い方

「mohi APIオプション 会話内容」
・Coto Goto APIの場合(mohi cg 会話内容)
  下記を聞くと教えてくれます。
   ・ニュース
   ・おみくじ引く
   ・○○の天気
   ・○○の意味を知りたい
・User Localの場合(mohi ul 会話内容)
・Docomo雑談APIの場合(mohi d 会話内容)

今後

今後はDocomoのAPIや他社も利用して、画像認識や形態素解析も実装したあと、
独自で情報を取ってくるものを作りたいと思ってます。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
7
Help us understand the problem. What are the problem?