0

Amazon Alexaの年金計算スキルを開発するためにnodejs 'alexa-sdk'を使用しています。私が持っている問題は、ある状態から別の状態に切り替えるときにセッション属性を保持しないということです。私はAmazon Alexaセッションの属性が維持されない

this.attributes['ATTRIBUTE_NAME'] = 'some_value'; 

のようにそれらを格納しています。しかし、私は答え(Alexa.CreateStateHandler(states.ANSWER[...])を得ポイントに到達したとき、すべての属性は、「未定義」されています。誰も私がセッション属性を格納したり渡したりすることで間違っていることをアドバイスできますか?

var Alexa = require('alexa-sdk'); 
var moment = require('moment'); // deals with dates and date formatting, for instance converts AMAZON.DATE to timestamp 

// import pension calculator 
var calculator = require('./pensionCalculator'); 

var GENDERCUTOFFDATE = new Date(1953, 12, 6); 

// States are required for conversational skills. 
// States assume a context. e.g. _DOB expects date of birth; providing a gender in this state would confuse Alexa. 
// UX design principle have to be as unambiguous as possible in language (e.g. "are you male or female" vs "what gender are you?") 
var states = { 
    START: '_STARTMODE', // Prompt the user to start or restart 
    DOB: '_DOB', 
    GENDER: '_GENDER', 
    ANSWER: '_ANSWER' 
}; 


// Outbound messages spoken back to end user. 
// alexa-nodejs-sdk wraps all strings in the advanced SSML speech markup (<speak>STRING HERE</speak>) that allows phonetic overrides etc. 
var snippets = { 
      WELCOME: "<s>Welcome to the D W P Pension Age calculator.</s> " + 
      "<s>You can ask to calculate your pension age or for the U K pension eligibility criteria?</s>", 

      WELCOME_REPROMPT: "You can say, " + 
      "Calculate my pension age or, say what are the eligibility criteria in the U K.", 

      GENDER: "Thank you. Are you female or male?", 

      GENDER_REPROMPT: "In order to calculate your pension age, please tell me: Are you male or female?", 

      GENDER_INVALID: "Sorry I couldn't understand your gender, can you please tell me if you are you male or female?", 

      DATEOFBIRTH: "Ok, please tell me what is your date of birth?", 

      DATEOFBIRTH_REPROMPT: "In order to calculate your pension age please tell me your date of birth?", 

      DATEOFBIRTH_INVALID_FUTURE: "Nice you're from the future. Did you bring a hoverboard? Seriously, can you please say your actual date of birth please?", 

      DATEOFBIRTH_INVALID: "Please say your date of birth. For example you can say, my date of birth is the 23rd of April 1980", 

      STOP: "Thank you for using the D W P pension calculator.", 

      HELP: "You can ask things like: What is my pension age or what are the eligibility criteria.", 

      HELP_REPROMPT: "Simply say: calculate pension or eligibility criteria.", 

      UNHANDLED: "I'm sorry I couldn't understand what you meant. Can you please say it again?" 
}; 


// You define a set of state handlers for every state PLUS the new session/launch event. 
var newSessionHandlers = { 

    // session variables stored in this.attributes 
    // session state is stored in this.handler.state 
    // handler.state vs Intent vs 
    'LaunchRequest': function() { 
     // Initialise State 
     this.handler.state = states.START; 

     // emitWithState should be called executeStateHandler("Start"). 
     // As such this will call a handler "Start" in the startStateHandlers object. 
     // Maybe this line and the previous line could be more coherently wrapped into a single 
     // function: 
     // this.stateTransition(states.START, "Start") 
     this.emit("Start") 
    }, 

    // It's unclear whether this can ever happen as it's triggered by Alexa itself. 
    "Unhandled": function() { 
     var speechText = "I wasn't launched yet"; 
     this.emit(":ask", speechText); 
    } 
}; 



// This is the beginning of our skill. 
// This is a list of accepted intents Alexa is listening for 
// when the skill has just started. 
// In this specific version, a user can't provide things like date of birth 
// or gender as part of the initial skill invocation because we've not included in this set of start state handlers. 
// We could but haven't in this particular scenario. 
var startStateHandlers = Alexa.CreateStateHandler(states.START, { 
    'Start': function() { 


     this.attributes['dob'] = ''; 
     this.attributes['gender'] = ''; 


     this.handler.state = states.START; 
     var speechText = snippets.WELCOME; 
     var repromptText = snippets.WELCOME_REPROMPT; 

     // emit is the exit point to instruct Alexa how to and what to communicate with end user. 
     // e.g. do we want further information? (:ask)/no further information, skill terminates (:tell) 
     // do we provide a voice response with or without a card on the mobile device (:ask vs :askWithCard) 
     // https://github.com/alexa/alexa-skills-kit-sdk-for-nodejs 
     // as we've said :ask we are expecting the user to provide more information. 
     // maybe this function could be called this.respond() 
     // this is going to speak the snippets.WELCOME which implicitly asks a question (hence :ask). 
     // reprompt text is automatically spoken after a few seconds. This is a feature of the NodeJS SDK. 
     // See Unhandled for the fallback/unrecognised utteranes. 
     this.emit(':ask', speechText, repromptText); 
    }, 

    // the intent text is defined in the 
    // Alexa interaction model web page at developer.amazon.com/ask 
    // represented as sample utterances. 
    'StartCalculationIntent': function() { 
     var speechText = snippets.DATEOFBIRTH; 
     var repromptText = snippets.DATEOFBIRTH_REPROMPT; 

     // Change State to calculation 
     this.handler.state = states.DOB; 
     this.emit(':ask', speechText, repromptText); 
    }, 

    // a predefined Utterance that you don't need to define in your interaction model 
    // We are choosing to provide this help function but equally you don't need to. 
    "AMAZON.HelpIntent": function() { 
     var speechText = snippets.HELP; 
     var repromptText = snippets.HELP_REPROMPT; 
     this.emit(':ask', speechText, repromptText); 
    }, 
    "Unhandled": function() { 
     var speechText = snippets.UNHANDLED; 
     this.emit(":ask", speechText); 
    }, 

    // User says stop. Stops even in the middle of a response. 
    "AMAZON.StopIntent": function() { 
     var speechText = snippets.STOP; 
     this.emit(":tell", speechText); 
    }, 

    // unclear really what the difference is; default working practice is 
    // to do the same thing 
    // in a production system we'd probably dedupe this function. 
    "AMAZON.CancelIntent": function() { 
     var speechText = snippets.STOP; 
     this.emit(":tell", speechText); 
    }, 
    "AMAZON.StartOverIntent": function() { 
     this.emit("Start") 
    }, 

    // TODO determine when this is requested and what initiates it 
    // Implement handler to save state if state should be stored persistently e.g. to DynamoDB 
    // 'SessionEndedRequest': function() { 
    //  console.log('session ended!'); 
    //  this.emit(':saveState', true); 
    // } 

    // TODO add 'AMAZON.RepeatIntent' that repeats the last question. 

}); 



var dobStateHandlers = Alexa.CreateStateHandler(states.DOB, { 

    'DateOfBirthIntent': function() { 

     var speechText = "", 
      repromptText = ""; 

     var date_string = this.event.request.intent.slots.dob.value; 
     var date = moment(date_string); 

     if (date.isValid()) { 

      if (!isFutureDate(date)) { 
       // ALL GOOD – dob not in the future 
       speechText = snippets.GENDER; 
       repromptText = snippets.GENDER_REPROMPT; 
       this.attributes['dob'] = date_string; 

       if(isGenderNeeded(date)) { 
        // Transition to next state 
        this.handler.state = states.GENDER; 
        // this.emit(":saveState", false); 
        this.emit(':ask', speechText, repromptText); 

       } else { 
        // gender not needed 
        // this.attributes['gender'] = "unisex"; 
        this.handler.state = states.ANSWER; 
        // this.emit(":saveState", false); 
        this.emit("Answer") 

       } 



      } else { 
       // dob in the future 
       speechText = snippets.DATEOFBIRTH_INVALID_FUTURE; 
       // this.emit(":saveState", false); 
       repromptText = snippets.DATEOFBIRTH_INVALID_FUTURE; // could be improved by using alternative prompt text 
       this.emit(':ask', speechText, repromptText); 
      } 

     } else { 
      // not a valid Date 
      speechText = snippets.DATEOFBIRTH_INVALID; 
      // this.emit(':saveState', false); 
      repromptText = snippets.DATEOFBIRTH_INVALID; // could be improved by using alternative prompt text 
      this.emit(':ask', speechText, repromptText); 
     } 
    }, 
    "AMAZON.HelpIntent": function() { 
     var speechText = snippets.HELP; 
     var repromptText = snippets.HELP_REPROMPT; 
     this.emit(':ask', speechText, repromptText); 
    }, 
    "Unhandled": function() { 
     var speechText = snippets.UNHANDLED; 
     this.emit(":ask", speechText); 
    }, 
    "AMAZON.StopIntent": function() { 
     var speechText = snippets.STOP; 
     this.emit(":tell", speechText); 
    }, 
    "AMAZON.CancelIntent": function() { 
     var speechText = snippets.STOP; 
     this.emit(":tell", speechText); 
    }, 
    "AMAZON.StartOverIntent": function() { 
     this.emit("Start") 
    }, 
    'SessionEndedRequest': function() { 
     // this.emit(':saveState', false); 
     // this.attributes['dob'] = date_string; 
     // this.attributes['dob'] = date_string; 
     console.log('session ended!'); 
    } 
}); 


var genderStateHandlers = Alexa.CreateStateHandler(states.GENDER, { 
    'GenderIntent': function() { 
     var speechText = "", 
      repromptText = ""; 

     var gender = this.event.request.intent.slots.gender.value; 

     if (isGenderSlotValid(gender)) { 
      // valid gender 
      this.attributes['gender'] = gender; 
      this.handler.state = states.ANSWER; 

      this.emit(':saveState', false); 
      this.emit("Answer"); 
     } else { 
      // not a valid gender 
      speechText = snippets.GENDER_INVALID; 
      repromptText = snippets.GENDER_INVALID; // could be improved by using alternative prompt text 

      this.emit(':saveState', false); 
      this.emit(':ask', speechText, repromptText); 
     } 
    }, 
    "AMAZON.HelpIntent": function() { 
     var speechText = snippets.HELP; 
     var repromptText = snippets.HELP_REPROMPT; 
     this.emit(':ask', speechText, repromptText); 
    }, 
    "Unhandled": function() { 
     var speechText = snippets.UNHANDLED; 
     this.emit(":ask", speechText); 
    }, 
    "AMAZON.StopIntent": function() { 
     var speechText = snippets.STOP; 
     this.emit(":tell", speechText); 
    }, 
    "AMAZON.CancelIntent": function() { 
     var speechText = snippets.STOP; 
     this.emit(":tell", speechText); 
    }, 
    "AMAZON.StartOverIntent": function() { 
     this.emitWithState("Start") 
    }, 
    'SessionEndedRequest': function() { 
     this.emit(':saveState', false); 
     console.log('session ended!'); 
    } 
}); 



var answerStateHandlers = Alexa.CreateStateHandler(states.ANSWER, { 
    'Answer': function() { 
     console.log(`##### START INPUT SNIPPETS #####`); 
     // var dob = 
     // var gender = ; 

     console.log(`this.attributes.dob: "${this.attributes.dob}"`); 
     console.log(`this.attributes.gender: "${this.attributes.gender}"`); 

     var pensionDate = calculator.calculatePension(this.attributes.dob, this.attributes.gender); 
     console.log(`pensionDate: "${pensionDate}"`); 

     var speechText = calculator.createPensionSnippet(pensionDate); 

     // Change State to Start again 
     this.handler.state = states.START; 
     this.emit(':tell', speechText); 

     console.log(`##### STOP SNIPPET #####`); 
     console.log(``); 

    }, 
    "Unhandled": function() { 
     var speechText = snippets.UNHANDLED; 
     this.emit(":ask", speechText); 
    } 
}); 



function isGenderSlotValid(gender) { 
    if (gender == "male" || gender == "female") { 
     return true 
    } else { 
     return false 
    } 
} 


function isFutureDate(dob) { 
    var today = moment(); 

    if (dob > today) { 
     return true 
    } else { 
     return false 
    } 
} 

function isGenderNeeded(dob) { 
    return dob < GENDERCUTOFFDATE; 
} 




exports.handler = function(event, context, callback) { 
    var alexa = Alexa.handler(event, context); 
    alexa.appId = process.env.appId; 
    // alexa.appId = "your skill ID"; // better store it as ENV variable at AWS Lambda 
    // alexa.resources = languageStrings; 

    // register intent handlers for each state + new session. 
    // Each state constrains possible intents Alexa is listening for. 
    // If you only have one handler you are context-free and cannot have state. 
    alexa.registerHandlers(newSessionHandlers, startStateHandlers, dobStateHandlers, genderStateHandlers, answerStateHandlers); 
    alexa.execute(); 
}; 
+0

なぜあなたは 'this.emit(":saveState "、false)'をやっていますか?率直に言って私は2番目のパラメータが何であるか分かりません(私は[公式説明](https://github.com/alexa/alexa-skills-kit-sdk-for-nodejs)が不明であることが分かります)。私は 'false'引数は基本的に状態を保存しないスキルを教えてくれると思います。 – spicypumpkin

答えて

-1

あなたは、このようにそれらにアクセスしてみました:あなたはthis.emit("...")後に「;」の数が不足している

this.attributes['gender']. 
0

、彼らは任意でよいが、私はそれらを追加したいです。

はまた、なぜあなたはそれが内部GENDER

最後に、私は私の状態変数を参照する以外の多くの場所でコメントアウトされます

this.emit(':saveState', false); 

を使用しているより良いエラー検出

ため"strict mode"を有効にしてくださいas

this.attributes['gender'] 

試しても悪いことではありません。

0

可能性1:

this.emit(':saveState', false);

は、DynamoDBのデータベースにデータを保存するために使用されます。データベースに保存しているようには見えないので、このコード行は不要です。 Alexaはユーザーセッション中に変数を保持し、スキルタイムアウトまたはユーザーがスキルを終了したときに忘れ去られます。

存在しないデータベースに保存しようとするミックスアップがあり、それがドロップされたデータの原因です。

alexa.dynamoDBTableName = 'YourTableName'; // That's it!

アドバイス:あなたは、コードの1行を追加するとそれは同じくらい簡単だアレクサノードSDK https://github.com/alexa/alexa-skills-kit-sdk-for-nodejs

で見つかった指示に従ってデータベースに保存するに興味があるなら

:すべての保存状態指示文を削除する

可能性2:

複数の状態が奇妙にリンクされています。このコードで

if (isGenderSlotValid(gender)) { 
     // valid gender 
     this.attributes['gender'] = gender; 
     this.handler.state = states.ANSWER; 

     this.emit(':saveState', false); 
     this.emit("Answer"); 
    } 

ユーザーは'GenderIntent'あなたは性別が何であるかを決定しました、その後、あなたは別の意図"Answer"を呼び出すを呼び出しています。私はあなたに "データを保存しようとする"の意思表示を見ますが、上記のようにthis.emit(':saveState', false);はローカルにはデータベースに保存されません。:askまたは:tellのセッション属性は、新しいインテントハンドラAnswerに切り替えてから:askまたは:tellを返す前にセッション属性が保存される可能性が非常に高いです。以前のイベントハンドラを書き込んだり破棄したりする可能性があります。gender ' s、アクション。

アドバイス:コードをAnswerからgenderに移動してください。必要な情報をすべて取得したら、別のハンドラにジャンプする必要はありません。

 if (isGenderSlotValid(gender)) { 
     // valid gender 
     this.attributes['gender'] = gender; 

     var pensionDate = calculator.calculatePension(this.attributes.dob, this.attributes.gender); 
     console.log(`pensionDate: "${pensionDate}"`); 

     var speechText = calculator.createPensionSnippet(pensionDate); 

     // Change State to Start again 
     this.handler.state = states.START; 
     this.emit(':tell', speechText); 
    } 

PSあなたはDOBで同じことを実行します。

} else { 
      // gender not needed 
      // this.attributes['gender'] = "unisex"; 
      this.handler.state = states.ANSWER; 
      // this.emit(":saveState", false); 
      this.emit("Answer") 

    } 

は、あなたの答えの状態を削除し、これらの機能の両方にその機能を動かし、それはただ、追加this.emit("Answer")

0

を言う場所:

'SessionEndedRequest': function() { 

    console.log('session ended!'); // Optional 
    this.emit(':saveState', true); 

} 

他のインテントの横にあるハンドラ関数では、ユーザーが予期せずセッションを終了するたびにデータを保存します。

関連する問題