Fortune Teller

What do you see in your future? Ask the Fortune Teller. This simple application demonstrates the use of Javascript to perform most of Fortune Teller's internal workings.

Try It!
  1. Set your Application URL to http://studio.247-inc.net/library2/code/ex-115/index.vxml
  2. Call the number shown in VXML Tools page
  3. Sign in, and play!

The Fortune Teller user interface is largely encapsulated within a single CFortuneTeller class. The class is contained in an external file, fortuneteller.js, and sourced into the voice application via the script element.

An instance of the CFortuneTeller class is created at document scope, and since this application doesn't transition to other documents during execution, the object stays in scope for the duration of the application.

The first time the main form is executed, it plays the prompt within the block element. Subsequent execution of the main form does not play this prompt because the block's guard condition is satisfied.

The prompt, noinput, and nomatch elements contain code that requests a random prompt from the CFortuneTeller class. The prompt is returned as a JavaScript object that contains two properties - wav and tts. The wav property contains a string representing the path to a recorded audio file. The tts property contains the corresponding prompt text. The text is played back to the user only if the recorded audio cannot be fetched.

If the user says nothing, the noinput handler is executed. After the third noinput, the user is returned to the main menu. If the user says something, the nomatch is highly likely to be executed because the grammar contains a phrase the user is unlikely to utter. If, by some chance, the user's utterance is recognized, the filled element clears the form item variable question causing the VoiceXML interpreter to resume form interpretation.

The VoiceXML code for this example follows:

<?xml version="1.0"?>
<!-- 
Tellme Studio Code Example 115 
Copyright (C) 2000-2006 Tellme Networks, Inc. All Rights Reserved. 

THIS CODE IS MADE AVAILABLE SOLELY ON AN "AS IS" BASIS, WITHOUT WARRANTY 
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, 
WARRANTIES THAT THE CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A 
PARTICULAR PURPOSE OR NON-INFRINGING. 

    The Tellme Fortune Teller
    
-->
<vxml version="2.0">

<script src="fortuneteller.js"/>

<script>
// instantiate the Fortune Teller class
var oFortuneTeller = new CFortuneTeller();
</script>

<form id="main">
  
   <!-- play intro -->
   <block>
      <audio src="welcome.wav">Welcome to the Tellme Fortune Teller.</audio>
      <break time="500ms"/>
   </block>

   <!-- no grammar, so anything not a universal triggers a nomatch -->
   <field name="question">
     
     <grammar mode="voice"
              root="root_rule"
              tag-format="semantics/1.0"
              type="application/srgs+xml"
              version="1.0"
              xml:lang="en-US">
       <rule id="root_rule" scope="public">
         <item>
           <one-of>
             <item>
               no grammar
             </item>
           </one-of>
           <tag>out.question = "nogrammar";</tag>
         </item>
       </rule>
     </grammar>


     <prompt>
       <var name="oPrompt" expr="oFortuneTeller.getPrompt()" />	
       <audio expr="oPrompt.wav"><value expr="oPrompt.tts"/></audio>
     </prompt>

     <!-- nomatch is the expected behavior in this case -->
     <nomatch>
       <var name="oAnswer" expr="oFortuneTeller.getAnswer()" />	
       <audio expr="'reply-short/' +  oAnswer.wav">
          The Fortune Teller says... <value expr="oAnswer.tts"/>
       </audio>
       <break time="1s"/>
       <reprompt/>
     </nomatch>

     <noinput count="1">
       <var name="oNoinput" expr="oFortuneTeller.getNoinput()" />	
       <audio expr="oNoinput.wav"><value expr="oNoinput.tts"/></audio>
       <break time="300ms"/>
       <audio src="reprompt1.wav">Ask a yes or no question.</audio>
     </noinput>

     <noinput count="2">
       <var name="oNoinput" expr="oFortuneTeller.getNoinput()" />	
	 <audio expr="oNoinput.wav"><value expr="oNoinput.tts"/></audio>
	 <break time="300ms"/>
	 <audio src="reprompt2.wav">Please ask your yes or no question!</audio>
     </noinput>

     <noinput count="3">
       <var name="oNoinput" expr="oFortuneTeller.getEject()" />	
       <audio expr="oNoinput.wav"><value expr="oNoinput.tts"/></audio>
       <break time="500ms"/>
       <exit/>
     </noinput>

     <filled>
       <!-- user could say "no grammar" -->
       <clear namelist="question" />
     </filled>

   </field>
    
</form>

</vxml>


The JavaScript code for this example follows:

//
// Tellme Fortune Teller Javascript code
//

// Fortune Teller class
function CFortuneTeller()
{
   // the following member variables are arrays of associative arrays (aka objects, aka hash tables)
   // each associative array consists of a path to a recorded audio file (wav) and text (tts).
   
   // array of prompt tuples
   this._prompts = [
     {"wav" : "prompt1.wav", "tts" : "What question brings you to seek the wisdom of the Fortune Teller?"},
     {"wav" : "prompt2.wav", "tts" : "What is your question, O supplicant?"},
     {"wav" : "prompt3.wav", "tts" : "Oooh, the Fortune Teller senses that something is on your mind.  What is it?"}
   ];
  
   // array of noinput tuples
   this._noinputs = [
     {"wav" : "noinput1.wav", "tts" : "The Fortune Teller is extremely busy!"}, 
     {"wav" : "noinput2.wav", "tts" : "The Fortune Teller has a full line of waiting supplicants and would still like to " +
		"play a few rounds of pool before going to bed."}, 
     {"wav" : "noinput3.wav", "tts" : "Don't be shy, the Fortune Teller can solve any problem."}
   ];

   // array of eject tuples
   this._ejects = [
     {"wav" : "eject1.wav", "tts" : "Guards, please escort the supplicant out of my chambers!"}, 
     {"wav" : "eject2.wav", "tts" : "Please come back when you are ready to ask a question.  Next!"}
   ];

   // array of answer tuples
   this._answers = [
     {"wav" : "answerno.wav", "tts" : "My answer is no."},
     {"wav" : "assuredly.wav", "tts" : "Most assuredly, yes."},
     {"wav" : "confirmnordeny.wav", "tts" : "I cannot confirm nor deny."}, 
     {"wav" : "counton.wav", "tts" : "This, you may count on."}, 
     {"wav" : "currentlysee.wav", "tts" : "As I currently see, yes."}, 
     {"wav" : "dontbet.wav", "tts" : "Don't bet on it."}, 
     {"wav" : "icannotfortell.wav", "tts" : "I cannot fortell."}, 
     {"wav" : "intelligenceno.wav", "tts" : "All intelligence points to no."}, 
     {"wav" : "lookinggood.wav", "tts" : "The future is looking good."}, 
     {"wav" : "mostcertainly.wav", "tts" : "Most certainly, yes."}, 
     {"wav" : "mostprobable.wav", "tts" : "Most probable."}, 
     {"wav" : "needtofocus.wav", "tts" : "You need to focus, and ask again."},
     {"wav" : "notknow.wav", "tts" : "It is better to not know."}, 
     {"wav" : "nsgood.wav", "tts" : "The future is not so good."},
     {"wav" : "sourcesyes.wav", "tts" : "All my sources point to yes."}, 
     {"wav" : "trylater.wav", "tts" : "Why don't you try later."}, 
     {"wav" : "uncertain.wav", "tts" : "Very uncertain."},
     {"wav" : "undeniably.wav", "tts" : "Yes, undeniably."}, 
     {"wav" : "unequivocally.wav", "tts" : "Unequivocally, yes."}, 
     {"wav" : "unquestionably.wav", "tts" : "It is unquestionably so."}
   ];

}

// given an array of audio tuples, return a random element
CFortuneTeller.prototype.getRandomAudio = function(a)
{
   var index = Math.floor(Math.random() * a.length);
   return a[index];
}

// pick a random prompt
CFortuneTeller.prototype.getPrompt = function()
{
   return this.getRandomAudio(this._prompts);
}

// pick a random noinput
CFortuneTeller.prototype.getNoinput = function()
{
   return this.getRandomAudio(this._noinputs);
}

// pick a random eject
CFortuneTeller.prototype.getEject = function()
{
   return this.getRandomAudio(this._ejects);
}

// pick a random answer
CFortuneTeller.prototype.getAnswer = function()
{
   return this.getRandomAudio(this._answers);
}


[24]7 Inc.| Terms of Service| Privacy Policy| General Disclaimers