Damian Mehers' Blog Android, VR and Wearables from Geneva, Switzerland.

11Nov/151

Building an Amazon Echo Skill to create Evernote notes

First, a demo: Alexa, tell Evernote to create a note "Remember to call my Mother":

I recently acquired an Amazon Echo, and although there is limited support for interacting with Evernote via IFTTT, I wanted to simply create Evernote notes as in the demo above.

I’m going to share how I created an Amazon Echo Skill to accomplish what it shown in the video above, and what roadblocks I hit on the way.

Updating the example

I started with the sample Amazon Echo skill which uses lambdas, and got that working pretty quickly.

To update it to work with Evernote, I changed the JavaScript code that recognized the intent to invoke saveNote when the intent is TakeANote (you'll see where this intent is set up later):

**
 * Called when the user specifies an intent for this skill.
 */
function onIntent(intentRequest, session, callback) {
    console.log("onIntent requestId=" + intentRequest.requestId +
        ', sessionId=' + session.sessionId);
    var intent = intentRequest.intent, intentName = intentRequest.intent.name;
    // Dispatch to your skill's intent handlers
    if ("TakeANote" === intentName) {
        saveNote(intent, session, callback);
    }
    else {
        throw "Invalid intent: " + intentName;
    }
}

Creating the note

My code to create the Evernote note (invoked by saveNote above) is pretty much boilerplate. It pulls the content from the list of slots (defined below) and uses it to create a note using the Evernote API:

function saveNote(intent, session, callback) {
    var cardTitle = intent.name;
    var contentSlot = intent.slots["Content"];
    var repromptText = "";
    var sessionAttributes = [];
    var shouldEndSession = false;
    var speechOutput = "";
    if (contentSlot) {
        var noteText = contentSlot.value;
        sessionAttributes = [];
        speechOutput = "OK.";
        repromptText = "What was that?";
        shouldEndSession = true;
        var noteStoreURL = '...';
        var authenticationToken = '...';
        var noteStoreTransport = new Evernote.Thrift.NodeBinaryHttpTransport(noteStoreURL);
        var noteStoreProtocol = new Evernote.Thrift.BinaryProtocol(noteStoreTransport);
        var noteStore = new Evernote.NoteStoreClient(noteStoreProtocol);
        var note = new Evernote.Note();
        note.title = "New note from Alexa";
        var nBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
        nBody += "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\">";
        nBody += "<en-note>" + noteText + "</en-note>";
        note.content = nBody;
        noteStore.createNote(authenticationToken, note, function (result) {
            console.log('Create note result: ' + JSON.stringify(result));
            callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
        });
    }
    else {
        speechOutput = "I didn't catch that note, please try again";
        repromptText = "I didn't hear that note.  You can take a note by saying Take a Note followed by your content";
        callback(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
    }
}

Notice the hard-coded authenticationToken? That means this will only work with my account. To work with anyone's account, including yours, we'd obviously need to do something different. More on that in a moment.

Packaging it up

I zipped up my JavaScript file, together with my node_modules folder and a node package.json:

{
  "name": "AlexaPowerNoter",
  "version": "0.0.0",
  "private": true,
  "dependencies": {
    "evernote": "~1.25.82"
  }
}

Once done, I uploaded my zip to my Amazon Skill, and then published it.

The Skill information

This is the skill information I used:
Alexa Skill Information
Obviously I couldn't use trademarked term "Evernote" as the Invocation Name in something that was public, but just for testing for myself, I think I'm OK.

The Interaction Model

I defined the interaction model like this:
Alexa Interaction Model
The sample utterances is way too limited here - Amazon recommend having several hundred utterances for situations where you allow free-form text. It would also be cool to be able to have an intent to let you search Evernote.

Once I'd done this, and set up my Echo to use my development account, I could create notes.

Authentication roadblock

The next step was to link anyone's Evernote account into the Skill. This is where I hit the roadblock. Amazon require that the authentication support OAUTH 2.0 implicit grant and Evernote supports OAUTH 1. I could attempt to create a bridging service, but the security implications of doing so are scary, and doing it properly would require more time than I have right now.

The source is in GitHub

I've published the source to this app in my GitHub account here. If you are a developer and want to try it out, get an Evernote Developer auth token and plug in the URL and token in the noteStoreURL and authenticationToken above.

Comments (1) Trackbacks (0)
  1. It is very disappointing that Evernote still doesn’t offer OAuth 2.0 . I wanted to build a skill along the lines of what you’ve described and I am deeply disappointed.


Leave a comment

No trackbacks yet.