ROOMGAME

ein Prototype für Amazon Alexa

Tobias Hartmann @ToH_82 .  Manuel Rülke @homecoded

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

aber warum?

Testen von States und weil es Spaß macht 

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

Roomescape?!

... Text-Adventure, Day of the Tentacle 

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

eine Idee eine Vision

eigene Roomescape spiele mit IOT 

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

ist sowas schwer?

Alexa Skill Development ... Klick, Klick, fertig

Amazon Developer Console

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

Amazon Developer Console

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

Amazon Developer Dashboard

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

{
  "languageModel": {
    "types": [
      {
        "name": "Direction",
        "values": [
          {
            "id": "1",
            "name": {
              "value": "North",
              "synonyms": [
                "up"
              ]
            }
          },
          {
            "id": "2",
            "name": {
              "value": "South",
              "synonyms": [
                "down"
              ]
            }
          },
          {
            "id": "3",
            "name": {
              "value": "East",
              "synonyms": [
                "right"
              ]
            }
          },
          {
            "id": "4",
            "name": {
              "value": "West",
              "synonyms": [
                "left"
              ]
            }
          }
        ]
      },
      {
        "name": "Item",
        "values": [
          {
            "id": "2",
            "name": {
              "value": "banana",
              "synonyms": []
            }
          },
          {
            "id": "1",
            "name": {
              "value": "torch",
              "synonyms": []
            }
          },
          {
            "id": "3",
            "name": {
              "value": "broom",
              "synonyms": []
            }
          },
          {
            "id": "4",
            "name": {
              "value": "grilled banana",
              "synonyms": []
            }
          }
        ]
      },
      {
        "name": "Object",
        "values": [
          {
            "id": "2",
            "name": {
              "value": "barbecue",
              "synonyms": [
                "bbq"
              ]
            }
          },
          {
            "id": "1",
            "name": {
              "value": "door",
              "synonyms": []
            }
          }
        ]
      }
    ],
    "intents": [
      {
        "name": "AMAZON.CancelIntent",
        "samples": []
      },
      {
        "name": "AMAZON.HelpIntent",
        "samples": []
      },
      {
        "name": "AMAZON.StartOverIntent",
        "samples": [
          "reset game"
        ]
      },
      {
        "name": "AMAZON.StopIntent",
        "samples": [
          "quit",
          "stop",
          "Goodbye"
        ]
      },
      {
        "name": "CombineIntent",
        "samples": [
          "combine {BaseItem} with {Item}",
          "use {BaseItem} with {Item}",
          "put {BaseItem} into {Item}"
        ],
        "slots": [
          {
            "name": "Item",
            "type": "Item"
          },
          {
            "name": "BaseItem",
            "type": "Item"
          }
        ]
      },
      {
        "name": "EatIntent",
        "samples": [
          "eat {Item}"
        ],
        "slots": [
          {
            "name": "Item",
            "type": "Item"
          }
        ]
      },
      {
        "name": "GoToIntent",
        "samples": [
          "go to {Direction}",
          "move to {Direction}",
          "go {Direction}",
          "move {Direction}",
          "venture {Direction}",
          "{Direction}"
        ],
        "slots": [
          {
            "name": "Direction",
            "type": "Direction"
          }
        ]
      },
      {
        "name": "PickUpIntent",
        "samples": [
          "pickup {Item}",
          "take {Item}"
        ],
        "slots": [
          {
            "name": "Item",
            "type": "Item"
          }
        ]
      },
      {
        "name": "ShowIntent",
        "samples": [
          "show",
          "describe room",
          "what can I see"
        ],
        "slots": []
      },
      {
        "name": "ShowInventoryIntent",
        "samples": [
          "ShowInventory",
          "Inventory"
        ],
        "slots": []
      },
      {
        "name": "UseIntent",
        "samples": [
          "use {Item} with {Object}",
          "open {Object} with {Item}",
          "hit {Object} with {Item}",
          "put {Item} into {Object}"
        ],
        "slots": [
          {
            "name": "Item",
            "type": "Item"
          },
          {
            "name": "Object",
            "type": "Object"
          }
        ]
      }
    ],
    "invocationName": "mansion"
  }
}

Skill Model JSON

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

JavaScript, what else

Alexa Skills Kit for NodeJs

Skills Kit für NodeJs

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

https://github.com/alexa/alexa-skills-kit-sdk-for-nodejs

npm install --save alexa-sdk
var Alexa = require('alexa-sdk');

exports.handler = function(event, context, callback){
    var alexa = Alexa.handler(event, context, callback);
};
var handlers = {
    'HelloWorldIntent': function () {
        this.emit(':tell', 'Hello World!');
    }
};

}

tell, ask, askWithCard, tellWithCard, confirmIntent, confirmIntentWithCard, ...

Skills Kit für NodeJs - States

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

https://github.com/alexa/alexa-skills-kit-sdk-for-nodejs

var states = {
    GUESSMODE: '_GUESSMODE', 
    STARTMODE: '_STARTMODE'
};

var newSessionHandlers = {
    'NewSession': function() {
        this.handler.state = states.STARTMODE;
    }
};

var startGameHandlers = Alexa.CreateStateHandler(states.STARTMODE, {
    'AMAZON.YesIntent': function() {
        this.handler.state = states.GUESSMODE;
    }
});

var guessModeHandlers = Alexa.CreateStateHandler(states.GUESSMODE, {
    'NumberGuessIntent': function() {}
});

Amazon Lambda Blueprints

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

Amazon Lambda Konfiguration

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

Wie sieht das am Ende aus

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

/* eslint-disable  func-names */
/* eslint quote-props: ["error", "consistent"]*/
/**
 * This sample demonstrates a simple skill built with the Amazon Alexa Skills
 * nodejs skill development kit.
 * This sample supports multiple lauguages. (en-US, en-GB, de-DE).
 * The Intent Schema, Custom Slots and Sample Utterances for this skill, as well
 * as testing instructions are located at https://github.com/alexa/skill-sample-nodejs-fact
 **/

'use strict';

const Alexa = require('alexa-sdk');

const APP_ID = undefined;  // TODO replace with your app ID (OPTIONAL).

const languageStrings = {
    'en': {
        translation: {
            FACTS: [
                'A year on Mercury is just 88 days long.',
                'Despite being farther from the Sun, Venus experiences higher temperatures than Mercury.',
                'Venus rotates anti-clockwise, possibly because of a collision in the past with an asteroid.',
                'On Mars, the Sun appears about half the size as it does on Earth.',
                'Earth is the only planet not named after a god.',
                'Jupiter has the shortest day of all the planets.',
                'The Milky Way galaxy will collide with the Andromeda Galaxy in about 5 billion years.',
                'The Sun contains 99.86% of the mass in the Solar System.',
                'The Sun is an almost perfect sphere.',
                'A total solar eclipse can happen once every 1 to 2 years. This makes them a rare event.',
                'Saturn radiates two and a half times more energy into space than it receives from the sun.',
                'The temperature inside the Sun can reach 15 million degrees Celsius.',
                'The Moon is moving approximately 3.8 cm away from our planet every year.',
            ],
            SKILL_NAME: 'Space Facts',
            GET_FACT_MESSAGE: "Here's your fact: ",
            HELP_MESSAGE: 'You can say tell me a space fact, or, you can say exit... What can I help you with?',
            HELP_REPROMPT: 'What can I help you with?',
            STOP_MESSAGE: 'Goodbye!',
        },
    },
    'en-US': {
        translation: {
            FACTS: [
                'A year on Mercury is just 88 days long.',
                'Despite being farther from the Sun, Venus experiences higher temperatures than Mercury.',
                'Venus rotates counter-clockwise, possibly because of a collision in the past with an asteroid.',
                'On Mars, the Sun appears about half the size as it does on Earth.',
                'Earth is the only planet not named after a god.',
                'Jupiter has the shortest day of all the planets.',
                'The Milky Way galaxy will collide with the Andromeda Galaxy in about 5 billion years.',
                'The Sun contains 99.86% of the mass in the Solar System.',
                'The Sun is an almost perfect sphere.',
                'A total solar eclipse can happen once every 1 to 2 years. This makes them a rare event.',
                'Saturn radiates two and a half times more energy into space than it receives from the sun.',
                'The temperature inside the Sun can reach 15 million degrees Celsius.',
                'The Moon is moving approximately 3.8 cm away from our planet every year.',
            ],
            SKILL_NAME: 'American Space Facts',
        },
    },
    'en-GB': {
        translation: {
            FACTS: [
                'A year on Mercury is just 88 days long.',
                'Despite being farther from the Sun, Venus experiences higher temperatures than Mercury.',
                'Venus rotates anti-clockwise, possibly because of a collision in the past with an asteroid.',
                'On Mars, the Sun appears about half the size as it does on Earth.',
                'Earth is the only planet not named after a god.',
                'Jupiter has the shortest day of all the planets.',
                'The Milky Way galaxy will collide with the Andromeda Galaxy in about 5 billion years.',
                'The Sun contains 99.86% of the mass in the Solar System.',
                'The Sun is an almost perfect sphere.',
                'A total solar eclipse can happen once every 1 to 2 years. This makes them a rare event.',
                'Saturn radiates two and a half times more energy into space than it receives from the sun.',
                'The temperature inside the Sun can reach 15 million degrees Celsius.',
                'The Moon is moving approximately 3.8 cm away from our planet every year.',
            ],
            SKILL_NAME: 'British Space Facts',
        },
    },
    'de': {
        translation: {
            FACTS: [
                'Ein Jahr dauert auf dem Merkur nur 88 Tage.',
                'Die Venus ist zwar weiter von der Sonne entfernt, hat aber höhere Temperaturen als Merkur.',
                'Venus dreht sich entgegen dem Uhrzeigersinn, möglicherweise aufgrund eines früheren Zusammenstoßes mit einem Asteroiden.',
                'Auf dem Mars erscheint die Sonne nur halb so groß wie auf der Erde.',
                'Die Erde ist der einzige Planet, der nicht nach einem Gott benannt ist.',
                'Jupiter hat den kürzesten Tag aller Planeten.',
                'Die Milchstraßengalaxis wird in etwa 5 Milliarden Jahren mit der Andromeda-Galaxis zusammenstoßen.',
                'Die Sonne macht rund 99,86 % der Masse im Sonnensystem aus.',
                'Die Sonne ist eine fast perfekte Kugel.',
                'Eine Sonnenfinsternis kann alle ein bis zwei Jahre eintreten. Sie ist daher ein seltenes Ereignis.',
                'Der Saturn strahlt zweieinhalb mal mehr Energie in den Weltraum aus als er von der Sonne erhält.',
                'Die Temperatur in der Sonne kann 15 Millionen Grad Celsius erreichen.',
                'Der Mond entfernt sich von unserem Planeten etwa 3,8 cm pro Jahr.',
            ],
            SKILL_NAME: 'Weltraumwissen auf Deutsch',
            GET_FACT_MESSAGE: 'Hier sind deine Fakten: ',
            HELP_MESSAGE: 'Du kannst sagen, „Nenne mir einen Fakt über den Weltraum“, oder du kannst „Beenden“ sagen... Wie kann ich dir helfen?',
            HELP_REPROMPT: 'Wie kann ich dir helfen?',
            STOP_MESSAGE: 'Auf Wiedersehen!',
        },
    },
};

const handlers = {
    'LaunchRequest': function () {
        this.emit('GetFact');
    },
    'GetNewFactIntent': function () {
        this.emit('GetFact');
    },
    'GetFact': function () {
        // Get a random space fact from the space facts list
        // Use this.t() to get corresponding language data
        const factArr = this.t('FACTS');
        const factIndex = Math.floor(Math.random() * factArr.length);
        const randomFact = factArr[factIndex];

        // Create speech output
        const speechOutput = this.t('GET_FACT_MESSAGE') + randomFact;
        this.emit(':tellWithCard', speechOutput, this.t('SKILL_NAME'), randomFact);
    },
    'AMAZON.HelpIntent': function () {
        const speechOutput = this.t('HELP_MESSAGE');
        const reprompt = this.t('HELP_MESSAGE');
        this.emit(':ask', speechOutput, reprompt);
    },
    'AMAZON.CancelIntent': function () {
        this.emit(':tell', this.t('STOP_MESSAGE'));
    },
    'AMAZON.StopIntent': function () {
        this.emit(':tell', this.t('STOP_MESSAGE'));
    },
};

exports.handler = function (event, context) {
    const alexa = Alexa.handler(event, context);
    alexa.APP_ID = APP_ID;
    // To enable string internationalization (i18n) features, set a resources object.
    alexa.resources = languageStrings;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

Details mit SSML

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

Speech Synthesis Markup Language

<speak>
    Good morning, <say-as interpret-as="spell-out">Dave</say-as> 
    <audio src="https://dave.42.com/audio/activate.mp3" /> 
</speak> 


<speak>
    I'm sorry, Dave. <break time="1s"/>
    <amazon:effect name="whispered">I'm afraid I can't do that.</amazon:effect>.
</speak>


<speak>
    <emphasis level="strong">This mission is too important for me</emphasis> 
     to allow you to jeopardize it.     
</speak>

https://developer.amazon.com/de/docs/custom-skills/speech-synthesis-markup-language-ssml-reference.html

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

Statemachine

weil Standard nicht genug war

Was ist eine Statemachine

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

  • Programmiermodell mit "Zuständen" (States)
  • definierte Übergänge zw. Zuständen (Transitions)
  • Aktionen (Actions/Events) abhängig vom Zustand

INAKTIV

SUCHEN

 

ANGRIFF

 

Wenn Abstand d. Spielfigur </> Sichtweite

Wenn Abstand d. Spielfigur </> Angriffsreichweite

 

Zustände einer computergesteuerten Spielfigur

Abbilden der Zustände durch gekapselteten Code (Klassen/Module) -> Struktur

Alexa hat eine eigene Statemachine. Warum nicht diese nutzen?

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

Vorteile Nachteile
Zustand wird automatisch in Session gespeichert Debugging
Zustand kann persistiert werden (DynamoDB) Läuft nur im Alexa SDK
Debugging nur mit erhöhtem Setup-Aufwand

Was macht unsere Statemachine anders?

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

Vorteile Nachteile
keine Abhängigkeiten Datenpersistenz
testbar
Wiederverwendbarkeit
Debugging

Ablauf

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

Aufruf

 

Intent

Slot-Daten

Alexa-Adapter

1. State-Persitenz
2. Mapping

State Machine

Event-Name

Event-Daten

State

Handler

plattform-
abhängig

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

Demo

was Alexa mit einer gegrillten Banane zu tun hat

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

UX, es heißt DD/DX

... für VUI/CUI brauchts DD/DX

Eine neue Herausforderung

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

Dialog Design

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

So menschlich wie möglich.

Satzvariationen bilden.

Kontextbezogene Antworten.

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

nettes Spiel aber

kann diese Dose auch was gescheites?

Vielseitiger als wir denken

Tobias Hartmann @ToH_82 . Manuel Rülke @homecoded

HOTEL

EMPFANG

OFFICE

DAHEIM

GAMES

BLOG

SHOP

Wir bringen Begeisterung und Einfachheit in die Interaktion zwischen Mensch und Software

HTTPS://DAVE42.COM/

Tobias Hartmann @ToH_82

Manuel Rülke @homecoded