This article has been localized into French by the community.
Reconnaissance vocale (faire écouter WPF)
Dans l'article précédent nous avons discutés de comment nous pouvons transformer le texte en mots vocalisés au moyen de la classe SpeechSynthesizer. Dans cet article nous ferons le chemin inverse en transformant des mots parlés en texte. Pour ce faire, nous utiliserons la classe SpeechRecognition située dans l'assembly System.Speech. Cette assembly ne fait pas partie de notre solution par défaut mais peut facilement être ajoutée. Selon la version de Visual Studio utilisée, la procédure ressemble à ceci:
Une fois ceci fait, commençons avec un exemple extrêmement simple de reconnaissance vocale:
<Window x:Class="WpfTutorialSamples.Audio_and_Video.SpeechRecognitionTextSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SpeechRecognitionTextSample" Height="200" Width="300">
<DockPanel Margin="10">
<TextBox Margin="0,10" Name="txtSpeech" AcceptsReturn="True" />
</DockPanel>
</Window>
using System;
using System.Speech.Recognition;
using System.Windows;
namespace WpfTutorialSamples.Audio_and_Video
{
public partial class SpeechRecognitionTextSample : Window
{
public SpeechRecognitionTextSample()
{
InitializeComponent();
SpeechRecognizer speechRecognizer = new SpeechRecognizer();
}
}
}
C'est effectivement tout ce dont vous avez besoin - le texte dans la capture d'écran ci-dessus a été dicté en utilisant mon casque-micro puis inséré dans le contrôle TextBox sous forme de texte, au moyen de la reconnaissance vocale.
Dès lors que vous initialisez un objet SpeechRecognizer, Windows démarre son application de reconnaissance vocale qui se chargera de tout le travail et redirigera le résultat à l'application active, en l’occurrence la nôtre. Cela se présente comme ceci:
Si vous n'avez pas déjà utilisé la reconnaissance vocale sur votre ordinateur, Windows vous affichera un assistant qui vous aidera à la mise en place de certains ajustements nécessaires.
Ce premier exemple vous permettra de dicter le texte à votre application, ce qui est super, mais qu'en est-il des commandes ? Windows et WPF vont ici en fait travailler de concert et changer vos boutons en commandes, atteignables au travers de la voix sans travail supplémentaire. Voici un exemple:
<Window x:Class="WpfTutorialSamples.Audio_and_Video.SpeechRecognitionTextCommandsSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SpeechRecognitionTextCommandsSample" Height="200" Width="300">
<DockPanel Margin="10">
<WrapPanel DockPanel.Dock="Top">
<Button Name="btnNew" Click="btnNew_Click">New</Button>
<Button Name="btnOpen" Click="btnOpen_Click">Open</Button>
<Button Name="btnSave" Click="btnSave_Click">Save</Button>
</WrapPanel>
<TextBox Margin="0,10" Name="txtSpeech" AcceptsReturn="True" TextWrapping="Wrap" />
</DockPanel>
</Window>
using System;
using System.Speech.Recognition;
using System.Windows;
namespace WpfTutorialSamples.Audio_and_Video
{
public partial class SpeechRecognitionTextCommandsSample : Window
{
public SpeechRecognitionTextCommandsSample()
{
InitializeComponent();
SpeechRecognizer recognizer = new SpeechRecognizer();
}
private void btnNew_Click(object sender, RoutedEventArgs e)
{
txtSpeech.Text = "";
}
private void btnOpen_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Command invoked: Open");
}
private void btnSave_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Command invoked: Save");
}
}
}
Vous pouvez essayer d'exécuter l'exemple et dire une des commandes. Exemple "New" ou "Open". Cela vous permet de dicter le texte au TextBox et au même moment invoquer la commande depuis l'interface utilisateur - plutôt classe, en effet !
Commandes spécifiques
Dans l'exemple du dessus, Windows va automatiquement passer en mode dictée dès lors qu'une zone de saisie de texte se voit attribuer le focus. Windows va ensuite essayer de distinguer entre la dictée et les commandes, mais cela peut se montrer difficile dans certaines situations.
Alors que les exemples ci-dessus se sont concentrés sur la dictée et l'interaction avec les éléments de l'interface utilisateur, l’exemple suivant se concentrera seulement sur la capacité à écouter et interpréter des commandes spécifiques. Cela signifie que la dictée sera complètement ignorée, même si les champs de saisie ont le focus.
Dans ce but, nous utiliserons la classe SpeechRecognitionEngine au lieu de la classe SpeechRecognizer. Une grande différence entre les deux est que la classe SpeechRecognitionEngine ne nécessite pas que la reconnaissance vocale de Windows soit exécutée et ne vous présentera pas d'assistant. A la place, il utilisera une reconnaissance de la voix basique et n'écoutera que la grammaire donnée à la classe.
Dans l'exemple suivant, nous allons donner un jeu de commandes dans le moteur de reconnaissance vocale. L'idée est qu'il devrait écouter deux mots: une commande/propriété et une valeur qui dans ce cas va servir à changer la couleur, taille et poids d'un texte dans un Label, simplement au moyen de commandes par votre voix. Avant de vous montrer l'extrait de code complet, je voudrais mettre l'accent sur la manière d'ajouter les commandes dans le moteur. Voici le dit code:
GrammarBuilder grammarBuilder = new GrammarBuilder();
Choices commandChoices = new Choices("weight", "color", "size");
grammarBuilder.Append(commandChoices);
Choices valueChoices = new Choices();
valueChoices.Add("normal", "bold");
valueChoices.Add("red", "green", "blue");
valueChoices.Add("small", "medium", "large");
grammarBuilder.Append(valueChoices);
speechRecognizer.LoadGrammar(new Grammar(grammarBuilder));
Nous utilisons un GrammarBuilder pour construire un jeu de règles grammaticales que nous pouvons charger dans le SpeechRecognitionEngine. Il a plusieurs méthodes d'ajout dans la plus simple est Append(). Cette méthode prend une liste de choix. Nous créons une instance de Choices contenant la première partie de l'instruction - à savoir la commande ou propriété à laquelle nous souhaitons accéder. Ces choix sont ajoutés au constructeur par la méthode Append().
Désormais, chaque fois que vous appelez une méthode append sur le GammarBuilder, vous lui instruisez d'écouter un mot. Dans notre cas, nous voulons en écouter deux, de ce fait, nous créons un autre jeu de choix qui contiendra les valeurs pour les commandes/propriétés désignées. Nous ajoutons un jeu de valeurs pour chacune des commandes possibles. Un jeu de valeurs pour la commande de poids, un autre pour la couleur et enfin un dernier pour la commande de taille. Toutes seront ajoutées à la même instance de Choices puis ajoutée au constructeur.
Enfin, nous le chargeons dans l'instance de SpeechRecognitionEngine par l'appel de la méthode LoadGrammar() qui prend une instance de Grammar en paramètre - en l’occurrence, basé sur notre instance de GrammarBuilder.
Avec ces explications, regardons l'exemple en entier:
<Window x:Class="WpfTutorialSamples.Audio_and_Video.SpeechRecognitionCommandsSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SpeechRecognitionCommandsSample" Height="200" Width="325"
Closing="Window_Closing">
<DockPanel>
<WrapPanel DockPanel.Dock="Bottom" HorizontalAlignment="Center" Margin="0,10">
<ToggleButton Name="btnToggleListening" Click="btnToggleListening_Click">Listen</ToggleButton>
</WrapPanel>
<Label Name="lblDemo" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48">Hello, world!</Label>
</DockPanel>
</Window>
using System;
using System.Globalization;
using System.Speech.Recognition;
using System.Windows;
using System.Windows.Media;
namespace WpfTutorialSamples.Audio_and_Video
{
public partial class SpeechRecognitionCommandsSample : Window
{
private SpeechRecognitionEngine speechRecognizer = new SpeechRecognitionEngine();
public SpeechRecognitionCommandsSample()
{
InitializeComponent();
speechRecognizer.SpeechRecognized += speechRecognizer_SpeechRecognized;
GrammarBuilder grammarBuilder = new GrammarBuilder();
Choices commandChoices = new Choices("weight", "color", "size");
grammarBuilder.Append(commandChoices);
Choices valueChoices = new Choices();
valueChoices.Add("normal", "bold");
valueChoices.Add("red", "green", "blue");
valueChoices.Add("small", "medium", "large");
grammarBuilder.Append(valueChoices);
speechRecognizer.LoadGrammar(new Grammar(grammarBuilder));
speechRecognizer.SetInputToDefaultAudioDevice();
}
private void btnToggleListening_Click(object sender, RoutedEventArgs e)
{
if(btnToggleListening.IsChecked == true)
speechRecognizer.RecognizeAsync(RecognizeMode.Multiple);
else
speechRecognizer.RecognizeAsyncStop();
}
private void speechRecognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
lblDemo.Content = e.Result.Text;
if(e.Result.Words.Count == 2)
{
string command = e.Result.Words[0].Text.ToLower();
string value = e.Result.Words[1].Text.ToLower();
switch(command)
{
case "weight":
FontWeightConverter weightConverter = new FontWeightConverter();
lblDemo.FontWeight = (FontWeight)weightConverter.ConvertFromString(value);
break;
case "color":
lblDemo.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString(value));
break;
case "size":
switch(value)
{
case "small":
lblDemo.FontSize = 12;
break;
case "medium":
lblDemo.FontSize = 24;
break;
case "large":
lblDemo.FontSize = 48;
break;
}
break;
}
}
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
speechRecognizer.Dispose();
}
}
}
Sur la photo d'écran, vous voyez l'application résultante après avoir émit les commandes "weight bold" et "color blue" - pas mal, non ?
L'aspect grammatical de l'exemple a déjà été expliqué et l'interface est très simple, alors concentrons nous sur le reste du code-behind.
Nous utilisons un ToggleButton pour activer ou désactiver l'écoute en utilisant les méthodes RecognizeAsync() et RecognizeAsyncStop(). La méthode RecognizeAsync() prend un paramètre qui informe le moteur de reconnaissance vocale si il doit faire une reconnaissance simple ou multiple. Pour notre exemple, nous souhaitons passer plusieurs commandes, donc Multiple est utilisé. Donc pour activer l'écoute, cliquez simplement sur le bouton et une nouvelle fois pour la désactiver. L'état est représenté visuellement sur le bouton qui sera "pressé" quand il est actif et normal quand il ne l'est pas.
Maintenant, en dehors de construire le Grammar, la partie la plus intéressante est là où nous interprétons la commande. C'est fait dans l'évènement SpeechRecognized auquel nous nous attachons depuis le constructeur. Nous utilisons le texte pleinement reconnu pour mettre à jour le label de démonstration pour montrer la dernière commande. Puis nous utilisons la propriété Words pour creuser la commande plus en profondeur.
Tout d'abord, nous vérifions qu'il a exactement les deux mots - une commande/propriété et une valeur. Si c'est bien le cas, nous vérifions la commande dans la première partie, et pour chaque commande possible, nous gérons la valeur en conséquence.
Pour les commandes de poids et de couleur, nous pouvons convertir les valeurs dans quelque chose que le Label peut comprendre automatiquement en utilisant un convertisseur, mais pour les tailles, nous interprétons les valeurs manuellement puisque les valeurs que j'ai choisi pour cet exemple ne peuvent pas l'être automatiquement. Prenez garde au fait que vous devriez gérer les exceptions dans tout les cas, puisque les commandes telles que "weight blue" vont essayer d'assigner la valeur "blue" à FontWeight, ce qui va naturellement résulter en une exception.
Résumé
Comme vous devriez l'avoir vu, la reconnaissance vocale avec WPF est à la fois facile et puissante - en particulier le dernier exemple qui devrait vous donner une bonne idée à quel point c'est puissant ! Avec la possibilité d'utiliser la dictée et/ou des commandes vocales spécifiques, vous pouvez vraiment fournir d'excellents moyens de saisie alternative dans vos applications.