Compartir a través de


Activar una aplicación en primer plano con comandos de voz a través de Cortana

Advertencia

Esta característica ya no se admite a partir de la actualización de mayo de 2020 de Windows 10 (versión 2004, nombre de código "20H1").

Además de usar comandos de voz en Cortana para acceder a las características del sistema, también puedes ampliar Cortana con características y funcionalidades de la aplicación. Con comandos de voz, la aplicación se puede activar en primer plano y se puede ejecutar una acción o un comando dentro de la aplicación.

Cuando una aplicación controla un comando de voz en primer plano, toma el foco y Cortana se descarta. Si lo prefiere, puede activar la aplicación y ejecutar un comando como una tarea en segundo plano. En este caso, Cortana conserva el foco y la aplicación devuelve todos los comentarios y resultados a través del lienzo de Cortana y la voz de Cortana .

Los comandos de voz que requieren contexto adicional o entrada de usuario (como enviar un mensaje a un contacto específico) se controlan mejor en una aplicación en primer plano, mientras que los comandos básicos (como enumerar los próximos viajes) se pueden controlar en Cortana a través de una aplicación en segundo plano.

Si quieres activar una aplicación en segundo plano mediante comandos de voz, consulta Activar una aplicación en segundo plano en Cortana mediante comandos de voz.

Nota:

Un comando de voz es una expresión única con una intención específica, definida en un archivo de definición de comandos de voz (VCD), dirigida a una aplicación instalada a través de Cortana.

Un archivo VCD define uno o varios comandos de voz, cada uno con una intención única.

Las definiciones de comandos de voz pueden variar en complejidad. Pueden admitir cualquier cosa desde una sola expresión restringida a una colección de expresiones de lenguaje natural más flexibles, todas denotando la misma intención.

Para demostrar las características de la aplicación en primer plano, usaremos una aplicación de planificación y administración de viajes denominada Adventure Works desde el ejemplo de comando de voz de Cortana.

Para crear un nuevo viaje de Adventure Works sin Cortana, un usuario iniciaría la aplicación y navegaría a la página Nuevo viaje . Para ver un viaje existente, un usuario iniciaría la aplicación, navegaría a la página Próximos viajes y seleccionaría el viaje.

Con comandos de voz a través de Cortana, el usuario puede decir simplemente "Adventure Works agregar un viaje" o "Agregar un viaje en Adventure Works" para iniciar la aplicación y navegar a la página Nuevo viaje . A su vez, diciendo "Adventure Works, mostrar mi viaje a Londres" iniciará la aplicación y navegará a la página detalles del viaje , que se muestra aquí.

Captura de pantalla del inicio de la aplicación en primer plano de Cortana

Estos son los pasos básicos para agregar la funcionalidad de comandos de voz e integrar Cortana con la aplicación mediante la entrada de voz o teclado:

  1. Cree un archivo VCD. Se trata de un documento XML que define todos los comandos hablados que el usuario puede decir para iniciar acciones o invocar comandos al activar la aplicación. Consulte Elementos y atributos de VCD v1.2.
  2. Registre los conjuntos de comandos en el archivo VCD cuando se inicie la aplicación.
  3. Controle el comando activation-by-voice-, la navegación dentro de la aplicación y la ejecución del comando.

Sugerencia

Requisitos previos

Si no estás familiarizado con el desarrollo de aplicaciones de Plataforma universal de Windows (UWP), consulta estos temas para familiarizarte con las tecnologías que se describen aquí.

Directrices de experiencia del usuario

Consulta Directrices de diseño de Cortana para obtener información sobre cómo integrar tu aplicación con Cortana y interacciones de voz para obtener sugerencias útiles sobre cómo diseñar una aplicación habilitada para voz útil y atractiva.

Creación de una nueva solución con un proyecto en Visual Studio

  1. Inicie Microsoft Visual Studio 2015.

    Aparece la página inicio de Visual Studio 2015.

  2. En el menú Archivo, seleccione Nuevo>Proyecto.

    Se abre el cuadro de diálogo Nuevo proyecto. El panel izquierdo del cuadro de diálogo le permite seleccionar el tipo de plantillas que se van a mostrar.

  3. En el panel izquierdo, expanda Plantillas instaladas > > Visual C# > Windows y, a continuación, elija el grupo de plantillas universales. El panel central del cuadro de diálogo muestra una lista de plantillas de proyecto para aplicaciones de Plataforma universal de Windows (UWP).

  4. En el panel central, seleccione la plantilla Aplicación vacía (Windows universal).

    La plantilla Aplicación en blanco crea una aplicación para UWP mínima que se compila y ejecuta, pero no contiene controles ni datos de interfaz de usuario. Agregue controles a la aplicación a lo largo de este tutorial.

  5. En el cuadro de texto Nombre , escriba el nombre del proyecto. En este ejemplo, usamos "AdventureWorks".

  6. Haga clic en Aceptar para crear el proyecto.

    Microsoft Visual Studio crea el proyecto y lo muestra en el Explorador de soluciones.

Agregar recursos de imagen al proyecto y especificarlos en el manifiesto de la aplicación

Las aplicaciones para UWP pueden seleccionar automáticamente las imágenes más adecuadas en función de la configuración específica y las funcionalidades del dispositivo (contraste alto, píxeles efectivos, configuración regional, etc.). Lo único que debe hacer es proporcionar las imágenes y asegurarse de que usa la convención de nomenclatura y la organización de carpetas adecuadas dentro del proyecto de aplicación para las distintas versiones de recursos. Si no proporciona las versiones de recursos recomendadas, la accesibilidad, la localización y la calidad de la imagen pueden sufrir, en función de las preferencias, capacidades, tipo de dispositivo y ubicación del usuario.

Para obtener más información sobre los recursos de imagen para los factores de contraste alto y escala, consulte Directrices para los recursos de icono e icono.

Asigne un nombre a los recursos mediante calificadores. Los calificadores de recursos son modificadores de carpeta y nombre de archivo que identifican el contexto en el que se debe usar una versión determinada de un recurso.

La convención de nomenclatura estándar es foldername/qualifiername-value[_qualifiername-value]/filename.qualifiername-value[_qualifiername-value].ext. Por ejemplo, images/logo.scale-100_contrast-white.png, que se puede hacer referencia en el código con solo la carpeta raíz y el nombre de archivo: images/logo.png. Consulte How to name resources using qualifiers (Cómo asignar nombres a los recursos mediante calificadores).

Se recomienda marcar el idioma predeterminado en los archivos de recursos de cadena (como en-US\resources.resw) y el factor de escala predeterminado en imágenes (como logo.scale-100.png), incluso si actualmente no tiene previsto proporcionar recursos de resolución localizados o múltiples. Sin embargo, como mínimo, se recomienda proporcionar recursos para 100, 200 y 400 factores de escala.

Importante

El icono de la aplicación usado en el área de título del lienzo de Cortana es el icono Square44x44Logo especificado en el archivo "Package.appxmanifest".

Creación de un archivo VCD

  1. En Visual Studio, haga clic con el botón derecho en el nombre del proyecto principal y seleccione Agregar > nuevo elemento. Agregue un archivo XML.
  2. Escriba un nombre para el archivo VCD (por este ejemplo, "AdventureWorksCommands.xml") y haga clic en Agregar.
  3. En Explorador de soluciones, seleccione el archivo VCD.
  4. En la ventana Propiedades , establezca Acción de compilación en Contenido y, a continuación, establezca Copiar en el directorio de salida en Copiar si es más reciente.

Edición del archivo VCD

Agregue un elemento VoiceCommands con un atributo xmlns que apunte a https://schemas.microsoft.com/voicecommands/1.2.

  1. Para cada idioma compatible con la aplicación, cree un elemento CommandSet que contenga los comandos de voz admitidos por la aplicación.

    Puedes declarar varios elementos CommandSet, cada uno con un atributo xml:lang diferente para que la aplicación se use en diferentes mercados. Por ejemplo, una aplicación para el Estados Unidos podría tener un CommandSet para inglés y un CommandSet para español.

    Precaución

    Para activar una aplicación e iniciar una acción mediante un comando de voz, la aplicación debe registrar un archivo VCD que contenga un CommandSet con un idioma que coincida con el idioma de voz seleccionado por el usuario para su dispositivo. El idioma de voz se encuentra en Configuración > Del idioma de voz del > sistema>.

  2. Agregue un elemento Command para cada comando que quiera admitir. Cada comando declarado en un archivo VCD debe incluir la siguiente información:

    • Atributo AppName que usa la aplicación para identificar el comando de voz en tiempo de ejecución.
    • Elemento Example que contiene una frase que describe cómo un usuario puede invocar el comando. Cortana muestra este ejemplo cuando el usuario dice "¿Qué puedo decir?", "Ayuda" o pulsa Ver más.
    • Un elemento ListenFor que contiene las palabras o frases que la aplicación reconoce como un comando. Cada elemento ListenFor puede contener referencias a uno o varios elementos PhraseList que contienen palabras específicas relevantes para el comando.

Nota:

Los elementos ListenFor no se pueden modificar mediante programación. Sin embargo, los elementos PhraseList asociados a los elementos ListenFor se pueden modificar mediante programación. Las aplicaciones deben modificar el contenido de PhraseList en tiempo de ejecución en función del conjunto de datos generado a medida que el usuario usa la aplicación. Consulte Modificar dinámicamente listas de frases de Cortana VCD.

Elemento Feedback que contiene el texto para que Cortana muestre y hable mientras se inicia la aplicación.

Un elemento Navigate indica que el comando de voz activa la aplicación en primer plano. En este ejemplo, el showTripToDestination comando es una tarea en primer plano.

Un elemento VoiceCommandService indica que el comando de voz activa la aplicación en segundo plano. El valor del atributo Target de este elemento debe coincidir con el valor del atributo Name del elemento uap:AppService del archivo package.appxmanifest. En este ejemplo, los whenIsTripToDestination comandos y cancelTripToDestination son tareas en segundo plano que especifican el nombre del servicio de aplicaciones como "AdventureWorksVoiceCommandService".

Para obtener más información, consulte la referencia de elementos y atributos de VCD v1.2.

Esta es una parte del archivo VCD que define los comandos de voz en-us para la aplicación Adventure Works.

<?xml version="1.0" encoding="utf-8" ?>
<VoiceCommands xmlns="https://schemas.microsoft.com/voicecommands/1.2">
  <CommandSet xml:lang="en-us" Name="AdventureWorksCommandSet_en-us">
    <AppName> Adventure Works </AppName>
    <Example> Show trip to London </Example>

    <Command Name="showTripToDestination">
      <Example> Show trip to London </Example>
      <ListenFor RequireAppName="BeforeOrAfterPhrase"> show [my] trip to {destination} </ListenFor>
      <ListenFor RequireAppName="ExplicitlySpecified"> show [my] {builtin:AppName} trip to {destination} </ListenFor>
      <Feedback> Showing trip to {destination} </Feedback>
      <Navigate />
    </Command>

    <Command Name="whenIsTripToDestination">
      <Example> When is my trip to Las Vegas?</Example>
      <ListenFor RequireAppName="BeforeOrAfterPhrase"> when is [my] trip to {destination}</ListenFor>
      <ListenFor RequireAppName="ExplicitlySpecified"> when is [my] {builtin:AppName} trip to {destination} </ListenFor>
      <Feedback> Looking for trip to {destination}</Feedback>
      <VoiceCommandService Target="AdventureWorksVoiceCommandService"/>
    </Command>
    
    <Command Name="cancelTripToDestination">
      <Example> Cancel my trip to Las Vegas </Example>
      <ListenFor RequireAppName="BeforeOrAfterPhrase"> cancel [my] trip to {destination}</ListenFor>
      <ListenFor RequireAppName="ExplicitlySpecified"> cancel [my] {builtin:AppName} trip to {destination} </ListenFor>
      <Feedback> Cancelling trip to {destination}</Feedback>
      <VoiceCommandService Target="AdventureWorksVoiceCommandService"/>
    </Command>

    <PhraseList Label="destination">
      <Item>London</Item>
      <Item>Las Vegas</Item>
      <Item>Melbourne</Item>
      <Item>Yosemite National Park</Item>
    </PhraseList>
  </CommandSet>

Instalación de los comandos de VCD

La aplicación debe ejecutarse una vez para instalar el VCD.

Nota:

Los datos de comandos de voz no se conservan en instalaciones de aplicaciones. Para asegurarse de que los datos del comando de voz de la aplicación permanecen intactos, considere la posibilidad de inicializar el archivo VCD cada vez que se inicie o active la aplicación, o mantenga una configuración que indique si el VCD está instalado actualmente.

En el archivo "app.xaml.cs":

  1. Agregue la siguiente directiva using:

    using Windows.Storage;
    
  2. Marque el método "OnLaunched" con el modificador async.

    protected async override void OnLaunched(LaunchActivatedEventArgs e)
    
  3. Llame a InstallCommandDefinitionsFromStorageFileAsync en el controlador OnLaunched para registrar los comandos de voz que el sistema debe reconocer.

En el ejemplo Adventure Works, primero definimos un objeto StorageFile.

A continuación, llamamos a GetFileAsync para inicializarlo con nuestro archivo "AdventureWorksCommands.xml".

A continuación, este objeto StorageFile se pasa a InstallCommandDefinitionsFromStorageFileAsync.

try
{
  // Install the main VCD. 
  StorageFile vcdStorageFile = 
  await Package.Current.InstalledLocation.GetFileAsync(
  @"AdventureWorksCommands.xml");

  await Windows.ApplicationModel.VoiceCommands.VoiceCommandDefinitionManager.
InstallCommandDefinitionsFromStorageFileAsync(vcdStorageFile);

  // Update phrase list.
  ViewModel.ViewModelLocator locator = App.Current.Resources["ViewModelLocator"] as ViewModel.ViewModelLocator;
  if(locator != null)
  {
     await locator.TripViewModel.UpdateDestinationPhraseList();
  }
}
catch (Exception ex)
{
  System.Diagnostics.Debug.WriteLine("Installing Voice Commands Failed: " + ex.ToString());
}

Controlar la activación y ejecutar los comandos de voz

Especifique cómo responde la aplicación a las activaciones posteriores de comandos de voz (después de que se haya iniciado al menos una vez y se hayan instalado los conjuntos de comandos de voz).

  1. Confirme que la aplicación se ha activado mediante un comando de voz.

    Invalide el evento Application.OnActivated y compruebe si IActivatedEventArgs.Kind es VoiceCommand.

  2. Determine el nombre del comando y lo que se habló.

    Obtenga una referencia a un objeto VoiceCommandActivatedEventArgs de IActivatedEventArgs y consulte la propiedad Result para un objeto SpeechRecognitionResult.

    Para determinar lo que dijo el usuario, compruebe el valor de Text o las propiedades semánticas de la frase reconocida en el diccionario SpeechRecognitionSemanticInterpretation.

  3. Realice la acción adecuada en la aplicación, como navegar a la página deseada.

En este ejemplo, hacemos referencia a VCD en el paso 3: Editar el archivo VCD.

Una vez que obtengamos el resultado del reconocimiento de voz para el comando de voz, obtenemos el nombre del comando del primer valor de la matriz RulePath . Como el archivo VCD definió más de un comando de voz posible, es necesario comparar el valor con los nombres de comando del VCD y realizar la acción adecuada.

La acción más común que puede realizar una aplicación es navegar a una página con contenido relevante para el contexto del comando de voz. En este ejemplo, navegamos a una página TripPage y pasamos el valor del comando de voz, cómo se ha introducido el comando y la frase "destino" reconocida (si procede). Como alternativa, la aplicación podría enviar un parámetro de navegación a SpeechRecognitionResult al navegar a la página.

Puede averiguar si el comando de voz que inició la aplicación se habló realmente o si se escificó como texto, desde el diccionario SpeechRecognitionSemanticInterpretation.Properties mediante la clave commandMode. El valor de esa clave será "voz" o "texto". Si el valor de la clave es "voz", considere la posibilidad de usar la síntesis de voz (Windows.Media.SpeechSynthesis) en la aplicación para proporcionar al usuario comentarios hablados.

Use SpeechRecognitionSemanticInterpretation.Properties para averiguar el contenido hablado en las restricciones PhraseList o PhraseTopic de un elemento ListenFor. La clave de diccionario es el valor del atributo Label del elemento PhraseList o PhraseTopic . Aquí se muestra cómo obtener acceso al valor de la frase {destination} .

/// <summary>
/// Entry point for an application activated by some means other than normal launching. 
/// This includes voice commands, URI, share target from another app, and so on. 
/// 
/// NOTE:
/// A previous version of the VCD file might remain in place 
/// if you modify it and update the app through the store. 
/// Activations might include commands from older versions of your VCD. 
/// Try to handle these commands gracefully.
/// </summary>
/// <param name="args">Details about the activation method.</param>
protected override void OnActivated(IActivatedEventArgs args)
{
    base.OnActivated(args);

    Type navigationToPageType;
    ViewModel.TripVoiceCommand? navigationCommand = null;

    // Voice command activation.
    if (args.Kind == ActivationKind.VoiceCommand)
    {
        // Event args can represent many different activation types. 
        // Cast it so we can get the parameters we care about out.
        var commandArgs = args as VoiceCommandActivatedEventArgs;

        Windows.Media.SpeechRecognition.SpeechRecognitionResult speechRecognitionResult = commandArgs.Result;

        // Get the name of the voice command and the text spoken. 
        // See VoiceCommands.xml for supported voice commands.
        string voiceCommandName = speechRecognitionResult.RulePath[0];
        string textSpoken = speechRecognitionResult.Text;

        // commandMode indicates whether the command was entered using speech or text.
        // Apps should respect text mode by providing silent (text) feedback.
        string commandMode = this.SemanticInterpretation("commandMode", speechRecognitionResult);
        
        switch (voiceCommandName)
        {
            case "showTripToDestination":
                // Access the value of {destination} in the voice command.
                string destination = this.SemanticInterpretation("destination", speechRecognitionResult);

                // Create a navigation command object to pass to the page. 
                navigationCommand = new ViewModel.TripVoiceCommand(
                    voiceCommandName,
                    commandMode,
                    textSpoken,
                    destination);

                // Set the page to navigate to for this voice command.
                navigationToPageType = typeof(View.TripDetails);
                break;
            default:
                // If we can't determine what page to launch, go to the default entry point.
                navigationToPageType = typeof(View.TripListView);
                break;
        }
    }
    // Protocol activation occurs when a card is clicked within Cortana (using a background task).
    else if (args.Kind == ActivationKind.Protocol)
    {
        // Extract the launch context. In this case, we're just using the destination from the phrase set (passed
        // along in the background task inside Cortana), which makes no attempt to be unique. A unique id or 
        // identifier is ideal for more complex scenarios. We let the destination page check if the 
        // destination trip still exists, and navigate back to the trip list if it doesn't.
        var commandArgs = args as ProtocolActivatedEventArgs;
        Windows.Foundation.WwwFormUrlDecoder decoder = new Windows.Foundation.WwwFormUrlDecoder(commandArgs.Uri.Query);
        var destination = decoder.GetFirstValueByName("LaunchContext");

        navigationCommand = new ViewModel.TripVoiceCommand(
                                "protocolLaunch",
                                "text",
                                "destination",
                                destination);

        navigationToPageType = typeof(View.TripDetails);
    }
    else
    {
        // If we were launched via any other mechanism, fall back to the main page view.
        // Otherwise, we'll hang at a splash screen.
        navigationToPageType = typeof(View.TripListView);
    }

    // Repeat the same basic initialization as OnLaunched() above, taking into account whether
    // or not the app is already active.
    Frame rootFrame = Window.Current.Content as Frame;

    // Do not repeat app initialization when the Window already has content,
    // just ensure that the window is active.
    if (rootFrame == null)
    {
        // Create a frame to act as the navigation context and navigate to the first page.
        rootFrame = new Frame();
        App.NavigationService = new NavigationService(rootFrame);

        rootFrame.NavigationFailed += OnNavigationFailed;

        // Place the frame in the current window.
        Window.Current.Content = rootFrame;
    }

    // Since we're expecting to always show a details page, navigate even if 
    // a content frame is in place (unlike OnLaunched).
    // Navigate to either the main trip list page, or if a valid voice command
    // was provided, to the details page for that trip.
    rootFrame.Navigate(navigationToPageType, navigationCommand);

    // Ensure the current window is active
    Window.Current.Activate();
}

/// <summary>
/// Returns the semantic interpretation of a speech result. 
/// Returns null if there is no interpretation for that key.
/// </summary>
/// <param name="interpretationKey">The interpretation key.</param>
/// <param name="speechRecognitionResult">The speech recognition result to get the semantic interpretation from.</param>
/// <returns></returns>
private string SemanticInterpretation(string interpretationKey, SpeechRecognitionResult speechRecognitionResult)
{
  return speechRecognitionResult.SemanticInterpretation.Properties[interpretationKey].FirstOrDefault();
}