Write a conditional AWS Lambda Function for AWS LEX - javascript

I am newbie in AWS Arena. This is my 2nd question regarding AWS Lambda function and AWS LEX. I want to write a lambda function to trigger 2 different intents based on the value of something without any user Utterance. For example
if a >= 90.....Intent-1 will work and say "Messi is the best Footballer" and
if a < 90......Intent-2 will work and say "Ronaldo is the best Footballer"

It is not supposed to work like that, intents are triggered based on what user types. For example, you can make an intent BestFootballer and it will be triggered on utterance who is the best footballer.
Now, once the intent is triggered you can apply some logic to dynamically create a response.
def build_response(message):
return {
"dialogAction":{
"type":"Close",
"fulfillmentState":"Fulfilled",
"message":{
"contentType":"PlainText",
"content":message
}
}
}
def perform_action(intent_request):
source = intent_request['invocationSource']
output_session_attributes = intent_request['sessionAttributes'] if intent_request['sessionAttributes'] is not None else {}
if source == 'FulfillmentCodeHook':
a = 100
if a < 90:
return build_response('Ronaldo is the best Footballer')
else:
return build_response('Messi is the best Footballer')
def dispatch(intent_request):
intent_name = intent_request['currentIntent']['name']
if intent_name == 'BestFootballer':
return perform_action(intent_request)
raise Exception('Intent with name ' + intent_name + ' not supported')
def lambda_handler(event, context):
return dispatch(event)
Hope it helps.

Related

Scrapy Splash, How to deal with onclick?

I'm trying to scrape the following site
I'm able to receive a response but i don't know how can i access the inner data of the below items in order to scrape it:
I noticed that accessing the items is actually handled by JavaScript and also the pagination.
What should i do in such case?
Below is my code:
import scrapy
from scrapy_splash import SplashRequest
class NmpaSpider(scrapy.Spider):
name = 'nmpa'
http_user = 'hidden' # as am using Cloud Splash
allowed_domains = ['nmpa.gov.cn']
def start_requests(self):
yield SplashRequest('http://app1.nmpa.gov.cn/data_nmpa/face3/base.jsp?tableId=27&tableName=TABLE27&title=%E8%BF%9B%E5%8F%A3%E5%8C%BB%E7%96%97%E5%99%A8%E6%A2%B0%E4%BA%A7%E5%93%81%EF%BC%88%E6%B3%A8%E5%86%8C&bcId=152904442584853439006654836900', args={
'wait': 5}
)
def parse(self, response):
goal = response.xpath("//*[#id='content']//a/#href").getall()
print(goal)
If you use some breakpoints you'll see its a frustrating job that I explain what I understood from my research.
when you are working with this kind of situation you have two ways:
1 - [Easy Way] use selenium and open a browser and click on each link and get the returned contents easily, you can run multiple browsers and get link contents simultaneously.
2 - [Hard Way] simulate what website does (by making similar functions inside python) and do exactly what website does in JS but in the end instead of showing the results, just save it in a variable and use it the way you want.
Now if you choose the HARD WAY this is what I found:
the link JS is like this:
commitForECMA(callbackC,'content.jsp?tableId=26&tableName=TABLE26&tableView=国产医疗器械产品(注册&Id=138150',null)
it calls a function named commitForECMA and get what this function returns and pass it to callBackC function.
well this was obvious, but its important to know what these functions do and how to replicate it.
commitForECMA:
this is the function:
function commitForECMA($_8, $_10, $_12) {
request = createXMLHttp();
request.onreadystatechange = $_8;
if ($_12 == null) {
_$du(request, _$Fe('uM6r2MG'), _$Fe("jp0YV"), $_10);
request.setRequestHeader(_$Fe("XACeXwDYXwcTV8Ur2"), _$Fe("YwDYgwceLwDT7iCYX3Ce9FKyvHKwPFa"));
} else {
var $_9 = "";
var $_19 = $_12.elements;
var $_0 = $_19.length;
for (var $_18 = 0; $_18 < $_0; $_18++) {
var $_14 = _$3P($_19, $_18);
if ($_14.type != _$Fe("yQ6YPMK20") && _$3P($_14, _$Fe('uwbm7wKV')) != "") {
if ($_9.length > 0) {
$_9 += "&" + $_14.name + "=" + _$3P($_14, _$Fe('kwbm7wKV'));
} else {
$_9 += $_14.name + "=" + _$3P($_14, _$Fe('Ewbm7wKV'));
}
$_9 += _$Fe("Jx2J03Up2Hsl");
}
}
_$du(request, _$Fe('uM6r2MG'), _$Fe("HVlesYq"), $_10);
$_9 = encodeURI($_9);
$_9 = encodeURI($_9);
request.setRequestHeader(_$Fe("d3CmOFDVz3CeXwoxBMq"), _$Fe("FMbZz3CmOFDV"));
request.setRequestHeader(_$Fe("yACeXwDYXwcTV8Ur2"), _$Fe("g3UraMD2O3UpNMCgB8cT6w6QzRbenM1TTQbS2MbJBRDY9"));
}
request.send($_9);
if ($_12 != null) {
$_12.reset();
}
}
yes as you can see it just creates a XMLHTTP request which (for the links in question) Posts the $_10 content to the server and get the results in callBackC function which is now in $_8. but the trick here is the $_10 contents goes through ~13000 lines of code to create links like this:
http://app1.nmpa.gov.cn/data_nmpa/face3/content.jsp?6SQk6G2z=GBK-56.it.xmhx8IaDT25ZyaSxljrwULe8AkNw8QjmeNqdT0YqZYbMZ2P6Jgn3ZUIgh3ibPI81bjA6xUCKJmzy1LD.4AZnk4g4G_iMO4tdiebiVDoPPtdVDIkDWw0OnDHek.d_2r.PfBtuIoxDvrbGDL.Lv2AuD6lxiObz_lldDHq6HnEw_irAP1hCH.Dr3KdW33DN2w0X1R75N3f8GXdHinmxXLtYbZNYZEE9K7lk9AGmBWgcTds.XgGVW3gDS5OEwoRat44Ecke8k7ZXoY_2revEbUrD8UpOrGprlPEwVYuAvLoTSZX8WJEWQ_QT2CDjNw0FOwAECzsFJa4hGgUtjCPzG&c1SoYK0a=GBK-4aeKAo74EouxLY.stFwdwvXQQG_hXMGG8gB0Hhe6V2Il9k9c8yiTLqduIXpv2RNt.H.weYXeF5XhV0CR2lATieRmk.cs8.fPhNpfGx7JkG1uacp75kDcmXsNtuKgbzRUHZh8vkj4UEYbPcwIYIOw5gFG_cMi9n1GYq0AXXK9UQn9IsmjCBuI7AOFw.pk91OgjvkJCcg2y0y3yDkGwZPcg5EktfAXi.PjmfaecWg8hodU87q6B3ZuPxhel9K9I3EDBxzCHtZqt_0YFlkJCcK4hLq
the problem is with obfuscation and also the nested variables and functions that can keep you out of track for hours if you try to debug it line by line (which I did) and the code makes the characters after content.jsp? part one by one and that explains why its about 13000 lines!!
this part request.send($_9); should have a body for request because its a POST request and $_9 was always null! it seems there are more protection levels to it as it seems.
callBackC:
well the callbackC is apparently a simple function to get responseText and show it to user:
function callbackC() {
if (request.readyState == 1) {
_$c2(document.getElementById(_$Fe("Y3CeXwDYXwq")), '=', _$Fe('vFKyXRUxEYlTW'), _$Fe("kHDxnHOaB3vE5HDxnHOSNMKQGQ6xOHK2z3Kw2Qne7MCm9FKyvhbwNROg"));
}
if (request.readyState == 4) {
if (request.status == 200) {
oldContent[oldContent.length] = request.responseText;
_$c2(document.getElementById(_$Fe("b3CeXwDYXwq")), '=', _$Fe('EFKyXRUxEYlTW'), request.responseText);
request = null;
} else {
_$c2(document.getElementById(_$Fe("u3CeXwDYXwq")), '=', _$Fe('BFKyXRUxEYlTW'), "<br><br><br><span style=font-size:x-large;color:#215add>服务器未返回数据</span>");
}
}
}
I didn't quiet get what those _$Xx functions do (because it goes so deep that its out of my patient!) but it seems they simply replaced the document.getElementById("someThing").innerText="Contents"; with multi layered functions so we can't understand the code easily, and the request.responseText is what you need which is HTML code for the table of results.
there is also a 3rd way which I don't know if you can implement it in your code, but since these functions are in a public scope you can simply override them by redefining these two functions (or replace the functions in the link with your own functions and run them). I tried to get the URL for the request which gave me the link I used in middle of this post, but it didn't worked (I just override the callBackC function and get request.responseURL) and the link gave me 404 error.
I don't think I said all I got from my observations but I think it's enough for you to know what you are up against if you are not already aware, and I hope I was helpful.
Reference:
XMLHttpRequest: Living Standard — Last Updated 16 August 2021

postman.setNextRequest failing to call

I have a collection of tests which I am trying to set up to run in a certain sequence. The sequence is decided using if/else if statements which check a variable in a data-file and set the next request depending on its value.
This works well for the initial request in my collection. But when it gets to a request later in the sequence, the if statement will recognize the correct variable but skip over the postman.setNextRequest() command and run the test below it in the collection order instead of running the specified test.
Does anyone know why this is happening? Seems like a bug with the postman.setNextRequest() function.
Request where function is working as expected:
var rsp = pm.response.json();
var base = pm.environment.get('baseUrl');
pm.environment.set('id', data['appName']);
var id = pm.environment.get('id');
pm.test("Status code is 200", function () {
pm.response.to.have.status(200);
pm.test("Response contains correct BaseUrl", function(){
var issuer = rsp.issuer;
pm.expect(issuer).to.contain(base);
//console.log(resName);
console.log('Passed - on to the next one!')
});
});
if (id === 'Application/Member_PRODUCTION'||id === 'Application/B2C_PRODUCTION'||id === 'Application/Claims Transformation_PRODUCTION'){
postman.setNextRequest('PKCE Step 1- Generate PKCE Challenge and Verifier');
}
else if (id === 'Application/sysTest_SysTest2_PRODUCTION'){
postman.setNextRequest("oAuth Step 1 - Unauthorised API call");
}
else{
postman.setNextRequest("oAuth Step 2- Get Session Data Key");
}
Next request where the function fails to work:
let cookieJar = pm.cookies.jar();
cookieJar.clear(pm.environment.get('baseUrl'));
var id = pm.environment.get('id');
console.log('oAuth check complete for application: '+ id);
pm.test("Status code is 302", function () {
pm.response.to.have.status(302);
console.log('Passed - on to the next one!')
});
if (id === 'Application/Member_PRODUCTION'){
console.log('Next Up - SCIM Tests')
postman.setNextRequest("SCIM Step 1 - Create Member");
}
else{
console.log('Next Up - Login Page Test')
postman.setNextRequest("Login Page Step 1- Get Session data key");
}
The request names were copied straight from the requests themselves so I don't believe that it cannot find the specified next request and the usage in both snippets above seems to be the same so I am a little stuck.

End conversation using Dialogflow Fulfillment Library v2 on firebase?

How do i set the "end conversation" flag using the Dialogflow Fulfillment Library WebhookClient class? I'm using the inline editor powered by Cloud Functions for Firebase, in case that matters.
The situation is that a particular intent cannot be visited more than 3 times. On the first and second visits you get a response, and it allows you to say something and continue; on the third visit, it should give a response then end the conversation/close the mic/kill the app (whatever the proper term is for this)
For non-ending responses i'm using WebhookClient.add(), and i'm using a mix of rich responses, and strings for Text to Speech.
From what I read on github (https://github.com/dialogflow/dialogflow-fulfillment-nodejs), i assumed WebhookClient.end() would be what i wanted. But when i use that, the sript crashes and i get nothing.
The following is all inside exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {...}
const agent = new WebhookClient({ request, response });
const fbContext = 'fallbackcount';
function fallback(agent) {
//all fallbacks use this fulfillment, we give up after 3 bunk responses
//check if we've been here before - we will find a context with a counter if we have
let countContext = agent.getContext(fbContext);
let fbcount = 0;
if (countContext)
{
if (typeof countContext.parameters !== "undefined" )
{
if(typeof countContext.parameters.count !== "undefined" )
{
fbcount = countContext.parameters.count;
}
}
}
console.log("current tracking" + fbcount.toString());
switch(fbcount) {
case 0:
{
agent.add(`Fallback response 1");
break;
}
case 1:
{
agent.add("Fallback response 2");
break;
}
default:
{
//intention: die on third bunk response
//reality: following line causes a problem and i get no response, and the app doesn't close
agent.end("Fallback response 3 - Goodbye!");
}
}
let newcount = fbcount + 1;
console.log("new tracking " + newcount.toString());
agent.setContext({
name: fbContext,
lifespan: 1,
parameters:{count: newcount}
});
}
What am i doing wrong?
Please note that this is NOT a duplicate of Actions on Google: Unable to Close Convo in DialogFlow Fulfillment as he is asking regarding the actions-on-google library, wheras I am using dialogflow-fulfillment-nodejs
I have also seen Dialogflow API V2 "End of conversation" flag in webhook request and that appears to be dealing in raw json, which i believe should be avoidable from what i've seen in docs
I don't know if this is the correct way to do it in this case, but I guess you could use a payload response to close the conversation, in which you set the "expectedUserResponse" to "false":
const googlePayloadJson = {
"expectUserResponse": false
};
let payload = new Payload(agent.ACTIONS_ON_GOOGLE, {});
payload.setPayload(googlePayloadJson);
agent.add(payload);
This worked for me:
function close(message){
let conv = agent.conv();
conv.close(message);
agent.add(conv);
}

Signature generation in Amazon S3 using Javascript

I am trying to send a PUT request to an Amazon compatible storage, and I keep getting the following error:
"<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Secret Access Key and signing method. For more information, see REST Authentication and SOAP Authentication for details.</Message><RequestId>0af9f985:155f11613d1:1732:13</RequestId></Error>"
Can someone please tell me how to generate the correct signature using the Secret Access Key and other parameters, in Javascript. I know that I am using the correct credentials, because all other operations supported by Amazon S3 are working, using the Amazon S3 SDK. I went through this link:
http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html, but I couldn't find what the method is expecting for each parameters.
Adding the code, that I have written. This is pretty much the same as you see in the Javascript SDK, only the method canonicalizedResource, is more simpler:
private stringToSign(request: any) {
var parts = [];
parts.push(request.headers['method']);
parts.push(request.headers['Content-MD5'] || '');
parts.push(request.headers['Content-Type'] || '');
parts.push(request.headers['presigned-expires'] || '');
var headers = this.canonicalizedAmzHeaders(request);
if (headers) parts.push(headers);
parts.push(this.canonicalizedResource(request));
return parts.join('\n');;
}
private canonicalizedAmzHeaders(request: any) {
var amzHeaders = [];
AWS.util.each(request.headers, function(name) {
if (name.match(/^x-amz-/i))
amzHeaders.push(name);
});
amzHeaders.sort(function(a, b) {
return a.toLowerCase() < b.toLowerCase() ? -1 : 1;
});
var parts = [];
AWS.util.each(amzHeaders, function(name) {
parts.push(amzHeaders[name].toLowerCase() + ':' + request.headers[amzHeaders[name]]);
});
return parts.join('\n');
}
private canonicalizedResource(request) {
return request.path || '/';
}
I call the method like:
var signature = this.sign(AWS.config.credentials.secretAccessKey, this.stringToSign(request));
Can you make sure your system time is up to date? I have had issues when my system time is out of sync. AWS rejects those API calls.

Dynamic EventSource with flask and javascript

I am currently building a tool using flask that does various actions using ssh. One of those actions is using DD to copy from X to Y.
I currently have the following javascript set up on my page
<script>
var source == new EventSource("/dd");
source.onmessage = function(event){
$('.determinate'.css('width', event.data+'%')
if(event.data == 100){
source.close()
}
}
Which calls the following flask generator which parse's the stdout of DD to return a % value for the current progress.
#app.route('/dd')
def progress():
def generate():
ssh.SSHClient('127.0.0.1', username, password)
chan = ssh.get_transport().open_session()
chan.settimeout(10800)
try:
ssh.do('dd if=/dev/sda of=/test.img')
while data:
data = chan.recv_stderr(1024)
try:
yield "data: " + str(data) + "\n\n\"
return Response(generate(), mimetype='text/event-stream')
The above is pseudo code, but the things i want to be able to change are the DD command (dd if=/dev/sda of=/test/img) from variables i get from the form that triggers this page, as well as the hostname from the ssh.connect function with request.remote_addr.
When i try to replace '127.0.0.1' with request.remote_addr i get an out of context error.
Is there anyway to pass flask/jinja2 variables such as {{ image.path }} to my generator view?. The pseudo code i want would be this, where hostname, and dd is dynamic ( changes are in curly brackets )
#app.route('/dd')
def progress():
def generate():
ssh.SSHClient({{ request.remote_addr }}, username, password)
chan = ssh.get_transport().open_session()
chan.settimeout(10800)
try:
ssh.do('dd if={{ device }} of={{ image.path }}')
while data:
data = chan.recv_stderr(1024)
try:
yield "data: " + str(data) + "\n\n\"
return Response(generate(), mimetype='text/event-stream')
Just figured it out, didn't read the last paragraph of the docs.
If You want to keep the context of the previous request in the generator just change
return Response(generate(), mimetype='text/event-stream')
to
return Response(stream_with_context(generatE()), mimetype='text/event-stream')
For passing data i just used the "session" object to pass data and then remove it when im done using it.

Categories