skillserver

package module
v0.0.0-...-dbd3917 Latest Latest
Warning

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

Go to latest
Published: Feb 1, 2020 License: MIT Imports: 20 Imported by: 0

README

go-alexa/skillserver

A simple Go framework to quickly create an Amazon Alexa Skills web service.

Updates

10/3/16: Go 1.7 is required now as go-alexa uses the new core context library. It's not ideal to require 1.7, but with Go's no breaking changes promise it should be an easy upgrade for the vast majority of projects out there and it's better to keep up with the current release. If this change causes any issues, please reach out with an issue.

4/5/16: After taking a few good addtions from the community recently, I also just added new hooks that make it even easier to get going since you don't have to write a full net/http handler (see the new Hello World below)!

What?

After beta testing the Amazon Echo (and it's voice assistant Alexa) for several months, Amazon has released the product to the public and created an SDK for developers to add new "Alexa Skills" to the product.

You can see the SDK documentation here: developer.amazon.com/public/solutions/alexa/alexa-skills-kit but in short, a developer can make a web service that allows a user to say: Alexa, ask [your service] to [some action your service provides]

Requirements

Amazon has a list of requirements to get a new Skill up and running

  1. Creating your new Skill on their Development Dashboard populating it with details and example phrases. That process is documented here: developer.amazon.com/appsandservices/solutions/alexa/alexa-skills-kit/docs/defining-the-voice-interface
  2. A lengthy request validation proces. Documented here: developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/developing-an-alexa-skill-as-a-web-service
  3. A formatted JSON response.
  4. SSL connection required, even for development.

How skillserver Helps

The go-alexa/skillserver takes care of #2 and #3 for you so you can concentrate on #1 and coding your app. (#4 is what it is. See the section on SSL below.)

An Example App

Creating an Alexa Skill web service is easy with go-alexa/skillserver. Simply import the project as any other Go project, define your app, and write your endpoint. All the web service, security checks, and assistance in creating the response objects are done for you.

Here's a simple, but complete web service example:

package main

import (
	alexa "github.com/mikeflynn/go-alexa/skillserver"
)

var Applications = map[string]interface{}{
	"/echo/helloworld": alexa.EchoApplication{ // Route
		AppID:    "xxxxxxxx", // Echo App ID from Amazon Dashboard
		OnIntent: EchoIntentHandler,
		OnLaunch: EchoIntentHandler,
	},
}

func main() {
	alexa.Run(Applications, "3000")
}

func EchoIntentHandler(echoReq *alexa.EchoRequest, echoResp *alexa.EchoResponse) {
	echoResp.OutputSpeech("Hello world from my new Echo test app!").Card("Hello World", "This is a test card.")
}

Details:

  • You define your endpoints by creating a map[string]interface{} and loading it with EchoApplication types that specify the Application ID and handler function.
  • All Skill endpoints must start with /echo/ as that's the route grouping that has the security middleware.
  • The easiest way to get started is define handler functions by using OnIntent, OnLaunch, or OnSessionEnded that take an EchoRequest and an EchoResponse.
  • ...but if you want full control you can still use the EchoApplication.Handler hook to write a regular net/http handler so you have full access to the request and ResponseWriter.
  • The JSON from the Echo request is already parsed for you. Grab it by calling skillserver.GetEchoRequest(r *http.Request).
  • You generate the Echo Response by using the EchoResponse struct that has methods to generate each part and that's it! ...unless you use the EchoApplication.Handler hook. In that case you need to write your JSON to the string with the EchoResponse.toString() method.

The SSL Requirement

Amazon requires an SSL connection for all steps in the Skill process, even local development (which still gets requests from the Echo web service). Amazon is pushing their AWS Lamda service that takes care of SSL for you, but Go isn't an option on Lamda. What I've done personally is put Nginx in front of my Go app and let Nginx handle the SSL (a self-signed cert for development and a real cert when pushing to production). More information here on nginx.com.

Contributors

Mike Flynn (@thatmikeflynn)

Documentation

Index

Constants

View Source
const (
	CanFulfillIntentAnswerYes   CanFulfillIntentAnswer = "YES"
	CanFulfillIntentAnswerNo                           = "NO"
	CanFulfillIntentAnswerMaybe                        = "MAYBE"
)

Variables

View Source
var Applications = map[string]interface{}{}

Functions

func HTTPError

func HTTPError(w http.ResponseWriter, logMsg string, err string, errCode int)

func Init

func Init(apps map[string]interface{}, router *mux.Router)

func IsValidAlexaRequest

func IsValidAlexaRequest(w http.ResponseWriter, r *http.Request) bool

IsValidAlexaRequest handles all the necessary steps to validate that an incoming http.Request has actually come from the Alexa service. If an error occurs during the validation process, an http.Error will be written to the provided http.ResponseWriter. The required steps for request validation can be found on this page: https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/developing-an-alexa-skill-as-a-web-service#hosting-a-custom-skill-as-a-web-service

func Run

func Run(apps map[string]interface{}, port string)

func RunSSL

func RunSSL(apps map[string]interface{}, port, cert, key string) error

Types

type AudioPlayerClearQueueBehavior

type AudioPlayerClearQueueBehavior string
const (
	ClearEnqueued AudioPlayerClearQueueBehavior = "CLEAR_ENQUEUED"
	ClearAll      AudioPlayerClearQueueBehavior = "CLEAR_ALL"
)

type AudioPlayerPlayBehavior

type AudioPlayerPlayBehavior string
const (
	ReplaceAll      AudioPlayerPlayBehavior = "REPLACE_ALL"
	Enqueue         AudioPlayerPlayBehavior = "ENQUEUE"
	ReplaceEnqueued AudioPlayerPlayBehavior = "REPLACE_ENQUEUED"
)

type CanFulfillIntentAnswer

type CanFulfillIntentAnswer string

type CanFulfillIntentPayload

type CanFulfillIntentPayload struct {
	CanFulfill CanFulfillIntentAnswer          `json:"canFulfill"`
	Slots      map[string]CanFulfillIntentSlot `json:"slots,omitempty"`
}

type CanFulfillIntentSlot

type CanFulfillIntentSlot struct {
	CanUnderstand CanFulfillIntentAnswer `json:"canUnderstand"`
	CanFulfill    CanFulfillIntentAnswer `json:"canFulfill"`
}

type Directive

type Directive map[string]interface{} // Shape differs wildly

type EchoApplication

type EchoApplication struct {
	AppID              string
	Handler            func(http.ResponseWriter, *http.Request)
	OnLaunch           func(*EchoRequest, *EchoResponse)
	OnIntent           func(*EchoRequest, *EchoResponse)
	OnSessionEnded     func(*EchoRequest, *EchoResponse)
	OnAudioPlayerState func(*EchoRequest, *EchoResponse)
}

type EchoContext

type EchoContext struct {
	System struct {
		ApiEndpoint    string `json:"apiEndpoint,omitempty"`
		ApiAccessToken string `json:"apiAccessToken,omitempty"`
		Device         struct {
			DeviceId string `json:"deviceId,omitempty"`
		} `json:"device,omitempty"`
		Application struct {
			ApplicationID string `json:"applicationId,omitempty"`
		} `json:"application,omitempty"`
		User struct {
			AccessToken string `json:"accessToken,omitempty"`
			UserId      string `json:"userId,omitempty"`
			Permissions struct {
				ConsentToken string `json:"consentToken,omitempty"`
			} `json:"permissions,omitempty"`
		} `json:"user,omitempty"`
	} `json:"System,omitempty"`
}

type EchoIntent

type EchoIntent struct {
	Name  string              `json:"name"`
	Slots map[string]EchoSlot `json:"slots"`
}

type EchoReprompt

type EchoReprompt struct {
	OutputSpeech EchoRespPayload `json:"outputSpeech,omitempty"`
}

type EchoReqBody

type EchoReqBody struct {
	Type      string            `json:"type"`
	RequestID string            `json:"requestId"`
	Timestamp string            `json:"timestamp"`
	Intent    EchoIntent        `json:"intent,omitempty"`
	Reason    string            `json:"reason,omitempty"`
	Message   map[string]string `json:"message"`
	Locale    string            `json:"locale"`
}

type EchoRequest

type EchoRequest struct {
	Version string      `json:"version"`
	Session EchoSession `json:"session"`
	Request EchoReqBody `json:"request"`
	Context EchoContext `json:"context"`
}

func GetEchoRequest

func GetEchoRequest(r *http.Request) *EchoRequest

func (*EchoRequest) AllSlots

func (this *EchoRequest) AllSlots() map[string]EchoSlot

func (*EchoRequest) GetIntentName

func (this *EchoRequest) GetIntentName() string

func (*EchoRequest) GetRequestType

func (this *EchoRequest) GetRequestType() string

func (*EchoRequest) GetSessionID

func (this *EchoRequest) GetSessionID() string

func (*EchoRequest) GetSlotValue

func (this *EchoRequest) GetSlotValue(slotName string) (string, error)

func (*EchoRequest) GetUserID

func (this *EchoRequest) GetUserID() string

func (*EchoRequest) VerifyAppID

func (this *EchoRequest) VerifyAppID(myAppID string) bool

func (*EchoRequest) VerifyTimestamp

func (this *EchoRequest) VerifyTimestamp() bool

Request Functions

type EchoRespBody

type EchoRespBody struct {
	OutputSpeech     *EchoRespPayload         `json:"outputSpeech,omitempty"`
	Card             *EchoRespPayload         `json:"card,omitempty"`
	Reprompt         *EchoReprompt            `json:"reprompt,omitempty"`         // Pointer so it's dropped if empty in JSON response.
	ShouldEndSession *bool                    `json:"shouldEndSession,omitempty"` // Same
	Directives       []Directive              `json:"directives,omitempty"`
	CanFulfillIntent *CanFulfillIntentPayload `json:"canFulfillIntent,omitempty"`
}

type EchoRespImage

type EchoRespImage struct {
	SmallImageURL string `json:"smallImageUrl,omitempty"`
	LargeImageURL string `json:"largeImageUrl,omitempty"`
}

type EchoRespPayload

type EchoRespPayload struct {
	Type    string        `json:"type,omitempty"`
	Title   string        `json:"title,omitempty"`
	Text    string        `json:"text,omitempty"`
	SSML    string        `json:"ssml,omitempty"`
	Content string        `json:"content,omitempty"`
	Image   EchoRespImage `json:"image,omitempty"`
}

type EchoResponse

type EchoResponse struct {
	Version           string                 `json:"version"`
	SessionAttributes map[string]interface{} `json:"sessionAttributes,omitempty"`
	Response          EchoRespBody           `json:"response"`
}

func NewEchoResponse

func NewEchoResponse() *EchoResponse

Response Functions

func (*EchoResponse) AudioPlayerClearQueue

func (this *EchoResponse) AudioPlayerClearQueue(clearBehavior AudioPlayerClearQueueBehavior) *EchoResponse

func (*EchoResponse) AudioPlayerPlay

func (this *EchoResponse) AudioPlayerPlay(
	behavior AudioPlayerPlayBehavior, streamUrl, token string, prevToken *string, offsetMs int,
) *EchoResponse

func (*EchoResponse) AudioPlayerStop

func (this *EchoResponse) AudioPlayerStop() *EchoResponse

func (*EchoResponse) Card

func (this *EchoResponse) Card(title string, content string) *EchoResponse

func (*EchoResponse) EndSession

func (this *EchoResponse) EndSession(flag bool) *EchoResponse

func (*EchoResponse) LinkAccountCard

func (this *EchoResponse) LinkAccountCard() *EchoResponse

func (*EchoResponse) OutputSpeech

func (this *EchoResponse) OutputSpeech(text string) *EchoResponse

func (*EchoResponse) OutputSpeechSSML

func (this *EchoResponse) OutputSpeechSSML(text string) *EchoResponse

func (*EchoResponse) Reprompt

func (this *EchoResponse) Reprompt(text string) *EchoResponse

func (*EchoResponse) RepromptSSML

func (this *EchoResponse) RepromptSSML(text string) *EchoResponse

func (*EchoResponse) SimpleCard

func (this *EchoResponse) SimpleCard(title string, content string) *EchoResponse

func (*EchoResponse) StandardCard

func (this *EchoResponse) StandardCard(title string, content string, smallImg string, largeImg string) *EchoResponse

func (*EchoResponse) String

func (this *EchoResponse) String() ([]byte, error)

func (*EchoResponse) VideoAppLaunch

func (this *EchoResponse) VideoAppLaunch(
	streamUrl, title, subtitle string,
) *EchoResponse

type EchoSession

type EchoSession struct {
	New         bool   `json:"new"`
	SessionID   string `json:"sessionId"`
	Application struct {
		ApplicationID string `json:"applicationId"`
	} `json:"application"`
	Attributes map[string]interface{} `json:"attributes"`
	User       struct {
		UserID      string `json:"userId"`
		AccessToken string `json:"accessToken,omitempty"`
	} `json:"user"`
}

type EchoSlot

type EchoSlot struct {
	Name        string               `json:"name"`
	Value       string               `json:"value"`
	Resolutions *EchoSlotResolutions `json:"resolutions,omitempty"`
}

type EchoSlotAuthority

type EchoSlotAuthority struct {
	Authority string                             `json:"authority"`
	Values    []EchoSlotAuthorityValueCollection `json:"values,omitempty"`
}

type EchoSlotAuthorityValue

type EchoSlotAuthorityValue struct {
	Id   string `json:"id"`
	Name string `json:"name"`
}

type EchoSlotAuthorityValueCollection

type EchoSlotAuthorityValueCollection struct {
	Value *EchoSlotAuthorityValue `json:"value,omitempty"`
}

type EchoSlotResolutions

type EchoSlotResolutions struct {
	ResolutionsPerAuthority []EchoSlotAuthority `json:"resolutionsPerAuthority,omitempty"`
}

type SSMLTextBuilder

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

func NewSSMLTextBuilder

func NewSSMLTextBuilder() *SSMLTextBuilder

func (*SSMLTextBuilder) AppendAmazonEffect

func (builder *SSMLTextBuilder) AppendAmazonEffect(text, name string) *SSMLTextBuilder

func (*SSMLTextBuilder) AppendAudio

func (builder *SSMLTextBuilder) AppendAudio(src string) *SSMLTextBuilder

func (*SSMLTextBuilder) AppendBreak

func (builder *SSMLTextBuilder) AppendBreak(strength, time string) *SSMLTextBuilder

func (*SSMLTextBuilder) AppendEmphasis

func (builder *SSMLTextBuilder) AppendEmphasis(text, level string) *SSMLTextBuilder

func (*SSMLTextBuilder) AppendParagraph

func (builder *SSMLTextBuilder) AppendParagraph(text string) *SSMLTextBuilder

func (*SSMLTextBuilder) AppendPlainSpeech

func (builder *SSMLTextBuilder) AppendPlainSpeech(text string) *SSMLTextBuilder

func (*SSMLTextBuilder) AppendProsody

func (builder *SSMLTextBuilder) AppendProsody(text, rate, pitch, volume string) *SSMLTextBuilder

func (*SSMLTextBuilder) AppendSentence

func (builder *SSMLTextBuilder) AppendSentence(text string) *SSMLTextBuilder

func (*SSMLTextBuilder) AppendSubstitution

func (builder *SSMLTextBuilder) AppendSubstitution(text, alias string) *SSMLTextBuilder

func (*SSMLTextBuilder) Build

func (builder *SSMLTextBuilder) Build() string

type StdApplication

type StdApplication struct {
	Methods string
	Handler func(http.ResponseWriter, *http.Request)
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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