VoiceXML 2.1 Development Guide Home  |  Frameset Home

  tutorial Screen Scraping   |  TOC  |  Final Notes  

Tutorial: Cookies and VoiceXML

The time comes when we will want to stop messing around with tutorials and lessons, and start writing a real application to make you wildly rich, and the envy of all the kids on the block. However, if you are reading this, the time is not now. But, the information in this Tutorial will make us a lot better prepared to deal with two common subjects; how to use cookies, and how to capture a spelled utterance from your callers.


A Few Notes...

This Lesson assumes that you are at least marginally familiar with the Cold Fusion markup language, and also assumes that you have a host that supports .cfm files. Remember, the free Voxeo webhosting offers no support for ColdFusion, or any other form of server side markup.

Be advised that VoiceXML  only supports session cookies, and not persistent cookies. As long as your cookie HTTP header doesn't set expiration, then you should be covered like a 'beretta sombrero'. And be forewarned, there will be no clever mentions regarding cookies of the chocolate chip variety in this Lesson. It's just too easy of a joke, and not very funny at all. Give us some credit, cake is tastier anyhow.


Step 1: Writing the VoiceXML code

By now, we most definitely don't need a rehash on how we go about authoring a VoiceXML document with a voice recognition field, so we will just whip it out, complete with all the fancy stuff:


<?xml version="1.0" encoding="utf-8" ?>
<vxml version="2.1">

<meta name = "maintainer" content="yourEmail@somewhere.com"/>

<link next="F_Name.cfm">
  <grammar type="text/gsl"> [start over] </grammar>
</link>

<form id="F1">
  <field name="F_name">

  <grammar src="FName.xml" type="application/grammar-xml"/>
  <prompt>
    Welcome to the login page for our application.
    Please spell your first name so we can verify your credentials.
  </prompt>

  <nomatch>
    <prompt>
      Sorry, i didnt get that.
      Please spell your first name.
    </prompt>
  </nomatch>

  <noinput>
    <prompt>
      Look buddy, I dont have all day, and I dont recognize
      M to the A double T as a valid first name.
      Spell your first name, or quit wasting my time.
    </prompt>
  </noinput>

  <filled>
    <submit next="L_Name.cfm" namelist="F_name"/>
  </filled>

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


A few things that you will note, is that we have a <link> grammar at the <vxml> level, which will take a user back to the start of the application, regardless of where or when he utters the command in the <link> grammar. In subsequent documents, we will want to make sure that we reference this file as the application root in order to make this link active throughout the scope of the application.

Once we gather a caller's first name in this page, we are going to <submit> the results to our next page, which just so happens to gather a caller's last name. In looking at this next document, you will doubtlessly find it eerily familiar:


<?xml version="1.0" encoding="utf-8" ?>
<vxml version="2.1" application="F_Name.cfm">

<meta name = "maintainer" content="yourEmail@somewhere.com"/>

<form id="F2">
  <field name="L_name">
  <grammar src="LName.xml" type="application/grammar-xml"/>

  <prompt>
    Okay, great. Now spell your last name, and we will be on our way.
  </prompt>

  <nomatch>
    <prompt>
      Sorry, i didnt get that.
      Please spell your last name.
    </prompt>
  </nomatch>

  <noinput>
    <prompt>
      Look buddy, I dont have all day.
      Spell your last name, or quit wasting my time.
    </prompt>
  </noinput>

  <filled>
    <submit next="Finish.cfm" namelist="L_name"/>
  </filled>
  </field>
</form>
</vxml>


See, I told you it would look familiar. As promised, we have referenced the 'F_name.cfm' document within the 'application' attribute of the 'vxml' element, so that our link grammar is active in this document as well. The rest of the code is pretty much unchanged, except this time, we are throwing you a curve ball and referencing the 'x-nuance-lastnamespelling' grammar instead. It's pretty tricky, but try and keep up, okay?


Step 2:  The Application.cfm Document

Since we now have our user input portion of the code completed, we can now focus on implementing some CF session variables, and adding cookies into the mix. If we paid attention to Lesson 17, then we know the basics of creating an Application.cfm file, (this is entirely different from a VoiceXML application root document!), which we will need in order to set a session cookie. We will start off by nesting everything within our file within <CFSILENT> tags, which will ensure that the ColdFusion doesn't insert any whitespace to our XML documents:


<CFSILENT>
</CFSILENT>


Next, we will add the <CFAPPLICATION> tag, along with it's accompanying SESSIONMANAGEMENT and SETCLIENTCOOKIES attributes. While we are at it, let's also add the <CFCOOKIE> tag to add support for a session cookie in our application. This last is very important when using cookies with ColdFusion; if we don't set the 'CFID' and 'CFTOKEN' in the Application.cfm file, then we will have persistent cookies set by the ColdFusion Server. And as we all know, persistent cookies aren't kosher at all.


<CFSILENT>
<CFAPPLICATION NAME="MyApp" SESSIONMANAGEMENT="yes" SETCLIENTCOOKIES="Yes">
  <CFCOOKIE NAME="CFID" VALUE="#CFID#"/>
  <CFCOOKIE NAME="CFTOKEN" VALUE="#CFTOKEN#"/>

</CFSILENT>


After this, we will want to insert some caching headers, so that our file is fetched fresh every time:


<CFSILENT>
<CFAPPLICATION NAME="MyApp" SESSIONMANAGEMENT="yes" SETCLIENTCOOKIES="Yes">
  <CFCOOKIE NAME="CFID" VALUE="#CFID#"/>
  <CFCOOKIE NAME="CFTOKEN" VALUE="#CFTOKEN#"/>

  <CFHEADER NAME="Cache-Control" VALUE= "no-cache">
  <CFHEADER NAME="Expires" VALUE="#Now()#">

</CFSILENT>



Lastly, we are now going to set up our session variables. Since we are using the <submit> element to pass VoiceXML variables to the ColdFusion side of things, we need to set up some logic in the Application.cfm file to recognize and catch these querystring values, and then assign them to ColdFusion session variables. Check out the highlighted code below:


<CFSILENT>
<CFAPPLICATION NAME="MyApp" SESSIONMANAGEMENT="yes" SETCLIENTCOOKIES="Yes">
  <CFCOOKIE NAME="CFID" VALUE="#CFID#"/>
  <CFCOOKIE NAME="CFTOKEN" VALUE="#CFTOKEN#"/>

  <CFHEADER NAME="Cache-Control" VALUE= "no-cache">
  <CFHEADER NAME="Expires" VALUE="#Now()#">

  <CFPARAM NAME="session.F_name" DEFAULT=""/>
    <CFIF isdefined('url.F_name')>
<CFSET session.F_name=url.F_name/>
    </CFIF>

  <CFPARAM NAME="session.L_name" DEFAULT=""/>
    <CFIF isdefined('url.L_name')>
<CFSET session.L_name=url.L_name/>
    </CFIF>


</CFSILENT>



Essentially, what we are doing is instantiating empty session variables:


  <CFPARAM NAME="session.F_name" DEFAULT=""/>


If there is an existing querystring value for 'F_name' or 'L_name', then they will be assigned as session variables in our code:


  <CFPARAM NAME="session.F_name" DEFAULT=""/>
    <CFIF isdefined('url.F_name')>
<CFSET session.F_name=url.F_name/>
    </CFIF>



Pretty easy, right? Now all that remains is to write out our final page, which will output the resultant session variable values.

Step 3:

Our last page is going to be similar to our first two VoiceXML documents, but we are going to access our ColdFusion session variables, so we will need to have this nested within <CFOUTPUT> elements. In addition, we also want to have the ability for a caller to re-enter the information if there has been a recognition mistake, and the interpreter gets either of the names wrong:


<?xml version="1.0" encoding="utf-8" ?>
<vxml version="2.1" application="F_Name.cfm">

<meta name = "maintainer" content="yourEmail@somewhere.com"/>

<CFOUTPUT>
<form id="F3">

  <field name="confirm" type="boolean">


    <prompt>
        The Cold Fusion session variables tells me that your name is
        #session.F_name#  #session.L_name# , is that right?.
    </prompt>
 

  <filled>
    <if cond="confirm == true">

    <prompt>
        Okay, #session.F_name#. Thanks for calling.
    </prompt>

    <else/>

    <prompt>
        Okay then, we will start from the beginning.
    </prompt>

    <goto next="F_name.cfm"/>
    </if>

  </filled>
  </field>
</form>
</CFOUTPUT>
</vxml>



Step 5: Our XML grammar files

The next new thing you will see in the code below is the 'x-nuance-firstnamespelling' built in grammar. This grammar is the proverbial cat's pajamas, bee's knees, the hassle's hoff. It allows you to spell a name, using natural, alphabetical speech, without resorting to requiring a military alphabet input from your callers. And it's pretty darned accurate, too, regardless of whether your name is 'Joey' or 'Mujibur'.

When using a Nuance 'x-grammar' file, we need to create a simple XML grammar wrapper for it. When constructing a wrapper for your x-nuance grammars, keep two things in mind. Firstly, you need to reference the platform grammar by specifying a <ruleref> with the following syntax:


<ruleref uri="builtin:x-nuance-(WHATEVER)"/>


Secondly, you must make absolutely certain that your return slot within the <tag> element matches up with the field slot itself:


<field name="F_name">

<tag><![CDATA[ <F_name $return> ]]> </tag> 

This being said, let's take a peek at our XML grammar wrappers that we will need for this tutorial:


FName.xml

<?xml version= "1.0"?>
<grammar xmlns="http://www.w3.org/2001/06/grammar"
        xml:lang="en-US"
        root="MYRULE">

  <rule id="MYRULE">
      <one-of>
        <item>
<ruleref uri="builtin:x-nuance-firstnamespelling"/>
    <tag><![CDATA[ <F_name $return> ]]> </tag> 
        </item>   
      </one-of>
    </rule>
</grammar>


LName.xml

<?xml version= "1.0"?>
<grammar xmlns="http://www.w3.org/2001/06/grammar"
        xml:lang="en-US"
        root="MYRULE">

  <rule id="MYRULE">
      <one-of>
        <item>
<ruleref uri="builtin:x-nuance-lastnamespelling"/>
    <tag><![CDATA[ <L_name $return> ]]> </tag> 
        </item>   
      </one-of>
    </rule>
</grammar>



Step 6: upload, and try it out


  Motorola source code.

What was just covered:




  ANNOTATIONS: EXISTING POSTS
awirtz
8/30/2005 2:11 PM (EDT)
In the last name VXML page, your nomatch prompt mentions _first_ name.

You are berating callers just for trying to say "M to the A double T?"  You have no idea...  (well, maybe you do but are just too nice to corrupt the dreams of the uninitiated and impressionable by revealing the true limits of caller stupidity)
MattHenry
8/30/2005 2:48 PM (EDT)
Hiya Aaron,

Thanks for the catch; I have corrected this oversight in our documentation.

~ M-A to the double T Henry
danielvinson
2/21/2007 3:38 AM (EST)
Hiya

Is there a version of this code that can be used on a static host i.e. the Voxeo server or do I have to arrange a CF server.

Just trying to improve the accuracy of spelling a word.

Thanks

Daniel
VoxeoBrian
2/21/2007 2:08 PM (EST)
Hello,

You certainly would not have have to pass the variables via submit to a cold fusion server, you can simply implement this within the filled element.

<prompt>
          You said <value expr="F_name"/>
        </prompt>

I hope this helps to clarify this for you, if you need further assistance please do let us know, we are more then happy to help!

Cheers

Brian

login

  tutorial Screen Scraping   |  TOC  |  Final Notes  

© 2003-2008 Voxeo Corporation  |  Voxeo IVR  |  VoiceXML & CCXML IVR Developer Site