Pierwsze starcie z syntezatorem mowy

“Stara” wersja Flaksatora korzystała z antycznej wersji MS TextToSpeech by “deklamować” powstałe limeryki. Połączenie patetycznego głosu syntezatora mowy z tymi wywalonymi od czapy tekstami stanowiło dodatkowy komiczny efekt. Korzystając z mojego udziału w projekcie Akademii Integracji (więcej: tutaj i tutaj), w pod-projekcie gdzie użycie kwestii związanych z syntezą i rozpoznawaniem mowy są kluczowe, postanowiłem popełnić ten krótki i jakże pouczający POC.

Źródła: (Github)
Tamże wrzuciłem od razu instalki Microsoft TextToSpeech wraz z bibliotekami językowymi.

Użycie syntezy mowy jest dość banalne:

SpeechSynthesizer synthesizer = new SpeechSynthesizer();
synthesizer.Speak("Witaj świecie.");

Oczywiście jeśli w systemie nie jest zainstalowany TTS kod powyższy ciepnie wyjątkiem.
Inaczej, jeśli brak w systemie polskiego “lektora”, to TTS spróbuje użyć domyślnego w systemie (zapewne en-US) i to co przeczyta to będzie bełkot.
Można spróbować to naprawić:

private bool InitializeSpeechEngine()
{
    _synthesizer = new SpeechSynthesizer();
    var knownVoices = _synthesizer.GetInstalledVoices().ToArray();
    var plVoice = knownVoices.SingleOrDefault(v => v.VoiceInfo.Culture.Name == "pl-PL");
    if (plVoice == null)
    {
        if (_synthesizer.Voice.Culture.Parent != null &&
            _synthesizer.Voice.Culture.Parent.Name == "en")
        {
            _synthesizer.Speak("Polish version of text-to-speech not found or activated.");
        }
        else
        {
            PlayInvalidSpeechEngineFailureWav();
        }
        return false;
    }
            
    return true;
}

Zdaje się, nie można wybrać programowo preferowanego języka, pozostaje kombinowanie ze sprawdzaniem co jest zainstalowane. W projekcie dla Akademii, zakładam, że odbiorcami są ludzie niewidomi lub ociemniali, więc wszystko powinno elegancko działać bez potrzeby grzebania po systemowej konfiguracji – a tu będzie trzeba osoby widzącej by wszystko skonfigurować. Bardzo źle.
Mało tego – na moim domowym Win 10 PL mam polskiego lektora. Na roboczym laptopie (Win 8 EN) oczywiście angielskiego (a nawet trzech). I nie da się zainstalować, ani wybrać wersji PL. Jeszcze gorzej.

Czyżbym musiał zdecydować się na innego dostawcę? Ivona w wersji Dev jest ponoć bezpłatna…

Z drugą stroną medalu jest jeszcze gorzej. Interfejs Speech Recognition wydaje się być całkiem ciekawy. Ja zbadałem na razie tylko bardziej interesującą mnie część dotyczącą obsługi wbudowanych komend, więc nie mam pojęcia jak to wygląda w przypadku rozpoznawania “otwartej mowy”, ale przypuszczam, że bardzo źle – widząc jak sobie radzą rozmaite Cortany i Siri nawet w wersji angielskiej…

W teorii konfiguracja komend jest bardzo ciekawa:

private Grammar CreateExitGrammar()
{
    Choices choices = new Choices( new [] {
        new GrammarBuilder("wyjdź") ,
        new GrammarBuilder("zamknij się"),
        new GrammarBuilder("zakończ")
    });
    Grammar grammar = new Grammar(choices)
    {
        Name = "exit"
    };
    return grammar;
}

private Grammar CreateWelcomeGrammar()
{
    Choices choices = new Choices(new[] {
        new GrammarBuilder("witaj") ,
        new GrammarBuilder("heloł"),
        new GrammarBuilder("siemka")
    });
    Grammar grammar = new Grammar(choices)
    {
        Name = "welcome"
    };
    return grammar;
}

Inicjalizacja silnika wydaje się też banalna:

private bool InitializeSpeechRecognitionEngine()
{
    var engines = System.Speech.Recognition.SpeechRecognitionEngine.InstalledRecognizers();
    if (engines.Count == 0)
    {
        // SpeechSDK:  https://www.microsoft.com/en-us/download/details.aspx?id=10121
        _synthesizer.Speak("Nie wykryto żadnych systemów rozpoznawania mowy.");
        return false;
    }

    var engine = engines.SingleOrDefault(r => r.Culture.Name == "pl-PL");
    if (engine == null)
    {
        // LanguagePacks: https://msdn.microsoft.com/en-us/library/hh378476(v=office.14).aspx
        _synthesizer.Speak("Nie wykryto systemu rozpoznawania mowy dla języka polskiego.");
        return false;
    }

    _recognizer = new SpeechRecognitionEngine(engine);
    _recognizer.SpeechRecognized += RecognizerOnSpeechRecognized;
    _recognizer.SetInputToDefaultAudioDevice();

    _recognizer.LoadGrammar(CreateExitGrammar());
    _recognizer.LoadGrammar(CreateWelcomeGrammar());

    return true;
}

A naiwna implementacja rozpoznawania komend czytelna w użyciu:

private void RecognizerOnSpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
    if (e.Result.Grammar.Name == "exit")
    {
        if (e.Result.Text == "zamknij się")
        {
            _synthesizer.Speak("Dobra, już! Zamykam się.");
        }
        else
        {
            _synthesizer.Speak("Zamykam program!");
        }
        Application.Exit();
    }
    else if (e.Result.Grammar.Name == "welcome")
    {
        HelloWorld();
    }
}

private void HelloWorld()
{
     _synthesizer.Speak("A teraz komputerek przemawia do ciebie!");
}

To co z tego, skoro na moim systemie PL nie udało mi się aktywować rozpoznawania mowy, mimo, że teoretycznie MS udostępnia odpowiednie pakiety! Na firmowym EN co prawda jest wersja angielska, ale nie urządza mnie ona ani trochę. Pozostaje także poszukać jakiejś innej alternatywy.

Google? HP?
Ktoś z Szanownych Czytelników ma jakieś doświadczenie i może coś zaproponować?