如何使用async在ALEXA intent中包含自定义API请求

问题描述 投票:0回答:1

我有以下问题已经花了我几个小时,但我无法解决它。

我想创建一个Alexa技能,向用户询问几个问题。之后用户输入发送到API。当我单独提出请求时,一切运作良好。当它包含在意图中时它不起作用。即使我使用异步,它也被跳过了。

这里的代码:

/* This code has been generated from your interaction model by skillinator.io

/* eslint-disable  func-names */
/* eslint quote-props: ["error", "consistent"]*/

// There are three sections, Text Strings, Skill Code, and Helper Function(s).
// You can copy and paste the contents as the code for a new Lambda function, using the alexa-skill-kit-sdk-factskill template.
// This code includes helper functions for compatibility with versions of the SDK prior to 1.0.9, which includes the dialog directives.



 // 1. Text strings =====================================================================================================
 //    Modify these strings and messages to change the behavior of your Lambda function

 var request = require('request');
 var size;
 var heightSlot = 188;
 var ageSlot = 35;
 var weightSlot = 88;
 var gender = "MALE"


 var jsonBody = {
     "gender" : gender,
     "unit": "METRIC",
     "height": heightSlot,
     "weight": weightSlot,
     "age": ageSlot
 }


 const options = {
         method: 'PUT',
         uri: "https://custom.apicall.com/api/finder/",
         //headers: headers,   // headers if your api requires
         body: jsonBody,
         json: true
 };


let speechOutput;
let reprompt;
let welcomeOutput = "This is a placeholder welcome message. This skill includes 6 intents. Try one of your intent utterances to test the skill.";
let welcomeReprompt = "sample re-prompt text";
// 2. Skill Code =======================================================================================================
"use strict";
const Alexa = require('alexa-sdk');
const APP_ID = undefined;  // TODO replace with your app ID (OPTIONAL).
speechOutput = '';
const handlers = {
    'LaunchRequest': function () {
        this.emit(':ask', welcomeOutput, welcomeReprompt);
    },
    'AMAZON.HelpIntent': function () {
        speechOutput = 'Placeholder response for AMAZON.HelpIntent.';
        reprompt = '';
        this.emit(':ask', speechOutput, reprompt);
    },
   'AMAZON.CancelIntent': function () {
        speechOutput = 'Placeholder response for AMAZON.CancelIntent';
        this.emit(':tell', speechOutput);
    },
   'AMAZON.StopIntent': function () {
        speechOutput = 'Placeholder response for AMAZON.StopIntent.';
        this.emit(':tell', speechOutput);
   },
   'SessionEndedRequest': function () {
        speechOutput = '';
        //this.emit(':saveState', true);//uncomment to save attributes to db on session end
        this.emit(':tell', speechOutput);
   },
    'AMAZON.FallbackIntent': function () {
        speechOutput = '';

        //any intent slot variables are listed here for convenience


        //Your custom intent handling goes here
        speechOutput = "This is a place holder response for the intent named AMAZON.FallbackIntent. This intent has no slots. Anything else?";
        this.emit(":ask", speechOutput, speechOutput);
    },
    'AMAZON.NavigateHomeIntent': function () {
        speechOutput = '';

        //any intent slot variables are listed here for convenience


        //Your custom intent handling goes here
        speechOutput = "This is a place holder response for the intent named AMAZON.NavigateHomeIntent. This intent has no slots. Anything else?";
        this.emit(":ask", speechOutput, speechOutput);
    },
    'findOutMyCalorie': function () {
        //delegate to Alexa to collect all the required slot values
       let filledSlots = delegateSlotCollection.call(this);
        speechOutput = '';
        //any intent slot variables are listed here for convenience

        let genderSlotRaw = this.event.request.intent.slots.gender.value;
        console.log(genderSlotRaw);
    let genderSlot = resolveCanonical(this.event.request.intent.slots.gender);
    console.log(genderSlot);
        let ageSlotRaw = this.event.request.intent.slots.age.value;
        console.log(ageSlotRaw);
        let ageSlot = resolveCanonical(this.event.request.intent.slots.age);
        console.log(ageSlot);
        let weightSlotRaw = this.event.request.intent.slots.weight.value;
        console.log(weightSlotRaw);
        let weightSlot = resolveCanonical(this.event.request.intent.slots.weight);
        console.log(weightSlot);
        let weight_unitSlotRaw = this.event.request.intent.slots.weight_unit.value;
        console.log(weight_unitSlotRaw);
        let weight_unitSlot = resolveCanonical(this.event.request.intent.slots.weight_unit);
        console.log(weight_unitSlot);
        let heightSlotRaw = this.event.request.intent.slots.height.value;
        console.log(heightSlotRaw);
        let heightSlot = resolveCanonical(this.event.request.intent.slots.height);
        console.log(heightSlot);
        let height_unitSlotRaw = this.event.request.intent.slots.height_unit.value;
        console.log(height_unitSlotRaw);
        let height_unitSlot = resolveCanonical(this.event.request.intent.slots.height_unit);
        console.log(height_unitSlot);
    myAsyncFn();



    //Your custom intent handling goes here
    speechOutput = "Deine Kalorienverbrauch ist " + size;
    this.emit(':ask', speechOutput, speechOutput);

        //Your custom intent handling goes here
        //speechOutput = "This is a place holder response for the intent named findOutMySize, which includes dialogs. This intent has 6 slots, which are gender, age, weight, weight_unit, height, and height_unit. Anything else?";
        //this.emit(':ask', speechOutput, speechOutput);
    },
    'Unhandled': function () {
        speechOutput = "The skill didn't quite understand what you wanted.  Do you want to try something else?";
        this.emit(':ask', speechOutput, speechOutput);
    }
};

exports.handler = (event, context) => {
    const alexa = Alexa.handler(event, context);
    alexa.appId = APP_ID;
    // To enable string internationalization (i18n) features, set a resources object.
    //alexa.resources = languageStrings;
    alexa.registerHandlers(handlers);
    //alexa.dynamoDBTableName = 'DYNAMODB_TABLE_NAME'; //uncomment this line to save attributes to DB
    alexa.execute();
};

//    END of Intent Handlers {} ========================================================================================
// 3. Helper Function  =================================================================================================

async function myAsyncFn() {
    try {
      await request(options, function(err, response) {
                     size = response.body.size;
                      console.log(response.body.size)

              });
    }
    catch (error) {
        console.log(error);
    }
}



function resolveCanonical(slot){
    //this function looks at the entity resolution part of request and returns the slot value if a synonyms is provided
    let canonical;
    try{
        canonical = slot.resolutions.resolutionsPerAuthority[0].values[0].value.name;
    }catch(err){
        console.log(err.message);
        canonical = slot.value;
    };
    return canonical;
};

function delegateSlotCollection(){
  console.log("in delegateSlotCollection");
  console.log("current dialogState: "+this.event.request.dialogState);
    if (this.event.request.dialogState === "STARTED") {
      console.log("in Beginning");
      let updatedIntent= null;
      // updatedIntent=this.event.request.intent;
      //optionally pre-fill slots: update the intent object with slot values for which
      //you have defaults, then return Dialog.Delegate with this updated intent
      // in the updatedIntent property
      //this.emit(":delegate", updatedIntent); //uncomment this is using ASK SDK 1.0.9 or newer

      //this code is necessary if using ASK SDK versions prior to 1.0.9
      if(this.isOverridden()) {
            return;
        }
        this.handler.response = buildSpeechletResponse({
            sessionAttributes: this.attributes,
            directives: getDialogDirectives('Dialog.Delegate', updatedIntent, null),
            shouldEndSession: false
        });
        this.emit(':responseReady', updatedIntent);

    } else if (this.event.request.dialogState !== "COMPLETED") {
      console.log("in not completed");
      // return a Dialog.Delegate directive with no updatedIntent property.
      //this.emit(":delegate"); //uncomment this is using ASK SDK 1.0.9 or newer

      //this code necessary is using ASK SDK versions prior to 1.0.9
        if(this.isOverridden()) {
            return;
        }
        this.handler.response = buildSpeechletResponse({
            sessionAttributes: this.attributes,
            directives: getDialogDirectives('Dialog.Delegate', null, null),
            shouldEndSession: false
        });
        this.emit(':responseReady');

    } else {
      console.log("in completed");
      console.log("returning: "+ JSON.stringify(this.event.request.intent));
      // Dialog is now complete and all required slots should be filled,
      // so call your normal intent handler.
      return this.event.request.intent;
    }
}


function randomPhrase(array) {
    // the argument is an array [] of words or phrases
    let i = 0;
    i = Math.floor(Math.random() * array.length);
    return(array[i]);
}
function isSlotValid(request, slotName){
        let slot = request.intent.slots[slotName];
        //console.log("request = "+JSON.stringify(request)); //uncomment if you want to see the request
        let slotValue;

        //if we have a slot, get the text and store it into speechOutput
        if (slot && slot.value) {
            //we have a value in the slot
            slotValue = slot.value.toLowerCase();
            return slotValue;
        } else {
            //we didn't get a value in the slot.
            return false;
        }
}

//These functions are here to allow dialog directives to work with SDK versions prior to 1.0.9
//will be removed once Lambda templates are updated with the latest SDK

function createSpeechObject(optionsParam) {
    if (optionsParam && optionsParam.type === 'SSML') {
        return {
            type: optionsParam.type,
            ssml: optionsParam['speech']
        };
    } else {
        return {
            type: optionsParam.type || 'PlainText',
            text: optionsParam['speech'] || optionsParam
        };
    }
}

function buildSpeechletResponse(options) {
    let alexaResponse = {
        shouldEndSession: options.shouldEndSession
    };

    if (options.output) {
        alexaResponse.outputSpeech = createSpeechObject(options.output);
    }

    if (options.reprompt) {
        alexaResponse.reprompt = {
            outputSpeech: createSpeechObject(options.reprompt)
        };
    }

    if (options.directives) {
        alexaResponse.directives = options.directives;
    }

    if (options.cardTitle && options.cardContent) {
        alexaResponse.card = {
            type: 'Simple',
            title: options.cardTitle,
            content: options.cardContent
        };

        if(options.cardImage && (options.cardImage.smallImageUrl || options.cardImage.largeImageUrl)) {
            alexaResponse.card.type = 'Standard';
            alexaResponse.card['image'] = {};

            delete alexaResponse.card.content;
            alexaResponse.card.text = options.cardContent;

            if(options.cardImage.smallImageUrl) {
                alexaResponse.card.image['smallImageUrl'] = options.cardImage.smallImageUrl;
            }

            if(options.cardImage.largeImageUrl) {
                alexaResponse.card.image['largeImageUrl'] = options.cardImage.largeImageUrl;
            }
        }
    } else if (options.cardType === 'LinkAccount') {
        alexaResponse.card = {
            type: 'LinkAccount'
        };
    } else if (options.cardType === 'AskForPermissionsConsent') {
        alexaResponse.card = {
            type: 'AskForPermissionsConsent',
            permissions: options.permissions
        };
    }

    let returnResult = {
        version: '1.0',
        response: alexaResponse
    };

    if (options.sessionAttributes) {
        returnResult.sessionAttributes = options.sessionAttributes;
    }
    return returnResult;
}

function getDialogDirectives(dialogType, updatedIntent, slotName) {
    let directive = {
        type: dialogType
    };

    if (dialogType === 'Dialog.ElicitSlot') {
        directive.slotToElicit = slotName;
    } else if (dialogType === 'Dialog.ConfirmSlot') {
        directive.slotToConfirm = slotName;
    }

    if (updatedIntent) {
        directive.updatedIntent = updatedIntent;
    }
    return [directive];
}
node.js request alexa
1个回答
0
投票

你收到错误信息吗?我的感觉是处理程序本身也需要异步。

我这样解决了

const getSpeechOutput = async function (version) {
  const gadata = await ga.getGA(gaQueryUsers, 'ga:users')

  let speechOutput;

...

  return speechOutput
}

const UsersIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'UsersIntent';
  },
  async handle(handlerInput) {
    try {
      const speechOutput = await getSpeechOutput("long");

      return handlerInput.responseBuilder
        .speak(speechOutput)
        .withSimpleCard(defaulttext.SKILL_NAME, speechOutput)
        .getResponse();

    } catch (error) {
      console.error(error);
    }
  },
};

module.exports = {
  UsersIntentHandler,
  getSpeechOutput
}

那个带有实际api调用的函数:

const getGA = async (gaQuery,requestResult) => {
    try {
      jwt.authorize()
      const result = await google.analytics('v3').data.ga.get(gaQuery)
      return result.data.totalsForAllResults[requestResult];
    } catch (error) {
      throw error
    }2
  }
© www.soinside.com 2019 - 2024. All rights reserved.