slanted W3C logo
Cover page images (keys)

音声インタフェースフレームワークの真髄

W3C Voice Browser ワーキンググループ担当 芦村和幸 <ashimura@w3.org>

日常生活と Web

web_and_voice

Web へのアクセス方法

基本的にはキー操作

携帯電話:

パソコン/PDA:

こんなときは,どうする?

ちょっと Web サイトで調べたいことが

→でも,パソコンを持ってこなかった...

携帯電話でもアクセスできるかもしれない

→でも,携帯電話でアクセスするのは,ちょっと面倒かもしれない

たとえば,車を運転していたら?

→運転中は,携帯電話の操作をしてはいけません!

声で Web にアクセス!

手が離せなくても,電話で話すことは可能

* パソコンやPDAのような難しいキー操作なしに

* 世界中のどこにでもある普通の電話で

* 声や簡単なボタン操作だけで

Web(インターネット)にアクセスする仕組があればいい

それが「音声ブラウザ」

音声ブラウザの利用例

天気予報

時刻表

留守電

銀行振込

チケット購入

音声ブラウザって,どうやって使うの?

使い方

利用者は,サーバに電話をかけて,声とボタンで操作するだけ

アプリケーション

銀行振込などの具体的なアプリケーションは,別途,アプリケーション開発者が作成

音声ブラウザ

音声ブラウザは,別途,ブラウザの開発ベンダが提供

簡単なデモ

[電話でビデオ録画]

* 日帰り出張で東京へ

* あっ,ビデオのタイマをかけてくるのを忘れた.

* これから帰ると間に合わない!!!

そんな時でも大丈夫 ;-)

* 開始・終了時間,チャンネルを指定

* 出演者,番組名,番組のジャンルなどで指定できると便利

W3C によるインタフェース仕様標準化

さまざまな機能を組合せ
簡単かつ確実にアプリケーション開発

* 音声端末の操作方法 (人とのインタフェース)

* 端末とブラウザとのインタフェース

* ブラウザとアプリケーションとのインタフェース

web_and_voice

音声インタフェースフレームワーク

音声ブラウザ実現に必要な
マークアップ言語仕様集

Voice Browser architecture and standards

音声インタフェースフレームワーク詳細

http://www.w3.org/TR/voice-intro/

Speech Interface Framework

マークアップ言語の例:
 VoiceXML のみを用いた単純な制御

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE vxml PUBLIC "-//Nuance/DTD VoiceXML 1.0//EN" "http://voicexml.nuance.com/dtd/nuancevoicexml-1-2.dtd" >
<vxml>

<form id="when">

<!-- 曜日 -->
<field name="date">
<grammar src="Date.grammar#Date"/>
<prompt>何曜日ですか?</prompt>
<filled namelist="date">
<if cond="date=='getsuyoo'">
<prompt>月曜日ですね。</prompt>
</if>
<if cond="date=='kayoo'">
<prompt>火曜日ですね。</prompt>
</if>
<if cond="date=='suiyoo'">
<prompt>水曜日ですね。</prompt>
</if>
<if cond="date=='mokuyoo'">
<prompt>木曜日ですね。</prompt>
</if>
<if cond="date=='kinnyoo'">
<prompt>金曜日ですね。</prompt>
</if>
<if cond="date=='doyoo'">
<prompt>土曜日ですね。</prompt>
</if>
<if cond="date=='nichiyoo'">
<prompt>日曜日ですね。</prompt>
</if>
</filled>
</field>

<!-- 開始時刻 -->
<field name="st">
<grammar src="Time.grammar#Time"/>
<prompt>何時からですか?</prompt>
<filled namelist="st">
<if cond="st=='ichiji'">
<prompt>一時からですね。</prompt>
</if>
<if cond="st=='niji'">
<prompt>二時からですね。</prompt>
</if>
<if cond="st=='sannji'">
<prompt>三時からですね。</prompt>
</if>
<if cond="st=='yoji'">
<prompt>四時からですね。</prompt>
</if>
<if cond="st=='goji'">
<prompt>五時からですね。</prompt>
</if>
<if cond="st=='rokuji'">
<prompt>六時からですね。</prompt>
</if>
<if cond="st=='shichiji'">
<prompt>七時からですね。</prompt>
</if>
<if cond="st=='hachiji'">
<prompt>八時からですね。</prompt>
</if>
<if cond="st=='kuji'">
<prompt>九時からですね。</prompt>
</if>
<if cond="st=='juuji'">
<prompt>十時からですね。</prompt>
</if>
<if cond="st=='juuichiji'">
<prompt>十一時からですね。</prompt>
</if>
<if cond="st=='juuniji'">
<prompt>十二時からですね。</prompt>
</if>
</filled>
</field>

<!-- 終了時刻 -->
<field name="et">
<grammar src="Time.grammar#Time"/>
<prompt>何時までですか?</prompt>
<filled namelist="et">
<if cond="et=='ichiji'">
<prompt>一時までですね。</prompt>
</if>
<if cond="et=='niji'">
<prompt>二時までですね。</prompt>
</if>
<if cond="et=='sannji'">
<prompt>三時までですね。</prompt>
</if>
<if cond="et=='yoji'">
<prompt>四時までですね。</prompt>
</if>
<if cond="et=='goji'">
<prompt>五時までですね。</prompt>
</if>
<if cond="et=='rokuji'">
<prompt>六時までですね。</prompt>
</if>
<if cond="et=='shichiji'">
<prompt>七時までですね。</prompt>
</if>
<if cond="et=='hachiji'">
<prompt>八時までですね。</prompt>
</if>
<if cond="et=='kuji'">
<prompt>九時までですね。</prompt>
</if>
<if cond="et=='juuji'">
<prompt>十時までですね。</prompt>
</if>
<if cond="et=='juuichiji'">
<prompt>十一時までですね。</prompt>
</if>
<if cond="et=='juuniji'">
<prompt>十二時までですね。</prompt>
</if>
</filled>
</field>

<!-- チャンネル -->
<field name="channel">
<grammar src="Channel.grammar#Channel"/>
<prompt>何チャンネルですか?</prompt>
<filled namelist="channel">
<if cond="channel=='ichi'">
<prompt>一チャンネルですね。</prompt>
</if>
<if cond="channel=='ni'">
<prompt>二チャンネルですね。</prompt>
</if>
<if cond="channel=='sann'">
<prompt>三チャンネルですね。</prompt>
</if>
<if cond="channel=='yonn'">
<prompt>四チャンネルですね。</prompt>
</if>
<if cond="channel=='go'">
<prompt>五チャンネルですね。</prompt>
</if>
<if cond="channel=='roku'">
<prompt>六チャンネルですね。</prompt>
</if>
<if cond="channel=='nana'">
<prompt>七チャンネルですね。</prompt>
</if>
<if cond="channel=='hachi'">
<prompt>八チャンネルですね。</prompt>
</if>
<if cond="channel=='kyuu'">
<prompt>九チャンネルですね。</prompt>
</if>
<if cond="channel=='juu'">
<prompt>十チャンネルですね。</prompt>
</if>
<if cond="channel=='juuichi'">
<prompt>十一チャンネルですね。</prompt>
</if>
<if cond="channel=='juuni'">
<prompt>十二チャンネルですね。</prompt>
</if>
</filled>
</field>

<prompt>では録画します。</prompt>

<catch event="nomatch noinput">
<prompt>すいません。聞き取ることができませんでした。</prompt>
<goto next="#when"/>
</catch>
</form>

</vxml>

文法ファイル: Date.grammar

Date
[
[げつよう げつ げつようび] {<date "getsuyoo">}
[かよう か かようび] {<date "kayoo">}
[すいよう すい すいようび] {<date "suiyoo">}
[もくよう もく もくようび] {<date "mokuyoo">}
[きんよう きん きんようび] {<date "kinnyoo">}
[どよう ど どようび] {<date "doyoo">}
[にちよう にち にちようび] {<date "nichiyoo">}
]

文法ファイル: Time.grammar

Time
[
[いちじ いち] {<time "ichiji">}
[にじ に] {<time "ni">}
[さんじ さん] {<time "sannji">}
[よじ よん] {<time "yoji">}
[ごじ ご] {<time "goji">}
[ろくじ ろく] {<time "rokuji">}
[しちじ しち なな] {<time "shichiji">}
[はちじ はち] {<time "hachiji">}
[くじ きゅう] {<time "kuji">}
[じゅうじ じゅう] {<time "juuji">}
[じゅういちじ じゅういち] {<time "juuichiji">}
[じゅうにじ じゅうに] {<time "juuniji">}
]

文法ファイル: Channel.grammar

Channel
[
[いっちゃん いち] {<channel "ichi">}
[にちゃん に] {<channel "ni">}
[さんちゃん さん] {<channel "sann">}
[よんちゃん よん し] {<channel "yonn">}
[ごちゃん ご] {<channel "go">}
[ろくちゃん ろく] {<channel "roku">}
[ななちゃん なな しち] {<channel "nana">}
[はっちゃん はち] {<channel "hachi">}
[きゅうちゃん きゅう] {<channel "kyuu">}
[じゅっちゃん じゅう] {<channel "juu">}
[じゅういっちゃん じゅういち] {<channel "juuichi">}
[じゅうにちゃん じゅうに] {<channel "juuni">}
]

音声インタフェースフレームワークの構成要素

対話制御

VoiceXML : 音声およびDTMF(キー操作)による Web アクセス制御

CCXML : 電話対話の流れを制御

SCXML : 複雑な状態遷移の制御

音声認識/合成

SRGS : 音声認識のための文法

SISR : 音声認識のための意味理解

SSML : 音声合成

PLS : 合成と認識のための辞書 (単語と読みの対応)

まとめ

日常生活と深く関わる Web

音声による Web アクセス

W3C が進めるインタフェース仕様の標準化

マークアップ言語の例2:
 SCXML を用いた状態遷移の例

<?xml version="1.0" encoding="us-ascii"?>
<!-- A wrapper state that contains all other states in this file
- it represents the complete state machine -->
<scxml xmlns="http://www.w3.org/2005/07/scxml"
       version="1.0"
       initalstate="Main">  
  <state id="Main">
    <!-- its initial state is Test1 -->
    <initial>
      <transition>
        <target next="Test1"/>
      </transition>
    </initial>
    <!-- Really simple state showing the basic syntax. -->
    <state id="Test1">
      <initial>
        <transition>
          <target next="Test1Sub1"/>
        </transition>
      </initial>
      <!-- Runs before we go into the substate -->
      <onentry> 
        <log expr="'Inside Test1'"/>
      </onentry>
      <!-- Here is our first substate -->
      <state id="Test1Sub1">
        <onentry>
          <log expr="'Inside Test1Sub1.'"/>
        </onentry>
        <onexit>
          <log expr="'Leaving Test1Sub1'"/>
        </onexit>
        <!-- Go to Sub2 on Event1 -->
        <transition event="Event1">
          <target next="Test1Sub2"/>
        </transition>
      </state>
      <!-- Here is the second substate 
           -    It is final, so Test1 is done when we get here -->
      <state id="Test1Sub2" final="true">
        <onentry>
          <log expr="'Inside Test1Sub2...'"/>
        </onentry>
        <onexit>
          <log expr="'Leaving Test1Sub2'"/>
        </onexit>
      </state>
      <!-- We get this event when we reach Test1Sub2. -->
      <transition event="Test1.done">
        <target next="Test2"/>
      </transition>
      <!-- We run this on the way out of Test1 -->
      <onexit>
        <log expr="'Leaving Test1...'"/>
      </onexit>
    </state>
    <state id="Test2">
      <initial>
        <transition>
          <target next="Test2Sub1"/>
        </transition>
      </initial>
      <!-- This time we reference a state 
           -    defined in an external file -->
      <state id="Test2Sub1" src="Test2Sub1.scxml"/>
      <!-- This time we reference a state 
           -    defined in an external file and 
           -    use the templating support to add
           -    an onexit hander. -->
      <state id="Test2Sub2" src="Template.scxml">
        <onexit>
          <log expr="'Leaving Substate Test2Sub2'"/>
        </onexit>
      </state>
      <!-- Test2Sub2 is defined as final, so this
           -  event is generated when we reach it -->
      <transition event="Test2.done">
        <target next="Test3"/>
      </transition>
    </state>
    <state id="Test3">
      <initial>
        <transition>
          <target next="Test3Sub1"/>
        </transition>
      </initial>
      <state id="Test3Sub1">
        <onentry>
          <log expr="'Inside Test3Sub1...'"/>
          <!-- Send our self an event in 5s -->
          <send event="Timer"  delay="5s"/>
        </onentry>
        <transition event="Timer">
          <!-- Transition on to Test4.
               -    This will exit both us and our parent. -->
          <target next="Test4"/>
        </transition>
        <onexit>
          <log expr="'Leaving Test3Sub1...'"/>
        </onexit>
      </state>
      <onexit>
        <log expr="'Leaving Test3...'"/>
      </onexit>
    </state>
    <state id="Test4">
      <onentry>
        <log expr="'Inside Test4...'"/>
      </onentry>
      <!-- Here we use the inline features of 
           -    target to create our scratch state.-->
      <initial>
        <transition>
          <target>
            <state id="Test4Sub1" >
              <onexit>
                <log expr="'Leaving Test4Sub1...'"/>
              </onexit>
              <!-- This transition causes the state to exit immediately
                   - after entering Test4Sub1.  The transition has no event or guard 
                   - so it is always active -->
              <transition>
                <target next="Test5"/>
              </transition>
            </state>
          </target>
        </transition>
      </initial>
    </state>
    <state id="Test5">
      <onentry>
        <log expr="'Inside Test5...'"/>
      </onentry>
      <initial>
        <transition>
          <target next="Test5P"/>
        </transition>
      </initial>
      <!-- Fire off our parallel states -->
      <parallel id="Test5P">
        <state id="Test5PSub1" final="true">
          <onentry>
            <log expr="'Inside Test5PSub1...'"/>
          </onentry>
        </state>
        <state id="Test5PSub2" final="true">
          <onentry>
            <log expr="'Inside Test5PSub2...'"/>
          </onentry>
        </state>
        <onexit>
          <log expr="'all parallel states done'"/>
        </onexit>
      </parallel>
      <!-- The parallel states are all final, so this
           -  event is generated immediately -->
      <transition event="Test5P.done">
        <target next="Test6"/>
      </transition>
    </state>
    <!-- 
         - This state shows invocation of external component
         - We will use CCXML + VoiceXML actions as an example 
         - as it is a good smoke test to show how it all 
         - fits together. 
         - Note: Odds are in a real app you would 
         - split this over several states but we 
         - are trying to keep it simple here. 
    -->
    <state id="Test6"
           xmlns:ccxml="http://www.w3.org/2002/09/ccxml"
           xmlns:v3="http://www.w3.org/2005/07/vxml3">
      <onentry>
        <!--
            - Use <send> to run a createcall using the 
            - CCXML component / Event I/O Processor
        -->
        <var name="dest" expr="'tel:+18315552020'"/>
        <send targettype="ccxml" event="ccxml:createcall" namelist="dest"/>
      </onentry>
      <transition event="ccxml:connection.connected" name="evt">      
        <!--
            - Here we use example V3 
            - Custom Action Elements instead of send . 
        -->
        <v3:form id="HelloWorld">
          <v3:block><v3:prompt>Hello World!</v3:prompt></v3:block>          
        </v3:form>
      </transition>
      <!--
          - Here we are using the low level <send> 
          - element to run a v3 form. Note that the event "v3:HelloWorld.done" 
          is assumed either to be set/sent explicitly by the v3:form code or 
          implicitly by some process outside of the v3:form
      -->
      <transition event="v3:HelloWorld.done" name="evt">
        <var name="src" expr="'helloworld2.vxml'"/>
        <var name="id" expr="'HelloWorld'"/>
        <send targettype="v3" event="v3:formstart" namelist="src id"/>
      </transition>
      <transition event="v3:HelloWorld2.done" name="evt">
        <ccxml:disconnect connectionid="evt.connectionid"/>      
      </transition>
      <transition event="ccxml:connection.disconnected">
        <!--
            - Here we are using the <exit/> shorthand to 
            - move ourself to a final state.
            - In this example you could do <target next="Done"/>
            - and get the same result.
        -->
        <exit/>
      </transition>
      <!-- Transitions to handle events generated by the component
           - component invoked successfully. this transition has no target 
           - so Test6 is not exited.
           - We are just going to log tha we were able to send an event. -->
      <transition event="send.successful">
        <log expr="'Event was able to be sent'"/>
      </transition>
      <!--
          - If we get an error event we move to the Done state that 
          - is a final state. 
      -->
      <transition event="error.send">
        <log expr="'Sending to and External component failed'"/>
        <target next="Done"/>
      </transition>
      <onexit>
        <log expr="'Finished with external component'"/>
      </onexit>
    </state>
    <!-- This final state is an immediate child of Main
         -  when we get here, Main.done is generated. -->
    <state id="Done" final="true"/>
    <!-- End of Main > -->
  </state>
</scxml>