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