Writing robust parsing grammars

Robust parsing grammars are similar to regular SRGS grammars; however, they do bring up issues that do not appear in standard SRGS grammars.

Writing a good concept set requires analysis and planning:

  1. Identify the concepts that must appear in the concept set, based on the slots to be filled. Usually, you will create one <concept> entry for each grammar slot (see Advanced robust parsing grammars). Each concept defines the phrases that contain the information needed to fill the slot.
  2. Write the concept rules. It is important to follow some guidelines:
    • Specify short phrases that contain key words. Avoid words that are not needed to identify the concept, and that do not contribute to the meaning. Assuming the training set contains filler rules s(ub-phrases like “I'd like to” or “is it possible to”), Recognizer covers them as non-concept phrases, and you should not include them as part of concept rules. Each single concept defines a fully-constrained set of phrases, so only those parts of an utterance that exactly match a concept phrase can fill a slot.
    • Where possible, avoid ambiguous words or phrases. This is a good rule for all grammars, but particularly important in robust parsing. For example, if utterances contain natural numbers (for example, “thirty five, four, sixty two”), the recognition can complete three numbers (35 4 62), four numbers (35 4 60 2 or 30 5 4 62), or five numbers (30 5 4 60 2).
    • Clearly separate phrases across concepts, and do not use the same phrase in more than one concept. With a clear separation and specific meanings for phrases, the grammar will get better recognition accuracy. For example, a travel application may ask for the time of the reservation, and the number of passengers traveling. In this case, the time and no_of_passengers concepts cannot simply recognize a number, because it would be unclear which slot that number is intended to fill. Instead, you must add extra words to each concept to make the context clear: “two pm” fills time, while “two adults” fills no_of_passengers.
    • Do not use weights in concept rules: they conflict with the RP algorithm.
    • When referring to an external grammar for a concept rule, you must set swirec_compile_parser_with_weights to “0” in that grammar.
  3. Ensure that all vocabulary in the concepts is covered by your SLM. If not, the SLM will never produce the recognition text used by the concepts.

Detailed restaurant guide example

In this example, the application needs the robust parsing grammar to fill three grammar slots that represent the location, food type, and the approximate price of the restaurant. We expect utterances such as the following:

  • "I would like to go out for a fast food restaurant spending around five euros per person near the main plaza in Madrid."
  • "Hello is there a cheap barbecue restaurant in King’s square?"
  • "I want to go to south gate to an Italian restaurant."

Define concepts

We define three concepts, one for each slot. We do not care about the order of concept phrases in an utterance, nor are we interested in words or phrases that may appear before, after, or between the concept phrases. Recognizer will automatically use a filler rule to cover any sequence of words that is not a concept phrase. The conceptset for our example might look like this:

<conceptset id="concepts" xmlns="http://www.nuance.com/grammar">
    <concept>
        <ruleref uri="#c_location"/>
        <tag>location = c_location.V</tag>
    </concept>
    <concept>
        <ruleref uri="#c_type"/>
        <tag>type = c_type.V</tag>
    </concept>
    <concept>
        <ruleref uri="#c_price"/>
        <tag>price = c_price.V</tag>
    </concept>
</conceptset>
...

Define concept rules

The next step is to write the concept rules. For our example, we define simple concept rules "c_location," "c_type," and "c_price" as follows (a real application requires many more alternatives for each rule):

...
<rule id="c_location">
    <one-of>
        <item>madrid <tag>V="madrid";</tag></item>
        <item>kings square <tag>V="kings square";</tag>
        </item>
        <item>old town <tag>V="old town";</tag></item>
        <item>south gate <tag>V="south gate";</tag></item>
    </one-of>
</rule> 
<rule id="c_type">
    <one-of>
        <item>barbecue   <tag>V="barbecue";</tag></item>
        <item>chinese    <tag>V="chinese";</tag></item>
        <item>fast food  <tag>V="fast food";</tag></item>
        <item>german     <tag>V="german";</tag></item>
        <item>italian    <tag>V="italian";</tag></item>
    <item>vegetarian <tag>V="vegetarian";</tag></item>
    </one-of>
    restaurant
</rule>
<rule id="c_price">
    <one-of>
        <item>cheap <tag>V="10";</tag></item>
        <item>
            <item repeat="0-1">
            <one-of>
                <item>about</item>
                <item>around</item>
                <item>costing</item>
                <item>for</item>
                <item>spending</item>
            </one-of>
        </item>
        <ruleref uri="#number"/> <tag>V=number.V;</tag>
        euros
        <item repeat="0-1">per person</item>
        </item>
    </one-of>
</rule>
<rule id="number">
    <one-of>
        <item>five        <tag>V= "5";</tag></item>
        <item>ten         <tag>V="10";</tag></item>
        <item>fifteen     <tag>V="15";</tag></item>
        <item>twenty      <tag>V="20";</tag></item>
        <item>twenty five <tag>V="25";</tag></item>
        <item>thirty      <tag>V="30";</tag></item>
        <item>thirty five <tag>V="35";</tag></item>
        <item>forty       <tag>V="40";</tag></item>
        <item>fifty       <tag>V="50";</tag></item>
    </one-of>
</rule>
...

While the c_location rule contains a simple list of location names, the c_type and the c_price rules require that the words "restaurant" and "euros" be spoken. This can help the parser to identify the concepts in an utterance. On the other hand, if a caller does not say "restaurant," the "type" slot will not be filled.

For each application, the grammar writer must carefully decide which additional words (like "restaurant" or "euros") are needed in the concept rules. For example, for a timetable application it is important to distinguish between the departure and destination locations. Therefore, words like "from" and "to" must be added to the respective concept rules.

Add the FSM and wordlist to the grammar

Add references to the finite state machine and the wordlist in the robust parsing grammar. The completed grammar looks like this:

<?xml version='1.0' encoding='UTF-8'?>
<grammar xml:lang="en-US" version="1.0" root="concepts"
    tag-format="swi-semantics/1.0"
    xmlns="http://www.w3.org/2001/06/grammar"
    mode="voice">
<meta name="swirec_fsm_grammar" content="ngram_RG.fsm"/>
<meta name="swirec_fsm_wordlist" content=
    "ngram_RG.wordlist"/>
<conceptset id="concepts" xmlns=
        "http://www.nuance.com/grammar">
    <concept>
        <ruleref uri="#c_location"/>
        <tag>location = c_location.V</tag>
    </concept>
    <concept>
        <ruleref uri="#c_type"/>
        <tag>type = c_type.V</tag>
    </concept>
    <concept>
        <ruleref uri="#c_price"/>
        <tag>price = c_price.V</tag>
    </concept>
</conceptset>
<rule id="c_location">
    <one-of>
        <item>madrid <tag>V="madrid";</tag></item>
        <item>kings square <tag>V="kings Square";</tag>
        </item>
        <item>old town <tag>V="old town";</tag></item>
        <item>south gate<tag>V="south gate";</tag></item>
    </one-of>
</rule> 
<rule id="c_type">
    <one-of>
        <item>barbecue   <tag>V="barbecue";</tag></item>
        <item>chinese    <tag>V="chinese";</tag></item>
        <item>fast food  <tag>V="fast food";</tag></item>
        <item>german     <tag>V="german";</tag></item>
        <item>italian    <tag>V="italian";</tag></item>
        <item>vegetarian <tag>V="vegetarian";</tag></item>
    </one-of>
        restaurant
</rule>
<rule id="c_price">
    <one-of>
        <item>cheap <tag>V="10";</tag></item>
        <item>
        <item repeat="0-1">
            <one-of>
                <item>about</item>
                <item>around</item>
                <item>costing</item>
                <item>for</item>
                <item>spending</item>
            </one-of>
            </item>
            <ruleref uri="#number"/> <tag>V=number.V;</tag>
            euros
            <item repeat="0-1">per person</item>
        </item>
    </one-of>
</rule>
<rule id="number">
    <one-of>
        <item>five        <tag>V= "5";</tag></item>
        <item>ten         <tag>V="10";</tag></item>
        <item>fifteen     <tag>V="15";</tag></item>
        <item>twenty      <tag>V="20";</tag></item>
        <item>twenty five <tag>V="25";</tag></item>
        <item>thirty      <tag>V="30";</tag></item>
        <item>thirty five <tag>V="35";</tag></item>
        <item>forty       <tag>V="40";</tag></item>
        <item>fifty       <tag>V="50";</tag></item>
    </one-of>
</rule>
</grammar>