Exercise 2: Building Custom Grammars

Grammars are used to recognize complex speech and DTMF input from the user. In this exercise, you will build a custom grammar declaratively using the Grammar-Xml (GRXML) syntax. You will also build a grammar dynamically at runtime using the Microsoft.Speech.Recognition.SrgsGrammar class in the UCMA 3.0 Workflow SDK.

Task 1 – Building a Custom Grammar with GRXML

  1. The EnterPIN activity expects a five-digit sequence of numbers. The ExpectedDtmfInputs property is not sufficient to properly describe this sequence; you would have to add every possible combination of five numbers between 1 and 9 as expected inputs. The solution is to use a DTMF grammar to declaratively describe the expected DTMF input.
  2. Add a new XML file to the WorkflowActivities project.
  3. Rename the XML file to PINGrammar.grxml.
  4. Open the properties of PINGrammar.grxml.
  5. Set Build Action to Content.
  6. Set Copy to Output Directory to Copy Always. When the WorkflowActivities project is compiled, PINGrammar.grxml is copied to the same location as the project’s binaries.

  7. Replace the contents of PINGrammar.grxml with the following.

    XML

    <grammar xml:lang="en-US" root="ValidPIN" mode="dtmf" tag-format="properties-ms/1.0" version="1.0" xmlns="https://www.w3.org/2001/06/grammar"> <rule id="digit" scope="public"> <one-of> <item>0</item> <item>1</item> <item>2</item> <item>3</item> <item>4</item> <item>5</item> <item>6</item> <item>7</item> <item>8</item> <item>9</item> </one-of> </rule> <rule id="ValidPIN" scope="public"> <one-of> <item repeat="5"> <ruleref uri="#digit"/> </item> </one-of> </rule> </grammar>
  8. You can specify if the grammar is restricted to DTMF by setting the mode attribute of the top-level grammar element to dtmf. Otherwise, the default behavior is that the grammar is used to validate both speech and DTMF input.
  9. A grammar is simply a set of rules. The first rule in this grammar dictates the input must be one-of the listed items in order to be valid. The items in the list are the numbers 0 through 9.
  10. The top-level grammar element specifies that the root rule for this grammar is the rule with the id of ValidPIN. The root rule is the main rule that the grammar will process. The ValidPIN rule references the digit rule and specifies that the sequence should be repeated five times.
  11. Switch to the workflow designer.
  12. Highlight the EnterPIN activity and open its properties.
  13. Set the value of the Grammars property to PINGrammar.grxml.

  14. Set the value of NoRecognitionPrompt to “Sorry, that is not a valid PIN”.

Task 2 – Building a Custom Grammar at Runtime

  1. You saw how the workflow presented the user with a list of tasks to choose from. In this simple example, the list came from an XML file included in the project.
  2. However, in a real life workflow, the task list would be retrieved from an external system such as a SQL Server database, or Microsoft Outlook. The workflow does not know in advance how many choices there are, so a static grammar does not work well in this case.
  3. Double-click the GetTasks activity and add the following code snippet to the end of the GetTasks_ExecuteCode event handler to create a grammar that validates the caller’s choice.

    Setting the ExpectedDtmfInputs property of the ChooseTask activity to null clears out the hardcoded settings in the activity. A grammar is constructed dynamically by creating an instance of SrgsDocument and adding rules to the grammar. A rule called Items that specifies that the caller must choose one of the valid task ids is created and added to the grammar’s Rules collection and specified as the root rule. The new grammar is added to the DtmfGrammars collection of the ChooseTask activity.

    C#

    // Clear out hardcoded expected Dtmf inputs this.ChooseTask.ExpectedDtmfInputs = null; // Create a dynamic grammar based on the number of tasks in the list var choices = new string[_tasks.Count]; choices = (from t in _tasks select t.Id.ToString()).ToArray(); var grammar = new SrgsDocument(); grammar.Mode = SrgsGrammarMode.Dtmf; var rule = new SrgsRule("Items"); var oneOf = new SrgsOneOf(choices); rule.Elements.Add(oneOf); grammar.Rules.Add(rule); grammar.Root = rule; // Clear out the grammars before adding a new one this.ChooseTask.Grammars.Clear(); this.ChooseTask.DtmfGrammars.Add(new Grammar(grammar));
  4. Switch to the workflow designer.
  5. Highlight the ChooseTasks activity and open its properties.
  6. Set the value of NoRecognitionPrompt to “Sorry, you did not select a valid task”.

Task 3 – Test the Custom Grammars

  1. Go to Debug >> Run Without Debugging or use the shortcut key [Ctrl]+[F5] to start the application.
  2. Open Microsoft Lync.
  3. Locate the contact associated with your provisioned UCMA 3.0 application, e.g. LabContact10600@fabrikam.com.
  4. Place an audio call to the contact. The attendant answers the call and welcomes the caller then prompts them to enter a five-digit PIN.
  5. Enter an invalid PIN, e.g. 1234*. The grammar specified in PINGrammar.grxml validates the PIN entered by the user and prompts the user that the input was not recognized. The activity’s NoRecognitionPrompt is played when the caller enters invalid input.
    1. Note: The Microsoft Lync numeric keypad allows the caller to enter numbers using the letters on the number keys. In order to enter some invalid input, enter * at the end of the PIN.
  6. Enter a valid PIN, e.g. 12345. The attendant retrieves a list of the caller’s active tasks and presents them as choices.
  7. Enter an invalid task number, e.g. 5. The dynamic grammar created at runtime will validate the user’s input and prompt the user to enter a valid choice.
  8. Hang up and close the call.
  9. Switch to the console application and press Enter. The application endpoint is terminated and the collaboration platform is shut down.