alphacep / vosk-server

WebSocket, gRPC and WebRTC speech recognition server based on Vosk and Kaldi libraries
Apache License 2.0
918 stars 248 forks source link

Added grammar loading and runtime processing #66

Open Lirein opened 4 years ago

Lirein commented 4 years ago

A has been added JSGF grammar online parser for the vosk asr-server working as websocket service. Best for the asterisk plugin integration.

Working example:

    -- Executing [#5@equip:1] Answer("SIP/user3-00000015", "") in new stack
    -- Executing [#5@equip:2] Wait("SIP/user3-00000015", "1") in new stack
    -- Executing [#5@equip:3] SpeechCreate("SIP/user3-00000015", "vosk") in new stack
[Jul 10 13:20:11] NOTICE[8188][C-00000016]: res_speech_vosk.c:188 vosk_recog_create: (vosk) Create speech resource
    -- Executing [#5@equip:4] Set("SIP/user3-00000015", "SPEECH_ENGINE(mode)=grammar") in new stack
[Jul 10 13:20:11] NOTICE[8188][C-00000016]: res_speech_vosk.c:554 vosk_recog_change: (vosk) Change setting name: mode value:grammar
    -- Executing [#5@equip:5] Set("SIP/user3-00000015", "SPEECH_ENGINE(language)=ru") in new stack
[Jul 10 13:20:11] NOTICE[8188][C-00000016]: res_speech_vosk.c:554 vosk_recog_change: (vosk) Change setting name: language value:ru
[Jul 10 13:20:11] NOTICE[8188][C-00000016]: res_speech_vosk.c:601 vosk_recog_get_settings: (vosk) Get settings name: language
    -- Executing [#5@equip:6] NoOp("SIP/user3-00000015", "ru") in new stack
    -- Executing [#5@equip:7] SpeechLoadGrammar("SIP/user3-00000015", "test,/home/director/vosk/vosk-server/websocket/test.gram") in new stack
    -- Executing [#5@equip:8] SpeechActivateGrammar("SIP/user3-00000015", "test") in new stack
    -- Executing [#5@equip:9] SpeechBackground("SIP/user3-00000015", "ivr0,25") in new stack
[Jul 10 13:20:11] NOTICE[8188][C-00000016]: res_speech_vosk.c:508 vosk_recog_start: (vosk) Start recognition
[Jul 10 13:20:11] NOTICE[8188][C-00000016]: res_speech_vosk.c:274 vosk_load_ws_grammar: (vosk) Upload grammar to engine over websocket: test 
[Jul 10 13:20:11] NOTICE[8188][C-00000016]: res_speech_vosk.c:337 vosk_set_ws_grammar: (vosk) Activate grammar in engine over websocket: test 
[Jul 10 13:20:11] NOTICE[8188][C-00000016]: res_speech_vosk.c:540 vosk_recog_start: (vosk) Connecting to the speech recognition service result 0
[Jul 10 13:20:12] NOTICE[8188][C-00000016]: res_speech_vosk.c:445 vosk_recog_write: (vosk) Got result: '{
  "partial" : ""
}'
[Jul 10 13:20:12] NOTICE[8188][C-00000016]: res_speech_vosk.c:445 vosk_recog_write: (vosk) Got result: '{
  "partial" : ""
}'
[Jul 10 13:20:13] NOTICE[8188][C-00000016]: res_speech_vosk.c:445 vosk_recog_write: (vosk) Got result: '{
  "partial" : ""
}'
[Jul 10 13:20:13] NOTICE[8188][C-00000016]: res_speech_vosk.c:445 vosk_recog_write: (vosk) Got result: '{
  "partial" : ""
}'
[Jul 10 13:20:13] NOTICE[8188][C-00000016]: res_speech_vosk.c:445 vosk_recog_write: (vosk) Got result: '{
  "partial" : ""
}'
[Jul 10 13:20:13] NOTICE[8188][C-00000016]: res_speech_vosk.c:445 vosk_recog_write: (vosk) Got result: '{
  "partial" : ""
}'
[Jul 10 13:20:13] NOTICE[8188][C-00000016]: res_speech_vosk.c:445 vosk_recog_write: (vosk) Got result: '{
  "partial" : ""
}'
[Jul 10 13:20:13] NOTICE[8188][C-00000016]: res_speech_vosk.c:445 vosk_recog_write: (vosk) Got result: '{
  "partial" : "нам не"
}'
[Jul 10 13:20:13] NOTICE[8188][C-00000016]: res_speech_vosk.c:445 vosk_recog_write: (vosk) Got result: '{
  "partial" : "нам не"
}'
[Jul 10 13:20:14] NOTICE[8188][C-00000016]: res_speech_vosk.c:445 vosk_recog_write: (vosk) Got result: '{
  "partial" : "нам не нужна реклама"
}'
[Jul 10 13:20:14] NOTICE[8188][C-00000016]: res_speech_vosk.c:445 vosk_recog_write: (vosk) Got result: '{
  "partial" : "нам не нужна реклама"
}'
[Jul 10 13:20:14] NOTICE[8188][C-00000016]: res_speech_vosk.c:445 vosk_recog_write: (vosk) Got result: '{
  "partial" : "нам не нужна реклама"
}'
[Jul 10 13:20:14] NOTICE[8188][C-00000016]: res_speech_vosk.c:445 vosk_recog_write: (vosk) Got result: '{
  "partial" : "нам не нужна реклама"
}'
[Jul 10 13:20:14] NOTICE[8188][C-00000016]: res_speech_vosk.c:445 vosk_recog_write: (vosk) Got result: '{
  "partial" : "нам не нужна реклама"
}'
[Jul 10 13:20:14] NOTICE[8188][C-00000016]: res_speech_vosk.c:445 vosk_recog_write: (vosk) Got result: '{
  "partial" : "нам не нужна реклама"
}'
[Jul 10 13:20:15] NOTICE[8188][C-00000016]: res_speech_vosk.c:445 vosk_recog_write: (vosk) Got result: '{"grammar": "cancel", "text": "\u043d\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u043d\u0430 \u0440\u0435\u043a\u043b\u0430\u043c\u0430", "result": [{"conf": 1.0, "start": 0.78, "end": 0.96, "word": "\u043d\u0430\u043c"}, {"conf": 1.0, "start": 0.96, "end": 1.05, "word": "\u043d\u0435"}, {"conf": 1.0, "start": 1.05, "end": 1.32, "word": "\u043d\u0443\u0436\u043d\u0430"}, {"conf": 1.0, "start": 1.32, "end": 1.71, "word": "\u0440\u0435\u043a\u043b\u0430\u043c\u0430"}]}'
[Jul 10 13:20:15] NOTICE[8188][C-00000016]: res_speech_vosk.c:453 vosk_recog_write: (vosk) Recognition result: нам не нужна реклама
[Jul 10 13:20:15] NOTICE[8188][C-00000016]: res_speech_vosk.c:469 vosk_recog_write: (vosk) Stream playing: yes mode is:grammar
    -- Executing [#5@equip:10] Verbose("SIP/user3-00000015", "0,Result was нам не нужна реклама") in new stack
Result was нам не нужна реклама
    -- Executing [#5@equip:11] Verbose("SIP/user3-00000015", "0,Result was cancel") in new stack
Result was cancel
    -- Executing [#5@equip:12] NoOp("SIP/user3-00000015", "") in new stack
    -- Auto fallthrough, channel 'SIP/user3-00000015' status is 'UNKNOWN'
[Jul 10 13:20:15] NOTICE[8188][C-00000016]: res_speech_vosk.c:196 vosk_recog_destroy: (vosk) Destroy speech resource
  == WebSocket connection to '127.0.0.1:2700' closed
[Jul 10 13:20:21] NOTICE[20407]: chan_sip.c:28731 handle_request_subscribe: Received SIP subscribe for peer without mailbox: user3
[Jul 10 13:20:21] NOTICE[8207]: chan_sip.c:28731 handle_request_subscribe: Received SIP subscribe for peer without mailbox: user3
[Jul 10 13:21:05] NOTICE[20407]: chan_sip.c:30450 sip_poke_noanswer: Peer 'user3' is now UNREACHABLE!  Last qualify: 1
[Jul 10 13:22:21] NOTICE[20407]: chan_sip.c:28731 handle_request_subscribe: Received SIP subscribe for peer without mailbox: user3
[Jul 10 13:22:21] NOTICE[8318]: chan_sip.c:28731 handle_request_subscribe: Received SIP subscribe for peer without mailbox: user3

The example grammar one is:

#JSGF V1.0;
grammar incoming;
<hello> = (алло | ало)+ | да | здравствуйте | ау | говори | говорите;
<disc1> = [а] [вы | ты] кто;
<disc2> = [а] (какая | что за) компания;
<disc3> = [а] [кто] кто [вы | это | ты] [такой | такая | такие];
<disc4> = [я] (не знаю такого | такого не знаю);
<disc5> = [а] (что | что [вы | ты] | [вы | ты] что) [(хотел | хотела | хочешь | хотели | хотите | предлагаете | предлагаешь) | ((хочешь | хотите | хотели | можете | можешь) [вы | ты] [нам] предложить) | ([нам | мне] (предложите | предлагаете)) | ((будете | будешь) предлагать)];
<disc6> = [а] ([вам | тебе] зачем [вам | тебе] [надо | нужно] | (что | что (вам | тебе) | (вам | тебе) что) (надо | нужно));
<disc7> = [а] (какой | какое) [у] [вас | тебя] (вопрос | предложение) ;
<disc8> = [а] по какому вопросу [звоните | звонишь];
<disc9> = [а] (зачем (вы | ты) | (вы | ты) зачем | чё (вы | ты) | что (вы | ты)) [нам] (звоните | звонишь) [нам];
<disc10> = [а] ([вам | тебе] зачем [он] [вам | тебе]) [нужен | нужны] [такой | такие] [специалисты | специалист] [по рекламе];
<disc11> = [а] [с] каким [специалистом];
<disc12> = [у нас | у меня] [нет] ([таких | таких] (специалистов | специалиста) | такого | таких | никем) [нет];
<disc13> = [а] ([вы] предлагаете | [ты] предлагаешь) что;
<disc14> = [а] в чем суть [вашего | твоего] предложения;
<disc15> = [а] (расскажите | расскажи) [мне | нам] (подробнее | поподробнее);
<disc16> = [мы] [таких | такого] не держим | (таких | такого) нет;
<disc17> = [а] [по] какой рекламе;
<disc18> = [а] (кого | чего | что);
<disclosure> = <disc1> | <disc2> | <disc3> | <disc4> | <disc5> | <disc6> | <disc7> | <disc8> | <disc9> | <disc10> | <disc11> | <disc12> | <disc13> | <disc14> | <disc15> | <disc16> | <disc17> | <disc18>;
<listen1> = [да | ну] это я;
<listen2> = [хорошо | ну | да] я [вас | тебя] (слушаю | выслушаю) [вас | тебя];
<listen3> = [я] готов [вас] выслушать;
<listen4> = [хорошо] (говорите | говори | хорошо | ичё | ну);
<listen5> = [ну] (продолжайте | продолжай | жги | жгите | валяй | валяйте);
<listen6> = [вы | ты] (можете | можешь) (задать | задавать) [вопрос | вопросы] мне;
<listen7> = (задавайте | задавай | озвучивай | озвучь | озвучьте) [вопрос | вопросы] [мне];
<listen8> = [ну] я [занимаюсь [рекламой]];
<listen9> = [ну] [можешь | можете] со мной [поговорить | переговорить];
<listen10> = [ну] (можешь | можете) (поговорить | переговорить) со мной;
<listen11> = [ну] [хорошо] со мной (можешь | можете) [поговорить | переговорить | говори];
<listen12> = [ну] [хорошо] (поговорите | говорите | поговори | говори) со мной;
<listen13> = [ну | да] (да | хорошо | интересно | ага | угу);
<listen> = <listen1> | <listen2> | <listen3> | <listen4> | <listen5> | <listen6> | <listen7> | <listen8> | <listen9> | <listen10> | <listen11> | <listen12> | <listen13>;
<softcancel1> = [спасибо] [мы] уже размещаем [рекламу] [извините];
<softcancel2> = [спасибо] [[у нас] уже | у нас] есть [[свои] поставщики | [своя] реклама] [извините];
<softcancel3> = [спасибо] [мы] уже (работаем | работали) [(с | над) (рекламой | экранами | вами | рекламщиками | размещением)] [извините];
<softcancel4> = [спасибо] (с нами | со мной) уже работают [спасибо | извините];
<softcancel5> = [спасибо] [мы] не нуждаемся [в рекламе] [спасибо | извините] | нет;
<softcancel> = <softcancel1> | <softcancel2> | <softcancel3> | <softcancel4> | <softcancel5>;
<cancel1> = (не звоните | незвоните) [нам | мне | сюда] [больше] [извините];
<cancel2> = (хватит | перестаньте | перестань | прекрати | прекратите | прекращай | прекращайте) ([нам | мне] звонить | [меня | нас] беспокоить) [извините];
<cancel3> = [да] (заебали | [идите | иди | пошли | пошёл | пошла] нахуй);
<cancel4> = [нет] [спасибо] [нам | мне] [ничего | ничё] (не [нужно | надо | интересно] | неинтересно) [извините];
<cancel5> = (нам | мне) (не интересно | неинтересно) [[твоё | твоих | ваше | ваших] (предложение | предложений)] [извините];
<cancel6> = [я] [ничем] не (могу | смогу) [вам | вас] [помочь | соединить | переключить | соединю] [извините];
<cancel> = <cancel1> | <cancel2> | <cancel3> | <cancel4> | <cancel5> | <cancel6>;
<retry1> = ещё раз [пожалуйста] | [[ещё [раз]] пожалуйста] (повторите | повтори) [ещё [раз]] [пожалуйста];
<retry2> = не (понял | поняла) [вас] [ещё раз] [повторите];
<retry3> = [вас] (не | плохо) (слышно | слышу) [вас] [повторите];
<retry4> = [говорите | говори] громче [пожалуйста];
<retry5> = плохая связь;
<retry> = <retry1> | <retry2> | <retry3> | <retry4> | <retry5>;
<recall1> = [я | он | она] [очень | сильно] (занят | занята) [очень | сильно];
<recall2> = ([мне] не удобно) |  ([я] не могу) говорить;
<recall3> = у [меня | него] [сейчас] нет времени | несейчас | не сейчас;
<recall4> = [[вы] [нам | мне] можете | [ты] [нам | мне] можешь] [нам | мне] (перезвони | позвони | перезвонить | позвонить | перезвоните | позвоните | звоните) [мне | нам] [пожалуйста] [позже | попозже | потом | позднее];
<recall5> = [давайте | давай] (поговорим | обсудим) (позже | попозже | потом);
<recall6> = [мы [сами] | я [сам]] (свяжемся | свяжусь) с (вами | тобой) (позже | попозже | потом);
<recall7> = (мы [вам] [сами] | я [тебе] [сам]) [вам | тебе] (перезвоним | перезвоню);
<recall8> = [вам | тебе] (перезвонят | перезвоню) [потом | позже | позднее];
<recall9> = [мы [с вами] [сами] [с вами] | я [с тобой] [сам] [с тобой]] (свяжусь | свяжемся);
<recall10> = [он] занят | [она] занята | [он] умер | [она] умерла | [он | она] в отпуске | [он] вышел | [он] ушёл | [она] вышла | [она] ушла | [он | она] в командировке | [он] уехал | [она] уехала | [он] отлучился | [она] отлучилась | (его | её) нет [на месте];
<recall11> = (перезвони | позвони | перезвоните | позвоните | набери | наберите) (позже | позднее | на [следующей | этой] неделе | завтра | послезавтра | после обеда | вечером | (в | во) (понедельник | вторник | среду | четверг | пятницу | субботу | воскресенье) | через (неделю | месяц));
<recall12> = [он | она] (будет) [позже | позднее | на [следующей | этой] неделе | завтра | послезавтра | после обеда | вечером | (в | во) (понедельник | вторник | среду | четверг | пятницу | субботу | воскресенье) | через (неделю | месяц | час)];
<recall> = <recall1> | <recall2> | <recall3> | <recall4> | <recall5> | <recall6> | <recall7> | <recall8> | <recall9> | <recall10> | <recall11> | <recall12>;
<switch1> = [я | да | ага | угу] [сейчас | уже] [я] [тебя | вас] (переключу | соединю | переключаю | соединяю | перевожу | переведу) [звонок | вас | тебя];
<switch2> = [да | ага | угу | хорошо] (оставайтесь | оставайся | останьтесь | останься | будьте | будь | ожидай | ожидайте | ждите | жди) [на (линии | связи)];
<switch3> = [одну] (минуту | секунду | минуточку | секундочку);
<switch4> = [да | ну | ага | угу] (сейчас | хорошо | конечно);
<switch5> = не (кладите | клади | ложите | ложи | бросайте | бросай) (трубку | телефон);
<switch6> = не (отключайтесь | отключайся);
<switch> = <switch1> | <switch2> | <switch3> | <switch4> | <switch5>;
<dictate1> = (диктую | запиши | запишите | пишите | пиши | записывай | записывайте | держи | держите | набери | наберите | набирай | набирайте) (номер [телефона] | телефон);
<dictate2> = (перезвоните | перезвони | позвоните | звоните | позвони | звони | свяжитесь | свяжись) (по номеру [телефона] | по телефону);
<dictate3> = ([вы] можете | [ты] можешь) связаться по (номеру [телефона] | по телефону);
<dictate> = <dictate1> | <dictate2> | <dictate3>;
<mail1> = [все | всё] [предложения] [отправляй | скидывай | высылай | направляй | перешли | отправляйте | отправьте | скидывайте | вышлите | высылайте | направляйте | перешлите] [предложение] [на] (электронную [почту | почта] | (почту | почта)) [отправляй | скидывай | высылай | направляй | перешли | отправляйте | отправьте | скидывайте | вышлите | высылайте | направляйте | перешлите] [ваше] [предложение];
<mail> = <mail1>;
<none> = ээ | а | нуу | аа;
public <command> = (sil)* (<disclosure> | <listen> | <softcancel> | <cancel> | <retry> | <recall> | <switch> | <dictate> | <mail> | <none>);
nshmyrev commented 4 years ago

This needs more work as grammar is not applied to the actual recognizer as in https://github.com/alphacep/vosk-server/blob/f3265315217e686082b4342d53a840540c8d1925/websocket/asr_server.py#L69

I also see no point in base64 and jsgf, you can send simple texts like I wrote before.

nshmyrev commented 4 years ago

Btw, we have recently implemented proper phrase list hints, you are welcome to try them:

https://github.com/alphacep/vosk-api/commit/57cc474c9fd7fc7ce36088a5756aa2b43c7dd0b2