Sample DTMF recognizer client

Nuance Mix offers a simple Python client application that you may download and use for DTMF recognition using the DTMF Recognizer gRPC API.

Prerequisites

To run this client, you need:

Build the app

Download the zip file and extract its files into the same directory as the nuance directory, which contains your proto files and Python stubs.

The files are:

  • nr-dtmf-client.py: Sample python client.
  • run-nr-dtmf-client.sh: Convenience script to acquire a token and run the sample client.
  • generate-protobuf-and-grpc-python.sh: Convenience script to generate the python stubs from the proto file.
  • dtmf_months.grxml: Example GRXML grammar, could be loaded as a URI grammar if hosted on a web server.
  • README.txt: Brief information on how to run the sample client.
  • nuance/nrc/v1/nrc.proto: The gRPC proto file for the Nuance Mix service.

Run the app

Use this command to generate an access token and run the app, where 01234.ulaw is the relative or absolute path to the audio file:

./run-python-client.sh 01234.ulaw

The token authorizes the application to call the NRaaS service. It takes your credentials and stores the resulting token in an environment variable, MY_TOKEN.

Alternatively, you can include the token-generation code within the application, reading the credentials from a configuration file.

  View nr-dtmf-client.py  

You can use this client to request DTMF recognition, optionally including recognition resources such as inline or URI DTMF grammars for specific DTMF sequences.

The script generate-protobuf-and-grpc-python.sh can be used to generate the Python stubs from the proto file. These are the resulting client files, above the nuance directory holding the proto file and its corresponding Python stubs:

├── README.txt
├── generate-protobuf-and-grpc-python.sh
├── run-nr-dtmf-client.sh
├── nr-dtmf-client.py
├── dtmf_months.grxml
└── nuance
    └── nrc
        └── v1
            ├── nrc.proto
			├── nrc_pb2.py
			└── nrc_pb2_grpc.py

You can use this client to request DTMF recognition, optionally including recognition resources such as inline or URI DTMF grammars for specific DTMF sequences.

Edit shell script

First, edit the shell script, run-nr-dtmf-client.sh, to add your credentials to generate an access token. The script generates a token that authorizes the client to call the Nuance Recognizer service. It takes your credentials and stores the resulting token in an environment variable, TOKEN.

#!/bin/bash

CLIENT_ID="<ENTER_YOUR_MIX_CLIENT_ID_HERE>"
SECRET="<ENTER_YOUR_MIX_CLIENT_SECRET_HERE>"

# URL encode the client id by converting ':' characters to '%3A'
CLIENT_ID=${CLIENT_ID//:/%3A}

AUTHURL="https://auth.crt.nuance.com/oauth2/token"

# Acquire token from server, extract token string from the json response.
export TOKEN="$(curl -s -u "$CLIENT_ID:$SECRET" "$AUTHURL" \
  -d "grant_type=client_credentials" \
  -d "scope=nr" \
  | python -c 'import sys, json; print(json.load(sys.stdin)["access_token"])'
  )"

# Run the client. Pass the token and DTMF sequence to recognize as command line arguments.
./nr-dtmf-client.py nr.api.nuance.com:443 $TOKEN $1

Alternatively, you might incorporate the token-generation code within the client, reading the credentials from a configuration file.

This client accepts arguments positionally, without names:

server_address = sys.argv[1]
access_token = sys.argv[2]
dtmf_sequence = sys.argv[3]

Pass these arguments as you run the client using the shell script:

    • The URI of the Nuance Recognizer region and language group. For the United States region and North America language group: nr.api.nuance.com:443.
  • An access token generated by the Mix OAuth server, usually as an environment variable, in this example $TOKEN.

  • A string of the DTMF sequence to be recognized.

Run the recognition client

The client accepts a string specifying a sequence of DTMF digits. The client will send that sequence of DTMF digits to Nuance Recognizer to recognize them. The DTMFs are sent one at a time with some delay in between each to simulate a live DTMF entry.

Run the client from the shell script, passing it a DTMF sequence string. The client loads a builtin DTMF grammar and also an inline DTMF grammar that recognizes some interesting sequences. You can also specify these preset sequences: pi, e, phi, sqrt2.

Scenario 1: Recognize 1,2,3,4

This scenario recognizes the DTMF sequence 1 2 3 4:

$ ./run-nr-dtmf-client.sh 1234
Recognizing DTMF sequence: ['1', '2', '3', '4']

Sending recognition_init {
  parameters {
    no_input_timeout_ms: 6000
    dtmf_interdigit_timeout_ms: 3000
    dtmf_term_char: "#"
  }
  resources {
    builtin: "builtin:dtmf/digits"
    weight: 1
  }
  resources {
    inline_grammar {
      grammar: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><grammar xml:lang=\"en-US\" mode=\"dtmf\" version=\"1.0\" tag-format=\"swi-semantics/1.0\" root=\"NUMBERS\" xmlns=\"http://www.w3.org/2001/06/grammar\"><rule id=\"NUMBERS\" scope=\"public\"><one-of><item><ruleref uri=\"#PI\" /><tag>MEANING=PI.SWI_literal.replace(/.*/, \'PI\')</tag></item><item><ruleref uri=\"#E\" /><tag>MEANING=E.SWI_literal.replace(/.*/, \'E\')</tag></item><item><ruleref uri=\"#PHI\" /><tag>MEANING=PHI.SWI_literal.replace(/.*/, \'PHI\')</tag></item><item><ruleref uri=\"#SQRT2\" /><tag>MEANING=SQRT2.SWI_literal.replace(/.*/, \'SQRT2\')</tag></item></one-of></rule><rule id=\"PI\"><item>3</item><item>*</item><item>1</item><item>4</item><item>1</item><item>5</item><item>9</item></rule><rule id=\"E\"><item>2</item><item>*</item><item>7</item><item>1</item><item>8</item><item>2</item><item>8</item></rule><rule id=\"PHI\"><item>1</item><item>*</item><item>6</item><item>1</item><item>8</item><item>0</item><item>3</item></rule><rule id=\"SQRT2\"><item>1</item><item>*</item><item>4</item><item>1</item><item>4</item><item>2</item><item>1</item></rule></grammar>"
    }
    weight: 2
  }
}


DTMFRecognize() reponse --> status {
  code: 200
  message: "OK"
}

Sending DTMF 1

DTMFRecognize() reponse --> start_of_speech {
  first_audio_to_start_of_speech_ms: 1000
}

Sending DTMF 2
Sending DTMF 3
Sending DTMF 4
DONE Sending DTMFs

DTMFRecognize() reponse --> result {
  formatted_text: "<result><interpretation conf=\"1\"><text mode=\"dtmf\">1 2 3 4</text><instance grammar=\"builtin:dtmf/digits\"><SWI_meaning>1234</SWI_meaning><MEANING conf=\"1\">1234</MEANING><SWI_literal>1 2 3 4</SWI_literal><SWI_grammarName>builtin:dtmf/digits</SWI_grammarName></instance></interpretation></result>"
  status: "SUCCESS"
}

In this example, the sequence was properly recognized and was matched by the builtin:dtmf/digits grammar.

<result>
  <interpretation conf="1">
    <text mode="dtmf">1 2 3 4</text>
    <instance grammar="builtin:dtmf/digits">
      <SWI_meaning>1234</SWI_meaning>
      <MEANING conf="1">1234</MEANING>
      <SWI_literal>1 2 3 4</SWI_literal>
      <SWI_grammarName>builtin:dtmf/digits</SWI_grammarName>
    </instance>
  </interpretation>
</result>

Scenario 2: Recognize pi

This scenario recognizes pi, one of the client’s pre-set DTMF sequences:

$ ./run-nr-dtmf-client.sh pi
Recognizing DTMF sequence: ['3', '*', '1', '4', '1', '5', '9']

Sending recognition_init {
  parameters {
    no_input_timeout_ms: 6000
    dtmf_interdigit_timeout_ms: 3000
    dtmf_term_char: "#"
  }
  resources {
    builtin: "builtin:dtmf/digits"
    weight: 1
  }
  resources {
    inline_grammar {
      grammar: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><grammar xml:lang=\"en-US\" mode=\"dtmf\" version=\"1.0\" tag-format=\"swi-semantics/1.0\" root=\"NUMBERS\" xmlns=\"http://www.w3.org/2001/06/grammar\"><rule id=\"NUMBERS\" scope=\"public\"><one-of><item><ruleref uri=\"#PI\" /><tag>MEANING=PI.SWI_literal.replace(/.*/, \'PI\')</tag></item><item><ruleref uri=\"#E\" /><tag>MEANING=E.SWI_literal.replace(/.*/, \'E\')</tag></item><item><ruleref uri=\"#PHI\" /><tag>MEANING=PHI.SWI_literal.replace(/.*/, \'PHI\')</tag></item><item><ruleref uri=\"#SQRT2\" /><tag>MEANING=SQRT2.SWI_literal.replace(/.*/, \'SQRT2\')</tag></item></one-of></rule><rule id=\"PI\"><item>3</item><item>*</item><item>1</item><item>4</item><item>1</item><item>5</item><item>9</item></rule><rule id=\"E\"><item>2</item><item>*</item><item>7</item><item>1</item><item>8</item><item>2</item><item>8</item></rule><rule id=\"PHI\"><item>1</item><item>*</item><item>6</item><item>1</item><item>8</item><item>0</item><item>3</item></rule><rule id=\"SQRT2\"><item>1</item><item>*</item><item>4</item><item>1</item><item>4</item><item>2</item><item>1</item></rule></grammar>"
    }
    weight: 2
  }
}


DTMFRecognize() reponse --> status {
  code: 200
  message: "OK"
}

Sending DTMF 3

DTMFRecognize() reponse --> start_of_speech {
  first_audio_to_start_of_speech_ms: 1000
}

Sending DTMF *
Sending DTMF 1
Sending DTMF 4
Sending DTMF 1
Sending DTMF 5
Sending DTMF 9
DONE Sending DTMFs

DTMFRecognize() reponse --> result {
  formatted_text: "<result><interpretation conf=\"1\"><text mode=\"dtmf\">3 * 1 4 1 5 9</text><instance grammar=\"10171153428116319910\"><MEANING conf=\"1\">PI</MEANING><SWI_literal>3 * 1 4 1 5 9</SWI_literal><SWI_grammarName>10171153428116319910</SWI_grammarName><SWI_meaning>{MEANING:PI}</SWI_meaning></instance></interpretation></result>"
  status: "SUCCESS"
}

In this example, the sequence was properly recognized and was matched by the inline grammar, which provided a meaning of “PI” to the recognized sequence.

<result>
  <interpretation conf="1">
    <text mode="dtmf">3 * 1 4 1 5 9</text>
    <instance grammar="10171153428116319910">
      <MEANING conf="1">PI</MEANING>
      <SWI_literal>3 * 1 4 1 5 9</SWI_literal>
      <SWI_grammarName>10171153428116319910</SWI_grammarName>
      <SWI_meaning>{MEANING:PI}</SWI_meaning>
    </instance>
  </interpretation>
</result>