Libraryless. Click here for Pure Java version (1116L/12K/37K).
1 | !752 |
2 | |
3 | static S logName = "log"; |
4 | static S voice = "William"; |
5 | |
6 | static S html(S uri, Map<S, S> params) { |
7 | if (eq(uri, "/has-speech")) { |
8 | S s = params.get("q"); |
9 | |
10 | logMap(logName, "time", now(), "heard", s); |
11 | |
12 | S text = getAnswer(s); |
13 | if (empty(text)) ret ""; |
14 | S soundURL = getSoundURLCereproc(text, voice); |
15 | S html = [[ |
16 | <audio controls autoplay> |
17 | <source src="SRC" type="audio/mpeg"> |
18 | ! Kein Ton im Browser ! |
19 | </audio> |
20 | ]]; |
21 | html = html.replace("SRC", htmlencode(soundURL)); |
22 | |
23 | logMap(logName, "time", now(), "saying", text); |
24 | |
25 | ret "Speech: " + tag("span", htmlencode(text), "style", "font-size: 20px") + "<br>" |
26 | + html; |
27 | } |
28 | |
29 | if (eq(uri, "/empty")) { |
30 | ret ""; |
31 | } |
32 | |
33 | if (eq(uri, "/upper")) { |
34 | S html = [=[ |
35 | <!DOCTYPE html> |
36 | <meta charset="utf-8"> |
37 | <title>TinyBrain Speech Demo</title> |
38 | <style> |
39 | * { |
40 | font-family: Verdana, Arial, sans-serif; |
41 | } |
42 | a:link { |
43 | color:#000; |
44 | text-decoration: none; |
45 | } |
46 | a:visited { |
47 | color:#000; |
48 | } |
49 | a:hover { |
50 | color:#33F; |
51 | } |
52 | .button { |
53 | background: -webkit-linear-gradient(top,#008dfd 0,#0370ea 100%); |
54 | border: 1px solid #076bd2; |
55 | border-radius: 3px; |
56 | color: #fff; |
57 | display: none; |
58 | font-size: 13px; |
59 | font-weight: bold; |
60 | line-height: 1.3; |
61 | padding: 8px 25px; |
62 | text-align: center; |
63 | text-shadow: 1px 1px 1px #076bd2; |
64 | letter-spacing: normal; |
65 | } |
66 | .center { |
67 | padding: 10px; |
68 | text-align: center; |
69 | } |
70 | .final { |
71 | color: black; |
72 | padding-right: 3px; |
73 | } |
74 | .interim { |
75 | color: gray; |
76 | } |
77 | .info { |
78 | font-size: 34px; |
79 | text-align: center; |
80 | color: #777; |
81 | display: none; |
82 | } |
83 | .right { |
84 | float: right; |
85 | } |
86 | .sidebyside { |
87 | display: inline-block; |
88 | width: 45%; |
89 | min-height: 40px; |
90 | text-align: left; |
91 | vertical-align: top; |
92 | } |
93 | #headline { |
94 | font-size: 80px; |
95 | font-weight: 300; |
96 | } |
97 | #info { |
98 | font-size: 50px; |
99 | text-align: center; |
100 | color: #777; |
101 | visibility: hidden; |
102 | } |
103 | #results { |
104 | font-size: 55px; |
105 | font-weight: bold; |
106 | border: 1px solid #ddd; |
107 | padding: 15px; |
108 | text-align: left; |
109 | min-height: 50px; |
110 | } |
111 | #start_button { |
112 | border: 0; background-color:transparent; |
113 | padding: 0; |
114 | } |
115 | </style> |
116 | |
117 | <div id="info"> |
118 | <p id="info_start">Click on the microphone icon and begin speaking.</p> |
119 | <p id="info_speak_now">Speak after the bleep.</p> |
120 | <p id="info_no_speech">No speech was detected</p> |
121 | <p id="info_no_microphone" style="display:none"> |
122 | No microphone was found. Ensure that a microphone is installed and that |
123 | <a href="//support.google.com/chrome/bin/answer.py?hl=en&answer=1407892"> |
124 | microphone settings</a> are configured correctly.</p> |
125 | <p id="info_allow">Click the "Allow" button.</p> |
126 | <p id="info_denied">Permission to use microphone was denied.</p> |
127 | <p id="info_blocked">Permission to use microphone is blocked. To change, |
128 | go to chrome://settings/contentExceptions#media-stream</p> |
129 | <p id="info_upgrade">Web Speech API is not supported by this browser. |
130 | Upgrade to <a href="//www.google.com/chrome">Chrome</a> |
131 | version 25 or later.</p> |
132 | </div> |
133 | <div class="right"> |
134 | <button id="start_button" onclick="startButton(event)"> |
135 | <img id="start_img" src="http://tinybrain.de:8080/speech/mic.gif" width="120" alt="Start"></button> |
136 | </div> |
137 | <div id="results"> |
138 | <span id="final_span" class="final"></span> |
139 | <span id="interim_span" class="interim"></span> |
140 | <p> |
141 | </div> |
142 | <div class="center"> |
143 | <p> |
144 | <div id="div_language"> |
145 | <?= $mode ?> |
146 | |
147 | <select id="select_language" onchange="updateCountry()"></select> |
148 | |
149 | <select id="select_dialect"></select> |
150 | </div> |
151 | </div> |
152 | <script> |
153 | var langs = |
154 | [['Afrikaans', ['af-ZA']], |
155 | ['Bahasa Indonesia',['id-ID']], |
156 | ['Bahasa Melayu', ['ms-MY']], |
157 | ['Català', ['ca-ES']], |
158 | ['?eština', ['cs-CZ']], |
159 | ['Deutsch', ['de-DE']], |
160 | ['English', ['en-AU', 'Australia'], |
161 | ['en-CA', 'Canada'], |
162 | ['en-IN', 'India'], |
163 | ['en-NZ', 'New Zealand'], |
164 | ['en-ZA', 'South Africa'], |
165 | ['en-GB', 'United Kingdom'], |
166 | ['en-US', 'United States']], |
167 | ['Español', ['es-AR', 'Argentina'], |
168 | ['es-BO', 'Bolivia'], |
169 | ['es-CL', 'Chile'], |
170 | ['es-CO', 'Colombia'], |
171 | ['es-CR', 'Costa Rica'], |
172 | ['es-EC', 'Ecuador'], |
173 | ['es-SV', 'El Salvador'], |
174 | ['es-ES', 'España'], |
175 | ['es-US', 'Estados Unidos'], |
176 | ['es-GT', 'Guatemala'], |
177 | ['es-HN', 'Honduras'], |
178 | ['es-MX', 'México'], |
179 | ['es-NI', 'Nicaragua'], |
180 | ['es-PA', 'Panamá'], |
181 | ['es-PY', 'Paraguay'], |
182 | ['es-PE', 'Perú'], |
183 | ['es-PR', 'Puerto Rico'], |
184 | ['es-DO', 'República Dominicana'], |
185 | ['es-UY', 'Uruguay'], |
186 | ['es-VE', 'Venezuela']], |
187 | ['Euskara', ['eu-ES']], |
188 | ['Français', ['fr-FR']], |
189 | ['Galego', ['gl-ES']], |
190 | ['Hrvatski', ['hr_HR']], |
191 | ['IsiZulu', ['zu-ZA']], |
192 | ['Íslenska', ['is-IS']], |
193 | ['Italiano', ['it-IT', 'Italia'], |
194 | ['it-CH', 'Svizzera']], |
195 | ['Magyar', ['hu-HU']], |
196 | ['Nederlands', ['nl-NL']], |
197 | ['Norsk bokmål', ['nb-NO']], |
198 | ['Polski', ['pl-PL']], |
199 | ['Português', ['pt-BR', 'Brasil'], |
200 | ['pt-PT', 'Portugal']], |
201 | ['Român?', ['ro-RO']], |
202 | ['Sloven?ina', ['sk-SK']], |
203 | ['Suomi', ['fi-FI']], |
204 | ['Svenska', ['sv-SE']], |
205 | ['Türkçe', ['tr-TR']], |
206 | ['?????????', ['bg-BG']], |
207 | ['P??????', ['ru-RU']], |
208 | ['??????', ['sr-RS']], |
209 | ['???', ['ko-KR']], |
210 | ['??', ['cmn-Hans-CN', '??? (????)'], |
211 | ['cmn-Hans-HK', '??? (??)'], |
212 | ['cmn-Hant-TW', '?? (??)'], |
213 | ['yue-Hant-HK', '?? (??)']], |
214 | ['???', ['ja-JP']], |
215 | ['Lingua lat?na', ['la']]]; |
216 | |
217 | for (var i = 0; i < langs.length; i++) { |
218 | select_language.options[i] = new Option(langs[i][0], i); |
219 | } |
220 | |
221 | // 5 = German, 6 = English |
222 | select_language.selectedIndex = 6; |
223 | updateCountry(); |
224 | select_dialect.selectedIndex = 6; |
225 | showInfo('info_start'); |
226 | |
227 | function updateCountry() { |
228 | for (var i = select_dialect.options.length - 1; i >= 0; i--) { |
229 | select_dialect.remove(i); |
230 | } |
231 | var list = langs[select_language.selectedIndex]; |
232 | for (var i = 1; i < list.length; i++) { |
233 | select_dialect.options.add(new Option(list[i][1], list[i][0])); |
234 | } |
235 | select_dialect.style.visibility = list[1].length == 1 ? 'hidden' : 'visible'; |
236 | } |
237 | |
238 | var final_transcript = ''; |
239 | var recognizing = false; |
240 | var ignore_onend; |
241 | var ignore_result; |
242 | var start_timestamp; |
243 | if (!('webkitSpeechRecognition' in window)) { |
244 | upgrade(); |
245 | } else { |
246 | var contentFrame = parent.contentframe; |
247 | var lastText = ""; |
248 | |
249 | start_button.style.display = 'inline-block'; |
250 | var recognition = new webkitSpeechRecognition(); |
251 | recognition.continuous = true; |
252 | recognition.interimResults = false; |
253 | |
254 | recognition.onstart = function() { |
255 | recognizing = true; |
256 | showInfo('info_speak_now'); |
257 | start_img.src = 'http://tinybrain.de:8080/speech/mic-animate.gif'; |
258 | }; |
259 | |
260 | recognition.onerror = function(event) { |
261 | if (event.error == 'no-speech') { |
262 | start_img.src = 'http://tinybrain.de:8080/speech/mic.gif'; |
263 | showInfo('info_no_speech'); |
264 | ignore_onend = true; |
265 | } |
266 | if (event.error == 'audio-capture') { |
267 | start_img.src = 'http://tinybrain.de:8080/speech/mic.gif'; |
268 | showInfo('info_no_microphone'); |
269 | ignore_onend = true; |
270 | } |
271 | if (event.error == 'not-allowed') { |
272 | if (event.timeStamp - start_timestamp < 100) { |
273 | showInfo('info_blocked'); |
274 | } else { |
275 | showInfo('info_denied'); |
276 | } |
277 | ignore_onend = true; |
278 | } |
279 | }; |
280 | |
281 | recognition.onend = function() { |
282 | recognizing = false; |
283 | if (ignore_onend) { |
284 | return; |
285 | } |
286 | start_img.src = 'http://tinybrain.de:8080/speech/mic.gif'; |
287 | |
288 | //final_transcript = ""; // DEH HACK |
289 | |
290 | if (!final_transcript) { |
291 | showInfo('info_start'); |
292 | return; |
293 | } |
294 | showInfo(''); |
295 | if (window.getSelection) { |
296 | window.getSelection().removeAllRanges(); |
297 | var range = document.createRange(); |
298 | range.selectNode(document.getElementById('final_span')); |
299 | window.getSelection().addRange(range); |
300 | } |
301 | }; |
302 | |
303 | recognition.onresult = function(event) { |
304 | var interim_transcript = ''; |
305 | if (ignore_result) { |
306 | ignore_result = false; |
307 | return; |
308 | } |
309 | for (var i = event.resultIndex; i < event.results.length; ++i) { |
310 | if (event.results[i].isFinal) { |
311 | var newData = event.results[i][0].transcript; |
312 | //final_transcript += newData; |
313 | final_transcript = newData; |
314 | var frameURL = "LINK/has-speech?q=" + encodeURIComponent(newData); |
315 | if (contentFrame && lastText != newData) { |
316 | lastText = newData; |
317 | contentFrame.location.href = frameURL; |
318 | } |
319 | } else { |
320 | interim_transcript += event.results[i][0].transcript; |
321 | } |
322 | } |
323 | final_transcript = capitalize(final_transcript); |
324 | final_span.innerHTML = linebreak(final_transcript); |
325 | interim_span.innerHTML = linebreak(interim_transcript); |
326 | if (/*final_transcript ||*/ interim_transcript) { |
327 | showButtons('inline-block'); |
328 | } |
329 | }; |
330 | |
331 | startRecognition(); |
332 | } |
333 | |
334 | function upgrade() { |
335 | start_button.style.visibility = 'hidden'; |
336 | showInfo('info_upgrade'); |
337 | } |
338 | |
339 | var two_line = /\n\n/g; |
340 | var one_line = /\n/g; |
341 | function linebreak(s) { |
342 | return s.replace(two_line, '<p></p>').replace(one_line, '<br>'); |
343 | } |
344 | |
345 | var first_char = /\S/; |
346 | function capitalize(s) { |
347 | return s.replace(first_char, function(m) { return m.toUpperCase(); }); |
348 | } |
349 | |
350 | function copyButton() { |
351 | if (recognizing) { |
352 | recognizing = false; |
353 | recognition.stop(); |
354 | } |
355 | copy_button.style.display = 'none'; |
356 | copy_info.style.display = 'inline-block'; |
357 | showInfo(''); |
358 | } |
359 | |
360 | function startButton(event) { |
361 | startRecognition(); |
362 | } |
363 | |
364 | function startRecognition() { |
365 | if (recognizing) { |
366 | recognition.stop(); |
367 | ignore_result = true; |
368 | return; |
369 | } |
370 | final_transcript = ''; |
371 | recognition.lang = select_dialect.value; |
372 | recognition.start(); |
373 | ignore_onend = false; |
374 | final_span.innerHTML = ''; |
375 | interim_span.innerHTML = ''; |
376 | start_img.src = 'http://tinybrain.de:8080/speech/mic-slash.gif'; |
377 | showInfo('info_allow'); |
378 | showButtons('none'); |
379 | start_timestamp = event.timeStamp; |
380 | } |
381 | |
382 | function showInfo(s) { |
383 | if (s) { |
384 | for (var child = info.firstChild; child; child = child.nextSibling) { |
385 | if (child.style) { |
386 | child.style.display = child.id == s ? 'inline' : 'none'; |
387 | } |
388 | } |
389 | info.style.visibility = 'visible'; |
390 | } else { |
391 | info.style.visibility = 'hidden'; |
392 | } |
393 | } |
394 | |
395 | var current_style; |
396 | function showButtons(style) { |
397 | if (style == current_style) { |
398 | return; |
399 | } |
400 | current_style = style; |
401 | copy_button.style.display = style; |
402 | copy_info.style.display = 'none'; |
403 | } |
404 | </script> |
405 | ]=]; |
406 | ret render(html); |
407 | } |
408 | |
409 | // frame set |
410 | |
411 | ret render([[ |
412 | <title>Pivo Talks To Itself</title> |
413 | |
414 | <frameset rows="280,*"> |
415 | <frame src="LINK/upper"></frame> |
416 | <frame name="contentframe" src="LINK/empty"></frame> |
417 | </frameset> |
418 | ]]); |
419 | } |
420 | |
421 | static S render(S html) { |
422 | ret html.replace("LINK/", rawLink("")); |
423 | } |
424 | |
425 | static S getAnswer(S s) { |
426 | ret "Yes " + s; |
427 | } |
Began life as a copy of #1002938
download show line numbers debug dex old transpilations
Travelled to 14 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pnmttuucjkfb, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1002940 |
Snippet name: | Pivo Bot Talks To Itself Test |
Eternal ID of this version: | #1002940/1 |
Text MD5: | 582f8871734e688566f8625ddd94dc4a |
Transpilation MD5: | 6f63e1fa30e24c1e807fdea5d27e5c03 |
Author: | stefan |
Category: | javax |
Type: | JavaX source code |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2016-04-10 15:39:07 |
Source code size: | 11866 bytes / 427 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 845 / 1057 |
Referenced in: | [show references] |