www.ospn.jp 聞きに来てくださった方はありがとうございました。
今年も北海道の人たちに会えたのでよかったです。また来年。
スライドとサンプルコード
www.slideshare.net github.com
www.ospn.jp 聞きに来てくださった方はありがとうございました。
今年も北海道の人たちに会えたのでよかったです。また来年。
www.slideshare.net github.com
2017/10/12 追記: API.AIのサービス名はDialogflowに変わりました。
API.AIのContextsとWebhookでChatOps環境を作ってみます。 https://docs.api.ai/docs/concept-contextsdocs.api.ai 今回は、SlackのChatbotとやりとりし、「管理者モード開始」から「管理者モード終了」までのやりとりの間に操作コマンドを実行できるようにします。
インテントは『管理者モード開始』、『管理者モード終了』、『stats』の3つを用意します。
『管理者モード開始』は、Output contextに「administrator」、User saysに「管理者モード開始」、アクションに「enter_administration」、パラメータとしてpasswordを@sys.anyエンティティで必須入力としておきます。また、パスワード検証をWebhook側で行うため、「Use Webhook」もチェックしておきます。
『管理者モード終了』は、Input contextに「administrator」、Output contextに「administrator」で、Output側はLife spanを0に設定します。Life spanを0にしたコンテキストを出力すると、既存のコンテキストから外れるようです。TextResponseで「管理者モードを終了します。」を返すように設定します。終了時はコンテキストを外す処理だけなので、Webhookは使いません。
『stats』は、操作コマンド用に使います。Input contextに「administrator」、Output contextに「administrator」で、OutputのLifespanは5としておきます。アクションは「stats」を設定しておきます。Webhookで処理するため、「Use Webhook」もチェックしておきます。
今回は操作コマンドとして、botのホストされている環境のメモリ使用量を表示してみます。コマンド名はstatsとしておきます。 WebフレームワークはFlask、また追加のモジュールでpsutilを使います。 Pythonのバージョンは3.6です。
from flask import Flask, request, jsonify import psutil app = Flask(__name__) SECRET_PASSWORD = 'hoge' @app.route("/", methods=['POST']) def webhook(): req = request.get_json(silent=True, force=True) resp = jsonify(process_request(req)) return resp def process_request(request_data): if "result" not in request_data: return {} action = request_data['result']['action'] if action == 'stats': return stats() elif action == 'enter_administration': return enter_administration(request_data) return {} def enter_administration(request_data): # get context contexts = request_data['result']['contexts'] for context in contexts: if context['name'] == 'administrator': administrator_context = context break else: return {} password = administrator_context['parameters']['password'] if password != SECRET_PASSWORD: return { 'speech': "パスワードが間違っています。", 'contextOut': [{'name': 'administrator', 'lifespan': 0}]} message = "管理者モードを開始します。" return { "data": {"slack": {"text": message}}, "displayText": message, "speech": message} def stats(): mem = psutil.virtual_memory() total_gb = mem.total / (1024 ** 3) used_gb = mem.used / (1024 ** 3) message = "メモリ使用量: {:01.1f}GB / {:01.1f}GB".format(used_gb, total_gb) return { "data": {"slack": {"text": message}}, "displayText": message, "speech": message} if __name__ == "__main__": app.run()
起動はpythonコマンドにソースコードのファイルを指定します。psutilを使っているのでWindowsでも動作します。
$ python main.py
起動すると、localhost:5000でlistenされます。
前回と同様に、ngrokで外部から接続できるようにして設定します。
$ ngrok http 5000
fulfillmentのWebhookにURLを設定してSAVEしておきます。
Slackでテスト用に追加されたapiai_botにDMで話しかけてみます。
正常動作していれば、botから応答があります。
コンテキストを使って状態を変えられるのは便利ですね。またコンテキストにパラメータを保持できるのも何かに使えそうです。
今回はパスワード検証部分はハッシュ化などはしていませんが、ワンタイムトークンを発行したりすれば、実用上も問題無さそうですかね。
2017/10/12 追記: API.AIのサービス名はDialogflowに変わりました。
Slackのbotなどを作るときに、API.AIを使うと面白いか便利かもねという話を聞いたので試しています。
API.AIの概要は公式ドキュメントの説明がわかりやすいのでそちらを読むのをオススメします。
自分が思った要点はこのあたり:
音声入力からのテキスト変換もapi.aiがやってたみたいですが、Deprecatedになってて、今はOSの機能か外部サービスを使うのを推奨しているみたいです。
自分の理解ではSlack、API.AI、webhookの関係を図にするとこんな感じ。ドキュメントのほうにも図があるので、そちらも参照されたし。
2016年にGoogleに買収されて、GCPとの連携が強化されていってるのかな。現状、利用は無料。
とりあえず、Slackからの発言をfulfillmentサービスのwebhookで受け取って、レスポンスを返すというのを試してみることにします。
今回は、Contextは使わず単純な文章の加工だけをやってみます。
この記事以外のサンプルコードだと、Webhookのドキュメントにあるものも参考にするとよさそう。
GitHub - dialogflow/fulfillment-webhook-weather-python
左メニューのエージェント名が表示される部分のドロップダウンから「Create new agent」をクリックしてエージェント作成画面を表示。
エージェント名の入力と言語を日本語にしてSAVE。
エンティティは、ユーザー入力から得られる値の定義です。
左メニューのENTITIESのところにある「+」ボタンをクリックしてエンティティの追加画面を表示。 エンティティ名をfood、値を「お好み焼き」「たこ焼き」で入力してSAVE。 ここで定義するもの以外にシステム定義のものや自由入力も扱えます。
インテントは、ユーザー発言をどのように変換、取り扱うかのルールの定義です。
左メニューのINTENTのところにある「+」ボタンをクリックしてインテントの追加画面を表示。 UserSaysに「大阪でたこ焼き食べます」と入力してEnterキーを押すと、エンティティが認識されます。今回の場合、「大阪」の部分は @sys.geo-city 、「たこ焼き」の部分は作成しておいたエンティティの @food と判定されました。
@sys.geo-cityは組み込みのエンティティです。一覧はドキュメントに記載があります。
SAVEボタンをクリックして保存します。
右ペインの「Try it now」のテキストボックスに、「東京でたこ焼きを食べます」と入力してパラメータの変換を試すと、geo-cityは「東京」、foodは「たこ焼き」として認識されました。
「SHOW JSON」ボタンをクリックすると、後述するfulfillmentサービスで外部に送信されるJSONを確認できます。
今回はインテントで変換したパラメータをWebhookで処理します。
Webhook用のWebサーバーとしてPythonとFlaskで簡単なレスポンスを返すものを用意しました。Pythonのバージョンは3.6です。
main.py:
from flask import Flask, request, jsonify app = Flask(__name__) @app.route("/", methods=['POST']) def webhook(): req = request.get_json(silent=True, force=True) resp = jsonify(process_request(req)) return resp def process_request(request_data): if "result" not in request_data: return {} food = request_data['result']['parameters']['food'] city = request_data['result']['parameters']['geo-city'] message = "場所: {}, 食べ物: {}".format(city, food) return { "data": {"slack": {"text": message}}, } if __name__ == "__main__": app.run()
パラメータで受け取った内容から定型文を生成して返すぐらいのものです。
起動はpythonコマンドにソースコードのファイルを指定します。
$ python main.py
起動すると、localhost:5000でlistenされます。
fulfillmentは外部サービスなどでレスポンスを返す機能です。先程用意したWebhookでレスポンスを返すように設定します。
webhookはapi.ai側から通信できる必要があります。どこかにデプロイしてもいいのですが、お試しなのでngrokを使いました。
ngrokコマンドが使える状態で、次のコマンドを実行すると、localhost:5000にngrok経由で外部からアクセスできるようになります。
$ ngrok http 5000
fulfillmentのWebhookにURLを設定してSAVEしておきます。
また、インテントの編集画面の下部に「Use Webhook」というチェックボックスがあるので、チェックしてSAVEしておきます。
Slackのbotとして動かすため、左メニューの「Integrations」からSlackのインテグレーションをONにします。
Slackへの接続ダイアログが表示されるので、任意のスラックグループを選びます。個人用のSlackを作って試すことをオススメします。
Slackのインテグレーションを有効にすると、Slack側にはapiai_botというアカウントが現れます。
Slackでテスト用に追加されたapiai_botにDMで話しかけてみます。
正常動作していれば、botから応答があります。
与えた文章から得たパラメータで応答されることを確認できました。
自然言語処理の部分を作り込むのは結構面倒なものですが、API.AIが肩代わりしてくれるのはうれしいですね。
API.AIのコンソールのUIがわかりづらい(どこがクリックできるのか、入力できるのかなど見た目でわからない、ラベルがない入力エリアなど)のですが、今後改善されることに期待したいです。
学習部分の調整は大変そうですが、いろいろ試していきたいです。
bpmappersのバージョン0.9を公開しました。
リポジトリはbeproud organization以下にありますが、権限を頂いて引き続きメンテナンスしています。
以前のバージョンでは、django.utilsにあったSortedDictとMultiValueDictをコピーして使っていたのですが、これを廃してOrderedDictとdefaultdictで動作するように改修しました。
また、テストコードはunittest+noseからpytestに変更しました。
古いDjangoのサポートを外して、1.8~1.11をサポートするようにしました。現状、Django 2.0で使えなくなるAPIを使っているところがあるので、次のバージョンでは直していきたいです。
django-ftpserverのバージョンを0.5.0に上げました。
pyftpdlibのFileSystemにDjangoのStorageAPIをつなげる機能を追加してみました。
StorageAPIとつなげると、面白そうだなーというのは前から考えてたんですが、StorageAPI側の機能が足りなくてラッパーが必須でいい解決方法が思い浮かばず放置になってました。
DjangoのStorageAPIはバージョンが上がるにつれて、ちょっとずつ機能が増えて、ようやく少しのラッピングでFileSystemの実装ができそうだったので、やってみた感じ。
django-storages経由でS3にFTPクライアントでつなげたり、django-gcloud-storage経由でGCSにつなげたりして遊んでました。
たのしい(^o^)
PyQというプログラミング学習サービスの紹介と宣伝です。
↓ これ ↓
以前、私が勤務していた株式会社ビープラウドが開発しています。
ビープラウドは、Python言語が得意でシステム開発をやってる会社です。connpassというイベントサイトの開発、運営もやってますね。
返金に関して月の途中解約による返金は廃止されたそうです。
料金、定期購読に関する詳しい説明 — Pythonオンライン学習サービス PyQドキュメント
PyQに機械学習、データ分析のコンテンツが追加されました。コンテンツの不足部分が補われたという感じで、より充実したものになっています。
機械学習のコンテンツは、サイボウズ・ラボの西尾さんが監修。Webで検索すれば西尾さんの勉強会等での資料等が見つかりますが、わかりやすい内容だと思いました。
PyQの機械学習コンテンツもやってみましたが、わかりやすく入門者に優しいものでした。これだけでもオススメできます。
https://www.beproud.jp/news/20170907/www.beproud.jp
追記ここまで。
Webブラウザ上で、プログラムコードを記述、実行しながら学習できるサービスです。
プログラミング言語は今のところPythonをターゲットにしているようです。
画面はこんな感じ。左側に説明文が表示されて、右側にエディタと実行結果の表示などが並びます。
見やすいです。
使ってみるとわかりますが、問題数は結構多いです。1つずつこなしていくとかなり時間がかかります。1日1時間ぐらいのペースで進めても、2~3ヶ月くらいかかりそうな感じ。
これからもコンテンツは増えていくようなので、期待できます。
PyQを使う大きな理由の一つかと思います。
プログラミングを学習する場合、最初に学習用の環境構築(ソフトウェアのインストールや設定)が必要になることがほとんどです。
OSやプログラミングの知識が無いと、この環境構築で結構手間取ります。
「プログラミングの勉強をしたいのに、準備でつまづいてしまう」
というのは、よくあります。私もはじめのころはつまづいてました。プログラミング研修の講師をしていたときも、つまづいている方を多く見かけました。
PyQは、Webブラウザ上でエディタやコマンドシェルを使えるので、環境構築が不要ですぐにはじめられます。複数のパソコンを所有してても、それぞれに環境を用意する必要もありません。
私も使ってみてますが、実際に書いたコードを動かせるのは良いですね。
この記事を書いている時点(2017/05)の時点では、サービス利用料金はライトプランで 2,980円/月 となってます。
個人学習ならライトプランでまずは十分かと思います。
プログラミング学習の本を1冊買うと3000円ぐらいはしますし、同程度の金額でPyQを1ヶ月使えるならありだなーと思います。
支払いのFAQを見ると、中途半端な日数で解約しても日割りで返金されるとあるので、ちょっと試してみてイマイチならすぐ解約するのも大丈夫そうです。 仕様変更で日割りでの返金は廃止されたみたいです。
料金、定期購読に関する詳しい説明 — Pythonオンライン学習サービス PyQドキュメント
PyQには、複数の利用者をチームとしてまとめて管理する機能があります。個人向けではなく、教育現場や会社などの組織向けの機能ですね。
PyQで学習している人の進捗具合を確認できる機能があります。誰がどの問題までクリアしたか、わかります。
講師や管理者などの指導する立場の方にはうれしい機能です。
まだ発展途上のサービスなので、細かな部分で気になるところもありますが、私が少し物足りないなーと思った点は次の通り。
上記は2017/05の段階で書いてますので、今後改善される可能性があります。気がついたら内容を更新します。
私はどちらかというと教える側なので、チーム管理の機能が便利だし、講師をやるときには使っていきたいなーという感じです。
そんな感じでPyQを応援しているので、よろしくお願いします。
CentOS7 (7.3) にCartonをインストールするところでハマったのでメモを残す。
GitHub - perl-carton/carton: Bundler or pip freeze for Perl
cpanmコマンドまではインストール済み。Cartonをインストールするとcartonコマンドを使えるようになる。
CentOS7はvagrantのboxから起動したもの。
Digest::MD5が入っていないとインストール途中でコケたので、先に入れておく。
$ cpanm --sudo Digest::MD5 $ cpanm --sudo Carton
Cartonが依存しているPath::Tinyのテストがfailしてインストールに失敗していた。依存しているDigest::MD5が入ってなかったらしい。
t/00-report-prereqs.t ............. ok t/basename.t ...................... ok t/basic.t ......................... ok t/children.t ...................... ok t/chmod.t ......................... ok Can't locate Digest/MD5.pm in @INC (@INC contains: t/lib /home/vagrant/.cpanm/work/1494991121.11260/Path-Tiny-0.104/blib/lib /home/vagrant/.cpanm/work/1494991121.11260/Path-Tiny-0.104/blib/arch /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at /usr/share/perl5/Digest.pm line 41. # Tests were run but no plan was declared and done_testing() was not seen. # Looks like your test exited with 2 just after 4. t/digest.t ........................ Dubious, test returned 2 (wstat 512, 0x200) All 4 subtests passed t/exception.t ..................... ok t/exports.t ....................... ok t/filesystem.t .................... ok t/input_output.t .................. ok t/input_output_no_PU_UU.t ......... ok t/input_output_no_UU.t ............ ok t/locking.t ....................... ok t/mkpath.t ........................ ok t/mutable_tree_while_iterating.t .. ok t/normalize.t ..................... ok t/overloading.t ................... ok t/parent.t ........................ ok t/recurse.t ....................... ok t/rel-abs.t ....................... ok t/subsumes.t ...................... ok t/symlinks.t ...................... ok t/temp.t .......................... ok t/visit.t ......................... ok t/zz-atomic.t ..................... skipped: Test::MockRandom required for atomicity tests t/zzz-spec.t ...................... ok Test Summary Report ------------------- t/digest.t (Wstat: 512 Tests: 4 Failed: 0) Non-zero exit status: 2 Parse errors: No plan found in TAP output Files=26, Tests=1696, 2 wallclock secs ( 0.16 usr 0.02 sys + 1.94 cusr 0.21 csys = 2.33 CPU) Result: FAIL Failed 1/26 test programs. 0/1696 subtests failed. make: *** [test_dynamic] Error 255 -> FAIL Installing Path::Tiny failed. See /home/vagrant/.cpanm/work/1494991121.11260/build.log for details. Retry with --force to force install it. -> FAIL Installing the dependencies failed: Module 'Path::Tiny' is not installed -> FAIL Bailing out the installation for Carton-v1.0.28. 14 distributions installed
これでようやく依存管理できそう?