Integrando a Cortana em seu aplicativo Windows 10

Com o lançamento do Windows 10 para Desktop no final desse mês, os desenvolvedores têm que estar preparados para trazer para seus aplicativos as novidades oferecidas pelo novo Sistema Operacional da Microsoft.

Uma dentre as várias funcionalidades apresentadas é a vinda da Cortana, assistente pessoal virtual já conhecida pelos usuários do Windows Phone. Ela pode auxiliá-los a pesquisar na web, encontrar coisas no PC, manter o controle de calendário e até mesmo contar piadas.

integrando_cortana_em_seu_aplicativo_windows_10_screenshot

Além dessas tarefas, a Cortana poderá ser integrada ao seu aplicativo trazendo assim um diferencial que poderá aumentar o envolvimento dos seus usuários.

Basicamente existem 3 formas de incorporar os comandos de voz no seu aplicativo:

  • Comandos de voz no primeiro plano (Foreground)
  • Reconhecimento de voz dentro do aplicativo
  • Comandos de voz no segundo plano (Background)

Nesse tutorial vamos explicar como fazer essa integração em uma app Universal Windows Platform usando comandos de voz no primeiro plano.

Para efeito de demonstração, imaginem que estamos trabalhando em um aplicativo responsável por controlar itens de uma casa inteligente, como por exemplo, luzes, portas, temperatura etc. Chamaremos esse app de HomeControl e queremos que alguns dos itens controlados por ele possam ser disparados através de comandos de voz interpretados pela Cortana.

Vamos começar!?!

Pré-requisitos:

Criando a definição de comandos de voz (VCD)

Atualmente a Cortana só está trabalhando em Inglês, portanto todos os comandos usados nesse tutorial serão feitos neste idioma.

O primeiro passo e também o mais importante é criar o Voice Command Definitions ou simplesmente VCD. É aqui que daremos as instruções sobre o que a Cortana deverá ouvir e interpretar. Para isso, criaremos um novo arquivo XML dentro do projeto Windows Universal (o arquivo poderá ser criado na raiz do projeto). Daremos o nome de HomeControlCommands.xml para esse arquivo.

Descreveremos aqui alguns pontos que serão inseridos neste arquivo recém criado.

Para requisitar alguma tarefa, os usuários precisam dizer o nome do aplicativo como parte do comando de voz. Exemplo:

Viber, start a chat with Jonas
Facebook, what’s up with Jonas
Adventure Works, show my trip to London

Por padrão é utilizado o nome de exibição do aplicativo mas podemos fornecer uma alternativa, como forma abreviada, quando o nome for longo ou difícil de ser pronunciado. Para isso, utilizaremos o elemento CommandPrefix, conforme especificado abaixo.

<?xml version="1.0" encoding="utf-8" ?>
<VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.2">
  <CommandSet xml:lang="en-us" Name="HomeControlCommandSet_en-us">
    <CommandPrefix>HomeControl</CommandPrefix>
    <Example>Control alarm, temperature, light and others</Example>
  </CommandSet>
</VoiceCommands>

Precisamos também colocar uma descrição para o comando dentro do elemento Example. Isso aparecerá quando solicitarmos o seguinte comando para a Cortana:

Cortana, what can I say?

integrando_cortana_em_seu_aplicativo_windows_10_cortana_help

Vamos criar o primeiro comando.

<Command Name="Activate_Alarm">
    <Example>Activate alarm</Example>
    <ListenFor>Activate alarm</ListenFor>
    <Feedback>Activating alarm</Feedback>
    <Navigate />
</Command>

Explicando o que acabamos de fazer, nós criamos um novo comando e demos um nome para ele através do atributo Name. É através desse nome que poderemos identificar qual o comando lançado quando estivermos dentro do app.

No elemento Example demos um exemplo representativo do que o usuário poderá dizer para utilizar desse comando.

O elemento ListenFor contém uma palavra ou frase que seu aplicativo irá reconhecer para este comando. Podemos ter até 10 elementos desse tipo para um mesmo comando. Como por exemplo:

<ListenFor>Activate alarm</ListenFor>
<ListenFor>Turn on alarm</ListenFor>
<ListenFor>Initialize alarm</ListenFor>

Após identificar o comando, a Cortana dará um feedback ao usuário para mostrar que executará o que foi solicitado. O texto exibido e falado pela Cortana será aquele definido aqui no elemento Feedback.

O elemento Navigate poderá conter um atributo chamado Target que pode ser usado para especificar a página que o aplicativo deve navegar.

Importante: Todos os elementos descritos acima são obrigatórios!

Algo que podemos fazer para melhorar os comandos é construir nossas frases usando palavras opcionais. Para isso, basta colocar essas palavras entre colchetes.

<Command Name="Activate_Alarm">
  <Example>Activate alarm</Example>
  <ListenFor>[Would] [you] [please] activate [the] alarm [please]</ListenFor>
  <Feedback>Activating alarm</Feedback>
  <Navigate />
</Command>

Vamos evoluir um pouco este exemplo para mostrar o atributo RequireAppName, responsável por especificar onde o nome do aplicativo pode aparecer no comando de voz.

<Command Name="Activate_Alarm">
  <Example>Activate alarm</Example>
  <ListenFor RequireAppName="BeforeOrAfterPhrase">Activate alarm</ListenFor>
  <ListenFor RequireAppName="ExplicitlySpecified">Activate {builtin:AppName} alarm</ListenFor>
  <Feedback>Activating alarm</Feedback>
  <Navigate />
</Command>

Dessa forma, podemos disparar esta ação através dos comandos de voz:

  • HomeControl, Activate alarm
  • Activate alarm, HomeControl
  • Activate, HomeControl, alarm

Para finalizar, podemos construir nossos comandos e prepará-los para receberem argumentos.

Para isso vamos usar os elementos PhraseList e PhraseTopic.

<Command Name="Change_Temperature">
  <Example>Change temperature to 25º degrees</Example>
  <ListenFor>Change temperature to {temperature} degrees</ListenFor>
  <Feedback>Changing temperature to {temperature} degrees</Feedback>
  <Navigate />
</Command>

<Command Name="Change_Light_Color">
  <Example>Change light color to yellow</Example>
  <ListenFor>Change light color to {colors}</ListenFor>
  <Feedback>Changing light color to {colors}</Feedback>
  <Navigate />
</Command>

<PhraseList Label="colors">
  <Item>yellow</Item>
  <Item>green</Item>
  <Item>red</Item>
</PhraseList>

<PhraseTopic Label="temperature">
</PhraseTopic>

Notem que usamos o PhraseTopic quando temos um range muito grande de palavras a serem identificadas. No nosso caso são diversos os valores de temperaturas que podem ser solicitados.

Já o PhraseList é apropriado para um conjunto relativamente pequeno de palavras. No nosso exemplo são algumas cores suportadas pelo controle de lâmpadas.

Em ambos os casos, o label desses elementos são referenciados através de chaves dentro dos comandos.

Ao final temos nosso VCD completo:

<?xml version="1.0" encoding="utf-8" ?>
<VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.2">
  <CommandSet xml:lang="en-us" Name="HomeControlCommandSet_en-us">
    <CommandPrefix>HomeControl</CommandPrefix>
    <Example>Control alarm, temperature, light and others</Example>
    
    <Command Name="Activate_Alarm">
      <Example>Activate alarm</Example>
      <ListenFor>[Would] [you] [please] activate [the] alarm [please]</ListenFor>
      <ListenFor RequireAppName="BeforeOrAfterPhrase">Activate alarm</ListenFor>
      <ListenFor RequireAppName="ExplicitlySpecified">Activate {builtin:AppName} alarm</ListenFor>
      <Feedback>Activating alarm</Feedback>
      <Navigate />
    </Command>

    <Command Name="Change_Temperature">
      <Example>Change temperature to 25º degrees</Example>
      <ListenFor>Change temperature to {temperature} degrees</ListenFor>
      <Feedback>Changing temperature to {temperature} degrees</Feedback>
      <Navigate />
    </Command>

    <Command Name="Change_Light_Color">
      <Example>Change light color to yellow</Example>
      <ListenFor>Change light color to {colors}</ListenFor>
      <Feedback>Changing light color to {colors}</Feedback>
      <Navigate />
    </Command>

    <PhraseList Label="colors">
      <Item>yellow</Item>
      <Item>green</Item>
      <Item>red</Item>
    </PhraseList>

    <PhraseTopic Label="temperature">
    </PhraseTopic>

  </CommandSet>
</VoiceCommands>

Para maiores informações acesse a documentação Voice Command Definition (VCD) elements and attributes.

Registrando o VCD no App Startup

Com o VCD criado, precisamos agora registrá-lo na abertura da aplicação. Para isso vá até o método App.OnLaunched dentro do arquivo App.xaml.cs e inclua as seguintes linhas:

        protected async override void OnLaunched(LaunchActivatedEventArgs e)
        {
            ...
            // Install the VCD
            try
            {
                StorageFile vcdStorageFile = await Package.Current.InstalledLocation.GetFileAsync(@"HomeControlCommands.xml");
                await VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync(vcdStorageFile);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("There was an error registering the Voice Command Definitions", ex);
            }
        }

Lidando com a ativação de comando de voz

Com a definição de comandos de voz registrada, a Cortana sabe agora quais são os comandos esperados para nossa aplicação. Precisamos apenas nos preparar para receber a notificação de quando algum dos nossos comandos forem interpretados.

Faça o override do método App.OnActivated dentro do arquivo App.xaml.cs como no código abaixo:

protected override void OnActivated(IActivatedEventArgs e)
{
	// Handle when app is launched by Cortana
	if (e.Kind == ActivationKind.VoiceCommand)
	{
		VoiceCommandActivatedEventArgs commandArgs = e as VoiceCommandActivatedEventArgs;
		SpeechRecognitionResult speechRecognitionResult = commandArgs.Result;

		string voiceCommandName = speechRecognitionResult.RulePath[0];
		string textSpoken = speechRecognitionResult.Text;
		IReadOnlyList<string> recognizedVoiceCommandPhrases;

		System.Diagnostics.Debug.WriteLine("voiceCommandName: " + voiceCommandName);
		System.Diagnostics.Debug.WriteLine("textSpoken: " + textSpoken);

		switch (voiceCommandName)
		{
			case "Activate_Alarm":
				System.Diagnostics.Debug.WriteLine("Activate_Alarm command");
				break;

			case "Change_Temperature":
				string temperature = "";

				if (speechRecognitionResult.SemanticInterpretation.Properties.TryGetValue("temperature", out recognizedVoiceCommandPhrases))
				{
					temperature = recognizedVoiceCommandPhrases.First();
				}

				System.Diagnostics.Debug.WriteLine("Change_Temperature command. The passed PhraseTopic value is " + temperature);
				break;

			case "Change_Light_Color":
				string color = "";

				if (speechRecognitionResult.SemanticInterpretation.Properties.TryGetValue("colors", out recognizedVoiceCommandPhrases))
				{
					color = recognizedVoiceCommandPhrases.First();
				}

				System.Diagnostics.Debug.WriteLine("Change_Light_Color command. The passed PhraseList value is " + color);
				break;

			default:
				System.Diagnostics.Debug.WriteLine("Unknown command");
				break;
		}
	}
}

Para testar, basta usar a Cortana e usar os comandos de voz registrados no VCD.

Exemplo: HomeControl, change temperature to 23 degrees

integrando_cortana_em_seu_aplicativo_windows_10_cortana_change_temperature

Nota: É possível utilizar os comandos desse tutorial com o Windows Phone 8.1. Para isso, altere o schema do VCD de http://schemas.microsoft.com/voicecommands/1.2 para http://schemas.microsoft.com/voicecommands/1.1. Além disso, para registrar o VCD, utilize o VoiceCommandManager.InstallCommandSetsFromStorageFileAsync no lugar do VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync.

O código fonte do exemplo acima está disponível no repositório GIT oficial do blog talkitbr.

Continuem acessando nosso blog talkitbr para saberem mais sobre as novidades que estão vindo por aí. Até mais!!!

5 comentários

  1. Cara, sabe quando vc procura muito uma coisa em vários lugares e acaba desistindo por não achar exatamente o que queria, e aí depois de um tempo por curiosidade dá mais uma leve procurada e sem querer acha a informação perfeita? Foi isso o que aconteceu comigo ao achar esse post.

    Parabéns por esse tutorial! Tudo o que eu queria saber, vc respondeu com esse post. Muito Obrigado!

    Curtir

  2. Hi, I ran the sample application and during runtime the VCD was registred into my system. Now the Homecontrol feature is available in Cortana. How can I unregister so that it will not available anymore in Cortana?

    Curtir

    • There’s no such method at this moment. I found this answer given by Andrew Pilley, from Microsoft: “Currently, there isn’t a way to remove a registered VCD explicitly, currently you need to remove your app, and then an attempt to trigger any of the voice commands the VCD registers will detect the missing app and remove the VCD”.

      Curtir

  3. Opa! Excelente tutorial! Duas perguntas basicas rsrs:

    1. Como faco para ver as mensagens de log quando ativo o App usando a cortana?
    2. Gostaria de testar o app usando texto ao inves de ter que falar. O que tenho que modificar?

    Obrigado!

    Curtir

  4. 1. Visual studio 2015. Abra propriedades do projeto e va em Debug, marque a opcao “Do not launch, but debug…”. Quando for debugar o projeto aperte F5 e ative o App pela cortana, o debug no VS comecara.
    2. O texto funciona automaticamente uma vez que o VCD foi carregador. POREM: nao inclua nada de pontuacao, nem mesmo um ponto ao final da frase..

    Curtir

Deixe um comentário