Voice dial

From SoftIVR

Revision as of 15:16, 31 December 2008 by Dave (Talk | contribs)
(diff) ←Older revision | Current revision (diff) | Newer revision→ (diff)
Jump to: navigation, search

Voice dial

This sample implements a voice-activated dialling application. What makes it a little special is that it gets the contacts to dial from those attached to a GMail account, which makes heavy use of SoftIVR's HTTP functionality and its XML handling capabilities.

The first part of the code logs us in to Google:

// Google credentials
gm_user = "softivr.call%40gmail.com";
gm_pass = "REDACTED";
// Do Google login
postdata = "accountType=HOSTED_OR_GOOGLE&Email=" + gm_user + "&Passwd=" + gm_pass + "&service=cp&source=SoftIVR-dial-1";
resp = httpPost("https://www.google.com/accounts/ClientLogin", postdata);
lines = resp.split(/\r|\n/);
auth = "";
for (i = 0; i < lines.length; i++) {
    if (lines[i].substr(0, 5) == "Auth=") {
        auth = lines[i].substr(5);
    }
}
if (auth.length === 0) {
    log("Google auth failed - data posted was " + postdata);
    finish();
}

Provided this has worked, we now go through the entries in the account's contact list, and build up a grammar. For each contact, the grammar consists of the contact's name, plus any combination of on or at, his, hers or their, and mobile, home or work - which elements of this last group being used depending on which numbers are stored for that contact. The grammar has the relevant contact numbers added to it to make the dialling part easy.

The code also builds up a phonebook in an array, which we will use in future to disambiguate ambiguous requests - such as 'Call Mike Smith', where Mike Smith has more than one contact number.

// We have an authentication token..!  Fetch address book, 1 entry at a time
// This will be s-l-o-w for large address books
cnum = 1;
pb = -1;
phonebook = [];
// We build up an ABNF grammar as we go along
grammar = "";
grammar = grammar + "#ABNF 1.0 ISO-8859-1;\n";
grammar = grammar + "language en-US;\n";
grammar = grammar + "public $dial = Call (";
while (cnum > 0) {
    contacts = httpGet("http://www.google.com/m8/feeds/contacts/default/full?max-results=1&start-index=" + cnum, "GData-Version: 2", "Authorization: GoogleLogin Auth=" + auth);
    parseXML(contacts);
    if (testXPath("entry")) {
        cname = getXPath("entry/title");
        pn = 0;
        while (testXPath("entry/gd:phoneNumber[" + pn + "]")) {
            // The 'type' of the number can be found after the # in the rel link
            // Assume 'work' if not found
            ntype = getXPath("entry/gd:phoneNumber[" + pn + "]/rel");
            num = getXPath("entry/gd:phoneNumber[" + pn + "]/content");
            hp = ntype.indexOf("#");
            if (hp > 0) {
                ntype = ntype.substr(hp + 1);
            } else {
                ntype = "work";
            }
            // Add number and type to the phone book
            if (pn === 0) {
                // This is the first entry for this contact, so add their name
                phonebook[cname] = [];
                grammar = grammar + cname + " { $.who='" + cname + "'; } [[on | at] [his | her | their] [";
            }
            // and add the number and type to the phone book..
            phonebook[cname][pn * 2] = num;
            phonebook[cname][pn * 2 + 1] = ntype;
            // ...and to the grammar.
            if (pn > 0) {
                grammar = grammar + " | ";
            }
            grammar = grammar + ntype + " { $.where='" + ntype + "'; $.num='" + num + "'; } ";
            pn = pn + 1;
        }
        if (pn > 0) {
            grammar = grammar + "]] | ";
        }
        cnum++;
    } else {
        cnum = 0;
    }
}

Having prepared our grammar, we answer the phone, prompt the user and see who they want to speak to:

// Got the phonebook, so answer the phone
answer();
say("Who would you like to call?");
 
// Strip trailing | from grammar and run ASR
grammar = grammar.substr(0, grammar.length - 2) + ");";
call = ASR(grammar);
parseXML(call);
num = getXPath("interpretation/instance/num");
dial("+44" + num.substr(1));

- and the job's done.