GoogleHomeをスプラトゥーンアシスタントにする #2 Twitterからステージ情報の取得

はじめに

Google Homeを買ったはいいものの、テレビ無し、外出ない、家電使わない自分には少々物足りないので
生活の大半を占めるスプラトゥーンのアシスタントをGoogle Homeには勤めてもらいます。

みたいな事を書いたので、その続きです。
GoogleHomeをDialogflow(旧:API.ai)でスプラトゥーンアシスタントにする

実装する機能

スプラトゥーンは3つのゲームモードがあり、それぞれ時間によってステージが異なります。
確認するにはスマホアプリかまたはゲーム内アナウンスで確認する必要があるので、これをハンズフリーで確認できるようにしたいと思います。
スクリーンショット 2017-10-16 17.55.37.png

実装する機能のイメージ↓

僕「ステージ 〇〇(ゲームモード)

GoogleHome「〇〇のステージは××(ステージ名)です

また、ゲームモードの「ガチマッチ」「リーグマッチ」ではルールが3種類あるのでそれも確認できるようにします。

使用ツール・環境

webhookの置き場にherokuを使用し、
前回とは違い、IFTTTは使用せずDialogflowとwebhookのみで実装します。

ステージ情報の取得

現在配信されているステージ情報を取ってきます。
公式アプリから閲覧できるイカリング2からプロキシをごにょごにょして取ってきてもいいんですが、
【スプラトゥーン2】イカリング2の戦績データをPCブラウザで無理矢理閲覧する

世の中には便利なBotを作っている人がいるのでこちらのBotのツイートから取得しようと思います。

ツイート取得機能は応用が効きそうですしね(イカリングからの取得が面倒そうだからという訳では無いです)

twythonをインストール

TwitterAPIを叩くのに今回はtwythonを使います。
初期設定はこちら参照
Twitter REST APIの使い方

どうせ大した事しないのでtwython使うまでも無い気はしますが...
$pip install twython

スクリプトを書きます。

twython.py
from twython import Twython, TwythonError


APP_KEY = "取得したAPI Key"
APP_SECRET = "取得したAPI Secret"
OAUTH_TOKEN = "取得したAccess Token"
OAUTH_TOKEN_SECRET = "取得したAccess Token Secret"

def getStage(num,mode):
    twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET)
    #ツイートを取得したいTwiiterアカウントのID
    screen_name = "splatoon2_stage"
    results = twitter.get_user_timeline(screen_name=screen_name,count=5)
    date = list(filter(lambda s:s != '', results[num]["text"].replace("▼","").replace("、","と").split()))
    time = date[1].replace((b'\xef\xbd\x9e').decode('utf-8'),"から")
    nawabari = date[3]
    gachi_mode = date[4]
    gachi_stage = date[5]
    league_mode = date[6].replace("リーグ:","モードは")
    league_stage = date[7]
    if mode == "ナワバリ":
        return time + nawabari
    elif mode == "ガチマッチ":
        return time+"モードは"+gachi_mode+"ステージは"+gachi_stage
    elif mode == "リーグマッチ":
        return time +league_mode +"ステージは"+ league_stage

if __name__ == '__main__':
    print(getStage(0,"ガチマッチ")+"です")

これで、現在のステージ名とガチマッチ・リーグマッチの場合は「ガチホコ」「ガチエリア」「ガチヤグラ」等のゲームモードを出力できるようになりました。

出力例
スクリーンショット 2017-10-16 17.14.47.png

これを後は前回作成したpythonファイルに書き加えればOKです。

webhook-dialogflow.py
from __future__ import print_function
from future.standard_library import install_aliases
install_aliases()

from urllib.parse import urlparse, urlencode
from urllib.request import urlopen, Request
from urllib.error import HTTPError

import json
import os

from flask import Flask
from flask import request
from flask import make_response, jsonify
import gspread
from oauth2client.service_account import ServiceAccountCredentials

from twython import Twython, TwythonError
APP_KEY = "取得したAPI Key"
APP_SECRET = "取得したAPI Secret"
OAUTH_TOKEN = "取得したAccess Token"
OAUTH_TOKEN_SECRET = "取得したAccess Token Secret"

# Flask app should start in global layout
app = Flask(__name__)


@app.route('/webhook', methods=['POST'])
def webhook():
    req = request.get_json(silent=True, force=True)
    result = req.get("result")
    parameters = result.get("parameters")
    text = ""
    if req.get("result").get("action") == "getSpreadSheet":
        text = getSpreadSheet(parameters.get("weapon_name"))
    if req.get("result").get("action") == "getStage":
        text = getStage(0,parameters.get("mode"))+"です"
    r = make_response(jsonify({'speech':text,'displayText':text}))
    r.headers['Content-Type'] = 'application/json'
    return r

def getStage(num,mode):
    twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET)
    screen_name = "splatoon2_stage"
    results = twitter.get_user_timeline(screen_name=screen_name,count=5)
    date = list(filter(lambda s:s != '', results[num]["text"].replace("▼","").replace("、","と").split()))
    time = date[1].replace((b'\xef\xbd\x9e').decode('utf-8'),"から")
    nawabari = date[3]
    gachi_mode = date[4]
    gachi_stage = date[5]
    league_mode = date[6].replace("リーグ:","モードは")
    league_stage = date[7]
    if mode == "ナワバリ":
        return time + nawabari
    elif mode == "ガチマッチ":
        return time+"モードは"+gachi_mode+"ステージは"+gachi_stage
    elif mode == "リーグマッチ":
        return time +league_mode +"ステージは"+ league_stage

def getSpreadSheet(weapon_name):
    #
    #省略 前回のスクリプト参照
    #
    return text

if __name__ == '__main__':
    port = int(os.getenv('PORT', 5000))

    print("Starting app on port %d" % port)

    app.run(debug=False, port=port, host='0.0.0.0')

では、次にwebhookを送信するDialogflowの設定に行きましょう。

Dialogflowのセッティング

詳しくは前回のを見て頂くとして、新規に設定する部分を載せます。
前回のBotに機能を追加する場合はIntentsに新しく返答を登録すればOKです。

Intents

Intentsで入力の受け取りや失敗した際の返答を登録します。
新しくstageを作成。CREATE INTENTで新規intentを登録可能です。
スクリーンショット_2017-10-18_22_06_40.png
(成績が前回作成したintent)

今回はユーザーの発言が「ステージ」だった場合にBotが反応し、
「ステージ」の後に続く部分をmodeとして入力で受け取ります。

スクリーンショット 2017-10-16 16.40.24.png
ActionにはgetStageと入力。JSONのこの部分を上記のpythonスクリプトは見て前回のwebhookと分岐させています。
スクリーンショット 2017-10-16 18.06.21.png

Entities

入力として受け取る単語をEntitiesから登録します。
今回もスプラトゥーンのデータベースは無いようなのでポチポチ登録しましょう。
スクリーンショット 2017-10-16 16.40.40.png

Fulfillment

前回と変更点はありません。
webhookを流すurlを入力しておきましょう。
20171012132542.png

これでセッティングは終了です。

テストする

Dialogdlowのコンソール右側にテキストを入力してテストしましょう。
スクリーンショット 2017-10-16 16.40.14.png
ステージが出てきました!
action,parameter valueも問題なさそうですね。

完成

動作の確認はこちらの動画から↓
IMAGE ALT TEXT HERE

おわりに

今回はゲームモードを取得しましたが、先日開催されたフェスやもう1つのゲームモードサーモンランに対応していないのでそこら辺やろうかと思います。
でも別々のTwitterBotから取得するぐらいならイカリングから読み出した方がいい気も…先は長いですね。
スプラトゥーン以外にもTwitterとの連携は便利そうなので使っていきたいです。

良きスプラトゥーンライフを!(フェスは負けました)

参考