alexa

package module
v0.0.0-...-61e4c35 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 15, 2020 License: GPL-3.0 Imports: 11 Imported by: 1

README

Alexa SDK for GO

Alexa SDK for native go on AWS Lambda
A coffee?

Installation:

go get https://github.com/dasjott/alexa-sdk-go

Usage / Quick Start

main

Your main function is fairly clear

func main() {
	alexa.AppID = "your-skill-id-1234"
	alexa.Handlers = handlers
	alexa.LocaleStrings = locales
	lambda.Start(alexa.Handle)
}

handlers

The 'handlers' variable mentioned in main:

var handlers = alexa.IntentHandlers{
	"LaunchRequest": func(c *alexa.Context) {
		sayHello(c, c.T("HELLO"))
	},
	"AMAZON.HelpIntent": func(c *alexa.Context) {
		c.Ask(c.T("HELP"))
	},
	"AMAZON.CancelIntent": bye,
	"AMAZON.StopIntent": bye,
	"AMAZON.NoIntent": bye,
	"AMAZON.YesIntent": func(c *alexa.Context) {
		sayHello(c, c.T("HELLO"))
	},
}

func bye(c *alexa.Context) {
	c.Tell(c.T("BYE"))
}
func sayHello(c *alexa.Context, speech string) {
	c.Tell(speech)
}

locales

The 'locales' variable mentioned in main:

var locales = alexa.Localisation{
	"de-DE": alexa.Translation{
		"HELLO":     []string{"Hallo.", "Guten Tag."},
		"BYE":       []string{"Tschüss.", "Bis dann."},
		"HELP":      "Ich kann Hallo sagen. Möchtest du jetzt Hallo sagen?",
	},
	"en-US": alexa.Translation{
		"HELLO":     "Hello.",
		"BYE":       []string{"Bye.", "See you."},
		"HELP":      "I can say hello. Do you want me to say hello?",
	},
}

As you may have noticed, some fields are string arrays but are accessed like single strings.
If you do so, the translation kit then chooses one string randomly from the given array, enabling you an easy way of implementing a more natural response behaviour of Alexa.

Alexa

The alexa package is the main package of this SDK. You already saw it in the previous section.
It provides you with the following functionality:

  • alexa.AppID = "your-skill-id-1234
    Fill in the skills ID here. It is checked on every request and a panic is released on a mismatch.
    Let it empty to skip that check (and panic)

  • alexa.Handlers = alexa.IntentHandlers{}
    The IntentHandlers type is a mapping of intent names to alexa.IntentHandler functions.
    See here, how to use it

  • alexa.IntentHandler The type for a intent function: func(c *alexa.Context). Put those mapped to the intent name into the alexa.IntenHandlers{}
    See here, how to use it

  • alexa.LocaleStrings = alexa.Localisation{}
    The IntentHandlers type is a mapping of language code strings to alexa.Translation functions.
    See here, how to use it

  • alexa.Translation{}
    A translation of all your strings. It is basicly a map, where the key is string and the value either string or []string.
    See here, how to use it and see here, how to access those strings in your intent code.

  • alexa.BeforeHandler
    You can assign a function func(*Context) to this property. This function is then called before any intent is called.
    If c.Abort() was called within this function, no following intent is called.

  • alexa.MultiHandler(func(c *alexa.Context), func(c *alexa.Context), func(c *alexa.Context))
    Provide this function instead of providing an intent function directly, if you want to use more than one function on that intent.
    You can add as many IntentHandler functions as you want.

  • alexa.Handle() This is the function the Lambda.Start() function wants to have. Just provide it as shown here

Context

Your intent functions are provided with an alexa.Context pointer. That contains all the information you need.

Conversational

This SDK keeps conversation with your customer simple. Basicly you want to ask or tell something. And sometimes you want to provide a card for the Alexa App.
On most functions (if they work with cards) you can immediately add card information.

Conversational functions are:

  • c.Tell("I am Batman")
    Tells something and ends the session.
    Usable with card.

  • c.Ask("Why so serious?") or c.Ask("Why so serious?", "didn't you hear me?")
    Asks the customer and keeps the session open, thus waiting for an answer. That can invoke an other intent then.
    The first argument is mandatory. It is the actual question. The second is reprompt speech. If you provide more than one (after the first), the reprompt speech is randomly chosen out of those.
    Usable with card.

  • c.ElicitSlot("mySlot", "What do you want?", "Are you sure?", optionalIntent)
    Asks the user about a specific slot value. First argument is the slots name, second is the actual speech (question), third is reprompt, if needed. The last one can be a modified *dialog.EchoIntent, if you need to do so. Otherwise let it be nil.
    Usable with card.

  • c.ConfirmSlot("TheSlot", "please confirm", optionalIntent)
    Let Alexa confirm the slot named in the first parameter by the customer. The second parameter is the speech rendered by Alexa and the third one can be a modified *dialog.EchoIntent, if you need to do so. Otherwise let it be nil.
    Usable with card.

  • c.ConfirmIntent("Confirm all the stuff please", optionalIntent)
    Let Alexa confirm all information given by the customer. The second parameter can be a modified *dialog.EchoIntent, if you need to do so. Otherwise let it be nil.
    Usable with card.

  • c.Delegate(optionalIntent)
    Delegate slot fulfillment to Alexa. You can check the dialog state c.DialogState() for e.g. 'STARTED' or 'COMPLETED' to know, whether all the slots are filled or you have to again Delegate.
    You can provide a *dialog.EchoIntent to send a modified intent, if you need to do so. Otherwise let it be nil.

With card

Just add one of these method calls to the conversation chain:

  • SimpleCard("My Title", "An explaining text")
    Adds a simple card with a title and some text.

  • StandardCard("My Title", "An explaining text", "https://url/to/small/image.png", "https://url/to/large/image.png")
    Adds a card with a title, some text, a small and a large picture.

  • LinkAccountCard()
    Adds a link account card, remembering the customer to do some account linking first.

Examples:
c.Tell("I am Batman").SimpleCard("Dark Knight said", "He is Batman")
c.Tell("Please link your Gotham account first").LinkAccountCard()

Progressive Request

Before you actually respond to the intent request, you can send progressive requests to keep your customer entertained while your response may take longer.
The SDK makes sure the request was responded before another one may be sent or before your intent response is sent.

  • c.Progress("Sorry, this may take a while")
    Sends a progress to Alexa to be rendered. You can use ssml.
    This method returns immediately as the request runs parallel to the subsequent code.

Voice

For most languages different voices are provided for temporary usage.

  • call the function dialog.SetVoice("Joey") to set up the according voice for all output.
  • use the function dialog.Voice("Kimberly", "Hey, I'm feeling fine.") for any particular string.

The according ssml tags are added automaticly.

Localization

As you could already notice, localization is rather easy with this SDK. It always automaticly chooses the current language and returns the translation.
There are three different functions provided:

  • c.T("FOO")
    Returns the translated string for the key "FOO"
    If FOO is an array of strings, a random string is chosen. If more than one key is provided, the values are concatenated.

  • c.TA("BAR")
    Returns the translated array for the key "BAR"
    If BAR is just a string, it returns an array with this one entry.

  • c.TR("BAZ", &MyStruct) or c.TR("BAZ", alexa.R{"foo":"bar"})
    Returns the translated string for the key "BAZ" and substitutes variables with the given struct. You can also provide an alexa.R for spontanious values. For preparing the struct read on.

Runtime values for localized strings

You can place values into your translated strings on runtime. You use the c.TR() function for this and as a second argument you provide a alexa.R or any struct.
Place variables to be substituted within your string as follows:
"BAZ": "You have {NUM} cookies"
The key would be "NUM" then. The translation kit either uses the struct field name or if provided an alexa tag. Example:

type MyStruct struct {
	Num int `json:"num" alexa:"NUM"`
}

The tag always wins over the field name.
Please note that cascaded structs work concatenated with dots as a value. A struct 'foo' contains another struct 'bar' which contains a value "baz". The replacement variable would then be 'bar.baz'.

special feature for floats
  • Float numbers are rendered according to language according to commas and dots.
  • the number of decimal places defaults to 2, but can be modified in two ways:
    • in your Translation map provide a field ":decimals": 4 to achieve four decimal places for that language.
    • in your struct provide the alexa tag with additional info: alexa:"NUM,3" to achieve 3 decimal places fot that specific field.

Attributes

Supported types: interface{}, string, bool, int, float32.
To access the session attributes, you simply use the Attr method of the context.

// to write attributes
c.Attr("my_number", 42)
c.Attr("my_str", "what a value")
c.Attr("my_flag", true)

// to read attributes
num := c.Attr("my_number").Int()
str := c.Attr("my_str").String()
flag := c.Attr("my_flag").Bool()

// delete an attribute
c.Attr("old_val", nil)

Please note that the SDK tries to cast values except for bool!.


The Attr method returns an Attr object which not only provides you with type cast methods, but also an Exists Method. Therefore you can do the following: ```go if a := c.Attr("page"); a.Exists() { c.Tell(c.TR("YOUR_PAGE", a.R())) } c.Tell(c.T("NO_PAGE")) ``` As you can see here, the Attr object also provides a method `R()` wich can directly be used as an input to `TR()` of localisation, as it returns a suitable map.
You can call the `R()` method with or without parameters. If you call it without parameters, the name of the key is the attributes name. If you provide parameters, these will be used as key names and thus will be replaced with the same value (can be useful).

Slots

For slots the alexa.Context provides the Method Slot("slotname"). It returns an object providing you with three values of the slot. If the slot does not exist in the request, those three values are empty, but never does the Slot method return nil. The three values of the slot here are:

  • ID
    The ID you can assign to a slot.
  • Value
    The value you can assign to a slot.
  • Spoken
    The words actually spoken by the customer.
  • ConfirmationStatus
    The status of the confirmation of this slot, if in a dialog
  • Match
    Is true if the actual spoken words are matching a value of this slot or its synonyms

Other methods

  • c.NewSession()
    Returns true if the session is just started and false otherwise.

  • c.SessionID()
    Returns the current sessions id.

  • c.Locale()
    Returns the current used language code. Possible values are de-DE, en-GB, en-US and more. Please see Amazon docs.

  • c.DialogState()
    Returns the current dialog state.

Properties

  • c.Intent
    The name of the currently called intent.

  • c.System
    Returns the system property of the request. That contains information about the calling system and user.

Donate?

If you appreciate what I do, please consider to buy me a coffee.
Thank you ;-)

Documentation

Index

Constants

View Source
const (
	// PermissionFullName - Full Name
	PermissionFullName = "alexa::profile:name:read"

	// PermissionGivenName - Given Name (First Name)
	PermissionGivenName = "alexa::profile:given_name:read"

	// PermissionEmailAddress - Email Address
	PermissionEmailAddress = "alexa::profile:email:read"

	// PermissionPhoneNumber - Phone Number
	PermissionPhoneNumber = "alexa::profile:mobile_number:read"
)
View Source
const (
	ConfirmationStatusNone      = "NONE"
	ConfirmationStatusDenied    = "DENIED"
	ConfirmationStatusConfirmed = "CONFIRMED"
)

Variables

View Source
var AppID string

AppID is the ID of the corresponding skill

View Source
var BeforeHandler func(*Context)

BeforeHandler can be set with a function to implement any checking before every intent. It returns true for going on with the actual intent or false to skip. Remember to implement a appropriate message to the user on skipping!

View Source
var GetTranslation func(locale string) Translation

GetTranslation is called with the current locale code. You must provide the according Translation.

View Source
var Handle = func(req *dialog.EchoRequest) (*dialog.EchoResponse, error) {
	if req == nil {
		panic("Echo request is nil")
	}

	if AppID != "" && !req.VerifyAppID(AppID) {
		panic("invalid app id")
	}
	if Handlers == nil {
		panic("no handlers set")
	}

	var trans *Translator
	if GetTranslation != nil {
		if langmap := GetTranslation(req.Request.Locale); langmap != nil {
			loc := Localisation{req.Request.Locale: langmap}
			trans = loc.GetTranslator(req.Request.Locale)
		}
	} else if LocaleStrings != nil {
		trans = LocaleStrings.GetTranslator(req.Request.Locale)
	}
	if trans == nil {
		panic("language " + req.Request.Locale + " not implemented")
	}

	c := Context{
		request:    req,
		handlers:   Handlers,
		response:   dialog.NewResponse(),
		translator: trans,
		attributes: req.Session.Attributes,

		System: &req.Context.System,
		Intent: &req.Request.Intent,
		Time:   req.GetTime(),
	}

	c.start(req)
	return c.getResult()
}

Handle is the function you hand over to the lambda.start

Functions

func API

func API(c *Context) *api.Client

API sets up a client to call the alexa api

Types

type Attr

type Attr struct {
	// contains filtered or unexported fields
}

Attr takes a generic value and converts it with provided functions

func (*Attr) Bool

func (u *Attr) Bool() bool

Bool gets the attribute as bool by given key

func (*Attr) Exists

func (u *Attr) Exists() bool

Exists determines whether the attribute ectually exists within the collection

func (*Attr) Float32

func (u *Attr) Float32() float32

Float32 gets attribute as float32 by given key

func (*Attr) Float64

func (u *Attr) Float64() float64

Float64 gets attribute as float64 by given key

func (*Attr) Int

func (u *Attr) Int() int

Int gets attribute as int by given key

func (*Attr) Int64

func (u *Attr) Int64() int64

Int64 gets attribute as int by given key

func (*Attr) Interface

func (u *Attr) Interface() interface{}

Interface gets attribute as interface{} by given key

func (*Attr) R

func (u *Attr) R(key ...string) map[string]string

R returns a map suitable for TR of localization If no key is provided, the attribute name is taken. If one or more key is provided, all the keys are added with the attributes value.

func (*Attr) String

func (u *Attr) String() string

String gets attribute as string by given key Can convert from float32, float64, int, int64

func (*Attr) StringArr

func (u *Attr) StringArr() []string

StringArr gets attribute as string array by given key

func (*Attr) Unmarshal

func (u *Attr) Unmarshal(data interface{}) error

Unmarshal gets attribute by given key and unmarshals it into data

type Cardable

type Cardable struct {
	// contains filtered or unexported fields
}

Cardable is returned by functions, to make them cardable

func (*Cardable) AskPermissionCard

func (c *Cardable) AskPermissionCard(permissions []string)

AskPermissionCard adds a "ask for permission" card to the response you can use the constants from this package, prefixed with Permission

func (*Cardable) LinkAccountCard

func (c *Cardable) LinkAccountCard()

LinkAccountCard adds a link account card to the response

func (*Cardable) SimpleCard

func (c *Cardable) SimpleCard(title, content string)

SimpleCard adds a simple card to the response

func (*Cardable) StandardCard

func (c *Cardable) StandardCard(title, content, smallImageURL, largeImageURL string)

StandardCard adds a standard card to the response

type Context

type Context struct {

	// System contains informations about the calling Device and User
	System *dialog.EchoSystem
	// Intent is the intents name
	Intent *dialog.EchoIntent
	// Time is the requests timestamp as go time.Time
	Time time.Time
	// contains filtered or unexported fields
}

Context is the object sent to every intent, collecting infos for response

func (*Context) Abort

func (c *Context) Abort()

Abort prevents the execution of a following handler within an alexa.MultiHandler chain.

func (*Context) Ask

func (c *Context) Ask(speechOutput string, repromptSpeech ...string) *Cardable

Ask the user something

func (Context) Attr

func (a Context) Attr(key string, values ...interface{}) *Attr

Attr gets or sets attributes. Set more than one value and it will become an array

func (*Context) AudioPlay

func (c *Context) AudioPlay(audio, id, speech string) *Cardable

AudioPlay is for AudioPlayer.Play

func (*Context) AudioStop

func (c *Context) AudioStop(speech string) *Cardable

AudioStop is for AudioPlayer.Stop, AudioPlayer.ClearQueue

func (*Context) ConfirmIntent

func (c *Context) ConfirmIntent(speechOutput, repromptSpeech string, updatedIntent *dialog.EchoIntent) *Cardable

ConfirmIntent confirm all the slots given to the intent by Alexa

func (*Context) ConfirmSlot

func (c *Context) ConfirmSlot(slotToConfirm, speechOutput, repromptSpeech string, updatedIntent *dialog.EchoIntent) *Cardable

ConfirmSlot confirm a slot value by Alexa

func (*Context) Delegate

func (c *Context) Delegate(updatedIntent *dialog.EchoIntent)

Delegate a slot fullfillment to Alexa

func (*Context) DialogState

func (c *Context) DialogState() string

DialogState gets the current state of the dialog

func (*Context) ElicitSlot

func (c *Context) ElicitSlot(slotToElicit, speechOutput, repromptSpeech string, updatedIntent *dialog.EchoIntent) *Cardable

ElicitSlot action to fullfill a slot of a certain intent

func (*Context) Locale

func (c *Context) Locale() string

Locale gets the locale string like one of: de-DE, en-AU, en-CA, en-GB, en-IN, en-US, ja-JP, fr-FR

func (*Context) NewSession

func (c *Context) NewSession() bool

NewSession determines whether this is a new session that was opened with this call

func (*Context) Now

func (c *Context) Now() time.Time

Now returns the time of the request on users side

func (*Context) Progress

func (c *Context) Progress(speech string)

Progress sends a progress for the user to be entertained while waiting

func (*Context) SessionID

func (c *Context) SessionID() string

SessionID is the unique ID of this session

func (*Context) Slot

func (c *Context) Slot(name string) *Slot

Slot gets a slot by name. The pointer is never nil.

func (*Context) T

func (c *Context) T(key ...string) string

T gets a translated string according to the given key. If the value is an array, a random value is chosen.

func (*Context) TA

func (c *Context) TA(key string) []string

TA gets a translated string array according to the given key.

func (*Context) TR

func (c *Context) TR(key string, replace interface{}) string

TR gets a translated string according to the given key. If the value is an array, a random value is chosen. Variables in {brackets} will be replaced. Use either the alexa.R or a struct for providing variables (tag name would be 'alexa')!

func (*Context) Tell

func (c *Context) Tell(speech string) *Cardable

Tell something to the user

type IntentHandler

type IntentHandler func(*Context)

IntentHandler function for the handler

func MultiHandler

func MultiHandler(handlers ...IntentHandler) IntentHandler

MultiHandler if you need more than one handler for an intent

type IntentHandlers

type IntentHandlers map[string]IntentHandler

IntentHandlers for collecting the handler functions

var Handlers IntentHandlers

Handlers are intent functions to be called by name

func (IntentHandlers) Add

func (h IntentHandlers) Add(name string, handler IntentHandler)

Add adds a handler afterwards.

type Localisation

type Localisation map[string]Translation

Localisation maps locale codes to according Translations

var LocaleStrings Localisation

LocaleStrings are all localized strings

func (Localisation) GetTranslator

func (loc Localisation) GetTranslator(locale string) *Translator

GetTranslator gets a translator for the given language

type R

type R map[string]interface{}

R (for Replace) is a shortcut for map[string]interface{}, while the value must be int (any), float (any) or string

type Slot

type Slot struct {
	// ID is the first ID of that slot value
	ID string
	// Value is the first value of slot, not the actual spoken value
	Value string
	// Value is the value of slot, not the actual spoken value
	Values []SlotValue
	// Spoken is the actual value, spoken by the user
	Spoken string
	// ConfirmationStatus is the status of the confirmation of this slot
	ConfirmationStatus string
	// Match is true, if the actual speech is a match to one of this slots values or its synonyms
	Match bool
}

Slot is a simple representation of the slot object from the echo request

func (*Slot) Empty

func (s *Slot) Empty() bool

Empty determines whether this slot is already filled

type SlotValue

type SlotValue struct {
	ID    string
	Value string
}

type Translation

type Translation map[string]interface{}

Translation is a set of translated strings. The value can be either a string or a string array

type Translator

type Translator struct {
	Phrases Translation
	// contains filtered or unexported fields
}

Translator actively translates keys to values

func (*Translator) GetArray

func (tr *Translator) GetArray(key string) []string

GetArray gets an array from the value according to the given key

func (*Translator) GetString

func (tr *Translator) GetString(key string) string

GetString gets a string from the value according to the given key

func (*Translator) GetStringAndReplace

func (tr *Translator) GetStringAndReplace(key string, replace R) string

GetStringAndReplace gets a translated string and replaces given keys with given values. Place key in {brackets} to be replaced here!

func (*Translator) GetStringWithVariables

func (tr *Translator) GetStringWithVariables(key string, data interface{}) string

GetStringWithVariables gets a translated string, where all placeholders are filled with the values from the given struct. Place key in {brackets} to be replaced here! As tag name use alexa.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL