# Printer test skill #### 1. Add new skill https://developer.amazon.com/alexa/console/ask/create-new-skill 1.1: "Custom model, Alexa-Hosted" ![](https://i.imgur.com/l6PIxtw.jpg) 1.2: "Start from Scratch" ![](https://i.imgur.com/7idBYnp.jpg) #### 2. Add invocation and intent 2.1: Add invocation, save model ![](https://i.imgur.com/IUFXs5Y.jpg) 2.2: Add intent, Name = "Print" ![](https://i.imgur.com/QfSqe4L.jpg) Add utterance "Print",click "+", save model, build model ![](https://i.imgur.com/s0iOasN.jpg) #### 3. Copy code below to replace the code in "Code", save and deploy ![](https://i.imgur.com/OgYHk4t.jpg) ```javascript= /* * * This sample demonstrates handling intents from an Alexa skill using the Alexa Skills Kit SDK (v2). * Please visit https://alexa.design/cookbook for additional examples on implementing slots, dialog management, * session persistence, api calls, and more. * */ const Alexa = require('ask-sdk-core'); const LaunchRequestHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest'; }, handle(handlerInput) { const speakOutput = 'Welcome, you can say Hello or Print. Which would you like to try?'; return handlerInput.responseBuilder .speak(speakOutput) .reprompt(speakOutput) .getResponse(); } }; const HelloWorldIntentHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' && Alexa.getIntentName(handlerInput.requestEnvelope) === 'HelloWorldIntent'; }, handle(handlerInput) { const speakOutput = 'Hello World!'; return handlerInput.responseBuilder .speak(speakOutput) //.reprompt('add a reprompt if you want to keep the session open for the user to respond') .getResponse(); } }; const HelpIntentHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.HelpIntent'; }, handle(handlerInput) { const speakOutput = 'You can say hello to me! How can I help?'; return handlerInput.responseBuilder .speak(speakOutput) .reprompt(speakOutput) .getResponse(); } }; const CancelAndStopIntentHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' && (Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.CancelIntent' || Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.StopIntent'); }, handle(handlerInput) { const speakOutput = 'Goodbye!'; return handlerInput.responseBuilder .speak(speakOutput) .getResponse(); } }; /* * * FallbackIntent triggers when a customer says something that doesn’t map to any intents in your skill * It must also be defined in the language model (if the locale supports it) * This handler can be safely added but will be ingnored in locales that do not support it yet * */ const FallbackIntentHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.FallbackIntent'; }, handle(handlerInput) { const speakOutput = 'Sorry, I don\'t know about that. Please try again.'; return handlerInput.responseBuilder .speak(speakOutput) .reprompt(speakOutput) .getResponse(); } }; /* * * SessionEndedRequest notifies that a session was ended. This handler will be triggered when a currently open * session is closed for one of the following reasons: 1) The user says "exit" or "quit". 2) The user does not * respond or says something that does not match an intent defined in your voice model. 3) An error occurs * */ const SessionEndedRequestHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'SessionEndedRequest'; }, handle(handlerInput) { console.log(`~~~~ Session ended: ${JSON.stringify(handlerInput.requestEnvelope)}`); // Any cleanup logic goes here. return handlerInput.responseBuilder.getResponse(); // notice we send an empty response } }; /* * * The intent reflector is used for interaction model testing and debugging. * It will simply repeat the intent the user said. You can create custom handlers for your intents * by defining them above, then also adding them to the request handler chain below * */ const IntentReflectorHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'; }, handle(handlerInput) { const intentName = Alexa.getIntentName(handlerInput.requestEnvelope); const speakOutput = `You just triggered ${intentName}`; return handlerInput.responseBuilder .speak(speakOutput) //.reprompt('add a reprompt if you want to keep the session open for the user to respond') .getResponse(); } }; /** * Generic error handling to capture any syntax or routing errors. If you receive an error * stating the request handler chain is not found, you have not implemented a handler for * the intent being invoked or included it in the skill builder below * */ const ErrorHandler = { canHandle() { return true; }, handle(handlerInput, error) { const speakOutput = 'Sorry, I had trouble doing what you asked. Please try again.'; console.log(`~~~~ Error handled: ${JSON.stringify(error)}`); return handlerInput.responseBuilder .speak(speakOutput) .reprompt(speakOutput) .getResponse(); } }; // //... const PrintIntentHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' && Alexa.getIntentName(handlerInput.requestEnvelope) === 'Print'; }, handle(handlerInput) { const speakOutput = 'Start to print!'; return handlerInput.responseBuilder .speak(speakOutput) .addDirective({ 'type': 'Connections.StartConnection', 'uri': 'connection://AMAZON.PrintPDF/1', 'onCompletion': 'RESUME_SESSION', 'input': { '@type': 'PrintPDFRequest', '@version': '1', 'title': 'title', 'description': 'description', 'url': 'https://ctspecbucket.s3.amazonaws.com/report.pdf' }, 'token': '...' }) .getResponse(); } }; //resume handler const SessionResumedRequestHandler = { canHandle(handlerInput) { const request = handlerInput.requestEnvelope.request; return request.type === 'SessionResumedRequest'; }, handle(handlerInput) { const status = handlerInput.requestEnvelope.request.cause.status; const code = status.code; const message = status.message; console.log(`SessionResumedRequest received status code : ${code} and message : ${message}`); // The current sessionId is same as the one in previous IntentRequest when the original Connections.StartConnection directive was returned. const currentSessionId = handlerInput.requestEnvelope.session.sessionId; // Continue requester skill experience. In this example, it renders a speech. return handlerInput.responseBuilder .speak("Requester skill received SessionResumedRequest") .getResponse(); } }; /** * This handler acts as the entry point for your skill, routing all request and response * payloads to the handlers above. Make sure any new handlers or interceptors you've * defined are included below. The order matters - they're processed top to bottom * */ exports.handler = Alexa.SkillBuilders.custom() .addRequestHandlers( LaunchRequestHandler, PrintIntentHandler, SessionResumedRequestHandler, HelloWorldIntentHandler, HelpIntentHandler, CancelAndStopIntentHandler, FallbackIntentHandler, SessionEndedRequestHandler, IntentReflectorHandler) .addErrorHandlers( ErrorHandler) .withCustomUserAgent('sample/hello-world/v1.2') .lambda(); ``` 5. Test ![](https://i.imgur.com/LWPZI4R.jpg)