Cortana を使用したユーザーとの関係構築 (Windows 10 by 10)

※本ブログは Building Apps for Windows "Using Cortana to interact with your customers (10 by 10)" の抄訳です。

Windows 10 by 10 開発シリーズの今回のテーマは、Windows 10 を使用してアプリを起動しなくてもユーザーとの関係を促進できる方法です。前回のトピックであるライブ タイルと通知では、アプリのエクスペリエンスを拡張する方法を 1 つ紹介しました。今回は、Windows 10 パーソナル アシスタントの Cortana を使用してアプリを拡張する方法を解説します。Cortana を使用して実現できることを解説するため、今回のブログ記事では GitHub (英語) の AdventureWorks サンプルを記事の中で掲載したコードのベースとして使用しています。

今回のブログ記事では、Cortana とは何か、Cortana とユーザーが有意義な会話をできるようにする方法、Cortana をアプリに実装するために必要な初期作業について説明します。また、Cortana を使用するシナリオに応じてアプリとエンド ユーザーはさまざまな形でやり取りできますが、そのうち最も一般的な 3 つの形も紹介します。

1_cortana10x10

 

Cortana とは

Windows 10 で採用されたすばらしい機能の 1 つに、もともと Windows Phone の機能だった Cortana パーソナル アシスタント (英語) ほがあります。Cortana は、自然言語を使用した操作を可能にする Windows 10 の中核的な機能です。Cortana を使用すると、ユーザーは人間に話しかけるのとまったく同じ方法で、Windows (コア OS とあなたが開発したものも含めたアプリとの両方) とかかわることができます。たとえば、Cortana が音声を使用してユーザーに答えを返すことができるような、あなたが開発したアプリならではの質問を考えてみてください。「次の旅行の日程はいつですか」、「ラジオ局を検索してもらえますか」、「ジャックはオンラインですか」のような質問です。これらの質問に対して Cortana が提示する音声と画面表示を提供することで、アプリは質問に答えることができるようになります。ユーザーがアプリで Cortana に頼むことができるタスクを考えてみましょう。たとえば、「ロンドンへの旅行をキャンセルしてください」、「このラジオ局を聞きたいです」、「遅れることをジャックに伝えてください」のようなものです。

音声コマンドをアプリへのディープ リンクとして使用すれば、音声コマンドを通じてアプリの情報にすばやくアクセスできます。アプリ内へのショートカットとして機能するタイルが作成可能であるのと同様に、音声コマンドもアプリ内画面へのショートカットとして使用できます。さらに、よくアクセスするアプリ内の行き先をスタート画面にピン留めする機能をユーザーに提供できるのと同様に、Cortana の音声コマンドを使用してその行き先にアクセスする機能も提供できます。この機能によって、ユーザーの生産性が向上し、さらにアプリにアクセスしやすくなります。

Cortana を拡張することで、ユーザーは簡単な音声コマンドを使用して作業できるようになり、ユーザーとの関係を構築し、ユーザーを喜ばせることができます。ただし、今回のブログ記事で取り上げるのは Cortana のユーザー機能ではなく、Cortana をアプリに実装する方法であることに注意してください。

Cortana との会話

Cortana の操作は会話ベースなので、普通に話していると錯覚する流れるようなエクスペリエンスが要求されます。MSDN では包括的な Cortana の設計ガイドラインで、ユーザー操作のベストプラクティスを紹介しています。Cortana の操作で成功を収めるには、やり取りが効率的、適切、明瞭、および信用できるという原則に従っている必要があることにも注意してください。

上記の各原則にどのような意味があるのかを説明しましょう。

  • 効率的: 言葉は少ない方が効果的になります。意味が通じる範囲で簡潔に、できる限り言葉数を減らします。
  • 適切: 本題から離れないようにします。ユーザーが ABBA のお気に入りの曲をプレイリストに追加するようにリクエストした場合、ABBA の曲を思う存分楽しめるようになったことをだけを簡潔に伝えます。バッテリーが少なくなっていることを一緒に伝えたりしてはいけません。 clip_image002
  • 明瞭: ユーザーに向けて会話を記述します。会話では、知っている人がほとんどいないような専門用語ではなく、日常的な言葉を使用するようにします。
  • 信用できる: 返答は実際に起こっていることやユーザーの好みを正確に反映している必要があります。アプリがタスクを完了していない場合に、完了したと伝えてはいけません。また、人によっては音声として聞くことを好まない可能性がある会話を返してもいけません。

cortanaBestFriend

 

さらに、Cortana とのやり取りをローカライズすることも検討が必要です。アプリの他の機能がローカライズ済みの場合や、アプリを世界で利用できるようにしている場合は、特にローカライズをご検討ください。現在 Cortana は、米国、英国、中国、フランス、イタリア、ドイツ、スペインでご利用いただけます。今後 Cortana を利用できる市場はさらに拡大する予定です。Cortana の操作をローカライズして市場に合わせることが、アプリに実装した Cortana 機能の使用を促進することにつながるでしょう。

Cortana に応答の教育を

Cortana は、音声コマンドの定義 (VCD) ファイルを使用して、ユーザーがアプリで行う可能性のある音声操作を定義します。VCD ファイルは XML ベースなので、コードによって作成できます。初めてアプリが実行されたときに VCD のコマンド セットがインストールされます。以下は、VCD の簡易サンプルです。

 <?xml version="1.0" encoding="utf-8"?>
<VoiceCommands xmlns="https://schemas.microsoft.com/voicecommands/1.1">
  <CommandSet xml:lang="en-us" Name="AdventureWorksCommandSet_en-us">
    <CommandPrefix> Adventure Works, </CommandPrefix>
    <Example> Show trip to London </Example>
 
    <Command Name="showTripToDestination">
      <Example> show trip to London </Example>
      <ListenFor RequireAppName="BeforeOrAfterPhrase"> show trip to {destination} </ListenFor>
      <Feedback> Showing trip to {destination} </Feedback>
      <Navigate/>
    </Command>
 
    <PhraseList Label="destination">
      <Item> London </Item>
      <Item> Dallas </Item>
    </PhraseList>
 
  </CommandSet>
<!— 他の言語用の CommandSet -->
</VoiceCommands>

アプリがアクティブになったときには、OnLaunched アプリ イベントハンドラーで InstallCommandSetsFromStorageFileAsyncを呼び出し、Cortana が聞き取るコマンドを登録する必要があります。デバイスのバックアップを復元してアプリを再インストールした場合、音声コマンド データは保持されないことに注意してください。アプリの音声コマンドデータが変更されないようにするには、アプリが起動またはアクティブ化されるたびに VCD ファイルを初期化することを検討してください。VCD の現在のインストール状況を示す設定ファイルを保存し、アプリが起動またはアクティブ化されるたびにその設定ファイルを確認することもできます。VCD をアプリに読み込む基本的なコードの一部を以下に示します。

 var storageFile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///CortanaVcd.xml"));
 
await Windows.ApplicationModel.VoiceCommands.VoiceCommandDefinitionManager.InstallCommandSetsFromStorageFileAsync(storageFile);

動的な変更

文法を初期化したら、今度はこの文法を実行時に動的に変更することができます。上記のコードで読み込んだ VCD を動的に変更するシンプルな例を以下に示します。

 private Windows.ApplicationModel.VoiceCommands.VoiceCommnadDefinition.VoiceCommandSet commandSetEnUs;
 
if (Windows.ApplicationModel.VoiceCommands.VoiceCommandDefinitionManager.InstalledCommandSets.TryGetValue("AdventureWorksCommandSet_en-us", out commandSetEnUs))
{
  // このコードは目的地リストをすべて置き換えます。
  await commandSetEnUs.SetPhraseListAsync("destination", new string[] {"Chicago", "Seattle", "New York", "Phoenix"});
}

アプリと Cortana のやり取り

アプリと Cortana は、さまざまな形でやり取りします。その中でも最も一般的形は次の 3 つです。

  1. Cortana 経由でアプリを起動します。アプリをフォアグラウンドで起動するだけではなく、アプリ内で実行する動作やコマンドのディープ リンクも指定できます。
  2. Cortana は、簡単なユーザー操作によってバックグラウンドでアプリにデータを保存したり、アプリからデータを返したりできるようにします。
  3. Cortana は、ユーザーとアプリが相互にやり取りできるようにします。

アプリをフォアグラウンドで起動する

複雑なタスクがあり、ユーザーがアプリ内に直接アクセスできるようにする場合は、Cortana を使用することをお勧めします。音声コマンドを使用することで一部の複雑なタスクはもっと短時間で完了し、正確性も向上するので、Cortana を使用するのが最適です。

 protected override void OnActivated(IActivatedEventArgs e)
{
  // 音声コマンドでアプリがアクティブ化されたかを確認します。
  if (e.Kind != Windows.ApplicationModel.Activation.ActivationKind.VoiceCommand)
  {
    return;
  }
 
  var commandArgs = e as Windows.ApplicationModel.Activation.VoiceCommandActivatedEventArgs;
  var navigationParameterString = "";
 
  Windows.ApplicationModel.VoiceCommands.VoiceCommand.SpeechRecognitionResult speechRecognitionResult = commandArgs.Result;
 
  // 音声コマンド名と話す対象のテキストを取得します。
  string voiceCommandName = speechRecognitionResult.RulePath[0];
  string textSpoken = speechRecognitionResult.Text;
 
  // commandMode は、”音声” または “テキスト” のいずれかで、ユーザーによる音声コマンドの入力方法を示します。
  // アプリでは無声でフィードバックを行う “テキスト” モードを考慮する必要があります。
  string commandMode = this.SemanticInterpretation("commandMode", speechRecognitionResult);
 
  switch (voiceCommandName)
  {
    case "showTripToDestination":
      // 音声コマンドの {destination} 語句の値にアクセスします。
      string destination = speechRecognitionResult.SemanticInterpretation.Properties["destination"][0];
 
      // ページに渡すナビゲーション パラメーター文字列を作成します。
      navigationParameterString = string.Format("{0}|{1}|{2}|{3}",
                    voiceCommandName, commandMode, textSpoken, destination);
 
      // この音声コマンドの移動先ページを設定します。
      navigateToPageType = typeof(TripPage);
    break;
 
    default:
      // 音声コマンド名に一致するものがない場合は MainPage に移動します。
      navigateToPageType = typeof(MainPage);
      break;
  }
 
  if (this.rootFrame == null)
  {
    // アプリで新しい Frame を作成する必要がありますが、表示はされません。
  }
 
  if (!this.rootFrame.Navigate(navigateToPageType, navigationParameterString))
  {
    throw new Exception("Failed to create voice command page");
  }
}

Cortana でアプリのデータを保存したり受け取ったりするシンプルなやり取り

Cortana を VCD に接続して基本的な操作を実行できるようにしたので、次は Cortana を使用してもっと難しい処理を行う方法について詳しく見ていきましょう。たとえば、Cortana 経由でユーザーにデータを返したり、一部のデータを保存したりすることができます。MSDN では総合的な Cortana 用にバックグラウンド アプリを設定するチュートリアルを用意しています。概要手順は次のとおりです。

  1. ソリューションで Windows ランタイム コンポーネント プロジェクトを作成します。
  2. IbackgroundTask インターフェイスを実装する新しいクラスを作成します。このクラスはアプリ サービスとして機能します。
  3. ユニバーサル Windows プラットフォーム (UWP) アプリの Package.appxmanifest で、この新しいアプリ サービスの新しい Extension を追加します。上記の MSDN ドキュメントではこの手順を詳しく解説しています。

Package.appxmanifest の XML サンプルは次のようになります。

 <Package>
  <Applications>
    <Application>
      <Extensions>
        <Extension Category="windows.appService"
          EntryPoint=
            "AdventureWorks.VoiceCommands.AdventureWorksVoiceCommandService">
          <AppService Name="AdventureWorksVoiceCommandService"/>
        </Extension>
      </Extensions>
    <Application>
  <Applications>
</Package>

アプリ サービスには、起動後に、ReportSuccessAsync を呼び出すのに 0.5 秒という時間が与えられます。Cortana はアプリから提供されたデータを使用して、VCD ファイルで指定されたフィードバックを画面に表示して、音声化します。アプリ サービスが呼び出しから戻るまでに 0.5 秒よりも長くかかる場合は、Cortana は以下に示すようなハンドオフ画面を挿入します。ReportSuccessAsync が呼び出されるか、5 秒経過するまで Cortana はハンドオフ画面を表示します。アプリ サービスによって ReportSuccessAsync が呼び出されなかった場合、または Cortana に情報を渡す VoiceCommandServiceConnection メソッドが呼び出されなかった場合、ユーザーはエラーメッセージを受け取り、アプリ サービスによる呼び出しはキャンセルされます。

2_cortana10x10

IbackgroundTask を実装してアプリ サービスとして機能できるようにするために必要な基本コードは次のとおりです。

 using Windows.ApplicationModel.Background;
 
namespace AdventureWorks.VoiceCommands
{
  public sealed class AdventureWorksVoiceCommandService : IBackgroundTask
  {
    public void Run(IBackgroundTaskInstance taskInstance)
    {
      BackgroundTaskDeferral _deferral = taskInstance.GetDeferral();
 
      //
      // TODO: コードの挿入
      //
      _deferral.Complete();
    }
  }
}

ユーザーと Cortana のやり取り

基本的なことは確認したので、Cortana でユーザーが多様な操作を行うための準備が整いましたアプリは、さまざまな種類の画面を指定することで次のような機能をサポートできます。

  • 正常終了
  • ハンドオフ
  • 進行状況
  • 確認
  • 不明瞭解消
  • エラー

上記のシナリオの 1 つである不明瞭解消について詳しく解説しましょう。アプリから返す選択肢は複数存在することがあります。この場合、アプリは次に行う処理についてあいまいさを解消しなければなりません。ユーザーが音楽を選択している場合、次に再生するユーザーのお気に入りのバンドの選択肢として ABBA、Nickelback、または White Snake があるとしても、Cortana はこれに対応できます。Adventure Works サンプルから抜粋した下記のコードは、アプリサービス内から不明瞭解消を扱う方法を示しています。

 // 最初の質問に対する VoiceCommandUserMessage を作成します。
var userPrompt = new VoiceCommandUserMessage();
userPrompt.DisplayMessage = "Which one do you want to cancel?";
userPrompt.SpokenMessage = "Which Chicago trip do you wanna cancel?";
// 2 番目の質問に対する VoiceCommandUserMessage を作成します。
// Cortana による再指示が必要な場合のためのものです。
var userReprompt = new VoiceCommandUserMessage();
userReprompt.DisplayMessage = “Which one did you want to cancel?”;
userReprompt.SpokenMessage = "Which one did you wanna to cancel?";
 
// アイテムの選択肢を表示するコンテンツ タイルのリストを作成します。
var destinationsContentTiles = new List<VoiceCommandContentTile>();
 
// アプリの VoiceCommandContentTiles を作成します。
for(int i=0; i < 5; i++)
{
  var destinationTile = new VoiceCommandContentTile();
  destinationTile.ContentTileType = VoiceCommandContentTileType.TitleWith68x68IconAndText;
 
  // AppContext はオプションです。
  // AppContext の値をアプリ固有の値に置き換えます。
  destinationTile.AppContext = "id_Vegas_00" + i;
  destinationTile.Title = "Tech Conference";
 
  destinationTile.TextLine1 = "May " + i + "th";
 
  destinationsContentTiles.Add(destinationTile);
}
 
// 不明瞭解消の応答を作成します。
var response = VoiceCommandResponse.CreateResponseForPrompt(userPrompt, userReprompt, destinationsContentTiles);
 
// Cortana に不明瞭解消の画面を表示することをリクエストします。
var voiceCommandDisambiguationResult = await voiceServiceConnection.RequestDisambiguationAsync(response);
 
if (voiceCommandDisambiguationResult != null)
{
   // voiceCommandDisambiguationResult.SelectedItem を使用して処理を受け取ります。
   // Cortana を呼び出して、5 秒後に次の画面を表示し、
   // 遷移画面を回避します。
}

現時点での Cortana のまとめ

この記事で Cortana が簡単にアプリに追加できることについて、理解を深めていただけたのであればさいわいです。アプリに Cortana を追加することで、ユーザーとのさまざまなやり取りの形が広がります。アプリを起動することから、アプリの起動も必要ない複雑なやり取りに至るまで、Cortana を実装することでユーザーとの関係を大きく促進できます。アプリの機能へのディープ リンクを新しい方法で提供するようなシンプルなものであってもCortana の拡張機能をアプリで活用する方法について検討していただけたのであればさいわいです。

アプリに Cortana を実装する意義があると感じた場合はぜひご活用ください。また、アプリを更新して提出したら DVLUP の課題「アプリに Cortana を追加」(英語) を活用してください。そうすれば、アプリの更新に対してポイントと XP を獲得できます。ご連絡は @WindowsDev 宛てにハッシュタグ #Win10x10 を付けて英語でお送りください。Windows での開発について開発者の皆様からコメントをお待ちしております。

また、Windows 10 by 10 開発シリーズのスケジュールで、このシリーズで今後取り上げる予定のトピックもご確認ください。Cortana の詳細については、2~3 週間後にあらためて本シリーズを確認してください。アプリで Cortana の自然言語機能を使用し、さらに個人に向けたユーザー エクスペリエンスを提供する方法について解説します。

Cortana の拡張に関する追加リソース

Cortana の拡張の詳細については、以下の追加リソースをご覧ください。

Oliver Matis は、アプリと Cortana の統合の一部始終に関する優れたベストプラクティスについて (英語) 掘り下げた記事を投稿しています。