Syntezator Mowy - odpowiedzi pobierane z INI.

Syntezator Mowy - odpowiedzi pobierane z INI.
tayamoto
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 9 lat
  • Postów:81
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 :).


------------------------------------------
If it’s hard, work harder; if it’s impossible, work harder still. Give it whatever it takes, but do it. - Burt Munro
olesio
  • Rejestracja:około 17 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Szczecin
  • Postów:4191
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.


Pozdrawiam.
edytowany 1x, ostatnio: olesio
MM
  • Rejestracja:około 12 lat
  • Ostatnio:6 miesięcy
  • Postów:91
0

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

tayamoto
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 9 lat
  • Postów:81
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.


------------------------------------------
If it’s hard, work harder; if it’s impossible, work harder still. Give it whatever it takes, but do it. - Burt Munro
Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
1
Kopiuj
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
...


edytowany 1x, ostatnio: Patryk27
flowCRANE
Dlaczego nie podajesz Inputa bezpośrednio do funkcji StringReplace?
Patryk27
Dla większej klarowności kodu, kompilator i tak to koniec końców zamieni.
flowCRANE
A podając bezpośrednio nie będzie klarowny..? Lepiej pisać kod od razu minimalistyczny, niż powierzać kompilatorowi aż taką optymalizację;
Patryk27
Jeżeliby chciało się wprowadzić kilka takich stringów np.od razu za pomocą pętli i tablicy bądź z jakiegoś powodu zamienić kolejność pierwszego, warto pisać tak :P Autor potem może sobie to zamienić jak chce.
tayamoto
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 9 lat
  • Postów:81
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.

Kopiuj
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.


------------------------------------------
If it’s hard, work harder; if it’s impossible, work harder still. Give it whatever it takes, but do it. - Burt Munro
edytowany 1x, ostatnio: tayamoto
Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
1

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


madmike
  • Rejestracja:prawie 20 lat
  • Ostatnio:ponad 5 lat
1

I trzymanie się pewnych reguł:

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

może jednak ładniej ;)

Kopiuj
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ć.


flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około godziny
  • Lokalizacja:Tuchów
  • Postów:12171
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.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
tayamoto
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 9 lat
  • Postów:81
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.


------------------------------------------
If it’s hard, work harder; if it’s impossible, work harder still. Give it whatever it takes, but do it. - Burt Munro
flowCRANE
W porządku - myślałem, że pisałeś kod z głowy i dlatego ;)
tayamoto
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 9 lat
  • Postów:81
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.


------------------------------------------
If it’s hard, work harder; if it’s impossible, work harder still. Give it whatever it takes, but do it. - Burt Munro
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około godziny
  • Lokalizacja:Tuchów
  • Postów:12171
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:

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

?

A jak masz zapisane to w INI?


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
tayamoto
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 9 lat
  • Postów:81
0

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


------------------------------------------
If it’s hard, work harder; if it’s impossible, work harder still. Give it whatever it takes, but do it. - Burt Munro
flowCRANE
Do kolorowania składni pliku INI są znaczniki <code=ini></code>, więc możesz śmiało wkleić oryginalną zawartość pliku ;)
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około godziny
  • Lokalizacja:Tuchów
  • Postów:12171
1

Czekaj czekaj, tak? :

Kopiuj
[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.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 3x, ostatnio: flowCRANE
tayamoto
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 9 lat
  • Postów:81
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źć.


------------------------------------------
If it’s hard, work harder; if it’s impossible, work harder still. Give it whatever it takes, but do it. - Burt Munro
flowCRANE
Obstawiam, że problem jest z nazewnictwem kluczy; Zobacz pod debugerem jak jest budowany łańcuch jako nazwa klucza; Tylko zbuduj go do pomocniczej zmiennej i w oknie Watches sprawdź jej zawartość przed wczytaniem informacji z pliku;
tayamoto
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 9 lat
  • Postów:81
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.


------------------------------------------
If it’s hard, work harder; if it’s impossible, work harder still. Give it whatever it takes, but do it. - Burt Munro
flowCRANE
Najważniejsze, że dziala, a podzielenie pliku na wiele mniejszych sekcji na pewno jest zaletą;

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.