2 * Copyright 2017 Samsung Electronics Co., Ltd.
4 * Licensed under the Flora License, Version 1.1 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://floralicense.org/license/
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 * This source code is a language specified script for Korean(ko_KR).
21 * If there is no script for some language, this script is loaded as default.
25 * vc_search_word function found the text with similarity calculated using words in the @param.
27 * @param param param from voice-control.
28 * @param replace If replace true, function correct some confused charaters and try again.
30 function vc_search_word(param, replace) {
31 /* phase 2. search partial word in the webpage */
32 /* second, compare with links in html documents */
33 if (vc_flag_log == true) {
34 vc_rec_result.style.background = 'rgba(0, 100, 200, 1)';
36 var resultTokenArr = param.split(' ');
37 var threshold = resultTokenArr.length * 0.3;
41 vc_print_log('=== start vc_search_word');
43 for (var i = 0; i < document.links.length; ++i) {
44 var text = document.links[i].textContent.replace(/[`~!‘’@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '');
45 text = text.replace(/ /g, '').toLowerCase();
48 for (var j = 0; j < resultTokenArr.length; j++) {
49 if (vc_is_visible(document.links[i], vc_scr, true) && text.indexOf(resultTokenArr[j].toLowerCase()) != -1) {
57 for (var i = 0; i < document.links.length; i++) {
58 if (temp[i] >= threshold && (max == -1 || temp[i] > temp[max])) {
59 el = document.links[i];
64 if (el != undefined) {
68 /* first, compare with whole text of elements in html documents */
70 for (var i = 0; i < resultTokenArr.length; i++) {
71 var obj = vc_selector([resultTokenArr[i]]);
72 for (var j = 0; j < obj.length; j++) {
74 if (temp.childElementCount === 0) {
75 if (temp.hasAttribute('vc_count') == false) {
76 temp.setAttribute('vc_count', 1);
79 temp.setAttribute('vc_count', parseInt(temp.getAttribute('vc_count')) + 1);
85 for (var i = 0; i < result.length; i++) {
86 var vccnt = parseInt(result[i].getAttribute('vc_count'));
87 if (vccnt >= threshold && (el == undefined || vccnt > parseInt(el.getAttribute('vc_count')))) {
92 for (var i = 0; i < result.length; i++) {
93 result[i].removeAttribute('vc_count');
96 if (el != undefined) {
100 if (replace == true) {
101 var rep = param.replace('이 ', '의 ');
102 el = vc_search_word(rep, false);
103 if (el != undefined) return el;
105 rep = param.replace('으 ', '이 ');
106 el = vc_search_word(rep, false);
107 if (el != undefined) return el;
109 rep = param.replace('에 ', '의 ');
110 el = vc_search_word(rep, false);
111 if (el != undefined) return el;
113 rep = param.replace('의 ', '에 ');
114 el = vc_search_word(rep, false);
115 if (el != undefined) return el;
118 return vc_search_character(param);
122 * vc_search_word function found the text with similarity calculated using characters in the @param.
124 * @param param param from voice-control.
126 function vc_search_character(param) {
127 vc_print_log('=== start searching(character level)');
128 if (vc_flag_log == true) {
129 vc_rec_result.style.background = 'rgba(200, 100, 0, 1)';
134 param = param.toLowerCase().split(' ');
135 for (var i = 0; i < vc_all_elem.length; i++) {
136 if (vc_all_elem[i].childElementCount == 0 && vc_is_visible(vc_all_elem[i]) == true) {
137 var text = vc_all_elem[i].textContent.replace(/[`~!‘’@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, ' ').toLowerCase().split(' ');
140 for(var k = 0; k < param.length; k++) {
141 var min = 2147483647;
143 if (3 > param[k].length) {
147 for(var j = 0; j < text.length; j++) {
148 if (3 > text[j].length) {
156 if (text[j].length > param[k].length) {
164 for (var l = 0; l <= longStr.length; l++) {
168 for (var s = 1; s <= shortStr.length; s++) {
171 for (var l = 1; l <= longStr.length; l++) {
172 var match = shortStr[s - 1] == longStr[l - 1] ? 0 : 1;
174 var rep = cost[l - 1] + match;
175 var ins = cost[l] + 1;
176 var del = ncost[l - 1] + 1;
178 ncost[l] = Math.min(rep, ins, del);
186 if (param[k].length * 0.25 >= cost[longStr.length] && min > cost[longStr.length]) {
187 min = cost[longStr.length];
191 if (min < 2147483647) {
194 score = score + param[k].length;
198 similarity.push(score);
200 similarity.push(2147483647);
204 vc_print_log('=== finish searching(character level)');
206 var min = 2147483647;
207 for (var i = 0; i < similarity.length; i++) {
208 if (min > similarity[i]) {
213 for (var i = 0; i < param.length; i++) {
214 if (3 <= param[i].length) {
215 threshold = threshold + param[i].length;
219 if (threshold > min) {
220 return vc_all_elem[similarity.indexOf(min)];
223 return vc_search_pronunciation(param);
227 * vc_search_word function found the text with similarity calculated using pronunciation keys in the @param.
229 * @param param param from voice-control.
231 function vc_convert_to_syllable(param) {
232 var korUnicodeStart = 44032;
233 var korUnicodeNum = 11172;
234 var korUnicodeEnd = 55204;
241 for (var i = 0; i < param.length; i++) {
242 var c = param.charCodeAt(i);
244 if (korUnicodeStart > c || korUnicodeEnd < c) {
248 var jongIdx = (c - korUnicodeStart) % korJongCnt;
249 var jungIdx = (((c - korUnicodeStart) - jongIdx) / korJongCnt) % korJungCnt;
250 var choIdx = ((((c - korUnicodeStart) - jongIdx) / korJongCnt) - jungIdx) / korJungCnt;
252 result.push(choIdx, jungIdx, jongIdx);
259 * vc_search_word function found the text with similarity calculated using pronunciation keys in the @param.
261 * @param param param from voice-control.
263 function vc_search_pronunciation(param) {
264 if (vc_flag_log == true) {
265 vc_rec_result.style.background = 'rgba(220, 0, 0, 1)';
267 if (param.length > 1) {
271 vc_print_log('=== start searching(pronuciation level)');
274 var sylla = vc_convert_to_syllable(param);
275 var threshold = sylla.length * 0.5;
277 var elScore = 2147483247;
279 for (var i = 0; i < vc_all_elem.length; i++) {
280 if (vc_all_elem[i].childElementCount == 0 && vc_is_visible(vc_all_elem[i]) == true) {
281 var text = vc_all_elem[i].textContent.replace(/[`~!‘’@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, ' ').toLowerCase().split(' ');
282 var score = 2147483247;
284 for (var j = 0; j < text.length; j++) {
285 if (param.length > text[j].length) {
288 var min = 2147483247;
290 for (var s = 0; s <= text[j].length - param.length; s++) {
291 var temp = vc_convert_to_syllable(text[j].substr(s, param.length));
294 for (var k = 0; k < sylla.length; k++) {
295 if (sylla[k] != temp[k]) {
299 if (cnt == threshold) {
315 if (threshold > score && elScore > score) {
322 vc_print_log('=== finish searching(pronuciation level)');
324 if (el != undefined) {
332 * vc_is_included_number function separate a number value from the @text.
334 * @param text text string from voice-control-webview.cpp.
336 function vc_is_included_number(text) {
337 var numbers = ['일', '이', '삼', '사', '오', '육', '칠', '팔', '구', '십',
338 '십일', '십이', '십삼', '십사', '십오', '십육', '십칠', '십팔', '십구', '이십',
339 '이십일', '이십이', '이십삼', '이십사', '이십오', '이십육', '이십칠', '이십팔', '이십구', '삼십',
340 '삼십일', '삼십이', '삼십삼', '삼십사', '삼십오', '삼십육', '삼십칠', '삼십팔', '삼십구', '사십',
341 '사십일', '사십이', '사십삼', '사십사', '사십오', '사십육', '사십칠', '사십팔', '사십구', '오십',
342 '오십일', '오십이', '오십삼', '오십사', '오십오', '오십육', '오십칠', '오십팔', '오십구', '육십',
343 '육십일', '육십이', '육십삼', '육십사', '육십오', '육십육', '육십칠', '육십팔', '육십구', '칠십',
344 '칠십일', '칠십이', '칠십삼', '칠십사', '칠십오', '칠십육', '칠십칠', '칠십팔', '칠십구', '팔십',
345 '팔십일', '팔십이', '팔십삼', '팔십사', '팔십오', '팔십육', '팔십칠', '팔십팔', '팔십구', '구십',
346 '구십일', '구십이', '구십삼', '구십사', '구십오', '구십육', '구십칠', '구십팔', '구십구', '백'];
347 var seven = ['채널', '질'];
348 var eight = ['발', '달'];
349 var convert = text.toLowerCase();
352 for (var i = 0; numbers.length > i; i++) {
353 if (true == convert.startsWith(numbers[i]) && (' ' == text[numbers[i].length] || text.length == numbers[i].length)) {
354 var partial = text.substr(numbers[i].length + 1);
357 for (var j = 0; 9 > j; j++) {
358 if (true == partial.toLowerCase().startsWith(numbers[j]) && (' ' == partial[numbers[j].length] || partial.length == numbers[j].length)) {
359 partial = partial.substr(numbers[j].length + 1);
365 if (vc_visible_hints[i - 1].type == 'input' || text.length == numbers[i].length) {
368 param : partial.trim()
375 for (var i = 0; seven.length > i; i++) {
376 if (true == convert.startsWith(seven[i]) && (' ' == text[seven[i].length] || text.length == seven[i].length) && (vc_visible_hints[6].type == 'input' || text.length == seven[i].length)) {
379 param : text.substr(seven[i].length + 1).trim()
385 for (var i = 0; eight.length > i; i++) {
386 if (true == convert.startsWith(eight[i]) && (' ' == text[eight[i].length] || text.length == eight[i].length) && (vc_visible_hints[7].type == 'input' || text.length == eight[i].length)) {
389 param : text.substr(eight[i].length + 1).trim()
403 * vc_correct_parameter function correct the voice recognition result.
405 * @param text text string from voice-control-webview.cpp.
407 function vc_correct_parameter(text) {
408 var result = vc_is_included_number(text);
410 /* if param is a number, move the value in param to cmd */
411 var words = result.param.split(' ');
412 if (isNaN(result.cmd) == true && isNaN(words[0]) == false) {
413 result.cmd = parseFloat(words[0]);
414 result.param = result.param.substr(words[0].length + 1).trim();
417 var idx_sep = result.param.indexOf('번 ');
418 if (isNaN(result.cmd) == true && 0 < idx_sep) {
419 if (idx_sep == result.param.length - 1) {
420 result.cmd = parseFloat(result.param.substr(0, idx_sep));
423 result.cmd = parseFloat(result.param.substr(0, idx_sep));
424 result.param = result.param.substr(idx_sep + 2, result.param.length);
432 * vc_check_web_control function check some special keyword and run it.
434 * @param spokenWord voice recognized result string.
436 function vc_check_web_control(text) {
437 text = text.toLowerCase();
438 var convert = text.replace(/ /g, '');
439 var googleSearch = '구글 검색';
440 var naverSearch = '네이버 검색';
441 var youtubeSearch = '유튜브 검색';
442 var googleSearch2 = '구글 ';
443 var naverSearch2 = '네이버 ';
444 var youtubeSearch2 = '유튜브 ';
446 if (text.startsWith(googleSearch) == true) {
447 location.href = 'https://www.google.co.kr/search?q=' + (text.substr(googleSearch.length)).trim();
448 } else if (text.startsWith(naverSearch) == true) {
449 location.href = 'https://search.naver.com/search.naver?where=nexearch&query=' + (text.substr(naverSearch.length)).trim();
450 } else if (text.startsWith(youtubeSearch) == true) {
451 location.href = 'https://www.youtube.com/results?search_query=' + (text.substr(youtubeSearch.length)).trim();
452 } else if (convert == '유튜브TV') {
453 location.href = 'https://www.youtube.com/tv';
454 } else if (text.startsWith(googleSearch2) == true) {
455 location.href = 'https://www.google.co.kr/search?q=' + (text.substr(googleSearch2.length)).trim();
456 } else if (text.startsWith(naverSearch2) == true) {
457 location.href = 'https://search.naver.com/search.naver?where=nexearch&query=' + (text.substr(naverSearch2.length)).trim();
458 } else if (text.startsWith(youtubeSearch2) == true) {
459 location.href = 'https://www.youtube.com/results?search_query=' + (text.substr(youtubeSearch2.length)).trim();
460 } else if (convert.startsWith('구글') == true) {
461 location.href = 'https://www.google.co.kr/';
462 } else if (convert.startsWith('네이버') == true) {
463 location.href = 'http://www.naver.com/';
464 } else if (convert.startsWith('유튜브') == true) {
465 location.href = 'https://www.youtube.com/';
466 } else if (convert == '취소') {
468 } else if (convert == '리프레쉬' || convert == '새로고침') {
470 } else if (convert == '아래로' || convert == '내려' || convert == '내려봐' || convert == '내려줘') {
471 vc_scroll_event_firing('DOWN');
472 } else if (convert == '위로' || convert == '올려' || convert == '올려봐' || convert == '올려줘') {
473 vc_scroll_event_firing('UP');
474 } else if (convert == '맨위로' || convert == '처음으로') {
475 vc_scroll_event_firing('TOP');
476 } else if (convert == '광고닫기' || convert == '광고찾기') {
477 document.querySelector('.videoAdUiSkipButton').click();
478 } else if (convert == '소스보기') {
480 } else if (convert == '다음페이지' || convert == '다음으로' || convert == '앞으로가기' || convert == '앞으로') {
482 } else if (convert == '이전페이지' || convert == '이전으로' || convert == '뒤로가기' || convert == '뒤로' || convert == '백' || convert == '벡') {
484 } else if (convert == '로그보기' && vc_flag_log) {
485 if (vc_log_area.style.visibility == 'visible') vc_log_area.style.visibility = 'hidden';
486 else vc_log_area.style.visibility = 'visible';