Building your first Botframework based Cortana Skill

Hi. I'm Cortana.

At //BUILD 2017 Microsoft announced support for Cortana Skills and connecting a Cortana Skill into a Bot Framework chatbot; given the number of chatbots out there using Microsoft Bot Framework, this is an extremely exciting move.

In this article I’ll show you how to create your first Cortana Skill from a Bot Framework chatbot and make it talk!

Cortana

If you’re not already familiar with Cortana, this is Microsoft’s “personal assistant” and is available on Windows 10 (version 1607 and above) and a couple of Windows phones (Lumia 950/950 XL), a standalone speaker – like an Amazon Echo – and a plethora of devices that can run the Cortana app, including iOS and Android and plenty of laptops.

Cortana all the things, Derrick.

You’re going to be seeing a lot more of this little box of tricks (“Bot” of tricks? Box of bots?.. hmm…), so you might as well get in on the act right now!

Bot Framework

I’m going to assume you have some knowledge of Microsoft’s Bot Framework for building multichannel chatbots. In case you’re not, then you should pop off now and familiarise yourself with these (but mainly just the first one):

Done that? Ok, great – now we can get started! I’m going to use the demo bot I created and have been using for most of my Bot Framework articles:

rposb demo bot - markdown

The Cortana channel

The first thing we’ll do is head over to the Bot Framework developer centre at dev.botframework.com. Log in, and choose the bot you want to power up with Cortana awesomeness!

bot listing

Now scroll down to the list of available channels and you should find a shiny new one called Cortana:

channel listing

It’s the pretty blue circle, not the pretty blue envelope, pretty blue speech bubble, pretty blue square speech bubble smiley thing, or the other pretty blue things…

You’ll now be taken to the channel configuration screen; if you’ve set up a bot on many channels before, you probably know what to expect. Fortunately this is a very short setup screen, with only one section you really need to pay attention to:

Invocation name

This is what you’ll have to say in order to get Cortana to invoke your skill. Don’t make this something hard to say or hard to understand etc etc. I’ve gone for “demo bot”.

The rest of the form looks like this:

cortana channel setup

Notice “Request user profile data” at the end? This is kinda cool and I’ll get on to it in another article; it allows your bot to request permission to access certain information about the user, like when you do Google OAuth and see a prompt saying “this site is requesting access to: your email address”

Leave it blank for now, hit “Save” and it will appear in your list of connected channels for that bot:

connected channel listing

Become an American!

If you’re already an American, then by now you should have achieved the bare minimum necessary to have your Bot Framework chatbot accessible through Cortana.

If, like me, you’re not so fortunate, then you need to pretend a bit. Cortana is currently limited to the en-US locale, so you may need to configure your pc to be U.S. friendly.

Tap the Windows key and type “Language” to open “Region and Language settings“:

Region and language settings

From here you’ll need to change your Region to “United States”, tap “Add a language” and search for “en-us” to add “English (United States)”.

You’ll need to restart and let your machine download the various updates and language packs necessary.

Hey Cortana!

Ok, now you should have done the bare minimum necessary to connect your bot to Cortana (at least for you).

Make sure you’re logged in to your pc using the same account that you use for your Bot Framework/Cortana dashboard configuration, otherwise your Cortana app won’t be able to find your skill.

Give it a go! In my case (because the invocation name for my bot is “demo bot”) I just say “Hey Cortana; ask demo bot hi”. Yeah, I know the structure doesn’t make sense, but Cortana seems to need you to say “ask” otherwise it thinks you’re sending a message to someone if you say “tell”.

Anyway, if it’s working you should see something like this:

thinking

Since this is the first time we’ve attempted to talk to the bot, we’re also given the permission prompt:

Bot permission prompt

Since I didn’t request any extra information from the user, the permission is just for “your request”, i.e. “hi”. I’m ok with that, so I’ll tap “Agree”.

Now the request is passed to my bot, processed, and the response is sent back:

Hi!

Wohoo! Now I’ll try one of the other commands my bot can handle – “markdown”:

markdown

Summary so far

Without much effort, we’ve taken an existing Bot Framework chatbot and exposed it via the Cortana channel. But it’s mute; no voice.

Before we make it talk, let’s investigate the Cortana dashboard a bit.

Cortana Dashboard

Go back to the Bot Framework dashboard and tap the “Manage in Cortana dash board” link to be taken to – surprisingly enough – the Cortana Dashboard:

Cortana dashboard

Deployment Ring

We already have some interesting info here; Deployed to self and Deploy to group. Right now, the only person who can use your skill is you; more specifically, the same Microsoft sign in account that your bot belongs to. In order to use your skill with Cortana, you must be logged in to Cortana using the same account.

If you want to share this skill with someone else, you can just tap “Deploy to group”, add in their Microsoft sign in email address, and you’ll be given a URL to send them which will give them access to your skill! Cool, huh?

Here I’m sharing the skill with .. um.. me!

Cortan deploy to group

… Thinky thinky thinky…
Cortana deploying to group

Ooh! I haz access too!
Cortana deployed group

Great for testing with a specific group of people.

Debug

Another point of interest is the “Debug” link; tap that and enable debug mode on the following page:

debug mode

If you talk to your bot now you’ll see an extra section in the Cortana response:

cortana haz debugz

This contains an awful lot of interesting info, such as the request containing whether the device has a screen:

    "entities": [
      {
        "type": "Intent",
        "name": "None",
        "entities": []
      },
      {
        "type": "DeviceInfo",
        "supportsDisplay": "true"
      }
    ]

That way, you can cater your bot response to be more audio based instead of visual, or vice versa.

What does your bot sound like?

Lastly, let’s make a couple of tiny changes to give our bot a voice. Right now you can talk to your bot, but you won’t hear anything in the response. Let’s fix that.

Open up your Bot Framework project and update to the latest version of Microsoft,Bot.Builder via Nuget:

 > Update-Package Microsoft.Bot.Builder

Now wherever you bot returns a reponse you can either:

  1. Use a new method SayAsync on the context:

    await context.SayAsync(text: "I'm text", speak: "I'm voice");
    
  2. If you usually create a reply from the incoming message activity using message.CreateReply then you can explicitly set the Speech property:

    var reply =  message.CreateReply();
    reply.Text = "This is text";
    reply.Speak = "This is speech";
    
  3. Or you could use this handy extension class:

    public static class MessageActivityExtension
    {
        public static void Say(
                this IMessageActivity activity,
                string text,
                string speech = null, 
                string inputHint = InputHints.AcceptingInput)
        {
            activity.Text = text;
            activity.Speak = speech ?? text;
            activity.InputHint = inputHint;
        }
    }
    

    which allows you to do something like:

    var reply =  message.CreateReply();
    reply.Say("This is text", "This is speech");
    

I’ll return to InputHints in a subsequent article

Go through your existing chatbot and add in a few Speech properties to the reponse, redeploy, and ask Cortana again; suddenly your bot will be able to speak! BOT EVOLUTION! Aw yeah!

Summary

In this article I’ve shown you how to connect your Bot Framework chatbot to the Cortana channel, how to set up your PC to set up Cortana and connect back to your bot, and how to give your bot a voice.

There’s still so much cool stuff to share, so stay tuned for more Cortana articles!

Smart TV 101 : Part #2 – App Development

I’m committing to doing 12 months of “101”s; posts and projects themed at beginning something new (or reasonably new) to me. January was all about node development awesomeness. February is all about Smart TV apps.

SDK

There is a wonderfully detailed SDK document for the current latest version (v4.0) which provides the environment to develop and test apps for the 2011, 2012, and 2013 series of TVs.

This consists of an IDE (a version of Eclipse), a selection of emulators for the three series of TVs it supports, automated test tools, app packaging facilities, and a few other tools.

There are examples and tutorials for projects ranging from gesture recognition, voice recognition, adaptive video streaming, through to advertisment embedding.

Developing gesture recognition apps for the 2013 Smart TV series

IDE – Ecplise

I’ve never been a fan of Eclipse as an IDE, but I’m stuck with it at the moment since it’s part of the Samsung SDK! To be fair, it does integrate into app development process quite well.

Once you’ve downloaded it from the SamsungDForum website and installed it you can create one of three types of application:

  1. Basic – for the less codey-types, using as visual editor. A bit like Visual Studio in design mode.
  2. Javascript – for writing the css, html, and js code yourself; this is the one I’ll be using
  3. Flash – strangely enough, for embedding flash into your app

ecplise-1

Within this flavour of Eclipse is the facility to launch the current application under development directly in an emulator, and also the ability to create a package for deployment (to be covered in the next post).

Emulator

As with any project in which you’re developing an application which will be running on a system that is different to the one on which you’re developing – such as iPhone or Android apps – you’re going to need a solid emulator.

The Samsung ones are actually reasonably good. There are some reasonably advanced debugging and testing facilities built into the SDK but even just having any javascript alert display within a debug window is extremely useful.

Smart TV Emulator

Developing a basic app

Right, let’s get down to business.

  1. Install the SDK
  2. Open up Eclipse
  3. Create a new Javascript app
  4. Make sure you’ve selected the project in the file explorer tab (i.e., not one of the js or html files)
  5. Click the Samsung Smart TV menu and select Open current project in Emulator

aaaaannnnd

samsung-emulator-1

WOW! Nothing!

Ok, let’s make it do something.

Add in a new div, give it an id, and whack in some text. This still won’t actually appear so edit the css and give it a height, width, and garish background colour.

There’s still one thing that you may need to check; I believe that this is now part of the standard base project, but in previous versions of the SDK you had to edit the Main.onLoad event and wire up a call to let the application manager know it was now ok to start showing things:

widgetAPI.sendReadyEvent

My resulting HTML looks a bit like:

<!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
		<title>AlrightMate</title>

		<!-- TODO : Common API -->
		<script type="text/javascript" language="javascript" src="$MANAGER_WIDGET/Common/API/Widget.js"></script>
		<script type="text/javascript" language="javascript" src="$MANAGER_WIDGET/Common/API/TVKeyValue.js"></script>

		<!-- TODO : Javascript code -->
		<script language="javascript" type="text/javascript" src="app/javascript/Main.js"></script>

		<!-- TODO : Style sheets code -->
		<link rel="stylesheet" href="app/stylesheets/Main.css" type="text/css">

		<!-- TODO: Plugins -->

	</head>

	<body onload="Main.onLoad();" onunload="Main.onUnload();">
		<div id="content">Alright mate?</div>
		
		<!-- Dummy anchor as focus for key events -->
		<a href="javascript:void(0);" id="anchor" onkeydown="Main.keyDown();"></a>

		<!-- TODO: your code here -->
	</body>
</html>

and the autogenerated Main.js script has this onLoad method:

Main.onLoad = function()
{
	// Enable key event processing
	this.enableKeys();
	widgetAPI.sendReadyEvent();
}

Notice the $MANAGER_WIDGET files referenced in the head; these files allow access to common object modules and are on the TV itself and installed as part of the SDK.

Try running the emulator again –

samsung-emulator-2

Stonking.

Developing a slightly less basic app

Using the API created in my January posts on nodejs I’m going to create a tv app which will display the results of a product search on the Asos catalogue.

The main.js file now has an updated onload method, which makes a call to the API and then passes the returned data to a new method:

Main.onLoad = function()
{	
	var URL = "http://rposbo-basic-node-api.apphb.com/products/socks?key=" + api_key;
	
	if (this.XHRObj != null){ 
		this.XHRObj.destroy(); 
	}
	this.XHRObj = new XMLHttpRequest();
	
	if (this.XHRObj) {
		alert("got XHR");
		this.XHRObj.onreadystatechange = function () {
			alert("State changed to " + Main.XHRObj.readyState); 
			if (Main.XHRObj.readyState == 4) { 
				alert("got data"); 
				Main.recieveData();
				} 
			}; 
		this.XHRObj.open("GET", URL, true); 
		this.XHRObj.send(null); 
	}
	
	// Enable key event processing
	this.enableKeys();
	widgetAPI.sendReadyEvent();
};

The new recieveData method which loops through the returned product data and creates some basic html elements to display the image and title in a list item:

Main.recieveData = function () {
	 
	alert("alerting data...");
	var data = JSON.parse(this.XHRObj.responseText);
	for(var i=0; i<data.products.length; i++)
		{		
			var product = data.products[i];
			alert("adding " + product.title);

			// image
			var productImg = document.createElement("img");
			productImg.setAttribute("src", product.image);
			
			// text
			var title = document.createTextNode(product.title);
			
			// link containing both
			var link = document.createElement("a");
			link.appendChild(productImg);
			link.appendChild(title);
			
			// list item containing link
			var listItem = document.createElement("li");
			listItem.appendChild(link);			
			
			document.getElementById('listing').appendChild(listItem);
		}	 
	};

No jQuery here, since I don’t want to have to load it up locally on to the tv and waste precious memory.

The single html file now looks like
index.html

<!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
		<title>rposboBasicTvApp</title>

		<!-- TODO : Common API -->
		<script type="text/javascript" language="javascript" src="$MANAGER_WIDGET/Common/API/Widget.js"></script>
		<script type="text/javascript" language="javascript" src="$MANAGER_WIDGET/Common/API/TVKeyValue.js"></script>

		<!-- TODO : Javascript code -->
		<script language="javascript" type="text/javascript" src="app/javascript/key.js"></script>
		<script language="javascript" type="text/javascript" src="app/javascript/Main.js"></script>

		<!-- TODO : Style sheets code -->
		<link rel="stylesheet" href="app/stylesheets/Main.css" type="text/css">

		<!-- TODO: Plugins -->

	</head>

	<body onload="Main.onLoad();" onunload="Main.onUnload();">

<div id="listing"></div>

		<!-- Dummy anchor as focus for key events -->
		<a href="javascript:void(0);" id="anchor" onkeydown="Main.keyDown();"></a>

		<!-- TODO: your code here -->
	</body>
</html>

The highlighted line is just where I define my API key and refer to it in Main.js.

This subtly changed code now looks something like:
asos-tv-emulator

Next up – deploying to a TV

We’ve got a basic app, now it’s time to get it on to the TV!

The code from this post is available on github