Pepperでモーションを作ったり会話を作ったりしているとそれはそれで非常に面白い感じがするのですが、やっぱりソーシャルなネットワークと接続したくなってしまいます。
PythonボックスでPythonを書いちゃえばいろいろできるわけですが、公式ドキュメントをみても、外部のライブラリをimportする方法が書いてない・・・
と思ったらHOW TO IMPORT PYTHON FILES IN YOUR PEPPER APPS?という記事があったので試してみることにします。
#Twitter Tweetボックスの作成
まずはじめに何が必要そうかのアタリをつけてみます。
Python で Twitter API にアクセス など読ませていただくに、Twitterへのアクセスには、以下の要素が必要になりそう。
- Twitter APIへのアクセスに必要なキー類
- Consumer Key
- Consumer Secret
- Access Token
- Access Token Secret
- Twitter APIに投稿したい内容
- ステータス(メッセージ)文字列
また、スクリプトからインポートされるライブラリとして、以下が必要になるかなと。
これらを踏まえて、以下のようなTwitter Tweetボックスを実現することを考えていくことにします。
Tweetボックスの仕様としては、
- 入力onStartは文字列型で、ツイートしたい内容messageを受け取る
- onStartに入力がされると、ツイート処理がおこなわれる
- 成功した場合はonStoppedが出力される。値はなし(「バン」タイプ)
- 失敗した場合はonFailedが出力される。ステータスコード(数値)が渡される
- Twitter APIへのアクセスに必要な Consumer Key, Consumer Secret, Access Token, Access Token Secretはパラメータによって与えられる
- Twitter APIへのアクセスはPythonによって記述し、importするOAuthのライブラリはプロジェクトのファイルとして保存する
という感じ。手順としては、
- Choregraphe上でPythonボックスを作る
- Pythonスクリプトからimportするライブラリを準備する
- Pythonスクリプトを記述する
の順番で試していくことにします。
##つくってみる
###ボックスの作成
まずは、Choregraphe上でボックスの形を作成していきます。
-
onStart入力の型を文字列に変更する。入力 onStart の**設定ボタンをクリック[A]**し、Typeドロップダウンリストをクリック[B]
-
次に、出力にonFailedを追加。出力の 追加[+]ボタンをクリック
入力と同様に設定ダイアログがあらわれるので、Nameに onFailed と入力 [A]し、Typeを[数]に変更 [B]
-
パラメータを追加する。変数の **追加[+]ボタンをクリック [A]し、Nameに Consumer Key と入力 [B]、Typeを[文字列]に変更 [C]**し、[OK]ボタンをクリック
-
5.と同じ要領で、Consumer Secret, Access Token, Access Token Secretを追加
これでボックスの外身の準備はOK。
###ライブラリの準備
TweetボックスではOAuthの認証のため、以下のライブラリをインポートすることにします。
このライブラリの requirements.txt を見ると、以下のライブラリも必要であることがわかったので、これらも含めることにします。
本来はパッケージ管理ツールとかちゃんと使うべきかなと思いつつ、まずはえいやで、以上3つのライブラリを使用してみる感じで、以下の手順でプロジェクトにライブラリのファイルを組み込んでみます。
-
requests-oauthlib, requests, oauthlib の3つのリポジトリからファイルを取得
今回は [Download ZIP] を選択し、リポジトリ内のファイルをZIPでダウンロードする。
-
適当なフォルダに
lib
フォルダを作成し、ダウンロードしたZIPファイル3つを展開したものを以下のような構成にまとめる-
lib
-
requests_oauthlib
__init__.py
- ...
-
oauthlib
__init__.py
- ...
-
requests
__init__.py
- ...
-
-
-
[インポートするフォルダーを選択]ダイアログが開くので、2.で作成した
lib
フォルダを選択し、[フォルダーの選択]ボタンをクリック
-
ファイルリストにlibディレクトリが追加されるので、ディレクトリツリーを展開し、ファイルがインポートされていることを確認
これで、プロジェクトのファイルとしてPythonのライブラリをインポートすることができた(はず)。
次に、TweetボックスのPythonスクリプトとして、これらのライブラリを使用してツイートするようなコードを記述していきます。
###Pythonスクリプトの記述
Tweetボックスをダブルクリックしてスクリプトエディタを開き、以下のスクリプトを貼りつけます。
class MyClass(GeneratedClass):
def __init__(self):
GeneratedClass.__init__(self)
def onLoad(self):
self.framemanager = ALProxy("ALFrameManager")
self.folderName = None
def onUnload(self):
import sys
if self.folderName and self.folderName in sys.path:
sys.path.remove(self.folderName)
self.folderName = None
def onInput_onStart(self, p):
import sys, os
self.folderName = os.path.join(
self.framemanager.getBehaviorPath(self.behaviorId), "../lib")
if self.folderName not in sys.path:
sys.path.append(self.folderName)
for moduleName in os.listdir(self.folderName):
# モジュールのreload
if moduleName in sys.modules:
self.logger.info("Loaded: %s, %s" % (moduleName, sys.modules[moduleName].__file__))
reload(sys.modules[moduleName])
from requests_oauthlib import OAuth1Session
self.logger.info("ツイートしています... %s" % p)
url = "https://api.twitter.com/1.1/statuses/update.json"
# ツイート本文
params = {"status": p}
twitter = OAuth1Session(self.getParameter("Consumer Key"),
self.getParameter("Consumer Secret"),
self.getParameter("Access Token"),
self.getParameter("Access Token Secret"))
req = twitter.post(url, params = params)
if req.status_code == 200:
self.logger.info("OK")
self.onStopped()
else:
self.logger.warn("Failed: %d" % req.status_code)
self.onFailed(req.status_code)
def onInput_onStop(self):
self.onUnload() #it is recommended to reuse the clean-up as the box is stopped
self.onStopped() #activate the output of the box
コードのポイントとしては・・・
-
まず、onLoad時にALFrameManagerへの参照(プロジェクト内ファイルのパス解決に利用)取得と、変数の初期化を実施
onLoaddef onLoad(self): self.framemanager = ALProxy("ALFrameManager") self.folderName = None
-
onStartの処理開始時に
sys.path
によって [プロジェクトの内容]に追加したPythonライブラリをインポート可能にonInput_onStartdef onInput_onStart(self, p): import sys, os self.folderName = os.path.join( self.framemanager.getBehaviorPath(self.behaviorId), "../lib") if self.folderName not in sys.path: sys.path.append(self.folderName)
-
プロジェクト内のPythonライブラリをロードし、処理をおこなう
onInput_onStartfrom requests_oauthlib import OAuth1Session self.logger.info("ツイートしています... %s" % p) ...
-
処理完了後、Twitter API呼び出しの戻り値により出力を呼び出す
onInput_onStart... if req.status_code == 200: self.logger.info("OK") self.onStopped() else: self.logger.warn("Failed: %d" % req.status_code) self.onFailed(req.status_code)
-
アンロード時、
sys.path
からプロジェクトのPythonライブラリに関するパスを削除onUnloaddef onUnload(self): import sys if self.folderName and self.folderName in sys.path: sys.path.remove(self.folderName) self.folderName = None
といった感じ。個人的には、 sys.path
書き換えは多少強引な感じもする・・・(アプリケーションごとにこれをやったらConflictしそうだし)
将来的にはpipとかがうまく統合されるとよいなあ、などと思いつつ。
##動作確認
作成したTweetボックスを試すため、以下のようなアプリケーションを作ってみる。
これで、任意のメッセージをツイートするフローを作成できた。Pepper実機もしくはバーチャルロボット(Macのみ)で動いた。
Windowsのバーチャルロボットでは実行不可。sslモジュールが有効でないっぽい・・・
こんな感じで、Pepperにツイートさせたりできる。カメラの画像を撮ってツイートとかできると、ハッカソン実況の仕事もPepperに任せられるな・・・などと思いつつ。今後も何かネタができたら書いていきます。