6

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]
Jedi
  • 3,088
  • 2
  • 28
  • 47
two7s_clash
  • 5,755
  • 1
  • 27
  • 44
  • Could you give the entire relevant log output? Since there's no [mcve], I cannot reproduce it, so I'd like to get an idea of what's happening. Among other things, I'm interested if there's a `[WARN]` or `[ERROR]` in front of the error message you gave - i.e. if it's your code from the snippet that's printing it or something else. – ivan_pozdeev Apr 27 '17 at 20:50
  • @ivan_pozdeev let me know what other info you need – two7s_clash Apr 28 '17 at 01:48

2 Answers2

1

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.

Jon Church
  • 2,320
  • 13
  • 23
  • If you look at my updates above, you can see that message.text isn't an empty string. And that I was force returning a string in my latest efforts. – two7s_clash Apr 28 '17 at 13:24
  • The first line of my answer is the same fix that the other user suggested, your alexaAppName is not setup, and running `claudia update --configure-alexa-skill` will fix that. Nowhere in your update do you mention setting `message.text === 'any string'`. I got your actual code working by my answer, try it out. – Jon Church Apr 28 '17 at 14:28
  • @two7s_clash If you stuck your updated code into the same block if statement that relied on `message.text` then that would not be executing either. Also, none of this will work until you follow the first step in my answer, anyways. – Jon Church Apr 28 '17 at 14:31
  • If you read the question, I state that everything works fine on FB and slack... furthermore, `message.text` has always had a value in my tests etc. Even with Alexa ...`message.text` is the user input that botBuilder gets from the user. +1 to you, but @Aperçu got the answer completely correct, and was the first response with the solution. – two7s_clash Apr 28 '17 at 14:48
  • Hmm now I'm curious about what your slots are for this intent. Would you mind elaborating? Message.text is parsed differently for Slack, FB, Viber, Alexa, etc by Claudia depending on where the request comes from. And for Alexa, claudia [concatenates the slot values](https://github.com/claudiajs/claudia-bot-builder/blob/master/lib/alexa/parse.js#L13) So you got your original code working fine now? I was unable to get the full user utterance, how did you do that? – Jon Church Apr 28 '17 at 14:57
  • Ahh, so I'm being tricky here and just passing everything the user says to that second lambda function (which is a hand-rolled NLP). I.e. I use Alexa for text-to-speech round-tripping only. `{ “intents”: [ { “intent”: “GetUserIntent”, “slots”: [ { “name”: “phrase”, “type”: “phrase” } ] } ] } ` Slot name: phrase, GetUserIntent {phrase} – two7s_clash Apr 28 '17 at 18:49
1

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.

Preview
  • 35,317
  • 10
  • 92
  • 112