HabiticaのVUI実装の失敗から学ぶVUIデザイン/実装

# HabiticaのVUI実装の失敗から学ぶVUIデザイン/実装

***[ヘルスケア Advent Calendar 2018](\"https://qiita.com/advent-calendar/2018/healthcare")　 23日目の記事です。***  

23日37時とぎりぎりになりましたが投稿させていただきます。 
・・・嘘です。申し訳ありません。遅刻です・・・

## INTRODUCTION  
### この記事で述べること


[Habitica](https://habitica.com/)という日々の習慣/TODOをゲーム化するアプリ/サービスがあります。 
こちらをしばらく実生活で使っているのですが、 
後述のモチベーションからHabiticaのVUI(voice user interface)を作ろうとしました。

しかし、作りながら運用/費用面も含めた様々なことに気づき、 
"本当に使えるものを作ろうとするWeb/アプリも含めたサービスからデザインしなおす必要がある"という考えに至りました。 
結果本当に簡単な機能を実装するに留まりました。  

とはいえ、その過程でVUIデザイン/実装について学びを得ることができました。 
それらを共有いたします。 

### なぜヘルスケアアドベントカレンダーに?

他の人の記事とは毛色が異なりますが、以下の理由からヘルスケアアドベントカレンダーに投稿させていただきました。  

- ヘルスケアにおいて、習慣やTODOの管理は重大な意味を持つため
- ヘルスケア向けにVUIを作ろうとすると、共通した課題にぶち当たると思われるため

### Notice

- 技術文書というよりは経験談に近いです。さらにこれらのtipsはまだ実戦でその効力を確かめられていません。  
  つまりは「次回作るときは自分はこうします」と言っているに過ぎません。
- おそらく車輪の再発明が含まれます
- イケてるvuiデザインのサービスをまだ自分も見つけられていないので、内容が妥当かは自分もわかりません。  
- ほとんどの項目はヘルスケア向けというよりは、一般的にvuiデザインにもいえることになります。  


### コード
なお実装したコードは以下にあります。実装はfirebase(gcp)とdialogflow, google actions(コードには含まれず)を使っています。  

[havitica-vui](https://github.com/yatszhash/habitica-vui)


なお、作りこみはされておらず実用性はあまりありません。  


## Habiticaとは  


[Habitica](https://habitica.com/)とは"gamefy your life"の文句の通り、
現実の習慣やTODOをgamefication（ゲーム化）することで、 
モチベーションを保つこと目指しているオープンソースのプロジェクトおよびサービス・アプリです。  

コミュニティによって開発されており、コードはオープンになっています。

[Githubのレポジトリ](https://github.com/HabitRPG/habitica)

画面はこんな感じです。  


![](https://habitica.com/static/images/screenshot.fc15c93.png)


日本語でもすでに多くの記事が書かれています。


- [現実という名のクソゲーな人生でやることすべてをRPGゲームに変える「Habitica」をプレイし山積みタスクを処理しまくり＆レベルアップしまくってみた - GIGAZINE](https://gigazine.net/news/20170105-habitica/)
- [朝の運動で経験値を得る、習慣化RPG「Habitica」を始めよう - Weed.nagoya - 挑戦＆物欲プログラマー](http://www.weed.nagoya/entry/2016/05/04/132506)
- [RPG風タスク管理ツール「Habitica」で人生をレベルアップ | Internet | ウェビンブログ](https://webbingstudio.com/weblog/internet/entry-822.html)

どういう風にゲーム化されているかといいますと、
登録されたタスクをこなしてチェックをすると、以下のようなイベントが起こります。

- 経験値がたまる。一定時間行うとレベルが上がる
- モンスターに攻撃できる
- アイテムをもらえる

逆に日課などを行わないと、

- HPが減る
- アイテムがなくなる

などといったイベントが起こります。

## VUI実装のモチベーション

HabiticaにVUI実装しようとしたのは、習慣づけアプリとしての弱点を補おうとしたためです。
例えば以下のようなことです。  

1. いちいちPC/スマホに触って、やったことをチェックするのがめんどくさい  
2. ゲーム内のダミーの報酬を得られるタイミングを、実際にやったタイミングの直後に近づけたい。やったことと報酬を時空間的に結びつけ、条件付けを行いたいため。  
3. Habiticaのレベルアップや報酬の演出はあっさりしている。しかしそれだと報酬を得た感覚が薄いため、声でほめたりしてカバーしたい  

もちろんGUIを拡張するなどVUI以外のアプローチもありますが、 
そちらはコミュニティの開発に任せて自分はVUIのアプローチをとってみました。　　

## VUIデザインのTIPS

本題です。TIPSを挙げていきます。　　

###  シナリオは理想的なものと実装の特性・制約に基づいたものの2パターン作る

UI(というかサービス)を作る上で、シナリオを作ることは非常に重要です。 
VUIを作る上でもかかせません。
特にVUIはほぼそのままモックになるので、脚本並みに詳細に書く必要があります。

ここでやっておくといいことは、2パターンのシナリオをしっかり作ることです。

- ユーザの相手を本物の人間(Habiticaなら、例えば秘書)と仮定したシナリオ
- 実装の特性・制約(例えばgoogle home)に忠実なシナリオ

どちらか一方しか書かない方、両者の中間ぐらいのものしか書かない方もいるのではないでしょうか？

2パターン書く理由としては、

1. ユーザの理想とできることのギャップを把握する  
   VUIは自然言語で双方向のコミュニケーションをというその特性上、ユーザの期待値が高いです。(すでに幻滅期に入っているかもしれませんが)
2. この時点でギャップを埋めたり、ギャップが気にならない工夫を入れる
3. ギャップのうちサービスの価値に響くもの、響かないものを認識できる
4. それでもダメならサービスそのものを再検討する

なお、シナリオ作成において実装に縛られすぎるのは、一般的にはバッドノウハウです。 
しかしVUIの場合モックに近いものになるので、問題は特にはないと思われます。

### 作る前に人間同士でロールプレイする。

シナリオを作ったらvui役、ユーザ役に別れて必ずロールプレイしましょう。
実は下記に挙げた注意点はロールプレイをすればすぐにわかります。  

**シナリオをテキストで書いて満足するだけではダメです。**  
例え、脚本家が書いたドラマの中での会話でも、やっぱり実際の会話とは違います。 
恥ずかしがらずに声を出してやりましょう。  

もちろん相手が想定ユーザーであるならばベストですが、
無理ならせめてエンジニアじゃない相手をユーザ役にしましょう。  

ロールプレイも先ほど同様2パターン両方やります。

### チャットボットとVUIでデザイン／実装を変える

"チャット"ボットってVUIもそうじゃないかと突っ込まれるかもしれませんが、 
ここではgoogle assistantやlineなど画面上でコミュニケーションをとれるものを指しています。  

チャットボットと比べて、VUIで注意すべき点として例えば以下のような点です。  

- 画面が使えない
- テキストで違和感がなかった場合でも、音声では違和感があったり、伝わりにくいことがある。
- 文字の入力と違い、入力途中で文を修正できない。  
- 間投詞(例えば"えーと""あー")など、意図する部分以外のノイズが多い。  
- 音声の場合長文は入力するのも聴くのもストレスになる。  
- 声色で感情が取れたり、個人を識別できる

もちろん、チャットボットデザイン／実装共有できる部分もありますが、 
それは一旦VUIとチャットボットで別々のデザインをして、共通化は後から考えたほうがいいでしょう。  

### 条件を埋めるデフォルト値を用意する。  

条件をなるべく与えて検索結果を絞り込んだり、情報を登録したい場合があります。 
例えばHabiticaの場合タスクの登録なら、

- 難易度
- タスクの種類(ToDo, 日課, 習慣)
- 期限
- タグ（何についてのタスクか。仕事や家事、運動など）

等です。しかしこれを毎回音声で指定するのは面倒です。 
個人に合わせて、

- よく使うパターンをデフォルト値にする　　
- コンテキストから推測する

とユーザの手間が省けます。  

もちろん確認時にデフォルト値を明示的に,

- [VUI] ToDoにクリスマスツリーの飾りつけを難易度優しいで登録しますか？

と聞き返すことは必要です。  

### 検索が必要となる機能はなるべく一発で高性能な検索結果を得る必要がある

VUIから、登録してあるDBの中身を利用するには、自然言語で検索を行える必要があります。 
例えば、Habiticaでは登録されているタスクをチェックするにはまずタスクを検索する必要があります。 

ここで厄介なのは"会話文での検索"です。理由は以下の2点です。

1. 会話文特有のクエリー表現  
   この点が曲者で、入力が検索のインデックスと一言一句違わず同じことはまずありません。  
   例えば  
   - 省略
   - 言いかえ
   - 余計な言葉のつけたし  
   は当然のように起こります。 <br>  
   例
   - [VUIの入力] 今日は早く起きられたから、チェックして
   - [タスクの登録内容] 習慣 "7時に起きる"  
2. 応答に結果の候補を多くだすことができない  
    lineなどの画面があるチャットと違い選択肢を多めに出して選ばせることはできません。  
    例えecho dotのように画面があっても、選択肢は3つが限界でしょう。  
    もちろん違ったら、「違います」と返事をしてもらって別の候補を返すこともできますが、 
    それでも2~3個が限界でしょう。  


以上の２点を考慮するために、以下のような対策をします

1. VUI専用の検索インデックス・アルゴリズムを作る
2. すでにある検索機能に合わせてクエリー変換をする  

1.のほうが性能は高いでしょうが、VUIのログが蓄積されている必要があります。 
2.は変換がボトルネックになりやすいのですが、今ある機能を流用できます。

##### ちなみに自分はどうしたか  
HabiticaはAPIでそもそも検索機能が提供されていません。 
そのため検索自体を自分でしました。  
コードの実装では検索は形態素解析 + 激遅い実装のcosine similarityで行っています。 
ほぼダミーな実装で性能が悪く、実用性はありません。  

本格的に実装するには、例えばElasticSearchなどの検索エンジンや機械学習を利用する必要があるでしょう。 
(この点に気づいたため、BM25などのスコアを実装するまでもないかと思い止めました。)

### コンテキストを考慮したエクスプローラを用意する

ユーザがデータを加えて管理するタイプのアプリケーションは、
ユーザが登録したデータの一覧にUIからアクセスできないと操作対象が分かりにくいことがあります。 
これがVUIにとってひじょうに厄介です。  

例えばHabiticaなら、今どういうタスクが登録されているか知りたいことがあります。 
しかしすべてを読み上げるわけにはいきません。 ここでもせいぜい2~3個でしょう。 　

ここまで絞るには、タスクなら

- 登録日の新旧
- 締め切りの近さ
- 難易度
- checklistの項目数（HabiticaはTaskの中にchecklistを登録できる）

などで優先度をスコアリングするといいでしょう。  

ただしコンテキスト関係なく、現在の登録内容を漠然と知りたいこともあるので
ランダムに返す機能も欲しいところです。  

###タイミングに合わせた音声からアクセスできるマニュアルやヘルプを用意する。

理想はユーザが会話の流れに沿って、会話を続ければ使い方や仕様を知らなくてすむことです。
しかし、実際にはどうしてもマニュアル・ヘルプ的な内容が必要になることがあります。 
ただし通常のアプリケーションのように、ただマニュアル・ヘルプドキュメントを用意すればいいわけではありません。  

そもそもVUIを使うユーザは手間を省きたいケースが多いのですから、
ユーザがわざわざ自発的にドキュメントに目を通したりヘルプを検索しないといけないというのはサービスの価値を下げます。

そのため会話からアクセスできる必要があります。
例えば必要なのは、このVUIが何をできるか機能レベルで説明するものです。

例

- [ユーザ]なにができる 
- [vui]このサービスはタスクの登録、削除、チェック、確認ができます


会話の流れの中で説明を入れられると、使い方が分かっているユーザにはストレスになります。

例

- [ユーザ] タスクを登録して
- [vui] タスクはToDo、習慣、日課の三種類、難易とてもやさしいやさしい普通難しいの4段階で登録できます。
- [ユーザ] (そんなの前も使ったんだから知ってるよ)

かといって、間違うまで分からないという仕様も考えものです。

- [ユーザ]タスクを登録して
- [vui]何のタスクを登録しますか
- [ユーザ] 　(どういうふうに登録するんだっけ。確かこんな感じでいけたはず)プロジェクトクリスマスツリーの飾りつけをasapで
- [vui] よくわかりませんでした。タスクはTodo,週間、日課の三種類、難易とてもやさしいやさしい普通難しいの4段階で登録できます。

これはこれでストレスになるので、会話の途中で常に今やろうとしていることのヘルプを尋ねられるといいでしょう。

- [ユーザ]タスクを登録して
- [vui]何のタスクを登録しますか
- [ユーザ] どういうふうに登録するんだっけ。
- [vui] タスクはToDo、習慣、日課の三種類、難易とてもやさしいやさしい普通難しいの4段階で登録できます。
- [ユーザ] ToDoにクリスマスツリーの飾りつけを難易度優しいで。

<!-- 
### intentは階層化する

dialogflowやalexなどボット開発の多くのサービス・フレームワークは、  
会話文をまず意図(=intent)で分類する仕組みをとっています。  
しかし、intentの粒度がそろわなかったり、  
サンプル文の中にどっちつかずのものがあると分類のprecisionやrecallが落ちます。  

例

- [ユーザ] ToDo仕事のタスクを登録するの内容を確認をして
- [VUI] (タスクの登録なのか内容の確認なのかどっちだろう・・・)

その場合は標準的な実装ではなくなりますが、intentを階層化したほうが性能があがります。

先ほどの例なら、
1. 
2.  -->
 
### 内容に応じて速度を変える

これはまだできるスマートスピーカーやアプリがあるかわかりませんが、 
内容に応じで音声の速度を変えられるとベターです。
例えば前述したエクスプローラや検索で2~3個の候補を挙げる応答の場合、
ゆっくり読み上げられると時間がかかって仕方がありません。  

聞き逃しがない程度にスピードを上げられると、ユーザーのストレスが減ります。  
もちろんゆっくり聴かないと分からない人もいるので、 
できれば個人に応じてカスタマイズできればベストですが、 
会話ログが十分にたまるまでは難しいでしょう。  


### モジュール化/オブジェクト指向設計/グラフ構造の徹底

最後だけデザインではなく、コーディング上の注意です。 
パターンが多く条件分岐がどんどんに増えるので、 
モジュール化やオブジェクト指向設計をいつも以上に徹底します。  

結合度が高いと変数の組み合わせからテストケースが膨大になります。 
理想的には、ユニットテストをしやすいような実装を心がけます。  

また、グラフ構造を意識してコーディングしないと、
どういう会話の経路がありうるのか分からなくなります。  

## まとめ

自分の経験から、VUIデザインのTipsを挙げてみました。 
VUIは一般ユーザがストレス無く操作できることが特に求められます。 
しかし、現状の技術の制約やプラクティスの蓄積具合ではまだまだ難しいところがあります。  

だからと言って、条件が整うまでVUIはやらないというのはその利点からもったいないと思います。 
是非使えるVUIのデザイン/実装にトライして、できればノウハウを共有していただけると幸いです。