Dziś napiszę trochę o komendach głosowych w WP8.
W WP 7.x można było używać tylko standardowych poleceń typu “Otwórz kalendarz”. Teraz mamy możliwość definiowania dla naszych aplikacji własnych komend z frazami. Postanowiłem trochę się zabawić i zamienić aplikację z ostatniego posta w szafę grającą spełniającą ustnie wypowiadane życzenia. Pamiętam, że w dzieciństwie podziwiałem jakiś układ elektroniczny przełączający obwód na zadane hasło… Były też bajki o Sezamie… No czy jakoś odwrotnie -;) W każdym razie dziś mała namiastka tego.
Obsługa mowy jest bardzo prosta. Jest to część wysokopoziomowego WinPRT API (btw szkoda że nie ma takiego API w Windows 8).
Zacznijmy od zdefiniowania pliku XML z komendami (najlepiej użyć do tego predefiniowanego szablonu w Visual Studio). W moim przypadku komendy w języku polskim przedstawiają się w tym pliku następująco:
<?xml version="1.0" encoding="utf-8"?>
<VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.0">
<CommandSet xml:lang="pl-PL" Name="myPolishCommands">
<CommandPrefix>Tuba</CommandPrefix>
<Example>Graj ostatni</Example>
<Command Name="playVideo">
<Example>Graj ostatni</Example>
<ListenFor>[Graj] {video}</ListenFor>
<Feedback>Gram {video}</Feedback>
<Navigate Target="/StartPage.xaml"/>
</Command>
<PhraseList Label="video">
<Item>ostatni</Item>
<Item>losowy</Item>
</PhraseList>
</CommandSet>
…
</VoiceCommands>
Ogólnie zakładam mówienie w trzech postaciach: “Tuba, graj ostatni”, “Tuba, graj losowy” lub “Tuba, graj {nazwa utworu}” oraz krótsze wersje tych wypowiedzi bez słowa “graj” (zdefiniowane jest ono w []). Pierwsze dwa przypadki są zdefiniowane w samym pliku XML (fraza “video” o wartościach “ostatni” i “losowy”, wstawianie wartości z frazy oznaczone jest {}). O trzecim przypadku za chwilę. Warto wspomnieć, że w tym samym pliku możemy równocześnie zdefiniować inne wersje językowe komend poprzez inny CommandSet (u mnie “myEnglishCommands” z językiem en-US). Druga rzecz jaką warto dodać, to wygodne przełączanie języka mowy w Ustawienia –> Mowa. Jest to zupełnie niezależne od wszystkich innych ustawień językowych w telefonie.
Należy teraz zarejestrować w systemie zdefiniowane przed chwilą komendy. Czynimy to raz przy uruchomionej aplikacji (przeważnie w obsłudze zdarzenia Load strony startowej).
async private void RegisterVoiceCommandsAtFirstRun()
{
var appSettings = IsolatedStorageSettings.ApplicationSettings;
if (appSettings.Contains("firstRun")) return;
Uri uri = new Uri("ms-appx:///VoiceCommands.xml", UriKind.Absolute);
await VoiceCommandService.InstallCommandSetsFromFileAsync(uri);
appSettings["firstRun"] = true;
}
Na tym etapie po jednokrotnym uruchomieniu aplikacji możemy wrócić do ekranu startowego i przytrzymać dłużej przycisk Start. Pojawi się okno dialogowe do słuchania komend (pierwszy screenshot z poniższych). Jeśli chcemy wiedzieć jakie aplikacje na naszym telefonie wspierają komendy naciskamy “?” i wyświetla się nam odpowiednie okno z pivotem (drugi screenshot). Przechodzimy wtedy do zakładki “aplikacje” (trzeci screenshot). Wróćmy jednak do chwili, gdy jesteśmy słuchani. Wypowiadamy nasze magiczne słowa i jeśli zostaniemy dobrze rozpoznani, to pojawi się okienko z ikoną naszej aplikacji i usłyszymy odpowiedź określającą podejmowaną czynność np. “Gram ostatni” (czwarty screenshot). Następnie aplikacja zostanie otworzona na wskazanej w definicji komendy stronie (u mnie jest to StartPage.xaml)
Jak aplikacja dowiaduje się, przez jaką komendę została uruchomiona? Komendy mogą mieć przecież różne parametry i zachowanie aplikacji może być nimi uwarunkowane. Twórcy WP8 nie szukali długo, zrealizowali to tak jak każdy inny mechanizm deep linking. Do adresu strony są doklejane parametry w określony sposób. W moim przypadku odczyt przychodzących parametrów został zrealizowany na stronie StartPage w następujący sposób:
async protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
//…
if (e.NavigationMode == System.Windows.Navigation.NavigationMode.New)
{
if (NavigationContext.QueryString.ContainsKey("voiceCommandName"))
{
string voiceCommandName = NavigationContext.QueryString["voiceCommandName"];
switch (voiceCommandName)
{
case "playVideo":
string video = NavigationContext.QueryString["video"];
//…
if (video == "last")
{
//...
}
else if (video == "random")
{
//...
}
else
{
//...
}
//…
break;
default:
break;
}
}
}
//…
}
Jak dodać tytuły klipów zarządzanych przez aplikację do wartości frazy “video”? Zbiór wartości odświeżam korzystając z metody:
async private Task UpdatePhrasesForVoiceCommands(string voiceCommandSet, string[] startPhrases)
{
var phrases = startPhrases.Concat(AllVideos.Select(f => GetTitle(f.Name.Replace(".mp4", "")))).ToList();
var videoVcs = VoiceCommandService.InstalledCommandSets[voiceCommandSet];
await videoVcs.UpdatePhraseListAsync("video", phrases);
}
Tytuł nagrania z YouTube obcinam do słów, które powinny zawierać tytuł utworu (GetTitle). Całość wywołuję w następujący sposób:
await UpdatePhrasesForVoiceCommands("myPolishCommands", new string[] { "ostatni", "losowy" });
Przykładowe uruchomienie aplikacji za pomocą komendy zawierającej nazwę utworu pokazałem na poniższym nagraniu:
P.S API dla mowy w WP8 obejmuje także zamianę tekstu na mowę oraz rozpoznawanie mowy za pomocą wbudowanych i własnych gramatyk, ale o tym może innym już razem.
Brak komentarzy:
Prześlij komentarz