BDD für Alexa Skills – Teil 1: Initiales Setup

Keine Kommentare

Angenommen ich möchte einen Alexa Skill entwickeln
Wenn ich die Dialoge mit Alexa vorab als ausführbare Akzeptanztests ablegen könnte
Dann wäre ein großer Schritt zu hochwertigen Skills getan

Behavior-Driven Alexa Skill Development mit cucumber.js

Motiviation

Eigentlich hatte ich diesen Blog-Artikel gar nicht geplant. Mich interessierte die Nutzerinteraktion von Anwendern mit Voice-UIs und ich wollte mich diesem Thema mit einem einfachen Alexa Skill nähern. Nun habe ich an vielen Stellen gelesen, wie einfach es doch ist, einen eigenen Skill zu schreiben. Allerdings sind mir die ersten Schritte dann leider doch recht schwer gefallen, also habe ich beschlossen meine Erfahrungen damit in einem Blog-Artikel zusammen zu fassen.

Schritt für Schritt kam dann der Wunsch nach Tests auf. Eigentlich wollte ich ja nur was ausprobieren und auf Tests komplett verzichten. Warum sich das für mich nicht bewährt hat erkläre ich im weiteren Verlauf.

Im ersten Teil dieser Blogserie beschreibe ich das initiale Skill-Setup.

Die initialen Anforderungen

  • Meine initialen Anforderungen an die Skill-Entwicklung waren:
    Es sollte über ein einfaches “Hello World”-Beispiel hinausgehen. Für mich hält sich der Lerneffekt bei extrem vereinfachten Beispielen doch sehr in Grenzen. Das Thema ist nunmal komplex und diese Komplexität wollte ich erfahren und nicht ausblenden. Also habe ich mir als Thema einen Skill vorgenommen, der das lästige Punktenotieren bei einem Würfelspiel übernimmt.
  • Also erwartete ich auch mehr als nur ein paar Zeilen Code. Diesen wollte ich in einem Git Repository sichern.
  • Auf Programmierebene wollte ich möglichst viel Vertrautes einsetzen, einfach damit ich das Maximale über Skill-Entwicklung lerne. Das hieß für mich: modernen JavaScript-Code schreiben – inkl. Features wie async / await oder einfache imports.

Setup des Skills

Ich habe mir das erstbeste Tutorial geschnappt um einfach mal loszulegen. Diesen Teil werde ich hier recht knapp halten. Dafür gibt es bereits gute Anleitungen im Netz (u.a. auch hier im codecentric Blog). Da sich das Vorgehen aber leicht geändert hat, gebe ich zumindest einen kurzen Überblick.

Für die Skill-Entwicklung müssen wir mindestens zwei Artefakte erstellen:

  • Das erste ist das Voice Interaction Model. In diesem Modell definieren wir, welche Befehle (Intents) ein Anwender in unserem Skill triggern kann und welche Spracheingaben (Utterances) welchen Intent auslösen.
  • Das zweite ist der Code der genau diese definierten Intents behandelt. Der also die Anfragen entgegennimmt, verarbeitet und (üblicherweise) mindestens mit einer Sprachausgabe antwortet. Dieser Code kann theoretisch als ein beliebiger Webservice angebunden werden, Amazon macht es einem aber einfacher, wenn man dafür eine Lambda-Funktion in der AWS-Cloud anlegt (so gehen wir hier vor).

Schematischer Ablauf des Aufrufs eines Alexa Skills wie im Text beschrieben.

Das Voice Interaction Model

Also unter: https://developer.amazon.com/alexa/console/ask einen neuen Skill anlegen, wofür zunächst ein Amazon Developer Account benötigt wird.

Screenshot der Seite zum Anlegen neuer Alexa Skills

Da ich für diesen Blog-Eintrag einen “normalen” Skill erstellen wollte (kein Briefing, Smart Home oder Video Skill) muss als Model “Custom” gewählt werden. Zudem wird es für diesen Blog-Eintrag ein Skill in deutscher Sprache werden.
Ist der Skill angelegt, werden wir von der Alexa Developer Console begrüßt. Dies ist die Seite in der das Sprachinterface (Voice Interaction Model) erstellt wird. Das Voice Interacation Model definiert, wie Anwender mit unserem Skill interagieren können, also welche ausgesprochenen Sätze erkannt und verarbeitet werden.
Auf der rechten Seite ist Amazon so hilfreich uns eine Checkliste anzubieten. Um den Skill lauffähig zu bekommen müssen wir also folgendes tun:

  • einen Invocation Name festlegen: der Name, den ein Anwender nennt um unseren Skill zu starten. In unserem Beispiel: Alexa, starte Fünferpasch (also ist der Invocation Name: “Fünferpasch”.
  • Intents, Samples & Slots definieren: die einzelnen Befehle die unser Skill entgegennimmt und wie der Anwender sie aufschreibt.
  • Das Modell abspeichern und bauen.
  • Den Endpoint definieren: der Endpoint ist der Code der aufgerufen wird um die Befehle zu verarbeiten. Im Allgemeinen eine AWS-Lambda-Funktion, obwohl auch ein anderer Webservice möglich ist.

Der Invocation Name ist recht schnell festgelegt. Als nächstes folgt der erste Intent für den Skill. Für das Würfelspiel ist der erste Schritt, dass man ein Spiel mit x Spielern starten kann. Also benötigen wir einen Intent zum Start eines Spieles.
Unter Intents:

Screenshot des Voice Interaction Model Editor in der alexa developer console

wird nun ein neuer Intent “starteSpiel” angelegt. Unter “Sample Utterances” kann man Phrasen eintragen, die der Anwender sagen kann um diesen Intent auszulösen.

Innerhalb einer solchen Utterance kann man sogenannte Slots verwenden, als Platzhalter für variable Benutzereingaben.

Für das Würfelspiel starten wir mit einer einzigen Utterance:

"Starte ein Spiel mit {spieleranzahl} Mitspielern"

Die geschweiften Klammern kennzeichnen den Slot “spieleranzahl” dem im unteren Bereich des Bildschirms der Slot Typ “AMAZON.number” zugeordnet wird. Im Resultat kann ein Anwender nun den Intent mit einer beliebigen Anzahl an Mitspielern aufrufen.

Screenshot: Zuordnung eines Slot-Types zu einem Slot in einem Intent

Wir könnten noch weitere Utterances ergänzen, oder Dialoge definieren mit denen Alexa fehlende Slots vom Anwender erfragen kann, aber an dieser Stelle wollen wir nur einen ersten Durchstich bis zur Implementierung der Lambda erzeugen.
Das Modell kann nun gespeichert und gebaut werden.

Setup der Lambda

Um die Intents verwenden zu können, muss nun ein Service angelegt werden, der die Anfragen dazu verarbeitet.
Verknüpft werden der Skill und die Lambda-Funktion unter dem Navigationseintrag “Endpoint”. Hier können wir momentan noch nicht die Lambda eintragen (die müssen wir ja erst anlegen), aber dort erfahren wir bereits die ID unseres Skill. Diese können wir im späteren Verlauf verwenden um den Zugriff auf unsere Lambda nur auf diesen einen Skill zu begrenzen.

Screenshot: Auslesen der Skill-Id auf der Seite zur Definition des Skill Endpoints

Die neue Lambda wird angelegt aus der Lambda Management Console unter:https://eu-west-1.console.aws.amazon.com/lambda/home?region=eu-west-1#/functions

Für einen Alexa Skill in Deutschland muss die AWS Region (oben rechts) auf EU (Ireland) gestellt werden. Hier wählen wir “Funktion erstellen”.
Auf der folgenden Seite können wir auswählen ob wir den Skill von Grund auf neu bauen, eine Vorlage verwenden oder uns im AW Serverless Application Repository bedienen.
Hier habe ich schon den ersten Fehler gemacht und unter „Vorlagen“ eine Vorlage für einen Alexa Skill verwendet. Das ist aber sooo 2018. Damit erstellt man eine Lambda auf Basis des (natürlich völlig veralteten) Alexa-SDK. Wir wollen aber das aktuelle Alexa Skills Kit SDK for Node.js (kur ASK-SDK v2) verwenden. Dazu wählen wir das AWS Serverless Application Repository und verwenden dort die Applikation “alexa-skills-kit-nodejs-factskill” als Vorlage:
Screenshot: Anlegen einer neuen Lambda Funktion basierend auf dem AWS Serverless Application Repository

Auf dem folgenden Bildschirm vergeben wir noch einen Namen für die neue AWS-Anwendungen und schließen den Vorgang mit einem Klick auf Deploy ab.

Screenshot: Konfiguration des Namen der neuen Lambda Funktion

Der Vorgang kann einige Zeit dauern. Aber die aktualisierte Vorlage legt automatisch auch eine Rolle mit Berechtigungen für die Ausführung der Lambda-Funktion an und erzeugt diese direkt für die Laufzeitumgebung node 8 (statt node 6). Wenn alles gut geht sieht der Bildschirm anschließend so aus:

Screenshot: Deployment Status der neu anzulegenden Lambda Funktion
Über den Button “Test App” kommen wir in die Anwendungsübersicht und von dort unter Ressourcen direkt zu unserem neuen Skill.

Screenshot: Übersicht über die neue Lambda Funktion mit dem Alexa Skill Kit Trigger

Im Abschnitt Konfiguration>Designer ist bereits ein Auslöser (Trigger) für das Alexa Skills Kit eingetragen. Unsere neue Lambda-Funktion kann also durch einen Alexa Skill ausgelöst werden. Hier könnten wir auch die Skill-Id aus dem oberen Abschnitt hinterlegen um Zugriffe nur von diesem einen Skill zu erlauben.
Wählen wir im Designer den Wurzelknoten für unsere Lambda aus (das ist bereits der Default wenn man die Seite öffnet), erscheint im unteren Bereich der Funktionscode unserer Lambda.
Der Wizard hat uns dort einige Handler angelegt, leider für Intents die wir für unseren Skill gar nicht benötigen. Diesen Code könnten wir nun online in einer rudimentären IDE bearbeiten.
Da wir aber mit git und unserer lokalen IDE arbeiten wollen, werden wir dies nun im nächsten Schritt ändern. Um aber einmal den Skill und die Lambda im Verbund testen zu können ersetzen wir nun den Code für die Index.js mit folgendem Code:

const Alexa = require('ask-sdk');
 
const LaunchRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'LaunchRequest';
  },
  handle(handlerInput) {
    const speech = 'Willkommen bei Fünferpasch';
    return handlerInput.responseBuilder
      .speak(speech)
      .withSimpleCard(SKILL_NAME, speech)
      .getResponse();
    },
  };
 
const HelpHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'AMAZON.HelpIntent';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .speak('Hilfe kommt')
      .getResponse();
  },
};
 
const ExitHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && (request.intent.name === 'AMAZON.CancelIntent'
        || request.intent.name === 'AMAZON.StopIntent');
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .speak('Tschüss')
      .getResponse();
  },
};
 
const SessionEndedRequestHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'SessionEndedRequest';
  },
  handle(handlerInput) {
    console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);
    return handlerInput.responseBuilder.getResponse();
  },
};
 
const ErrorHandler = {
  canHandle() {
    return true;
  },
  handle(handlerInput, error) {
  console.log(`Error handled: ${error.message}`);
    return handlerInput.responseBuilder
      .speak('Tut mir leid. Es ist ein Fehler aufgetreten')
      .reprompt('Der Techniker ist informiert')
      .getResponse();
  },
};
 
const SKILL_NAME = 'Fünferpasch';
 
const skillBuilder = Alexa.SkillBuilders.standard();
 
exports.handler = skillBuilder
  .addRequestHandlers(
    LaunchRequestHandler,
    HelpHandler,
    ExitHandler,
    SessionEndedRequestHandler
  )
  .addErrorHandlers(ErrorHandler)
  .lambda();

Neben den Standard-Handlern für Error und Hilfe gibt es nun nur noch einen LaunchRequestHandler der ausgeführt wird, wenn unser Skill gestartet wird.
Damit unser Skill dies auch auslöst, müssen wir nun unsere Lambda-Funktion als Endpoint für unseren Skill registrieren. Die ARN dazu finden wir am oberen rechten Bildschirmrand, praktischerweise versehen mit einem Button um diese direkt in die Zwischenablage zu kopieren.

Screenshot: Ermitteln der ARN der Lambda Funktion

Nun müssen wir wieder zurück zu unserem Skill wechseln und die ARN unter Endpoint in das Feld “Default Region” einfügen.

Screenshot: Verknüpfung des Alexa Skills mit der Lambda Funktion

Nicht vergessen, diese Änderung mit “Save Endpoints” abzuspeichern.

Damit haben wir schon eine erste funktionsfähige Version unseres Skill. Bislang werden wir nur begrüßt, aber immerhin.
Die einfachste Möglichkeit dies zu testen ist es, in der Hauptnavigation in den Tab “Test” zu wechseln. Dort könntet ihr über den Alexa Simulator per Tastatur mit dem Skill interagieren:

Screenshot: Test des Alexa Skills im Alexa Simulator

Um den Skill aufzurufen, müsst ihr die Tests im Simulator zunächst erlauben. Dies stellt ihr im Dropdown-Feld oben links ein (im Screenshot markiert).

Ausblick

Damit hätten wir den ersten Schritt erreicht. Der nächste Schritt wird sein, die Entwicklung der Lambda aus der Online IDE in eine lokale IDE zu verlegen.

Stefan Spittank

Stefan ist seit 2016 für die codecentric AG am Standort Solingen tätig.
Anwendungen nutzbar zu machen und eine gute „User Experience“ zu erreichen ist sein täglich Brot. Dabei helfen ihm auch seine langjährigen Erfahrungen als Verantwortlicher für User Interfaces in der IT-Branche.

Weitere Inhalte zu JavaScript

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.