This article has been localized into Czech by the community.
Rozpoznávání řeči (přimějme WPF poslouchat)
V předchozím článku jsme diskutovali o tom, jak můžeme převést text na mluvená slova pomocí třídy SpeechSynthesizer. V tomto článku půjdeme opačným směrem, tím že převedeme mluvená slova na text. K tomu použijeme třídu SpeechRecognition, která se nachází v sestavení System.Speech. Toto sestavení standardně není součástí vašich řešení, ale můžeme ho snadno přidat. V závislosti na tom, kterou verzi Visual Studia používáte, proces vypadá nějak takto:
Až to budeme mít, začneme extrémně jednoduchým příkladem rozpoznávání řeči:
<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();
}
}
}
To je vlastně vše, co potřebujete - text na snímku obrazovky výše byl diktován prostřednictvím mého headsetu a poté vložen do ovládacího prvku TextBox jako text, prostřednictvím použití rozpoznávání řeči.
Jakmile inicializujete objekt SpeechRecognizer, Windows spustí svou aplikaci pro rozpoznávání řeči, která udělá všechnu těžkou práci a poté pošle výsledek do aktivní aplikace, v tomto případě naší. Vypadá to takto:
Pokud jste na svém počítači dříve nepoužívali rozpoznávání řeči, Windows vás provede průvodcem, který vám pomůže začít a udělat některé nezbytné úpravy.
Tento první příklad vám umožní diktovat text do vaší aplikace, což je skvělé, ale co příkazy? Windows a WPF zde budou skutečně spolupracovat a převedou vaše tlačítka na příkazy, dostupné prostřednictvím řeči, bez jakékoli další práce. Zde je příklad:
<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");
}
}
}
Můžete zkusit spustit příklad a poté vyslovit jeden z příkazů, například "New" nebo "Open". To vám skutečně umožní diktovat text do textového pole, zatímco zároveň vyvoláváte příkazy z uživatelského rozhraní - opravdu pěkné!
Specifické příkazy
Ve výše uvedeném příkladu Windows automaticky přejde do režimu diktátu, jakmile je zaměřena na textové pole. Windows se pak pokusí rozlišit mezi diktátem a příkazy, což může samozřejmě být v určitých situacích obtížné.
Zatímco výše uvedené příklady se zaměřovaly na diktát a interakci s prvky uživatelského rozhraní, tento další příklad se zaměří na schopnost naslouchat a interpretovat pouze specifické příkazy. To také znamená, že diktát bude zcela ignorován, i když je fokus na textová vstupní.
Pro tento účel použijeme třídu SpeechRecognitionEngine místo třídy SpeechRecognizer. Velký rozdíl mezi nimi je, že třída SpeechRecognitionEngine nevyžaduje, aby bylo spuštěno rozpoznávání řeči ve Windows, a neprovede vás průvodcem rozpoznávání hlasu. Místo toho použije základní rozpoznání hlasu a bude naslouchat pouze gramatice, kterou do třídy zadáte.
V dalším příkladu naplníme rozpoznávací engine sadou příkazů. Myšlenka je, že by měl naslouchat dvěma slovům: příkazu/vlastnosti a hodnotě, která v tomto případě bude použita ke změně barvy, velikosti a tloušťky textu v ovládacím prvku Label, pouze na základě vašich hlasových příkazů. Než vám ukážu celý vzorek kódu, chci se zaměřit na způsob, jakým přidáváme příkazy do enginu. Zde je kód:
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));
Používáme GrammarBuilder pro sestavení sady gramatických pravidel, která můžeme načíst do SpeechRecognitionEngine. Má několik metod append, přičemž nejjednodušší je Append(). Tato metoda bere seznam možností. Vytvoříme instanci Choices s první částí instrukce - příkazem/vlastností, ke které chceme přistupovat. Tyto možnosti jsou přidány do sestavovače metodou Append().
Pokaždé, když na GrammarBuilder zavoláte metodu append, instruujete ho, aby poslouchal slovo. V našem případě chceme, aby poslouchal dvě slova, takže vytvoříme sekundární sadu možností, která bude obsahovat hodnotu pro určený příkaz/vlastnost. Přidáme řadu hodnot pro každý z možných příkazů - jednu sadu hodnot pro příkaz váhy, jednu sadu hodnot pro příkaz barvy a jednu sadu hodnot pro příkaz velikosti. Všechny jsou přidány do stejné instance Choices a poté připojeny k sestavovači.
Nakonec to načteme do instance SpeechRecognitionEngine voláním metody LoadGrammar(), která bere jako parametr instanci Grammar - v tomto případě na základě naší instance GrammarBuilder.
Takže, s tímto vysvětlením, pojďme se podívat na celý příklad:
<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();
}
}
}
Na snímku obrazovky vidíte výslednou aplikaci, poté co jsem použil hlasové příkazy "weight bold" (váha tučně) a "color blue" (barva modrá) – je to super, že?
Gramatické aspekty příkladu už byly vysvětleny a rozhraní je velmi jednoduché, takže se soustřeďme na zbytek kódu v pozadí.
Používáme ToggleButton k povolení nebo zakázání poslechu pomocí metod RecognizeAsync() a RecognizeAsyncStop(). Metoda RecognizeAsync() bere parametr, který informuje rozpoznávací engine, zda má provést jedno rozpoznání nebo více rozpoznání. Pro náš příklad chceme zadat několik příkazů, takže se používá možnost Multiple. K povolení poslechu stačí kliknout na tlačítko a k jeho zakázání znovu klikněte. Stav je vizuálně reprezentován tlačítkem, které bude "stištěno" když je povoleno a normální, když je zakázáno.
Kromě sestavování gramatiky je nejzajímavější část tam, kde interpretujeme příkaz. To se dělá v události SpeechRecognized, na kterou se připojíme v konstruktoru. Používáme plně rozpoznaný text k aktualizaci ukázkového štítku, abychom ukázali poslední příkaz, a pak používáme vlastnost Words k hlubšímu proniknutí do skutečného příkazu.
Nejprve zkontrolujeme, zda má přesně dvě slova - příkaz/vlastnost a hodnotu. Pokud tomu tak je, nejprve zkontrolujeme část příkazu a pro každý možný příkaz odpovídajícím způsobem zpracujeme hodnotu.
Pro příkazy váhy a barvy můžeme hodnotu převést na něco, co štítek automaticky pochopí, pomocí konvertoru, ale pro velikosti interpretujeme zadané hodnoty manuálně, protože hodnoty, které jsem pro tento příklad vybral, nemohou být převedeny automaticky. Mějte na paměti, že byste měli vždy zpracovávat výjimky, protože příkaz jako "weight blue" (váha modrá) se pokusí přiřadit hodnotu modrá k FontWeight, což samozřejmě vyústí ve výjimku.
Shrnutí
Jak doufám vidíte, rozpoznávání řeči s WPF je jak jednoduché, a tak silné - zejména poslední příklad by vám měl dát dobrou představu o tom, jak moc silné to je! S možností použít diktát a/nebo specifické hlasové příkazy, můžete ve svých aplikacích skutečně poskytnout vynikající prostředky pro alternativní vstup.