voxeo ccxml voicexml 笔记

voxeo开发文档

https://evolution.voxeo.com/docs/quickStart.jsp

w3c voicexml2.0规范 http://www.w3.org/TR/voicexml20/ 

ccxml和voicexml的区别

VoiceXML
          VXML可以理解为另外一种表示语言,类似于HTML和WML。它是一种表述对话(dialog)的语言,用来控制业务过程中的人机交互过程,适用于面向电话、手机等终端设备的语音应用,例如自动客户服务、自助查询系统、个人消息系统等。
         将VoiceXML与HTML对比,就能很容易理解了。浏览器解释后,HTML表示的内容是以文字图像方式显示在屏幕上的,VoiceXML的内容是以语言的方式播放给用户的。HTML接收用户的文字输入和鼠标点击,VoiceXML接受用户的语音输入,进行语音识别,或者是通过电话按键输入DTMF数据。
         VoiceXML是一种独立的语言,不能内嵌到现有的web语言中(如HTML,WML)。
         VoiceXML--语音扩展描述语言是由AT&T、IBM、Lucent Technologies、以及Motorola通过W3C协会于2000年联合推出的电话语音应用系统标准,是为语音应用制订的基于XML的语音可扩展标记语言。有了VoiceXML,互联网信息从此能够以语音的方式流向公用电话网,从而使互联网服务得以延伸到电话用户。VoiceXML彻底改变了传统的CTI(计算机电话集成系统) 的开发模式和应用范围,使公用电话网、语音处理技术、以及互联网有机地结合为一体,架起了电话用户与Web对话的桥梁。
         VoiceXML的目的是用来控制语音方式的人机交互过程的,因而它缺乏对呼叫的控制能力。例如会议、呼叫控制、建立呼叫、拒绝呼叫等等都无法实现。

CCXML
         针对VoiceXML在呼叫控制方面的不足,CCXML补充了这部分的功能。它能够发起呼叫、过滤和路由进入的呼叫、处理外部的异步事件。并且它能支持多方会议,可以将VoiceXML实例作为参与者加入会议,并控制VoiceXML的执行和停止。与VoiceXML类似,由CCXML浏览器负责解释执行CCXML文档。
         CCXML可以独立使用,但很多情况下是与VoiceXML配合使用,CCXML控制整个呼叫模型,VoiceXML控制每个呼叫中的用户交互。单纯的VoiceXML是无法实现电话QQ之类的涉及到多方通话的业务的,利用CCXML就有可能实现了。

参见:http://hi.baidu.com/ttlove%B6%A1%B6%A1/blog/item/c6c184c4a71350aa8326ac56.html

还有一个CallXML应该是voxeo自己开发的。

disconnect与exit不同,前者更适合挂断电话,后者交由voice引擎处理,在voxeo平台上就不发事件(但是会触发dialog.exit)。

The <disconnect> element will throw a 'connection.disconnect.hangup' event, while the <exit> element will NOT throw this event.

与tropo不同,这里需要自己在voicexml中catch这个事件来做出进一步处理。

<?xml version="1.0" encoding="UTF-8"?>

<vxml version = "2.1">

  <catch event="connection.disconnect.hangup">
    <submit next="MyCleanupPage.jsp" namelist="var1 var2"/>
    <exit/>
  </catch>

  <form>
    <field name="dummy">

      <property name="timeout" value="1s"/>
      <!-- set the 'noinput' timeout to 1 second -->

      <prompt>
        Thanks for calling, you may now hang up.
      </prompt>

      <!-- create a 'garbage' grammar that will never, EVER get a match -->
      <grammar> [(kathy bates is really hot)] </grammar>

      <filled>
        <prompt> no way this will ever happen, babycakes. </prompt>
      </filled>

      <noinput>
        <disconnect/>
      </noinput>

    </field>
  </form>
</vxml>

用户挂断事件触发顺序:

ccxml 中connection.disconnected事件

当前voicexml中的connection.disconnect.hangup事件

ccxml 中dialog.exit事件

上面的顺序我还不能确定,从多次测试日志来看,都是先ccxml的再dialog的disconnect,但是我看日志似乎并不能保证顺序,但是dialogexit绝对是在最后触发。

voicexml使用disconnect元素事件触发顺序:

当前voicexml中的connection.disconnect.hangup事件(事件中无论是否使用exit都会退出当前dialog)

ccxml 中dialog.exit事件

注意到上面没有触发ccxml的connection.disconnected事件

电话也没真正的挂断,所以需要在ccxml 中dialog.exit事件中使用ccxml的<disconnect />来挂断当前电话。

当时用了<disconnect />时再会触发ccxml的connection.disconnected事件。

对外呼叫,需要另外申请token:http://www.vxml.org/t_15.htm

开始呼叫请求参数:

session.calledid=999xxxxx //这可以认为是appid,见http://www.vxml.org/t_7.htm

session.virtualplatform=Staging

session.parentsessionid=3eb50832ca7a2104fec96deb811eeb22

session.sessionid=6949a5eb396caf6d2f250a870dea5e50 //

session.accountid=12345678

session.callerid=abc //呼叫方id,对于skype呼叫是skype账号,对于电话则是电话号码,竟然不带区号(+1)?

 

对于record元素,以下为例:

<?xml version="1.0" encoding="UTF-8"?>
<vxml version="2.1">
	<script>
		<![CDATA[
           function hasSlot()
           {           
            return undefined != application.lastresult$ && undefined != application.lastresult$.interpretation;
           }
          ]]>
	</script>

	<var name="input" />
	<var name="record" />
	<form id="F1">
		<!-- ***************************************************************** -->
		<!-- for purposes of simplicity, we will use the built-in boolean type -->
		<!-- note that no grammar construct is needed -->
		<!-- ***************************************************************** -->

		<record name="input_record" beep="true" maxtime="10s"
			finalsilence="4000ms" type="audio/x-wav">
			<prompt>
				say yes or no here to test the built in boolean grammar
			</prompt>
			<grammar type="application/grammar+xml" root="MAIN"
				xml:lang="en-us">
				<rule id="MAIN">
					<one-of>
						<item>
							yes
							<tag>out.slot = "yes"</tag>
						</item>
						<item>
							no
							<item repeat="0-1">nothing</item>
							<tag>out.who = out + "no"</tag>
						</item>
					</one-of>
				</rule>
			</grammar>

			<filled>
				<if
					cond="hasSlot()">
					<assign name="input"
						expr="application.lastresult$.interpretation" />
					<else />
					<assign name="input" expr="'NO_MATCH'" />
				</if>

				<assign name="record" expr="input_record" />
				<goto next="#frmGO" />
			</filled>
			<noinput>
				<assign name="input" expr="'NO_INPUT'" />
				<goto next="#frmGO" />
			</noinput>
			<nomatch>
				<assign name="input" expr="'NO_MATCH'" />
				<assign name="record" expr="input_record" />
				<goto next="#frmGO" />
			</nomatch>
		</record>
	</form>
	<form id="frmGO">
		<block>
			<submit namelist="input record" method="post"
				next="index.vxml" />
		</block>
	</form>
</vxml>

这个例子里包含了几个知识点:

1: ECMAScript

2:record包含grammar与识别赋值

3:grxml语法

4:识别结果赋值与影子变量

5:多个form,form提交与跳转

6:变量声明

 

下面逐一讲解:

1: ECMAScript

voicexml浏览器下的脚本,与javascript不是等同的。上例中我定义了个函数hasSlot,来判断是否存在被语法识别的结果。使用CDATA避免转移,如果直接用<if>元素判断则要将&&转变为&amp;&amp; 注意javascript种常见的!!application.lastresult$写法行不通,不能进行类型转换。

2:record包含grammar与识别赋值

一般grammar是放在field标签下,那么grammar的识别结果是赋值到了field属性的name变量中的,record下可以包含grammar但是record的name属性是保存录音的,当form提交时如果包含了record的name的值,则会以multipart/form-data方式提交,将record流包含在请求中。那么此时grammar的值就需要通过application级变量来获得。

变量作用域 参见http://www.3ucs.com/3ucs/VoiceXML2_0/VoiceXML5.1.htm

   VoiceXML使用ECMAScript作用域链,允许在应用的不同层次中声明变量。例如,在文档的作用域中声明的变量在该文档的任何地方都可以引用。而在<catch>元素中声明的本地变量只能在该<catch>元素中被引用。为了保护各个作用域变量的语义,所有的ECMAScript变量都要声明。使用没有声明的变量会导致一个ECMAScript错误,并抛出error.semantic事件。
    变量有如下几个作用域:
session这是一些只读的变量,在整个用户会话期间都是可用的。它们由解释器环境声明并设置。在VoiceXML文档中不能再声明新的session变量。见5.1.4节。
application这是一些由<var>元素和<script>元素声明的变量,且<var>元素和<script>元素都是应用根文档的<vxml>元素的子元素。这些变量在加载应用根文档时被初始化。在应用根文档被加期间,这些变量都是存在的,且在应用根文档和应用叶文档中都可以访问它们。注意,当在应用根文档中执行时,document.x和application.x是等价的。
document这是一些由<var>元素和<script>元素声明的变量,且该<var>元素和<script>元素都是该文档的<vxml>元素的子元素。这些变量在加载文档时被初始化。在文档被加期间,这些变量都是存在的,且只能在该文档中访问它们。除非该文档是应用根文档,在这种情况下,在应用根文档和应用叶文档中都可以访问它们。
dialog每个dialog(<form>元素或<menu>元素)都有一个dialog作用域,当用户访问该dialog时,该作用域才存在。Dialog变量是由<var>元素和<script>元素声明的变量,且该<var>元素和<script>元素都是<form>元素或<menu>元素的子元素;Dialog变量也可以是由各种form item声明的变量。<form>元素的<var>子元素和<script>子元素在该<form>元素被首次访问时初始化。<var>元素里面的可执行内容在执行可执行内容时被初始化。Form item变量在该form item被选定时初始化。
(anonymous)每个<block>元素,<filled>元素,和<catch>元素定义了一个新的anonymous作用域。在这些元素中声明的变量的作用域即为anonymous 。它们只能在相应的<block>元素,<filled>元素,或<catch>元素中被引用。
    下面的图表就是作用域层次:
voicexml-scope

上例中就是使用了 application.lastresult$[i].interpretation这个ECMAScript变量,它包含了这次识别的语义解释,详见http://www.w3.org/TR/voicexml20/#dml3.1.5

3:grxml语法 4:识别结果赋值与影子变量

srgs语法输出匹配 参见http://www.w3.org/TR/speech-grammar/

上例中使用的是srgs的grxml形式,其规范很多,针对上例,gxml中在用户说yes时会复制out.slot属性为yes,而当用户说no时会赋值out.who为 out + “no”,这里out指代输出,slot和who使我自定义的slot属性,用户说yes时提交参数input就会是input.slot = yes,说no时提交参数就会是input.who=no,看到没,我只要求提交input 参数,但是voicexml引擎却将input作为一个数据对象,添加了识别时grxml添加的属性值。

如果不用tag,形如:

/>

<item> yes

</item>

<item> no <item repeat="0-1">nothing</item>

</item>

那么用户说yes则就提交input=yes,用户说no就提交input=no。

参见http://www.3ucs.com/3ucs/VoiceXML2_0/VoiceXML3.6.htm

5:多个form ,form提交与跳转

一个文档可有多个form但是提交还需要用submit,form的id可作为跳转标记,使用goto标签。

一个form中的field变量别的form是不可见的,所以使用var标签申明document级别变量一边传递值。

6:变量声明

尽量不要变量重名,下级变量会覆盖上级变量。

 

在Tropo中有signal的概念,但是voicexml是做不到这点的,要实现signal,还要ccxml的配合:

http://docs.voxeo.com/ccxml/1.0-final/frame.jsp?page=sendevent_ccxml10.htm

http://docs.voxeo.com/ccxml/1.0-final/frame.jsp?page=ccxml10_passtovxml.htm

ccxml无法向voicexml发送事件,而一旦使用dialogstart开始voicexml过程,每个voicexml dialog的goto,submit等标签提交会继续执行提交返回的下一个dialog,除非使用exit来交还控制给ccxml。所以如果signal在每次voicexml提交后都有新的自定义事件怎么处理?

可通过http请求设置当前ccxml的变量表明当前的事件

定义两个自定义事件:

setcur_event:此事件将当前会话的signal列表存储在变量中。

trigger_event:此事件将传入的参数如上面设置的当前signal变量类表比对,如果匹配则触发对应的事件。

 

在voxeo平台上我还遇到这么个问题,如下代码:

test.vxml

<?xml version="1.0" encoding="UTF-8"?> 

<vxml version = "2.1"> 

<meta name="author" content="Matthew Henry"/> 
<meta name="copyright" content="2005 voxeo corporation"/> 
<meta name="maintainer" content="[email protected]"/> 

<form id="F1"> 

  <block name="B_1"> 
    <prompt> preparing to go to another page.</prompt>    
    <goto next="test.vxml" maxage="5000" maxstale="5000" 
          fetchtimeout="10s"/> 
  </block> 

</form> 
</vxml>

可以看到,我想让其说一句话后继续跳到本页面test.vxml。结果是什么也听不到,一直循环跳转,我试过submit,audio,一个form跳到另一个form,都是这样,最后才搞清楚原来这种情况下,voxeo会预加载next中的页面,那么如果next和本页面相同就导致了循环儿什么都不执行。这应该是voxeo的bug。

 

它这平台太脆弱了,如果在event="error.*"事件中出错的话,就导致了递归错误,弄得debugger一直刷,我即使把程序删掉了还是这样,亏得它的服务器不垮。

ccxml中的EMCscript:

打日志:

ccxmllog

 

在event="error.*"事件中,可获得error相关信息:

event$.name 错误名称

event$.reason 错误原因

<block><prompt>结构最好放在field 中或是record中,否则voxeo直接忽略。

当使用ccxml dialogterminate结构中断当前dailog时,会触发当前dialog中的connection.disconnect.hangup事件。这不知是个bug还是什么,愚蠢之极。

 

fetchtimeout 需要和maxage,maxstale配合使用才起效果,而且建议以毫秒为单位

<goto next="#form1" fetchtimeout="100000" maxage="100000" maxstale="20000"/>

 

只允许dtmf模式:

根节点下设置 <property name="inputmodes" value="dtmf" />


Total views.

© 2013 - 2018. All rights reserved.

Powered by Hydejack v6.6.1