Remember that Amazon Alexa Skill that I built for City Cinema? Well it’s now generally available: if you have an Echo device anywhere in the world, you can enable the “City Cinema” skill.

My usual coding practice when hacking away at things like this is to write horribly-organized spaghetti code to see whether things are going to work at all, and to understand the underlying patterns, and then to loop back and create more elegant, reusable code once I’ve got some more insight. I’ve now done the loop-back for the code that powers the City Cinema schedule, building a PHP class that allows me to do things like this:

<?php
$c = new CityCinema('whatsPlaying', '2017-03-15);
$message = $c->speakable;
?>

(which will set $message equal to a speakable version of the City Cinema schedule for March 15, 2017).

The great thing about reusable code is that it’s, well, reusable. Meaning that when I went to explore the now-Google-owned API.ai platform for developing conversational interfaces, I could use the same PHP class to act as the back-end webhook for that too, with almost no modifications.

API.ai is a considerably more sophisticated platform than Amazon’s Alexa Skills Kit: coding for API.ai seems a lot less like coding for ELIZA and more like using a tool that’s custom-tailored for this task.

So, for example, the UI for creating a new “intent” looks like this in API.ai:

Screen shot of the API.ai intent creation screen.

Rather than needing to spell out, in JSON, all of the various utterances that I want to glue to my business logic, I simply specify some sample phrases, highlight where the entities that are required appear in them (connecting “Tuesday” to the @sys.date entity, for example), and API.ai takes it from there; even though I didn’t specify it in my examples, there’s enough to be derived from these that I can say “Ask City Cinema what’s on tap for Wednesday” and it will figure out what I mean.

One of the nicest features of API.ai is that it supports multiple conversational integrations from the same setup, and these are very easy to deploy.

For example, once I had the Google Actions integration working (to allow me to support Google Home and Google Assistant), I was able to roll out a Twitter bot in about 5 minutes; the only change required was to my back-end webhook, where I changed “do you want to hear a description” to “do you want a description” when the source was Twitter.

As a result, if you send a Twitter Direct Message to @city_cinema, you can now ask it the same questions you can ask Alexa and Google, like “what’s playing tonight?” or “what’s running on Sunday?” And I’ve added a couple of conveniences too, like “what’s your location?” and “how much are tickets?” Here’s what it looks like in action:

 

Screen shot of the City Cinema Twitter "bot" in action showing a dialog where I ask it questions and it responds.

Give it a try!

🗓️
Twitter  •  API.ai  •  Alexa  •  Google Home  •  Google Actions
🗓️

If you were an admirer of the seminal Penguin Café Orchestra, then you might like Penguin Cafe, a sort of spiritual reconstitution thereof by founder Simon Jeffes’s son Arthur:

Penguin Cafe was founded by Arthur Jeffes in 2009, bringing together a diverse and disparate group of musicians from the likes of Suede, Gorillaz and Razorlight, initially to perform his father Simon Jeffes’ legacy of world renowned Penguin Cafe Orchestra music, ten years after his untimely death in 1997.

Arthur, a composer in his own right, quickly began to create new and unique genre-defying music, with the spellbinding philosophy of the Penguin Cafe always in his mind.

The recently-released The Imperfect Sea is both of and a departure from the fathership. It’s available from the excellent Erased Tapes, which has itself just turned 10 and released a fresh new website.

You can’t do much better than putting the Erased Tapes back catalogue into a Spotify playlist and letting it run all day.

Penguin Cafe album cover for The Imperfect Sea
🗓️

Lost in the shuffle of the Amazon Echo Dot that we’ve been using for the past month is its capacity to receive as well as send via Bluetooth.

I knew you could pipe the audio from the Echo into a Bluetooth speaker; what I only realized today is that you can pipe the audio of other services—like a phone or tablet—to the Echo.

For me this solves the problem of there being no SoundCloud skill for the Echo: I can simply use the Android SoundCloud app and send the audio to the Echo. Because the Echo is hardwired to our hifi, this gives me a handy bridge to blasting SoundCloud audio into the living room.

🗓️

I was either mistakenly issued two double machiattos, or an anonymous suitor was trying to pick me up. Regardless, I’m now exceedingly well-caffeinated.

🗓️

I use Apache Solr, and the related Drupal module, to power the search on this site.

Something that’s always bothered me about the out-of-the-box way this displays search results is that the date display with each search result is the “date the content was last changed.”

So, for example, for this post I wrote in 2015, the date that appears under the search result (when I search the site for pickles) isn’t November 1, 2015, when I wrote the post, but rather July 7, 2016, when it was last updated:

Things I’ve Liked Recently

favourite meal there: toast (from Breadworks bread), smoked salmon, vegetables, pickled onions and cheese. …

Peter Rukavina - 2016-07-03 11:22 - 1 comment

Because Drupal’s very vigilant about keeping the “changed” date current, this date can get updated for a lot of different reasons.

For example, on July 3, 2016 I used the Search and Replace Scanner module do to some automated processing of almost every post here, and Drupal dutifully updated the “changed” date for all of the affected posts to July 3, 2016. That’s fine for auditing purposes, but it just creates confusion for displaying search results, when what I want to know is when was this written.

There are various ways to fix this: altering Solr so that it indexes the created rather than changed date, altering the search results template so that it looks up the created date and displays it, etc.

But the simplest approach, assuming you’ve no need to track revisions, is to simply update the changed dates to match the created dates, via a MySQL query, like this:

UPDATE node SET changed = created;

Once I did that, and then deleted the Solr index and re-indexed everything, the dates in search results became much more helpful:

Things I’ve Liked Recently

favourite meal there: toast (from Breadworks bread), smoked salmon, vegetables, pickled onions and cheese. …

Peter Rukavina - 2015-11-01 14:35 - 1 comment

This is a “nuclear option,” inasmuch as you lose the audit trail for each node. But it was quick and painless for me.

🗓️

Just enjoying Charlottetown Monthly over coffee. Only 33 years out of sync. Great article about Danny Dan MacDonald.

Photo of Charlottetown Monthly magazine cover from 1984
🗓️
Magazines  •  Charlottetown  •  History  •  Coffee
Audio file

I had my first Alexa Skill certified today, one I built over the past couple of weeks for City Cinema here in Charlottetown.

“Alexa Skills” are custom apps built for Amazon’s voice-controlled Echo line of products; think of them as a very early prototype of the computer on Star Trek, but lacking most of the artificial intelligence.

While Echo devices aren’t yet available for sale in Canada, they work in Canada, at least mostly, and it’s clear they’ll be here eventually. So it’s a good time to build up some “voice app” muscle memory, and City Cinema was a good, simple, practical use case.

Simple and practical because there’s really only one thing people want to know about City Cinema: what’s playing. Tonight. On Friday. Next Thursday.

So here’s a high-level overview of what it took to make an Alexa Skill.

First, I needed to select an Invocation Name. This is the “trigger word” or the “app name” that Alexa will glue to my skill. I selected the obvious: City Cinema.

Next, I created an Intent Schema, a JSON description of the things my skill can do, its methods, in other words.

In this case, it can only do a single thing–tell you what’s playing–so there’s only a single intent defined, WhatsPlaying, that has an optional parameter (called a “slot” in Alexa-speak), the date. There are also a few built-in intents added to the schema to allow me to define what happens when a user answers “yes” or “no” to a question, and when they cancel or stop.

{
  "intents": [
    {
      "intent": "WhatsPlaying",
      "slots": [
        {
          "name": "Date",
          "type": "AMAZON.DATE"
        }
      ]
    },
    {
      "intent": "AMAZON.YesIntent"
    },
    {
      "intent": "AMAZON.NoIntent"
    },   
    {
      "intent": "AMAZON.CancelIntent"
    },
    {
      "intent": "AMAZON.StopIntent"
    }
  ]
}

Next, I defined the Sample Utterances, a list of the actual things that users can say that will initiate a “what’s playing” lookup:

WhatsPlaying what's playing on {Date}
WhatsPlaying what's playing {Date}
WhatsPlaying what's on {Date}
WhatsPlaying what's showing on {Date}
WhatsPlaying what is playing on {Date}
WhatsPlaying what is playing {Date}
WhatsPlaying what is on {Date}
WhatsPlaying what is showing on {Date}
WhatsPlaying showtimes for {Date}
WhatsPlaying what are the showtimes for {Date}
WhatsPlaying what are showtimes for {Date}
WhatsPlaying showtimes for {Date}
WhatsPlaying the schedule for {Date}
WhatsPlaying schedule for {Date}

Defining these utterances is where you realize that a lot of what we call “artificial intelligence” is still very ELIZA-like: a nest of if-then statements.

Finally, I pointed the skill at an API endpoint on a server that I control. There are no limitations here other than that the endpoint must be served via HTTPS.

From this point, I could code the endpoint in whatever language I liked; all I needed to do is accept inputs from Alexa, and respond with outputs.

I opted to code in PHP, and to use the nascent third-party Amazon Alexa PHP Library as a convenience wrapper.

There are a bunch of things the endpoint must do that using this wrapper makes easier: requests must be validated as having come from Amazon, and there must be application logic in place to respond to LaunchRequest, SessionEndedRequest, and IntentRequest requests.

Other than that, the heavy lifting of the skill is relatively simple, at least in this case.

When a user says, for example, “Alexa, ask City Cinema what’s playing tonight,” Alexa matches the utterance to one of those that I defined, WhatsPlaying what’s playing {Date}, and passes my endpoint the intent (WhatsPlaying) and the date (as YYYY-MM-DD).

So I end up with a PHP object that looks, in part, like this:

[intent] => Array
    (
        [name] => WhatsPlaying
        [slots] => Array
            (
                [Date] => Array
                    (
                        [name] => Date
                        [value] => 2017-03-02
                    )

            )

    )

From there I just use the same business logic that the regular CityCinema.net site uses to query the schedule database; I then munge the answer into SSML (Speech Synthesis Markup Language) to form the response. I pass back to Alexa a JSON response that looks like this:

{
  "version": "1.0",
  "response": {
    "outputSpeech": {
      "type": "SSML",
      "ssml": "<speak><p>Playing at City Cinema on <say-as interpret-as=\"date\">????0302</say-as>: Jackie<break strength='weak'/> at <say-as interpret-as=\"time\"> 7:00</say-as>.</p><p>Do you want to hear a description of this film?</p></speak>"
    },
    "card": {
      "content": "Jackie at  7:00",
      "title": "Playing Thursday, March  2",
      "type": "Simple"
    },
    "shouldEndSession": false
  },
  "sessionAttributes": {
    "Operation": "FilmDetails",
    "Date": "2017-03-02"
  }
}

While I can return a plain text reply, using SSML allows me to express some additional nuance in how dates and times are interpreted, and to insert breathy pauses when it helps to increase clarity.

Note that I also pass back some sessionAttributes values, Operation and Date. This allows me to respond properly when the user says “yes” or “no” in reaction to the question “Do you want to hear a description of this film?”; they are, in essence, parameters that are passed back to my endpoint with the follow-on intent. Like this, in part:

case 'AMAZON.NoIntent':

  if (array_key_exists('Operation', $alexaRequest->session->attributes)) {
    $operation = $alexaRequest->session->attributes['Operation'];
  }
  switch ($operation) {
    case "FilmDetails":
      $message = "<speak>";
      $message .= "Ok, see you at the movies!";
      $message .= "</speak>";
      $card = '';
      $endSession = TRUE;
      break;
  }

  break;

The Alexa Skills API also provides facility for passing back a “card,” which is a text representation (or variation) of the speech returned.

For example, for a “what’s playing” intent, I return the name of the film and the time; if the user answers “yes” to the “Do you want to hear a description of this film?” question, then I follow up with a card that includes the full film description (I experimented with passing this back for speaking, but it was too long to be useful).

An example of some "cards" returned to the Alexa Skills API.

And that’s it. The application logic is a little more complex than I’ve outlined, mostly to handle the edge cases and the required responses to things like a request without a date, or a request like “Alexa, launch City Cinema.” But the PHP endpoint code only runs 257 lines long. It is not rocket science.

There’s an Apple-like certification process that happens once you’re ready to launch a skill to the public; in my case I submitted the skill for certification at 11:00 a.m. on February 28 and got back a positive response on March 2 at 1:46 a.m., so it was a less-than-48-hour turnaround.

The skill is now live on Amazon.com.

I foolishly selected “Canada” as the sole country where it would be available when I submitted the skill for certification; because the Echo isn’t available in Canada, this renders the skill effectively unusable for the moment because to use an Echo in Canada you have to pretend to be in the U.S.

I’ve opened this up to all countries now, which requires a re-certification. So in a few days the world should have access to the skill. And, eventually, when the Echo gets released in Canada, the skill should be of practical utility to Echo owners in the neighbourhood.

🗓️
Alexa  •  Amazon Echo  •  City Cinema

You’ve been unexpectedly imprisoned in a hellish overseas grotto. Besides your captors, the only person present is another prisoner, one cell over. You cannot see them, but if you whisper, you can communicate without being overheard.

As the days wear on, together you begin to develop a plan for escape.

You are nervous, though: much depends on your ability to trust your fellow prisoner, and your furtive whispered conversations have done little to offer you any evidence this is wise.

You decide to bring things to a head before continuing, and so, using a stray piece of coal and a page ripped from the only book in your cell, you fashion a crude note.

“No, No, No,” you write.

After lights-out you manage to toss the note into your coconspirator’s cell.

The next evening the crumpled note returns.

“Yes, No,” has been added.

Escape is in your grasp.

🗓️

Twenty-two years ago this November I attended the Atlantic Provinces Library Association conference for the first time; I produced a pre-conference workshop on “the Internet,” and took participants through the basics of this novel thing called HTML in a computer lab on the University of PEI campus. By coincidence, at the same time as I was conducting the workshop I was also scheduled to appear on Morningside for the first time. It was a heady day.

The APLA conference is back in Charlottetown again this year, running May 23 to 26, 2017 from the Rodd Charlottetown Hotel. And I’m back on the program again, this time around with a talk titled Why your Library Needs a Hacker in Residence: (and What I’ve Learned by Being One):

Four years ago I was appointed Hacker in Residence at the University of Prince Edward Island’s Robertson Library. The appointment came out of my desire, as a non-librarian, non-academic technologist and libraryophile, to find a way to engage more fully in the life of the library, and to use the lens of librarianship and the academy to inform my work in the community. The position is unpaid and comes with no responsibilities; I’ve variously succeeded and failed at making the best of it. And in this talk I’ll tell my story, leading to some thought about why your library might benefit from following the same path.

Conference registration is open now, and you need not be a librarian to attend: there are a compelling collection of sessions, from bookbinding to data visualization, and if you are interested in libraries, technology, and society I heartily encourage you to attend.

🗓️

About This Blog

Photo of Peter RukavinaI am . I am a writer, letterpress printer, and a curious person.

To learn more about me, read my /now, look at my bio, listen to audio I’ve posted, read presentations and speeches I’ve written, see things I’ve favourited elsewhere, or get in touch (peter@rukavina.net is the quickest way).

I have been writing here since May 1999: you can explore the 25+ years of blog posts in the archive.

You can subscribe to an RSS feed of posts, an RSS feed of comments, an RSS feed of favourites elsewhere, or a podcast RSS feed that just contains audio posts. You can also receive a daily digests of posts by email. I also publish an OPML blogroll.

Instagram • YouTube • Vimeo • ORCID • OpenStreetMap • Internet Archive • PEI.art • Drupal • Github.