Clova CEKでのスキル開発の始め方〜Pythonで開発スタート編〜
こんにちは、n0bisukeです。
#linebootawards
のハッカソンで奈良先端科学技術大学院大学に来ています。
前回はNode.jsでのチュートリアルを書きましたが、今回はPythonでのClovaの開発チュートリアルを書いていきます。
PythonとClovaの連携をとりあえずやりたいって人向けです。
Clovaってなんぞやって人はこちらの記事たちを先に読んでみてください。
いわゆるClovaのAPIのことをCEKと呼ぶんですよ〜
そもそも僕がPythonの使い方がイマイチ分かってないので抜けがある可能性高いのでコメントなどいただけたら幸いです。 -> @n0bisuke
作るもの
今回、「倦怠期のカップルや夫婦のコミュニケーションを円滑にするスキル」 という案が出ていたのでそれをネタにチュートリアルを進めてみたいと思います。
旦那「妻の気分を教えて」
Clova「妻の気分はいい感じです。」
これを作ってみます。会話のキッカケを増やしたり作ったりするスキルですね。
完成はこんなイメージです。
中身はハローワールド的な内容なので単純にClovaに喋ってもらう入門だと思ってください。
環境
- Clova Friends Mini (サリー)
- Python v2.7.10
Google Chrome / macOS Sierra v10.12
$ python -v
でPythonのバージョン調べられます。
使い始めの申請
まずは、新規チャンネル作成からチャンネルを作成します。
こちらの記事を参照して、利用開始できる状態にしましょう。
「チャネルの基本設定」の箇所まで進められばOKです。
ちなみに今回は以下の情報にしてみました。
- スキル名: 倦怠期Clova
- 呼び出し名(メイン): 倦怠期
- 呼び出し名(サブ): ケンタッキー
「倦怠期(けんたいき)」と言う言葉が発話した際に「ケンタッキー」と誤認識される可能性があったので呼び出し名(サブ)
にケンタッキーを登録しています。(笑うところ)
対話モデルの作成
Clova Developer Centerにアクセスします。
作成中スキルの一覧が表示されます。
作成対象となるスキル名の対話モデル
の修正
を選択します。
すると別ウィンドウが開き、対話モデルの編集画面になります。
なぜここだけ別ウィンドウなのかは永遠の謎。
インテントとスロット
インテントとスロットを設定していきます。
個人的にはインテントとスロットの概念を理解すればあとはBOT開発などとそこまで変わらないような印象があります。
説明はあってるのか不安なので、スマートスピーカー開発に慣れてる人が見て変だったら教えてください笑
公式ドキュメントのこの辺を見ると詳しく載っています。
スロット
スロットはスキル内で扱う名詞情報です。
今回の「妻の気分を教えて」という発話を認識させる為に
気分という名詞(スロット)を登録しましょう。
また、「妻の欲しい物を知りたい」というケースに対応するために欲しい物というスロットを登録します。
また、その名詞(スロット)はどういう属性かという上位概念をスロットタイプとして設定します。
では実際に左側のメニューにカスタムスロットタイプ
という項目があるので、そこの+ボタン
を押します。
ここでスロットタイプのタイトルを決めますが、気分や欲しい物や妻がどういった状態かを知りたいので、ここではstatus
(ステータス)としました。
書いてて今回の例が少し分かりにくいかなぁと思ってるのですが、Node.jsのチュートリアルでは「秋葉原のカレー屋を教えて」という例文を利用していて、秋葉原や、神田、神保町といった駅名や地名、場所にちなんだ単語をスロットに登録しました。この場合は
area
(エリア)というスロットタイプにしました。
statusとスロットタイプに入力して作成を押すと、statusというスロットタイプが作成されます。
僕みたいに覚えにくい人はスロットタイプ=単語群
だと思えば良いと思います。
次にスロット登録です。
スロットの新たな代表語を入力
の箇所に気分
と入力し、同義語の箇所に読み方や別名を入力します。こうすることできぶん
などの名称でも認識してくれるようになります。欲しい物
の場合は欲しいもの
やほしいもの
なども登録してあげると認識精度が上がります。
同義語はカンマで区切って複数登録できます。
最後に保存
を押してスロットはOKです。個人的には難所50%クリアです。
インテント
インテントは会話や命令の種類です。
今回の「妻の気分を教えて」は妻の状態を知りたいという命令だと思うので
WifeStatusIntent(ワイフステータス)を作ってみます。
メニュー左のカスタムインテント
箇所の+ボタン
を選択し、インテント名を入力して進みます。
次にサンプル発話リスト
箇所に例文を入れていきます。
先ほどから何回も出ている「妻の気分を教えて」をここに入力してエンターを押しましょう。
さらに気分
の部分が先ほど登録したスロット部分になるので、この文章のここがスロットだよということを登録してあげます。
気分
をドラッグするとスロット登録が出来るフォームが出てくるのでそこでstatus
と入力してスロット名を登録します。
さらにスロットタイプのプルダウンメニューが出てくるので先ほど作成したstatus
スロットを紐付けします。
最後に保存を押しましょう。
対話モデルのビルド
ここまで来たら左上のビルド
ボタンを押してひとまず完了です。
ここ、少し時間かかります。
1~2分程度掛かります。昔は10~20分程掛かってたのですが、アップデートで凄く短縮されました。
Clova Developer Centerにおいて作成する対話モデルのビルド時間が大幅に削減されました、ぜひお試しください!これまでご不便をおかけしてごめんなさい、まだまだ色々ありますが少しずつ改善重ねていきますので、皆様と一緒にClovaを育てていければ嬉しいです!よろしくお願いします!!!#Clova_CEK pic.twitter.com/1H0zKpevDy
— LINE_DEV (@LINE_DEV) 2018年8月31日
ただ待つのも時間が勿体無いので次の準備にかかりましょう。
Pythonの環境準備
お待たせしました。コード書いていきましょう。
PythonのSDKがあるのでこちらを使っていきます。
Python以外の言語のSDKも現時点ではSwift/Kotlin/Elixir/Java/Go/Node.jsのSDKが出ています。
Pythonのインストールがまだな方は公式サイトなどからDLしてインストールして下さい。
MacだとデフォルトでPythonがインストールされているのでインストールに関してはそこまで問題無いと思います。
ターミナル操作が不安な方はこちらの記事を先に見ておきましょう。
準備
以下のコマンドで進めていきます。基本Mac向けなのでWinな人は適宜読み替えをお願いします。
- pipのインストール
pipはNode.jsでいうnpmのようなPython向けのモジュールの管理ツールです。
$ sudo easy_install pip
- Flaskのインストール
Python向けのマイクロフレームワークのFlaskをpip経由でインストールします。 Node.jsでいうExpressのようなものです。
$ pip install Flask
- clova-cek-sdk
Clova CEKのPython SDKをインストールします。
$ pip install clova-cek-sdk
- server.pyを作成
フォルダ作成と準備です。
$ mkdir clova_kentaiki
$ cd clova_kentaiki
server.py
を作成してプログラムを書いていきましょう。
$ touch server.py
コードを書いていく
server.py
に以下のコードを記述します。
また、スキルの基本情報を登録した際のExtention ID
を利用するので確認しておきましょう。
公式のサンプルよりもシンプルにしています。
以下のコードのapplication_id=“MY EXTENSION ID”の箇所を自分のExtension IDに書き換えましょう
# coding: utf-8
from flask import Flask, request, jsonify
import cek
app = Flask(__name__)
clova = cek.Clova(
application_id="MY EXTENSION ID",
default_language="ja",
debug_mode=True)
# /clova に対してのPOSTリクエストを受け付けるサーバーを立てる
@app.route('/clova', methods=['POST'])
def my_service():
body_dict = clova.route(body=request.data, header=request.headers)
response = jsonify(body_dict)
response.headers['Content-Type'] = 'application/json;charset-UTF-8'
return response
# 起動時の処理
@clova.handle.launch
def launch_request_handler(clova_request):
welcome_japanese = cek.Message(message="調子どうだい?", language="ja")
response = clova.response([welcome_japanese])
return response
# WifeStatusIntentの発火箇所
@clova.handle.intent("WifeStatusIntent")
def wife_status_handler(clova_request):
print("ワイフインテント")
message_japanese = cek.Message(message="奥さんの気分はいい感じです", language="ja")
response = clova.response([message_japanese])
return response
# 終了時
@clova.handle.end
def end_handler(clova_request):
# Session ended, this handler can be used to clean up
logger.info("Session ended.")
# 認識できなかった場合
@clova.handle.default
def default_handler(request):
return clova.response("Sorry I don't understand! Could you please repeat?")
起動
記述出来たら以下のコマンドで起動しましょう。
$ FLASK_APP=server.py flask run
* Serving Flask app "server.py"
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
で起動です。エラーがなければとりあえずOKです。
5000番ポートでサーバーが起動します。
ngrokでホスティングせずに疎通確認
ngrokというトンネリングツールを使ってローカル開発が出来るようにしましょう。
LINE BOTの開発でも同様ですが、通常はHTTPS対応したサーバーにプログラムをホスティングしてClovaと通信させます。
HTTPS対応したサーバーを用意するのは骨が折れるのとホスティングして失敗するとエラー修正が大変なので、ローカル開発で最初は挙動確認するのが個人的にはおすすめです。
ngrokを使うことでローカル環境をホスティング環境のようにエミュレート出来るイメージです。
$ npm i -g ngrok
これでインストール完了です。
npmを入れてない人はbrew経由でもインストール可能です。
$ brew install ngrok
以下のコマンドで利用しますが、ngrokがターミナル占有してしまうので、Pythonを起動するターミナルとは別で立ち上げましょう。
$ ngrok http 5000
こんな雰囲気。右がngrok、左がPythonです。
ngrokを起動すると
Forwarding https://xxxxxxx.ngrok.io -> localhost:5000
といった項目が表示されます。
このhttps://xxxxxxx.ngrok.io
に/clova
を追加したアドレスをClovaのサーバー設定のExtensionサーバーのURL
に記載して保存しましょう。
https://xxxxxxx.ngrok.io/clova
となります。
xxxxxx
の箇所はngrokを再起動すると変わってしまうのでその際は再度サーバー設定を更新してください。
これでClovaに話しかけると手元(ローカル環境)のPythonプログラムまでリクエストが来ます。
テスターでテスト
直接話しかけても良いのですが、テスターを使ってみましょう。
対話モデルのダッシュボードに戻ります。
たぶんビルドは完了してますよね。
テスト
を選択し、ユーザーのサンプル発話をテスト
の箇所に「妻の気分を教えて」と入力しテストボタン
押しましょう。
Pythonを起動させているターミナル側で
ワイフインテント
と表示されていればOKです。
疎通確認が出来ました!
コードでいうと@clova.handle.intent("WifeStatusIntent")
の箇所までリクエストが通ってることになります。
# WifeStatusIntentの発火箇所
@clova.handle.intent("WifeStatusIntent")
def wife_status_handler(clova_request):
print("ワイフインテント")
message_japanese = cek.Message(message="奥さんの気分はいい感じです", language="ja")
response = clova.response([message_japanese])
return response
エラーが出る場合
エラーが出た人はserver.py
内のExtension IDの設定を忘れている可能性が高いので再度チェックしてみましょう。
Clovaにしゃべらせる
最後です!
スロット情報も取得してみる
server.py
の@clova.handle.intent("WifeStatusIntent")
の箇所をまるっと差し替えてみましょう。
# WifeStatusIntentの発火箇所
@clova.handle.intent("WifeStatusIntent")
def wife_status_handler(clova_request):
print("ワイフインテント")
slot = clova_request.slot_value("status")
message_japanese = cek.Message(message="もう一回言って下さい", language="ja")
if u"気分" in slot:
message_japanese = cek.Message(message="奥さんの気分はいい感じです", language="ja")
elif u"欲しい物" in slot:
message_japanese = cek.Message(message="奥さんは旅行に行きたがっています", language="ja")
response = clova.response([message_japanese])
return response
clova_request.slot_value("status")
にスロット情報が入っているので、あとはif文で判定して喋らせる内容を変更していきます。
最後のresponse = clova.response([message_japanese])
を呼ぶことでClovaが喋ってくれます。
ここまでをまとめたコードはこちらです。
実機テスト
server.py
のサーバーを再起動して試してみましょう。
起動する際は、{ウェイクワード} -> {スキル名}を起動してとなります。
- ウェイクワード: Clovaの呼び名
- スキル名: 基本情報に登録したスキル名
その後、設定したインテントを発話しましょう。
ということで、人によって違うのですが僕の場合はねぇ、Clova
がウェイクワードになっていて、今回は倦怠期
というスキル名でした。
のびすけ: 「ねぇクローバ」
Clova: 「ポンっ(LEDが緑色に光る)」
のびすけ: 「倦怠期を起動して」
Clova: 「調子どうだい?」 (← server.pyで記述している)
Clova: 「ポンっ(LEDが緑色に光る)」
のびすけ:「妻の気分を教えて」
Clova: 「奥さんの気分はいい感じです」 (← server.pyで記述している)
のびすけ:「妻の欲しい物を教えて」
Clova: 「奥さんは旅行に行きたがっています」 (← server.pyで記述している)
という感じの使い方になります。
完成動画はこの記事の上部を確認して下さい。↑
ちなみに、妻が状況を登録するときはこんな感じでやる模様です。
おまけ: 発話履歴の確認
テスターの発話履歴
を見るとClova側でどんな認識になっているかが分かるのですが”妻の”が”その”などに認識されていて認識の揺れが発生してるのが分かりますね。
Clovaが発話をうまく認識してくれないときはここを見て確認しましょう。
まとめ
こんな感じでとりあえず試す手順を紹介しました。
ホスティングもnowやherokuを使うと簡単に出来るので立花さんのハンズオン資料を参照して理解を深めましょう!
ホスティングに関しても余裕があれば追記したいと思います。