I am having trouble with sending a JSON response from my python3.8 lambda function (default lambda_handler function). I am pretty sure I understand what I am doing after reading most of the docs and the Lambda Function Input Event and Response Format. from that resource, it says the only required section is the 'dialogAction' section.
Right now, my lex-bot has 1 intent and one slot. I know that this works because when I add a logger to the code, I can see that my lambda function is recieving confirmed JSON format.
My code tries to send a final response from the lambda function, but when I run the lex-bot in the console I get the following error:
Invalid Lambda Response: Received invalid response from Lambda: Can not construct instance of IntentResponse, problem: The validated object is null at [Source: {"dialogAction": {"type": "Close", "fulfillmentState": "Fulfilled", "message": {"contentType": "PlainText", "content": "milk"}}}; line: 1, column: 128]
Here is my python code:
import json
import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
def lambda_handler(event, context):
# print
item = event["sessionState"]["intent"]["slots"]["MilkProduct"]["value"]["resolvedValues"][0]
logger.debug(item)
return{
"dialogAction": {
"type": "Close",
"fulfillmentState": "Fulfilled",
"message": {
"contentType": "PlainText",
"content": item
}
}
}
I do not think this is necessary for you to see, but here is what the lex-bot is sending me after it confirms the slot for the intent has been confirmed:
{
"sessionId": "120304235774457",
"inputTranscript": "I want to buy milk",
"interpretations": [
{
"intent": {
"slots": {
"MilkProduct": {
"shape": "Scalar",
"value": {
"originalValue": "milk",
"resolvedValues": [
"milk"
],
"interpretedValue": "milk"
}
}
},
"confirmationState": "None",
"name": "BuyCream",
"state": "ReadyForFulfillment"
},
"nluConfidence": 1
},
{
"intent": {
"slots": {},
"confirmationState": "None",
"name": "FallbackIntent",
"state": "ReadyForFulfillment"
}
}
],
"responseContentType": "text/plain; charset=utf-8",
"invocationSource": "FulfillmentCodeHook",
"messageVersion": "1.0",
"sessionState": {
"intent": {
"slots": {
"MilkProduct": {
"shape": "Scalar",
"value": {
"originalValue": "milk",
"resolvedValues": [
"milk"
],
"interpretedValue": "milk"
}
}
},
"confirmationState": "None",
"name": "BuyCream",
"state": "ReadyForFulfillment"
},
"originatingRequestId": "417dff57-5260-45cc-81a7-06df13fbee9a"
},
"inputMode": "Text",
"bot": {
"aliasId": "TSTALIASID",
"aliasName": "TestBotAlias",
"name": "Shopping",
"version": "DRAFT",
"localeId": "en_US",
"id": "JTGNDOEVQG"
}
}
Can someone please tell me what I am doing wrong? I have been at this for hours and I seriously do not know what I am doing wrong.
Thanks
Related
I would like to Delete a VM with its attached resources including Network Interfaces, data disks, OS Disk and Public IP when a certain URL is called with a delete method:
http://servername.com/azr/vm_name/subscription_id/resource_group
However, I'm having some issues attaching the Public IP For deletion.
I'm doing this by:
Calling Azure GET VM API to get the VM and resource details and saving the response JSON into a variable "response_json"
{
"name": "TestAZR",
"id": "/subscriptions/xx-xxx-xx/resourceGroups/xxx-xxx-xx/providers/Microsoft.Compute/virtualMachines/TestAZR",
"type": "Microsoft.Compute/virtualMachines",
"location": "eastus",
"properties": {
"vmId": "xxx-xxx-xxx",
"hardwareProfile": {
"vmSize": "Standard_DS1_v2"
},
"storageProfile": {
"imageReference": {
"publisher": "MicrosoftWindowsServer",
"offer": "WindowsServer",
"sku": "2016-datacenter-gensecond",
"version": "latest"
},
"osDisk": {
"osType": "Windows",
"name": "TestAZR_disk1",
"createOption": "FromImage",
"caching": "ReadWrite",
"managedDisk": {
"storageAccountType": "xx",
"id": "/subscriptions/xx-xxx/resourceGroups/xx=xxx=x/providers/Microsoft.Compute/disks/TestAZR_disk1
},
"deleteOption": "Detach",
"diskSizeGB": 127
},
"dataDisks": [
{
"lun": 0,
"name": "TestAZR_DataDisk_0",
"createOption": "Attach",
"caching": "ReadOnly",
"writeAcceleratorEnabled": false,
"managedDisk": {
"storageAccountType": "Premium_LRS",
"id": "/subscriptions/xx-xxx-/resourceGroups/xx-xxx-x/providers/Microsoft.Compute/disks/TestAZR_DataDisk_0"
},
"deleteOption": "Detach",
"diskSizeGB": 1024,
"toBeDetached": false
},
{
"lun": 1,
"name": "TestAZR_DataDisk_1",
"createOption": "Attach",
"caching": "ReadOnly",
"writeAcceleratorEnabled": false,
"managedDisk": {
"storageAccountType": "Premium_LRS",
"id": "/subscriptions/xx-xxx-x/resourceGroups/xx-xxx-xx/providers/Microsoft.Compute/disks/TestAZR_DataDisk_1"
},
"deleteOption": "Detach",
"diskSizeGB": 1024,
"toBeDetached": false
}
]
},
"osProfile": {
"computerName": "TestAZR",
"adminUsername": "AAAA",
"windowsConfiguration": {
"provisionVMAgent": true,
"enableAutomaticUpdates": true,
"patchSettings": {
"patchMode": "AutomaticByOS",
"assessmentMode": "ImageDefault",
"enableHotpatching": false
},
"enableVMAgentPlatformUpdates": false
},
"secrets": [],
"allowExtensionOperations": true,
"requireGuestProvisionSignal": true
},
"networkProfile": {
"networkInterfaces": [
{
"id": "/subscriptions/xx-xxx-x/resourceGroups/xx-xxx-x/providers/Microsoft.Network/networkInterfaces/testazrexecute35_z1",
"properties": {
"deleteOption": "Detach"
}
}
]
},
"diagnosticsProfile": {
"bootDiagnostics": {
"enabled": true
}
},
"provisioningState": "Succeeded",
"timeCreated": "2022-09-15T19:04:13.2910488+00:00"
},
"zones": [
"1"
]
}
Modifying the response_json setting each "DeleteOption" with "Delete" so they get deleted with the VM
Sending the response_json in a PATCH API with the request.
Deleting VM with the DELETE VM API
This works for deleting VM along with Network Interface, Data Disks and OS Disk but Public IP doesn't seem to be deleted with Network Interface automatically.
So I tried this alternatively:
I use the GET Network interface API that contains the Public IP name inside:
{
"name": "testazr845_z1",
"id": "/subscriptions/xx-xxx-xx/resourceGroups/xx-xxx-xx/providers/Microsoft.Network/networkInterfaces/testazr845_z1",
"etag": "W/\"xx-xxx-xx\"",
"properties": {
"provisioningState": "Succeeded",
"resourceGuid": "xx-xxx-",
"ipConfigurations": [
{
"name": "ipconfig1",
"id": "/subscriptions/xxx-xxxx-xx/resourceGroups/xxx-xxx-xx/providers/Microsoft.Network/networkInterfaces/testazr845_z1/ipConfigurations/ipconfig1",
"etag": "W/\"xxx-xxx-xx\"",
"type": "Microsoft.Network/networkInterfaces/ipConfigurations",
"properties": {
"provisioningState": "Succeeded",
"privateIPAddress": "",
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"name": "TestAZR-ip",
"id": "/subscriptions/xxx-xxx-x/resourceGroups/xx-xxx-xx/providers/Microsoft.Network/publicIPAddresses/TestAZR-ip",
"properties": {
"provisioningState": "Succeeded",
"resourceGuid": "xx-xxxx-xx",
"publicIPAddressVersion": "IPv4",
"publicIPAllocationMethod": "Dynamic",
"idleTimeoutInMinutes": 4,
"ipTags": [],
"ipConfiguration": {
"id": "/subscriptions/xxx-xxxx-x/resourceGroups/xx-xxx-xx/providers/Microsoft.Network/networkInterfaces/testazr845_z1/ipConfigurations/ipconfig1"
},
"deleteOption": "Detach"
},
"type": "Microsoft.Network/publicIPAddresses",
"sku": {
"name": "Basic",
"tier": "Regional"
}
},
"subnet": {
"id": "/subscriptions/xx-xxxx-xx/resourceGroups/VPCxAzrDev/providers/Microsoft.Network/virtualNetworks/xx-xx/subnets/alphatest_ase_subnet"
},
"primary": true,
"privateIPAddressVersion": "IPv4"
}
}
],
"dnsSettings": {
"dnsServers": [],
"appliedDnsServers": [],
"internalDomainNameSuffix": ""
},
"macAddress": "",
"enableAcceleratedNetworking":,
"vnetEncryptionSupported":,
"enableIPForwarding":,
"primary":,
"virtualMachine": {
"id": "/subscriptions/xx-xxx-xx/resourceGroups/xxx-xxx/providers/Microsoft.Compute/virtualMachines/TestAZR"
},
"hostedWorkloads": [],
"tapConfigurations": [],
"nicType": "Standard",
"allowPort25Out": true
},
"type": "Microsoft.Network/networkInterfaces",
"location": "eastus",
"kind": "Regular"
}
I save that response into a variable json "network_interface_json", and in it I modify it with {"DeleteOption" : "Delete"} for the Public IP
I send this json in the PATCH API that's listed for deleting resources with VM
https://learn.microsoft.com/en-us/azure/virtual-machines/delete?tabs=rest2%2Ccli3%2Cportal4%2Cportal5
However I'm getting the following error message when sending this request:
{
"error": {
"code": "LinkedAuthorizationFailed",
"message": "The client '123124-12312-xx' with object id '1231-xx-xx' has permission to perform action 'Microsoft.Network/networkInterfaces/write' on scope '/subscriptions/xxx-xx-xx/resourceGroups/xx-xx-x/providers/Microsoft.Network/networkInterfaces/AZRTEST; however, it does not have permission to perform action 'Microsoft.Network/virtualNetworks/subnets/join/action' on the linked scope(s) '/subscriptions/xx-xxx-x/resourceGroups/VPCxAzureDevelopment/providers/Microsoft.Network/virtualNetworks/VPCxAzureDevelopment-eastus/subnets/xxx-xxx-subnet' or the linked scope(s) are invalid."
}
}
So it seems to be a permissions issue? Or maybe the json I'm using isn't correct to send for PATCH API? I've tried removing the subnet part but this doesn't seem to work, open to any suggestions.
I'm currently working with some JSON data that is presenting a challenge, i need to print the device name in my script next to the latency float, i can easily print the latency float as there is a key:value , however the device name does not sit the same, therefore i cannot figure out how to print this especially as it changes for each API Url i am looping through to retrieve the data
The data i want to print is "DEVICE123-Et10"
See JSON data below,
{
"notifications": [
{
"timestamp": "511513234234",
"path_elements": [
"Devices",
"DEVICE1",
"versioned-data",
"connectivityMonitor",
"status",
"hostStatus",
"DEVICE123-Et10",
"defaultStats"
],
"updates": {
"httpResponseTime": {
"key": "httpResponseTime",
"value": {
"float": 0
}
}
}
},
{
"timestamp": "15153324243",
"path_elements": [
"Devices",
"DEVICE1",
"versioned-data",
"connectivityMonitor",
"status",
"hostStatus",
"DEVICE123-Et10",
"defaultStats"
],
"updates": {
"packetLoss": {
"key": "packetLoss",
"value": {
"int": 0
}
}
}
},
{
"timestamp": "151522324234",
"path_elements": [
"Devices",
"DEVICE1",
"versioned-data",
"connectivityMonitor",
"status",
"hostStatus",
"DEVICE123-Et10",
"defaultStats"
],
"updates": {
"latency": {
"key": "latency",
"value": {
"float": 0.238756565643454
}
}
}
},
{
"timestamp": "158056745645645",
"path_elements": [
"Devices",
"DEVICE1",
"versioned-data",
"connectivityMonitor",
"status",
"hostStatus",
"DEVICE123-Et10",
"defaultStats"
],
"updates": {
"jitter": {
"key": "jitter",
"value": {
"float": 0.03500000213213
}
}
}
}
]
}
Current code i am using to loop through my URL list and get the latency:
jsonrequest = requests.get(url, cookies=cookies, verify=False).json()
try:
print(jsonrequest['notifications'][2]['updates']['latency']['value']['float'])
except KeyError:
print(jsonrequest['notifications'][1]['updates']['latency']['value']['float'])```
I went ahead and wrote a script to do what you wanted. It loops through all the notifications until a "latency" update is found. Then it takes the second-to-last item from the list, since it's always second to last.
import json
import requests
data = requests.get(url, cookies=cookies, verify=False).json()
notifications = data["notifications"]
for notification in notifications:
if notification["updates"].get("latency"):
latency = notification["updates"]["latency"]["value"]["float"]
name = notification["path_elements"][-2]
print(name, latency)
I am using a site's REST API's and have been primarily using Python's 'requests' module to GET json responses. The goal of the GET requests are to ultimately pull a user's form response which ends up being a complex json document. To deal with this:
user_form_submission = requests.get('https://www.url/doc.json',
auth = (api_key, secret),
params = params)
python_obj = json.loads(user_form_submission.text)
trimmed_dict = python_obj['key'][0]['keys']
For context, this is what trimmed_dict would look like formatted as .json:
{
"Date": { "value": "2020-04-26", "type": "date" },
"Location": {
"value": "Test ",
"type": "text",
"geostamp": "lat=34.00000, long=-77.00000, alt=17.986118, hAccuracy=65.000000, vAccuracy=10.000000, timestamp=2020-04-26T23:39:56Z"
},
"form": {
"value": [
{
"form_Details": {
"value": [
{
"code": {
"value": "0000000000",
"type": "barcode"
},
"Name": { "value": "bob", "type": "text" }
}
],
"type": "group"
},
"Subtotal": { "value": "4", "type": "decimal" },
"form_detail2": {
"value": [
{
"name": {
"value": "billy",
"type": "text"
},
"code": {
"value": "00101001",
"type": "barcode"
},
"Classification": {
"value": "person",
"type": "select1"
},
"Start_Time": { "value": "19:43:00", "type": "time" },
"time": { "value": "4", "type": "decimal" }
}
],
"type": "subform"}
}
]
}
}
Now I have a portion of the json that contains both the useful and useless. From this point, can I pass this obj in a POST? I've tried every way that I can think of approaching it, and have been shut down.
Understanding how I want to go about this, this is how I thought it would go:
json_post = requests.post(' https://url/api/doc.json',
auth = (api_key, secret),
json = {
"form_id" : 'https://url.form.com/formid',
'payload':{
json.dumps(trimmed_dict)
}})
But, when I do this, I get the following error --
TypeError: Object of type set is not JSON serializable
How can I push this dict through this POST? If there's a more effective way of going about it, I am very open to suggestion.
Try removing the curly braces around json.dumps(trimmed_dict). json.dumps turns your trimmed_dict into a string, which becomes a python set when surrounded with braces.
Additionally you could remove json.dumps and plug the trimmed_dict into the structure directly as the value associated with payload.
Remove the extra {} from the payload. payload itself is a key and json.dumps(trimmed_dict) as a value is enough
json_post = requests.post(' https://url/api/doc.json',
auth = (api_key, secret),
json = {
"form_id" : 'https://url.form.com/formid',
"payload": json.dumps(trimmed_dict)
})
I'm trying to write a typeform bot but I am a totally beginner so I have problems with request.post
I am trying to fill this typeform: https://typeformtutorial.typeform.com/to/aA7Vx9
by this code
import requests
token = requests.get("https://typeformtutorial.typeform.com/app/form/result/token/aA7Vx9/default")
data = {"42758279": "true",
"42758410": "text",
"token": token}
r = requests.post("https://typeformtutorial.typeform.com/app/form/submit/aA7Vx9", data)
print(r)
I think that something is wrong with "data" and I am not sure if I use token in a good way. Could you help me?
So, first of all, you need to get another field with the token. To do that, you should pass the header 'accept': 'application/json' in your first request. In the response, you'll get the json object with the token and landed_at parameters. You should use them in the next step.
Then, the post data shoud be different from what you're passing. See the network tab in the browser's developer tools to find out the actual template. It has a structure like that:
{
"signature": <YOUR_SIGNATURE>,
"form_id": "aA7Vx9",
"landed_at": <YOUR_LANDED_AT_TIME>,
"answers": [
{
"field": {
"id": "42758279",
"type": "yes_no"
},
"type": "boolean",
"boolean": True
},
{
"field": {
"id": "42758410",
"type": "short_text"
},
"type": "text",
"text": "1"
}
]
}
And finally, you should convert that json to text so the server would successfully parse it.
Working example:
import requests
import json
token = json.loads(requests.post(
"https://typeformtutorial.typeform.com/app/form/result/token/aA7Vx9/default",
headers={'accept': 'application/json'}
).text)
signature = token['token']
landed_at = int(token['landed_at'])
data = {
"signature": signature,
"form_id": "aA7Vx9",
"landed_at": landed_at,
"answers": [
{
"field": {
"id": "42758279",
"type": "yes_no"
},
"type": "boolean",
"boolean": True
},
{
"field": {
"id": "42758410",
"type": "short_text"
},
"type": "text",
"text": "1"
}
]
}
json_data = json.dumps(data)
r = requests.post("https://typeformtutorial.typeform.com/app/form/submit/aA7Vx9", data=json_data)
print(r.text)
Output:
{"message":"success"}
I created a simple bot with a simple lex intent. This lex intent has one single slot slotTwo.
Then I linked it with a python lambda function. I want to access to the value of that slot from inside the lambda function.
python lambda function receives the parameters context and event. The link below shows the structure for the parameter event.
https://docs.aws.amazon.com/lex/latest/dg/lambda-input-response-format.html
I copy it here too:
{
"currentIntent": {
"name": "intent-name",
"slots": {
"slot name": "value",
"slot name": "value"
},
"slotDetails": {
"slot name": {
"resolutions" : [
{ "value": "resolved value" },
{ "value": "resolved value" }
],
"originalValue": "original text"
},
"slot name": {
"resolutions" : [
{ "value": "resolved value" },
{ "value": "resolved value" }
],
"originalValue": "original text"
}
},
"confirmationStatus": "None, Confirmed, or Denied (intent confirmation, if configured)"
},
"bot": {
"name": "bot name",
"alias": "bot alias",
"version": "bot version"
},
"userId": "User ID specified in the POST request to Amazon Lex.",
"inputTranscript": "Text used to process the request",
"invocationSource": "FulfillmentCodeHook or DialogCodeHook",
"outputDialogMode": "Text or Voice, based on ContentType request header in runtime API request",
"messageVersion": "1.0",
"sessionAttributes": {
"key": "value",
"key": "value"
},
"requestAttributes": {
"key": "value",
"key": "value"
}
}
However, when I print out the content of this parameter I see only the slot and I can access to its value directly, first level.
START RequestId: 60a541d8-b3c8-48b0-a7a3-6b3f65d96482 Version: $LATEST
{
"slotTwo": "some text here"
}
The test from the lambda console works fine. It is able to retrieve the value and continue the logic.
However when I test the bot from Lex it does not work.
Any idea why?
Thanks so much
Ester
My bad.
I missed that the values indicated in the lamdda test must correspond to the whole JSON structure. So now I added this as event test:
{
"currentIntent": {
"name": "intent-name",
"slots": {
"slotTwo": "Hi from the sendmessagetest"
}
}
}
and I access the slot within the lambda this way:
messagetext = event['currentIntent'] ['slots'] ['slotTwo']
Feel free to delete my post if you find it confusing.
Thanks everyone