You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ws-client.js 16KB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. // #region web speech recognition api
  2. var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition;
  3. var SpeechGrammarList = SpeechGrammarList || webkitSpeechGrammarList;
  4. var SpeechRecognitionEvent = SpeechRecognitionEvent || webkitSpeechRecognitionEvent;
  5. // #endregion
  6. // #region state management
  7. var state = '';
  8. var question = 0;
  9. var rePrompt = false;
  10. var partTwo = false;
  11. var questionThreeCount = 0;
  12. var strike = 0;
  13. // #endregion
  14. // #region questions
  15. const QUESTION_ONE = 'Ich werde Ihnen jetzt langsam eine Liste mit Worten vorlesen. Danach wiederholen Sie bitte möglichst viele dieser Worte. Auf die Reihenfolge kommt es nicht an.';
  16. const QUESTION_ONE_PT2 = 'Vielen Dank. Nun nenne ich Ihnen die gleichen 10 Worte ein zweites mal. Auch danach sollen Sie wieder möglichst viele Worte wiederholen';
  17. const QUESTION_TWO = 'Nennen Sie mir bitte so viel Dinge wie möglich, die man im Supermarkt kaufen kann. Sie haben dafür eine Minute Zeit. Und Los';
  18. const QUESTION_THREE = 'Ich werde Ihnen jetzt eine Zahlenreihe nennen, die Sie mir dann bitte in umgekehrter Reihenfolge wiederholen sollen. Wenn ich beispielsweise, vier - fünf sage, dann sagen Sie bitte, fünf - vier.';
  19. // #endregion
  20. // #region intents
  21. const WELCOME_INTENT = 'Default Welcome Intent';
  22. const WELCOME_FOLLOWUP_YES = 'Default Welcome Intent - yes';
  23. const WELCOME_FOLLOWUP_NO = 'Default Welcome Intent - no';
  24. const MORE_TIME = 'Add Time Intent';
  25. const MORE_TIME_YES = 'Add Time Intent - yes';
  26. const MORE_TIME_NO = 'Add Time Intent - no';
  27. const QUIT_INTENT = 'Quit Intent';
  28. const FALLBACK_INTENT = 'Default Fallback Intent';
  29. const HELP_INTENT = 'Help Intent';
  30. const CHOOSE_QUESTION = 'Frage_Starten';
  31. const NEXT_QUESTION = 'Nächste Frage';
  32. // #endregion
  33. // #region questions and expected results
  34. const QUESTION_ONE_ANSWERS = { 'teller': 1, 'hund': 1, 'lampe': 1, 'brief': 1, 'apfel': 1, 'apfelwiese': 2, 'apfelbaum': 2, 'und': 1, 'hose': 1, 'tisch': 1, 'wiese': 1, 'glas': 1, 'baum': 1 };
  35. const QUESTION_ONE_QUESTIONS = ['teller', 'hund', 'lampe', 'brief', 'apfel', 'hose', 'tisch', 'wiese', 'glas', 'baum'];
  36. const QUESTION_TWO_ANSWERS = {};
  37. var QUESTION_TWO_QUESTIONS;
  38. const QUESTION_THREE_QUESTIONS_PT1 = ['7, 2', '4, 7, 9', '5, 4, 9, 6', '2, 7, 5, 3, 6', '8, 1, 3, 5, 4, 2'];
  39. const QUESTION_THREE_QUESTIONS_PT2 = ['8, 6', '3, 1, 5', '1, 9, 7, 4', '1, 3, 5, 4, 8', '4, 1, 2, 7, 9, 5'];
  40. const QUESTION_THREE_ANSWERS_PT1 = ['27', '974', '6945', '63572', '245318'];
  41. const QUESTION_THREE_ANSWERS_PT2 = ['68', '513', '4791', '84531', '597214'];
  42. LoadQuestionTwo();
  43. function LoadQuestionTwo () {
  44. var xmlhttp;
  45. if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari
  46. xmlhttp = new XMLHttpRequest();
  47. } else { // code for IE6, IE5
  48. xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
  49. }
  50. xmlhttp.onreadystatechange = function () {
  51. if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
  52. var text = xmlhttp.responseText.toLowerCase();
  53. // Now convert it into array using regex
  54. QUESTION_TWO_QUESTIONS = text.split('\r\n');
  55. for (let word of QUESTION_TWO_QUESTIONS) {
  56. QUESTION_TWO_ANSWERS[word] = 1;
  57. }
  58. }
  59. };
  60. xmlhttp.open('GET', 'lebensmittel.txt', true);
  61. xmlhttp.send();
  62. }
  63. // #endregion
  64. // #region points
  65. const questionPoints = {
  66. 1: 0,
  67. 2: 0,
  68. 3: 0,
  69. 4: 0,
  70. 5: 0 };
  71. // #endregion
  72. // tokenization
  73. const separators = [' ', '\\\+', '-', '\\\(', '\\\)', '\\*', '/', ':', '\\\?'];
  74. // Timers
  75. var timerId;
  76. // #region html elements
  77. var serverPara = document.querySelector('.server');
  78. var diagnosticPara = document.querySelector('.output');
  79. var testBtn = document.querySelector('button');
  80. var testBtn2 = document.getElementById('speechBtn');
  81. var infoPara = document.getElementById('info');
  82. var userPrompt = document.getElementById('query');
  83. // #endregion
  84. // websocket to communicate with the server
  85. var ws = new WebSocket('ws://' + window.location.host + window.location.pathname + 'ws');
  86. // #region speech recognition initialization
  87. var recognition = new SpeechRecognition();
  88. recognition.lang = 'de-DE';
  89. // recognition.interimResults = false;
  90. recognition.maxAlternatives = 1;
  91. recognition.continuous = true;
  92. var answerQuery = '';
  93. var skipRecording = false;
  94. // #endregion
  95. // #region speech synthesis initialization
  96. var speechsynth = new SpeechSynthesisUtterance();
  97. var listSpeechsynth = new SpeechSynthesisUtterance();
  98. var voices;
  99. // #endregion
  100. // #region speech events
  101. window.speechSynthesis.onvoiceschanged = function () {
  102. voices = window.speechSynthesis.getVoices();
  103. voices.forEach(element => {
  104. if (element.name === 'Google Deutsch') {
  105. speechsynth.voice = element;
  106. listSpeechsynth.voice = element;
  107. }
  108. });
  109. listSpeechsynth.rate = 0.7;
  110. };
  111. speechsynth.onend = function (event) {
  112. switch (question) {
  113. case 1:
  114. break;
  115. case 2:
  116. break;
  117. case 3:
  118. break;
  119. case 4:
  120. break;
  121. case 5:
  122. break;
  123. }
  124. if (!skipRecording) {
  125. recognition.start();
  126. console.log('reocgnition started. Question: ' + question);
  127. }
  128. skipRecording = false;
  129. diagnosticPara.textContent = '';
  130. console.log('global speech end');
  131. };
  132. // #endregion
  133. // #region websocket events
  134. ws.onopen = function () {
  135. serverPara.style.background = 'green';
  136. serverPara.innerHTML = 'Server online';
  137. };
  138. ws.onmessage = function (payload) {
  139. var dialogflowResult = JSON.parse(payload.data);
  140. checkIntent(dialogflowResult);
  141. document.querySelector('h1').innerHTML = dialogflowResult.intent.displayName;
  142. };
  143. // #endregion
  144. // INTENT HANDLING
  145. function checkIntent (result) {
  146. switch (result.intent.displayName) {
  147. case QUIT_INTENT:
  148. state = 'quit';
  149. if (timerId !== undefined) {
  150. clearTimeout(timerId);
  151. }
  152. skipRecording = true;
  153. speak('Beende die Durchführung.');
  154. break;
  155. case WELCOME_INTENT:
  156. state = 'detect';
  157. speak(result.fulfillmentText);
  158. break;
  159. case WELCOME_FOLLOWUP_YES:
  160. startQuestion(1);
  161. break;
  162. case WELCOME_FOLLOWUP_NO:
  163. skipRecording = true;
  164. speak('Okay, Danke fürs Benutzen.');
  165. break;
  166. case MORE_TIME:
  167. state = 'detect';
  168. speak('Brauchen Sie noch etwas Zeit?');
  169. break;
  170. case MORE_TIME_YES:
  171. rePrompt = true;
  172. state = 'answer';
  173. speak('Alles klar');
  174. break;
  175. case MORE_TIME_NO:
  176. skipRecording = true;
  177. state = 'answer';
  178. speak('Verstanden');
  179. recognition.stop();
  180. ws.send(answerQuery);
  181. break;
  182. case CHOOSE_QUESTION:
  183. question = result.parameters.fields.num.numberValue;
  184. state = 'answer';
  185. handleQuestion();
  186. break;
  187. case FALLBACK_INTENT:
  188. // if (state === 'answer') {
  189. // handleAnswer(result.queryText)
  190. // }
  191. break;
  192. default:
  193. break;
  194. }
  195. }
  196. // #region question handling
  197. function startQuestion (number) {
  198. question = number;
  199. state = 'answer';
  200. handleQuestion();
  201. }
  202. function handleQuestion () {
  203. switch (question) {
  204. case 1:
  205. skipRecording = true;
  206. speak(QUESTION_ONE);
  207. readQuestionOne();
  208. break;
  209. case 2:
  210. readQuestionTwo();
  211. break;
  212. case 3:
  213. readQuestionThree();
  214. break;
  215. case 4:
  216. break;
  217. case 5:
  218. break;
  219. }
  220. }
  221. function readQuestionOne () {
  222. for (let i = 0; i < QUESTION_ONE_QUESTIONS.length; i++) {
  223. let utterance = new SpeechSynthesisUtterance();
  224. utterance.voice = voices[2];
  225. utterance.rate = 0.75;
  226. utterance.text = QUESTION_ONE_QUESTIONS[i];
  227. window.speechSynthesis.speak(utterance);
  228. if (i === 9) {
  229. utterance.onend = function (event) {
  230. recognition.start();
  231. console.log('reocgnition started. Question: ' + question);
  232. };
  233. }
  234. }
  235. }
  236. function readQuestionTwo () {
  237. let utterance = new SpeechSynthesisUtterance();
  238. utterance.voice = voices[2];
  239. utterance.text = QUESTION_TWO;
  240. window.speechSynthesis.speak(utterance);
  241. utterance.onend = function (event) {
  242. window.setTimeout(
  243. function () {
  244. recognition.stop();
  245. console.log('recognition stopped');
  246. handleAnswer(answerQuery);
  247. }, 6000);
  248. recognition.start();
  249. console.log('reocgnition started. Question: ' + question);
  250. };
  251. }
  252. function readQuestionThree () {
  253. skipRecording = true;
  254. speak('Dankeschön, weiter geht es mit der nächsten Frage.');
  255. let utterance = new SpeechSynthesisUtterance();
  256. utterance.voice = voices[2];
  257. utterance.text = QUESTION_THREE;
  258. window.speechSynthesis.speak(utterance);
  259. utterance.onend = function (event) {
  260. speak(QUESTION_THREE_QUESTIONS_PT1[questionThreeCount]);
  261. };
  262. utterance.onerror = function (event) {
  263. console.log('An error has occurred with the speech synthesis: ' + event.error);
  264. };
  265. }
  266. function handleAnswer (query) {
  267. switch (question) {
  268. case 1:
  269. handleAnswerToFirstQuestion(query);
  270. break;
  271. case 2:
  272. handleAnswerToSecondQuestion(query);
  273. break;
  274. case 3:
  275. handleAnswerToThirdQuestion(query);
  276. break;
  277. case 4:
  278. break;
  279. case 5:
  280. break;
  281. }
  282. }
  283. function handleAnswerToFirstQuestion (answer) {
  284. var tokens = answer.split(new RegExp(separators.join('|'), 'g'));
  285. questionPoints[question] += calculatePoints(tokens, QUESTION_ONE_ANSWERS);
  286. if (partTwo) {
  287. partTwo = false;
  288. console.log('question 1 points: ' + questionPoints[question]);
  289. skipRecording = true;
  290. speak('Vielen Dank, nun geht es weiter mit der nächsten Frage');
  291. startQuestion(2);
  292. // state = 'detect'
  293. } else {
  294. rePrompt = false;
  295. skipRecording = true;
  296. speak(QUESTION_ONE_PT2);
  297. readQuestionOne(QUESTION_ONE);
  298. partTwo = true;
  299. }
  300. }
  301. function handleAnswerToSecondQuestion (answer) {
  302. var tokens = answer.split(new RegExp(separators.join('|'), 'g'));
  303. questionPoints[question] = calculatePoints(tokens, QUESTION_TWO_ANSWERS);
  304. console.log('question 2 points: ' + questionPoints[question]);
  305. startQuestion(3);
  306. // state = 'detect'
  307. }
  308. function handleAnswerToThirdQuestion (query) {
  309. speechsynth.rate = 0.87;
  310. query = query.replace(' ', '');
  311. let answerArray;
  312. let questionArray;
  313. if (!partTwo) {
  314. answerArray = QUESTION_THREE_ANSWERS_PT1;
  315. } else {
  316. answerArray = QUESTION_THREE_ANSWERS_PT2;
  317. }
  318. if (query === answerArray[questionThreeCount]) {
  319. strike = 0;
  320. partTwo = false;
  321. questionThreeCount++;
  322. questionPoints[question] = questionThreeCount + 1;
  323. questionArray = QUESTION_THREE_QUESTIONS_PT1;
  324. } else {
  325. strike++;
  326. partTwo = true;
  327. questionArray = QUESTION_THREE_QUESTIONS_PT2;
  328. }
  329. if (strike === 2 || questionThreeCount === 5) {
  330. speechsynth.rate = 1;
  331. console.log('question 3 points: ' + questionPoints[question]);
  332. skipRecording = true;
  333. speak('weiter geht es mit der Nächsten Frage');
  334. startQuestion(4);
  335. return;
  336. }
  337. speak(questionArray[questionThreeCount]);
  338. console.log('count: ' + questionThreeCount + ', strike: ' + strike + ', points: ' + questionPoints[question]);
  339. }
  340. // #endregion
  341. // #region global functions
  342. function startDemenzScreening () {
  343. ws.send('starte demenz test');
  344. // startQuestion(2);
  345. testBtn.disabled = true;
  346. testBtn.textContent = 'Test in progress';
  347. infoPara.textContent = 'wait...';
  348. diagnosticPara.textContent = 'detecting...';
  349. }
  350. function speak (sentence) {
  351. speechsynth.text = sentence;
  352. window.speechSynthesis.speak(speechsynth);
  353. }
  354. function testSpeechOut () {
  355. answerQuery = 'apfel wiese tisch apfel lampe pferd';
  356. question = 1;
  357. for (let i = 0; i < 2; i++) {
  358. var tokens = answerQuery.split(new RegExp(separators.join('|'), 'g'));
  359. questionPoints[question] += calculatePoints(tokens, QUESTION_ONE_ANSWERS);
  360. }
  361. console.log(questionPoints[question]);
  362. // speechsynth.text = 'test 123';
  363. // speechsynth.volume = 1;
  364. // speechsynth.rate = 1;
  365. // console.log(speechsynth);
  366. // window.speechSynthesis.speak(speechsynth);
  367. // console.log(window.speechSynthesis);
  368. }
  369. // function recognizeSpeech () {
  370. // if (state === 'answer') {
  371. // var arr;
  372. // switch (question) {
  373. // case 1:
  374. // arr = QUESTION_ONE_QUESTIONS;
  375. // break;
  376. // case 2:
  377. // // arr = QUESTION_TWO_QUESTIONS;
  378. // break;
  379. // case 3:
  380. // arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
  381. // break;
  382. // case 4:
  383. // break;
  384. // case 5:
  385. // break;
  386. // }
  387. // // var grammar = '#JSGF V1.0; grammar colors; public <color> = ' + arr.join(' | ') + ' ;';
  388. // // var speechRecognitionList = new SpeechGrammarList();
  389. // // speechRecognitionList.addFromString(grammar, 1);
  390. // // recognition.grammars = speechRecognitionList;
  391. // }
  392. recognition.onresult = function (event) {
  393. var last = event.results.length - 1;
  394. var speechResult = event.results[last][0].transcript.toLowerCase();
  395. diagnosticPara.textContent += speechResult + ' ';
  396. // console.log('Confidence: ' + event.results[0][0].confidence)
  397. console.log('process: ' + speechResult);
  398. processSpeech(speechResult);
  399. // testBtn.disabled = false
  400. // testBtn.textContent = 'record...'
  401. };
  402. function processSpeech (speechResult) {
  403. console.log('To dialogflow: ' + speechResult);
  404. ws.send(speechResult);
  405. let timeOut;
  406. switch (question) {
  407. case 1:
  408. timeOut = 6500;
  409. break;
  410. case 2:
  411. answerQuery += speechResult;
  412. return;
  413. case 3:
  414. if (speechResult.includes('uhr')) {
  415. speechResult = speechResult.replace('uhr', '');
  416. }
  417. timeOut = 6500;
  418. break;
  419. case 4:
  420. break;
  421. case 5:
  422. timeOut = 6500;
  423. break;
  424. }
  425. if (state === 'answer') {
  426. if (timerId != undefined) {
  427. clearTimeout(timerId);
  428. }
  429. answerQuery += speechResult;
  430. timerId = window.setTimeout(
  431. function () {
  432. // if (!rePrompt) {
  433. // ws.send('ich brauche noch etwas Zeit')
  434. // } else {
  435. console.log('recording end. Evaluate: ' + answerQuery);
  436. handleAnswer(answerQuery);
  437. answerQuery = '';
  438. diagnosticPara.textContent = '';
  439. // }
  440. recognition.stop();
  441. console.log('timer fallback');
  442. }, timeOut);
  443. } else {
  444. console.log('recording end.');
  445. recognition.stop();
  446. }
  447. }
  448. // #region speech recognition event
  449. recognition.onspeechend = function () {
  450. // recognition.stop();
  451. // testBtn.disabled = false;
  452. // testBtn.textContent = 'Start new test';
  453. };
  454. recognition.onerror = function (event) {
  455. testBtn.disabled = false;
  456. testBtn.textContent = 'Start new test';
  457. diagnosticPara.textContent = 'Error occurred in recognition: ' + event.error;
  458. };
  459. recognition.onaudiostart = function (event) {
  460. // Fired when the user agent has started to capture audio.
  461. };
  462. recognition.onaudioend = function (event) {
  463. };
  464. recognition.onend = function (event) {
  465. // Fired when the speech recognition service has disconnected.
  466. };
  467. recognition.onnomatch = function (event) {
  468. // Fired when the speech recognition service returns a final result with no significant recognition. This may involve some degree of recognition, which doesn't meet or exceed the confidence threshold.
  469. // console.log('SpeechRecognition.onnomatch')
  470. };
  471. recognition.onsoundstart = function (event) {
  472. // Fired when any sound — recognisable speech or not — has been detected.
  473. };
  474. recognition.onsoundend = function (event) {
  475. // Fired when any sound — recognisable speech or not — has stopped being detected.
  476. };
  477. recognition.onspeechstart = function (event) {
  478. // Fired when sound that is recognised by the speech recognition service as speech has been detected.
  479. };
  480. recognition.onstart = function (event) {
  481. // Fired when the speech recognition service has begun listening to incoming audio with intent to recognize grammars associated with the current SpeechRecognition.
  482. };
  483. // }
  484. // #endregion
  485. function calculatePoints (tokens, d) {
  486. let points = 0;
  487. let dict = {};
  488. Object.assign(dict, d);
  489. for (let word of tokens) {
  490. if (dict[word] !== undefined) {
  491. points += dict[word];
  492. delete dict[word];
  493. }
  494. }
  495. return points;
  496. }
  497. // #endregion
  498. testBtn.addEventListener('click', startDemenzScreening);
  499. testBtn2.addEventListener('click', testSpeechOut);