Next IVR

Providing innovative contact center solutions and services.

A GRXML Grammar for Alphanumeric IDs


In the health industry, I've frequently run into the following predicament:  User IDs are no longer simple numeric fields.  Traditionally, an employee's Social Security number may have been used as an id, but HIPAA has put an end to that.

For speech recognition, this could present a common tuning and maintenance issue.  The following XSLT document is designed to automate this maintenance.

First, let's take a look at some simple user IDs stored in my sample database.

SELECT UserIDs FROM SampleIDs
UserIDs
119821
319871
31987M
D19821
D1982M
D19871
...

You can see there are a few alphanumeric patterns being used with these IDs.  Using a simple replacement, we can get all the non-numeric patterns in the database:

SELECT
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(UserIDs,
'1', '_'), '2', '_'), '3', '_'), '4', '_'), '5', '_'), '6', '_'),
'7', '_'), '8', '_'), '9', '_'), '0', '_') AS
Pattern,
 COUNT(\*) AS RecordCount
 FROM SampleIDs
 GROUP BY
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(UserIDs,
'1', '_'), '2', '_'), '3', '_'), '4', '_'), '5', '_'), '6', '_'),
'7', '_'), '8', '_'), '9', '_'), '0', '_')
Pattern RecordCount
D_____  71680
_____M  57344
X____M  14336
D____M  71680
X_____  14336
______  57344

With this, we'll simply assume there is an even chance for any of these patterns being used on a call.  So, D_____ has the probability of 71680/286720 or a 25% chance of being provided.  Using this information, we can weight the probability of this pattern matching an utterance for a user ID.

First, I run the above SQL statement and put the results into a dataset.  You can simply create the XML from the recordset, too.  My XML results look like this:

<records>
  <record>
    <Pattern>D_____</Pattern>
    <RecordCount>71680</RecordCount>
  </record>
  <record>
    <Pattern>_____M</Pattern>
    <RecordCount>57344</RecordCount>
  </record>
  <record>
    <Pattern>X____M</Pattern>
    <RecordCount>14336</RecordCount>
  </record>
  <record>
    <Pattern>D____M</Pattern>
    <RecordCount>71680</RecordCount>
  </record>
  <record>
    <Pattern>X_____</Pattern>
    <RecordCount>14336</RecordCount>
  </record>
  <record>
    <Pattern>______</Pattern>  
    <RecordCount>57344</RecordCount>  
  </record>  
</records>

Now comes the fun part - using XSLT to create a GRXML grammar file.

A couple of points about the XSL file:

  1. For the JavaScript function buildCharacterArray(s1), you could probably slim the function down to "return s1.split('');"  It splits a string into a character array.
  2. XSLT doesn't have a for-each loop, so I recursively call the buildItem template.
  3. In this example, the TAG is set as an attribute of the related ITEM element.  For other platforms, this may need to be an element trailing the ITEM element.  Of course, the tag syntax is different on each platform:(
  4. In the real world you may find, through transcriptions and tuning, that people may utter dashes and spaces, too, or say, "B as in boy."  They may also truncate leading 0's (00001214V may be spoken 1214V).
  5. It doesn't handle robust recognition for utterances like "nine double oh one seven" or "nine thirty nine twenty two."  Unless you find patterns through transcriptions and tuning, effectively accommodating this will drop your accuracy and performance through the floor.
  6. Use your web server to cache the GRXML output; there's no need to run it too often.

The resulting grammar looks like this :

<?xml version="1.0" encoding="utf-8" ?>  
<grammar xml:lang="en-US" version="1.0" root="main" mode="voice"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  xmlns:nextivr="http://www.nextivr.com/XSLFunctions"
  xmlns:rs="urn:schemas-microsoft-com:rowset">  
  <rule id="main" scope="public">  
    <one-of>  
      <item weight="0.25">  
        <ruleref type="application/srgs+xml" uri="\#D_____" />  
      </item>  
      <item weight="0.2">  
        <ruleref type="application/srgs+xml" uri="\#_____M" />  
      </item>  
      <item weight="0.05">  
        <ruleref type="application/srgs+xml" uri="\#X____M" />  
      </item>  
      <item weight="0.25">  
        <ruleref type="application/srgs+xml" uri="\#D____M" />  
      </item>  
      <item weight="0.05">  
        <ruleref type="application/srgs+xml" uri="\#X_____" />  
      </item>  
      <item weight="0.2">  
        <ruleref type="application/srgs+xml" uri="\#______" />  
      </item>  
    </one-of>  
  </rule>  
  <rule scope="private"
    id="D_____">  
    <item tag="D">D</item>  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
  </rule>  
  <rule scope="private"
    id="_____M">  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <item tag="M">M</item>  
  </rule>  
  <rule scope="private"
    id="X____M">  
    <item tag="X">X</item>  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <item tag="M">M</item>  
  </rule>  
  <rule scope="private"
    id="D____M">  
    <item tag="D">D</item>  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <item tag="M">M</item>  
  </rule>  
  <rule scope="private"
    id="X_____">  
    <item tag="X">X</item>  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
  </rule>  
  <rule scope="private"
    id="______">  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
    <ruleref type="application/srgs+xml" uri="\#number" />  
  </rule>  
  <rule scope="private" id="number">  
    <one-of>  
      <item tag="1">one</item>  
      <item tag="2">two</item>  
      <item tag="3">three</item>  
      <item tag="4">four</item>  
      <item tag="5">five</item>  
      <item tag="6">six</item>  
      <item tag="7">seven</item>  
      <item tag="8">eight</item>  
      <item tag="9">nine</item>  
      <item tag="0">zero</item>  
    </one-of>  
  </rule>  
</grammar>