/
VoxaDocumentationRelease210RainAgencyMar222017 VoxaDocumentationRelease210RainAgencyMar222017

VoxaDocumentationRelease210RainAgencyMar222017 - PDF document

melanie
melanie . @melanie
Follow
343 views
Uploaded On 2021-08-23

VoxaDocumentationRelease210RainAgencyMar222017 - PPT Presentation

Contents1Installation12InitialCon2guration33Respondingtoalexaevents54Usingthedevelopmentserver75Respondingtoanintentevent96ProjectSamples1161StarterKit1162MyFirstPodcast1163AccountLinking117Links1371M ID: 869687

149 alexaevent skill voxa alexaevent 149 voxa skill voxadocumentation release2 x0028fe00 reply return index callback env json 150 model

Share:

Link:

Embed:

Download Presentation from below link

Download Pdf The PPT/PDF document "VoxaDocumentationRelease210RainAgencyMar..." is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.


Presentation Transcript

1 VoxaDocumentationRelease2.1.0RainAgencyM
VoxaDocumentationRelease2.1.0RainAgencyMar22,2017 Contents: 1Installation12InitialConguration33Respondingtoalexaevents54Usingthedevelopmentserver75Respondingtoanintentevent96ProjectSamples116.1StarterKit................................................116.2MyFirstPodcast.............................................116.3AccountLinking.............................................117Links137.1Models..................................................137.2ViewsandVariables...........................................147.3Controllers................................................157.4Transition.................................................167.5ThealexaEventObject........................................167.6ThereplyObject............................................177.7Voxa...................................................177.8RequestFlow...............................................227.9I18N.........

2 ........................................
..........................................237.10Plugins..................................................257.11Debugging................................................277.12StarterKit................................................287.13MyFirstPodcast.............................................307.14AccountLinking.............................................34 i ii CHAPTER1 Installation Voxaisdistributedvianpm $npminstallvoxa--save 1 VoxaDocumentation,Release2.1.0 2Chapter1.Installation CHAPTER2 InitialConguration InstantiatingaStateMachineSkillrequiresacongurationspecifyingyourViewsandVariables. usestrict;constVoxa=require(voxa);constviews=require(./views):constvariables=require(./variables);constskill=newVoxa({variables,views}); 3 VoxaDocumentation,Release2.1.0 4Chapter2.InitialConguration CHAPTER3 Respondingtoalexaevents Onceyouhaveyourskillcon

3 guredrespondingtoeventsisassimpleasc
guredrespondingtoeventsisassimpleascallingtheskill.lambdamethod constskill=require(./MainStateMachine);exports.handler=skill.lambda(); 5 VoxaDocumentation,Release2.1.0 6Chapter3.Respondingtoalexaevents CHAPTER4 Usingthedevelopmentserver Theframeworkprovidesasimplebuiltinserverthat'sconguredtoserveallPOSTrequeststoyourskill,thisworksgreatwhendeveloping,speciallywhenpairedwithngrok //thiswillstartanhttpserverlisteningonport3000skill.startServer(3000); 7 VoxaDocumentation,Release2.1.0 8Chapter4.Usingthedevelopmentserver CHAPTER5 Respondingtoanintentevent skill.onIntent(HelpIntent,(alexaEvent)�={return{reply:HelpIntent.HelpAboutSkill};});skill.onIntent(ExitIntent,(alexaEvent)�={return{reply:ExitIntent.Farewell};}); 9 VoxaDocumentation,Release2.1.0 10Chapter5.Respondingtoanintentevent CHAPTER6 ProjectSamples Tohelpyougetstarte

4 dthestatemachinehasanumberofexampleproje
dthestatemachinehasanumberofexampleprojectsyoucanuse.StarterKitThisisthesimplestproject,itdenesthedefaultdirectorystructurewerecommendusingwithvoxaprojectsandhasanexampleserverless.ymllethatcanbeusedtodeployyourskilltoalambdafunction.MyFirstPodcastInthisexampleyouwillseehowtoimplementapodcastskillbyhavingalistofaudiosinale(podcast.js)withtitlesandurls.ItimplementsallaudiointentsallowedbytheaudiobackgroundfeatureandhandlesalltheplaybackrequestsdispatchedbyAlexaonceanaudiohasstarted,stopped,failed,nishedornearlytonish.Keepinmindtheaudiosmustbehostedinasecureserver.AccountLinkingAmorecomplexprojectthatshowshowtoworkwithaccountlinkingandmakeresponsesusingthemodelstate.Itusesserverlesstodeployyouraccountlinkingserverandskilltolambda,createadynamodbtabletostoreyouraccountlinkingandcreateans3buckettostoreyourstaticassets.ItalsohasagulptasktouploadyourassetstoS3 11 VoxaDocumentation,Relea

5 se2.1.0 12Chapter6.ProjectSamples CHAPTE
se2.1.0 12Chapter6.ProjectSamples CHAPTER7 Links •searchModelsModelsarethedatastructurethatholdsthecurrentstateofyourapplication,theframeworkdoesn'tmakemanyassumptionsonitandonlyrequireshaveafromEventmethodthatshouldinitializeitbasedonthealexaEventsessionattributesandaserializemethodthatshouldreturnJSON.stringifyablestructuretothenstoreinthesessionattributes usestrict;const_=require(lodash);classModel{constructor(data){_.assign(this,data);}staticfromEvent(alexaEvent){returnnewthis(alexaEvent.session.attributes.modelData);}serialize(){returnthis;}}module.exports=Model; 13 VoxaDocumentation,Release2.1.0 ViewsandVariablesViewsViewsaretheVoxawayofhandlingrepliestotheuser,they'retemplatesofresponsesthatcanhaveacontextasdenedbyyourvariablesandModelThereare5responsesinthefollowingsnippet:LaunchIntent.OpenResponse,ExitIntent.Farewell,HelpIntent.HelpAboutSkill,Count.SayandCount.te

6 ll constviews={LaunchIntent:{OpenRespons
ll constviews={LaunchIntent:{OpenResponse:{tell:Hello!Good{time}},},ExitIntent:{Farewell:{tell:Ok.Formoreinfovisit{site}site.},},HelpIntent:{HelpAboutSkill:{tell:Formorehelpvisitwww.rain.agency},},Count:{Say:{say:{count}},Tell:{tell:{count}},},}; VariablesVariablesaretherenderingenginewayofaddinglogicintoyourviews.They'redessignedtobeverysimplesincemostofyourlogicshouldbeinyourmodelorcontrollers.Avariablesignatureis:variable(model,alexaEvent)Arguments•model–Theinstanceofyourmodelforthecurrentalexaevent.•AlexaEvent–Thecurrentalexaevent.ReturnsThevaluetoberenderedorapromiseresolvingtoavaluetoberenderedintheview. constvariables={site:functionsite(model){returnPromise.resolve(example.com);},count:functioncount(model){returnmodel.count;},locale:functionlocale(model,alexaEvent){returnalexaEvent.locale;}}; 14Chapter7.Links VoxaD

7 ocumentation,Release2.1.0 ControllersCon
ocumentation,Release2.1.0 ControllersControllersinyourapplicationcontrolthelogicofyourskill,theyrespondtoalexaalexaEvents,externalresources,manipulatetheinputandgiveproperresponsesusingyourModel,ViewsandVariables.Statescomeinoneoftwoways,theycanbeanobjectofmappingsfromintentnametostate. skill.onState(entry,{LaunchIntent:launch,AMAZON.HelpIntent:help,}); OrtheycanbeafunctionthatgetsaalexaEventobject. skill.onState(launch,(alexaEvent)�={return{reply:LaunchIntent.OpenResponse,to:die};}); Yourstateshouldrespondwithatransition.Thetransitionisaplainobjectthatcantakedirectives,toandreplykeys.TheentrycontrollerTheentrycontrollerisspecialinthatit'sthedefaultstatetogotoatthebeginningofyoursessionandifyourstatereturnsnoresponse.Forexampleinthenextsnippedthere'sawaitingstatethatexpectsanAMAZON.NextIntentoranAMAZON.PreviousIntent,int

8 hecasetheuserssayssomethingunexpectedlik
hecasetheuserssayssomethingunexpectedlikeanAMAZON.HelpIntentthestatereturnsundened,theStateMachineframeworkhandlesthissituationsbyredirectingtotheentrystate skill.onState(waiting,(alexaEvent)�={if(alexaEvent.intent.name===AMAZON.NextIntent){alexaEvent.model.index+=1;return{reply:Ingredients.Describe,to:waiting}}elseif(alexaEvent.intent.name===AMAZON.PreviousIntent){alexaEvent.model.index-=1;return{reply:Ingredients.Describe,to:waiting}}}); TheonIntenthelperForthesimplepatternofhavingacontrollerrespondtoanspecicintenttheframeworkprovidestheonIntenthelper skill.onIntent(LaunchIntent,(alexaEvent)�={return{reply:LaunchIntent.OpenResponse,to:die};}); Underthehoodthiscreatesanewkeyintheentrycontrollerandanewstate 7.3.Controllers15 VoxaDocumentation,Release2.1.0 TransitionAtransi

9 tionistheresultofcontrollerexecution,it'
tionistheresultofcontrollerexecution,it'ssimpleobjectwithsomekeysthatcontroltheowofexecutioninyourskill.toThetokeyshouldbethenameofstateinyourstatemachine,whenpresentitindicatestotheframeworkthatitshouldmovetoanewstate.Ifabsentit'sassumedthattheframeworkshouldmovetothediestate. return{to:stateName}; directivesDirectivesareusedpasseddirectlytothealexaresponse,theformatisdescribedinthealexadocumentation return{directives:{type:AudioPlayer.Play,playBehavior:REPLACE_ALL,url:lesson.Url,offsetInMilliseconds:0,},}; replyThereplykeycantake2forms,asimplestringpointingtooneofyourviewsoraReplyobject. return{reply:LaunchIntent.OpenResponse};constreply=newReply(alexaEvent,{tell:Hithere!});return{reply}; ThealexaEventObjectclassAlexaEvent(event,lambdaContext)ThealexaEventobjectcontainsalltheinformationfromtheAlexaevent,it'sanobjectkeptfortheentirelifecycleofthe

10 statemachinetransitionsandassuchisaperfe
statemachinetransitionsandassuchisaperfectplaceformiddlewaretoputinformationthatshouldbeavailableoneveryrequest.AlexaEvent.modelThedefaultmiddlewareinstantiatesaModelandmakesitavailablethroughalexaEvent.modelAlexaEvent.intent.paramsThealexaEventobjectmakesintent.slotsavailablethroughintent.paramsafteraplyingasim-pletransformationso{slots:[{name:Dish,value:FriedChicken}]}becomes{Dish:FriedChicken}AlexaEvent.userAconveniencegettertoobtaintheuserfromsesssion.userorcontext.System.user 16Chapter7.Links VoxaDocumentation,Release2.1.0 ThereplyObjectclassReply(alexaEvent[,message])ThereplyobjectisusedbytheframeworktorenderAlexaresponses,ittakesallofyourstatements,cardsanddirectivesandgeneratesaproperjsonresponseforAlexaArguments•alexaEvent(AlexaEvent)–•message–AmessageobjectReply.append(message)AddsstatementstotheReplyArguments•message–Anobjectwithk

11 eysask,tell,say,reprompt,cardordirective
eysask,tell,say,reprompt,cardordirectiveskeys.OranotherreplyobjectReturnstheReplyobjectReply.toJSON()ReturnsAnobjectwiththeproperformattosendbacktoAlexa,withstatementswrappedinSSMLtags,cards,repromptsanddirectivesVoxaclassVoxa(cong)Arguments•config–Congurationforyourskill,itshouldincludeViewsandVariablesandoptionallyamodelandalistofappIds.IfappIdsispresentthentheframeworkwillcheckeveryalexaeventandenforcetheapplicationidtomatchoneofthespeciedapplicationids. constskill=newVoxa({Model,variables,views,appIds}); Voxa.lambda()ReturnsAlambdahandlerthatwillcallyourskill.executemethod exports.handler=skill.lambda(); Voxa.execute(event)ThemainentrypointfortheSkillexecutionArguments•event–Theeventsentbyalexa.•context–ThecontextofthelambdafunctionReturnsPromiseAresponseresolvingtoajavascriptobjecttobesentasaresulttoAlexa. skill.execute(event,context).then(resultʏ

12 E00;=callback(null,result)).catch(callba
E00;=callback(null,result)).catch(callback); 7.6.ThereplyObject17 VoxaDocumentation,Release2.1.0 Voxa.onState(stateName,handler)MapsahandlertoastateArguments•stateName(string)–Thenameofthestate•handler(function/object)–ThecontrollertohandlethestateReturnsAnobjectorapromisethatresolvestoanobjectthatspeciesatransitiontoanotherstateand/oraviewtorender skill.onState(entry,{LaunchIntent:launch,AMAZON.HelpIntent:help,});skill.onState(launch,(alexaEvent)�={return{reply:LaunchIntent.OpenResponse,to:die};}); Voxa.onIntent(intentName,handler)AshortcutfordeniningstatecontrollersthatmapdirectlytoanintentArguments•intentName(string)–Thenameoftheintent•handler(function/object)–ThecontrollertohandlethestateReturnsAnobjectorapromisethatresolvestoanobjectthatspeciesatransitiontoanothers

13 tateand/oraviewtorender skill.onIntent(&
tateand/oraviewtorender skill.onIntent(HelpIntent,(alexaEvent)�={return{reply:HelpIntent.HelpAboutSkill};}); Voxa.onIntentRequest(callback[,atLast])ThisisexecutedforallIntentRequestevents,defaultbehavioristoexecutetheStateMachinemachinery,yougenerallydon'tneedtooverridethis.Arguments•callback(function)–•last(bool)–ReturnsPromiseVoxa.onLaunchRequest(callback[,atLast])AddsacallbacktobeexecutedwhenprocessingaLaunchRequest,thedefaultbehavioristofakethealexaeventasanIntentRequestwithaLaunchIntentandjustdefertotheonIntentRequesthandlers.Yougenerallydon'tneedtooverridethis.Voxa.onBeforeStateChanged(callback[,atLast])Thisisexecutedbeforeenteringeverystate,itcanbeusedtotrackstatechangesormakechangestothealexaeventobjectVoxa.onBeforeReplySent(callback[,atLast])Addsacallbacktobeexecutedjustbeforesendingthereply,internallythisisusedtoaddtheserializedmodelandnext

14 statetothesession.Itcanbeusedtoalterther
statetothesession.Itcanbeusedtoalterthereply,orforexampletotrackthenalresponsesenttoauserinanalytics. 18Chapter7.Links VoxaDocumentation,Release2.1.0 skill.onBeforeReplySent((alexaEvent,reply)�={constrendered=reply.write();analytics.track(alexaEvent,rendered)}); Voxa.onAfterStateChanged(callback[,atLast])Addscallbackstobeexecutedontheresultofastatetransition,thisarecalledaftereverytransitionandinternallyit'susedtorenderthetransitionreplyusingtheviewsandvariablesThecallbacksgetalexaEvent,replyandtransitionparams,itshouldreturnthetransitionobject skill.onAfterStateChanged((alexaEvent,reply,transition)�={if(transition.reply===LaunchIntent.PlayTodayLesson){transition.reply=_.sample([LaunchIntent.PlayTodayLesson1,LaunchIntent.,!PlayTodayLesson2]);}returntransition;}); Voxa.onUnhandledState(callback[,atLast])Addsacallbacktobeexecutedwhenastatetransiti

15 onfailstogeneratearesult,thisusuallyhapp
onfailstogeneratearesult,thisusuallyhappenswhenredirectingtoamissingstateoranentrycallforanonconguredintent,thehandlersgetaalexaeventparameterandshouldreturnatransitionthesameasastatecontrollerwould.Voxa.onSessionStarted(callback[,atLast])AddsacallbacktotheonSessinStartedevent,thisexecutesforalleventswherealexaEvent.session.new===trueThiscanbeusefultotrackanalytics skill.onSessionStarted((alexaEvent,reply)�={analytics.trackSessionStarted(alexaEvent);}); Voxa.onRequestStarted(callback[,atLast])Addsacallbacktobeexecutedwheneverthere'saLaunchRequest,IntentRequestoraSessionEndedRequest,thiscanbeusedtoinitializeyouranalyticsorgetyouraccountlinkinguserdata.Internallyit'susedtoinitializethemodelbasedontheeventsession skill.onRequestStarted((alexaEvent,reply)�={alexaEvent.model=this.config.Model.fromEvent(alexaEvent);}); Voxa.onSessionEnded(callback[,atLast])AddsacallbacktotheonSess

16 ionEndedevent,thisiscalledforeverySessio
ionEndedevent,thisiscalledforeverySessionEndedRequestorwhentheskillreturnsatransitiontoastatewhereisTerminal===true,normallythisisatransitiontothediestate.YouwouldnormallyusethistotrackanalyticsVoxa.onSystem.ExceptionEncountered(callback[,atLast])ThishandlesSystem.ExceptionEncounteredeventthataresenttoyourskillwhenaresponsetoanAudioPlayereventcausesanerror returnPromise.reduce(errorHandlers,(result,errorHandler)�={if(result){returnresult;} 7.7.Voxa19 VoxaDocumentation,Release2.1.0 returnPromise.resolve(errorHandler(alexaEvent,error));},null); ErrorhandlersYoucanregistermanyerrorhandlerstobeusedforthedifferentkindoferrorstheapplicationcouldgenerate.Theyallfollowthesamelogicwhereifthersterrortypeisnothandledthenthedefaultistobedeferredtothemoregeneralerrorhandlerthatultimatelyjustreturnsadefaulterrorreply.They'reexecutedsequentiallyandwillstopwhenthersthandlerreturnsareply.Voxa.onSta

17 teMachineError(callback[,atLast])Thishan
teMachineError(callback[,atLast])ThishandlerwillcatchallerrorsgeneratedwhentryingtomaketransitionsinthestateMachine,thiscouldincludeerrorsinthestatemachinecontrollers,,thehandlersget(alexaEvent,reply,error)param-eters skill.onStateMachineError((alexaEvent,reply,error)�={//itgetsthecurrentreply,whichcouldbeincompleteduetoanerror.returnnewReply(alexaEvent,{tell:Anerrorinthecontrollerscode}).write();}); Voxa.onError(callback[,atLast])Thisisthemoregeneralhandlerandwillcatchallunhandlederrorsintheframework,itgets(alexaEvent,error)parametersasarguments skill.onError((alexaEvent,error)�={returnnewReply(alexaEvent,{tell:Anunrecoverableerroroccurred.}).write();}); PlaybackControllerhandlersHandleeventsfromtheAudioPlayerinterfaceaudioPlayerCallback(alexaEvent,reply)AllaudioplayermiddlewarecallbacksgetaalexaeventandareplyobjectArguments•alexaEvent(AlexaEvent)–

18 ThealexaeventsentbyAlexa•reply(obje
ThealexaeventsentbyAlexa•reply(object)–AreplytobesentasaresponseReturnsobjectwriteYouralexaeventhandlershouldreturnanappropriateresponseaccordingtotheeventtype,thisgenerallymeansappendingtothereplyobjectInthefollowingexamplethealexaeventhandlerreturnsaREPLACE_ENQUEUEDdirectivetoaPlaybackNearlyFinished()event. skill[onAudioPlayer.PlaybackNearlyFinished]((alexaEvent,reply)�={constdirectives={type:AudioPlayer.Play,playBehavior:REPLACE_ENQUEUED,token:"",url:https://www.dl-sounds.com/wp-content/uploads/edd/2016/09/Classical-Bed3-,!preview.mp3, 20Chapter7.Links VoxaDocumentation,Release2.1.0 offsetInMilliseconds:0,};returnreply.append({directives});}); Voxa.onAudioPlayer.PlaybackStarted(callback[,atLast])Voxa.onAudioPlayer.PlaybackFinished(callback[,atLast])Voxa.onAudioPlayer.PlaybackStopped(callback[,atLast])Voxa.onAudioPlayer.PlaybackFailed(cal

19 lback[,atLast])Voxa.onAudioPlayer.Playba
lback[,atLast])Voxa.onAudioPlayer.PlaybackNearlyFinished(callback[,atLast])Voxa.onPlaybackController.NextCommandIssued(callback[,atLast])Voxa.onPlaybackController.PauseCommandIssued(callback[,atLast])Voxa.onPlaybackController.PlayCommandIssued(callback[,atLast])Voxa.onPlaybackController.PreviousCommandIssued(callback[,atLast]) 7.7.Voxa21 VoxaDocumentation,Release2.1.0 RequestFlow 22Chapter7.Links VoxaDocumentation,Release2.1.0 I18NInternationalizationsupportisdoneusingthei18nextlibrary,thesametheAmazonAlexaNodeSDKuses.ConguringtheskillforI18NTouseityouneedtocongureyourskilltousetheI18NRendererclassinsteadofthedefaultrendererclass. constVoxa=require(voxa);constskill=newVoxa({Model,variables,views,RenderClass:Voxa.I18NRenderer}); TheframeworktakescareofselectingthecorrectlocaleoneveryalexaeventbylookingatthealexaEvent.request.localeproperty.ChangesinyourviewsTheotherchangeyouwillneedi

20 stodeneyourviewsusingthei18nexttrans
stodeneyourviewsusingthei18nexttranslateformat: usestrict;constviews=(functionviews(){return{en-us:{translation:{LaunchIntent:{OpenResponse:{tell:Hello!Good{time}},},Question:{Ask:{ask:Whattimeisit?},},ExitIntent:{Farewell:{tell:Ok.Formoreinfovisit{site}site.},},Number:{One:{tell:{numberOne}},},},},de-de:{translation:{LaunchIntent:{OpenResponse:{tell:Hallo!guten{time}},},Question:{Ask:{ask:wiespätistes?},},ExitIntent:{Farewell:{tell:OkfürweitereInfosbesuchen{site}Website},},Number:{One:{tell:{numberOne}},},},},}; 7.9.I18N23 VoxaDocumentation,Release2.1.0 }());module.exports=views; VariablesVariablesshouldworkmostlythesameaswiththeDefaultRenderer,withtheexceptionthatvariableswillnowgetalocalekey usestrict;/***Variablesfortests**Copyright(c)2016RainAgency.*LicensedundertheMITlic

21 ense.*/constPromise=require(bluebir
ense.*/constPromise=require(bluebird);constvariables={time:functiontime(){consttoday=newDate();constcurHr=today.getHours();if(curHr12){returnPromise.resolve(Morning);}if(curHr18){returnPromise.resolve(Afternoon);}returnPromise.resolve(Evening);},site:functionsite(){returnPromise.resolve(example.com);},count:functioncount(model){returnmodel.count;},numberOne:functionnumberOne(model,request){if(request.request.locale===en-us){returnone;}elseif(request.request.locale===de-de){returnein;}return1;},};module.exports=variables; 24Chapter7.Links VoxaDocumentation,Release2.1.0 PluginsPluginsallowyoutomodifyhowtheStateMachineSkillhandlesanalexaevent.Whenapluginisregistereditwillusethedifferenthookpointsinyourskilltoaddfunctionality.Ifyouhaveseveralskillswithsimilarbehaviorthenyouransweristocreateaplugin.UsingapluginAfteri

22 nstatiatingaStateMachineSkillyoucanregis
nstatiatingaStateMachineSkillyoucanregisterpluginsonit.BuiltinpluginscanbeaccessedthroughVoxa.plugins usestrict;constVoxa=require(voxa);constModel=require(./model);constviews=require(./views):constvariables=require(./variables);constskill=newVoxa({Model,variables,views});Voxa.plugins.replaceIntent(skill); StateFlowpluginStoresthestatetransitionsforeveryalexaeventinanarray.stateFlow(skill)StateFlowattachescallbackstoonRequestStarted(),onBeforeStateChanged()andonBeforeReplySent()totrackstatetransitionsinaalexaEvent.flowarrayArguments•skill(Voxa)–TheskillobjectUsage constalexa=require(alexa-statemachine);alexa.plugins.stateFlow.register(skill)skill.onBeforeReplySent((alexaEvent)�={console.log(alexaEvent.flow.join(�));//entry�firstState�secondState�die}); Replaceintentplu

23 ginItallowsyoutorenameanintentnamebasedo
ginItallowsyoutorenameanintentnamebasedonaregularexpression.Bydefaultitwillmatch/(.*)OnlyIntent$/andreplaceitwith$1Intent.replaceIntent(skill[,cong])ReplaceIntentpluginusesonIntentRequest()tomodifytheincommingrequestintentnameArguments•skill(Voxa)–ThestateMachineSkill 7.10.Plugins25 VoxaDocumentation,Release2.1.0 •config–Anobjectwiththeregextolookforandthereplacevalue.Usage constskill=newVoxa({Model,variables,views});Voxa.plugins.replaceIntent(skill,{regex:/(.*)OnlyIntent$/,replace:$1Intent});Voxa.plugins.replaceIntent(skill,{regex:/^VeryLong(.*)/,replace:Long$1}); WhyonlyIntents?Agoodpracticeistoisolateanutteranceintoanotherintentifitcontainsasingleslot.Bycreatingtheonlyintent,alexawillprioritizethisintentiftheusersaysonlytheslot.Let'sexplainwiththefollowingscenario.Youneedtheusertoprovideazipcode.soyoushouldhaveanintentcalledZipCodeIntent.Butyoustillhavet

24 omanageiftheuseronlysaysitszipcodewithno
omanageiftheuseronlysaysitszipcodewithnootherwordsonit.Sothat'swhenwecreateanOnlyIntent.Let'scalledZipCodeOnlyIntent.Ourutterancelewillbelikethis: ZipCodeIntenthereismy{ZipCodeSlot}ZipCodeIntentmyzipis{ZipCodeSlot}...ZipCodeOnlyIntent{ZipCodeSlot} Butnowwehavetwostateswhicharebasicallythesame.ReplaceintentpluginwillrenameallincomingrequestsintentsfromZipCodeOnlyIntenttoZipCodeIntent.CloudwatchpluginItlogsaCloudWatchmetricwhentheskillcatchesanerrororsuccessexecution.Paramscloudwatch(skill,cloudwatch[,eventMetric])CloudwatchpluginusesVoxa.onError(),Voxa.onStateMachineError()andVoxa.onBeforeReplySent()tologmetricsArguments•skill(Voxa)–ThestateMachineSkill•cloudwatch–AnewAWS.CloudWatchobject.•putMetricDataParams–ParamsforputMetricDataUsage constAWS=require(aws-sdk);constskill=newVoxa({Model,variables,views});constcloudWatch=newAWS.CloudWatch({}); 26Chapter7.Lin

25 ks VoxaDocumentation,Release2.1.0 conste
ks VoxaDocumentation,Release2.1.0 consteventMetric={MetricName:CaughtError,//NameofyourmetricNamespace:SkillName//Nameofyourskill};Voxa.plugins.cloudwatch(skill,cloudWatch,eventMetric); AutoloadpluginItacceptsanadaptertoautoloadinfointothemodelobjectcomingineveryalexarequest.ParamsautoLoad(skill[,cong])Autoloadpluginusesskill.onSessionStartedtoloaddatathersttimeuseropenaskillArguments•skill(Voxa)–ThestateMachineSkill.•config–AnobjectwithanadapterkeywithagetPromisemethodinwhichyoucanhandleyourdatabaseaccesstofetchinformationfromanyresource.Usage constskill=newVoxa({Model,variables,views});Voxa.plugins.autoLoad(skill,{adapter}); DebuggingVoxausesthedebugmoduleinternallytologanumberofdifferentinternalevents,ifyouwanthavealookatthoseeventsyouhavetodeclarethefollowingenvironmentvariableDEBUG=voxaThisisanexampleofthelogoutput voxaReceivednewevent:{"version":"

26 1.0","session":{"new":true,"sessionId":,
1.0","session":{"new":true,"sessionId":,!"SessionId.09162f2a-cf8f-414f-92e6-1e3616ecaa05","application":{"applicationId":,!"amzn1.ask.skill.1fe77997-14db-409b-926c-0d8c161e5376"},"attributes":{},"user":{,!"userId":"amzn1.ask.account.","accessToken":""}},"request":{"type":"LaunchRequest",,!"requestId":"EdwRequestId.0f7b488d-c198-4374-9fb5-6c2034a5c883","timestamp":"2017-,!01-25T23:01:15Z","locale":"en-US"}}+0msvoxaInitializedmodellike{}+8msvoxaStartingthestatemachinefromentrystate+2svoxaRunningsimpleTransitionforentry+1msvoxaRunningonAfterStateChangeCallbacks+0msvoxaentrytransitionresultedin{"to":"launch"}+0msvoxaRunninglaunchenterfunction+1msvoxaRunningonAfterStateChangeCallbacks+0msvoxalaunchtransitionresultedin{"reply":"Intent.Launch","to":"entry","message":{,!"tell":"Welcomemail@example.com!"},"session":{"data":{},"reply":null}}+7ms 7.11.Debugging27 VoxaDocumentation,Release2.1.0 StarterKitThispro

27 jectisdesignedtobeasimpletemplateforyour
jectisdesignedtobeasimpletemplateforyournewskills.Withsomewellthoughtdefaultsthathaveprovenusefulwhendevelopingreallifeskills.DirectoryStructureIthasthefollowingdirectorystructure .-README.md-config|-env.js|-index.js|-local.json.example|-production.json|-staging.json-gulpfile.js-package.json-serverless.yml-services-skill|-MainStateMachine.js|-index.js|-variables.js|-views.js-speechAssets|-IntentSchema.json|-SampleUtterances.txt|-customSlotTypes-test-server.js congBydefaultyourskillwillhavethefollowingenvironments:•local•staging•productionWhatenvironmentyou'reisdeterminedintheconfig/env.jsmoduleusingthefollowingcode: usestrict;functiongetEnv(){if(process.env.NODE_ENV)returnprocess.env.NODE_ENV;if(process.env.AWS_LAMBDA_FUNCTION_NAME){//TODOputyourownlambdafunctionnamehereif(process.env.AWS_LAMBDA_FUNCTION_NAME===)returnproduction;returnstaging

28 ; 28Chapter7.Links VoxaDocumentation,Rel
; 28Chapter7.Links VoxaDocumentation,Release2.1.0 }returnlocal;}module.exports=getEnv(); skillThisiswhereyourcodetohandlealexaeventsgoes,youwillusuallyhaveaStateMachinedenition,thiswillincludestates,middlewareandaModel,ViewsandVariablesspeechAssetsThisshouldbeaversioncontrolledcopyofyourintentschema,sampleutterrancesandcustomslots.server.jsAnhttpserverforyourskillconguredtolistenonport3000,thisshouldbeusedfordevelopmentonly.servicesJustacommonplacetoputmodelsandlibrariestestYouwritetestsright?gulpleAgulprunnerconguredwithawatchtaskthatstartsyourexpressserverandlistensforchangestoreloadyourapplication.serverless.ymlTheserverlessframeworkisatoolthathelpsyoumanageyourlambdaapplications,assumingyouhaveyourAWScredentialssetupproperlythisstarterkitdenestheveryminimumneededsoyoucandeployyourskilltolambdawiththefollowingcommand: $slsdeploy Runningtheproject1.Clonethevoxareposito

29 ry2.Createanewskillprojectusingthesample
ry2.Createanewskillprojectusingthesamples/starterKitdirectoryasabasis3.Makesureyou'rerunningnode4.3,thisiseasiestwithnvm 7.12.StarterKit29 VoxaDocumentation,Release2.1.0 4.Createaconfig/local.jsonleusingconfig/local.json.exampleasanexample5.Runtheprojectwithgulpwatch6.Atthispointyoushouldstartngrokhttp3000andcongureyourskillintheAmazonDeveloperpaneltousethengrokhttpsendpoint.MyFirstPodcastThisprojectwillhelpyoubuildapodcastskillusingtheAudiodirectivestemplate.Youwillbeabletomanageloop,shuferequestsaswellasoffertheuserthepossibilitytostartanaudioover,pause,stopitorplaythenextorpreviousaudiofromapodcastlist.DirectoryStructureIthasthefollowingdirectorystructure .-README.md-config|-env.js|-index.js|-local.json.example|-production.json|-staging.json-gulpfile.js-package.json-serverless.yml-services-skill|-data||-podcast.js|-MainStateMachine.js|-index.js|-states.js|-variables.js|-views.js-speech

30 Assets|-IntentSchema.json|-SampleUtteran
Assets|-IntentSchema.json|-SampleUtterances.txt|-customSlotTypes-test-server.js congBydefaultyourskillwillhavethefollowingenvironments:•local•staging•productionWhatenvironmentyou'reisdeterminedintheconfig/env.jsmoduleusingthefollowingcode: 30Chapter7.Links VoxaDocumentation,Release2.1.0 usestrict;functiongetEnv(){if(process.env.NODE_ENV)returnprocess.env.NODE_ENV;if(process.env.AWS_LAMBDA_FUNCTION_NAME){//TODOputyourownlambdafunctionnamehereif(process.env.AWS_LAMBDA_FUNCTION_NAME===)returnproduction;returnstaging;}returnlocal;}module.exports=getEnv(); skillindex.jsFirstleinvokedbythelambdafunction,itinitializesthestatemachine.Youdon'tneedtomodifythisle.MainStateMachine.jsStatemachineisinitializedwithyourmodel,viewsandvariables.Theclassstates.jswillbeinchargetohandleallintentsandeventscomingfromAlexa.Youdon'tneedtomodifythis&

31 #2;le.states.jsAlleventsandintentsdispat
#2;le.states.jsAlleventsandintentsdispatchedbytheAlexaVoiceServicetoyourskillarehandledhere.YoucanintegrateanyothermoduleorAPIcallstothirdpartyservices,calldatabaseresourcesorjustsimplyreplyaHelloorGoodbyeresponsetotheuser.Theaudiointentshandledinthisexampleare:•AMAZON.CancelIntent•AMAZON.LoopOffIntent•AMAZON.LoopOnIntent•AMAZON.NextIntent•AMAZON.PauseIntent•AMAZON.PreviousIntent•AMAZON.RepeatIntent•AMAZON.ResumeIntent•AMAZON.ShufeOffIntent•AMAZON.ShufeOnIntent•AMAZON.StartOverIntentYoucantrackthevaluesforloop,shufeandcurrentURLplayinginthetokenpropertyoftheAlexaeventinthepathalexaEvent.context.AudioPlayer.token: 7.13.MyFirstPodcast31 VoxaDocumentation,Release2.1.0 skill.onState(loopOff,(alexaEvent)�={if(alexaEvent.context){consttoken=JSON.parse(alexaEvent.context.AudioPlayer.token);constshuffle=token.shuffle;cons

32 tloop=0;constoffsetInMilliseconds=alexaE
tloop=0;constoffsetInMilliseconds=alexaEvent.context.AudioPlayer.,!offsetInMilliseconds;letindex=token.index;if(index===podcast.length){index=0;}constdirectives=buildPlayDirective(podcast[index].url,index,shuffle, ,!loop,offsetInMilliseconds);return{reply:Intent.LoopDeactivated,to:die,directives};}return{reply:Intent.Exit,to:die};}); ForanyoftheseeventsyoucanmakeAlexatospeakafteruser'sactionwithareplyobject,optionallyyoucandenethediestateandpassthroughthedirectivesobjectwitheitheraAudioPlayer.PlayorAudioPlayer.Stopdirectivetype.Youcanalsohandledthefollowingplaybackrequestevents:•AudioPlayer.PlaybackStarted•AudioPlayer.PlaybackFinished•AudioPlayer.PlaybackStopped•AudioPlayer.PlaybackNearlyFinished•AudioPlayer.PlaybackFailedYou'renotallowedtorespondwithareplyobjectsinceit'sjustaneventmostfortrackignpurposes,soit'soptionaltoimplementan

33 dyoucandothefollowingsyntax: skill[
dyoucandothefollowingsyntax: skill[onAudioPlayer.PlaybackStarted]((alexaEvent)�={console.log(onAudioPlayer.PlaybackStarted,JSON.stringify(alexaEvent,null, ,!2));}); IncasetheuserhasactivatedtheloopmodebydispatchingtheAMAZON.LoopOnIntentintent,youcanimplementaqueuelistintheAudioPlayer.PlaybackNearlyFinishedthisway: skill[onAudioPlayer.PlaybackNearlyFinished]((alexaEvent,reply)�={consttoken=JSON.parse(alexaEvent.context.AudioPlayer.token);if(token.loop===0){returnreply;}constshuffle=token.shuffle;constloop=token.loop;letindex=token.index+1;if(shuffle===1){ 32Chapter7.Links VoxaDocumentation,Release2.1.0 index=randomIntInc(0,podcast.length-1);}elseif(index===podcast.length){index=0;}constdirectives=buildEnqueueDirective(podcast[index].url,index,shuffle, ,!loop);returnreply.append({directives});});functionbuildEnqueueDirective(url,index,shuffle,loop){co

34 nstdirectives={};directives.type=Au
nstdirectives={};directives.type=AudioPlayer.Play;directives.playBehavior=REPLACE_ENQUEUED;directives.token=createToken(index,shuffle,loop);directives.url=podcast[index].url;directives.offsetInMilliseconds=0;returndirectives;} ThebuildEnqueueDirectivefunctionisinchargetobuildadirectiveobjectwithaqueuebehavior,whichwillallowtheskilltoplaythenextaudioassoonasthecurrentoneisnished.Thisiswhereyourcodetohandlealexaeventsgoes,youwillusuallyhaveaStateMachinedenition,thiswillincludestates,middlewareandaModel,ViewsandVariables.data/podcast.jsAJSONvariablewithtitlesandurlsfor5audioexampleshostedinasecureserver,allalongplayapodcastwhichtheusercanshufeorloop.Youcanmodifythislewithwhateverotheraudiotoaddtoyourplaylist.Keepinmindthattheymustbehostedinasecureserver.ThesupportedformatsfortheaudioleincludeAAC/MP4,MP3,HLS,PLSandM3U.Bitrates:16kbpsto384kbps.speechAssetsThisshould

35 beaversioncontrolledcopyofyourintentsche
beaversioncontrolledcopyofyourintentschema,sampleutterrancesandcustomslots.server.jsAnhttpserverforyourskillconguredtolistenonport3000,thisshouldbeusedfordevelopmentonly.servicesJustacommonplacetoputmodelsandlibrariestestYouwritetestsright? 7.13.MyFirstPodcast33 VoxaDocumentation,Release2.1.0 gulpleAgulprunnerconguredwithawatchtaskthatstartsyourexpressserverandlistensforchangestoreloadyourapplication.serverless.ymlTheserverlessframeworkisatoolthathelpsyoumanageyourlambdaapplications,assumingyouhaveyourAWScredentialssetupproperlythisstarterkitdenestheveryminimumneededsoyoucandeployyourskilltolambdawiththefollowingcommand: $slsdeploy Runningtheproject1.Clonethevoxarepository2.Createanewskillprojectusingthesamples/my-first-podcastdirectoryasabasis3.Makesureyou'rerunningnode4.3,thisiseasiestwithnvm4.Createaconfig/local.jsonleusingconfig/local.json.exampleasanexample5.Runtheprojectwith

36 gulpwatch6.CreateaskillinyourAmazonDevel
gulpwatch6.CreateaskillinyourAmazonDeveloperPortalaccountundertheALEXAmenu.7.GototheinteractionmodeltabandcopytheintentschemaandutterancesfromthethespeechAssetsfolder.8.Atthispointyoushouldstartngrokhttp3000andcongureyourskillintheAmazonDeveloperpaneltousethengrokhttpsendpoint.AccountLinkingThisprojectisdesignedtobeasimpletemplateforyournewskillswithaccountlinking.User'sinformationisstoredinaDynamoDBtablesoyoucanfetchitfromtheskillonceusersareauthenticated.DirectoryStructureIthasthefollowingdirectorystructure .-README.md-config|-env.js|-index.js|-local.json.example|-production.json|-staging.json-gulpfile.js-package.json-serverless.yml-services|-model.js 34Chapter7.Links VoxaDocumentation,Release2.1.0 |-userStorage.js-skill|-MainStateMachine.js|-index.js|-states.js|-variables.js|-views.js-speechAssets|-IntentSchema.json|-SampleUtterances.txt|-customSlotTypes-test-www-infrastructure|-mount.js-route

37 s|-index.js|-skill.js-server.js cong
s|-index.js|-skill.js-server.js congBydefaultyourskillwillhavethefollowingenvironments:•local•staging•productionWhatenvironmentyou'reisdeterminedintheconfig/env.jsmoduleusingthefollowingcode: usestrict;functiongetEnv(){if(process.env.NODE_ENV)returnprocess.env.NODE_ENV;if(process.env.AWS_LAMBDA_FUNCTION_NAME){//TODOputyourownlambdafunctionnamehereif(process.env.AWS_LAMBDA_FUNCTION_NAME===)returnproduction;returnstaging;}returnlocal;}module.exports=getEnv(); skillindex.jsFirstleinvokedbythelambdafunction,itinitializesthestatemachine.Youdon'tneedtomodifythisle. 7.14.AccountLinking35 VoxaDocumentation,Release2.1.0 MainStateMachine.jsStatemachineisinitializedwithyourmodel,viewsandvariables.Theclassstates.jswillbeinchargetohandleallintentsandeventscomingfromAlexa.Youdon'tneedtomodifythisle.states.jsAlleventsandintentsdispatch

38 edbytheAlexaVoiceServicetoyourskillareha
edbytheAlexaVoiceServicetoyourskillarehandledhere.YoucanintegrateanyothermoduleorAPIcallstothirdpartyservices,calldatabaseresourcesorjustsimplyreplyaHelloorGoodbyeresponsetotheuser.Beforetheverybeginningofthelesson,youcanimplementthemethodonRequestStartedtofetchuser'sdatafromDynamoDBbasedontheaccessTokencomingfromAlexa skill.onRequestStarted((alexaEvent)�={if(!alexaEvent.session.user.accessToken){returnalexaEvent;}conststorage=newUserStorage();returnstorage.get(alexaEvent.session.user.accessToken).then((user)�={alexaEvent.model.user=user;returnalexaEvent;});}); IftheuserisnotauthenticatedyoucanalsosendaLinkingAccountcardtotheAlexaappsousersknowthatbeforeusingyourskill,theymustgetauthenticated.speechAssetsThisshouldbeaversioncontrolledcopyofyourintentschema,sampleutterrancesandcustomslots.wwwAstandardexpressprojectconguredtoserveyourskillinthe/skillroute.Combinedwithngrokthis

39 isagreattoolwhendevelopingordebugging.ro
isagreattoolwhendevelopingordebugging.routes/index.jsYoucanhandleallGETandPOSTrequestsforyouraccountlinkingprojectshere.ThemostcommononewillbethePOSTcalloftheformafterusershitthesubmitbutton.Inthisexample,wegatheruser'sinformationandcreatearowinDynamoDBfortheirinformation.ForexampleyoucangenerateanUUIDtoidentifytheusersastheprimarykeyandsenditbacktoAlexaastheaccessTokensoyoucaneasilyfetchuser'sinformationlateron. router.post(/,(req,res,next)�={constmd=newMobileDetect(req.headers[user-agent]);constdb=newStorage();constemail=req.body.email;constcode=uuidV4().replace(/-/g,);constparams={id:code,email, 36Chapter7.Links VoxaDocumentation,Release2.1.0 };returndb.put(params).then(()�={constredirect=${req.query.redirect_uri}#state=${req.query.state}&access_,!token=${code}&token_type=Bearer;if(md.is(AndroidOS)){console.log(redirectin

40 gandroidto:${redirect});res.redirec
gandroidto:${redirect});res.redirect(redirect);}else{console.log(redirectingwebto:${redirect});res.render(auth/success,{page:success,title:Success,redirectUrl:redirect,});}}).catch(next);}); Tonishtheauthenticationprocessyouhavetomakearedirectiontotheredirect_uriAmazonsendstoourservice.Sincetherecouldbe2originstoredirectto,wecreatethisURLdynamically;theseendpointscouldlooklikethis:•https://pitangui.amazon.com/spa/skill/account-linking-status.html?vendorId=xxx�-ForUnitedStatesstore•https://layla.amazon.com/spa/skill/account-linking-status.html?vendorId=xxxxxx�-ForUKandGermanystoreTheotherparameterstosendare:•access_token=YOUR-TOKEN•token_type=BearerservicesJustacommonplacetoputmodelsandlibrariesuserStorage.jsUsethisleasanexampletohandledatabaselogic.SinceweuseDynamoDBforthisexample,weincluded2methods,aputand

41 aget,souser'sinformationgetstoredfromthe
aget,souser'sinformationgetstoredfromtheaccountlinkingprojectandgetfetchedfromthealexaskillside.ForreachingoutDynamoDByouneedsomepermissionsforyourlambdafunction.MakesuretograntyourlambdafunctionwitharolewithDynamoDBaccess.testYouwritetestsright?gulpleAgulprunnerconguredwithawatchtaskthatstartsyourexpressserverandlistensforchangestoreloadyourapplication. 7.14.AccountLinking37 VoxaDocumentation,Release2.1.0 serverless.ymlTheserverlessframeworkisatoolthathelpsyoumanageyourlambdaapplications,assumingyouhaveyourAWScredentialssetupproperlythisstarterkitdenestheveryminimumneededsoyoucandeployyourskilltolambdawiththefollowingcommand: $slsdeploy Runningtheproject1.Clonethevoxarepository2.Createanewskillprojectusingthesamples/starterKitdirectoryasabasis3.Makesureyou'rerunningnode4.3,thisiseasiestwithnvm4.Createaconfig/local.jsonleusingconfig/local.json.exampleasanexample5.Runtheprojectwithgulp

42 watch6.Atthispointyoushouldstartngrokhtt
watch6.Atthispointyoushouldstartngrokhttp3000andcongureyourskillintheAmazonDeveloperpaneltousethengrokhttpsendpoint. 38Chapter7.Links Index AAlexaEvent()(class),16AlexaEvent.intent.params(AlexaEvent.intentattribute),16AlexaEvent.model(AlexaEventattribute),16AlexaEvent.user(AlexaEventattribute),16audioPlayerCallback()(built-infunction),20autoLoad()(built-infunction),27Ccloudwatch()(built-infunction),26RreplaceIntent()(built-infunction),25Reply()(class),17Reply.append()(Replymethod),17Reply.toJSON()(Replymethod),17SstateFlow()(built-infunction),25Vvariable()(built-infunction),14Voxa()(class),17Voxa.execute()(Voxamethod),17Voxa.lambda()(Voxamethod),17Voxa.onAfterStateChanged()(Voxamethod),19Voxa.onAudioPlayer.PlaybackFailed()(Voxa.onAudioPlayermethod),21Voxa.onAudioPlayer.PlaybackFinished()(Voxa.onAudioPlayermethod),21Voxa.onAudioPlayer.PlaybackNearlyFinished()(Voxa.onAudioPlayermethod),21Voxa.onAud

43 ioPlayer.PlaybackStarted()(Voxa.onAudioP
ioPlayer.PlaybackStarted()(Voxa.onAudioPlayermethod),21Voxa.onAudioPlayer.PlaybackStopped()(Voxa.onAudioPlayermethod),21Voxa.onBeforeReplySent()(Voxamethod),18Voxa.onBeforeStateChanged()(Voxamethod),18Voxa.onError()(Voxamethod),20Voxa.onIntent()(Voxamethod),18Voxa.onIntentRequest()(Voxamethod),18Voxa.onLaunchRequest()(Voxamethod),18Voxa.onPlaybackController.NextCommandIssued()(Voxa.onPlaybackControllermethod),21Voxa.onPlaybackController.PauseCommandIssued()(Voxa.onPlaybackControllermethod),21Voxa.onPlaybackController.PlayCommandIssued()(Voxa.onPlaybackControllermethod),21Voxa.onPlaybackController.PreviousCommandIssued()(Voxa.onPlaybackControllermethod),21Voxa.onRequestStarted()(Voxamethod),19Voxa.onSessionEnded()(Voxamethod),19Voxa.onSessionStarted()(Voxamethod),19Voxa.onState()(Voxamethod),17Voxa.onStateMachineError()(Voxamethod),20Voxa.onSystem.ExceptionEncountered()(Voxa.onSystemmethod),19Voxa.onU

Related Contents


Next Show more