Osd Developers Guide
Osd Developers Guide
Developers Guide
Notice
OpenSpeech Dialog 1.4 Developers Guide Copyright 20012007 Nuance Communications, Inc. All rights reserved. Published by Nuance Communications, Inc. One Wayside Road, Burlington, Massachusetts, 01803, U.S.A. Last updated July 16, 2007. Nuance Communications, Inc. provides this document without representation or warranty of any kind. The information in this document is subject to change without notice and does not represent a commitment by Nuance Communications, Inc. The software and/or databases described in this document are furnished under a license agreement and may be used or copied only in accordance with the terms of such license agreement. Without limiting the rights under copyright reserved below, and except as permitted by such license agreement, no part of this document may be reproduced or transmitted in any form or by any means, including, without limitation, electronic, mechanical, photocopying, recording, or otherwise, or transferred to information storage and retrieval systems, without the prior written permission of Nuance Communications, Inc. Nuance, the Nuance logo, DialogModules, and RealSpeak are trademarks or registered trademarks of Nuance Communications, Inc. or its affiliates in the United States and/or other countries. All other trademarks referenced herein are the property of their respective owners.
Contents
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi Restrictions and limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xii Audiences and objectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xii Abbreviations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii Available documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiv Related standards and third-party documents . . . . . . . . . . . . . . . . . xiv Chapter 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Overview of OSD applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Dialog configurations with xHMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 VoiceXML runtime platforms with the OSD framework . . . . . . . . . . . 1 Application Java code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Sample applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Running the pizza application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Chapter 2. OSDM node configuration (<osdm>) . . . . . . . . . . . . . . . . . . . . . . . . . . 5 <OSDM> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Chapter 3. Dynamic property framework (DPF) . . . . . . . . . . . . . . . . . . . . . . . . . 15 Using DPF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Performance guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 Error handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 Setting up the DPF tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 Storing HTTP parameters in the DPF tree . . . . . . . . . . . . . . . . . . . . . . . . . . 18 DPF facades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Generic facade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 OSDM-like facade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Nuance Proprietary
iii
Chapter 4. Creating an OSD component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Example PIN component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Details for the example component . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 Implementing OSD components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Create the directory structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Configure the DPF tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Defining the DPF (dpfInit.xml) . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 Enabling DPF (appconfig.xhmi) . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Create xHMI file for the component (pin.xhmi) . . . . . . . . . . . . . . . . . 29 The collection node example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 The confirmation node example . . . . . . . . . . . . . . . . . . . . . . . . . . 31 The error <catch> example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 Write a wrapper for the component (appconfig.xhmi) . . . . . . . . . . . . 34 Calling OSD components from VoiceXML applications . . . . . . . . . . . . . . 36 Calling OSD components from xHMI applications . . . . . . . . . . . . . . . . . . 37 Create the application structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 Create the application configuration (appconfig.xhmi) . . . . . . . . . . . 37 Example parameter list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 Example reference to a component . . . . . . . . . . . . . . . . . . . . . . . . 38 Example call to a component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 Example result handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 Example error handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 Chapter 5. TransitionNode configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 Chapter 6. Server-side event handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 Handling events on application servers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 Performance considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 Enabling server-side event handling . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 Counting events as they occur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 How to catch events on the application server . . . . . . . . . . . . . . . . . . 47 Examples of event handling on the application server . . . . . . . . . . . 47
iv
Nuance Proprietary
Restarting a node and varying the output . . . . . . . . . . . . . . . . . . 48 Using conditions to vary the output . . . . . . . . . . . . . . . . . . . . . . . 49 Setting the maximum retries of a node . . . . . . . . . . . . . . . . . . . . . 50 Running scripts inside event handlers . . . . . . . . . . . . . . . . . . . . . 51 Complete event-handling example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 Chapter 7. OSD logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 About OSD logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 Diagnostic logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 Page logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 Application logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 Log message formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 Scoping of log messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 Nesting log events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 Log events, parameters, and values . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 Generic log events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 Transaction events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 Node transitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 Catch handlers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 Final transitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 Database interactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 Caller segmentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 Transfers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 Turning application logging on and off . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 Chapter 8. OSD administration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 Deployment to a web server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 Providing an XML parser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 Starting a session . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 Operation administration & management (OA&M) . . . . . . . . . . . . . . . . . . 73 Using JMX in Tomcat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 Configuring the JMX connector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 Set JMX parameters in web.xml . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 Load the configurator class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Nuance Proprietary
Managing configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 Balancing system loads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 Controlling shutdown and update operations . . . . . . . . . . . . . . . . . . 76 The IOAM interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 OA&M event notifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 Default error messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 Extending error messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 Localizing OA&M notifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 Routing calls to the application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 Background concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 Registering OSD applications for routing . . . . . . . . . . . . . . . . . . 81 Configuring the routing servlet . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 Setting the persistent storage directory . . . . . . . . . . . . . . . . . . . . 81 Setting the initial routing table . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 Enabling the routing servlet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 Configuring the web application server . . . . . . . . . . . . . . . . . . . . 83 Static routing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Dynamic routing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Using the routing servlet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Chapter 9. Application development topics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 Using skip lists to avoid recognizing specific words . . . . . . . . . . . . . . . 85 Key facts about skip lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 When skip list processing occurs . . . . . . . . . . . . . . . . . . . . . . . . . . 87 Controlling where skip list processing occurs . . . . . . . . . . . . . . . 87 OSD automatically adds homophones to skip lists . . . . . . . . . . 88 Sample skip list grammar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 Dynamic prompts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 Writing prompt text to an attribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 Adding output to the StepResponse . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 Working with dates and times programmatically . . . . . . . . . . . . . . . . . . . . 94 Setting dates and times . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 Getting dates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
vi OpenSpeech Dialog 1.4 Developers Guide Nuance Proprietary
Details on date and time formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 Exceptions for invalid timestamps . . . . . . . . . . . . . . . . . . . . . . . . . 97 Creating grammars dynamically (at runtime) . . . . . . . . . . . . . . . . . . . . . . . 98 Comparison of dynamic and static grammars . . . . . . . . . . . . . . . . . . . 98 Overview of OSD support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Example of a dynamic grammar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 Reading the <config> content of a node . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 Add the elements by extending the DTD . . . . . . . . . . . . . . . . . . . . . . 101 Use the new element in your xHMI configuration . . . . . . . . . . . . . . 101 Write classes to access the custom node . . . . . . . . . . . . . . . . . . . . . . . 102 Extending the application object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 Rendering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 Extending the rendering system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 Create a custom node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 Configure the custom node in xHMI . . . . . . . . . . . . . . . . . . . . . . 110 Change the <vuiforward> map in xHMI . . . . . . . . . . . . . . . . . . 110 Create a jsp page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 Using custom Render Data objects . . . . . . . . . . . . . . . . . . . . . . . 112 Chapter 10. The OSD Datamodel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 Overview of variables and data storage . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 Datamodel error events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 Accessing variables with xHMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 Accessing variables with ECMAScript . . . . . . . . . . . . . . . . . . . . . . . . 115 Passing variables to subdialogs . . . . . . . . . . . . . . . . . . . . . . . . . . 116 Writing your own bean . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 Accessing variables with Java code . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 Access from a custom node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 Access from an update rule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 Access from an attribute facade . . . . . . . . . . . . . . . . . . . . . . . . . . 119 Access from a custom bean . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 ISessionFrame methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 Differences between a.best() and s.best(a) . . . . . . . . . . . . . . . . . . . . 121 AttributeBean methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Nuance Proprietary vii
Writing a factory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 When do you need a factory? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 Steps for writing a factory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 Implementing IDataElementFactory . . . . . . . . . . . . . . . . . . . . . . . . . . 123 The factory lifecycle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 Configuring factories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 Using the OSD datamodel interface . . . . . . . . . . . . . . . . . . . . . . . . . . 125 Implementing IDataModelAccess . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 Example user-defined JNDI factory . . . . . . . . . . . . . . . . . . . . . . . . . . 126 Chapter 11. FAQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 Evaluating variables and making logic decisions . . . . . . . . . . . 129 Accessing variables in ECMAScript expressions . . . . . . . . . . . 130 Declaring custom classes in xHMI . . . . . . . . . . . . . . . . . . . . . . . . 131 Creating attributes via Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 Configuring OSDM parameters dynamically . . . . . . . . . . . . . . 131 Timing of updates in the SessionFrame . . . . . . . . . . . . . . . . . . . 131 Changing the provided rendering jsp . . . . . . . . . . . . . . . . . . . . . 132 Recognizing long utterances with robust parsing grammars . 132 Chapter 12. Getting started with development . . . . . . . . . . . . . . . . . . . . . . . . . 133 Speech application development lifecycle . . . . . . . . . . . . . . . . . . . . . . . . . 134 Application design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 Design the callflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 Design the prompts and speech grammars . . . . . . . . . . . . . . . . . . . . 137 Application development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 Create a directory structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 Configure the application (create xHMI files) . . . . . . . . . . . . . . . . . . 139 Validating with a DTD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139 Validating with a W3C schema . . . . . . . . . . . . . . . . . . . . . . . . . . 140 Implementing custom nodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 General activities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 Test the application callflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141 Application deployment and tuning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
viii
Nuance Proprietary
Chapter 13. Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143 Appendix A. Predefined properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 Miscellaneous properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 Ambiguous recognition results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 Skip list processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 Properties for OpenSpeech Insight logging (OSI) . . . . . . . . . . . . . . . . . . . 148 Appendix B. Command line tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 Summary of command line tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 Recording list tool (listing prompts for the recording studio) . . . . . . . . . 151 Grammar List tool (lists grammars in an xHMI file) . . . . . . . . . . . . . . . . . 154 Validate tool (validating xHMI configuration files) . . . . . . . . . . . . . . . . . 155 Appendix C. Timestamp abbreviations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 Appendix D. Negative confirmations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
Nuance Proprietary
ix
Nuance Proprietary
Preface
Introduction
OpenSpeech Dialog (OSD) is an open environment for platform vendors and application developers to accelerate development time for speech applications, lower the total cost of application deployment, and provide a higher level of service to customers. OSD interprets the xHMI1 configuration language, which is an open XML specification language for dialog applications. The xHMI language provides a high-level language for designing and specifying speech applications. Together, OSD and the xHMI language address the complexity of implementing user interfaces that personalize telephone calls for each customer and that offer natural-language dialogs with broad vocabularies. Without OSD and xHMI, considerable design and programming skill is required to build these advanced applications using VoiceXML or JSP pages, and because of the complexity the costs are often too expensive to justify development. OSD and xHMI change this cost structure by speeding development, improving reliability, automating operational reports, and reducing the amount of tuning needed for initial phases of deployment.
Nuance Proprietary
In addition, environments that integrate OSD gain access to Nuance products that also use OSD. These products include:
SpeechPAKs (vertical application suites for healthcare, finance, utilties, etc.) DirectoryAssistant (telephone directory solutions) SpeechAttendant (automated telephone attendant solutions) X|Mode (multi-modal applications) Custom applications built by the Nuance Professional Services organization
For its natural language capabilities, OSD requires version 3.0.4 of the OpenSpeech Recognizer (OSR 3.0.4 and higher). This includes the following OSD capabilities:
Robust parsing grammars (first available in OSR 3.0.3, but only with sentence-based confidence scores) Slot-base confidence scoresBy default, OSR provides confidence scores for entire sentences and not for individual grammar (attribute) slots. To enable slot-based scores, you must configure OSR to add the special grammar key SWI_attributes to the recognition result. This can be done with the swirec_ extra_nbest_keys parameter inn an OSR user configuration file. For example, in a configuration file the parameter might appear as follows:
<!-- Add a Nuance grammar key to the XML result. --> <param name="swirec_extra_nbest_keys"> <value>SWI_meaning</value> <value>SWI_literal</value> <value>SWI_grammarName</value> <value>SWI_utteranceSNR</value> <value>SWI_attributes</value> </param>
Application developers are responsible for building speech applications that meet their customers business needs. With xHMI configurations and the OSD runtime environment, application developers can provide truly conversational speech interfaces. The xHMI configuration defines the conversational callflow of
xii
Nuance Proprietary
applications, and the OSD runtime provides interfaces, classes, and methods for developing xHMI applications. To develop OSD applications, you also need the xHMI Reference Guide.
Abbreviations
Abbreviation ASP ASR CCXML DPF DTD FIA HTTP J2EE JSP MVC NL OSD RDO SALT SRGS SSFT SSML TTS VCL VoiceXML W3C Description Application Services Platform Automatic Speech Recognition Call Control eXtensible Markup Language Dynamic Property Framework working draft (from the W3C) Document Type Definition Form Interpretation Algorithm Hypertext Transfer Protocol Java 2 Platform, Enterprise Edition Java Server Pages Model-View-Controller Natural Language OpenSpeech Dialog Render Data Object Speech Application Language Tags Speech Recognition Grammar Specification (from the W3C) ScanSoft (the former name of Nuance Communications, Inc.) Speech Synthesis Markup Language (from the W3C) Text to Speech Verification Candidate List Voice Extensible Markup Language World Wide Web Consortium
xiii
Available documentation
The documentation set for the OSD product includes the following:
OSD Migration Guide Topics for applications and platforms built on previous releases of OSD and xHMI. xHMI Reference Guide Overview, architecture, and the xHMI language. OSD Integration Guide How to add OSD to an existing application development platform. OSD Developers Guide How to use OSD to build applications.
xiv
Nuance Proprietary
W3C Schema
xv
xvi
Nuance Proprietary
Chapter 1
Introduction
This guide helps Java application developers to build speech applications using the OSD runtime framework with xHMI configurations.
Nuance Proprietary
xHMI configurations that define dialog behavior and the transitions between dialogs (for example, the prompts, confirmations, speech grammars, and so on). Most OSD installations are integrated into a runtime platform that is partnered with Nuance. You can also use OSD as provided directly by Nuance. OSD is a flexible and extensible framework providing several integration APIs for customizing your Java applications. OSD provides interfaces, classes, and methods for controlling dialogs and interacting with the session states configured via xHMI. OSD renders VoiceXML pages to your browser platform. The pages define everything needed for playing output to users and communicating with speech recognizers and text-to-speech engines. OSD writes detailed log messages for application analysis and tuning, and it provides an interface for systems operations. OSD does not provide telephony, operational control, speech recognition, text-to-speech, or the logging of log messages. We assume these services are controlled by your browser platform.
Implementing decision logic based on the current status of a session (the SessionFrame status) and on external information (for example, using a customer database to personalize the application callflow). Accessing back-end databases and performing transactions (for example, a money transfer in a bank application).
Sample applications
OSD installations include sample code. Here is the path to the samples:
installdir\OpenSpeech Dialog\samples\
The pizza application The ./pizza directory contains a simple application for ordering pizza. The application illustrates basic xHMI configuration concepts and Java coding practices. The restaurant guide application The ./restguide directory contains a simple application for selecting a restaurant and booking a table. The application illustrates the use of advanced natural language features.
Nuance Proprietary
The controller example The ./sourcecode/servlet directory contains the source code for the front controller for handling events that affect the model or views. The transfer example The ./transfer directory contains code that demonstrates how to use the Transfer node for telephony transfers (typically to human agents). The routing example The ./routing directory contains the OSD routing servlet. Use the servlet for routing incoming telephone calls to OSD applications, and for performing rolling updates of applications. For an overview, see Routing calls to the application on page 81. Dialog node examples The ./sourcecode/nodes directory contains source code of the OSD implementation of the xHMI primitive nodes: Output, Collection, and Transfer. The sources are provided for educational purposes and serve as a reference for application developers building custom nodes. OSDM samples These samples are useful if you plan to use OpenSpeech DialogModules (OSDMs) in your application. OSDMs perform specific callflow and prompting actions such as collecting a telephone number from a user. The ./dateofbirth directory contains an xHMI application that makes use of the date OSDM to ask for a date. To run this example an OSDM installation is required. The ./appconfig/OSDM directory contains fragments of xHMI configurations that show how to use OpenSpeech DialogModules in OSD. Use TmplAppConfig.fragment.xml as a template for other OSDM nodes.
Before installing this (or any OSD application) on an application server, you must copy dialogmanager-shared-1.4.jar to the shared library folder of the application server:
Application server Tomcat WebSphere Shared library folder TomcatInstallDir\shared\lib WebSphereInstallDir\lib
Nuance Proprietary
To install the sample on the application server perform these steps: 1 Deploy the pizza.war file
Tomcat WebSphere Copy pizza.war to TomcatInstallDir\webapps\ and start deployment on the management console. In the Administrative Console click ApplicationsInstall New Applications. Follow the standard procedures to install a war file.
Ensure that the jar files included in the sample application have precedence.
No action required. In the Administrative Console click ApplicationsEnterprise Applications. Select the pizza application. In the next page make the following changes: Classloader Mode PARENT_LAST WAR Classloader Policy
Tomcat WebSphere
Ensure that you are using an XML parser that is compatible with JAXP 1.3. OSD installs the Apache Xerces parser, which you can use. OSD installs the parser in the java/lib/ext directory. For Tomcat 5.0, copy the XML parser libraries (xercesImpl.jar and xml-apis.jar) to the common/endorsed folder of the Tomcat installation, and then restart Tomcat. Change the properties in installdir\webapps\pizza\WEBINF\ global.prop. Most importantly, you must specify your servers:
set grammar_server_ext prompt_server_ext osdm_server_ext Location of grammars Location of prompts Location of dialog modules
Nuance Proprietary
Chapter 2
The <osdm> element invokes sub-components and enables the creation of re-usable, modular, building blocks for applications. You can call any OpenSpeech DialogModule (OSDM) provided by Nuance or other vendor, and you can implement your own sub-components. (For details and an example, see Creating an OSD component on page 23.) You can run sub-components as client-side or server-side executions: a client-side invocation runs as a VoiceXML <subdialog>, and a server-side invocation runs inside the application itself. You cannot randomly change from client- to server-side; you must use one or the other, but not both. Server-side sub-components must be OSD applications configured with xHMI. (See Server-side versus client-side sub-components below.)
<OSDM>
Defines a modular, re-usable dialog executed as an application sub-component.
Scope Scope Parent Allowed child elements node <config> <fills>
Nuance Proprietary
Attributes Attribute1 srcexpr src Description Required (except when you use src). An ECMAScript expression containing the URL of an OSDM or an OSD application. Required (except when you use srcexpr). For client-side, this is the URL of the sub-components VoiceXML subdialog. (For client-side, the <osdm> tag is a simple wrapper around a VoiceXML <subdialog>.) For server-side, this is the URL of the sub-components xHMI configuration file. The path can be relative or absolute. 1. Either srcexpr or src is required; you cannot specify both. Implemented tags
Each <osdm> element in your xHMI configuration invokes a client-side or server-side component:
The server-side capability enables complete encapsulation of the called module within a single application context. (You can use the server-side class to call any OSD application configured with xHMI.) The client-side capability enables partial encapsulation of non-OSD applications. You can use the client-side class to call OpenSpeech DialogModules (OSDMs) created by Nuance and any other component that can run as a <subdialog> on the VoiceXML page.
There are performance differences when calling an OSD component with OSDMNode or ServerSideOSDMNode. We recommend implementing components as described in Creating an OSD component and using OSDMNode initially to call it. If you suspect degraded performance, change to ServerSideOSDMNode and compare results.
Nuance Proprietary
Client-sideWhen you execute an OSD component using OSDMNode, OSD renders a VoiceXML page with a <subdialog> that calls the component. When the component exits, the OSDMNode regains control and continues. OSDMNode adds a roundtrip communication with the browser platform. The cost depends mostly on the number of parameters passed between the application and the components: if the application passes many parameters to components, or the components return many parameters to the application, the performance cost increases.
Server-sideIn comparison, when you execute an OSD component on the server-side, the ServerSideOSDMNode creates a component handler without generating a VoiceXML page to get to the component. There is no roundtrip communication with the browser platform. ServerSideOSDMNode adds a validation procedure and uses more memory. The cost depends on the size of the components xHMI configuration files: larger files adds load.
If the URL starts with a forward slash (/), the location is relative to the application context root. For example, if the root is http://server/app, then these src values are equivalent: /subapps/getPIN.xhmi (relative) and http://server/app/subapps/getPIN.xhmi (absolute). If the URL does not start with a forward slash, the file location is relative to the parent xHMI file location (the calling applications xHMI file). For example, if the parent xHMI is at: /xhmi/callPIN.xhmi, then using a src value of subapps/getPIN.xhmi resolves to http://server/app/xhmi/subapps/getPIN.xhmi.
Nuance Proprietary
Events:
Client-side Server-side The sub-component must handle all events. Events are automatically forwarded to the calling application if not handled by the sub-component. This allows applications to write top-level event handlers (for example, a single configuration to handle hang-up events in all components).
Sharing data:
Client-side The calling application can use <property> to configure the VoiceXML page that runs the OSDM subdialog. It cannot set attributes in the sub-component. The subdialog can return attribute values. The calling application can use <property> to set attribute values in the sub-component. The sub-component can return values from any of its top-level (global-scope) attributes. Both the application and the sub-component share the same DPF tree (see Dynamic property framework (DPF) on page 15).
Server-side
Return values:
Client-side Server-side The calling application evaluates explicit return values when performing transitions to the <next> target. The calling application evaluate the expr return value. (See examples below.)
Global transitions in the calling application are not available to the sub-component. (This applies to both client- and server-side sub-components.)
Nuance Proprietary
<!--This example invokes a client-side OSDM--> <node id="PIN" class="com.scansoft.osd.nodes.OSDMNode"> <config> <!-- Configure the called sub-component--> <property-list> <property name="length" value="4"/> </property-list> <!--Specify the OSDM location--> <osdm src="%{osdm_server}osdm3-pin/osd-component"> <!--Map returned values to attributes--> <fills name="PINReturnValue" slot="returnvalue"/> <fills name="PINReturnCode" slot="returncode"/> <fills name="PINConfidence" slot="confidencescore"/> </osdm> </config> <transition> <!--Transition based on OSDM returncode--> <next name="SUCCESS"> <target path="playbackResult"/> </next> <next name="FAILURE"> <target path="/ErrorHandler(PINReturnValue)"/> </next> </transition> </node> <!--...--> </dialog> </xhmi>
The OSDMnode class allows you to specify transitions directly to other nodes by setting transition properties to the values returned by the OSDM. The above example uses blue text to show the transitions that use the returned properties.
Example server-side invocation
The next example invokes a server-side sub-component. It is nearly identical to the previous client-side example; the differences are highlighted with comments:
<!--Abbreviated header information--> <xhmi xml:lang="en-US" root="PinDialog"> <dialog id="PinDialog" root="PIN"> <var-list> <var name="PINReturnValue" type="attribute"/> <var name="PINReturnCode" type="attribute"/> <var name="PINConfidence" type="attribute"/>
Nuance Proprietary
</var-list> <!--This example invokes a server-side OSDM--> <node id="PIN" <!-- specify the server-side class --> class="com.scansoft.osd.nodes.ServerSideOSDMNode"> <config> <!-- Configure the called sub-component--> <property-list> <!-- set global attribute; creating it if necessary --> <property name="length" value="4"/> </property-list> <!-- Specify location; getPIN must be an OSD application --> <!-- Relative path = same dir as the calling application --> <osdm src="getPIN.xhmi"> <!-- Map returned values to attributes in calling appn--> <fills name="PINReturnValue" slot="returnvalue"/> <fills name="PINReturnCode" slot="returncode"/> <fills name="PINConfidence" slot="confidencescore"/> </osdm> </config> <transition> <!-- Transition targets based on the returned expr --> <next name="expr"> <target condexpr="PINReturnCode == 'SUCCESS'" path="playbackResult"/> <target condexpr="PINReturnCode == 'FAILURE'" path="="/ErrorHandler(PINReturnValue)"/> </next> </transition> </node> <!--...--> </dialog> </xhmi> Returning server-side values to the calling application
The calling application can define attributes to be filled when the sub-component returns (see the <fills> elements in the Example server-side invocation). To accomplish the return, the sub-component must define the return path and assign values to the returning attributes. The following example shows how the getPIN.xhmi sub-component might be implemented:
<!--...--> <transition> <next name="expr"> <!--If PIN is verified, then return--> <target condexpr="s.ver('pin')" path="return">
10
Nuance Proprietary
<assign name="returnvalue" value="s.best('pin')"/> <assign name="returncode" value="'SUCCESS'"/> <assign name="confidencescore" value="s.conf('pin')"/> </target> <!--Confirm PIN (not shown) if defined, but not verified--> <target condexpr="s.def('pin')" path="confirmPIN"/> <!--If retry counter exceeded, then return failure--> <target condexpr="maxRetries == 3" path="return"> <assign name="returnvalue" value="''"/> <assign name="returncode" value="'FAILURE'"/> <assign name="confidencescore" value="0"/> </target> <!--If PIN not defined, then retry (not shown)--> <target path="getPIN"/> </next> </transition> <!--...-->
Note: The sub-component can only return data in globally-scoped attributes. In the example, returnvalue, returncode, and confidencescore must be declared as top-level attributes in the sub-component (or declared in the attributes attribute of the sub-component root dialog.
Passing parameters to sub-components
The calling application uses properties to configure attributes in sub-components. The attributes are globally scoped (they are mapped to top-level attributes in the sub-component; you cannot set local attributes in dialogs or nodes). The <property> elements in the calling application will reset the values of the corresponding attributes (if they exist) in the sub-component. Thus, you can define default values in the sub-component, and override those attributes as needed with the calling application. You cannot configure properties on the VoiceXML platform with server-side components. The <property> configurations are identical for client-side and server-side components, but the effect is different: for client-side sub-components, OSD renders the properties as VoiceXML properties. Note: A good coding practice is to declare expected attributes at the top of sub-component. This is recommended but not required (since OSD will create the attributes if they do not already exist).
Nuance Proprietary
11
12
Nuance Proprietary
<transition> <!-- The OSDM node sets the transition property with the OSDM return code nodeAskForDate.returncode. The actual jump destination depends on it. --> <next name="SUCCESS"> <target path="#nodeOnSuccess"/> </next> <next name="AMBIGUOUS"> <target path="#nodeOnSuccess"/> </next> <next name="COMMAND"> <target condexpr="s.best('osdmReturnValue')== 'Help'" path="#nodeOnCmdHelp"/> <target condexpr="s.best('osdmReturnValue')== 'Guided Tour'" path="#nodeOnCmdGuidedTour"/> <target path="#nodeOnCmdOther"/> </next> </transition> <vuiforward> <forward name="callOSDM" path="/outputOSDM.jsp" /> </vuiforward> </node> </dialog> </xhmi>
Nuance Proprietary
13
14
Nuance Proprietary
Chapter 3
The Dynamic Property Framework (DPF)1 enables changing and passing property values during runtime execution. You can set properties statically or dynamically with as many DPF trees as needed in your OSD applications and components. One use for DPF is to pass parameters when calling OSD components from a client application (see Creating an OSD component on page 23).
Using DPF
After you set up a DPF tree, the DPF object and its properties are available to all ECMAScript expressions in the xHMI configuration. For example myDPF.mycomponent.daily is a reference to the daily property, which appears in mycomponent in the root tree named myDPF. Use the root name as a prefix in property paths. For example, consider this script:
<output id="advertisement"> <audio srcexpr="myDPF.mycomponent.daily"/> <output>
Assuming that daily has the value http://server/usedcars.wav, the system automatically renders this VoiceXML fragment: <prompt><audio src=" http://server/usedcars.wav "/><prompt>
1The
dynamic property framework is modeled according to the W3C working draft DPF from November 2004.
Dynamic property framework (DPF) Using DPF 15
Nuance Proprietary
Performance guidelines
For all DPF structures (DPF trees and DPF facades):
Loading large DPF trees can affect runtime performance. Because OSD creates DPF structures when it encounters <var> elements, the best location to define DPF trees is at the global scope. Applications must treat DPF structures as read-only when sharing those structures with other applications. Otherwise, one application can corrupt property values in other applications by writing to the shared DPF tree. Avoid defining property names that might cause problems with your ECMAScript interpreter. Do not define a property name that is also the name of a DPF tree or the String Function.
Error handling
When DPF errors occur, OSD throws error events for datamodel errors just as it would any error. For a description of events, see <catch> in the xHMI Reference Guide. Applications should always catch the error.datamodel root event or at least the general error event.s
Above, the example creates a tree named DPF. The tree automatically reads these properties files, in order: 1 2 /dpf/dpfInit.xml initialization file. This file is required. /all.properties file. This file is optional; if it does not exist, the system writes a warning.
16
Nuance Proprietary
/myComponent.properties file. This file is optional; if it does not exist, the system writes a warning. Typically, the name you provide for myComponent is the same name you provide for <mycomponent> in the dpfInit.xml file described below.
You can create as many DPF trees as needed. Define the contents of each tree in an xml file, then refer to this file in the configuration. This example creates a tree named myDPF that is defined in myDPFInit.xml:
<var name="myDPF" type="dpf:/dpf/myDPFInit.xml"/>
In the example above, the content is static. You can supply dynamic values programmatically by writing a java class and linking it to the property:
<?xml version="1.0" encoding="UTF-8"?> <DPF> <mycomponent> <todays_ad class="com.mycorp.myclassname"> </todays_ad> </mycomponent> </DPF>
Your class must extend com.scansoft.osd.dpf.DPFProperty, and supply the value of the property. The class must overwrite the following method: public String getValue() You must avoid name conflicts when designing property names; this is especially important for reusable components. One way to accomplish this is to use a subtree in DPF which has the same name as the component (as shown by <mycomponent> in the previous example). The framework creates the DPF tree whenever it encounters the dpf variable. Because the variable is scoped, the tree is also scoped. For example, when a <node> contains a <var> that loads a DPF tree, the framework re-creates the tree every time the callflow enters the node (the name is always the same, as is the content). You can create a DPF that is available globally to more than one application. When applications define this tree, they share a single instance of the tree instead of creating new instances.
Nuance Proprietary Dynamic property framework (DPF) Setting up the DPF tree 17
Use this for read-only properties. Applications should not write to these DPF trees because any changes immediately affects all applications using the tree.
If you send a parameter myparam=42 to mycomponent, it is inserted into the DPF as follows: DPF mycomponent a = 40 b = 41 myparam = 42 Note: Avoid using underscores in parameter names. Using the underscore (_) character in parameter names will create hierarchies in the DPF tree. This feature was designed for special purposes and should be avoided in your applications. For every underscore in the parameter name, a new level in the DPF tree is created. For example, if you send a_b_c=42 to mycomponent, the DPF tree looks like this: DPF mycomponent todays_ad class="com.mycorp.myclassname" a
18
b c=42
DPF facades
You can group several DPF trees into a facade, andthen reference properties in the facade instead of the specific trees where the properties reside. When OSD looks up a property, it searches the trees in the facade in an order that you define. Accessing DPF facade entries with scripts is the same as for DPF trees. For example, consider the ECMAScript expression in this configuration:
<output id="advertisement"> <audio srcexpr="myDPF.mycomponent.daily"/> <output>
Generic facade
This is a generic (list-like) approach that could be used to implement the following OSDM-like DPF facade.
<var name="myDPF" type="dpf_facade"/>
Setting dpf trees to this dpf facade can be done by executing the following ECMAScript expression:
<script> myDPF.addTree(dpfA); </script>
This DPF facade has the following methods: addNamedTree(String name, IDPFProperty dpf)adds a DPF tree with the specified name. addTree(IDPFProperty dpf)adds a DPF tree. removeTree(int index)removes the tree specified by the index. setTree(int index, IDPFProperty dpf) getTree(int index)returns the tree specified by the index. size()returns the number of DPF trees in the DPFFacade.
Nuance Proprietary
19
OSDM-like facade
This facade is tailored to the usage needed in packaged applications like OSDMS. Filling the DPF facade works like this:
<var name="myDPF" type="dpf_facade_osdm"> <param name="all" expr="dpfAll"/> <param name="component" expr="dpfComponent"/> <param name="language" expr="dpfEnglish"/> <param name="instance" expr="dpfInstance"/> </var>
The DPF tree instantiation can also be done using the mechanism described in the Outside Bean Creation document. The dpf_facade type allows renewing the references at runtime like in the following example for language. The other references can be renewed similarly.
<script> myDPF.language = dpfGerman; </script>
Once the DPF facade is accessed like a normal DPF tree the referenced DPF trees will be searched in the following order: 1 2 3 4 instance dpf language DPF tree component DPF tree all DPF tree
20
Nuance Proprietary
Nuance Proprietary
21
22
Nuance Proprietary
Chapter 4
This chapter shows how to write an OSD component that you can call from OSD applications or directly from a platform browser. It has a step-by-step description for writing and calling the component
Introduction
An OSD component is a web application. Conceptually, it is a re-usable building block for speech applications. You can call a component from VoiceXML or OSD applications:
By calling OSD components from existing VoiceXML applications, you can use the components without fully re-implementing the applications. By adding a <subdialog> to the VoiceXML application, the applications benefits without being configured with xHMI. By calling OSD components from OSD applications, you increase modularity and re-usability. Applications call components as if they were nodes (using the OSDMNode class). The node generates a VoiceXML page that uses <subdialog>.
Components run inside the calling application; they are not standalone applications. For example, this has implications for logging since the component is part of a session whereas an OSD application comprises the entire session. When a component exits (<target path="return"/>), the calling application regains control of the session. When a standalone OSD application exits, the session ends.
Nuance Proprietary
23
When you call a component, the URI ends with /osd-component. When you call a standalone OSD application the URI ends with /osd. When calling a component, applications pass property values using HTTP parameters. When components return to their calling application, they fill values in a formal parameter list defined in the applications root dialog. The list reinforces the purpose of a component to perform a specific activity, and ensures that the component returns a specific amount of information.
The application configures the collection prompts, and defines the PIN length. Then it calls the component, gets the result, and continues. The component collects the PIN, confirms it if necessary, and returns the result. The component uses xHMI to configure the prompts, grammars, confirmations, and so on, needed to perform the collection. The example is kept simple to demonstrate the key features. For example, there is no configuration for nomatch, noinput, and help.
System User
System
24
Nuance Proprietary
User
No
System User
System User
This figure shows the callflow for the example OSD component:
Initial Prompt
Something recognized
Rejected by user
Confirmation
Success
Failure
Nuance Proprietary
25
Implementing OSD components Calling OSD components from VoiceXML applications Calling OSD components from xHMI applications
26
Nuance Proprietary
Create the directory structure Configure the DPF tree Create xHMI file for the component (pin.xhmi) Write a wrapper for the component (appconfig.xhmi)
For detailed DPF information, see Dynamic property framework (DPF) on page 15.
Nuance Proprietary Creating an OSD component Implementing OSD components 27
You must define a DPF tree so applications can set parameters for OSD components to use in its callflow. You should define default values for every entry in the DPF tree. The examples below use the length property to demonstrate setting and changing the default value. For the Example PIN component, the application sets the PIN length. Below, we create the <length> property in the dpfInit.xml file as well as properties for prompts and various counters. The example configures a single element called pin below the DPF root element. The system automatically includes all properties in the pin.properties file under the pin element.
<?xml version="1.0" encoding="UTF-8"?> <DPF> <pin> <length>4</length> <collection_initialprompt> <![CDATA[ Please state your <value expr="DPF.pin.length"/>-digit PIN]]> </collection_initialprompt> <collection_maxnoinputs>3</collection_maxnoinputs> <collection_maxnomatches>3</collection_maxnomatches> <collection_maxretries>3</collection_maxretries> <confirmation_initialprompt>I think you said </confirmation_initialprompt> <confirmation_initialprompt2>Correct? </confirmation_initialprompt2> <confirmation_maxnoinputs>3</confirmation_maxnoinputs> <confirmation_maxnomatches>3</confirmation_maxnomatches> <confirmation_maxretries>3</confirmation_maxretries> </pin> </DPF>
You can reference DPF properties using DPF.pin.name syntax. For example: <value expr="DPF.pin.length"/>. In a component, this xHMI fragment assigns the length from the DPF:
<property-list> <property name="length" expr="DPF.pin.length"/> </property-list>
28
Nuance Proprietary
The component can access all its properties with the asterisk symbol (*) as a wildcard. The following example references all pin properties:
<property-list> <property-set expr="DPF.pin.*"/> </property-list>
To see DPF in a more complete example, see The collection node example on page 30.
Enabling DPF (appconfig.xhmi)
The OSD component must enable DPF in its xHMI configuration. Typically, you configure the DPF in a global <var-list>. For the Example PIN component, this is done in the appconfig.xhmi file as follows:
<var-list> <var name="DPF" type="dpf" expr="'pin'"/> </var-list>
Note: Do not enclose the OSD component with <xhmi> </xhmi> elements. The header defines a dialog called pin that has a root node called collection, which uses three parameters: returncode, returnvalue, and confidencescore. The parameters are implicitly defined in the component with no need for <var> definitions.
Nuance Proprietary
29
The PIN component first executes the collection node, which makes extensive use of the DPF tree defined in Configure the DPF tree. The user hears the prompt: Please state your n-digit PIN, and the value of n is set dynamically. Here is the collection node configuration in pin.xhmi. It defines properties, prompts, grammars, and transitions; and it gets these values from the DPF tree (the values previously set by the calling application):
<node id="collection" class="Collection"> <config> <property-list> <!--Get properties set by the calling application --> <property name="_maxnoinputs" expr="DPF.pin.collection_maxnoinputs" /> <property name="_maxnomatches" expr="DPF.pin.collection_maxnomatches"/> <property name="_maxretries" expr="DPF.pin.collection_maxnoretries"/> </property-list> <output-list> <initial> <output> <!--Get prompt set by the application --> <value expr="DPF.pin.collection_initialprompt"/> </output> </initial> </output-list> <grm-list> <!--Use the digits built-in grammar, and use the length set by the application. <grm srcexpr="'builtin:grammar/digits?minlength='+DPF.pin.length+';max length='+DPF.pin.length"> <!--NONE is a required keyword for built-in grammars --> <fills name="pin" slot="NONE"/> </grm> </grm-list> <!--Perform recognition and fill slot with the result --> <understand namelist="pin"/> </config>
30
Nuance Proprietary
<transition> <next name="expr"> <!--If pin is verified, return SUCCESS, score, and pin --> <target condexpr="pin.ver()" path="return"> <assign name="returncode" value="SUCCESS"/> <assign name="confidencescore" expr="pin.conf()"/> <assign name="returnvalue" expr="pin.best()"/> </target> <!--If pin is defined, confirm with the user --> <target condexpr="pin.def()" path="confirmation"/> <!--The SessionFrame automatically records executions. If pin is not defined after 2 attempts, return failure --> <target condexpr="s.nodeVisits()>2" path="return"> <assign name="returncode" value="FAILURE"/> <assign name="returnvalue" value="noValueInCaseOfFailure"/> <assign name="confidencescore" value = "0"/> </target> <!--If the pin slot was not filled, try again to collect --> <target path="collection"/> </next> <!--Only one <next> since collection always returns expr --> </transition> </node>
The collection node maps values to several predefined OSD properties: _maxnoinputs, _maxnomatches, and _maxnoretries. OSD automatically renders these properties to configure the browser. To prepare for recognition, the node defines a grammar. In this example, we use the built-in digits grammar with parameters for the minimum, expected, and the maximum number of digits.1 The values for these parameters are retrieved from the DPF tree (where set by the calling application). The grammar fills the pin attribute with the recognition result.
The confirmation node example
The confirmation node executes when pin is defined, but not verified. This means the dialog collected a valid PIN, but the confidence score was too low to automatically verify. When the user confirms, the node returns the PIN to the calling instance of the PIN component, and the instance returns to the calling application.
1The
documentation for built-in grammars is provided in the OSR Language Supplement for the recognized language.
Creating an OSD component Implementing OSD components 31
Nuance Proprietary
32
Nuance Proprietary
<!--Perform recognition and fill slot with the result --> <understand namelist="YESNO"/> </config> <transition> <next name="expr"> <!--If user confirmed, return success, score, and pin --> <target condexpr="YESNO.best()=='true'" path="return"> <assign name="returncode" value="SUCCESS"/> <assign name="returnvalue" expr="s.best('pin')"/> <assign name="confidencescore" expr="pin.conf()"/> </target> <!--If not confirmed after 2 attempts, return failure --> <target condexpr="s.nodeVisits()>2" path="return"> <assign name="returncode" value="FAILURE"/> <assign name="returnvalue" value="noValueInCaseOfFailure"/> <assign name="confidencescore" value = "0"/> </target> <!--If caller rejected, collect a new PIN --> <target condexpr="YESNO.best()=='false'" path="collection"/> <!--If not confirmed, try again --> <target path="confirmation"/> </next> </transition> </node> The error <catch> example
The PIN component must catch and handle any errors that occur during collection and confirmation. This is configured by the following block at the dialog scope in pin.xhmi:
<catch> <!-- Handler for disconnected sessions --> <target event="connection.disconnect" path="return"> <assign name="returncode" value="FAILURE"/> <assign name="returnvalue" value="noValueInCaseOfFailure"/> <assign name="confidencescore" value = "0"/> </target> <!-- Handler for speech that is too long -->
Nuance Proprietary
33
<target event="maxspeechtimeout" path="return"> <assign name="returncode" value="FAILURE"/> <assign name="returnvalue" value="maxspeechtimeout"/> <assign name="confidencescore" value = "0"/> </target> <!-- Handler when no speech is detected too many times --> <target event="maxnoinputs" path="return"> <assign name="returncode" value="FAILURE"/> <assign name="returnvalue" value="maxnoinputs"/> <assign name="confidencescore" value = "0"/> </target> <!-- Generic handler for all remaining error events --> <target event="error" path="return"> <assign name="returncode" value="FAILURE"/> <assign name="returnvalue" value="error"/> <assign name="confidencescore" value = "0"/> </target> <!-- Generic handler for all remaining events--> <target event="." path="return"> <assign name="returncode" value="FAILURE"/> <assign name="returnvalue" value="defaultEventHandlerActivated"/> <assign name="confidencescore" value = "0"/> </target> </catch>
34
Nuance Proprietary
This example wraps the OSD component described in Example PIN component:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE xhmi SYSTEM "../dtd/xhmi.dtd"> <xhmi root="pin" xmlns="http://www.scansoft.com/2004/xhmi" xmlns:xi="http://www.w3.org/2001/XInclude"> <vuiforward> <!--Define jsp's for generating VoiceXML --> <forward name="_collection" path="/collection.jsp"/> <forward name="_error" path="/error.jsp"/> <forward name="_return" path="/return.jsp"/> </vuiforward> <!--Enable the DPF --> <var-list> <var name="DPF" type="dpf" expr="'pin'"/> </var-list> <!--Include the pin dialog --> <xi:include href="inc/pin.xhmi"/> </xhmi>
Above, the wrapper defines an xHMI application with the pin root dialog. This structure (using <xi:include>) is recommended because it enables you to also use the pin.xhmi file directly in an OSD application.
Nuance Proprietary
35
The VoiceXML application can use the HTTP request to set properties because the OSD component configures a DPF tree to receive them. For an example, see Implementing OSD components. Above, the <subdialog> inserts length into the tree, and the component accesses the property using syntax like DPF.pin.length. For an example, in The collection node example on page 30).
36
Nuance Proprietary
Nuance Proprietary
37
<dialog id="Main" root="intro"> <!-Insert Main dialog; see Example parameter list... Insert intro node; see Example reference to a component... Insert pinOSDM node; see Example call to a component... Insert presentResult node; see Example result handling... Insert ErrorHandler dialog; see Example error handling... --> </dialog> <catch> <!-- Handle the most common expected events --> <target event="connection.disconnect" path="exit"/> <target event="error" path="exit"/> <target event="." path="exit"/> </catch> </xhmi> Example parameter list
To receive return values from OSD components, the OSD application must declare a formal list of attributes in its root dialog. Below is the root dialog for the Example PIN component. The Main dialog defines intro as the root node, and declares attributes to contain the return values. Here is the beginning of the Main dialog:
<dialog id="Main" root="intro"> <var-list> <var name="osdmPINReturnValue" type="attribute"/> <var name="osdmPINReturnCode" type="attribute"/> <var name="osdmPINConfidence" type="attribute"/> </var-list>
The OSD application calls components as if they were nodes. Below, intro is the first node called by the Main dialog of the Example PIN component. The node
38
Nuance Proprietary
adds a prompt to the output queue and calls the pinOSDM node. Here is the configuration:
<!--The output class sends the prompt to an output queue --> <node id="intro" class="Output"> <config> <output-list> <initial> <output>Welcome to the PIN demonstrator</output> </initial> </output-list> </config> <transition> <next name="expr"> <!--Call the next node, in this case an OSD component --> <target path="pinOSDM"/> </next> <!--Only one <next> because the target is unconditional--> </transition> </node> Example call to a component
This example defines a node that invokes an OSD component. You can use the OSDMNode or ServerSideOSDMNode classes for the definition. Below is the configuration for the pinOSDM node, which calls the Example PIN component. Like all nodes using the OSDMNode class, pinOSDM uses a namelist to send properties to the OSDM (in this example, we set the PIN length). The system writes property values to a DPF tree provided by the OSD component, and the values override any defaults defined in the component.
<node id="pinOSDM" class="com.scansoft.osd.nodes.OSDMNode"> <config> <property-list> <property name="length" value="3"/> </property-list> <!--Call the PIN component --> <osdm src="%{osdm_server}osdm3-pin/osd-component"> <!--Fill slots with values of returned parameters --> <fills name="osdmPINReturnValue" slot="returnvalue"/> <fills name="osdmPINReturnCode" slot="returncode"/> <fills name="osdmPINConfidence" slot= "confidencescore"/> </osdm> </config>
Nuance Proprietary
39
<transition> <next name="SUCCESS"> <target path="presentResult"/> </next> <next name="FAILURE"> <target path="/ErrorHandler(osdmPINReturnValue)"/> </next> </transition> </node>
The <transition> block defines what happens after the PIN component returns. On SUCCESS, the application calls the presentResult node. On FAILURE the application calls the ErrorHandler dialog (and passes the return value as a parameter for use in the error message).
Example result handling
A real application would do something useful with the collected PIN, but this sample merely repeats the collected PIN to the user and then exits. Here is the configuration for the presentResult node:
<node id="presentResult" class="Output"> <config> <output-list> <initial> <output> Your pin is <say-as interpret-as="number" format="digits"> <value expr="osdmPINReturnValue.best()"/> </say-as> Goodbye </output> </initial> </output-list> </config> <transition> <next name="expr"> <target path="exit"/> </next> </transition> </node> </dialog>
Note how the presentResult node controls the text-to-speech output: because the format is declared as digits, the TTS engine will speak the PIN as individual digits (for example, one-two-three-four) instead of combining digits into some natural number expression (for example, twelve thirty-four or one thousand two hundred thirty-four).
40
Nuance Proprietary
The ErrorHandler dialog is called when an error occurs.2 This example error handler simply informs about the error (for testing purposes), and then the application exits. A real application would do something more useful; for example, it might transfer the telephone call to a human operator. Here is the configuration for the ErrorHandler dialog:
<dialog id="ErrorHandler" root="errorHandler" attributes="resval"> <node id="errorHandler" class="Output"> <config> <output-list> <initial> <output>An error occurred: <value expr="s.best('resval')"/> </output> <output>please try again later</output> </initial> </output-list> </config> <transition> <next name="expr"> <target path="exit"/> </next> </transition> </node> </dialog>
2For
this example, the error handler is implemented as a dialog instead of a node. This choice emphasizes that a re-usable dialog is more useful when the example performs a more complicated transaction.
Creating an OSD component Calling OSD components from xHMI applications 41
Nuance Proprietary
42
Nuance Proprietary
Chapter 5
TransitionNode configuration
The TransitionNode node class provides a way to specify transitions in a node. Using a Transition node allows you to centralize and re-use transition handling instead of repeating transition configurations in every node.
Description <config> Element <property-list> Description Specifies predefined properties that steer the transition to the next node.
TransitionNode ignores all elements in <config> except for the predefined properties (see Predefined properties on page 147). Your Transition nodes can log activities just as any other node: use <log> inside the <node> and its <target> elements.
Example
Below is an example Transition node. It defines three targets that could be used by several nodes in the application:
<node class="com.scansoft.osd.nodes.TransitionNode" id="transit"> <transition> <next name="expr"> <target condexpr="s.best('serviceType')=='WEATHER'" path="/Weather"/> <target condexpr="s.best('serviceType')=='NEWS'" path="/News"/> <target condexpr="true" path="/Help"/> </next> </transition> </node>
Nuance Proprietary
TransitionNode configuration
43
44
Nuance Proprietary
Chapter 6
When events arise, application designers and developers can handle them client-side or server-side:
Client-side event handling means handling events on the VoiceXML page. Server-side event handling means handling events on the application server.
By default, event handling is done client-side. To change the default, see Enabling server-side event handling on page 46.
Overview
Prior to OSD 1.4, applications handled user-defined events on the application server and handled predefined recognition events (nomatch, noinput and help) on the VoiceXML page. As of OSD 1.4, applications can define a single event-handling mechanism located on the server-side. When recognition events arise, and the application handles them client-side, the only possible actions are to play a prompt and restart the node to collect the information. Many more actions are possible on the server-side:
Nuance Proprietary
45
Performance considerations
Server-side event handling shifts processing requirements from client to server. Applications are likely to demand more processing on the server-side (because more actions are possible there). A disadvantage to server-side event handling is that it adds one roundtrip of messages between the VoiceXML interpreter and the web application server for each recognition event that occurs. If you anticipate high counts of recognition events (nomatch, noinput and help), then you should consider the additional network load of roundtrip messages for your application.
You can set the properties at the global, dialog, or node scope. (Thus, applications can switch between client- and server-side event handling on a node- by-node basis. Note: Applications can use client-side or server-side event handling for each type of recognition event. For example, you can handle noinput events on the client and nomatch and help on the server. (However, you cannot mix client and server for the same type of event; for example, you cannot handle noinput events on both the client and server.) Setting _renderNoMatchOutputs to false disables automatic playing of the nomatch output and sends the nomatch event to the server.
46
Nuance Proprietary
For examples showing counters, see Restarting a node and varying the output on page 48 and Using conditions to vary the output on page 49.
Nuance Proprietary
47
</transition> <!-- The simplest event handler restarts the node --> <catch> <target event="nomatch" path="#collect"/> <target event="noinput" path="#collect"/> </catch> </node>
This is still a collection </output> </initial> </output-list> <grm-list> <grm src="collection.grxml"> <fills name="collectedItem"/> </grm> </grm-list> </config> <transition> <next name="expr"> <target condexpr="collectedItem.def()" path="#bye"/> </next> </transition> <catch> <!-- if nomatch arises, increment counters and restart node--> <target event="nomatch" path="#collect"> <assign name="nomatches" expr="Number(s.best('nomatches'))+1"/> <assign name="counter" expr="Number(s.best('counter'))+1"/> </target> <!-- if noinput arises, increment counters and restart node--> <target event="noinput" path="#collect"> <assign name="nomatches" expr="Number(s.best('noinputs'))+1"/> <assign name="counter" expr="Number(s.best('counter'))+1"/> </target> </catch> </node>
(In the preceding example, we omit <understand> assuming that it is defined at a higher scope.)
50
Nuance Proprietary
Define the maximum retry counter as first or last transition in the node. Here, the counter is the first transition target:
<node> <!-- ... --> <transition> <target condexpr="s.best('counter')>17" path="Help"> <log>counter reached maximum number of events</log> </target> <!-- remaining targets go here --> <!-- ... --> </transition> <!-- ... --> </node>
To see where this <target> fits inside the node, see the example in Restarting a node and varying the output on page 48.
</grm-list> <understand namelist="collectedItem"/> </config> <transition> <next name="expr"> <target condexpr="collectedItem.def()" path="#bye"/> </next> <!-- ... <next> ... --> </transition> <catch> <!-- if nomatch happened, restart collect --> <target event="nomatch" path="#collect"> <output>Please say something I can understand!</output> <script> a = 'executed every time this target is used'; </script> </target> </catch> </node>
The first execution of the node sends the following output: This is a collection. The first nomatch event, and any subsequent nomatch, sends this output: Please say something I can understand! This is still a collection.
52
Nuance Proprietary
Nuance Proprietary
53
<node class="Collection" id="collect"> <log>collection entered</log> <log>counter is '<value expr="counter"/>'</log> <config> <property-list> <!-- do not handle reco events on client-side --> <property name="_renderNoMatchOutpurs" expr="'false'"/> <property name="_renderNoInputOutpurs" expr="'false'"/> <property name="_renderNoHelpOutpurs" expr="'false'"/> </property-list> <output-list> <initial> <output>This is a collection</output> </initial> </output-list> <grm-list> <grm src="collection.grxml"> <fills name="collectedItem"/> </grm> </grm-list> <understand namelist="collectedItem"/> </config> <transition> <next name="expr"> <!-- Check the total retry counter. --> <target condexpr="counter > 17" path="#bye"> <log> maximum retries and events exceeded; leaving unsuccessful collection </log> </target> <!-- if data was collected, go to next node --> <target condexpr="collectedItem.def()" path="#bye"> <log>leaving successful collection</log> <clear name="counter"/> </target> <!-- by default, retry the node --> <target condexpr="true" path="#collect"> <log>executing node again</log> <assign name="counter"
54 OpenSpeech Dialog 1.4 Developers Guide Nuance Proprietary
expr="Number(s.best('counter'))+1"/> </target> </next> </transition> <catch> <!-- handle nomatch and noinput recognition events --> <target event="nomatch" path="#collect"> <log> nomatch event occurred; the number of times this node has tried to collect is <value expr="counter.best()"/> </log> <script>counter=counter+1;</script> <clear name="collectedItem"/> </target> <target event="noinput" path="#collect"> <log> noinput event occurred; the number of times this node has tried to collect is <value expr="counter.best()"/> </log> <script>counter=counter+1;</script> <clear name="collectedItem"/> </target> </catch> <!-- The final is triggered when the node is exited without an explicit transition at the dialog or global level.--> <final> <log>non node transition used to leave collection</log> </final> </node> <node id="bye" class="Output"> <config> <output-list> <initial> <output>Thanks for calling</output> </initial> </output-list> </config> <transition> <next name="expr"> <target path="exit"/> </next>
Nuance Proprietary Handling events with application servers Complete event-handling example 55
</transition> </node> <final> <!-- this <final> is for the dialog scope --> <log> Dialog exited without transitioning to another dialog </log> </final> </dialog> <catch> <!-- global handler for handup events --> <target event="session.connection.disconnect" path="exit"/> </catch> </xhmi>
56
Nuance Proprietary
Chapter 7
OSD logging
About OSD logging, an overview of the available logging streams. Application logging, a description of xHMI configuration and critical events your applications should log. Turning application logging on and off
Diagnostic loggingFor debugging and monitoring system operations, OSD uses log4j, an open-source utility that is a project of the Apache Software Foundation. Page loggingFor debugging, OSD writes copies of every VoiceXML page it renders. Application loggingFor analysis and tuning of your applications, OSD writes log files to a documented file system. You have control of the content of log messages, and you can choose more than one format of records in the files. For example, the most common format is the one used by the OpenSpeech Insight (OSI) tuning tool.
Nuance Proprietary
57
Diagnostic logging
For debugging and monitoring system operations, OSD uses log4j, an open-source Java utility that is a project of the Apache Software Foundation. The utility has six logging levels:
You control the logging mostly with the help of a log4j property file. The contents of the file control the format of the log entries and the amount of logged information. For each OSD application, you point to the log4j property file with the
log4jPropertyFileName context parameter in the applications web.xml. For
example:
<web-app> <context-param> <param-name> log4jPropertyFileName </param-name> <param-value> WEB-INF/log4j.properties </param-value> <description> Location of log4j property file for diagnostic logging. </description> </context-param> </web-app>
If you omit this parameter, the default location of the property file is /log/OSD.log inside the installed application. For concepts, reference, and configuration details, see this website: http://logging.apache.org/log4j/docs/ Performance tips:
Disable console output in the log4j.properties file. In a production system, do not use DEBUG or INFO levels. Limit logging for each class if specific DEBUG or INFO logs are required.
58
Nuance Proprietary
Page logging
For debugging, OSD can write a copy of every VoiceXML page it renders to a local directory. When you enable this feature, OSD creates a directory named pages, and writes the pages there. Page logging adds a substantial load to your computer system. Do not use it during normal operations. When you use it, enable it for one http session (web service) at a time, since the code running in the background is not thread safe. Note: Do not enable page logging on production systems that are already operating near capacity. To enable page logging, add the following <filter> and <filter-mapping> elements to your applications web.xml file:
<web-app>
...
<filter> <filter-name>PageLog</filter-name> <filter-class> com.scansoft.osd.servlet.FilterPageLog </filter-class> </filter> <filter-mapping> <filter-name>PageLog</filter-name> <servlet-name>osdservlet</servlet-name> </filter-mapping> </web-app>
Application logging
Application logging writes information about the dialog flow as it occurs during each session: you write messages with the <log> element, and your subsequent analysis of the logs reveals the performance of the application, its overall success, and the success of its discrete parts. Although OSD automatically writes some application logs, application developers provide the majority of logs for the OSD applications and components they write. By using <log> in the appropriate locations of your xHMI configuration, you control when the application writes messages and the content of those messages (for example, you might indicate the success or failure of a transaction when leaving a dialog).
Nuance Proprietary OSD logging Application logging 59
However, it is better to write event-based messages so that the logs can merge with other Nuance speech products in a complementary fashion. Each speech product has a different role during sessions, and their logs describe different aspects of runtime events. During a session, the products write logs to different directories and machines. The files are complementary because you can assembly all the logs for analysis by a single tuning tool. Here is the format of an event-based message:
<log> EVNT=event-name |parameter-name <value>=value <!--Insert more parameter/value pairs here--> </log>
You can use any number of <log> elements and parameter/value pairs. The field EVNT is required; it classifies the event. Log message values can be scripts or constants. Use ECMAScript to provide dynamic values that are only available at runtime. For example, a script can access the SessionFrame:
<log> EVNT=OSDInfo| INFO=pizzatopping: <value expr="pizzatopping.best()"/> </log>
In this example, the expression writes the name of the pizza topping collected from the caller. The name is the first hypothesis in the recognition result.
60
Nuance Proprietary
invoking any node inside that dialog. Alternatively, if you log an event inside a <node>, the event is logged only when invoking that node.
Nuance Proprietary
61
CLIDa caller id. For example the telephone number of the caller. GRP1, GRP2, GRP3, GRP4a category for the caller. INFOany additional information about the event. NAMEthe name of the event. SERVthe name of a database server. RESNthe reason for the RSLT. RSLTthe result of the event. The values are:
FAIL indicates a failed event, for example, in which all the required information was not collected from the caller due to a recognition or user interface problem. SUCC indicates a successful situation, for example, where all the required information was collected from the caller. UNKN indicates an unknown situation. For example, the caller disconnected or inexplicably requested a transfer to a human agent.
62
Nuance Proprietary
Use the OSDInfo event for any generic message, for example at the beginning and end of dialogs and nodes, and after successful transfers. This example shows the beginning of a dialog:
<dialog id="Main" root="intro"> <!-- ... --> <log> EVNT=OSDInfo | INFO=Gathering user input </log>
Use the OSDError event for any generic error message. For example:
<log> EVNT=OSDerror | INFO=An error occurred, going to last anchor. </log>
OSDInfo and OSDError are also useful for certain transfer situations. See Transfers.
Transaction events
One use for log messages is to signal the start and end of application transactions such as the accessing of records in a database or the execution of a group of nodes. A transaction consists of one or more collections from a caller, and can also include database interactions. For example, applications that identify users might define a transaction to include these parts:
To measure the success of an application, your logs must report each transaction. For example, in a banking application users identify themselves, view account balances, transfer currency among accounts, and make payments. The application associates transactions with each of these tasks and tracks them using the <log> element. Because transactions begin and end, their associated log messages must also begin and end. You can start and end transactions anywhere in your xHMI configuration, but in general a <dialog> starts a transaction and a <node> starts a task (or a sub-transaction) within a transaction. Here are recommendations:
Nuance Proprietary
63
Write start and end events for each <dialog>. Write start and end events for each <node> in the <dialog>.
Use SWItrxe in the transitions at the end of a transaction. The NAME must match the name of a previous SWItrxb event:
<!--transition--> <!--next--> <!--target--> <log> EVNT=SWItrxe|NAME=get_size_from_user|RSLT=SUCC |INFO=prompts queued </log> </target> </next> </transition> Node transitions
A node transition is always the result of gathering new information (for example, from a recognizer or a database). Depending on the status of the dialog (resulting from the new information applied to its attributes), the transition chooses the next target. For transitions that are transfers, see Transfers on page 67. Generally, a start transaction has already been logged, and the transition needs an end transaction event. Because transitions have the characteristics of an if-then-else decision, you need to log information for each possible outcome, including messages for:
Each <target> in the nodes <transition> Each <target> in the dialogs <transition> Each <target> in a global <transition> Each <target> in a thrown event
Heres an example for successful outcomes: When the transaction for the node is successful (target condition=true), configure this log in the <transition> element:
<log> EVNT=SWItrxe | NAME=get_pizzasize |RSLT=SUCC </log>
64
Nuance Proprietary
When the transaction is a failure, configure the log message in the <final> element. See Final transitions.
Catch handlers
Catch handlers should log the thrown events. The <catch> element enables the application to react to specific situations. Your logs can provide details and frequencies of those situations. Using <log> in a global catch handler (the <catch> inside the <xhmi> element) defines global log messages. OSD processes catch handlers before node transitions. When the system throws an event, and the <catch> has a true transition, the system invokes the target and never visits the nodes transition. This behavior ensures catching events immediately when they occur.
Final transitions
Use <log> inside <final> to report final status before the application exits, but remember that applications do not visit <final> at the end of every session. For example, events such as failing transactions are good candidates for final logging. The logging is done in these cases:
OSD calls the nodes <final> element when leaving the node without using a node transition. This occurs when there is an exception during execution, and when using a <transition> or <catch> at the dialog or global scope. OSD calls the dialogs <final> element when leaving the dialog without using a dialog or node target. This occurs when there is an exception during execution, and when using a global <transition> or <catch>.
Heres an example:
<final> <log> EVNT=SWItrxe |NAME=get_pizzasize |RSLT+FAIL |RESN=targetmissing |INFO=Node left without a target used. User data not complete. </log> Database interactions
You can log database interactions as individual transactions or nest them in other transactions. Because it is logged as a transaction, a database transaction has a start and end event log. Use SWIdbtx at the beginning of a database transaction. For example:
<node id="Your_databaseAccess_node_name" class="com.YourName.nodes.Database"> <log> EVNT=SWIdbtx|NAME=go_fetch_my_data></log>
Use SWIdbrx at the end of a database transaction. The NAME must match the name of a previous SWIdbtx event:
Nuance Proprietary OSD logging Application logging 65
<!--transition--> <!--next--> <!--target--> <log> EVNT=SWItrxe |NAME=go_fetch_my_data |RSLT=SUCC </log> </target> </next> </transition> Caller segmentation
You can use logs to group user populations into categories. For example, you can identify particular aspects of a call (its id number) and the callers (what they say and what they want). You can categorize types of callers, types of products, or the parts of a product a caller wants. To accomplish this, log the SWIcllr event in a <dialog> whenever a collection reveals new information that characterizes the caller. If you write the same information more than once, OSI uses the latest value logged. It is a good idea to log caller information as soon as it becomes available and if information changes, it should be logged again. Repetition of previously logged data is not necessary. This example identifies the user with the session ID from the servlet container, which is stored in a predefined OSD property. The message categorizes the user by the size of pizza ordered and their desired topping
<log> EVNT=SWIcllr |CLID=s.best('_sessionId') |GRP1=s.best('pizzasize') |GRP2=s.best('pizzatopping') </log>
Below, is a more detailed example. GRP1 should be filled with the pizza size and GRP2 should be filled with the pizza topping requested by the caller. 1 In the beginning of the application the first information logged is the call ID stored in the SessionFrame:
<!--Global scope near the top of the xHMI file--> <log>EVNT=SWIcllr|CLID=${s.best("__callId")}</log>
In the log file, this might appear as: EVNT=SWIcllr|CLID=1234 2 Then the application asks the caller about the pizza size. Assume the caller answers large. Below, the next SWIcllr event fills GRP1 with the answer:
66
Nuance Proprietary
<log>EVNT=SWIcllr|GRP1=s.best('pizzasize')</log>
In the log file, this might appear as follows. Note that the CLID remains known to the system.: EVNT=SWIcllr|CLID=1234|GRP1=large 3 Next, the application asks the caller about the topping. Assume the caller answers ham. Below, the next SWIcllr event fills GRP2 with the answer:
<log>EVNT=SWIcllr|GRP2=s.best('pizzatopping')</log>
In the log file, this might appear as follows. Again, the previously logged values remain known: EVNT=SWIcllr|CLID=1234|GRP1=large|GRP2=ham
Transfers
Logging transfers is another type of transaction logging. Because a speech application should result in a minimum of transfers, logging them provides critical information for tuning an application. OSD makes three types of transfers:
It is very important to log the SWItrfr event when the application transfers the caller to another application or to a human operator. This is the last opportunity to add session information, and it enables analysis of how sessions are ending. You can write transfer log messages in either of these locations:
In the node from which the caller is transferred In the Transfer node when the transfer is happening
Use SWItrfr to log the critical part, that is, the actual transfer, inside the <transition> element. Example for blind transfers:
<log> EVNT=SWItrfr |NAME=blind |RESN=caller demanded a blind transfer| INFO=Transferring caller blindly </log>
Nuance Proprietary
67
Use OSDinfo and OSDerror to log transfer events other than the actual transfer. For example:
<transition> <target condexpr= "s.best('typeOfTransfer')=='hangup'" path="#nodeBye"> <log> EVNT=OSDinfo |INFO=Caller does not want a transfer. Transferring caller to %{_transferDestination} </log> </target> </transition>
68
Nuance Proprietary
# using filter.XYZ.class=... # # PLEASE NOTE: use ONE filter only # # Configure each filter XYZ as follows: # # [REQUIRED] filter.XYZ.class # The implementation of com.nuance.log.IFilter # # [OPTIONAL] filter.XYZ.logdir # The directory to write log files. The default is: logs/ # # [OPTIONAL] filter.XYZ.filepattern # The pattern for generating the logfile. The default pattern # uses the sessionid in the file name: sid_%{SESSIONID}.log # filter=OSI_SIMPLIFIED filter.OSI_SIMPLIFIED.class=com.nuance.log.OSISimplifiedFilter filter.OSI_SIMPLIFIED.logdir=log filter.OSI_SIMPLIFIED.logmerge=classic filter.OSI_SIMPLIFIED.maxBackupIndex=100 filter.OSI_SIMPLIFIED.bufferSize=52428800 # Here is the default filepattern # filter.OSI_SIMPLIFIED.filepattern=coreEvents.log # Here is the filepattern used by OSD filter.OSI_SIMPLIFIED.filepattern=http://host:8080/osd-osilogge r/log
Nuance Proprietary
69
70
Nuance Proprietary
Chapter 8
OSD administration
You can copy and edit the global.prop file that resides in the WEB-INF directory of any OSD sample application. The file contains properties that the application can reference in the xHMI configuration file (see the xHMI Reference Guide for details on properties). You can edit the web.xml to add certain services as shown in this chapter. You can dynamically configure each session of an OSD application by including specific URL parameters in the first request to the application.
Uploading a war file for installation. Copying the war file into the webapps directory and restarting the server. Automatically unpacking the war file without restarting the server.
If your web application does not use a war file, you can copy the whole directory structure to the web application server for deployment. See your web application server documentation for information about deployment.
Nuance Proprietary
71
Starting a session
The first request of a client to an OSD application creates a session on the server. You can configure the session using URL parameters appended to the request, but you must do this in the initial request and not in subsequent requests. OSD accepts the following parameters in the first request:
callId callerId calledId session ID (you can define this parameter as described below)
For example, you could send this start request to the sample pizza application:
http://server:port/pizza/osd?xhmiCallerId=123&xhmiCalledId= 456&xhmiCallId=789
OSD initializes the session with the parameter values, and stores them in predefined attributes named __callerId, __calledId and __callId. You can access the attributes in the same way as any variable, for example: __callerId.best(). The rendering system use these properties to when rendering markup for your browser. If you replace the OSD rendering system, you can access the properties as _xhmiCallerId, _xhmiCalledId and _xhmiCallId. To define a session ID, add a global property to the xHMI configuration file:
<property name="_aliasUrlParamUserSessionId" value="SID"/>
Then, the request to the OSD application can contain a SID parameter:
http://server:port/pizza/osd?xhmiCallerId=123&xhmiCalledId= 456&xhmiCallId=789&SID=abc
72
Nuance Proprietary
The session ID becomes available to xHMI and the rendering system as follows:
xHMI attributes rendering property __userSessionIdName and __userSessionIdValue _xhmiUserSessionId (This corresponds to __userSessionIdValue. The name is contained in the property _aliasUrlParamUserSessionId that is set in the xHMI configuration.)
You can rename the callId, callerId, and calledId parameters using the following by adding these global properties in the xHMI configuration file:
<property name="_aliasUrlParamCallerId" value="myCallerId"/> <property name="_aliasUrlParamCalledId" value="myCalledId"/> <property name="_aliasUrlParamCallId" value="myCallId"/>
With the redefined parameter names, the example request URL looks like:
http://server:port/pizza/osd?myCallerId=123&myCalledId= 456&myCallId=789&mySID=abc
For Tomcat, set the servlet-listener to add the OA&M MBean. You must do this even if you have more existing web applications using the JMX configurator and the web application server is already configured for it. The JMX configurator then detects the new configuration and only adds an MBean.
Set JMX parameters in web.xml
Add the following configuration to the same web.xml that contains the JMXConfigurator listener (described in Load the configurator class on page 75). This example shows default values. If you do not need to change values, you can omit them from the configuration:
<context-param> <param-name>jmxProtocol</param-name> <param-value>jmxmp</param-value> </context-param> <context-param> <param-name>jmxHost</param-name> <param-value>localhost</param-value> </context-param> <context-param> <param-name>jmxPort</param-name> <param-value>1099</param-value> </context-param> <context-param> <param-name>jmxUrlPath</param-name> <param-value></param-value> </context-param> <context-param> <param-name>mbeanDomain</param-name> <param-value>OSD</param-value> </context-param>
74
Nuance Proprietary
The protocol, host, port, and URL path parameters form the service url: service:jmx:jmxmp://localhost:1099 The mbeanDomain parameter names the MBean in the ObjectName: OpenSpeech Dialog:MBean=Instrumentation For details, see the javadoc for the JMXServiceURL and ObjectName classes.
Load the configurator class
To enable JMX in Tomcat, insert the following lines into the web.xml:
<listener> <listener-class> com.scansoft.osd.oam.jmx.JMXConfigurator </listener-class> </listener>
This configuration loads the JMXConfigurator class as a web application context listener, and enables the JMX server components. Note: All OSD web applications share this setting. Any web application that uses this configurator will possibly overwrite settings from the previously loaded web applications. We strongly recommended using a single web application to set up JMX.
Managing configuration
After you complete the JMX configuration, an MBean named Instrumentation becomes available to JMX Management consoles (under the mbeanDomain, configured as OSD by default). You can use any JMX management console.
The load balancer must direct each OSD session to a single server. To accomplish this, the service uses the JSESSIONID cookie to balance loads. The cookie is described in the Java Servlets Specification. The VoiceXML browser platform must support and use this cookie for each call when communicating with application servers running OSD applications.
Nuance Proprietary
75
The following table shows the management operations accessible through the class IOAM and exposed by the JMX MBean server. For details on the methods, see the OSD Integration Guide and javadoc.
Method acceptNewSessions blockNewSessions getMaxActiveSessions getNumSessions getProperties getStatistics kill listApplications sendNotification setMaxActiveSessions Description Cancels a previous call to blockNewApplications or kill. Prevents new sessions. Gets the maximum number of sessions allowed. Gets the current number of sessions. Gets all context properties for an application. Gets statistical information about an application. Aborts all sessions immediately. Lists the names of all running applications. Sends a message to the OAM management framework. Sets the maximum number of sessions allowed.
76
Nuance Proprietary
OSD adds a timestamp and a prefix of predefined key-value pairs to the userdata. The pairs are taken from the create method of the DialogManager Invocation Interface:
Key Sessionid appname Value Usually the ID generated by the application server (jessionid) The application name
Nuance Proprietary
77
Value The callers telephone number (if available) The called number (if available) A unique identifier of the call (if available)
The messages.dtd file contains keys for the predefined error messages. OSD uses the keys to find message text in messages.xml. Here is a list of keys:
Message key CONFIGURATION_ERROR VUIFORWARDMAP_UNDEFINED TRANSITION_FAILED NO_NEW_SESSIONS SHUTTING_DOWN CONTEXT_NOT_REGISTERED NODE_EXECUTION_FAILED PROCESSING_ERROR PROTOCOL_ERROR PROTOCOL_ERROR_DIALOG_NOT_STARTED PROTOCOL_ERROR_ONLY_HANGUP PROTOCOL_ERROR_SMEX BROWSER_ERROR_EVENT Message parameters none {0} name of node none none none {0} name of application {0} name of node {0} information about failed processing none none none none {0} event message
Each message describes a single error. OSD fills the {0} construct at runtime. For a description of how this works, see the javadoc for the ErrorMessages class.
Extending error messages
You can define new error messages and use them in any custom nodes you create. (OSD does not use the messages in the predefined nodes.) The DialogManager API has a method for sending the custom error messages from within your Java code.
78
Nuance Proprietary
Extending the error messages is simple: 1 Copy messages.dtd, messages_custom.dtd, and messages.xml from their installation location in the OSD system folder) to a temporary location for editing. Do not change the originally installed versions of these files. Edit the messages_custom.dtd file to define the new messages. (OSD automatically appends the file to messages.dtd.) Edit the messages.xml file to write the text of the messages. Copy the dtd files to the WEB-INF/dtd folder of every web application that will use the custom error messages.
2 3 4
Example
Here is an example of messages_custom.dtd. It shows the key for a new message called HELLO_WORLD:
<?xml version="1.0" encoding="UTF-8"?> <!ELEMENT HELLO_WORLD (#PCDATA)>
Here is an example of messages.xml. It shows the text added for the new message:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE messages SYSTEM "dtd/messages.dtd"> <messages> <CONFIGURATION_ERROR> Configuration error. Check the appconfig.xhmi for errors. </CONFIGURATION_ERROR>
Nuance Proprietary
79
<VUIFORWARDMAP_UNDEFINED> VUIForwardMap undefined in node {0}. Check VUI forward maps in the appconfig.xhmi </VUIFORWARDMAP_UNDEFINED> <!--...more definitions...--> <HELLO_WORLD>Hello World Message</HELLO_WORLD> </messages>
Your application can return the new message from the ErrorMessages class, which is available through the DialogNode class (see the javadoc).
When you include the full or partial language code, you can provide any number of files with different language codes. (For example, you could have Spanish files messages_es.xml, messages_es-ES.xml, and messages_es-CO.xml.) At runtime the system chooses messages in this order: 1 2 3 4 From the given locale From the default locale From the messages.xml From the internal defaults
OSD sends messages from these definitions to the OA&M client in notification messages. Using the localized messages.xml and messages.dtd files, you can overwrite the default messages defined in the ErrorMessages class. Because the
80 OpenSpeech Dialog 1.4 Developers Guide Nuance Proprietary
default notification messages have built-in defaults, no messages.xml file is needed. OSD provides the dtd is provided in its system folder. You must copy the dtd to every web application that uses custom error messages. (See Extending error messages on page 78.)
OSD provides a routing servlet that accepts and forwards requests from voice browsers to OSD web applications. The routing servlet offers an easy way to update web applications and to perform management operations for application installation, update, and removal. The routing servlet lets you map requests to specific web applications using telephone numbers or application names. Importantly, the servlet lets you remove applications from service so they can be updated without interrupting sessions. To remotely manage the routing, the management framework provides a set of management operations. OSD installs an example implementation of a routing application (which uses JMX) in the routing.war that is installed in the samples folder. For additional discussion of the routing servlet, see the OSD Integration Guide.
There are no special steps to register an OSD application for routing. At startup, every OSD application registers itself to the OSD framework and is therefore available for routing. The framework knows which context of an OSD application is the latest (and stores this knowledge in the oamDataDirectory). If a server restarts, the applications are configured to use the latest context when receiving start requests. Theres two ways to configure the routing servlet:
Configure static or dynamic routing. Configure the routing servlet dynamically at runtime.
The servlet needs a persistent storage location; you must configure this location in the web application deployment descriptor (web.xml). Do this in only one
Nuance Proprietary
81
web.xml, and the setting will be used by every OSD web application. To configure this setting add the following context parameter to the web.xml:
<context-param> <param-name> oamDataDirectory </param-name> <param-value> C:\OSDSavedData </param-value> </context-param> Setting the initial routing table
The web.xml also configures the initial entry set of the routing table. Use this example as a model to specify the set:
<context-param> <param-name>routingTableEntry001</param-name> <param-value>123,HelloWorld</param-value> </context-param> <context-param> <param-name>routingTableEntry017</param-name> <param-value>456,HelloWeb</param-value> </context-param>
Each entry is named routingTableEntryXYZ where XYZ is a unique string or number. Every parameter name that starts with routingTableEntry is an entry for the routing table. In the example, the phone number 123 maps to the HelloWorld application, and 456 maps to HelloWeb. In all entries, the application names must match the <display-name> entry in the web.xml of the web applications.
Enabling the routing servlet
The <servlet> and <servlet-mapping> elements are required in the web.xml for starting the RoutingServlet. These elements accept the parameters described in later in this section.
<servlet> <servlet-name> routingservlet </servlet-name> <servlet-class> com.scansoft.osd.servlet.RoutingServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name> routingservlet </servlet-name> <url-pattern> /router </url-pattern> </servlet-mapping>
82
Nuance Proprietary
The order of the entries in the web.xml file is significant (and is dictated by the dtd used for the file). Consult the documentation for your web application server for details.
Configuring the web application server
To use the Routing Servlet, the web application server must allow the routing servlet to access different web contents. For example, Tomcat requires a configuration such as the following in the server.xml file inside the <host> element:
<DefaultContext reloadable="true" crossContext="true"/>
Static routing
The routing configurator sets up the RoutingServlet using parameters from the web.xml. These parameters include settings for the initial routing table. To enable routing in Tomcat, insert the following lines in the web.xml:
<listener> <listener-class> com.scansoft.osd.oam.jmx.RoutingServiceConfigurator </listener-class> </listener>
This configuration reads the routing table entries from web.xml and sets up the routing table with these values. With static routing, the routing table does not change after this initial setup. With dynamic routing, changes are possible at runtime.
Dynamic routing
For dynamic routing, you must set up JMX as described in Set JMX parameters in web.xml on page 74. After specifying the web.xml entries described there, make the settings needed for Static routing. After setting up the dynamic routing a new MBean is available under the JMX mbeanDomain OSD for changing the routing table at runtime. For information, see Managing configuration on page 75.
To use the configured routing servlet, copy the routing.war file into the web applications folder of your web application server. Sending requests to the routing servlet is similar to sending requests to the OSD servlet. Here is a URL request to the OSD servlet for starting a dialog with the pizza application on MyServer port 8080:
http://MyServer:8080/routing/router?application=Pizza
Here is a request using telephone number 123 and a routing table as identifiers:
http://MyServer:8080/routing/router?calledId=123
If the request uses both application name and telephone number, the telephone number takes precedence (assuming the routing table has an appropriate entry).
Nuance Proprietary OSD administration Operation administration & management (OA&M) 83
The returned page carries the real context that handled the forwarded request; this allows all subsequent requests to be sent directly to the serving context instead of the routing servlet. The URL used in the request to the routing servlet is forwarded to the target application without change. Therefore, the start request can carry additional information to configure the OSD application.
84
Nuance Proprietary
Chapter 9
Using skip lists to avoid recognizing specific words Dynamic prompts Working with dates and times programmatically Creating grammars dynamically (at runtime) Reading the <config> content of a node Extending the application object Rendering
System
In the example above, the negative confirmation Not Boston is understood, but then BOLTON! is mis-recognized again as Boston. Users get angry when applications make mistakes like this; and skip lists solve the problem.
Nuance Proprietary
Application development topics Using skip lists to avoid recognizing specific words
85
86
Nuance Proprietary
For background information, this figure shows when skip list processing occurs:
By default skip lists are processed by OSD (which is known as server-side processing) and disabled on the speech recognizer (which is known as ASR-side processing). This is equivalent to the following setting of the properties serverSideSkipList and asrSideSkipList:
<property-list>
Nuance Proprietary
Application development topics Using skip lists to avoid recognizing specific words
87
Above, these are the default settings. If you want server-side processing, do not change the defaults. Alternatively, you can process skip lists on the speech recognizer instead of using OSD. Set the parameters as follows:
<property-list> <property name="serverSideSkipList" value="false"/> <property name="asrSideSkipList" value="true"/> </property-list>
You can enable skip list processing on both sides (recognizer and OSD), but this adds load to processing without increasing performance. The default is to process skip lists on the OSD machine. This is recommended for these reasons:
If you are not using the Nuance Recognizer, and your recognizer does not support ECMAScript in speech grammars that can be activated via parameter grammars, you must change the default processing location. PerformanceIf your recognition server is already heavily loaded, the additional ECMAScript processing for skip lists might be undesirable. Normally, the additional load is minimal. There is a small cost savings (cpu and network activity) to process with OSD. For example, there is less rendering for the voice browser and less data transfer to the recognizer. This is not likely a significant factor for changing the default processing location.
But processing on the recognizer is also useful because it returns more accurate results that are easier to work with. (The recognizer replaces skipped hypotheses with new possibilities and re-adjusts confidences levels, whereas OSD simply removes next-best entries. With OSD, removed slots are not re-filled and confidence scores are not re-adjusted.)
OSD automatically adds homophones to skip lists
88
If any of the items on the skip list are associated with homophones, OSD automatically adds the homophones to the list. This is done because the default implementation of xHMI works with semantic values, and it could
Nuance Proprietary
unknowingly prompt with an item that has a different semantic value but the same pronunciation. To avoid this, OSD reads the contents of the skip list, detects homophones, and appends them to the list. Assume the following dialog:
System User System User System What is the persons name? Cager. Meyer, correct? No. Please say the name again.
Above, when the caller says no, OSD has a skip item containing Meyer. Because Meyer has homophones such as Mayer, Meier, and Mayor, OSD also adds these names to the skip list.
Sample skip list grammar
Nuance Proprietary
Application development topics Using skip lists to avoid recognizing specific words
89
Dynamic prompts
To present dynamic content to the caller, the application developer can do either of the following:
Write the presentation text (the text to be presented to the caller) to an attribute and then use an ECMAScript expression in the <output> configuration. Add the output to the StepResponse that is passed to the rendering system.
To describe these alternatives (below), we use the Hello World example (originally presented in the xHMI Reference Guide). In these examples, the prompt text is hard-coded in java. This is done for simplicity; in a real application, the dynamic prompts would be generated from database content.
90
Nuance Proprietary
<transition> <next name="expr"> <target condexpr="true" path="exit"/> </next> </transition> </node> </dialog> <catch> <target event="error" path="exit"> <log>An error occurred.</log> </target> </catch> <vuiforward> <forward name="_outputExit" path="/outputExit.jsp"/> <forward name="_exit" path="/exit.jsp"/> </vuiforward> </xhmi> java code for the custom node package com.scansoft.osd.tutorial; import java.util.Calendar; import java.util.GregorianCalendar; import import import import com.scansoft.xhmi.DialogException; com.scansoft.xhmi.IStepRequest; com.scansoft.xhmi.IStepResponse; com.scansoft.xhmi.nodes.Output;
public class DynamicPrompt1 extends Output { public void execute(IStepRequest request, IStepResponse response) throws DialogException { // calculate prompt text String greetingPrompt = new String( "Hello!" ); Calendar calendar = new GregorianCalendar(); int hour = calendar.get(Calendar.HOUR_OF_DAY); if( hour < 10 ) { greetingPrompt = "Good morning!"; } else if( hour > 17 ) { greetingPrompt = "Good evening!"; }
Nuance Proprietary
91
(An alternative implementation to the above is discussed in Adding output to the StepResponse on page 92.)
92
Nuance Proprietary
package com.scansoft.osd.tutorial; import java.util.Calendar; import java.util.GregorianCalendar; import import import import import import com.scansoft.osd.config.XInitial; com.scansoft.osd.config.XOutput; com.scansoft.xhmi.DialogException; com.scansoft.xhmi.IStepRequest; com.scansoft.xhmi.IStepResponse; com.scansoft.xhmi.nodes.Output;
public class DynamicPrompt2 extends Output{ public void execute(IStepRequest request, IStepResponse response) throws DialogException { // calculate prompt text String greetingPrompt = new String( "Hello!" ); Calendar calendar = new GregorianCalendar(); int hour = calendar.get(Calendar.HOUR_OF_DAY); if( hour < 10 ) { greetingPrompt = "Good morning!"; } else if( hour > 17 ) { greetingPrompt = "Good evening!"; } XInitial initial = new XInitial(); initial.add(new XOutput(greetingPrompt)); // write output to step response response.putInitialOutputList(initial); super.execute(request, response); } }
Nuance Proprietary
93
Update rulesOSD provides sample date and time update rules for evaluating timestamp information in recognition results, improving the next-best entries, and filling slot attributes in the SessionFrame. Attribute facadesWhen discussing dates and times with users, one challenge is to collect separate slots of timestamp information, and then use them together. For example, the application might allow: date, day, day of week, month, year, time of day, hour of day, and so on. Internally, the application translates these slots into a concise timestamp object. Externally, the application needs to formulate output using any combination of the slots. To simplify the challenge, applications can use attribute facades. For example, date and time attribute facades can detect when timestamps are incomplete (i.e. when slots are missing), and automatically formulate follow-up questions in output to users. To collect each slot, the needed grammars are automatically referenced, and the application does not need to control the chaotic activation and deactivation of individual grammars in the recognizer.
94
Nuance Proprietary
resolving ambiguities. You can specify dates in the following combinations of fields:
Complete timestamp date time timezone Partial timestamp combinations date time date time timezone date
The set method provides additional control. The format string allows various timestamp formats with these values: osd:datetime vxml:date vxml:time The assume string allows changes to assumptions when filling in omitted parts of the timestamp with these values: ASSUMEPAST ASSUMEFUTURE ASSUMECLOSEST ASSUMENOTHING For example, to set a timestamp in the past (the first day of the current month):
set("-01","osd:datetime","ASSUMEPAST")
Getting dates
Use the get method of IDateTime to retrieve dates in any desired format. You can get complete dates or parts of dates. The signature is: String get(String format) For example, the following format string prints a four-digit year (zero padded when only three digits are available), a two-digit month, and so on. This for is similar to the ISO8601 definition for dates and times: YYYY-MM-dd HH:mm:ss Z
Nuance Proprietary
95
96
Nuance Proprietary
The com.scansoft.osd.date.DateTime class uses the following format for the time portion of a timestamp: HH:mm:ss Z The Z is a timezone designator showing an offset relative to Greenwich Mean Time (GMT). It can take the values -23.59 to +23.59. For example: 2005-02-10 10:00:00 +01:00 The timezone must contain a plus sign (+) or a minus sign (-). The format is: (+|-)HH:mm In the timezone format, HH is a two-digit number between 0 and 23, and mm is a two-digit number between 0 and 59. Times are always based on a 24-hour clock (not 12-hour). You cannot specify am or pm. You can abbreviate values when specifying the time. The class fills abbreviations using zeros:
Specification 13:15 13 :30 ::55 Time 13:15:00 (this is 1.15 am) 13:00:00 00:30:00 00:00:55
The set method rejects invalid dates and times by throwing an exception that states the error. For example, the date 2005-02-40 is invalid (because there is no month having more than 31 days). The smallest possible date is 1-1-1 (the first day of the first month in year 1). Although there is a zero time (00:00:00 is midnight), there is no zero date: a value of 0-0-0 will throw an exception.
Nuance Proprietary
97
Large vocabularies of known information (item lists, natural language grammars, robust parsing grammars, and so on) are built as static grammars. Smaller, customized vocabularies (personalized information that is specific to the session) are built as dynamic grammars (typically, by jsp pages). Static and dynamic grammars can be complementary. For example, two grammars can be activated in parallel where the larger grammar is static, and the smaller grammar is dynamically generated to extend the coverage of the recognized speech.
3 4
Add and use the grammar. Release unused grammars. This is optional to improve performance.
To store and release grammars, the com.scansoft.xhmi.nodes.DialogNode class provides the storeGrammar and releaseGrammar methods. OSD adds the dynamic grammar to the generated page so it is activated for the next recognition.
Nuance Proprietary
99
// add grammar to set of used grammars addDynamicGrammar(response, ul, dynamicGrammar); } // the following method is called from DialogNode#transition protected void removeDynamicGrms(IStepResponse response) throws DialogException { releaseGrammar(name); // release grammar after using it } }
Use the node in your xHMI configuration. You must configure the <understand> element with any attribute names that are filled by the dynamic grammars. Otherwise, the system cannot copy recognized slots to attributes:
<node class="com.examples.nodes.DynamicGrammarCollection" id="collect"> <config> <property-list> <property name="attributeToFill" value="dummy"/> </property-list> <output-list> <initial> <output>please state value for 'dummy'</output> </initial> </output-list> <understand namelist="dummy"/> </config> <transition> <next name="expr"> <target path="#waiting"/> </next> </transition> </node>
To extend the <config>, perform these steps: 1 2 3 Add the elements by extending the DTD Use the new element in your xHMI configuration Write classes to access the custom node
Put the definition of the custom element into the custom.dtd file. For example:
<!ELEMENT parameter-list (parameter+)> <!ELEMENT parameter EMPTY> <!ATTLIST parameter name NMTOKEN #REQUIRED type NMTOKEN #REQUIRED value CDATA #IMPLIED default CDATA #IMPLIED >
Nuance Proprietary
101
<config> <parameter-list> <parameter name="helloPrompt" value="Hello!" type="String"/> <parameter name="morningPrompt" value="Good morning!" type="String" default="Hello"/> <parameter name="eveningPrompt" value="Good evening!" type="String" default="Hello"/> <parameter name="morning" value="10" type="Integer" /> <!-- 10am --> <parameter name="evening" value="17" type="Integer" /> <!-- 5pm --> </parameter-list> </config> <transition> <next name="expr"> <target condition="true" path="exit"/> </next> </transition> </node> </dialog> <catch> <target event="error" path="exit"> <log>An error occurred.</log> </target> </catch> <vuiforward> <forward name="_outputExit" path="/outputExit.jsp"/> <forward name="_exit" path="/exit.jsp"/> </vuiforward> </xhmi>
102
Nuance Proprietary
public class CustomConfig extends Output{ class XParameterList extends HashMap implements IDomElementReader{ public static final String XML_ELEMENT_NAME = "parameter-list"; public static final String TAG_ATTRIBUTE = XParameter.XML_ELEMENT_NAME; public String getXMLElementName() { return XML_ELEMENT_NAME; }
Nuance Proprietary
103
public void readFromDomElement(Element element, String namespacePrefix, Node namespaceNode) throws XMLException { String xpath = "./" + namespacePrefix + ":" + TAG_ATTRIBUTE; try { try { NodeList nodeList = XPathAPI.selectNodeList( element, xpath, namespaceNode); if (nodeList != null) { for (int n=0; n< nodeList.getLength() ; n++) { XParameter param = new XParameter(); param.readFromDomElement( (Element)nodeList.item(n), namespacePrefix, namespaceNode ); put( param.getName(), param ); } } } catch (TransformerException e) { throw new DialogException("Cannot find: " + xpath, e); } } catch (Exception e) { throw new XMLException( "Cannot get XParameterList", e); } } }
104
Nuance Proprietary
class XParameter implements IDomElementReader { public static final String XML_ELEMENT_NAME = "parameter"; public static public static public static "value"; public static "default"; private private private private final String XML_ATTRIB_NAME = "name"; final String XML_ATTRIB_TYPE = "type"; final String XML_ATTRIB_VALUE = final String XML_ATTRIB_DEFAULT =
public String getXMLElementName() { return XML_ELEMENT_NAME; } public String getAttribute(Node node, String attributeName) { NamedNodeMap map = node.getAttributes(); Node n = map.getNamedItem(attributeName); if (n == null) { return null; } else { return n.getNodeValue(); } }
Nuance Proprietary
105
public void readFromDomElement( Element element, String namespacePrefix, Node namespaceNode) throws XMLException { name_ = getAttribute(element, XML_ATTRIB_NAME); type_ = getAttribute(element, XML_ATTRIB_TYPE); if( type_.equalsIgnoreCase( "String") ) { value_ = new String(getAttribute( element, XML_ATTRIB_VALUE)); if( null != getAttribute( element, XML_ATTRIB_DEFAULT)) { default_ = new String(getAttribute( element, XML_ATTRIB_DEFAULT)); } } else if( type_.equalsIgnoreCase( "Integer") ) { value_ = new Integer(Integer.parseInt( getAttribute(element, XML_ATTRIB_VALUE))); if( null != getAttribute( element, XML_ATTRIB_DEFAULT)) { default_ = new Integer(Integer.parseInt( getAttribute(element, XML_ATTRIB_DEFAULT))); } } } public String getName() { return name_; } public void setName(String string) { name_ = string; }
106
Nuance Proprietary
public Object clone() { Object clone = null; try { clone = super.clone(); } catch(CloneNotSupportedException e) { // should never happen // because we have implemented clone, // so it is supported throw new RuntimeException(e); } return clone; } } public void execute(IStepRequest request, IStepResponse response) throws DialogException { XParameterList parameterList = new XParameterList(); //read parameter list from xHMI IDomElementReader reader = getConfig( getApplication().getNamespacePrefix() + ":" + XParameterList.XML_ELEMENT_NAME, parameterList, DialogManagerConstants.SCOPE_NODE, true); // access parameters (this sample does not // make use of the default value) XParameter param = (XParameter)parameterList.get("morning"); int morning = ((Integer)param.value_).intValue(); param = (XParameter)parameterList.get("evening"); int evening = ((Integer)(param).value_).intValue(); param = (XParameter)parameterList.get("morningPrompt"); String goodMorning = ((String)(param).value_); param = (XParameter)parameterList.get("eveningPrompt"); String goodEvening = ((String)(param).value_); param = (XParameter)parameterList.get("helloPrompt"); String hello = ((String)(param).value_);
Nuance Proprietary
107
// calculate prompt text String greetingPrompt = new String( hello ); Calendar calendar = new GregorianCalendar(); int hour = calendar.get(Calendar.HOUR_OF_DAY); if( hour < morning ) { greetingPrompt = goodMorning; } else if( hour > evening ) { greetingPrompt = goodEvening; } XInitial initial = new XInitial(); initial.add(new XOutput(greetingPrompt)); // write output to step response response.putInitialOutputList(initial); super.execute(request, response); } }
You can access the application from a node simply by calling getApplication and casting the result to your application class. For example:
MyApplication app = (MyApplication)getApplication();
Do not store any dynamic session data in the application object because the data will be lost in the case of a session failure and re-initialization. Instead, store all dynamic data in the SessionFrame.
108
Nuance Proprietary
Rendering
OSD renders Voice XML 2.0 pages and sends them to your browser. It implements the rendering system using jsp pages stored in installDir\voiceXML\jsp. The jsp pages use a JSP tag library using the xhmi-voicexml.tld descriptor file. OSD stores the file in installDir\voiceXML\jsp\WEB-INF. Applications must copy the file to their WEB-INF folder. OSD provides these jsp pages:
collection.jspplays prompt and collects user input error.jspused internally by OSD outputExit.jspoptionally plays prompts and exits outputOSDM.jspoptionally plays prompts and calls an OSDM outputSync.jspplays a prompt and triggers VoiceXML generation return.jsphandles the return from a component to the calling application root.jspused internally by OSD root-nocache.jspused internally by OSD start.jspused internally by OSD submit.jspinvokes a transfer to another VoiceXML application transfer.jspinvokes a call transfer
These pages correspond to the predefined <vuiforward> properties _collection, _outputExit, _transfer, plus the vui forward key defined by the class OSDMNode: callOSDM. In addition to the Render Data objects defined by xHMI, OSD uses the following Render Data object:
Key RenderOsdmGeneric Object OSDMCallDesc
In this table the key is an entry in the hash map of Render Data objects contained in the step response
a complete rendering system completely (for example, to adopt a different markup language) is described in the OSD Integration Guide.
Application development topics Rendering 109
Nuance Proprietary
exports additional functionality with a VoiceXML <object> element. To use the functionality, an application needs to generate an appropriate VoiceXML page. For example, assume you want to use an object called X, and a call to this object needs two parameters a and b. The following example shows the desired rendering of VoiceXML when the parameter values are 42 and 43 (values chosen arbitrarily for this example):
<object name="X"> <param name="a" value="42"/> <param name="b" value="43"/> </object>
Create a custom node Configure the custom node in xHMI Change the <vuiforward> map in xHMI Create a jsp page
We need a custom node that sets a viuforward key to select the new rendering component. We define an arbitrary key (named "callX"). The node execute function looks like this:
public void execute(IStepRequest request, IStepResponse response) throws DialogException { setVuiForward(response, "callX"); response.setCommit(true); }
The node can set required parameters (a and b in the example scenario) because the runtime framework passes all properties that are visible to a node into the StepResponse as a Render Data object. Therefore, your xHMI configuration defines properties in the <config> section of the custom node. For example:
<config> <property name="a" value="42"/> <property name="b" value="43"/> </config>
You must map the vuiforward key created by the custom node to the jsp page that renders the VoiceXML. Any existing mappings are unchanged (even if they
Nuance Proprietary
are not used in the new custom node). Assume that the name of jsp page we want to create is callObjectX.jsp:
<vuiforward> <forward name="_collection" path="/collection.jsp"/> <forward name="_outputExit" path="/outputExit.jsp"/> <forward name="callX" path="/callObjectX.jsp"/> </vuiforward>
Above, this example assumes the new page resides in the root directory of the web application.
Create a jsp page
In our example scenario, the jsp page needs to render a VoiceXML document that makes a call to the object. It is beyond the scope of this document to explain this process in detail. However, we explain how JSP code can access the properties we need. For Render Data objects that contain properties, the runtime framework uses the key RenderPropertyList. The object returned for the key implements the interface IPropertyList. The Render Data object can be found in a StepResponse object. First, we retrieve this object from the HTTP request, and then we extract the property list. The following JSP fragment shows how to do this:
<%@page contentType="text/xml;charset=UTF-8" errorPage="/error.jsp" import="com.scansoft.osd.StepResponse" import="com.scansoft.xhmi.renderbeans.RenderBeanKeys" %> <% StepResponse stepResponse = (StepResponse)request.getAttribute ( RequestAttributeNames.STEP_RESPONSE ); IPropertyList props = (IPropertyList)stepResponse.get ( RenderBeanKeys. RENDER_PROPERTY_LIST); %> ... more VoiceXML here <object name="X"> <param name="a" value="<%=props.getValue("a")%>"/> <param name=""b" value="<%=props.getValue("b")%>"/> </object> ... more VoiceXML here
Note the use of the getValue function to access a property in the list. For more rendering information, study the JSP page supplied with the OSD installation.
Nuance Proprietary Application development topics Rendering 111
The example scenario above shows how to use a system-defined Render Data object to create a custom render component. You can also use arbitrary objects as your own Render Data object. The only requirement is that the key for storing these objects in the StepResponse must not conflict with any of the render keys defined by xHMI (see the appendix of reserved names in the xHMI Reference Guide). To add your object to the response, make a call like this inside the execute function of a node:
response.put("myKey", new MyClass());
112
Nuance Proprietary
Chapter 10
This chapter describes the model for handling application data in OSD and xHMI, including how to declare and use variables, access data from application components, and define new datatypes.
Recognition data (results from the recognizer). In xHMI, you define this data as attribute variables. For example:
<var name="destination" type="attribute" expr="'London'"> <param name="temporary" expr="true"/> <param name="verified" expr="false"/> <param name="homophone" expr="true"/> </var>
Application data of common datatypes: integers, double words, booleans, and strings. For example, this includes counters for purposes like retries, no-match recognitions, and how often a node has been entered. You can also store static strings to hold presentation data (such as the application name). In xHMI, you define this data as typed variables. For example:
<var-list> <var name="maxIndex" type="int" expr="17" /> <var name="counter" type="int" expr="maxIndex + 2" /> <var name="pi" type="double" expr="3.1415" /> <var name="isValid" type="boolean" expr="true" />
Nuance Proprietary
113
Application data of complex datatypes: you can define Java classes for any complex type, and then define xHMI variables of these types. For example:
<var name="rc" type="class:org.examples.beans.MyComplexType"> <param name="age" expr="1 billion years"/> <param name="message" expr="'hello World'"/> <param name="version" expr="1.0"/> </var>
ECMAScript variables. You can define and use data within ECMAScript, and you can use xHMI variables in ECMAScript expressions. See Accessing variables with ECMAScript.
Below is a attribute facade variable. This example refers to a fictitious class org.example.MyFacade as an example of a user-defined Java extension to OSD.
1Some
severe errors (for example, errors in xHMI configuration files) throw the general error event. The event message provides details. When enabled, the diagnostic log (osd.log) contains an exception trace.
Nuance Proprietary
114
The class accepts the parameter namelist, which is defined in the extension. The namelist is a string with attribute names separated by white space:
<var name="myFacade" type="facade:org.example.MyFacade"> <param name="namelist" expr="'myAttribute'"/> </var>
Below, the ECMAScript appears in a conditional target. If myAttribute is defined, the path is taken:
<target condexpr="myAttribute.def()" path="#next"/>
Here is a guard condition. The node is entered if myAttribute is not yet defined:
<node id="n1" class="Collection"> <guard condexpr="myAttribute.undef()"/> ... </node>
Here is a script that creates the ECMAScript variable z and assigns the top n-best results associated with the xHMI variable myAttribute:
<script> var z = myAttribute.best(); ... </script>
The following example shows a complex datatype called agent. You could create such a datatype by extending org.examples.bean.MyComplexType with the identifier agent. You must define the variable before using it in a script; for example:
<var name="agent" type="class:org.example.beans.MyComplexType"/>
The example sets three properties of the agent: age, version and message. (Not shown are the variable declarations, which must be done before the script executes.)
Nuance Proprietary The OSD Datamodel Overview of variables and data storage 115
The following example is equivalent to the previous. It gets the same result with different syntax using ECMAScript setter methods:
<script> agent.setAge(39); agent.setVersion(3.0); agent.setMessage('hello'); </script> Passing variables to subdialogs
When your application transitions to a subdialog, you can pass variables to the subdialog as parameters. This example passes two variables (myAttribute and myCounter):
<target path="MySubdialog(myAttribute myCounter)"/>
You can pass any <var> of any type, but when using a variable for recognition purposes it must be an attribute datatype. In other words, the following xHMI elements require attribute variables:
The passed variables are available in the target subdialog using the names defined in the dialogs parameter list. Above, myAttribute and myCounter become known as attrib1 and count1. Changes to these local variables also change values in the higher scoped variables. For example, setting count1 to 5 above, results in myCounter=5 in the parent dialog.
116
Nuance Proprietary
Nuance Proprietary
117
Complex datatypes Custom nodes Attribute facades Update rules Extensions to the nodes, facades, and update rules provided with OSD
When creating a class, implement the IDataModel interface to gain access to the datamodel. In general, this means the following:
IDataModel model = // get datamodel instance Object varObj = model.get("myAttribute"); AttributeBean attr = (AttributeBean) varObj; // use the attribute Access from a custom node
To get the datamodel from a custom node, extend DialogNode and use the getDataModel method. For example:
public class MyNode extends DialogNode { public void execute(IStepRequest request, IStepResponse response) { IDataModel model = super.getDataModel(); // the model is accessed // now get any data in the model ... } }
Above, DialogNode is the base class for all nodes. Use getDataModel to return the current scope of the IDataModel instance. The getDataModel method has the signature:
public IDataModel getDataModel(); Access from an update rule
To write to the datamodel from an update rule, implement the IUpdateRule interface. For simplicity, also implement the IDataModelAccess interface to automatically reference the datamodel in the instantiated rule before the rule is initialized. (For information on update rules, see the xHMI Reference Guide.) For example:
public class MyUpdateRule implements IUpdateRule, IDataModelAccess {
118
Nuance Proprietary
private IDataModel model = null; private String attrName = null; //OSD calls this method after you create an instance of this // updater rule and before it calls the init method. public void setDataModel(IDataModel model) { this.model = model; } //Initialize this instances of the update rule, taking a list // of attribute names separated by whitespace. // This implementation only expects one attribute on the list. public void init(String variableNames) throws DialogException { this.attrName = variableNames.split("\\s")[0]; } //Define behavior when update rule runs as a pre-update rule. public void preUpdate( INbestResult nbestResult, ISessionFrame sf) throws DialogException { AttributeBean attr = (AttributeBean) model.get(attrName); // work with the attribute bean ... } public void postUpdate( INbestResult nbestResult, ISessionFrame sf) throws DialogException { } } Access from an attribute facade
To get the datamodel from an attribute facade, implement the IAttributeFacade interface. For simplicity, also implement the IDataModelAccess interface to automatically reference the datamodel in the instantiated facade before using the facade. For example:
public class MyAttributeFacade implements IAttributeFacade, IDataModelAccess { private IDataModel model = null; //OSD calls this method after you create an instance of this // updater rule and before it calls the init method. public void setDataModel(IDataModel model) { this.model = model; }
Nuance Proprietary
119
//A user defined method for this attribute facade. public String someFacadeMethod() { AttributeBean attr = (AttributeBean) model.get("myAttribute"); return attr.getBest(); } }
Above, DefaultAttributeFacade is the base class. Use getDataModel to return the current scope of the IDataModel instance. The getDataModel method has the signature:
public IDataModel getDataModel(); Access from a custom bean
Your JavaBeans must implement the interface IDataModelAccess. OSD uses dependency injection to provide IDataModel references to instances of each bean. For example, this bean implements the interface, sets the model, and gets an xHMI variable named myAttribute:
public class MyComplexType implements IDataModelAccess { private IDataModel model = null; //OSD calls this method after you create an instance of this // updater rule and before it calls the init method. public void setDataModel(IDataModel model) { this.model = model; } public String getAttrValue() { AttributeBean attr = (AttributeBean) model.get("myAttribute"); //Return the best choice from the recognition result. return attr.best(); } // ... see myComplexType in Writing your own bean }
The getAttrValue method is only defined in this class (for bean instances). You can use it in xHMI as follows:
<script>rc.getAttrValue()</script>
ISessionFrame methods
amb(java.lang.String qname)returns true if the specified attribute's first best value is ambiguous, false otherwise. Returns a boolean.
120
Nuance Proprietary
best(java.lang.String qname)returns the first best value of an attribute or null if it does not exist in the current node, one of the dialogs on the stack or in global scope. Returns a java.lang.String. conf(java.lang.String qname)returns the confidence (0..1.0) of the first best value of an attribute or 0 if it does not exist in the current node, one of the dialogs on the stack or in global scope. Returns a double. def(java.lang.String qname)checks whether attribute is defined. Returns a boolean. hom(java.lang.String qname)returns true if the specified attribute's first best value is homophone, false otherwise. Returns a boolean. nbest(java.lang.String qname, int order)returns the n-th best value of an attribute or null if the attribute does not exist. Returns a java.lang.String. nconf(java.lang.String qname, int order)returns the confidence of the n-th best item of an attribute or 0 if the attribute does not exist. Returns a double. nsay(java.lang.String qname, int order)returns the representation of the best items in a format that is suitable for output generation. Returns a java.lang.String. say(java.lang.String qname)returns the representation of the best items in a format that is suitable for output generation. Returns a java.lang.String. undef(java.lang.String qname)checks whether an attribute is not defined. Returns a boolean. unver(java.lang.String qname)checks whether attribute is not verified. Returns a boolean. ver(java.lang.String qname)checks whether attribute is verified. Returns a boolean.
The expression mySlot.best() uses simpler syntax. If the variable is undefined, the expression throws error.script.execution. You can use s.best('mySlot') even when mySlot is not defined (in which case the ISessionFrame instance returns null).
Nuance Proprietary
121
AttributeBean methods
AttributeBean methods clear() : return void amb() : return boolean best(): return String nbest(int): return String say(): return String nsay(int): return String conf(): return double nconf(int): return double def(): return boolean undef(): return boolean ver(): return boolean unver(): return boolean getAmbiguousCount(): return int skip(String): return void like <clear name/> like s.amb like s.best.. like s.nbest like s.say.. like s.nsay like s.conf.. like s.nconf like s.def.. like s.undef.. like s.ver.. like s.unver.. like s.amb add value to skip list of this attribute bean, like IAttribute#skip()
Writing a factory
You can define a complex variable in the xHMI configuration, and then use a factory in OSD to instantiate a JavaBean object of the desired class in the datamodel. OSD provides the following predefined factories:
In addition, you can create factories of your own, and use these factories to create classes conveniently without knowing their concrete type.
122
Nuance Proprietary
If you anticipate creating objects with many parameters, then a factory simplifies and significantly reduces the xHMI configuration. If you need access to an external registry like JNDI or Spring, a factory creates a bridge between the registry and the contents of the xHMI datamodel. This is possible because a factory can contain arbitrary Java code that accesses xHMI variables and interacts with the external entity.
Implementing IDataElementFactory
To write a factory, implement the interface IDataElementFactory. The interface defines a create method that your implementation must provide to create objects of the desired type. Any JavaBeans or factories that you create must have a default constructor in the implementation. (Other constructors are also allowed.) OSD uses the default constructor to initialize variables defined with <var name="a" type="z"/>. In other words:
When you do not define expr, OSD uses the default constructor. When you define expr, OSD uses the constructor for the type of the expr result. If this constructor is not present, OSD throws the error.datamodel event.
* For example, the scheme 'class' would call the class loader. * This loads the class and creates an instance * of the loaded class. */ public Object create(String uri, IDataModel dm); }
The framework instantiates factories when executing their corresponding <var> elements, and then removes them after building the variable. Therefore, your factory implementations must not store data for individual application sessions.
Configuring factories
After creating a new IDataElementFactory class, you must configure it in the /WEB-INF/lib/osd-config.xml configuration file. During runtime initialization, the osd-config.xml configuration file defines the available datatypes and their classes. For example:
<osd-config> <var-types> <!-- predefined datatypes provided with OSD -> <var-type name='int' class='java.lang.Integer'/> <var-type name='string' class='java.lang.String'/> <var-type name='double' class='java.lang.Double'/> <var-type name='boolean' class='java.lang.Boolean'/> <var-type name='attribute' class='com.scansoft.osd.datamodel.AttributeBean'/> </var-types> <var-factories> <!-- predefined factories provided with OSD -> <var-factory name='class' class='com.scansoft.osd.datamodel.ClassFactory'/>
124
Nuance Proprietary
<var-factory name='facade' class='com.scansoft.osd.datamodel.FacadeFactory'/> <!-- example user-defined factory -> <var-factory name='record' class='org.examples.beans.MyComplexType'/> </var-factories> </osd-config>
Above, you can create new types and classes, and insert them into the configuration file. Also, you can replace any class with an implementation of your own. For example, if you implement a variant for integers, you can map int to a class other than java.lang.Integer.
Implementing IDataModelAccess
Applications must implement this interface in any object (such as a bean, update rule, attribute facade, or class factory) that accesses the OSD datamodel and SessionFrame interfaces. In response, OSD automatically injects the datamodel into the object when the object is created.
public interface IDataModelAccess {
Nuance Proprietary
125
The injected instance of the datamodel is appropriately scoped, and all variables are available. This includes OSD variables such as __callId, __callerId, and __ calledId (as described in the xHMI Reference Guide).
import javax.naming.InitialContext; public class JNDIFactory implements IDataElementFactory { private InitialContext context = new InitialContext(); public Object create(String schemeSpecificPart) { return context.lookup(schemeSpecificPart); } }
<osd-config> <var-types> ... </var-types> <var-factories> ... <var-factory name="jndi" class="com.scansoft.osd.datamodel.JNDIFactory"/> ... </var-factories> </osd-config>
126
Nuance Proprietary
Above, the example gets weatherforecast from the JNDI local context, which must contain an instance of the org.examples.jndi.WeatherService class. Then, you can use myBean to access the methods of the class as follows (we assume the class implements a temperature method:
<script> var t = myBean.temperature(); </script>
Nuance Proprietary
127
128
Nuance Proprietary
Chapter 11
FAQ
In xHMI <transition>, use the "condexpr" attribute of <target> to write some conditions using ECMAScript. This approach has the advantage that you only need one Java class (independent from the conditions), because the conditions are expressed in xHMI. The disadvantage is that sometimes the expressions might get too complicated to be written and debugged in ECMAScript. b Write a java node with an empty execute function and a transition function that checks your condition:
Nuance Proprietary
129
public String transition(StepResponse response) throws DialogException { if (getSessionFrame().best("varname").equals("G")) { return "good"; } else if (getSessionFrame().best("varname").equals("B")) { return "bad"; } }
Q: How can I specify branching conditions in xml when a node always returns the same transition property. A: You can use more than one <target> elements within a <next> element, each with a condition. See the xHMI Reference Guide for details.
130
Nuance Proprietary
the access to the best value of an Attribute or the confidence of that. For example:
s.best('varname')
gives you the value of the first best attribute. This is equivalent to:
$s.get('varname').getFirstBest().getText()
You can also put arbitrary objects into the SessionFrame with getObject and putObject. These are stored in a hashtable. So, in ECMAScript you would access them with:
((MyClass)s.getObject('myname')).getSomeMember()
To access the SessionFrame, call the getSessionFramemethod. This example, adds a new attribute and assigns a value to it.
public void addAttribute(String qname, String value)
Nuance Proprietary
131
Your custom pages will not benefit from feature updates and bug fixes in future OSD releases. Your custom jsp pages are required to support OSI logging. This is an error-prone task that easily leads to a situation where problems occur only very late in the development process (for example, only when logged data is analyzed).
132
Nuance Proprietary
In rare circumstances, an application developers might want to create their own pages. Example reasons:
To use a VoiceXML object tag to trigger non-VoiceXML functions of the browser platform. To use custom ECMAScript on the generated page. To generate different mark-up such as SALT.
Nuance Proprietary
133
134
Nuance Proprietary
Chapter 12
An xHMI speech or multi-modal application typically consists of one or more xHMI files, a web deployment descriptor file (web.xml), grammar files, audio files, Java files for custom nodes and backend logic. It is beyond the scope of this document to describe the development process for such an application in detail. However, it is assumed that the development process roughly follows the process in the picture below. Usually such a process is iterative, that is a version of the application is created with a subset of the functionality, it is then tested and refined and tested again and so on until it the application meets all test criteria.
Nuance Proprietary
133
In this document, we focus on the aspects of the lifecycle that are closely related to xHMI. (These are depicted in the white boxes).
Application design
Application design includes the specification of every possible interaction with end-users: the prompts, the speech grammar coverage, and the expected
134
Nuance Proprietary
recognition results. All these specifications are reflected in the applications xHMI configuration. At the highest level of organization, the xHMI configuration consists of dialogs and nodes: major branches of the application are represented by <dialog> elements; individual interactions are represented by <node> elements. The callflow (as embodied in dialogs and nodes) can be highly conditionalized. That is, the nodes that are visited and prompts that are played can change depending on current state of the session with the caller. This is a key strength of OSD applications; they are not limited to linear (directed-dialog) callflow models. Instead, OSD applications are most versatile when employed for information-driven or state-driven models. For example, you might design a directed-dialog as the default callflow:
System User Do you want ice cream or pizza? Ice cream
System User
System User
The default callflow can be conditionalized (in the xHMI configuration instead of the application code) depending on the data collected (an information-driven dialog):
System User Do you want ice cream or pizza? Ice cream cone.
System
Nuance Proprietary
135
OSD relies on a design that defines the individual pieces information needed, that collects the pieces, and that changes depending on which pieces have been collected. For example, the previous example might have evolved as follows:
System User Do you want ice cream or pizza? Small ice cream.
System
Cone or cup?
Define the branches of the application, the tasks to be accomplished in each branch, and the primitive activities that comprise each task.
Each branch of the application is a single, self-contained dialog (<dialog>). Each primitive activity in the callflow is a node (<node>). Each node collects information, sends information, interacts with a database, or calls an object such as a SpeechPAK or an OpenSpeech DialogModule (OSDM).
One goal is to determine the optimal size of a task by balancing tasks that are small enough to be generic and reusable yet large enough to perform a meaningful transaction.
Define the root dialog of the application, and the root nodes of each dialog:
Define a root dialog, the first dialog that runs at the start of every session. Define a root node inside each dialog, the first node that runs in the dialog.
Specify the transitions (<transition>) between the nodes. A transition happens when all callflow activity is completed inside the current dialog and node.
136
Nuance Proprietary
Define the possible states (success, failure, and so on) at the end of each node. Define the possible targets (<target>) for the next dialog or node Define the conditions for choosing the correct target to when transitioning from the current node or dialog.
Define how error situations are handled (<catch>). Consider an operator fallback. Define the information collected by each node, and the likely vocabulary words used by callers. Specify a label for each piece of data (<var>). Define an OpenSpeech Insight (OSI) transaction for each high-level application branch, mid-level application task, and detailed-level node. To prove that the callflow meets application objectives, there should be at least one transaction for each application requirement. Transactions are logged (<log>), added to OSI databases, and used for generating reports (for example, transaction success rates) and tuning (for example, locating correcting dialogs and nodes with high failure rates).
Globally recognized (for example, for commands and shortcuts). Statically recognized (the expected utterances are known in advance and the speech grammar can be written before the runtime session begins). Dynamically recognized (the expected utterances are identified during the session and the speech grammar must be written at runtime by the application.
You can write highly-constrained or minimally-constrained speech grammars. This includes robust parsing grammars (grammars that distinguish meaningful phrases within longer utterances) and natural language grammars (grammars that categorize each utterance based on large samplings of possible sentences and their intended meanings).
Nuance Proprietary
137
Application development
Steps for coding an xHMI application: 1 2 3 4 5 Create a directory structure. Configure the application (create xHMI files). Test the application callflow. Implement grammars. (Not described in this guide.) Create recordings. (Not described in this guide.)
Here are details: myappStorage of jsp pages (or links to the pages). The jsp pages from install-dir\voiceXML\jsp need to be copied (or linked) into the application root directory. If you use Ant as build tool, the Ant build.xml goes into this directory. myapp/audioContains waveforms (caller utterances) collected by the application. myapp/grammarsContains speech and DTMF grammars. myapp/logContains application-dependent log files. Use this directory for diagnostic log files created by log4j. The log4j.properties file supplied in the /samples directory shows how to set the log file location. For more information, see Diagnostic logging on page 58.
138
Nuance Proprietary
myapp/xhmi/appContains appconfig.xhmi (the xHMI configuration file) and global.prop (global properties). myapp/xhmi/dtdContains a copy (or link) to the xHMI DTD file. myapp/xhmi/incContains xHMI include files. myapp/WEB-INFContains files needed by the application including classfiles, libraries, taglib tld files, and files for any custom nodes such as a database access node. Some specific files in the directory:
log4j.propertiesThe log4j configuration properties. messages.xmlLocalized alarm messages in different languages. web.xmlThe web application configuration file. A copy (or link) of the tag descriptor file: install-dir\voiceXML\jsp\WEB-INF\ xhmi-voicexml.tld
myapp/WEB-INF/libContains copies (or links) to all OSD jar files. The files are located in the following directories:
install-dir\lib install-dir\Shared\java\lib\ext
myapp/WEB-INF/srcThe source code for any customization needed by the application (for example, for a custom database access node). myapp/WEB-INF/testContains all code for unit tests (source code, dtds, data, etc.) See Testing on page 143. myapp/WEB-INF/test/srcContains only the source code for unit test classes. See Testing on page 143.
The dtd (Document Type Definition) for xHMI configurations can be found in <installdir>/system/xhmi.dtd. It consist of two entities: xhmi_main.dtd and custom.dtd. We recommend you copy these three files into a directory relative to the location of you xHMI file. In your applications xHMI file you can then use a DOCTYPE declaration such as the following: <!DOCTYPE xhmi SYSTEM "dtd/xhmi.dtd">
Nuance Proprietary
139
The dtd can be extended by declaring new elements in the custom.dtd file. A typical use case is when a node requires a new xml element inside <config>. The dtd for these elements accept "any", element, so declaring them in custom.dtd will suffice.
Validating with a W3C schema
A mechanism similar to the dtd is provided for schema validation. The schema files (*.xsd) can also be found in <installdir>/system." For schema validation, declare attributes in the xHMI root element (instead of using DOCTYPE) as shown in the following example:
<xhmi root="Main" xmlns:xi="http://www.w3.org/2001/XInclude" xml:lang="en-US" xmlns="http://www.scansoft.com/2004/xhmi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.scansoft.com/2004/xhmi xhmi.xsd">
If the application needs to access some backend logic, such as a transactional system or a database, custom nodes are used to implement the desired behavior. Sometimes an application developer might also choose to implement decision logic in Java instead of building the logic with ECMAScript expressions in xHMI. Any Java IDE, such as Eclipse can be used for this step. See also, Application development topics on page 85.
General activities
Design the behavior of the application, and divide the main user tasks into separate modules. In xHMI, use a separate <dialog> for each module, and within each <dialog>, use a <node> for each phase of interaction with the user. For example, a corporate speech application might have these modules:
greetings and security checks corporate information and promotions employee directory technical support good-byes and follow-up
Each module has a node for each subtask. For example, greetings and security checks might have nodes for public greeting, internal greeting, and security password. Within each <node>, define the needed configuration, prompts, slots, grammars, and transitions. To re-use definitions, define them at the dialog or global scopes.
140
Nuance Proprietary
Nuance Proprietary
141
142
Nuance Proprietary
Chapter 13
Testing
grammar testingtesting that the grammar delivers the expected semantic results with a variety of different utterances call-flow testtesting that the application behaves in the way expected with a variety of semantic inputs backend interface testtesting the access to a backend system system testtesting the complete system, usually by making telephony calls acceptance testtesting the system at the customer's premises
A speech application test is often executed by making phone calls into a life system. The system is comprised of a number of complex sub-systems, such as the telephony switch, a VoiceXML gateway with a browser, an application server and a backend system such as a database. Testing an application under development in this way can be a cumbersome procedure, because the application will show errors, in which case, after fixing the error, the process of deploying and calling has to be repeated. With OSD you simply the process by executing the call-flow tests at a Java API level, without the need to deploy the application. In this way it is possible to create automatic regression tests for an application.
Nuance Proprietary
Testing
143
From the xHMI architecture, recall the separation of the Front-end Controller and the DialogManager:
*.xHMI
Application
update
Session Frame
Front Controller
Dialog Manager
Dialog Node
create
At the IDialogManagerInvocation interface (a), many aspects of an application can be examined. We will use this interface for callflow testing:
(a)
Tester
Dialog Manager
Create and initialize an application object. The xHMI file is read during initialization. Create a DialogManager, passing in the application object Make a start request by calling the stepRequest method Test that the StepResponse contains the expected Render Data objects and test their content
144
Nuance Proprietary
Setup the semantic input, i.e. the results that would have been created by the recognizer Make a further request supplying the results
During execution of the nextStep method, the DialogManager executes one or several nodes. If one of these nodes accesses the backend system, this access is included in call-flow testing. The StepResponse object contains the Render Data Objects that would have been used to render the markup in a deployed system. Information that can be retrieved from these objects is e.g. a list of activated grammars and a list of prompts. The OSD library contains a support class that facilitates the access to these objects. See class com.scansoft.osd.test.TstSupport. A test program can also access the SessionFrame object with:
ISessionFrame dialogManager.getSessionFrame();
From the SessionFrame, the current dialog and node names can be read as well as the SessionFrame attributes and user objects. The following is a small example of how such a test looks like. You can find a more comprehensive example in a subfolder of the pizza sample application: \samples\pizza\test\src\com\scansoft\osd\samples\pizza\TestPizzaOrder Both examples are using JUnit, a popular unit test framework (see www.junit.org). However, any other suitable test software can also be used.
public void testFirstInitialOutput() { try { String configFileName = appRoot + "/output.xhmi"; Application app = new Application(); app.init(appRoot, configFileName); DialogManager dm = new DialogManager(app, "ABC", "usrid", "1235", "callerId", "calledId", "callId", null); dm.init(); StepRequest request = new StepRequest(); StepResponse response = dm.nextStep(request); assertEquals("__exitDialog",
Nuance Proprietary
Testing
145
dm.getSessionFrame().getCurrentDialogName()); assertEquals("__exitNode", dm.getSessionFrame().getCurrentNodeName()); assertEquals(2, TstSupport.getNumberOfQueuedOutputs(response)); assertEquals("Hello World from Nuance", TstSupport.getFirstQueuedOutput(response)); assertEquals("GoodBye", TstSupport.getQueuedOutput(response, 1)); assertTrue(dm.isTerminated()); } catch (Exception e) { fail(e.getMessage()); } }
146
Nuance Proprietary
Appendix A
Predefined properties
Miscellaneous properties
Ambiguous recognition results
Applications can use the following properties to handle ambiguous recognition results for speech that has more than one meaning:
ambiguousSeparatorChar ambiguousGroupSeparatorChar
Above, the users response is ambiguous; it could refer to Frankfurt Oder or Frankfurt Main. A well-written speech grammar will detect ambiguous meanings and provide all possibilities in the recognition result; the grammar concatenates the meanings. For example, the top next-best item might appear as follows:
0 Frankfurt|frankfurt oder#frankfurt main
147
The application can configure guard conditions to control how the ambiguous meanings should be distinguished. Above, the pound sign (#) and pipe symbol (the vertical bar, |) are used inside the speech grammar as delimiters:
The pound sign (#) is a delimiter between ambiguous items (frankfurt oder and frankfurt main). To use a different separator, you must configure that delimiter with the following OSD property: ambiguousSeparatorChar
The pipe symbol (|) is a delimiter between an ambiguous group (Frankfurt) and the ambiguous items. To use a different separator, you must configure that delimiter with the following OSD property: ambiguousGroupSeparatorChar
OSILogServer
148
Nuance Proprietary
Property OSIVarNameUniqueCallID
Description This property defines the name of the VoiceXML variable that holds a unique call ID at any time during page execution. There is no default value. OSD checks for an ID set via a shadow variable in the platform adaptor and also check for a global xHMI property.
OSIUrlCallStart
This property selects the web application that handles the start of call event for execution of server-side OSI logging requests. Typically, this is a log OSDM. This parameter is mandatory for server-side OSI logging. See example below. This property selects the web application that handles the end of call event for execution of server-side OSI logging requests. Typically, this is a log OSDM. This parameter is mandatory for server-side OSI logging. See example below. This property selects the web application that handles the general application event for execution of server-side OSI logging requests. Typically, this is a log OSDM. This parameter is mandatory for server-side OSI logging. See example below.
OSIUrlCallEnd
OSIUrlLogApplication
149
150
Nuance Proprietary
Appendix B
Prerequisites
To run the commandline tools, your system requires the following:
Java SDK version 1.4.2 or higher with java.exe in the current path. OSD version 1.1. This release sets the environment variable SWIOSD to the OSD base directory and adds SWIOSD\bin to the path.
151
Windows command:
rl.bat (-i|--inputfile) <infile> (-o|--outputfile) <outfile>
Linux command:
rl.sh (-i|--inputfile) <infile> (-o|--outputfile) <outfile>
The tool reads the inputfile and extracts all outputs. Any output that has an id and an <audio> tag is written to the outputfile. The input and output parameters are required. The <infile> is the name of the xHMI configuration file. The <outfile> is the name of the recording list that will be created Given is the following output definition at node scope in the configuration file /xyz/appconfig.xhmi:
<output id="id1"><audio src="uri">text</audio></output>
(If there is audio file at the URI, then the text is played.) The recording list generator generates the following file:
file /xyz/appconfig.xhmi dialog DlgName node NodeName output-id id1 soundfile uri text text
This file now serves as input for the recording of the outputs. If the output is not specified in a node/dialog then the node/dialog fields contain the value none. Here is a more interesting example:
<output id="bla"> <audio src="problems.wav"> We could not understand you. </audio> <audio src="operator.wav"> An operator will assist you soon. </audio> </output>
152
Nuance Proprietary
Screen output:
Warning: Found an <output> element with multiple <audio> elements Warning: Found name mismatch: output id is 'bla', but audio file is called 'problems.wav' Warning: Found name mismatch: output id is 'bla', but audio file is called 'operator.wav'
Recording file:
file appconfig.xhmi appconfig.xhmi dialog OperatorTransfer OperatorTransfer node doTransfer doTransfer output-id bla bla soundfile problems.wav operator.wav text We could not understand you. An operator will assist you soon.
Nuance Proprietary Recording list tool (listing prompts for the recording studio)
153
Linux command:
gl.sh (-i|--inputfile) <infile> (-o|--outputfile) <outfile>
The input and output parameters are required. The <infile> is the name of the xHMI configuration file. The <outfile> is the filename of the recording list that will be created. This example shows a sample output file (the count of slots can vary).
dialog id none none none none Order Order Order node id none none none none size topping confirm grm id restart help starkey shortcut size none yes_no grm name restart.grxml __help.grxml starkey.grxml shortcut.grxml size.grxml topping.grxml Boolean __help __help pizzasize pizzasize pizzatopping yesNo pizzatopping slot 0 slot 1 grammar path path/to/grammars path/to/grammars path/to/grammars path/to/grammars path/to/grammars path/to/grammars builtin:grammar
154
Nuance Proprietary
Linux command:
validate.sh <filename>
The <filename> is the name of the xHMI configuration file. If errors occur they are written to the stderr device, warnings are written to stdout. The tool performs numerous validations; not all are documented. File-level validations:
Validation of the file against the DTD Validation of the reference to the root dialog (ensures the root dialog is defined) Validation of all references to root nodes in dialogs (ensures root nodes exist) Validation of path attributes of all nodes (ensures the specified paths exist)
check for duplicate symbols validate all <fills> elements to ensure that the name attributes used are previously declared in that scope validate all <verify> elements to ensure that the actor attributes used are previously declared in that scope validate all <verify> elements to ensure that the vcl attributes used are previously declared in any scope validate all <verify> elements to ensure that all names in the vcl' attribute are activated by grammars in visible scopes validate all <understand> elements to ensure that the attributes used in the namelist are previously declared in that scope check all <property> elements for suspicious names. For example:
155
When their names suggest that they are meant to override xHMI system properties but are missing the leading underscore character (_). When their names match a discontinued OSI logging property name.
validate values of properties check that each grammar (<grm> element) has a <fills> element as a child, except when the <fills> element is optional (when the <grmr> element has an event attribute). check consistency of all instances of verifyOutput against the VCL. This ensures that the used attributes or facades exist in one of the verify-output-list elements (on different scopes). for <verify> ensure that the vcl and appendvcl attributes are not used at the same time; also, ensure that any appended attributes are also declared.
156
Nuance Proprietary
Appendix C
Timestamp abbreviations
When using the OSD-provided classes for date and time, dates can be abbreviated as defined in the following grammar:
S fulldate datetime datez timez date date2 date3 time minute second year month day hour minute -> fulldate | datetime | datez | timez | date | time -> date ' ' time ' ' z -> date ' ' time -> date ' ' z -> time ' ' z -> year date2 | date2 -> '-' month date3 | date3 -> '-' day | *eps* -> hour time2 | time2 -> minute time3 | time3 -> second | *eps* -> ('0' | | '9') year | ('0' | | '9') -> ('0' | | '9') ('0' | | '9') -> ('0' | | '9') ('0' | | '9') -> ('0' | | '9') ('0' | | '9') -> ('0' | | '9') ('0' | | '9')
Nuance Proprietary
157
second z
-> ('0' | | '9') ('0' | | '9') -> ( '+' | '-' ) ( hour ':' minute | ':' minute | hour | hour ': ')
Above, *eps* is the empty word, terminal symbol are quoted. Other symbols are rule references.
158
Nuance Proprietary
Appendix D
Negative confirmations
When using robust parsing grammars (sometimes called open grammars), the ROOT rule is not a rule but a set of concepts. Although the following grammar is complete, the example does not show the additional files needed for robust parsing (fsm, wordlist, and userdict). See the OSR Grammar Developers Guide for details. Instead of a single ROOT rule, the ROOT rule is divided into individual rules; each rule is called by a rule-ref tag inside a concept tag. The concept tag then uses ECMAScript to copy the values into the returned slots.
<?xml version="1.0" encoding="UTF-8"?> <grammar version="1.0" xmlns="http://www.w3.org/2001/06/grammar" xml:lang="en-US" mode="voice" root="concepts"> <meta name="swirec_user_dict_name" content="my.userdict"/> <meta name="swirec_fsm_grammar" content="some.fsm"/> <meta name="swirec_fsm_wordlist" content="some.wordlist"/> <conceptset id="concepts" xmlns="http://www.scansoft.com/grammar"> <concept> <ruleref uri="#r_origin"/> <tag> origin = r_origin.origin; </tag> </concept> <concept> <ruleref uri="#r_origin_destination"/> <tag> origin = r_origin_destination.origin; destination = r_origin_destination.destination; </tag> </concept>
Nuance Proprietary
159
<concept> <ruleref uri="#neg_origin_destination"/> <tag> var tmp = ''; if (neg _origin_destination.origin != undefined) { tmp += (tmp!='' ? '**' : '') + 'origin*' + neg _origin_destination.origin; } if (neg _origin_destination.destination != undefined) { tmp += (tmp!='' ? '**' : '') + 'destination *' + neg _origin_destination. destination; } if (tmp != '') { NEG_GROUP = tmp; } </tag> </concept> <concept> <ruleref uri="#neg_origin"/> <tag> NEG_origin = neg_origin.NEG_origin; </tag> </concept> </concepts> <rule id="neg_origin_destination" <item> <ruleref uri="#r_not"/> <ruleref uri="#r_origin_destination"/> <tag> origin = r_origin_destination.origin; destination = r_origin_destination.destination; </tag> </item> </rule>
160
Nuance Proprietary
<rule id="neg_origin"> <item> <ruleref uri="#r_not"/> <ruleref uri="#neg_origin"/> <tag> NEG_origin = r_origin.origin; </tag> </item> </rule> <rule id="r_not"> <one-of> <item>not</item> </one-of> </rule> <rule id="r_origin"> <item> from <ruleref uri="#r_cities"/> <tag>origin=r_cities.v;</tag> </item> </rule> <rule id="r_origin_destination"> <item> from <ruleref uri="#r_cities"/> <tag>origin=r_cities.v;</tag> to <ruleref uri="#r_cities"/> <tag>destination=r_cities.v;</tag> </item> </rule> <rule id="r_cities"> <one-of> <item>boston<tag>v='boston';</tag></item> <item>austin<tag>v='austin';</tag></item> <item>houston<tag>v='houston';</tag></item> </one-of> </rule> </grammar>
The order of the concepts is defined by the training of the voice model for a robust parsing grammar and not by the order of the tags.
Nuance Proprietary
161
162
Nuance Proprietary