Sirikitでworkout名の認識のさせ方について調査

- SiriKitでworkout系のアプリを作ろうかと思い、「siriにどう話しかければworkoutのコマンドとして認識されるか？」を調べてみました
    - 事の発端は、documentを読んでもコマンド例がほとんど載っておらず、「どう話しかければいいのか？/実際の使い勝手はどうなのか？」が気になったからです。
    - そもそも、とあるタスクの言い回しはたくさんありますし、Siriも日々改良中でしょうから「きちんとした形でdocumentにコマンド仕様を載せるのが難しい/ユーザの意図はSiriがうまいことやってIntentオブジェクトを作るから、developerは気にしなくてok」といったところでしょうか・・
- SiriKitで出来ることや環境構築手順については他の記事をご参照ください
    - 日本語なら [SiriKitを試す(excite Officialエンジニアブログ)](http://blog.excite.co.jp/exdev/25421658/) がいいかもしれません
    - 公式のdocumentは [こちら](https://developer.apple.com/sirikit/)
- 2016/7/25に試しました

## 環境
- Xcode8.0 beta3
- iOS10 beta3

## どういうコマンドだとSiriに認識されるのか？
- File -> New -> Target -> Intent Extension追加時に自動生成されるソースのコメントには「start my workout using アプリ名」というような例がありましたが、いくつか言い回しを変えてみました

### 手順
1. iOS10を入れた実機の 設定 -> Siri の言語を英語にする
2. Macのシステム環境設定 -> 音声入力と読み上げ を システムの声: Susan 読み上げ速度: 通常より少し遅め にする
3. Macのconsoleから `echo "start hoge workout using {アプリ名}" | say` して出力された音声を実機のSiriに聞かせてアプリが呼ばれるかを確かめる

### 結果

- okの場合はアプリで定義したIntentHandlerが呼ばれ、(例えばstart workoutの場合)
    1. `func handler(for intent: INIntent) ` ...(A)
    2. `func resolveWorkoutName(forStartWorkout intent: INStartWorkoutIntent, with completion: (INSpeakableStringResolutionResult) -> Void) ` (intent.workoutNameがnilじゃない場合は呼ばれない）
    3. (A)が4回ほど呼ばれる
    4. `func resolveIsOpenEnded(forStartWorkout intent: INStartWorkoutIntent, with completion: (INBooleanResolutionResult) -> Void)`
    5. (A)が呼ばれる
    6. func confirm(startWorkout intent: INStartWorkoutIntent, completion: (INStartWorkoutIntentResponse) -> Void)
    7. (A)が呼ばれる
    8. func handle(startWorkout intent: INStartWorkoutIntent, completion: (INStartWorkoutIntentResponse) -> Void)

という順番で処理が走りました。

|コマンド|結果|備考|
|:-----|:-----|:-----|
|start jogging workout using {アプリ名}|ok|intent.workoutNameは「Optional(run)」 になる|
|start jogging using {アプリ名}|NG (I'm not sure I understand. といってsiriの画面で止まる)||
|jogging workout using {アプリ名}|NG ( My appologies, I can't help you with that.)||
|cancel workout using {アプリ名}|ok|intent.workoutNameはnil|
|cancel jogging workout using {アプリ名}| ok |intent.workoutNameは Optional(run)|
|end workout using {アプリ名}|ok|intent.workoutNameはnil|
|end jogging workout using {アプリ名}|ok|intent.workoutNameは Optional(run)|

#### 気づき
- 「jogging」と言ってもworkoutNameは「run」となりました。おそらく文言揺れをSiri側で吸収しているんでしょう
    - が、「揺れを吸収した結果どういう言葉になるのか」もdocumentには無いのでdeveloperとしてはつらそう・・・
- startする時は「○○workout」という風にworkoutをつけないと認識してくれないっぽい

## どんな単語がworkout名として認識されるのか？
- 上記でjoggingがrunになったりしたので他の単語だとどうなのかを試してみました
- 個人的にはlife log系のアプリで使ってみたい (例えば「Hey,Siri. {アプリ名}に読書するって言って！」と話せば 読書が開始されたというログをつけたい)と思ってるので運動とは関係なさそうな単語でもworkout名として認識されるかを試してみました
- 以下の表のworkout名について `start {workout名} workout using {アプリ名}` で試しました

|workout名|結果 (ok:アプリのhandlerが実行された)|
|:--|:--|
|jogging|ok (intent.workoutNameはrun)|
|swimming|ok (swim)|
|bench press| ok(nil)|
|reading| ok (nil) |
|journal describing| ok (nil) |
|meditation| ok(nil) |
|having a bath| ok(nil)|
|programming| ok(nil)|
|studying| ok(nil)|
|sleeping| ok(nil)|
|going to bed| NG (I'm not sure I understand. でSiriの画面で止まる)|
|working| ok(nil)|
|meeting| ok(nil)|

#### 気づき
- 「workout」さえ後ろにつければとりあえずhandlerは呼ばれるっぽい (が、workoutNameはnilになる）

## 日本語で話したらどうなるのか？
- excite Officialエンジニアブログの方では日本語によるハンドリングは出来なかったとのことですが、7/25現在で以下のフレーズでハンドリングすることができました (実機とMacのSiri/読み上げ の音声は日本語に変えました）

|コマンド|結果|
|:---|:---|
|{アプリ名}でジョギングワークアウトを開始| ok(workoutNameはrun)|
|{アプリ名}でジョギングを開始| ok(run)|
|{アプリ名}でプログラミングを開始|NG(すみません、よくわかりません でSiriの画面で止まる）||
|{アプリ名}でプログラミングワークアウトを開始|ok(workoutNameは nil)|

#### 気づき
- 一般的なワークアウト(運動)名だと後ろに「ワークアウト」をつけなくても認識された
- life log的な項目(上の例だと「プログラミング」) でも「ワークアウト」をつけることでhandlerは呼ばれた

### 今後に向けて
- [App Vocabulary File Format](https://developer.apple.com/library/prerelease/content/documentation/Intents/Conceptual/SiriIntegrationGuide/CustomVocabularyKeys.html) を使えば、ライフログ的な項目をworkout名として認識させられるかなー？と思ってちょっと試してみましたが、まだ成功してません (´・ω・`)