Dans cette partie, nous allons nous intéresser à une NUI (Natural User Interface) : la reconnaissance vocale à travers Cortana qui est l’assistant vocal de Windows10.
Les commandes vocales dans les applications windows sont disponibles depuis déjà un moment, l’intérêt de Cortana est de pouvoir établir un semblant d’interactivité. On parle ici d’un semblant car il faut programmer le comportement, et c’est que nous allons voir à travers cet article.
Nous allons étudier une interaction directe avec l’application et une autre sous forme de dialogue directement dans Cortana afin de contrôler notre lampe Philips HUE, pour laquelle nous avions développé un serveur lors d’une partie précédente.
Le traitement du langage humain peut mener à certaines ambiguïtés. Cette problématique peut être levée avec LUIS que nous traiterons dans un prochain article. L’ensemble du code de cet article est disponible sur notre Github.

Objectifs

Architecture

Pour interagir avec Cortana il faut une application sous Windows10, et si on souhaite la diffuser également sous Windows Phone, une application universelle (UWP) est tout indiquée. Nous suivrons une logique de programmation de type MVVM tout au long de cet article. Pour raison de simplicité nous avons utilisé le framework MVVM Light, mais tout le code peut être compatible avec d’autres frameworks tel que PRISM.
Il existe deux interactions avec Cortana : la première est de lancer des ordres lorsque l’application est en cours d’exécution, et la seconde est d’inscrire des commandes auprès de Cortana (sous forme de composant).

Architecture Cortana
Les commandes vocales sont décrites dans un fichier XML qui suit la norme VCD. Ci dessous un exemple de fichier de définition (celui que nous utiliserons dans cet article est disponible sur notre github) :

Le nœud VoiceCommands peut contenir plusieurs CommandSet, ce qui est utile lorsque vous souhaitez utiliser votre reconnaissance vocale dans plusieurs langues. Vous devez renseigner la langue du CommandSet (dans notre cas ‘fr-fr’).

Le nœud CommandSet contient le nom de l’application (AppName) qui indiquera à Cortana à quelle application fait référence la suite de commandes.

Le nœud ListenFor correspond à la phrase que devra comprendre Cortana et le noeud FeedBack permettra à Cortana de faire un retour utilisateur si la correspondance a été trouvée pour cette commande.

En prenant la grammaire définie ci dessus, nous pouvons donc éteindre la commande avec la commande suivante : “Génie, éteins la lampe”

Interface

Pour réaliser cette application, nous n’allons pas avoir besoin d’une interface complexe. Nous aurons une simple zone d’interaction avec un label qui sera bindé sur notre ViewModel.

ScreenShot

Le fichier d’interface sera la vue lamp.xaml.

Ordre direct

Afin de développer cette application nous allons créer un projet BlankApp (Windows Universel).

Creations du projet sous visual studio 2015

 

Avant toute chose nous allons créer un viewModel (LampViewModel.cs) qui permettra d’instancier une dataAccess pour faire les appels aux API.

Ce viewModel contiendra les commandes (OnLight, OffLight, ChangeColor) à exécuter pour piloter notre lampe. Afin de garder notre UI réactive, nous utiliserons ici le couple async / await pour nous assurer de l’asynchronisme de nos commandes. La variable Message est bindée sur notre interface permettant d’avoir un feedback pour notre utilisateur.

 

Pour faire la liaison entre notre viewModel et notre serveur d’API pilotant les lampes Philips HUE, nous passerons par notre classe Light.cs située dans la dataAccess. Pour faire transiter notre structure d’objet vers notre serveur, nous sérialisons avec la méthode JsonConvert.SerializeObject 

 

Maintenant l’ensemble du travail va s’effectuer dans l’App.xaml.cs

Il faut tout d’abord charger le fichier de définition des commandes vocales (VoiceCommandDefinition.xml) situé à la racine du projet. Ce chargement doit avoir lieu au moment du lancement de l’application, sur l’event OnLaunched.

 

Puis sur la réponse à l’event OnActivated, nous allons filtrer le résultat de la reconnaissance vocale afin d’instancier le ViewModel avec les bons paramètres. Le filtre s’effectue avec l’enum ActivationKind et la valeur VoiceCommand. Cette condition nous permet de pouvoir caster en toute sécurité l’argument commandArgs en VoiceCommandActivatedEventArgs. Ce cast nous permet de récupérer le nom de la commande ainsi que le texte qui a été prononcé pour activer cette commande. Ensuite, il ne reste qu’à filtrer le nom de la commande pour configurer le contexte d’exécution. Dans un exemple plus complet nous pourrions récupérer par exemple l’id de la lampe sur laquelle on souhaite agir.

 

Le cas du changement de couleur pour une lampe va nous permettre d’introduire le concept de désambiguïsation. Typiquement pour le changement de couleur nous avons introduit dans le fichier VoiceCommandDefinition.xml une possibilité de choix au niveau des couleurs avec la variable color. La liste de choix pour cette variable se trouve dans le noeud PhraseList ayant pour label le nom de la variable à savoir dans notre cas color.

 

Pour obtenir ce choix et pouvoir envoyer les bons paramètres à notre viewModel, nous utiliserons la propriété SemanticInterpretation du résultat de la commande vocale. Pour factoriser le code nous utiliserons la méthode :

 

Maintenant nous pouvons compléter le switch case pour différencier les différentes commandes :

 

Ensuite nous pouvons lancer la navigation vers la page qui est associée au viewModel avec la méthode Navigate 

 

La récupération des paramètres navigationCommand s’effectuera dans la méthode OnNavigatedTo de la page. Dans la logique du MVVM, le DataContext est bindé sur le ViewModel de la page, ce qui nous permet de pouvoir récupérer les commandes du ViewModel et de pouvoir passer les paramètres de la commande vocale.

 

Maintenant nous avons le chemin complet pour lancer une commande à travers Cortana et allumer notre lampe.

OrdreDirectCortana

Intégration plus poussée dans Cortana

Jusqu’à présent nous devions lancer l’application pour interagir avec elle grâce à notre voix. Pour un usage plus efficient il ne faudrait plus lancer l’application. Nous allons donc réaliser toutes les actions à travers Cortana.

Pour cela il faut rajouter un composant à notre solution, pour que celui-ci puisse s’inscrire dans la logique de Cortana. Quand l’assistant vocal détectera que notre interaction correspond à notre logiciel, il viendra utiliser notre composant pour interagir avec nous et nous guider dans le flux d’exécution.

Add Runtime Component VS2015

 

Nous devons ensuite créer une classe CortanaDialogFlow qui implémente l’interface IBackgroundTask. Cette interface définie une méthode Run dans laquelle nous allons définir notre flux.

La première étape est de récupérer le AppServiceTriggerDetails qui nous permettra de vérifier si le déclenchement correspond bien à notre composant.

La deuxième étape est de récupérer la commande vocale. Ensuite nous retrouverons la même logique pour dispatcher les ordres vers notre dataAccess grâce à un switch case sur le nom de la commande. Si aucune commande ne correspond, nous lancerons l’application.

 

La méthode SendCompletionMessageForAmbiance permet d’établir un dialogue avec notre utilisateur pour lui indiquer les différents choix s’offrant à lui. Dans le but d’apporter un retour à notre utilisateur nous commençons par lui afficher un message à travers notre méthode ShowProgressScreen. Pour afficher une réponse à notre utilisateur il faut utiliser la méthode CreateResponse de la classe statique VoiceCommandResponse qui prend en paramètre un type VoiceCommandUserMessage. Ce type est intéressant car il va nous permettre d’indiquer ce que Cortana devra afficher mais également prononcer à travers les propriétés respectives DisplayMessage et SpokenMessage.

 

Pour constituer une liste de choix il faut créer une liste de VoiceCommandContentTile. Dans notre cas nous allons utiliser uniquement un contenu textuel pour interagir.

 

Lorsque la liste de choix est réalisée nous pouvons l’afficher à l’utilisateur avec la fonction CreateResponseForPrompt. Celle-ci, en plus de prendre en paramètre notre liste de choix, doit également prendre les messages à afficher à l’utilisateur. Lorsque l’utilisateur a répondu nous devons analyser sa réponse pour récupérer le nom de l’ambiance.

 

Vous pouvez également demander une confirmation à votre utilisateur; la réponse négative ou positive sera alors contenu dans la réponse.

 

Selon la réponse de l’utilisateur, nous pouvons lancer notre ordre grâce à la dataAccess.

Une fois l’interaction terminée il faut notifier l’utilisateur que le flux est terminé.

 

Ci-dessous vous pouvez voir l’enchaînement des différentes étapes. Je vous invite à regarder le fichier sur notre Github afin d’avoir l’implémentation complète de cet exemple.

Afin que le composant puisse s’enregistrer une première fois au lancement de l’application, il faut le déclarer dans le manifest de l’application. Pour cela on référence le composant dans le projet MVVM, puis on édite le fichier Package.appx.manifest. Dans l’onglet Declarations on ajoute un App Service. On renseigne un nom pour notre service permettant de l’identifier ensuite dans notre fichier VoiceCommandDefinition.xml à travers le nœud  <VoiceCommandService Target=”CortanaDialogFlow”/> . Dans notre exemple nous utiliserons le nom de la classe CortanaDialogFlow, puis on lui donne le point d’accès à cette méthode en renseignant Entry Point. Le nom du point d’accès correspond au namespace + le nom de la classe pour nous RuntimeComponentCortana.CortanaDialogFlow.

 

AppManifest

 

Pour tester notre code il faut donc démarrer une première fois l’application, afin que le composant puisse s’enregistrer grâce au contrat. Pour le debug, on peut laisser l’application ouverte, ce qui nous permet de mettre des breakpoints dans le composant, mais en toute logique nous pouvons la fermer.

Pour lancer une commande, on peut maintenant s’adresser à Cortana avec la phrase suivante : “Genie change d’ambiance”

CortanaFlow

Conclusion

Cet article a été écrit un peu avant l’annonce de Microsoft à la //Build 2016 où Satya Nadella a annoncé que l’avenir des applications allait passer par l’avènement des bots. Pour accompagner cette annonce, Microsoft a sorti un framework permettant de programmer des bots qui seront mis en relation avec des logiciels, sites ou des assistants vocales tel que Cortana.

Avec ce type d’application, nous pouvons changer les usages des différents logiciels que nous utilisons. Nous vivons dans un monde de plus en plus multi-taches. Avec les assistants vocaux nous libérons nos mains pour réaliser d’autres tâches en parallèle.

Partager