Syntezator Mowy - odpowiedzi pobierane z INI.

0

Witam
Jakiś czas temu bawiłem się z synteza mowy. Biorąc obecnie dostępne na rynku "glosy" rezultaty są na tyle zadowalające ze postanowiłem nieco rozbudować program. Do tej pory kwestie były dodawane z poziomu samego programu.
W chwili obecnej próbuje wprowadzić pobieranie odpowiedzi z Ini. Oczywiście nie jest problemem pobranie wartości z ini i przypisanie jej do zmiennej, jednak problem pojawia się gdy chcę w pobranej odpowiedzi wstawić jakaś zmienna z programu. tzn.

np. Program ma odczytać aktualna godzinę
('jest godzina'-(cześć pobrana z ini) +time- (zmienna z programu)'słonce zajdzie za'-(cześć z ini)+ słonce (zmienna z programu).

Kwestia zapisana w INI.
jest godzina słonce zajdzie.

Całość dodatkowo komplikuje założenie ze do jednego zdarzenia programu np. buttona ma być kilka kwestii z których wybierana i syntezowana będzie jedna, w każdej z tych kwestii zmienna pobierana z programu może być w innym miejscu wypowiedzi. Proszę o rady jak dodać do zapisanych w ini kwestii znacznik określający ze program ma w danym miejscu podstawić np. aktualny czas. Mam nadzieje ze za dużo nie namieszałem i jest to w miarę jasne :).

0

Za pewne ktoś tutaj będzie miał lepszy pomysł, ale ja bym ustalił sobie jakieś słowa kluczowe. Przykładowo %time% i później robiąc StringReplace z flagą rfIgnoreCase zamieniał te "słowa kluczowe" na pożądane wartości słowne jako tekst do odczytania przez syntezator. To coś trochę jak działanie wpisów %s, %d i tym podobnych w funkcji Format. Tylko tam oczywiście od strony kodu jest to rozwiązane - o ile wiem - trochę inaczej.

0

pozwolę sobie poczytać, do czego doszliście, bo ten temat próbowałem rozgryźć, ale niestety mi sie nie udało.

0

Olesio jesteś w stanie podać jakiś żywy przykład to co znalazłem za 4P jest napisane dość powierzchownie i nie wiele z tego rozumiem a zaproponowane przez Ciebie rozwiązanie chyba załatwi mój problem.

1
Function ResolveConstants(const Input: String): String;
Begin
 Result := Input;

 Result := StringReplace(Result, '%time%', TimeToStr(Time), [rfReplaceAll]);
End;

Coś w ten deseń, jak zgaduję.


to co znalazłem za 4P jest napisane dość powierzchownie i nie wiele z tego rozumiem

http://www.delphibasics.co.uk/RTL.asp?Name=StringReplace
http://delphi.about.com/library/rtl/blrtlStringReplace.htm
http://www.stringreplace.com/delphi/delphi-stringreplace-function/
http://docwiki.embarcadero.com/Libraries/XE4/en/System.SysUtils.StringReplace
...

0

Ok przerobiłem nieco podana przez ciebie funkcje i całość wygląda tak jeśli możecie zwrócić mi uwagę na błędy będę wdzięczny.

iprocedure TUstawienia.Speech(const Msg: integer; wartosc:integer);
var
  odpowiedzi:TStringList;
  PlikINI: TIniFile;
  a,Count:integer;
  text: string;
begin

    odpowiedzi:=Tstringlist.create;

    PlikINI:= TIniFile.Create(ExtractFilePath(Application.ExeName)+'Pliki Ustawien\Odpowiedzi.ini');
    Count := PlikINI.ReadInteger('Odpowiedzi',inttostr(msg), 0);
         for a := 0 to Count -1 do
            odpowiedzi.Add (PlikINI.Readstring('odpowiedzi',inttostr(msg)+ IntToStr(a+1),''));//dodanie  
            text:=odpowiedzi.Strings[Random(odpowiedzi.count)];

            text := StringReplace(text, '%time%', (FormatDateTime('HH:MM',Time)), [rfReplaceAll]); //sprawdzenie slowa kluczowego

            OknoDialogu.Items.Add(text);//dodanie do listboxa
            OknoDialogu.ItemIndex:= 0; index listboxa na 0
            SpeechEngine.Speak((text),SVSFlagsAsync); //synteza
           odpowiedzi.Free;   //zwolnienie pamieci
    PlikINI.Free;
    end;
    end;
end;

Całość oczywiście w tej chwili działa.

1

Zacząłbym od zmiany formatowania kodu, jest nieczytelne.
Btw, oczywiste komentarze w stylu odpowiedzi.Free; //zwolnienie pamieci są zbędne.

1

I trzymanie się pewnych reguł:

odpowiedzi.Add (PlikINI.Readstring('odpowiedzi',inttostr(msg)+ IntToStr(a+1),''));

może jednak ładniej ;)

odpowiedzi.Add(PlikINI.Readstring('odpowiedzi', IntToStr(msg) + IntToStr(a + 1), ''));

Wiem, że delphi nie zwraca uwagi na wielkość liter, ale dla swojego własnego dobra lepiej jednak tego się nauczyć.

1

Należy także dodać, że przy pracy z dynamicznie tworzonymi klasami warto wykorzystać blok try .. finally (oraz opcjonalnie try .. except);

Poza tym podany przez Ciebie @tayamoto kod jest jakiś dziwny - gdzieć pogubiłeś begin i masz dwa dzikie end na końcu kodu; Pewnie pisany z głowy - w każdym razie wymaga poprawki.

0

Dzieki wszystkim za sugestie zaraz sformatuje i poprawie kod, Co do :

furious programming napisał(a):

Poza tym podany przez Ciebie @tayamoto kod jest jakiś dziwny - gdzieć pogubiłeś begin i masz dwa dzikie end na końcu kodu; Pewnie pisany z głowy - w każdym razie wymaga poprawki.

To na początku kodu mam jeszcze sprawdzenie dwóch warunków if z które nie wiele wnosiły do sprawy i nie było sensu ich dodawać stad te dzikie end.

0

Mam jeszcze jedno pytanie a z racji ze temat nadal otwarty nie będę spamował forum. Mianowicie pobieranie i syntezę komunikatów z ini wywołuje
Speech(1,3);
Gdzie "1" to index komunikatu z ini natomiast 3 to waga komunikatu (inna bajka mało istotna dla sprawy).
Wszystko jest dobrze jeśli index komunikatu nie przekroczy 10 potem zmienna count z w/w procedury przybiera wartość 0 i wszystko się sypie. Próbowałem dodać separator miedzy "count" a "a" ale nic to nie dało. Jakieś sugestie.

0

Wszystko jest dobrze jeśli index komunikatu nie przekroczy 10 potem zmienna count z w/w procedury przybiera wartość 0 i wszystko się sypie.

Na tej linijce:

Count := PlikINI.ReadInteger('Odpowiedzi',inttostr(msg), 0);

?

A jak masz zapisane to w INI?

0

11=3
111= cos
112= cos
113= cos

1

Czekaj czekaj, tak? :

[odpowiedzi]
11=3
111= cos
112= cos 
113= cos

Czyli 11, 111, 112 i 113 to są klucze? Proponuję je lepiej nazwać, bo przez takie identyfikatory możesz mieć problemy... Dodatkowo zobacz pod debugerem jak jest budowany łańcuch w pętli.


Może zrób sobie osobne sekcje dla różnych typów odpowiedzi; Poza tym przekazywanie liczb w argumentach metody Speech jest mało czytelne; Proponowałbym zrobić sobie enumy ze słowną reprezentacją typów odpowiedzi, przez co kod będzie czytelniejszy; Jeśli potrzebowałbyś zamienić sobie enuma na liczbę to wystarczy zwykłe rzutowanie na Byte; A jeśli w pliku INI nazwałbyś "słownie" klucze, to możesz sobie zrobić macierz indeksowaną tym enumem i z niej pobierać słowną nazwę klucza i wtedy za jego pomocą wczytać odpowiednie informacje.

0

Tak myślałem niestety to zmienia również sposób wywoływania komunikatu w kodzie, wszystko działa dopóki klucz nie przekroczy 10, ale chyba będę musiał to inaczej ogryźć.

0

Przepuściłem pomocnicza zmienna przez debuggera i ścieżka była układana prawidłowo, najwidoczniej sama składnia nie była właściwa. W chwili obecnej już sobie poradziłem i udało mi się zachować numeryczne odwołanie do odpowiedzi. Zrezygnowałem z ogólnej sekcji "odpowiedzi' zastąpiłem ja wieloma sekcjami typu integer które są jednocześnie odwołaniami do komunikatów z kodu, same zaś klucze to odpowiedzi. Rozwiazanie możne mało profesjonalne ale udało się usunac problem, niemniej bardzo dziękuję za zainteresowanie i wszelkie sugestie. Pozdrawiam.

1 użytkowników online, w tym zalogowanych: 0, gości: 1