Adding voice-based search to a PhoneGap app

16

[춢처] http://www.raymondcamden.com/index.cfm/2011/12/2/Adding-voicebased-search-to-a-PhoneGap-app

Posted in Mobile, jQuery, JavaScript | Posted on 12-02-2011 | 3,805 views

A few weeks back I blogged about plugins under PhoneGap. If you haven't read that blog entry, take a quick look at it. For the most part, plugins in PhoneGap are pretty simple. Download a Java file. Download a JavaScript file. Make one tweak to an XML file and you're good to go. In that entry I made use of the SpeechRecognizer plugin for Android. Since that blog entry was kind of a joke (ok, most of my blog entries contain code that is a kind of a joke - but let's forget about that for a moment), I thought it might be nice to demonstrate a more real world use for the plugin. With that in mind here's a simple application built without and with speech recognition.

I began with a simple idea - an application that would allow you to quickly search for images. Turns out the Google Image API is deprecated, but Bing still has a valid API. Not only that, it works really well! About the only weird thing i had with the API was Microsoft's... unusual... capitalization of stuff. That being said, it didn't take long to build up a simple form and tie it to their API. Here is the HTML for the page.

<iframe style="WIDTH: 0px; DISPLAY: inline; HEIGHT: 0px" id="print_frame_94E1D4127AFB03DD1B0AE5DA0DFA9A0F" frameborder="0"></iframe> 1<!DOCTYPE HTML>
2<html>
3<head>
4
5<meta name="viewport" content="width=320; user-scalable=no" />
6<meta http-equiv="Content-type" content="text/html; charset=utf-8">
7<title>PhoneGap</title>
8<script type="text/_javascript" charset="utf-8" src="js/phonegap-1.2.0.js"></script>
9<script type="text/_javascript" charset="utf=8" src="js/jquery-1.7.min.js"></script>
10<script type="text/_javascript" charset="utf=8" src="js/main.js"></script>
11<style>
12input {
13 width:100%;
14 padding: 10px;
15}
16
17img {
18 display:block;
19 margin-left:auto;
20 margin-right:auto;
21}
22p {
23 display:block;
24 margin-left:auto;
25 margin-right:auto;
26 width: 80%;
27}
28</style>
29</head>
30
31<body onload="init()">
32
33<input type="search" id="searchField" value="star wars">
34<input type="button" id="searchButton" value="Search">
35
36<div id="results"></div>
37
38</body>
39</html>

Nothing special there - just a form field and a button. Btw - Pro Tip here - when working on web applications do not be shy about defaulting form fields as I've done above. You get real sick and tired of re-entering text input after you've run your application a few hundred times. Obviously the default value there would be removed before release. Here's a quick shot of how it looks.

Now let's look at the code....

<iframe style="WIDTH: 0px; DISPLAY: inline; HEIGHT: 0px" id="print_frame_15A7DE94A3298EE37B402CDD477F3BA1" frameborder="0"></iframe> 1var appid = "5252D701A7CE4B4F3C190F1403D2181F2C330F2E";
2
3function init() {
4 document.addEventListener("deviceready", deviceready, true);
5}
6
7function deviceready() {
8 console.log('loaded');
9
10 $("#searchButton").bind("touchstart",function() {
11 var s = $.trim($("#searchField").val());
12 console.log("going to search for "+s);
13
14 $.getJSON("http://api.search.live.net/json.aspx?Appid="+appid+"&query="+escape(s)+"&sources=image&image.count=20", {}, function(res) {
15 var results = res.SearchResponse.Image.Results;
16 if(results.length == 0) {
17 $("#results").html("No results!");
18 return;
19}
20 var s = "";
21 for(var i=0; i<results.length; i++) {
22 s+= "<p><img src='"+results[i].Thumbnail.Url+"'><br/><a href='"+results[i].Url+"'>"+results[i].DisplayUrl+"</a></p>";
23}
24 $("#results").html(s);
25});
26
27});
28}

Again - nothing terribly complex here. Bind to the button - check the value - and hit Bing. Here's an example of the result.

Ok, so far so good. So let's add speech recognition! As I said above, there is a process that plugins follow. It involves getting a Java file, a JavaScript file, and editing your plugins.xml file. The SpeechRecognizer page actually  documents this well. Before I go into the code though I ran into a brick wall.

How do I handle the UI?

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

That's a pretty important question, and I won't pretend to know the best answer to this. I decided to add a button to the left of the text field. This way the user could click the button or the text field if they didn't want to use the recognizer. I'm not saying this is the best answer but it seemed to work ok. Here's the updated HTML:

<iframe style="WIDTH: 0px; DISPLAY: inline; HEIGHT: 0px" id="print_frame_9E79018CBB79A6560823EF8596E1C73A" frameborder="0"></iframe> 1<!DOCTYPE HTML>
2<html>
3<head>
4
5<meta name="viewport" content="width=320; user-scalable=no" />
6<meta http-equiv="Content-type" content="text/html; charset=utf-8">
7<title>PhoneGap</title>
8<script type="text/_javascript" charset="utf-8" src="js/phonegap-1.2.0.js"></script>
9<script type="text/_javascript" charset="utf=8" src="js/jquery-1.7.min.js"></script>
10<script type="text/_javascript" charset="utf-8" src="js/SpeechRecognizer.js"></script>
11<script type="text/_javascript" charset="utf=8" src="js/main.js"></script>
12<style>
13#micButton, #searchField {
14 padding: 10px;
15}
16
17input[type=button] {
18 width: 100%;
19}
20
21img {
22 display:block;
23 margin-left:auto;
24 margin-right:auto;
25}
26p {
27 display:block;
28 margin-left:auto;
29 margin-right:auto;
30 width: 80%;
31}
32</style>
33</head>
34
35<body onload="init()">
36
37<button id="micButton" disabled="disabled">SPEAK!</button> <input type="search" id="searchField" value="">
38
39<input type="button" id="searchButton" value="Search">
40
41<div id="results"></div>
42
43</body>
44</html>

And the new UI....

Ok, now let's take a look at the code.

<iframe style="WIDTH: 0px; DISPLAY: inline; HEIGHT: 0px" id="print_frame_C3B7CB998402A80989E79CCD0FC778F4" frameborder="0"></iframe> 1var appid = "5252D701A7CE4B4F3C190F1403D2181F2C330F2E";
2
3function init() {
4 document.addEventListener("deviceready", deviceready, true);
5}
6
7function deviceready() {
8 console.log('loaded');
9
10 window.plugins.speechrecognizer.init(speechInitOk, speechInitFail);
11
12 function speechInitOk() {
13 $("#micButton").removeAttr("disabled");
14}
15
16 function speechInitFail(e) {
17 //Since this isn't critical, we don't care...
18}
19
20 $("#micButton").bind("touchstart", function() {
21 var requestCode = 4815162342;
22 var maxMatches = 1;
23 var promptString = "What do you want?";
24 window.plugins.speechrecognizer.startRecognize(speechOk, speechFail, requestCode, maxMatches, promptString);
25});
26
27 function speechOk(result) {
28 var match, respObj;
29 if (result) {
30 respObj = JSON.parse(result);
31 if (respObj) {
32 var response = respObj.speechMatches.speechMatch[0];
33 $("#searchField").val(response);
34 $("#searchButton").trigger("touchstart");
35}
36}
37}
38
39 function speechFail(m) {
40 navigator.notification.alert;("Sorry, I couldn't recognize you.", function() {}, "Speech Fail");
41}
42
43 $("#searchButton").bind("touchstart",function() {
44 var s = $.trim($("#searchField").val());
45 console.log("going to search for "+s);
46
47 $.getJSON("http://api.search.live.net/json.aspx?Appid="+appid+"&query="+escape(s)+"&sources=image&image.count=20", {}, function(res) {
48 var results = res.SearchResponse.Image.Results;
49 if(results.length == 0) {
50 $("#results").html("No results!");
51 return;
52}
53 var s = "";
54 for(var i=0; i<results.length; i++) {
55 s+= "<p><img src='"+results[i].Thumbnail.Url+"'><br/><a href='"+results[i].Url+"'>"+results[i].DisplayUrl+"</a></p>";
56}
57 $("#results").html(s);
58});
59
60});
61}

So first off, we have to see if we can even do recognition. Therefore I've got a call to init it in my device ready block. If it works, we remove the disabled attribute from the button. The button has an event handler that will fire off the request to the device. The request code is random so don't worry about it too much. Once clicked, the device will prompt you to speak:

In the result handler, we can simply then grab the response object and assume the first result is what we want. Notice I automatically trigger the search. That may or may not be a good idea. You may want the user to have a chance to confirm the recognition first. I thought it was kind of cool to have it automatically search though. Here's an example - and yes - I did say "red banana":

That's it. If you want to play with this, I've included a zip of the Eclipse project. You will find the first draft in the assets folder as "www - Copy". You will also find an APK you can install. Note - I had JDK issues with the SpeechRecognizer Java file. So the version in my zip is slightly edited to get around that.

Download attached file

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
138 [신규] 안드로이드 개발자 등록시 판매자 계정 신청 비활성화 되신 분들 file 가을의 곰을... 2012.05.24 7554
137 소프트웨어 특허출원, 소프트웨어 특허 명세서 작성법 안내 가을의 곰을... 2012.05.14 5474
136 안드로이드 앱에 애드센스 추가하기 가을의 곰을... 2012.05.09 8361
135 특허출원방법 특허청 (hwp문서) 가을의 곰 2012.05.09 5234
134 특허 출원 방법특허출원 방법/ 특허 file 가을의 곰을... 2012.05.09 5318
133 부가가치세(부가세) 인터넷 납부, 홈택스를 통한 납부 방법 file 가을의 곰을... 2012.05.08 6129
132 상표 등록(출원) 혼자서 하기 4편. 출원서 제출과 출원비용 납부하기 file 가을의 곰을... 2012.05.08 5383
131 상표 등록(출원) 혼자서 하기 3편. 서식작성기를 통한 출원서 작성하기 file 가을의 곰을... 2012.05.08 5046
130 상표 등록(출원) 혼자서 하기 2편, 특허청의 인증서 발급과 문서작성 프로그램 설치 file 가을의 곰을... 2012.05.08 6009
129 상표 등록(출원) 혼자서 하기 1편, 특허청에서 상표등록을 위한 출원인코드부여 신청 file 가을의 곰을... 2012.05.08 4810
128 xcode3 과 xcode4 동시에 설치하기 file 가을의 곰을... 2012.05.06 6301
127 [Xcode4] 간편하진 인터페이스빌더 - Outlet, Action 추가/연결 방법 file 가을의 곰을... 2012.05.06 5947
126 xcode3 개발환경에서 xcode4 개발환경으로 이주하기 file 가을의 곰을... 2012.05.06 8502
» 폰갭(phonegap) 에서의 음성인식 웹 검색 file 가을의 곰을... 2012.05.06 4710
124 [책] 내 책을 출판하는 방법, 책 쓰는 방법 file 가을의 곰을... 2012.05.05 4835
123 sourceinsight 환경설정 및 단축키 file 가을의 곰을... 2012.05.01 8371
122 고령자 유망직업 20가지 가을의 곰을... 2012.05.01 4795
121 2010년 정보시스템감리사 세부출제분야 가을의 곰을... 2012.04.29 4787
120 2009년도 감리사 필기시험 출제 분야(안) 가을의 곰을... 2012.04.29 4896
119 [소방전기] 승자와 패자 가을의 곰을... 2012.04.29 4751
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED