VoiceXML入门学习指南
保留所有版权,请引用而不是转载本文(原文地址 https://yeecode.top/blog/126/ )。
VoiceXML(语音可扩 展标记语言)是用来描述语音对话过程的标记语言。其定义了如何使用语音识别、语音合成、互联网访问、数据库访问、语音文件播放、DTMF输入等功能开发一 个完整的语音应用系统。
用VoiceXML开发的语音应用系统,不仅可以完全代替传统CTI(计算机电话集成) 系统所能提供的功能,而且还可以使应用系统开发过程极其简单快捷、系统有极高的可扩展性、可维护性、可移植性、可重用性和开放性。
1 概述
1.1 VoiceXML的历史与背景
VoiceXML的出现最早可以追溯到1995在AT&T公司开发的基于XML的电话标记语言(PML)。随后,AT&T、Lucent Technologies以及Motorola公司分别各自着手开发自己的类似于PML的语音标记语言。到了1998年,W3C组织的“语音浏览器”会议上,AT&T和Lucent Technologies分别展现了他们各自的类同PML的标记语言、Motorola和IBM公司分别推出VoxML和SpeechML、HP和PipeBeach公司也分别推出TalkML和VoiceHTML。AT&T、IBM、Lucent Technoglies、以及Motorola随后成立了VoiceXML论坛,其目的是为了建立一个语音对话应用系统的国际标准。到了2000年,AT&T、IBM、Lucent Technologies、以及Motorola通过W3C协会联合推出语音可扩展标记语言VoiceXML1.0。该标准一经推出,便得到相关行业众多公司的响应。经过两年多的论证和实际系统验证,VoiceXML2.0最终草案在2003年推出。
1.2 为什么要用VoiceXML?
VoiceXML的推出给电话语音系统带来全新的应用和开发概念,使传统的CTI技术从繁琐、封闭的模式中走了出来,使广大的语音系统开发人员可以用极其简单的方法实现复杂系统的开发。
完全替代传统CTI:传统的电话语音系统典型的工作方式是接受用户的按键输入和语音文件播放、跟据用户的需求为用户提供相应服务。基于VoiceXML开发的电话语音系统完全可以替代传统CTI系统所能提供的功能。
语音识别功能:基于VoiceXML开发的电话语音系统除了接受用户的按键输入之外,还可以接受用户的语音输入。系统通过语音识别功能实现对用户输入语音到文本的转换。这对于许多仅用按键输入方式而无法解决或解决起来很繁琐的应用领域很有实用意义。
语音合成功能:基于VoiceXML开发的电话语音系统除了能够播放预先录制的语音文件之外,还可以将系统中的文本转换成语音的方式播放给用户。这对于那些需要播报即时消息和可变信息等的应用领域很有实用价值。
与互联网联结: 长期以来,公用电话网和互联网是分离的。随着互联网技术的迅速发展,互联网信息与日俱增,以及互联网相关服务的日新月异,将互联网与公用电话网整合为一 体,使广大的电话用户也能享受到互联网提供的信息和服务显得越来越有吸引力。VoiceXML使公用电话网与互联网有机地结合,使两网的信息能够相互流 动。例如,电话语音流言可以通过互联网以电子邮件的方式传送到目的地;互联网上的新闻可以通过电话播放给用户等。
灵活的数据库接口:许多电话语音应用系统离不开数据库访问。VoiceXM通过脚本方式提供灵活的数据库接口,使得应用系统可以方便地访问各种数据库,如:Microsoft SQL Server 2000、Oracle、Sybase、Microsoft Access、MySQL等。
简化开发过程: 用VoiceXML将电话语音应用系统开发人员从繁琐的编码细节中解脱了出来。开发人员不需要了解相关软件(如语音识别和语音合成)和硬件(如语音卡)API的编程接口,只需要把精力放在应用领域的业务流程上。开发过程轻松快捷、开发周期大大缩短(7-10倍)。VoiceXML使开发人员得以用简 单的方法实现复杂的工作。
除此之外,基于VoiceXML开发的语音应用系统具有很高的系统可扩展性、可维护性、可移植性、可重用性和开放性。
1.3 VoiceXML现状
自 2000年VoiceXML1.0推出以后经过不断的修改,于2003年1月推出最新的VoiceXML2.0最终推荐版本。根据W3C称,该版本将会比 较稳定,鼓励各VoiceXML浏览器生产厂家可以根据此版本进行开发。预计不久VoiceXML2.0将会正式推出。
中国目前也有一些相关行业的公司在着手开发有关VoiceXML的产品。深圳市华琛科技有限公司是国内领先的VoiceXML语音平台生产厂家。在华琛公司 的VoPromote平台上,开发人员可以用VoiceXML2.0脚本语言开发应用于各行业的电话语音系统。
1.4 小结
VoiceXML标准的出现给电话语音应用系统的开发带来了全新的概念,同时还大大扩展了语音应用系统的应用范围。可以预计,VoiceXML标准的推广将会极大地推动电话语音应用系统的开发和应用,将给广大的电话用户带来深远的影响。
2 元素介绍
Voice XML的常用元素如下:
<assign>给变量赋值。<audio>播放语音文件。<block>无用户交互的可执行代码块。<catch>捕获一个事件。<choice>定义一个菜单项。<clear>清除一个或多个框架项。<disconnect>结束一次通话。<else>用于<if>元素中的else。<elseif>用于<if>元素中的elseif。<enumerate>列举菜单选项。<error>捕获一个<error>事件。<exit>退出一次通话。<field>在框架中申明一个输入域。<filled>指定当输入域被填充以后需要作的操作。<form>提示信息和接受数据的对话框架。<goto>把控制转向在同一个或不同文档中的对话。<grammar>指定语音识别或DTMF语法。<help>捕获一个<help>事件。<if>条件逻辑。<initial>在进入一个双向交互式对话框架时申明初始对话逻辑。<link>在所有对话公共链接区域指定控制转向。<log>生成调试信息。<menu>定义菜单对话。<meta>定义一个元数据项。<metadata>定义元数据信息。<noinput>捕获一个<noinput>事件。<nomatch>捕获一个<nomatch>事件。<object>系统扩展的对象。<option>在一个输入域中选择一个选项。<param><object>或<subdialog>的参数。<prompt>指定语音合成提示和声音文件输出。<property>指定特性值以控制平台设置。<record>录音。<reprompt>指定重新提示。<return>从子对话中返回。<script>定义ECMAScript模块。<subdialog>调用一个子对话。<submit>向文件服务器上传数据。<throw>产生一个事件。<transfer>电话转接。<value>在提示中插入一个值。<var>声明一个变量。<vxml>VoiceXML文档标识。 下面对VoiceXML2.0元素进行一些简单介绍。
2.1 <assign>
给一个声明过的变量赋值。在下面的例子中,<assign>将“学习VoiceXML”赋值给变量verb。由于<assign> 的属性expr的值是一个Javascript表达式,用单引号将学习VoiceXML括起来以表示其为字符串而不是变量。下面的例子将输出“我学习 VoiceXML”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<var name="verb"/>
<block>
<assign name="verb" expr="'学习VoiceXML'"/>
我<value expr="verb"/>。
</block>
</form>
</vxml>
2.2 <audio>
播放一个语音文件。下面的例子输出<audio>的属性src所指定的语音文件名welcome.wav。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<block>
<audio src="welcome.wav"/>
</block>
</form>
</vxml>
2.3 <block>
该元素包含一个没有用户交互发生的代码区域。下面的例子中,<block>包含一个提示元素<prompt>以输出提示信息。下面的例子输出“欢迎使用华琛公司语音系统。”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<block>
<prompt>欢迎使用华琛公司语音系统。</prompt>
</block>
</form>
</vxml>
2.4 <catch>
捕捉被抛出的事件。它既可以捕捉系统预定义的事件(noinput、nomatch、error、help等),也可以捕捉由抛出的用户自定义的事件。下面的例子中,当输入没有匹配“number”语法时,<catch>捕捉到“nomatch”事件,并输出提示“对不起我没有听懂,请您再说一遍。”,重新回到“phonenumber”输入域。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<catch event="nomatch">
<prompt>对不起我没有听懂,请您再说一遍。</prompt>
</catch>
<field name="phonenumber" type="number">
<prompt>请告诉我您的电话号码。</prompt>
<filled>
<prompt>
您的电话号码是<value expr="phonenumber"/>
</prompt>
</filled>
</field>
</form>
</vxml>
2.5 <choice>
定义一个菜单项。下面的例子中,两个<choice>组成两个菜单项“天气预报”和“股票市场”,当输入其中一个菜单项,控制转向由<choice>的属性next所指向的文件。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<menu>
<prompt>
欢迎使用华琛公司语音服务系统。今天我能为您做什么?
了解今天的天气情况请说"天气预报";了解股市情况请说"股票市场"。
</prompt>
<choice next="weather.vxml">天气预报</choice>
<choice next="stocks.vxml">股票市场</choice>
</menu>
</vxml>
2.6 <clear>
清除一个或多个框架项。下面的例子中,当输入不等于5时,清除“result”这个框架项,使控制重新回到“result”这个输入域。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<field name="result" type="number">
<prompt>3加2等于多少?</prompt>
<filled>
<if cond="result != 5">
算错了,重来一遍。
<clear namelist="result"/>
<else/>
算对了,祝贺你!
</if>
</filled>
</field>
</form>
</vxml>
2.7 <disconnect>
结束一次通话。在下面的例子中,输出提示“谢谢使用华琛公司语音系统。再见!”后,<disconnect>马上结束这次的通话。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<block>
<prompt>谢谢使用华琛公司语音系统。再见!</prompt>
<disconnect/>
</block>
</form>
</vxml>
2.8 <else>
用于<if>中的流程控制元素。在下面的例子中,当输入等于5时,输出提示“算对了,祝贺你!”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<field name="result" type="number">
<prompt>3加2等于多少?</prompt>
<filled>
<if cond="result != 5">
算错了,重来一遍。
<clear namelist="result"/>
<else/>
算对了,祝贺你!
</if>
</filled>
</field>
</form>
</vxml>
2.9 <elseif>
用于<if>中的流程控制元素,作用相当于编程语言中的if嵌套。在下面的例子中,当输入不等于字符串“天气预报”且输入等于字符串“股票市场”时,控制转向由<goto>的属性next所指向的文件。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<field name="service">
<grammar src="services.grxml" type="application/srgs+xml"/>
<prompt>
欢迎使用华琛公司语音服务系统。今天我能为您做什么?
了解今天的天气情况请说"天气预报";了解股市情况请说"股票市场"。
</prompt>
<filled>
<if cond="service == '天气预报'">
<goto next="weather.vxml"/>
<elseif cond="service == '股票市场'"/>
<goto next="stocks.vxml"/>
<else/>
<prompt>谢谢您使用华琛公司语音系统。再见!</prompt>
</if>
</filled>
</field>
</form>
</vxml>
2.10 <enumerate>
列举菜单选项。它指定了一个模板,顺序地应用于所有的菜单选项来自动产生一段提示。一般用到的变量有两个,_prompt和_dtmf,前者表示菜 单选项<choice>的提示,后者表示赋给菜单选项<choice>的dtmf序列。在下面额例子 中,<enumerate>自动产生了这样一个提示“需要天气预报服务,请说天气预报;需要股票行情服务,请说股票行情;”,并输出这个提示。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<menu>
<prompt>
<enumerate>
需要<value expr="_prompt"/>服务,请说<value expr="_prompt"/>;
</enumerate>
</prompt>
<choice next="weather.vxml">天气预报</choice>
<choice next="stocks.vxml">股票市场</choice>
</menu>
</vxml>
2.11 <error>
捕获一个error事件,它实际上是<catch event="error">的缩写,<help>、<noinput>、<nomatch>也是类似的情 况。在下面的例子中,当输入不等于字符串“1234567”时,error事件被捕获,并输出提示“对不起您输入了错误密码。”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<error>
<prompt>对不起您输入了错误密码。</prompt>
<disconnect/>
</error>
<field name="password " type="digits">
<prompt>请输入密码</prompt>
<filled>
<if cond="password != '1234567'">
<throw event="error"/>
<else/>
密码正确。
</if>
</filled>
</field>
</form>
</vxml>
2.12 <exit>
退出一次通话,并把控制交给解释器。与<disconnect>不同的是,<exit>把控制交给解释器后,解释器仍然可以做一些 事情,例如,播放最高一级的菜单给用户,或者挂机,或者把用户转接到人工服务,而<disconnect>则是产生一个挂机事件,并清空所有的进程。在下面的例子中,当输入不等于字符串“1234567”时,输出提示“密码错误。”,把控制交给解释器。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<field name="password " type="digits">
<prompt>请输入密码</prompt>
<filled>
<if cond="password != '1234567'">
密码错误。
<exit/>
<else/>
密码正确。
</if>
</filled>
</field>
</form>
</vxml>
2.13 <field>
在框架中声明一个输入域,它的属性name用来存储用户的输入。在下面的例子中,当输入匹配“number”语法时(例如输入“23”),用户的输入被存储在变量age中,并输出提示“你刚才说你有23岁。”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<field name="age" type="number">
<prompt>请告诉我你的年龄?</prompt>
<filled>
<prompt>你刚才说你有<value expr="age"/>岁。</prompt>
</filled>
</field>
</form>
</vxml>
2.14 <filled>
指定当输入域被填充以后的操作。在下面的例子中,<filled>指定了当输入与被填充后(例如输入“23”),系统应该输出提示“你刚才说你有23岁。”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<field name="age" type="number">
<prompt>请告诉我你的年龄?</prompt>
<filled>
<prompt>你刚才说你有<value expr="age"/>岁。</prompt>
</filled>
</field>
</form>
</vxml>
2.15 <form>
提示信息和接受数据的对话框架,是构成VoiceXML文档的主要元素。在下面的例子中,系统输出提示信息“欢迎使用华琛公司语音系统。”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<block>
<prompt>欢迎使用华琛公司语音系统。</prompt>
</block>
</form>
</vxml>
2.16 <goto>
把控制转向在同一个或不同文档中的对话。主要用于三种情况:
- 把控制转向同一框架的另外一个框架项,
<goto nextitem="block1"/>; - 把控制转向同一文档的另外一个框架,
<goto next="#form2"/>,下面的例子就是属于这种情况,控制由form1转向form2; - 把控制转向另一个文档,
<goto next="documengt2.vxml"/>。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form id="form1">
<block>
<prompt>你在form1中。</prompt>
<goto next="#form2"/>
</block>
</form>
<form id="form2">
<block>
<prompt>你在form2中。</prompt>
</block>
</form>
</vxml>
2.17 <grammar>
指定语音识别或DTMF语法,它可以是内部语法,也可以是外部语法。在下面的例子中,指定了外部语法文件是services.grxml,当输入匹配这个语法时(例如“天气预报”),系统输出“你要了解的是:天气预报”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<field name="drink">
<prompt>你要了解天气预报,还是股票市场?</prompt>
<grammar src="services.grxml" type="application/srgs+xml"/>
</field>
<filled>
<prompt>
你要了解的是:<value expr="drink"/>
</prompt>
</filled>
</form>
</vxml>
2.18 <help>
捕获一个<help>事件,它实际上是<catch event="help">的缩写,<error>、<noinput>、<nomatch>也是类似的情 况。在下面的例子中,当输入不等于字符串“1234567”时“help”事件被捕捉,并输出提示“对不起,您输入了错误密码。”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<help>
<prompt>对不起,您输入了错误密码。</prompt>
</help>
<field name="password " type="digits">
<prompt>请输入密码</prompt>
<filled>
<if cond="password != '1234567'">
<throw event="help"/>
</if>
</filled>
</field>
</form>
</vxml>
2.19 <if>
条件逻辑。在下面的例子中,当输入不等于“5”时,输出提示“算错了,重来一遍。”,并清空变量“result”,使控制重新回到输入域“result”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<field name="result" type="number">
<prompt>3加2等于多少?</prompt>
<filled>
<if cond="result != 5">
算错了,重来一遍。
<clear namelist="result"/>
<else/>
算对了,祝贺你!
</if>
</filled>
</field>
</form>
</vxml>
2.20 <initial>
在 进入一个双向交互式对话框架时申明初始对话逻辑,如果输入匹配指定的语法,则跳过相应的输入域。在下面的例子中,当输入匹配语法 “cityandprovince.grxml”时(例如输入“广东深圳”),则跳过输入域“province”和“city”,输出提示“您要查广东省 深圳市的天气预报”,否则依次进入输入域“province”和“city”,等待用户输入。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form id="weather_info">
<grammar src="cityandprovince.grxml" type="application/srgs+xml"/>
<initial name="start">
<prompt>您要查询哪里的天气预报</prompt>
</initial>
<field name="province">
<prompt>您要查询哪个省份的天气预报</prompt>
</field>
<field name="city">
<prompt>
您要查<value expr="province"/>省的哪个城市的天气预报
</prompt>
</field>
<block>
<prompt>
您要查<value expr="province"/>省<value expr="city"/>市的天气预报
</prompt>
</block>
</form>
</vxml>
2.21 <link>
在所有对话链接区域指定共有的控制转向,<link>有至少一个语法,当输入匹配<link>中的语法时,控制转 向<link>的属性next所指向的位置。在下面的例子中,当用户的输入匹配语法“services.grxml”时,控制转向文 档"“block.vxml”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<link next="block.vxml">
<grammar src="services.grxml" type="application/srgs+xml"/>
</link>
<form>
<field name="service" type="digits">
<prompt>请输入密码</prompt>
<filled>
您输入的是<value expr="service"/>。
</filled>
<//field>
</form>
</vxml>
2.22 <log>
生成调试信息,以便开发者调试程序,或分析程序的性能,它对解释器解释程序没有任何的副作用。在下面的例子中,系统生成调试信息“用户进入系统。”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form scope="document">
<block>
<log>用户进入系统。</log>
</block>
</form>
</vxml>
2.23 <menu>
定义菜单对话。在下面的例子中,当输入匹配菜单项之一,例如输入“天气预报”,则控制转向<choice>的属性next所指向的文件“weather.vxml”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<menu>
<prompt>
欢迎使用华琛公司语音服务系统。今天我能为您做什么?
了解今天的天气情况请说"天气预报";了解股市情况请说"股票市场"。
</prompt>
<choice next="weather.vxml">天气预报</choice>
<choice next="stocks.vxml">股票市场</choice>
</menu>
</vxml>
2.24 <meta>
定义一个元数据项,类似于在HTML中定义元数据。在下面的例子中,定义了三个元数据。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<meta name="maintainer" content="[email protected]"/>
<meta http-equiv="Expires" content="0"/>
<meta http-equiv="Date" content="Thu,12 Dec 2000 23:27:21 GMT"/>
<form>
<block>
欢迎使用华琛公司语音系统
</block>
</form>
</vxml>
2.25 <metadata>
定义元数据信息。
2.26 <noinput>
捕获一个<noinput>事件,它实际上是<catch event="noinput">的缩写,<error>、<help>、<nomatch>也是类似的情 况。在下面的例子中,当一段事件没有输入,系统就抛出<noinput>事件,并被捕捉,输出提示“对不起我没有听见。”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<noinput>
<prompt>对不起我没有听见。</prompt>
</noinput>
<field name="password " type="number">
<prompt>请输入密码</prompt>
<filled>
<if cond="password != '1234567'">
<prompt>输入密码错误。</prompt>
<else/>
<prompt>欢迎使用华琛公司语音系统。</prompt>
</if>
</filled>
</field>
</form>
</vxml>
2.27 <nomatch>
捕获一个<nomatch>事件,它实际上是<catch event="nomatch">的缩写,<error>、<help>、<noinput>也是类似的情 况。在下面的例子中,当输入没有匹配“number”语法时,系统就抛出<nomatch>事件,并被捕捉,输出提示“对不起,我没有听懂。 ”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<nomatch>
<prompt>对不起,我没有听懂。</prompt>
</nomatch>
<field name="password " type="number">
<prompt>请输入密码</prompt>
<filled>
<if cond="password != '1234567'">
<prompt>输入密码错误。</prompt>
<else/>
<prompt>欢迎使用华琛公司语音系统。</prompt>
</if>
</filled>
</field>
</form>
</vxml>
2.28 <object>
与系统扩展功能相结合的接口,通过它使VoiceXML平台可以使用用户定制的扩展功能。下面的例子中,“VoFTp”是用户定制的功能,引用它可以让VoiceXML平台能够从指定的FTP服务器下载指定的文件到指定的路径。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<block>将文件从指定服务器下载到指定文件</block>
<object name="download" classid="VoFTP">
<param name="ip" expr="'192.168.0.1'"/>
<param name="userid" expr="'anonymous'"/>
<param name="password" expr="'[email protected]'"/>
<param name="method" expr="'get'"/>
<param name="remotefile" expr="'/todownload.doc'"/>
<param name="localfile" expr="'downloaded.doc'"/>
<param name="fetchaudio" expr="'fetchaudio.wav'"/>
<param name="type" expr="'ascii'"/>
</object>
<block>
<if cond="download.status == 'success'">
<prompt>文件下载成功</prompt>
<else/>
<prompt>文件下载失败</prompt>
</if>
</block>
</form>
</vxml>
2.29 <option>
在一个输入域中声明一个供选择的选项。若一个输入域的输入选项比较简单,用这个元素比较方便。在下面的例子中,两个<option>在输入域 “service”中声明了两个选项,当输入匹配这两个选项时(例如输入按键“1”),系统输出提示“你刚才说天气预报。”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<property name="inputmode" value="dtmf"/>
<field name="service">
<prompt>
欢迎使用华琛公司语音服务系统。今天我能为您做什么?
了解今天的天气情况请说"天气预报";了解股市情况请说"股票市场"。>
</prompt>
<option dtmf="1" value="天气">天气预报</option>
<option dtmf="2" value="股票">股票市场</option>
<filled>
<prompt>你刚才说<value expr="service"/>。</prompt>
</filled>
</field>
</form>
</vxml>
2.30 <param>
<object> 或<subdialog>的参数,它声明了要传递给<object>或<subdialog>的参数的值。在下面的 例子中,七个<param>分别声明了要传递给“VoFTP”的七个参数的相应的值。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<block>将文件从指定服务器下载到指定文件</block>
<object name="download" classid="VoFTP">
<param name="ip" expr="'192.168.0.1'"/>
<param name="userid" expr="'anonymous'"/>
<param name="password" expr="'[email protected]'"/>
<param name="method" expr="'get'"/>
<param name="remotefile" expr="'/todownload.doc'"/>
<param name="localfile" expr="'downloaded.doc'"/>
<param name="fetchaudio" expr="'fetchaudio.wav'"/>
<param name="type" expr="'ascii'"/>
</object>
<block>
<if cond="download.status == 'success'">
<prompt>文件下载成功</prompt>
<else/>
<prompt>文件下载失败</prompt>
</if>
</block>
</form>
</vxml>
2.31 <prompt>
指定语音合成提示和声音文件输出。在下面的例子中,输出语音合成提示“欢迎使用华琛公司语音系统。”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<block>
<prompt>欢迎使用华琛公司语音系统。</prompt>
</block>
</form>
</vxml>
2.32 <property>
指定平台特性值以控制平台设置。关于平台特性的详细情况请参见http://www.w3.org/TR/voicexml20/#dml6.3。在下面的例子中,指定了平台的“bargein”属性的值,使系统的提示不能被打断。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<property name="bargein" value="false"/>
<block>
<prompt>欢迎使用华琛公司语音系统。</prompt>
</block>
</form>
</vxml>
2.33 <record>
录音,录音保存在<record>的属性name所声明的变量里。在下面的例子中,输出提示“在‘嘟’声后请录音。”,然后开始录音,并把录音保存在变量“msg”
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<record name="msg" beep="true" maxtime="10s" finalsilence="4000ms"
type="audio/x-wav">
<prompt timeout="5s">
在“嘟”声后请录音
</prompt>
</record>
<block>
<value expr="msg"/>
</block>
</form>
</vxml>
2.34 <reprompt>
捕捉一个事件后控制重新转向一个输入域时,指定这个输入域的新提示。在下面的例子中,当系统捕捉到<nomatch>时,输出提示“对不起我没有听懂。”,并指定重新提示,因此,控制重新转向输入域,会再次输出提示“请告诉我你的年龄?”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<field name="age" type="number">
<prompt>请告诉我你的年龄?</prompt>
<nomatch>
对不起我没有听懂。
<reprompt/>
</nomatch>
<filled>
<prompt>你刚才说你有<value expr="age"/>岁。</prompt>
</filled>
</field>
</form>
</vxml>
2.35 <return>
从子对话中返回,它结束了子对话框的运行,并把控制和数据返回给调用它的对话框。在下面的例子中,<return>把控制和数据“password”返回到调用它的对话框“main”,输出“密码是 1234567 。”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form id="main">
<subdialog name="result" src="#info">
<param name="parameter" value="密码"/>
</subdialog>
<block>
<prompt>密码是<value expr="result.password"/>。</prompt>
</block>
</form>
<form id="info">
<var name="parameter"/>
<var name="password"/>
<block>
<if cond="parameter=='密码'">
<assign name="password" expr="'1234567'"/>
</if>
<return namelist="password"/>
</block>
</form>
</vxml>
2.36 <script>
定义客户端的ECMAScript(JavaScript)模块。在下面的例子中,定义了一个求阶乘的JavaScript模块,输入一个数后(例如输入“4”),调用这个JavaScript模块,输出提示“4的阶乘是24”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<script>
<![CDATA[function factorial(n){return(n<=1)? 1:n * factorial(n-1);}]]>
</script>
<form>
<field name="fact" type="number">
<prompt>告诉我一个数,我将计算其阶乘。</prompt>
<filled>
<prompt>
<value expr="fact"/>的阶乘是<value expr="factorial(fact)"/>
</prompt>
</filled>
</field>
</form>
</vxml>
2.37 <subdialog>
调用另一个对话框作为当前对话框的子对话框,它有利于创建可重用的应用程序。在下面的例子中,对话框“main”调用了“info”作为子对话框,输出“密码是 1234567 。”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form id="main">
<subdialog name="result" src="#info">
<param name="parameter" value="密码"/>
</subdialog>
<block>
<prompt>密码是<value expr="result.password"/>。</prompt>
</block>
</form>
<form id="info">
<var name="parameter"/>
<var name="password"/>
<block>
<if cond="parameter=='密码'">
<assign name="password" expr="'1234567'"/>
</if>
<return namelist="password"/>
</block>
</form>
</vxml>
2.38 <subdialog>
向文件服务器上传数据。在下面的例子中,变量“company”被传到文件“process.asp”作处理,如果有多个变量要上传,用空格格开。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<var name="company" expr="'华琛公司'"/>
<block>
<submit namelist="company" next="process.asp"/>
</block>
</form>
</vxml>
process.asp:
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<block>
您传过来的公司名是<%=request.QueryString("company")%>
</block>
</form>
</vxml>
2.39 <throw>
抛出一个事件。可以是系统预定义的,如本例,<nomatch>、<noinput>、<help>等也是系统预定义的;也可以是程序定义的事件,如<throw event="weather"/>,抛出一个程序定义的事件“weather”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<error>
<prompt>对不起您输入了错误密码。</prompt>
<disconnect/>
</error>
<field name="password " type="digits">
<prompt>请输入密码</prompt>
<filled>
<if cond="password != '1234567'">
<throw event="error"/>
<else/>
密码正确。
</if>
</filled>
</field>
</form>
</vxml>
2.40 <transfer>
让解释器把呼入者连接到另外一个电话(即电话转接)或语音应用程序。在下面的例子中,解释器把呼入者转接到另一个电话83158433。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<transfer name="mycall" dest="tel:83158433" vop_greeting="greetings.wav"
vop_record="f:/record.wav"
transferaudio="fetchaudio.wav" connecttimeout="8s" maxtime="10000s"
bridge="true" vop_listen="false">
<filled>
<if cond="mycall == 'success'">
<prompt>已返回有效的按键值</prompt>
<elseif cond="mycall == 'far_end_disconnect'"/>
<prompt>远端已挂机</prompt>
<elseif cond="mycall == 'near_end_disconnect'"/>
<prompt>近端已挂机</prompt>
<elseif cond="mycall == 'busy'"/>
<prompt>转接的电话忙</prompt>
</if>
</filled>
</transfer>
</form>
</vxml>
2.41 <value>
在提示中插入一个值。在下面的例子中输出“我学习VoiceXML。”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<var name="verb" expr="'学习VoiceXML'"/>
<block>
我<value expr="verb"/>。
</block>
</form>
</vxml>
2.42 <var>
声明一个变量。在下面的例子中,声明了一个变量“verb”,并给它赋值“‘学习VoiceXML’”,本例输出提示“我学习VoiceXML。”。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<var name="verb" expr="'学习VoiceXML'"/>
<block>
我<value expr="verb"/>。
</block>
</form>
</vxml>
2.43 <vxml>
VoiceXML文档标识,它是VoiceXML文档最顶级的元素。
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<block>
欢迎使用华琛公司语音系统。
</block>
</form>
</vxml>
3 VoiceXML2.0脚本结构
3.1 基本结构
学习了基本的元素后,我们使用元素来实现脚本。
本章将简单介绍VoiceXML2.0脚本文件的结构,使初学者对VoiceXML有一个大概的了解。
现在让我们来看一个简单的例子:
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<block>
欢迎使用华琛公司语音系统!
</block>
</form>
</vxml>
当电话接通,用户将会听到由语音合成的“欢迎使用华琛公司语音系统!”。第1,2和8行是每个VoiceXML脚本文件都应该包含的;第3到第7行是一个对话表,用<from>…</form>标志;在该对话表中有一个块<block>…</block>, 其包含了要输出的内容。
如果不用语音合成功能,上面的例子还可以写成:
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<block>
<audio src="welcome.wav"/>
</block>
</form>
</vxml>
当电话一接通,用户将会听到预先录制好的语音文件welcome.wav的内容。
用 VoiceXML编写语音应用程序,不仅可以方便地实现语音文件以及文本的播放(通过语音合成的功能),而且还可以方便地实现按键输入以及语音输入(通过 语音识别的功能)。
VoiceXML定义两种基本输入方式:菜单<menu>和输入域<field>。
菜单将输入的内容列举出 来,并根据需要允许用户用按键或/和语音的方式进行输入。以下是一个用菜单接受用户输入的例子:
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<menu dtmf="true">
<prompt>
用户您好。请选择华琛为您提供的服务:
1 天气预报 2 股票市场
<choice next="weather.vxml">天气预报</choice>
<choice next="stocks.vxml">股票市场</choice>
</prompt>
</menu>
</vxml>
当电话接通,用户将会听到提示“用户您好。请选择华琛为您提供的服务:1 天气预报 2 股票市场”,并等待用户输入;当用户说“天气预报”或按键输入“1”后,系统将转向另一个VoiceXML脚本文件(定义天气预报的对话流)。第3行到第 10行定义了整个菜单;第4到第9行是提示<prompt>定义;第7和第8行列举出菜单项。
除了菜单方式之外,用输入域<field>也可以接受用户输入:
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<field name="inputitem">
<prompt>
用户您好。请选择华琛为您提供的服务:
1 天气预报 2 股票市场
</prompt>
<grammar mode="voice" root="item1">
<rule id="item1">
<one-of>
<item>天气预报</item>
<item>股票市场</item>
</one-of>
</rule>
</grammar>
<grammar mode="dtmf" root="item2">
<rule id="item2">
<one-of>
<item>1</item>
<item>2</item>
</one-of>
</rule>
</grammar>
<filled>
<if cond=" inputitem == '天气预报'">
<goto next="weather.vxml"/>
<else/>
<goto next="stocks.vxml"/>
</if>
</filled>
</field>
</form>
</vxml>
该例中<field>定义的输入流程与前面例子中<menu>定义的流程相同,即当电话接通,用户将会听到提示“用户您好。请选择 华琛为您提供的服务:1 天气预报 2 股票市场”,并等待用户输入;当用户说 “天气预报” 或按键输入“1”后,系统将转向另一个VoiceXML脚本文件(定义天气预报的对话流)。第9行到第16行和第17行到第24行分别定义了语音输入和按键输入的语法。该例中的语法本身出现在VoiceXML脚本文件中,这类语法称为在线语法。语法也可以不是在线语法,它们可以被放在一个独立的语法文件 中。
电话录音功能是实际应用系统中常常会遇到的。下面的例子给出如何用VoiceXML提供的录音元素实现电话录音功能:
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<record name="msg"
beep="true"
maxtime="10s"
finalsilence="4000ms"
type="audio/x-wav">
<prompt timeout="5s">
请在'嘟'声后留言。
</prompt>
</record>
<block>
<prompt>
您的留言是<value expr="msg"/>。
</prompt>
</block>
</form>
</vxml>
当电话接通,用户将会听到“请在‘嘟’声后留言”的提示,随后系统提示“嘟”声并等待用户留言;最长录音时间为10秒(maxtime=“10s”),当用 户停止说话4秒(finalsilence=“4000ms”)后系统停止录音,录音将被放在变量msg中;录音停止后用户将听到系统提示"您的留言是" 和录音内容。第4行到第9行是录音功能的定义;第10行到第14行播放提示和录音内容。
VoiceXML 不仅提供上述基本的输入输出功能,还提供了其它功能,如电话转接、强大的数据库接口、互联网接口、Javascript操作、对话流自由转向、模块化结构 等功能。除此之外,VoiceXML还提供了扩展接口<object>,使得其功能得到更为广泛的延伸。
显而易见,用VoiceXML编写一个电话语音应用系统,摆脱了传统的CTI技术的开发方法和模式。开发人员不需要了解语音板卡、交换机、语音合成、语音识 别等的编程细节,只需要把精力放在业务流程上。用VoiceXML不仅完全可以代替传统CTI技术所能完成的功能,而且还能完成用传统CTI技术难以实现 的功能。用VoiceXML开发语音应用系统周期短、对技术人员要求相对较低。基于VoiceXML开发出来的应用系统有很好的可扩展性、可维护性、可移植性、可重用性和开放性。
3.2 语音识别与语音合成
<menu>和<field>可以用来接受用户的语音输入。当用户通过说话的方式与系统进行交谈时,系统将根据脚本中提供的语法对用户的语音输入进行识别。系统根据识别得到的结果和脚本文件的定义决定下一步的操作。
在某些VoiceXML元素中允许出现要输出的文本,如<prompt>。有文件输出时会自动启动语音合成功能以将文本转换成语音并播放给用户。
3.3 VoiceXML与互联网的接口
VoiceXML中每个文件是通过URI访问的。因而,VoiceXML脚本文件、语音文件、语法文件、ASP、PHP文件和数据库等都可以置放在互联网中。
3.3.1 通过URI访问互联网中的VoiceXML脚本文件
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<block>
<goto next="http://vopromote/vxmls/book_examples/welcome.vxml"/>
</block>
</form>
</vxml>
welcome.vxml:
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<block>
欢迎使用华琛公司语音系统!
</block>
</form>
</vxml>
3.3.2 通过URI访问互联网中的语音文件
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<block>
<audio src="http://vopromote/vxmls/book_examples/fetchaudio.wav"/>
</block>
</form>
</vxml>
3.3.3 通过URI访问互联网中的语法文件
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<field name="drink">
<prompt>你要咖啡,牛奶,茶,还是什么都不要?</prompt>
<grammar src="http://vopromote/vxmls/book_examples/example_drinks.grxml"
type="application/srgs+xml"/>
<filled>
<prompt>
你要喝<value expr="drink"/>
</prompt>
</filled>
</field>
</form>
</vxml>
example_drinks.grxml:
<?xml version="1.0"?>
<grammar version="1.0" xmlns="http://www.w3.org/2001/06/grammar"
xml:lang="zh" root="DRINK" mode="voice">
<rule id="DRINK" scope="public">
<one-of>
<item>咖啡<tag>咖啡</tag></item>
<item>茶<tag>茶</tag></item>
<item>牛奶<tag>牛奶</tag></item>
<item>什么都不要<tag>什么都不要</tag></item>
</one-of>
</rule>
</grammar>
3.3.4 通过URI访问互联网中的ASP文件
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<block>
<goto next="http://vopromote/vxmls/book_examples/internet_asp.asp"/>
</block>
</form>
</vxml>
通过URI访问互联网中的PHP文件与访问ASP文件类似。 internet_asp.asp:
<?xml version="1.0"?>
<!DOCTYPE vxml SYSTEM "file:///VoPromote/deploy/config/vxml2.0.dtd">
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<%
dim greeting
greeting = "我在学习VOICEXML"
%>
<var name="greeting" expr="'<%=greeting%>'"/>
<block>
<value expr="greeting"/>
</block>
</form>
</vxml>
3.3.5 通过URI访问互联网中的数据库
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<block>
<goto next="http://vopromote/vxmls/book_examples/internet_database.asp"/>
</block>
</form>
</vxml>
internet_database.asp:
<?xml version="1.0"?>
<vxml version="2.0" xmlns="http://www.w3.org/2001/vxml">
<form>
<%
Set conn = Server.CreateObject("ADODB.Connection")
conn.open "driver={SQL Server};
server=your_database_server;
uid=your_uid;
pwd=your_pwd;
database=your_database_name"
command = "your_command"
Set rs = conn.Execute(your_command)
%>
<var name="username_one" expr="'<%=rs("xxxxx")%>'"/>
<var name="accounts_one" expr="'<%=rs("xxxxxxxx")%>'"/>
<var name="password_one" expr="'<%=rs("xxx")%>'"/>
</form>
</vxml>
3.4 VoiceXML与数据库的接口
VoiceXML通过其所支持的脚本语言,如ASP、PHP、CGI等访问多种数据库。
在windows操作系统中可以为各种windows支持的数据库连接设置数据源。如果已经为数据库连接设置了相应的数据源,可以这样访问数据库:
Set conn = Server.CreateObject("ADODB.Connection")
Conn.open "dsn=odbc_name;uid=your_uid;pwd=your_pwd"
另外也可以如2.4.5那样直接指定数据库驱动来访问需要的数据库。 总之,ASP、PHP、CGI等所支持的各种访问数据库的接口,VoiceXML都支持,因为VoiceXML支持这些脚本语言。
3.5 小结
用 VoiceXML给电话语音应用系统的开发带来全新的概念。开发人员不需要了解语音板卡、语音识别、以及语音合成的API接口,可以任意选择接入不同的数 据库,可以不用把时间放在繁琐的编程细节,从而只需把精力放在应用流程的定义。VoiceXML简单易学,尤其是对于有WEB开发经验的开发人员更是轻松。
可以访问个人知乎阅读更多文章:易哥(https://www.zhihu.com/people/yeecode),欢迎关注。