基于NodeJS+Lambda的Alexa技能分页询问功能实现求助
Hey there! Let's figure out how to add pagination to your Alexa skill—this is such a common use case, and I’ve helped a few folks get this working with Node.js and Lambda before. Here’s a straightforward, step-by-step guide tailored to your setup:
Since Lambda functions are stateless (they don’t retain data between calls), we need to store two key pieces of info for the conversation:
- The full array of data from your API
- The index of the last item we’ve already spoken
Alexa’s Session Attributes are perfect for this—they act as temporary storage for the current user session. We’ll update these attributes as we paginate through the data.
We’ll need three core handlers:
- Your original data-fetching intent (to start the flow)
- A handler for when the user says "Yes" (to get the next batch)
- A handler for when the user says "No" (to end the session)
Example Code for Handlers
First, your main data intent handler (starts the flow):
const FetchDataIntentHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' && Alexa.getIntentName(handlerInput.requestEnvelope) === 'YourDataIntentName'; }, async handle(handlerInput) { // 1. Fetch your data from the API const fullDataArray = await fetchYourApiData(); // Replace with your actual API call // 2. Store data and initial index in session attributes const sessionAttributes = handlerInput.attributesManager.getSessionAttributes(); sessionAttributes.fullData = fullDataArray; sessionAttributes.currentIndex = 10; // We'll speak items 0-9 first // 3. Build speech for the first 10 items const firstBatchSpeech = fullDataArray.slice(0, 10) .map((item, idx) => `${idx + 1}. ${item.yourDataField}`) // Replace with your data's display field .join(' '); // 4. Add the follow-up question and keep the session open const speechOutput = `${firstBatchSpeech} Would you like to hear the next 10 items?`; const repromptText = "I didn't catch that—would you like to hear the next 10 items?"; handlerInput.attributesManager.setSessionAttributes(sessionAttributes); return handlerInput.responseBuilder .speak(speechOutput) .reprompt(repromptText) .withShouldEndSession(false) // Critical: keeps the session alive for user input .getResponse(); } };
Next, the handler for when the user says "Yes":
const AmazonYesIntentHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.YesIntent'; }, handle(handlerInput) { const sessionAttributes = handlerInput.attributesManager.getSessionAttributes(); const { fullData, currentIndex } = sessionAttributes; // Check if there are any items left to speak if (currentIndex >= fullData.length) { return handlerInput.responseBuilder .speak("There are no more items to share. Thanks for using the skill!") .withShouldEndSession(true) .getResponse(); } // Get the next batch of up to 10 items const nextBatch = fullData.slice(currentIndex, currentIndex + 10); const nextBatchSpeech = nextBatch .map((item, idx) => `${currentIndex + idx + 1}. ${item.yourDataField}`) .join(' '); // Update the current index for next time sessionAttributes.currentIndex += 10; handlerInput.attributesManager.setSessionAttributes(sessionAttributes); // Build the response (with follow-up if more items exist) let speechOutput, repromptText; if (sessionAttributes.currentIndex < fullData.length) { repromptText = "Would you like to hear the next 10 items?"; speechOutput = `${nextBatchSpeech} ${repromptText}`; } else { speechOutput = `${nextBatchSpeech} That's all the items we have. Thanks for listening!`; } return handlerInput.responseBuilder .speak(speechOutput) .reprompt(repromptText || "") .withShouldEndSession(sessionAttributes.currentIndex >= fullData.length) .getResponse(); } };
Finally, the handler for when the user says "No":
const AmazonNoIntentHandler = { canHandle(handlerInput) { return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.NoIntent'; }, handle(handlerInput) { return handlerInput.responseBuilder .speak("Alright, thanks for using the skill! Have a great day.") .withShouldEndSession(true) .getResponse(); } };
Don’t forget to enable the built-in intents in your Alexa Developer Console:
- Go to your skill’s Interaction Model > Intents
- Click Add Intent > select Use an existing intent from Alexa’s built-in library
- Search for and add
AMAZON.YesIntentandAMAZON.NoIntent - Save and build your model (this is mandatory for the intents to work)
- Session ends unexpectedly? Double-check that
withShouldEndSession(false)is set when you’re waiting for user input. - Data not persisting between calls? Make sure you’re calling
handlerInput.attributesManager.setSessionAttributes(sessionAttributes)after updating the attributes. - Built-in intents not triggering? Confirm you’ve added them to your interaction model and deployed the updated model to your development environment.
内容的提问来源于stack exchange,提问作者Yannick Borschneck

