Pepperくん秘書化計画 ~スケジュール編~
Zenfone 3につづいて Zenbook 3 を発売日に購入したメディアフォース齊藤です。
Zenfone 3 Laserを購入しようか迷ってます。
本記事はアプレッソ Advent Calendar 2016 の16日目の記事です。
qiita.com
去年も書かせていただいてますが、偶然にも 同じく16日でした。
スクリプト開発時に気をつけるべき3つのポイント - Appresso Engineer Blog
毎年12月16日は齊藤の日として広めて参りたいと思います。
Pepperくん秘書化計画とは
さて、Pepperくん秘書化計画についてご説明しましょう。
みんなだいすき顔面蒼白のPepperくんですが、説明係だったり案内係だったりとめんどくさい客来客対応として使われるケースが多いように思います。
Pepperくんを個人で購入される方はあまり多くはないと思いますが、なかなかに値が張ります。
せっかくなので自分のために使いたい!ということでPepperくんには秘書として存分に働いてもらおう計画です。
構成図
- Pepperくんに教えを乞う
- PepperくんがDataSpider Cloud(以下、DSC)にHTTPリクエスト飛ばす
- DSCがGoogle API経由でスケジュールを取得
- DSCでスケジュールをセリフ状のテキストに整形し、レスポンスボディで返す
- Pepperくんが受け取ったテキストを喋る
やろうと思えばPepper -> Google APIの直接でも出来ると思うんですが、GoogleのOAuth2認証やテキスト整形がめんどくさかったので簡単にできそうなDataSpiderを利用しました。
ちなみにDSCはまだリリースされていないので、DSC想定で普通のDataSpiderをEC2に置いてある感じです。
Google APIを取得する
DataSpiderによるGoogle API連携についてはこの記事を参考にしてます。
DataSpider RESTアダプタを使ってGoogleカレンダーの予定を取得する。 - Qiita
記事からちょっと変えた点
- 認証情報の「APIを呼び出す場所」をその他のUIに変更してます。
この場合、リダイレクトURLは不要ですが、http://localhost:7700 を指定しておきます。
また、最近 Google アカウントは二段階認証を導入しましたが、検証時点では二段階認証があると認証のレスポンスが受け取れなかったので無効にしてます。
DataSpider側のアプリをつくる
DSC_GoogleCalendar.zip に DataSpider プロジェクトを置いてあります。
- OAuth認証のグローバルリソースを作成しておく。
- 変数のcalendarIdに取得したいカレンダーIDを入れておく。カレンダーIDについてはここでは説明しないのでググってください。
- 実行すると、returnText にセリフ状のテキストが入ります。
- サービス登録し、HTTPトリガーを作成する。HTTPトリガーでreturnTextをレスポンスボディに含める設定にします。
- HTTPトリガーの設定が完了したら、ブラウザからHTTPトリガーにアクセスする。
- ブラウザにテキストが表示されたらOKです。
Pepperアプリ
Pepperアプリの開発にはChoregrapheを使っています。
Pepperは「今日のスケジュール」といったワードに反応してスケジュールを教えて欲しいところです。
- Choregrapheプロジェクト全体像
ということでChoregrapheプロジェクトはPepper_DSC.zipに置いてます。
プロジェクトの構成
- Speech Reco. で「今日;明日;ありがとう」を登録しておきます。「今日」と「明日」でそれぞれのスケジュールを通知し、「ありがとう」で終了します。
- TextEditの「DataSpiderのURL」には先程ブラウザで確認したURLを設定しておきます。
- HTTP Getはこちらの記事を参考にしていますが、変えた部分があるのでコード全文載せておきます。
class MyClass(GeneratedClass): def __init__(self): GeneratedClass.__init__(self) def onLoad(self): #put initialization code here pass def onUnload(self): #put clean-up code here pass def onInput_onStart(self, url): from HTMLParser import HTMLParser import urllib2, contextlib class ContentParser(HTMLParser): def __init__(self): HTMLParser.__init__(self) self.inscript = False self.inbody = False self.text = "" def handle_starttag(self, tag, attrs): if tag == "body": self.inbody = True if tag == "script": self.inscript = True def handle_endtag(self, tag): if tag == "body": self.inbody = False if tag == "script": self.inscript = False def handle_data(self, data): if self.inbody and not self.inscript: self.text = self.text + data try: timeout = int(self.getParameter("Timeout")) self.logger.info("Loading... %s" % url) response = urllib2.urlopen(url) text = response.read() self.logger.info("Loaded: %s" % text) self.onStopped(text) except urllib2.URLError, message: self.logger.warn("Failed to open: %s, message=%s" % (url, message)) self.onFailed(message)
コードはやっつけですみません。。。
デモ
今日の成果物
— 齊藤毅 (@tsuyoshi_saito) 2016年12月10日
スケジュール教えてくれるくん pic.twitter.com/aqK8u41TgW
中々おもしろい感じにできたんじゃないでしょうか
あいだにDataSpiderを経由することで実装がやや難しい認証周りが比較的簡単に実装できたり、DeepLearningに学習用データも一緒に登録したりもできたりするのでPepper単体で完結できるものでも挟んでおくと色々はかどりそうですね :D