レベル: 中級 Martin Brown, Developer and writer, Freelance
2007年 10月 02日 4 回シリーズの最終回である今回は、VoiceXML を入力として、基本的な Web 検索の場合も Yahoo のローカル検索の場合も Yahoo Search API を照会するアプリケーションを開発します。照会の結果として、特定の場所と地域でのビジネスに関する情報が返されると、そのアプリケーションは返された結果を、照会を依頼した呼び出し側に対して読み上げます。
はじめに
最近ではインターネット検索が当然のものとなっており、検索用に利用できるサービスが無数にあります。また Web 検索も拡大しました。Web を持っている会社は非常に多いため、今や多くの会社では、その会社の Web データと従来のオフライン・データ (ビジネス・ディレクトリーや、地図および所在地の情報など) を統合し、さまざまなビジネスや情報を検索できるようにしています。
こうした情報は、検索を実行依頼して、その結果を聞くために VXML (VoiceXML) を使うには最適です。この記事では、それを行うアプリケーションを作成します。そのための手順は以下のとおりです。
- Web 検索のワークフローを検討する
- VXML フォーム要素を出力するための汎用クラスを作成する
- 広範な入力をサポートする VXML 文法を作成する
- Yahoo の検索インターフェースを使う
- VXML と Yahoo 検索を使って Web 検索を実行する
- VXML と Yahoo 検索を使ってローカル検索を実行する
このシリーズについて
Web 上では、音声とオーディオ全般が次第に一般的なものになりつつあります。その例として、今や大量の音楽やウェブキャストがオンライン上にあふれています。このシリーズでは、音声と XML を組み合わせ、次のようないくつかの便利なアプリケーションを作成する方法について説明します。
Web 検索のワークフロー
Web 検索のワークフローは、ローカル検索と従来の Web 検索という 2 つのタイプの検索から 1 つを選択できる、単純なメニューを提供します。前者は検索語と場所という 2 つの入力値を必要とし、後者は検索語しか必要ありません。基本的なシーケンスを図 1 に示します。
図 1. Web 検索のワークフロー
メニューを選択するための基本的な方法の例は、このシリーズの以前の記事で説明しました。そのため、この記事ではその部分の説明を省略します。
ただし検索語については、入力される言葉として、(VoiceXML の仕様で認識される) もっと広範囲の選択肢をサポートします。そして、この情報をアプリケーションの一部として出力するための、単純な VoiceXML クラスを作成します。
自由形式の文法の入力を作成する
このシリーズの第 3 回では VoiceXML 用のブログ・ソリューションについて説明しました。そこで見たように、任意の音声テキストを読み込み、それをテキスト・フォーマットに変換する便利な変換方法は今のところありません。そのため音声認識システムをもっと正確なものにするためには、音声受信されることが想定される語句を指定しなければなりません。
通常、特定のフレーズ (例えば「I am sad」など) を指定したり想定したりする場合には、そのフレーズを文法ルールの中で明示的に定義します。例えば (eye am sad) のようにします。
Web 検索の場合には、もっと自由な形式のテキスト入力が必要です。「変換」サポートがないため、どんなテキストでも構わず受け入れるということはできませんが、ある範囲の言葉を用意しておき、さまざまな言葉をユーザーが好きなだけ繰り返す、というようにすることができます。
それを実現するためには、対象とする一連の言葉に対してグループを指定し、そしてそうした言葉の少なくとも 1 つ以上をサポートするルールを作成します。例えば、「java」、「apple」、「windows」、あるいはこれらの言葉の任意の組み合わせをサポートしたい場合には、Terms [ (java) (apple) (windows) ] という言葉のグループを指定します。
そして、その同じ文法に、.Phrase +Terms (.フレーズ+言葉) の繰り返しを想定するルールを追加します。
そうすると、ユーザーはこれらの言葉のどれでも、どのような組み合わせでも、どのような期間にわたっても、繰り返すことができます。例えば「java apple」または「java apple window」は有効です。
もちろん、これは他の方法でも実現できるため、これ自体にはそれほど使い道がありません。これが真価を発揮するのは、結合できる、あるいは厳密なコントロールを提供できる他の英単語と組み合わせた場合です。例えば、Terms [ (java) (apple) (windows) (and) (or) ] を使って定義を拡張したとします。
そうするとユーザーは、「java and apple」または「java and windows」、さらには「java and apple or windows」と発声することができます。
今度はこれを使って、ほとんど自由形式の入力を、標準化された出力クラスを使って受け付けるシステムを構築します。
汎用の VXML 出力クラスを作成する
ここでは、事前定義されたフォーマットに従ってフラグメントの特定要素を生成する、標準化された VXML 出力を作成します。これによって VXML の作成が簡単になり、しかも入力フォーマットは自由形式のため、情報の作成がはるかに容易になります。
WebSearchVXML クラスには、アプリケーションに必要な適切な VXML を出力する単純なメソッドがいくつかあるため、このクラスをさまざまなアプリケーションで動作するように適応させることができます。ここでは (System.out.println() メソッドを使って) 標準出力に出力しますが、Web ベースのアプリケーションの中で VoiceXML アプリケーションの動的要素に対して動作するように容易に適応させることができます。
- Web 検索でサポートされる言葉のリスト
- ローカル検索でサポートされる言葉のリスト
- サポートされる都市または場所のリスト
-
VXMLPrompt は <prompt>メッセージ</prompt> ブロックを出力します。
-
VXMLTerms は、prompt ブロックが埋め込まれたフィールド・ブロックと、自由形式の言葉の文法出力を出力します。
-
VXMLOptions は、prompt ブロックが埋め込まれたフィールド・ブロックと、単語で表された選択肢のリスト (あるリスト (例えば都市のリスト) の中からユーザーが 1 つを選択するようにしたい場合に適切です) を出力します。
-
VXMLHeader は標準化されたヘッダーを出力します。
-
VXMLFooter は単純なフッターを出力します。
リスト 1 は、この結果作成されたクラスを示しています。
リスト 1. 標準化された VXML クラス
public class WebSearchVXML {
String webterms[] = { "java",
"apple",
"windows",
"britney spears",
"lindsey lohan"};
String localterms[] = { "plumber",
"restaurant",
"electrician",
"supermarket"};
String cities[] = { "London",
"Nottingham",
"Manchester",
"York",};
PrintStream out = System.out;
public void WebSearchVXML() {
}
private void OutputGSLTerms(String[] terms) {
this.out.println("<grammar type=\"text/gsl\">" +
"<![CDATA[\n" +
".Phrase +Terms\n" +
"Terms [ ");
for(int i=0;i<terms.length;i++) {
this.out.println("(" + terms[i] + ")");
}
this.out.println("]\n" +
"]]>" +
"</grammar>");
}
private void OutputOptionTerms(String[] terms) {
for(int i=0;i<terms.length;i++) {
this.out.println("<option>" + terms[i] + "</option>");
}
}
public void VXMLPrompt(String prompt) {
this.out.println("<prompt>" + prompt + "</prompt>");
}
public void VXMLTerms(String fieldname,
String prompt,
String [] terms) {
this.out.println("<field name=\"" + fieldname + "\">");
VXMLPrompt(prompt);
OutputGSLTerms(terms);
this.out.println("</field>");
}
public void VXMLOptions(String fieldname,
String prompt,
String [] terms) {
this.out.println("<field name=\"" + fieldname + "\">");
VXMLPrompt(prompt);
OutputOptionTerms(terms);
this.out.println("</field>");
}
public void VXMLHeader() {
this.out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
this.out.println("<vxml version=\"2.1\">");
}
public void VXMLFooter() {
this.out.println("</vxml>");
}
}
|
この結果、ユーザーからの入力を受け付ける VXML フォームを非常に素早く出力できるようになります。
汎用のインターフェースを使う
例えば、リスト 2 のコードを使って「ローカル」検索用の VXML を生成することができます。
リスト 2. 単純な検索を出力する
WebSearchVXML search = new WebSearchVXML();
search.VXMLHeader();
System.out.println("<form>");
System.out.println("<block>");
search.VXMLPrompt("Welcome to the Internet search service");
System.out.println("</block>");
search.VXMLTerms("phrase",
"Enter the search phrase to use when searching the web",
search.webterms);
search.VXMLOptions("location",
"Enter the location to limit your search to",
search.cities);
System.out.println("<filled><submit name=\"/VXMLSearch/search\"
namelist=\"phrase location\">");
System.out.println("</form>");
search.VXMLFooter();
|
リスト 3 は、これによって生成される VXML を示しています。
リスト 3: VXML 出力
<?xml version="1.0" encoding="UTF-8"?>
<vxml version="2.1">
<form>
<block>
<prompt>Welcome to the Internet search service</prompt>
</block>
<field name="phrase">
<prompt>Enter the search phrase to use when searching the web</prompt>
<grammar type="text/gsl"><![CDATA[
.Phrase +Terms
Terms [
(java)
(apple)
(windows)
(britney spears)
(lindsey lohan)
]
]]></grammar>
</field>
<field name="location">
<prompt>Enter the location to limit your search to</prompt>
<option>London</option>
<option>Nottingham</option>
<option>Manchester</option>
<option>York</option>
</field>
<filled><submit name="/VXMLSearch/search" namelist="phrase location">
</form>
</vxml>
|
この場合の本当の利点は、サポートされる言葉や都市のリストを変更、または拡張するために、ストリング配列を更新するだけでよいという点です。
結果として作成された選択肢とサポートされる入力値は完全に自由形式のテキストではありませんが、言葉のリストが十分に充実したものであれば、とても柔軟なものになるはずです。
Yahoo の検索インターフェースを使う
Yahoo の検索インターフェースでは、Yahoo の検索データベースのほとんどすべてを検索することができます。この便利なインターフェースは、さまざまな検索パラメーターを作成するための、また検索結果から詳細を取得するためのさまざまな方法を提供しています。
Yahoo の検索システムを使い始める前に、API キーを入手するために登録する必要があります。API キーを入手できたら、Yahoo の検索 SDK (「参考文献」を参照) をダウンロードします。この SDK は Java™ の JAR ファイルの形式になっており、Yahoo の検索インターフェースと通信するために必要なすべてのものを含んでいます。
この API を使う Java プログラムをコンパイルするためには、この yahoo の JAR をクラスパス $ javac -cp yahoo_search-2.0.2.jar LocalSearch.java に含める必要があります。
これで、検索語を受け付け、見つかった結果をリストするために必要なVXML を出力する、単純な検索関数を作ることができます。
Web 検索を実行する
単純な Web 検索を実行するためには、登録した際に Yahoo から受け取った API キーを使って SearchClient() オブジェクト・インスタンスを作成します。これによって、検索を実行する、そして実際に任意の検索タイプをサポートするクライアント・オブジェクトが作成されます。
リクエストに関しては、WebSearchRequest() クラスを使って新しいリクエスト・オブジェクトを作成し、検索語として使用するストリングを指定します。
クライアントを使ってリクエストを送信すると、Yahoo はそのリクエストに関する一般的な情報を含む WebSearchResults オブジェクトと、個々の結果の配列を返します。それぞれの結果にはページのタイトルや URL その他の情報が含まれますが、その大部分は VoiceXML のアプリケーションではあまり使い道がありません。全体的なシーケンスを図 4 に示します。
リスト 4. Yahoo を使って Web 検索を実行する
public static void DoSearch(String term) {
SearchClient client = new SearchClient("INSERTKEY");
WebSearchRequest request = new WebSearchRequest(term);
try {
WebSearchResults results = client.webSearch(request);
System.out.println("<block><prompt>Found " +
results.getTotalResultsAvailable() +
" hits for " +
term +
". Detailing the top " +
results.getTotalResultsReturned() +
" results.</prompt></block>");
for (int i = 0; i < results.listResults().length; i++) {
WebSearchResult result = results.listResults()[i];
System.out.println("<block><prompt>" +
result.getTitle() +
".<break/>" +
"</prompt></block>");
}
}
catch (Exception e) {
System.err.println("An error occurred");
}
}
|
リスト 4 のコードは、プロンプト・ブロックのテキストと、検索全体に関する情報 (つまりヒット数) のブロック、そして次に、Yahoo の Web 検索データベースで見つかる結果それぞれに対するブロックを出力するように設計されています。
リスト 5 は、このプロセスで生成される VXML の例を示しています。
リスト 5. 生成される VXML
<?xml version="1.0" encoding="UTF-8"?>
<vxml version="2.1">
<form>
<block><prompt>Found 73600000 hits for britney spears. Detailing the top 10
results.</prompt></block>
<block><prompt>Britney Spears - The Official
Site.<break/></prompt></block>
<block><prompt>WORLDOFBRITNEY.COM.<break/>
</prompt></block>
<block><prompt>Britney Spears - britney.com - Jive
Records.<break/></prompt></block>
<block><prompt>Britney Spears Zone | Britney Divorce, Pregnant,
Baby Pictures, Pics &
News.<break/></prompt></block>
<block><prompt>britneyspears.org.<break/></prompt></block>
<block><prompt>WoBPictures.com [100030013].<break/>
</prompt></block>
<block><prompt>Britney Spears - Wikipedia, the free
encyclopedia.<break/></prompt></block>
<block><prompt>Britney Spears | Music Artist | Videos, News, Photos &
Ringtones | MTV.<break/></prompt></block>
<block><prompt>Britney Spears.<break/></prompt></block>
<block><prompt>Britney Spears - Yahoo! Music.<break/>
</prompt></block>
<disconnect/>
</form>
</vxml>
|
音声ブラウザーが読み上げる際には、一部の情報をおかしな風に表現しますが、これは音声ブラウザーが出力のタイプを判断しようとしているためです。例えば「WORLDOFBRITNEY.COM」は、(「W」、「O」、「R」、・・ のように) 文字列として出力されますが、これはブラウザーが「WORLDOFBRITNEY.COM」を頭字語と見なすためです。
他の値の出力は、その値を音声ブラウザーがどう判断するかによります。例えば、ヒット数は「seventy three million, six hundred thousand (73,600,000)」のように正しく読み上げられます。残念ながら、「WoBPictures.com」というタイトルの中の数は、まるで単なる数字の羅列であるかのように表現されます。
ローカル検索を実行する
Yahoo 検索システムでは、ローカル検索は検索語と場所の両方に依存します。場所の指定方法はさまざまなため、検索情報の指定方法は Web 検索のインターフェースよりも少し複雑です。
従ってローカル検索では、VoiceXML の選択ページの検索語と場所を受け付け、その情報に基づいて検索を実行します。そのシーケンスは次のとおりです。
- Yahoo の SearchClient リクエストを作成します。
- 検索対象の場所を (
setLocation() を使って) 設定します。
- 検索対象のクエリーを (
setQuery() を使って) 設定します。
検索オブジェクトを組み立ててしまえば、結果データを抽出するための基本的なプロセスは Web 検索のソリューションでのプロセスと同じです。
この実際の例をリスト 6 に示します。
リスト 6. ローカル検索から VoiceXML を出力する
public static void DoSearch (String term,String location) {
SearchClient client = new SearchClient("INSERTKEY");
LocalSearchRequest request = new LocalSearchRequest();
request.setLocation(location);
request.setQuery(term);
try {
LocalSearchResults results = client.localSearch(request);
System.out.println("<block><prompt>Found " +
results.getTotalResultsAvailable() +
" hits for " +
term + " in " + location +
". Detailing the top " +
results.getTotalResultsReturned() +
" results.</prompt></block>");
for (int i = 0; i < results.listResults().length; i++) {
LocalSearchResult result = results.listResults()[i];
Pattern pattern = Pattern.compile("&");
Matcher matcher = pattern.matcher(result.getTitle());
System.out.println("<block><prompt>" +
matcher.replaceAll("and") +
".<break/> Phone number: " +
result.getPhone() +
"</prompt></block>");
}
}
catch (Exception e) {
System.err.println("Error calling Yahoo! Search Service: " +
e.toString());
}
}
|
この特定の出力での 1 つの注意点として、アンパーサンド (&) 文字をすべて「and」という単語で置き換えていることに注目してください。大部分の VoiceXML システムは、ほとんどの XML/HTML エスケープ文字 (& ならば & になります) で動作するように設計されていますが、一部の音声ブラウザーは、情報が適切にエスケープされていないと (それによって VXML 文書の XML としての妥当性が失われるため)、その情報の処理を行いません。情報は正しいフォーマットで出力するように注意する必要があります。上記の例でこれを実現するためには、正規表現を使って置き換えを行います。
この例での 2 番目の注意点は、見つかった会社のタイトルと共に電話番号を出力する点です。多くの音声ブラウザーでは、電話番号を数字のフォーマットで識別し、各桁を電話番号として正しく出力します (例えば「nine hundred」や「six hundred and six」などとは言いません) 。
ここまでに、完全な VXML の例を数多く見てきました。では、それぞれの検索結果を出力する (ブロックとして整理された) 基本的な内容の出力を見てみましょう (リスト 7)。
リスト 7. 基本的な内容の出力
<block><prompt>Found 14 hits for plumber in New York.
Detailing the top 10 results.</prompt></block>
<block><prompt>State Plumbing Inspector.<break/>
Phone number: (606) 862-1297</prompt></block>
<block><prompt>Hibbitts Brothers Wholesale.<break/>
Phone number: (606) 864-2256</prompt></block>
<block><prompt>State Plumbing Inspector Paul Ray.<break/>
Phone number: (606) 862-1297</prompt></block>
<block><prompt>Willard Neeley Plumbing and Htg.<break/>
Phone number: (606) 864-6203</prompt></block>
<block><prompt>Vanhook Plumbing Htg and Cooling.<break/>
Phone number: (606) 862-8228</prompt></block>
<block><prompt>Rooter Man of South Eastern Ky.<break/>
Phone number: (606) 878-1339</prompt></block>
<block><prompt>Kettry Roaden Plumbing.<break/>
Phone number: (606) 528-3396</prompt></block>
<block><prompt>Prestige Marble.<break/>
Phone number: (606) 523-9186</prompt></block>
<block><prompt>Herb King Plumbing.<break/>
Phone number: (606) 364-4534</prompt></block>
<block><prompt>AAA Plumbing.<break/>
Phone number: (606) 528-0705</prompt></block>
|
この出力の音声版は完全なものではありません。例えば、配管と暖房機器の会社である「Vanhook Plumbing and Htg」ならば、「Htg」を完全なつづりで書く必要があります。音声ブラウザーが「Htg」を「heating」に拡張して解釈する可能性はないからです。
まとめ
この記事では、Yahoo の Web ページ・データベースと Yahoo のローカル・ビジネス・ディレクトリー・データベースの両方に対して検索を行い、検索結果の VXML を Yahoo の検索 API を使って出力する方法について説明しました。作成されたソリューションでは、ユーザーはサービスを呼び出し、システムに対して、ニューヨークの配管業者を上位 10 件、あるいは「java」と「apple」について触れているサイトの上位 10 件をリストするように指示することができます。ここで重要なことは、自由形式の語句を入力できることです。この入力方式のおかげで、語句や単語、そしてこれらの単語や語句の無限の組み合わせをサポートすることができ、検索を可能な限り正確なものにすることができます。
また、VXML を生成するための標準化した方法も説明しました。この方法は標準的な VoiceXML ブラウザーの選択システムでも使用することができます。
このシリーズが、皆さん独自の VoiceXML アプリケーションを開発するための確実な基礎となれば幸いです。
ダウンロード | 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|
| Part 4 sample code | x-voicexml4-search.zip | 3KB | HTTP |
|---|
参考文献 学ぶために
製品や技術を入手するために
- RSS フィードと Atom フィードを構文解析し、生成し、そして公開するためのオープン・ソースの Java ツールとライブラリー、Rome RSS/Atom syndication をダウンロードしてください。
- XML-RPC ソースに接続するための単純化されたインターフェース、Apache XML-RPC Client を入手してください。
-
Voxeo には、VoiceXML アプリケーションのための豊富な情報とホスティング・ソリューションが用意されており、従来の回線や VoIP、そして Skype からアクセスすることができます。
- 皆さんの次期開発プロジェクトを IBM trial software で構築してください。developerWorks から直接ダウンロードすることができます。
議論するために
著者について  | 
|  | Martin Brown は、プロのライターとして 8 年以上の経験を持ち、さまざまな分野で多数の本と記事を執筆しています。専門分野は、Perl、Python、Java、JavaScript、Basic、Pascal、Modula-2、C、C++、Rebol、Gawk、Shellscript、Windows、Solaris、Linux、BeOS、Mac OS/X など数え切れないほどの開発言語とプラットフォーム、そして Web プログラミング、システム管理、そしてシステム統合にも及びます。彼は ServerWatch.com、LinuxToday.com、IBM developerWorks の定期的なコントリビューターで、Computerworld、The Apple Blog、そして Microsoft の SME (Subject Matter Expert) などのサイトでもお馴染みのブロガーとなっています。連絡先は彼の Web サイト、http://www.mcslp.com です。 |
記事の評価
|