BETA
Aby się zalogować, najpiew wybierz portal.
Aby się zarejestrować, najpiew wybierz portal.
Podaj słowa kluczowe
Słowa kluczowe muszą mieć co najmniej 3 sąsiadujące znaki alfanumeryczne
Pole zawiera niedozwolone znaki

Baza wiedzy











Nawigacja głosowa w .NET, czyli Microsoft Speech Application SDK. Część 3: „Budujemy prostą aplikację - ciąg dalszy”

30-12-2004 03:42 | User 81271
Ciąg dalszy artykułu pod tytułem: Nawigacja głosowa w .NET, czyli Microsoft Speech Application SDK. Część 2: "Budujemy prostą aplikację". Zajmujemy się tworzeniem aplikacji dialogowej typu "voice-only", na przykładzie prostego programu przyjmującego głosowe zamówienia na bilety do kina. W tej części przedstawię zagadnienia związane z SemanticMap, tworzeniem prompt'ów i głosowych kontrolek potwierdzenia oraz anulowania zamówienia.
  • Wstęp

Ciąg dalszy artykułu pod tytułem: Nawigacja głosowa w .NET, czyli Microsoft Speech Application SDK. Część 2: "Budujemy prostą aplikację".
Zajmujemy się tworzeniem aplikacji dialogowej typu "voice-only", na przykładzie prostego programu przyjmującego głosowe zamówienia na bilety do kina.
W tej części przedstawię zagadnienia związane z SemanticMap, tworzeniem prompt'ów i głosowych kontrolek potwierdzenia oraz anulowania zamówienia.

  •  Mapa semantyczna

Skoro mamy już przypisane znaczenie i wiemy jakie wartości będą zwracane z każdego rozpoznanego zwrotu, to utworzymy teraz elementy, w których będziemy te informacje przechowywać i powiążemy je z odpowiednimi kontrolkami QA.

W aplikacjach typu voice-only elementami przechowującymi(w języku SML) informacje semantyczne rozpoznanego zwrotu są elementy kontrolki SemanticMap, tzw. SemanticItems.

SemanticMap została domyślnie dołączana przy tworzeniu projektu.

Wchodzimy do Property Builder SemanticMap. Dodajemy nowy element. Zmieniamy jego ID na nodeTitle, z listy TargetElement wybieramy PanelKino (ID kontrolki po stronie serwera z która powiązany jest docelowy element), z listy TargetAttribute wybieramy value i zaznaczamy opcję BindOnChanged (tzn. element będzie „wiązał się” z kontrolką za każdym razem, gdy nastąpi zmiana jego wartości).

Klikamy Apply i tak samo tworzymy kolejne elementy o następujących nazwach: nodeDayOfWeekText, nodeTimeText, nodeHoursValue, nodeMinutesValue, nodeAmount, nodeYes, nodeNo, nodeCancel.

 

Teraz przypiszemy wcześniej utworzone reguły gramatyczne do odpowiednich kontrolek.

W Property Builder kontrolki TitleQA przechodzimy do zakładki Input/General klikamy Add Existing Grammar i wybieramy plik naszej gramatyki Kino.grxml wybierając regułę Title.

Na zakładce Answers klikamy pierwszą komórkę w kolumnie SemanticItems wybierając element nodeTitle. Klikamy w kolumnie XPathTrigger, lecz niestety nic nam się nie pojawia. Klikamy więc na XPathTrigger Sample Sentence Tool i w polu Sample Speech Input wpisujemy tytuł filmu(zwrot rozpoznawany przez daną regułę), np. Grinch i klikamy Go. Otrzymaliśmy dzięki temu „namiary” na węzeł, w którym przechowywane są tekstowe wartości tytułów filmów : /SML/Title – jest to nazwą węzła SML, którą ustawiliśmy w Semantic Script Editor. Teraz możemy z kolumny XPathTrigger wybrać nasz węzeł (jeśli ktoś ma dobrą pamięć może oczywiście wpisać go ręcznie). Dzięki temu powiążemy informację semantyczną z węzła SML/Title z elementem nodeTitle w SemanticMap i tym samym powiążemy ją z kontrolką TitleQA. Podobnie postępujemy z kontrolkami DayQa, TimeQa i AmountQA, pamiętając, że moduł rozpoznawania mowy w regule Time zwraca nam trzy wartości: TimeText, HoursValue, MinutesValue. Tak więc w tym przypadku zakładka odpowiedzi będzie wyglądała tak jak na Rys. 5.

 

Rys. 5. Powiązanie SemanticItems z węzłami SML

 

 

  • Tworzenie bazy wypowiedzi

Wypowiedź (prompt) w aplikacji voice-only jest to jedyny interfejs z użytkownikiem. Jest to tekst wypowiadany(syntezowana mowa lub nagrany tekst) do użytkownika, może to być pytanie, powitanie, instrukcja lub informacja. Każdy projekt wypowiedzi może zawierać więcej niż jedną bazę takich wypowiedzi.

Do tworzenia bazy wypowiedzi w Speech SDK służy Speech Prompt Editor. Aby z niego skorzystać należy w Solution Explorer dwukrotnie kliknąć na pliku Prompts.promptdb.

Jest pewien sposób na szybkie wypełnienie bazy wypowiedzi zwrotami, które wpisaliśmy we właściwościach kontrolek QA. Tak więc z menu View wybieramy Prompt Validation, a następnie Do Validate Solution. W wyniku otrzymamy spor błędów. Tekst zaznaczony na czerwono nie ma swojego odpowiednika w postaci pliku wav – istnieje tylko jako tekst, który jest przekształcany na syntezowaną mowę. Dlatego też klikamy Add all to Database, aby dodać bazy te wszystkie zwroty do bazy wypowiedzi. Zostaną one wpisane do kolumny Transcription (bez przecinków, kropek itp.). Zwroty w nawiasach kwadratowych mają swoje odzwierciedlenie w kolumnie Extractions. Znajdują się tu segmenty (części) zwrotów. Segmenty te mogą być połączone z innymi tworząc pełne zwroty i dzięki temu aplikacja będzie mogła odpowiedzieć tym właśnie zwrotem w razie takiej potrzeby. Tworzenie segmentów zmniejsza bazę wypowiedzi, gdyż nie trzeba (a często jest to niemożliwe) tworzyć każdej kombinacji zwrotów. Do bazy dodajemy zwroty, które mogą wystąpić podczas rezerwacji biletów.

 

Teraz przechodzimy do nagrywania wypowiedzi. Wybierz z menu Prompt opcję Record All.

Pojawi się nowe okno Recording Tool. Naciśnij Record i wypowiedz do mikrofonu zwrot znajdujący się w polu Display text. (jeśli w polu Has Alignments nie pojawi się „ptaszek” to powtórz nagranie). Zostanie utworzony plik wav (niestety plik ten nie istnieje fizycznie na dysku, lecz tylko w bazie wypowiedzi) dla danego zwrotu i jeśli ten zwrot zawarty jest wewnątrz nawiasów kwadratowych, będzie on podzielony na segmenty.

Każde nagranie można edytować. Trzeba w tym celu kliknąć dany zwrot w kolumnie Has Wave. Lecz nie można tym narzędziem dokonywać poważniejszych edycji pliku dźwiękowego. Istnieje natomiast możliwość importu plików dźwiękowych formacie wav.

Na poniższym rysunku (Rys. 6) przedstawione są nagrane wypowiedzi oraz Recording Tool służący do ich nagrywania.

 

Rys. 6. Speech Prompt Editor

 

 

Dobrym sposobem na tworzenie naturalnie brzmiących i wyraźnych wypowiedzi jest wypowiadanie słów na przemian ze słowem rozpoczynającym i kończącym się głoską bezdźwięczną, np. t, p, f, s, k. Takim słowem może być np. Patrick. I tak jeśli chcemy uzyskać najlepszy efekt można zastosować tę metodę i nagrać przykładowy tekst :

 „We have Patrick Lord of the Rings, Patrick Grinch, Patrick The Incredibles, Patrick Matrix, Patrick Shrek.”.

Następnie zwrot ten dzielimy na segmenty.  

 

Po skończeniu nagrań ponownie dokonujemy walidacji. Można w tym celu wpisać w oknie Prompt Validation zwrot, który chcemy sprawdzić czy istnieje w bazie i kliknąć Do Validate (można też walidować całe pliki tekstowe zawierające zwroty) lub dokonać walidacji całego projektu wypowiedzi wybierając Do Validate Solution. Zwroty, które nie istnieją w bazie wypowiedzi będą zamienione na syntezowaną mowę i wypowiedziane przez systemowgo lektora.

 

Teraz należy wskazać każdej kontrolce QA źródło (nagranych) wypowiedzi. Dokonamy tego za pomocą kontrolki SpeechControlSettings, która służy do ustawiania wspólnych właściwości dla kontrolek głosowych znajdujących się na stronie (zawiera kolekcję elementów, w których przechowywane są te właściwości). Wstawiamy z Toolbox/Speech kontrolkę SpeechControlSettings. Najpierw zdefiniujemy dla niej źródło wypowiedzi (bazę wypowiedzi). W panelu Properties zmieniamy jej ID na QASpeechControlSettings, a w Speech/Items klikamy przycisk edycji, wywołując okno SpeechControlSettingsItem Collection Editor. W nim dodajemy nowy element. W jego właściwościach zmieniamy ID na SpeechControlSettingsItemQA i wybieramy QA/Prompt/PromptDatabases i klikamy przycisk edycji wywołując kolejne okno PromptDatabase Collection Editor. Dodajemy nową bazę wypowiedzi, a jako źródło podajemy ścieżkę (względną) do pliku bazy wypowiedzi. W naszym przypadku wpisujemy Prompts/KinoPrompts.prompts i zatwierdzamy. Teraz trzeba każdej kontrolce QA w naszej aplikacji wskazać kolekcję tych właściwości (w naszym przypadku źródło wypowiedzi). W tym celu otwieramy Property Builder dla kontrolki WelcomeQA i z listy Speech Settings Item wybieramy element, w którym przechowywane są te właściwości, czyli SpeechControlSettingsItemQA. Podobnie czynimy z pozostałymi kontrolkami QA. Jeśli po walidacji projektu wypowiedzi nie było żadnych błędów to wszystkie kontrolki QA w naszej aplikacji będą pobierały nagrane zwroty z naszej bazy wypowiedzi i nie będzie zwrotów zamienianych na syntezowaną mowę i wypowiadanych przez systemowego lektora

Dla każdej kontrolki QA można zmienić standardowe ustawienia tzw. timeout, np. czas przez jaki moduł rozpoznawania mowy będzie czekał na odpowiedź użytkownika, zanim nastąpi ponowienie pytania.

 

 

  • Utworzenie kontrolek potwierdzenia i anulowania rezerwacji

Aplikacja musi się upewnić czy wszystkie zwroty zostały poprawnie przez nią rozpoznane. W tym celu przytacza rozpoznane zwroty (w naszym przykładzie syntezowana mowa) i prosi użytkownika o ich skorygowanie. Jeśli nie wszystkie zwroty zostały poprawnie rozpoznane proces rezerwacji biletów rozpoczyna się na nowo.

Na naszą stronę główną do PanelKino przeciągamy kontrolkę QA i nadajemy jej ID ConfirmQA, a SpeechIndex ustawiamy na 7 (żeby była aktywna przed ThanksQA) Dodajemy jej informacje semantyczne, wiążąc ją z odpowiednim elementem SemanticMap. Wykonujemy to tak jak w przypadku kontrolki TitleQA, czyli w Property Builder w zakładce Inupt/General dodajemy istniejąca gramatykę Kino.grxml i regułę Confirm, a w zakładce odpowiedzi wiążemy element nodeYes z węzłem /SML/Yes i element nodeNo z węzłem /SML/No.

Teraz chcemy, aby lektor systemowy przytoczył rozpoznane zwroty. Odznaczamy więc opcję BargeIn w zakładce Output/General, aby użytkownik wysłuchał do końca tej wypowiedzi i dopiero wtedy zdecydował czy są one poprawne. Zaznaczamy Prompt function i wybieramy Manage this page’s prompt function script files. Dodajemy nowy plik funkcji nadając mu nazwę Kino.pf. Prompt functions są pisane w JScript, ale są przechowywane w pliku z rozszerzeniem *.pf (zamiast *.js), zawierającym nagłówek XML, aby mogły zostać poprawnie zinterpretowane przez Prompt Function Editor i aby umożliwić Prompt Validation Tool walidację wypowiedzi.

Zatwierdzamy i z listy rozwijanej pod RadioButtonem wybieramy <New… >. Edytujemy utworzoną tym samym funkcję ConfirmQA_prompt. W nowym oknie w kolumnie Parameter Name pod History wpisujemy nazwy parametrów (zmiennych, którym przypiszemy wartości rozpoznanych zwrotów) dla reguł gramatycznych Title, Day, Time, Mount nadając im nazwy pTitle, pDay, pTime, pAmount, a w Validation Value wpisujemy w podwójnych apostrofach w oddzielnych linijkach odpowiadające im rozpoznawane zwroty .

I tak dla pTitle wpiszemy:

“Lord of the Rings”

“Grinch”

„The Incredibles”

„Matrix”

„Shrek”

Dla pDay wpisujemy np. „Monday”. Dla pTime – „five o’clock”. Dla pAmount – „one”. Wartości te są używane jedynie do pomyślnego przejścia przez proces walidacji. W kolumnie Runtime Value wpisujemy zwracaną przez odpowiedni element SemanticMap wartość, np. dla pTitle wpiszemy nodeTitle.value. Lecz my stworzymy uniwersalną funkcję zwracającą tę wartość, przekazując jej jako parametr odpowiedni element SemanticMap, w którym jest przechowywany rozpoznany zwrot, np. dla pTitle wpisujemy PobierzWartość(nodeTitle). Za chwilę zdefiniujmy te funkcję. A teraz dopiszemy kilka linijek kodu do naszej funkcji ConfirmQA_prompt. Definicja tej funkcji jest przedstawiona na Rys. 7.

 

 

Rys. 7. Prompt Function Editor

 

 

Nadszedł czas na zdefiniowanie funkcji PobierzWartosc(param). Otwórz Default.aspx w widoku HTML i zaraz za elementem <body> wpisz następujący kod:

            <SCRIPT>

            // <![CDATA[

                        function PobierzWartosc(param)

                        {

                             return(param == null ? null : param.value);

                        }

            // ]]>

            </SCRIPT>

 

Skoro mamy już funkcję, która pyta nas o potwierdzenie rezerwacji teraz trzeba zdefiniować funkcję, która podejmie odpowiednie działanie, w przypadku gdy użytkownik nie potwierdzi rezerwacji – w naszym przypadku rozpoczyna dialog od początku.

 

function niePotwierdzonaRezerwacja()

{

      if(nodeNo.value == "No")

      {

            nodeTitle.Clear();

nodeDayOfWeekText.Clear();

nodeTimeText.Clear();

nodeHoursValue.Clear();

nodeMinutesValue.Clear();

nodeAmount.Clear();

nodeYes.Clear();

nodeNo.Clear();

nodeCancel.Clear();    

      }

      return;

}

Wpisujemy ten kod do Default.aspx zaraz za nawiasem klamrowym zamykającym funkcję PobierzWartosc(param). W Property Builder dla SemanticMap wybieramy element nodeNo i w polu OnClientChanged wpisujemy nazwę tej funkcji: niePotwierdzonaRezerwacja.

 

Teraz zajmiemy się stworzeniem kontrolki, która będzie anulowała naszą rezerwację i zakończy rozmowę. Zgodnie z regułą Cancel – aplikacja będzie reagować na słowa: Cancel i Stop. A co najważniejsze: wszystkie kontrolki (z wyjątkiem, które mają odznaczoną opcję AllowCommands) będą reagować na te słowa przez cały czas trwania aplikacji

Na początku zdefiniujemy dwie funkcje:

 

var activeQA=true;

 

function CzyAktywnaQA()

{

      return activeQA;

}

 

function AnulujRezerwacje()

{

      activeQA = false;

}

Wpisujemy powyższy kod wewnątrz elementów CDATA w pliku Default.aspx.

Gdy aplikacja jest uruchamiana stan aktywności wszystkich kontrolek jest ustawiony na true i nasza zmienna activeQA przyjmuje wartość true. Funkcja CzyAktywnaQA zwraca wartość zmiennej activeQA. Funkcja AnulujRezerwacje, natomiast, dezaktywuje wszystkie kontrolki QA na stronie, co kończy naszą aplikacje. Wymaga to jednak zdefiniowania dla każdej kontrolki QA własności ClientActivationFunction.

 

Teraz na stronę główną przeciągamy kontrolkę Command, w Property Builder zmieniamy jej ID na CancelCommand. Jako Speech SettingsItem wybieramy SpeechControlSettingsItemQA. Z listy Scope wybieramy KinoPanel (jest to identyfikator kontrolki, wewnątrz której kontrolka Command jest aktywna), a w polu Type wpisujemy Cancel (uwaga na wielkość liter). Podobnie jak wcześniej w zakładce Input dodajemy nasza gramatykę Kino.grxml i regułę Cancel. Używając XPathTrigger Sample Sentence Tool uzyskujemy węzeł /SML/Cancel, który wybieramy z listy XPathTrigger. W polu OnClientCommand wpisujemy AnulujRezerwacje. W zakładce VoiceOutput/General w polu InlinePrompts wpisujemy:

 „Your ordered has been canceled. Goodbye. ”.

Teraz dla każdej kontrolki QA w PanelKino wpisujemy we właściwościach w polu ClientActivationFunction  nazwę naszej funkcji: CzyAktywnaQA.

 

 

  • Startujemy….

Przed uruchomieniem aplikacji warto jeszcze sprawdzić kolejność aktywności kontrolek w panelu Speech Control Outline. Znajdują się tam również przydatne informacje dla każdej z nich, co widać na Rys. 8.

 

Rys. 8. Speech Control Outline

 

Należy jeszcze raz dokonać walidacji projektu wypowiedzi i ewentualnie nagrać nowe zwroty.

 

Aplikację voice-only najlepiej uruchamiać w Telephony Application Simulator. W tym celu otwieramy Solution Explorer i klikamy prawym klawiszem myszy na Default.aspx. Wybieramy Browse with. Dodajemy nowy program c:\Program Files\Microsoft Speech Application SDK 1.0\SDKTools\Telephony Application Simulator\TASim.exe. Ustawiamy go jako domyślny.

Po jego uruchomieniu, standardowo uruchomiona zostaję także konsola Speech Debugging Console, w której możemy podejrzeć jakie funkcję są w danym momencie wykonywane lub jaki zwrot został rozpoznany oraz przeprowadzić inne czynności służące „odpluskwianiu” programu (aby można było odpowiedzieć na zadane pytanie należy kliknąć przycisk Use Audio).

My jednak wyłączyliśmy w opcjach uruchamianie za każdym razem tej konsoli (będzie ona startowała tylko wtedy, gdy wystartujemy naszą aplikację z opcją Debug). Gdy w oknie TASim pojawi się komunikat “Ready to dial” w pole destination device wpisujemy numer, pod który należy zadzwonić, aby połączyć się z daną aplikacją. Nasza aplikacja nie ma stałych numerów – numery te należy zdefiniować (np. w pliku XML), wtedy gdy np. w jednym projekcie mamy kilka aplikacji głosowych. W naszym przypadku wpisujemy dowolną liczbę, np. 111 i klikamy dial.

Teraz możemy zarezerwować np. 2 bilety na sobotę na godzinę 18:00 na film „Nie ma mocni” (oczywiście z angielskim dubbingiem :) ).

 

 

  • Linki

Załączniki:

Podobne artykuły

Komentarze 3

User 81271
User 81271
3 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Plik bazy prompt'ów (Prompts.promptdb) zajmuje ok. 9 MB i dlatego nie zamieszczalem go tu na serwerze. Jeśli ktoś jest zainteresowany to proszę o namiary - a wyślę "czem prędzej".
xqsnake
xqsnake
8 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
i co to formatowanie zostanie tak do konca? moglby ktos sie tym zajac?
User 79543
User 79543
30 pkt.
Poczatkujacy
21-01-2010
oceń pozytywnie 0
Poniższy tekst nie powinien się tu znaleźć - jest fragmentem innej recenzji:
 
Błędy merytoryczne:
ABB jest ciut więcej ;)
 
Co warto dodać:
Ciekawszy przykład
pkt.

Zaloguj się lub Zarejestruj się aby wykonać tę czynność.