Add Speech Recognition
You're ready for this how-to guide if you've got the following:
A FreeClimb account
A registered application
A configured FreeClimb Number
Your tools and language installed
Node.js
Using the FreeClimb library, an asynchronous out dial request can be created. At minimum a request to create an out dial request requires a To
and From
number which the user would need to provide in this example. The callConnectUrl
and the statusCallbackUrl
in your App Config specifies the callback for connected out dial calls and status updates respectively. Successful invocation of the create
method indicates the asynchronous out dial request has successfully been queued. All subsequent updates for the request will be directed to the URLs provided.
Create your package.json file and save in the root directory of your project:
{
"name": "node-speech-recognition-how-to-guide",
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"@freeclimb/sdk": "^3.8.0",
"body-parser": "^1.19.0",
"dotenv": "^8.1.0",
"express": "^4.17.1"
}
}
Install the package by running the following in the command line/terminal:
yarn install
Example code:
require('dotenv').config()
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
app.use(bodyParser.json())
const freeclimbSDK = require('@freeclimb/sdk')
const { PerclScript, GetSpeech, GrammarType, Say, GetSpeechReason, Hangup } = require('@freeclimb/sdk')
const port = process.env.PORT || 80
const host = process.env.HOST
const accountId = process.env.ACCOUNT_ID
const apiKey = process.env.API_KEY
const to = 'YOUR_TO_NUMBER'
const from = 'YOUR_FROM_NUMBER'
const applicationId = process.env.APPLICATION_ID
const configuration = freeclimbSDK.createConfiguration({ accountId, apiKey })
const freeclimb = new freeclimbSDK.DefaultApi(configuration)
//Invoke create method to initiate the asynchronous outdial request
freeclimb.makeACall({ to, from, applicationId, callConnectUrl: `${host}/incomingCall` }).catch(err => { console.log(err) })
The callConnectUrl
provided in App Config will be the recipient of FreeClimb requests for additional actions upon call answer. The additional PerCL actions are contained in the context of the response. In this sample both the Say
and GetSpeech
PerCL actions are utilized. The GetSpeech
PerCL actionUrl
provided will be invoked upon completion of the action.
app.post('/incomingCall', (req, res) => {
res.status(200).json(new PerclScript({
commands: [
new GetSpeech({
actionUrl: `${host}/colorSelectDone`,
grammarFile: `${host}/grammarFile`,
grammarType: GrammarType.URL,
prompts: [
new Say({ text: "Please select a color. Select green, red, or yellow." })
]
})
]
}).build())
})
For a grammar file to be used by FreeClimb, a download URL for the grammar file must be provided. To host the file on the same server as your FreeClimb app, use the following code:
app.get('/grammarFile', function (req, res) {
const file = `${__dirname}/colorGrammar.xml`
res.download(file)
})
Successful completion of the GetSpeech
PerCL action will result in the receipt of a FreeClimb request at the actionUrl
defined in the GetSpeech
request. Upon receipt of the request additional PerCL actions are created to speak the selected color and gracefully terminate the out dial call. The sample uses additional Say
and Hangup
PerCL actions to speak the selected color and gracefully terminate the call.
app.post('/colorSelectDone', (req, res) => {
if (req.body.reason === GetSpeechReason.RECOGNITION) {
res.status(200).json(new PerclScript({
commands: [
new Say({ text: `Selected color was ${req.body.recognitionResult}` }),
new Hangup({})
]
}).build())
} else {
res.status(200).json(new PerclScript({
commands: [
new Say({ text: "There was an error in selecting a color" }),
new Hangup({})
]
}).build())
}
})
Upon termination of the call the statusCallbackUrl
provided in the App Config receives a FreeClimb request and an empty response is provided.
Handle Status Updates:
// Specify this route with 'Status Callback URL' in App Config
app.post('/status', (req, res) => {
res.status(200)
})
Start the server:
app.listen(port, () => {
console.log(`Starting server on port ${port}`)
})
The custom grammar used was:
<?xml version="1.0" encoding="UTF-8"?>
<grammar xml:lang="en-US" tag-format="semantics-ms/1.0" version="1.0" root="PersyColor" mode="voice" xmlns="http://www.w3.org/2001/06/grammar">
<rule id="PersyColor" scope="public">
<item>
<item repeat="0-1"><ruleref uri="#UMFILLER"/></item>
<item>
<one-of>
<item>green<tag>$._value = "GREEN";</tag></item>
<item>red<tag>$._value = "RED";</tag></item>
<item>yellow<tag>$._value = "YELLOW";</tag></item>
</one-of>
</item>
<item repeat="0-1"><ruleref uri="#TRAILERS"/></item>
</item>
</rule>
<rule id="UMFILLER">
<one-of>
<item> uh </item>
<item> um </item>
<item> hm </item>
<item> ah </item>
<item> er </item>
</one-of>
</rule>
<rule id="TRAILERS">
<one-of>
<item> maam </item>
<item> sir </item>
</one-of>
</rule>
</grammar>
Java
To initiate any interaction with FreeClimb a FreeClimbClient
object must be created. Using the CallsRequester
created upon successful creation of the FreeClimbClient
an asynchronous out dial request can be created. At minimum a request to create an out dial request requires a To
, From
and callConnectUrl
. In this sample a statusCallbackUrl
is also included. Successful invocation of the create
method indicates the asynchronous out dial request has successfully been queued. All subsequent updates for the request will be directed to the URLs provided.
Create your build.gradle file and save it to the root directory in your project:
/*
* This file was generated by the Gradle 'init' task.
*
* This is a general purpose Gradle build.
* Learn how to create Gradle builds at https://guides.gradle.org/creating-new-gradle-builds
*/
buildscript {
repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}
//Add the dependency
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:2.1.6.RELEASE"
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
bootJar {
baseName = 'gs-spring-boot'
version = '0.1.0'
}
repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile "org.springframework.boot:spring-boot-starter-web"
testCompile "junit:junit"
compile 'com.github.FreeClimbAPI:FreeClimb-Java-SDK:3.0.0'
}
sourceSets {
main {
java {
srcDirs = ['src'] // changed line
}
}
}
Build the file by running the following in your terminal/command line:
gradle build
Example code:
import com.vailsys.freeclimb.webhooks.call.VoiceCallback;
import com.vailsys.freeclimb.webhooks.percl.GetSpeechActionCallback;
import com.vailsys.freeclimb.webhooks.percl.SpeechReason;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.vailsys.freeclimb.percl.PerCLScript;
import com.vailsys.freeclimb.percl.Say;
import com.vailsys.freeclimb.percl.GetSpeech;
import com.vailsys.freeclimb.percl.GetSpeechNestable;
import com.vailsys.freeclimb.percl.GrammarType;
import com.vailsys.freeclimb.percl.Hangup;
import com.vailsys.freeclimb.percl.Language;
import com.vailsys.freeclimb.percl.Pause;
import com.vailsys.freeclimb.api.call.Call;
import com.vailsys.freeclimb.api.call.CallStatus;
import java.io.File;
import java.util.LinkedList;
import javax.servlet.http.HttpServletResponse;
import com.vailsys.freeclimb.api.FreeClimbClient;
import com.vailsys.freeclimb.api.FreeClimbException;
try {
// Create FreeClimbClient object
// Your account ID & api key can be found under API credentials on the FreeClimb Dashboard
FreeClimbClient client = new FreeClimbClient(accountId, apiKey);
Call call = client.calls.create(toNumber, fromNumber, applicationId);
} catch (FreeClimbException ex) {
// Exception throw upon failure
}
The callConnectUrl
provided in the App config will be the recipient of FreeClimb request for additional actions upon call answer. The additional PerCL actions are contained in the context of the response. In this sample both the Say
and GetSpeech
PerCL actions are utilized. The GetSpeech
PerCL actionUrl
provided will be invoked upon completion of the action.
@RequestMapping(value = {
"/InboundCall" }, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String inboundCall(@RequestBody String body) {
VoiceCallback callStatusCallback;
try {
// Convert JSON into call status callback object
callStatusCallback = VoiceCallback.createFromJson(body);
} catch (FreeClimbException pe) {
PerCLScript errorScript = new PerCLScript();
Say sayError = new Say("There was a problem processing the incoming call.");
errorScript.add(sayError);
return errorScript.toJson();
}
// Create an empty PerCL script container
PerCLScript script = new PerCLScript();
// Verify call is in the InProgress state
if (callStatusCallback.getCallStatus() == CallStatus.IN_PROGRESS) {
// Create PerCL get speech script (see grammar file contents below)
GetSpeech getSpeech = new GetSpeech(selectColorDone, grammarDownload);
// Set location and type of grammar as well as the grammar rule
getSpeech.setGrammarType(GrammarType.URL);
getSpeech.setGrammarRule("FreeClimbColor");
// Create PerCL GetSpeechNestable list
LinkedList<GetSpeechNestable> prompts = new LinkedList<>();
// Create PerCL say script with US English as the language
Say say = new Say("Please select a color. Select green, red, or yellow.");
say.setLanguage(Language.ENGLISH_US);
// Add PerCL say script to GetSpeechNestable list
prompts.add(say);
// Set GetSpeechNestable list as PerCL get speech prompt list
getSpeech.setPrompts(prompts);
// Add PerCL get speech script to PerCL container
script.add(getSpeech);
}
return script.toJson();
}
Successful completion of the GetSpeech
PerCL action will result in the receipt of a FreeClimb request at the actionUrl
defined in the GetSpeech
request. Upon receipt of the request addition PerCL actions are created to speak the selected color and gracefully terminate the out dial call. The sample uses additional Say
and Hangup
PerCL actions to speak the selected color and gracefully terminate the call.
@RequestMapping(value = {
"/SelectColorDone" }, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String recordCallBack(@RequestBody String body) {
GetSpeechActionCallback getSpeechActionCallback;
try {
// convert JSON into get speech status callback object
getSpeechActionCallback = GetSpeechActionCallback.createFromJson(body);
} catch (FreeClimbException pe) {
PerCLScript errorScript = new PerCLScript();
Say sayError = new Say("Error with get speech callback.");
errorScript.add(sayError);
return errorScript.toJson();
}
// Create an empty PerCL script container
PerCLScript script = new PerCLScript();
// Check if recognition was successful
if (getSpeechActionCallback.getReason() == SpeechReason.RECOGNITION) {
// Create PerCL say script with US English as the language
Say say = new Say("Selected color was " + getSpeechActionCallback.getRecognitionResult());
say.setLanguage(Language.ENGLISH_US);
// Add PerCL say script to PerCL container
script.add(say);
} else {
// Create PerCL say script with english as the language
Say say = new Say("There was an error in selecting a color.");
say.setLanguage(Language.ENGLISH_US);
// Add PerCL say script to PerCL container
script.add(say);
}
// Create PerCL pause script with a duration of 100 milliseconds
Pause pause = new Pause(100);
// Add PerCL pause script to PerCL container
script.add(pause);
// Create PerCL say script with US English as the language
Say sayGoodbye = new Say("Goodbye");
sayGoodbye.setLanguage(Language.ENGLISH_US);
// Add PerCL say script to PerCL container
script.add(sayGoodbye);
// Create PerCL hangup script
Hangup hangup = new Hangup();
// Add PerCL hangup script to PerCL container
script.add(hangup);
// Convert PerCL container to JSON and append to response
return script.toJson();
}
The getSpeech
PerCL command will request the grammar file from the URL specified. Here the grammar file is downloaded and sent to FreeClimb.
@RequestMapping(value = "/grammarFile", method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@ResponseBody
public FileSystemResource getFile(HttpServletResponse response) {
response.setContentType("application/xml");
response.setHeader("Content-Disposition", "attachment; filename=\"colorGrammar.xml\"");
return new FileSystemResource(new File("colorGrammar.xml"));
}
Upon termination of the call the statusCallbackUrl
provided in the App Config receives a FreeClimb request and an empty response is provided.
@RequestMapping(value = { "/Status" }, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public String ColorSelectionStatus(@RequestBody String str) {
// Create an empty PerCL script container
PerCLScript script = new PerCLScript();
// Convert PerCL container to JSON and append to response
return script.toJson();
}
C#
To initiate any interaction with FreeClimb a FreeClimbClient
object must be created. Using the CallsRequester
created upon successful creation of the FreeClimbClient
an asynchronous out dial request can be created. At minimum a request to create an out dial request requires a To
, From
and applicationId
. Successful invocation of the create
method indicates the asynchronous out dial request has successfully been queued. All subsequent updates for the request will be directed to the Urls provided.
Example code:
try {
// Create the FreeClimbClient
// Your account ID & api key can be found under API credentials on the FreeClimb Dashboard
FreeClimbClient client = new FreeClimbClient (accountId, apiKey);
// Create a Call
Call call = client.getCallsRequester.create (phoneNumber, // To
freeClimbPhoneNumber, // From,
applicationId); // Application to Handle the call
}
catch (FreeClimbException ex) {
System.Console.Write (ex.Message);
}
The callConnectUrl
of the provided application in the original create
request will be the recipient of FreeClimb request for additional actions upon call answer. The additional PerCL actions are contained in the context of the response. In this sample both the Say
and GetSpeech
PerCL actions are utilized. The GetSpeech
PerCL actionUrl
provided will be invoked upon completion of the action.
Example code:
[HttpPost] // POST /voice
public ActionResult SelectColorCallAnswered (CallStatusCallback callStatusCallback) {
// Create an empty PerCL script container
PerCLScript script = new PerCLScript ();
// Verify call is in the InProgress state
if (callStatusCallback.getDialCallStatus == ECallStatus.InProgress) {
// Create PerCL get speech script (see grammar file content below)
string actionUrl = AppUrl + "/voice/SelectColorDone";
string grammarFile = AppUrl + "/grammars/FreeClimbColor.xml";
GetSpeech getSpeech = new GetSpeech (actionUrl, grammarFile);
// Set location and type of grammar as well as the grammar rule
getSpeech.setGrammarType (EGrammarType.Url);
getSpeech.setGrammarRule ("FreeClimbColor");
// Create PerCL say script with US English as the language
Say say = new Say ();
say.setLanguage (ELanguage.EnglishUS);
// Set prompt for color selection
say.setText ("Please select a color. Select green, red or yellow.");
// Add PerCL say script to PerCL get speech prompt list
getSpeech.setPrompts (say);
// Add PerCL get speech script to PerCL container
script.Add (getSpeech);
}
// Convert PerCL container to JSON and append to response
return Content (script.toJson (), "application/json");
}
Successful completion of the GetSpeech
PerCL action will result in the receipt of a FreeClimb request at the actionUrl
defined in the GetSpeech
request. Upon receipt of the request additional PerCL actions are created to speak the selected color and gracefully terminate the out dial call. The sample uses additional Say
and Hangup
PerCL actions to speak the selected color and gracefully terminate the call.
Example code:
[HttpPost("SelectColorDone")]
public ActionResult SelectColorDone (GetSpeechActionCallback getSpeechStatusCallback) {
// Create an empty PerCL script container
PerCLScript script = new PerCLScript ();
// Check if recognition was successful
if (getSpeechStatusCallback.getReason == ESpeechTermReason.Recognition) {
// Create PerCL say script with US English as the language
Say say = new Say ();
say.setLanguage (ELanguage.EnglishUS);
// Set prompt to speak the selected color
say.setText (string.Format ("Selected color was {0}", (getSpeechStatusCallback.getRecognitionResult).ToLower ()));
// Add PerCL say script to PerCL container
script.Add (say);
} else {
// Create PerCL say script with US English as the language
Say say = new Say ();
say.setLanguage (ELanguage.EnglishUS);
// Set prompt to indicated selection error
say.setText ("There was an error in selecting a color.");
// Add PerCL say script to PerCL container
script.Add (say);
}
// Create PerCL pause script with a duration of 100 milliseconds
Pause pause = new Pause (100);
// Add PerCL pause script to PerCL container
script.Add (pause);
// Create PerCL say script with US English as the language
Say sayGoodbye = new Say ();
sayGoodbye.setLanguage (ELanguage.EnglishUS);
// Set prompt
sayGoodbye.setText("Goodbye");
// Add PerCL say script to PerCL container
script.Add (sayGoodbye);
// Create PerCL hangup script
Hangup hangup = new Hangup ();
// Add PerCL hangup script to PerCL container
script.Add (new Hangup ());
// Convert PerCL container to JSON and append to response
return Content (script.toJson (), "application/json");
}
The custom grammar used was:
<grammar xml:lang="en-US" tag-format="semantics-ms/1.0" version="1.0" root="FreeClimbColor" mode="voice" xmlns="http://www.w3.org/2001/06/grammar">
<rule id="FreeClimbColor" scope="public">
<item>
<item repeat="0-1"><ruleref uri="#UMFILLER"/></item>
<item>
<one-of>
<item>green<tag>$._value = "GREEN";</tag></item>
<item>red<tag>$._value = "RED";</tag></item>
<item>yellow<tag>$._value = "YELLOW";</tag></item>
</one-of>
</item>
<item repeat="0-1"><ruleref uri="#TRAILERS"/></item>
</item>
</rule>
<rule id="UMFILLER">
<one-of>
<item> uh </item>
<item> um </item>
<item> hm </item>
<item> ah </item>
<item> er </item>
</one-of>
</rule>
<rule id="TRAILERS">
<one-of>
<item> maam </item>
<item> sir </item>
</one-of>
</rule>
</grammar>
Updated about 1 month ago