Lex & Lambda: Slots Being Set Manually Reset to Null - node.js

Building a bot in which we fulfill an intent in a Lambda function. In this function, based on a user's selection, we have to set two slots to certain values.
The slots in question are "userResponse," "chatType," and "segment."
The code attempts to fill the latter slots based on the userResponse slot. Looks something like this:
let requestedService = event.currentIntent.slots.userResponse;
if (requestedService === "a") {
event.currentIntent.slots.segment = 'a';
event.currentIntent.slots.chatType = 'a';
} else {
event.currentIntent.slots.segment = 'b';
event.currentIntent.slots.chatType = 'b';
}
Thus, upon code running, the slots may look like this:
{
"userResponse": "a",
"chatType": "a",
"segment" "a"
}
Now that we've fulfilled all of our slots, we pass the fulfill intent dialog action back to Lex.
callback(null, {
"sessionAttributes": event.sessionAttributes,
"dialogAction": {
"type": "Close",
"fulfillmentState": "Fulfilled",
"message": {
"contentType": "PlainText",
"content": "Please wait"
}
}
});
The problem is, when I send this information back to Lex, the slots that I've just manually set are somehow wiped out and returned to Lex as null, so that the slots are like this:
{
"userResponse": "a",
"chatType": null
"segment" null
}
No other code is present between setting the slot values and then calling the dialog action. In this Lambda function's CloudWatch log, I've console logged the event just prior to the dialog action call and it shows the slots as being fulfilled. And yet...somehow, Lex is not getting those slots back with the correct data.
Is there something I'm missing? Why is Lex receiving null values when they're not null in Lambda?

According to the document, I think you have to introduce the slots in the response object:
callback(null, {
"sessionAttributes": event.sessionAttributes,
"dialogAction": {
"type": "Close",
"fulfillmentState": "Fulfilled",
"stols": event.currentIntent.slots, // this change
"message": {
"contentType": "PlainText",
"content": "Please wait"
}
}
});

Related

Missing element in SOAP API request using Python's Zeep, but the element is in the request dictionary

i'm using Zeep to interact with Workday's SOAP API to edit a someone's Workday username. Here is the following request body to the Human Resources WSDL, v37.2
request_dict = {
"Workday_Account_for_Worker_Update": {
"Worker_Reference": {
"Employee_Reference": {
"Integration_ID_Reference": {
"ID": {
"type": "WD-EMPLID",
"_value_1": user_id
}
}
}
},
"Workday_Account_for_Worker_Data": {
"User_Name": username
}
}
}
response = client.service.Update_Workday_Account(request_dict)
The error message i receive is
zeep.exceptions.ValidationError: Missing element Workday_Account_for_Worker_Data (Workday_Account_for_Worker_Update.Workday_Account_for_Worker_Data), but the element is clearly there. Anyone have any idea what I'm doing wrong?
You are not using the correct method signature to perform the call.
If you do a:
python -mzeep https://community.workday.com/sites/default/files/file-hosting/productionapi/Human_Resources/v37.2/Human_Resources.wsdl > output.txt
and you look inside the produced output.txt file, you will see that Update_Workday_Account has this signature:
Update_Workday_Account(
Worker_Reference: ns0:Worker_ReferenceType,
Non_Worker_Reference: ns0:RoleObjectType,
Workday_Account_for_Worker_Data: ns0:Workday_Account_for_Worker_DataType,
version: xsd:string,
_soapheaders={header: ns0:Workday_Common_HeaderType}
) -> None
so your code should probably be something like this:
worker_reference = {
"Employee_Reference": {
"Integration_ID_Reference": {
"ID": {
"type": "WD-EMPLID",
"_value_1": user_id
}
}
}
}
workday_account_for_worker_data = {
"User_Name": username
}
client.service.Update_Workday_Account(worker_reference, None, workday_account_for_worker_data)
I can't really test the call from my side so you should substitute appropriate parameters on your side before making the request.

microsoft bots to teams using nodejs fails with missing activityid when updating the same activity

My code has a simple card carousel which has action button like below:
actions = [
{
"type": "Action.Submit",
"title": "Qualify",
"data": { "action" : "qualify_lead" }
},
{
"type": "Action.OpenUrl",
"title": "Retire",
"url": "{viewUrl}"
},
{
"type": "Action.ShowCard",
"title": "Add Note",
"card": this.noteCard(item.LeadId, "leads")
}
]
I am having a method to handle qualify_lead action like below
async qualifyLead(context:any){
console.log("in qualifyLead:" + JSON.stringify(context.activity))
await context.updateActivity(this.successCard('Lead is qualified'))
}
All I am doing on purpose is to replace entire carousel with a simple text message. But it fails with error:
Error: BotFrameworkAdapter.updateActivity(): missing activity.id
Where do i get this ?
I am using google firebase for this and the wrapper code is like below
const {
TurnContext,
TeamsActivityHandler,
CardFactory,
AttachmentLayoutTypes,
ActionTypes
} = require('botbuilder');
class TeamsConversationBot extends TeamsActivityHandler {
constructor() {
super();
this.leadState =
this.conversationState.createProperty('leadCarouselState');
this.onMessage(async (context:any, next:any) => {
TurnContext.removeRecipientMention(context.activity);
let msg = context.activity.text
const action = context.activity.value
let objNum = ''
let keyword = ''
if(msg === undefined && action === undefined)
msg = 'help'
else if(msg !== undefined){
msg = msg.trim().toLowerCase()
if(msg.indexOf("help") > -1)
msg = 'help'
else{
if(msg.startsWith('lead')){
msg = 'lead'
}
}
}
switch (msg) {
case 'lead':
await this.lead(context, userKey, platform)
break;
case 'qualify_lead':
await this.qualifyLead(context)
break;
}
await next();
});
}
I'm not sure exactly what this.successCard('Lead is qualified') does, but presumably it returns an Activity. To my knowledge, in order for this Activity to replace another one, you need to set it's Id property to match the previous message. That means that, when you send the previous message (i.e. the card), you need to capture the reference that's returned from the send method on the context (e.g. into bot state), and then use it for this new activity.
As I explained in my answer to your other question, you need to save the activity ID in bot state and then apply it to the update that you're sending. The Bot Framework can't update an activity unless you tell it which activity to update, and you do that using an activity ID.
This was the part that saves the ID:
const dict = await this.carouselState.get(turnContext, {});
dict[batchId] = {
[KEYACTIVITYID]: response.id,
[KEYLEADS]: leads
};
And this was the part that applies it to the updated activity:
const update = this.createCarousel(batchId, leads);
update.id = info[KEYACTIVITYID];

IOTHubMessage.forEach is not a function?

Can anyone tell me how to parse this problem?
I have an thrown error message that when i create azure cosmossDB, my cosmosDB output binding thrown message that IOTHubMessage.forEach is not a function;
module.exports = function (context, IoTHubMessages) {
context.log(`JavaScript eventhub trigger function called for message array: ${IoTHubMessages}`);
var count = 0;
var totalTemperature = 0.0;
var totalHumidity = 0.0;
var deviceId = "*****";
IoTHubMessages.forEach(message => {
context.log(`Processed message: ${message}`);
count++;
totalTemperature += message.temperature;
totalHumidity += message.humidity;
deviceId = message.deviceId;
});
var output = {
"deviceId": deviceId,
"measurementsCount": count,
"averageTemperature": totalTemperature / count,
"averageHumidity": totalHumidity / count
};
context.log('Output content: ${output}');
context.bindings.outputDocument = output;
context.done();
};
What am i missing? Please assist, thanks.
It wasn't included in your answer, but the issue is most likely in your functions.json file. The bindings for IoTHub by default only handle one message at a time. This means that your IoTHubMessages isn't an array, but a single object. You need to change cardinality from one to many.
To change this, edit your functions.json file to include a cardinality property.
{
"type": "eventHubTrigger",
"name": "eventHubMessages",
"direction": "in",
"eventHubName": "MyEventHub",
"cardinality": "many",
"connection": "myEventHubReadConnectionAppSetting"
}
In case you made this function in the portal, you can change the cardinality of the binding in the Integrate part of the function:

Gmail API - How to Request Only one Name/Value Pair from Email Payload Headers?

How can we capture only the email address in an api response for the gmail API. The
fields parameter is set to payload/headers, which returns way more data than we need in the response.
All we need is the value from one name/value pair in the JSON response; for example
The full response as we have it now looks something like this
{
"payload": {
"headers": [
{
"name": "Delivered-To",
"value": "xxxxxxx"
{
"name": "Received",
"value": "xxxxxxxx"
},
{
"name": "Received-SPF",
"value": "----"
},......
{
"name": "To",
"value": "xxxxxxx"
}, ...... E.T.C........E.T.C ......
/*All we want is one name/value pair to be returned e.g. */
{
"payload": {
"headers": [
{
"name": "X-Failed-Recipients",
"value": "............."
}
]
}
A better question might be is there a better way to capture bounced/returned mail than this via the gmail API?
Also, is it possible to request an XML response instead of JSON. How can that be done for the gmail API?
Thanks !!
You can do messages.get(format=METADATA, metadataIncludeHeaders=["To", "From", "Subject"]) for example, now to just request the specific headers you care about . Note this only works with the metadata format (it won't include the body also, if you want all the body you get the full email. Based on the list of headers, shouldn't be too hard to turn that into a map/dict of key => [list, of, values].
As to your second question, yes you can definitely request response in any format you want. That's a standard Google API question though. I can't find a good reference (surely some searching will) but typically you can set an "alt=xml" or "alt=" query parameter to get response in that format. Not sure how this is exposed in any particular client library.
First you need to get your message payload and then you want to use the getall method to return a list of headers and then you can use the getitem to pull any specific header you want from that list.
I converted the String into a String and took it as a JSON Array and iterated through it to take the JSON Object that I required.
private static DirtyMail getHeaderParts(DirtyMail mail, List<MessagePartHeader> headers)
{
try {
//Convert the header into JSON Array for easy processing of data.
JSONArray headerArray = new JSONArray(headers.toString());
for(int n = 0; n < headerArray.length() ; n++) {
JSONObject jsonObject = headerArray.getJSONObject(n);
//Pull date
if(jsonObject.get(Constants.DATE)!=null) {
mail.setDate(jsonObject.getString(Constants.DATE));
}
//Pull Subject
//Pull reply-to address
//Pull delivered-from address
//Pull delivered-to address
Log.d(TAG, "JSON Object : "+ jsonObject);
}
//Log.d(TAG,"header String: "+headers.toString());
} catch (Exception e) {
e.printStackTrace();
}
return mail;
}
I kept these values in the Constant class :
// Data pulled from inside the header
public static final String DATE = "Date";
public static final String SUBJECT = "Subject";
public static final String REPLY_TO = "Reply-To";
public static final String DELIVERED_TO = "Delivered-To";
public static final String FROM = "From";
I don't know if this is the best fix for this, but this works and gives the data as I require.

Website Message Box by Automating InternetExplorer with VBA Excel

I am in the process of automating a process to fill up a website. With an Excel Macro, once I log into the website, insert a value in the required textbox and click the button, a website Message Box comes up with an alert asking me to confirm - Are you sure to update the value?
The execution of the macro stops at that level, resulting in no further execution of the macro.
On searching for the solution, I found out that a JavaScript function, the function which is executed on confirmation of the message box, should be called from macro instead of clicking the original button on the webpage.
I would like to have help in writing the code to call JavaScript function in Excel Macro.
Following is the HTML code from the view source page of the webpage.
$('#reloadButton').click(function () {
$(this).text(
$(this).attr('name')
).attr('disabled', 'disabled');
window.location.href = window.location.href.replace(/#.*$/, '');
});
SignalConsumer = function () {};
SignalConsumer.prototype = new TraderSettingsTool();
SignalConsumer.prototype.mySummaryPage = 'https://kvinvest.com/month/?action=template&tid=my_status';
SignalConsumer.prototype.isShowWaiver = 0;
SignalConsumer.prototype.amountPrecision = 1;
SignalConsumer.prototype._elements = {
"trading": {
"popup": $('#ssc-trading-popup'),
"amount": $('#ssc-trading-amount'),
"trade": $('#ssc-trading-trade'),
"provides": $('#ssc-trading-provides')
},
"slippage": {
"popup": $('#ssc-slippage-popup')
},
"provider": {
"popup": $('#ssc-provider-popup')
},
"consumers":{
"holder": $('#ssc-consumers-holder'),
"template": $('#ssc-consumers-template'),
"form": $('#ssc-consumers-form')
},
"subscribe": {
"server": $('#ssc-subscribe-server'),
"apply": $('#ssc-subscribe-apply'),
"loader": $('#ssc-subscribe-loader'),
"info": $('#ssc-subscribe-info'),
"form": $('#ssc-subscribe-form'),
"description": $('#ssc-subscribe-description')
},
"activate": {
"form": $('#ssc-activate-form'),
"slippage": $('#ssc-activate-slippage'),
"amount": $('#ssc-activate-amount'),
"popup": $('#ssc-activate-popup'),
"apply": $('#ssc-activate-apply'),
"cancel": $('#ssc-activate-cancel'),
"agree": $('#ssc-activate-agree'),
"sll": $('#ssc-activate-sll-value'),
"loader": $('#ssc-activate-sll-loader'),
"redirect": $('#ssc-activate-redirect')
},
"waiver": {
"popup": $('#ssc-waiver-popup'),
"agree": $('#ssc-waiver-agree'),
"apply": $('#ssc-waiver-apply'),
"subscribe": $('#ssc-waiver-subscribe')
},
"history": {
"log": $('#ssc-history-log')
}
};
SignalConsumer.prototype.bindEvents = function () {
var self = this;
this._elements.subscribe.form.find('form').submit(function () {
return false;
});
// I THINK BELOW IS THE MESSAGE BOX POP UP
this._elements.subscribe.apply.click(function () {
if(!confirm('Are you sure to update?')){
return false;
}
self.subscribeToServer();
return false;
});
// On show history popup
this._elements.history.log.click(function () {
self.loadHistoryLog();
return false;
});
// --- ACTIVATION LOGIC ---
this._elements.activate.apply.click(function () {
self.applyActivateServer();
return false;
});
this._elements.activate.agree.change(function () {
var disabled = $(this).is(':checked') ? '' : 'disabled';
self._elements.activate.apply.attr('disabled', disabled);
});
this._elements.activate.cancel.click(function () {
self.hidePopUp();
return false;
});
this._elements.activate.redirect.click(function () {
self.hidePopUp();
});
Well, what I won't do in this answer is provide the code that you request.
This answer is more like a suggestion since I'm not entirely sure about where you are going with this and if the technical approach that you suggest is what you are actually looking for.
It doesn't make a lot of sense to me, to connect the VBA engine with a web client unless you're aiming at retrieval of data only - such as for example a web query.
If you want to create an interactive data flow between the VBA engine and a web application, it seems more logical to create a connection with a server side script (written in PHP or ASP) that is connected to a database system (or if you want to store values in temporary session variables for that matter).
The fact that a user inputs a value, followed by a button click suggests that you want to build in a certain calculation logic. This is typically done on the server, and not browser level.
Therefore what I suggest you do is:
Javascript/jQuery -> PHP/ASP -> VBA
If that makes any sense to you.

Resources