Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

issues with Claudia.js text responses and Alexa

I'm working on a Claudia.js bot that can be reached through Slack, FB messenger, and as an Alexa skill. Supposedly in claudia, you can return plain text and the framework will give it back to the "frontend" correctly... What I have currently have here works fine with FB and Slack, but when I access it through the Alexa "Service Simulator" I always get "The response is invalid." Here is the lambda that uses Claudia.js. Basically it gets messages from the client and then shunts them to another Lambda that is the "AI". Alexa seems to be choking on line 67. Ideas?

const promiseDelay = require('promise-delay');
// const aws = require('aws-sdk');
// const lambda = new aws.Lambda();
const lambda = require('aws-lambda-invoke');

const botBuilder = require('claudia-bot-builder');

const stackTrace = require('stack-trace');

//const slackDelayedReply = botBuilder.slackDelayedReply;
const getIntentName = alexaPayload =>
    alexaPayload &&
    alexaPayload.request &&
    alexaPayload.request.type === 'IntentRequest' &&
    alexaPayload.request.intent &&
    alexaPayload.request.intent.name;


const api = botBuilder((message, apiRequest) => {
  console.log = console.log.bind(null, '[LOG]');
  console.info = console.info.bind(null, '[INFO]');
  console.error = console.error.bind(null, '[ERROR]');
  console.warn = console.warn.bind(null, '[WARN]');

  console.info(message, apiRequest);
  console.log(apiRequest.body);

  const requestData = {
    'user-id': {
      type: message.type,
      ID: message.sender
    },
    epoch: 1484771343.01,
    'payload-type': 'luis',
    facets: {},
    utterance: 'Seek Showtimes',
    payload: {
      query: 'Seek Showtime',
      topScoringIntent: {
        intent: 'SeekShowtime',
        score: 1.0
      },
      intents: [{
        intent: 'SeekShowtime',
        score: 1
      }],
      entities: []
    }
  };
  if (message.text) {
    return new Promise((resolve, reject) => {
      lambda.raw.invoke({
        FunctionName: 'ca2',
        Payload: JSON.stringify(requestData),
      }, (err, done) => {
        if (err) {
          const trace = stackTrace.parse(err);
          console.warn(err);
          console.error(trace);
          return reject(err);
        }
        resolve(done);
      });
    }).then((result) => { // the initial response
      const payload = JSON.parse(result.Payload);
      console.log(payload.utterance);
      return payload.utterance;
    }).catch((error) => {
      const trace = stackTrace.parse(error);
      console.warn(error);
      console.error(trace);
      return 'Could not setup';
    });
  } else if (getIntentName(apiRequest.body) === 'ExitApp') {
    return {
      response: {
        outputSpeech: {
          type: 'PlainText',
          text: 'Bye from Bot!'
        },
        shouldEndSession: true
      }
    };
  } else {
    return {};
  }
},
{ platforms: ['facebook', 'slackSlashCommand', 'alexa'] }
);

module.exports = api;

Update -- even if I hardcode a plain text string response or use Alexa Message Builder I still get "The response is invalid." as the Service Response is coming back "undefined."

Looking at logs, as soon as the response is returned (for parsing by botBuilder and a pass to Alexa) this error occurs [TypeError: Cannot read property 'replace' of undefined]


Another update:

If I replace return payload.utterance with something like

if (type === 'alexa-skill') {
        Console.warn('trying to contact alexa');
        return "Hi from Alexa";
      }

The problem persists.

Here is where the Json Request comes in, no problem:

2017-04-27T18:06:30.552Z    3d70c273-2b74-11e7-a1c8-bf3fec00cbff    STORE Map { "user-id": Map { "type": "alexa-skill", "ID": "amzn1.ask.account.AF6FUNJDSHGCXPVSAO5HUSRYFBD3SPCJJLILC4HLPS3K3L4AOWIMXPS4ZDDCXQ3ZVIV5L4FOMYD23PWZXEIAKYQBVXIQTPE2WW2PMBIXQIY3TUATXADCVNYO7NYUR2B45EU5GRIWBFHQIPLQVDQZMXD7IYVGTKAV3OWPHROCPR7XIUGNSJEAGQZJOMULSKT5HYSNUNJONASE34Y" }, "epoch": 1484771343.01, "payload-type": "luis", "utterance": "when is Logan playing", "payload": Map { "query": "when is Logan playing" } }

Here is the response I get back from the other lambda (the payload):

017-04-27T18:06:32.513Z 3d70c273-2b74-11e7-a1c8-bf3fec00cbff    [LOG] mnlpData { StatusCode: 200,
Payload: '{"utterance": "To find movies playing near you, I need to know where you are. Please tell me your zip code.", "AskLocation": 1, "context": {"updated": 1493316392.162429, "user_id": "TEST_ID_TUES_14", "sessions": [{"intents": ["SeekShowtime", "SeekShowtime"], "facet-delta": {}, "facets": {"ity.location": {"ity.zip": "", "ity.code": "", "ity.theatre-name": ""}, "ity.movie": {"ity.title": "", "ity.code": ""}, "ity.time": [], "ity.date": []}, "modes": ["", "SHOWTIME_SWITCH", "AskLocation", "SHOWTIME_SWITCH", "AskLocation"]}], "created": 1493316379.950335, "mode_process_count": 2, "user-id": {"type": "alexa-skill", "ID": "amzn1.ask.account.AF6FUNJDSHGCXPVSAO5HUSRYFBD3SPCJJLILC4HLPS3K3L4AOWIMXPS4ZDDCXQ3ZVIV5L4FOMYD23PWZXEIAKYQBVXIQTPE2WW2PMBIXQIY3TUATXADCVNYO7NYUR2B45EU5GRIWBFHQIPLQVDQZMXD7IYVGTKAV3OWPHROCPR7XIUGNSJEAGQZJOMULSKT5HYSNUNJONASE34Y"}, "utterance": ["To find movies playing near you, I need to know where you are. Please tell me your zip code."]}}' }

then:

2017-04-27T18:06:32.514Z    3d70c273-2b74-11e7-a1c8-bf3fec00cbff    [WARN] trying to contact alexa

and then the error:

2017-04-27T18:06:32.514Z    3d70c273-2b74-11e7-a1c8-bf3fec00cbff    [TypeError: Cannot read property 'replace' of undefined]
like image 281
two7s_clash Avatar asked Apr 18 '17 15:04

two7s_clash


2 Answers

First, if you notice the payload that is sent to you from the other lambda, you can see the utterance is an array, so you might have to pass the first element if present.

By looking at the code of the bot builder, my best bet is that the error you're getting is due to the fact your alexaAppName is undefined, and when passing it down to the responder that is encoded in base64, it's not possible to run a replace of this variable.

I would try to make sure my app name is correctly configured and what's given is a valid string as shown in the alexa claudia example.

like image 57
Preview Avatar answered Sep 22 '22 17:09

Preview


If you haven't already, run claudia update --configure-alexa-skill and enter your bot's name, then use the url it gives in your alexa skill builder setup. Select HTTPS instead of lambda arn.

Currently, message.text is being passed as an empty string, which means that none of your log blocks are firing, and you are returning an empty object at the very bottom of your code. Test it yourself by replacing that empty object with a string, the alexa tester no longer complains.

So why is message.text an empty string? Claudia js populates the text field by concatenating all the slots that have been filled for your intent. If your intent has no slots, then claudia passes an empty string.

Add slots to your intent, make sure the skill is configured, and fix the logic statement issues.

like image 45
Jon Church Avatar answered Sep 20 '22 17:09

Jon Church