Response cards not displaying in website-lex - aws-lambda

I have created Lex Chatbot and developed a website and integrated this Chatbot. Its working fine.But response cards in the form of buttons are not showing up.I got to know that I have to invoke it from lambda function.So I included the response card code .It works ,but after displaying the buttons it goes back and asks the first slot value again.I dont know where I am wrong
Here is the expected conversation.
User:Hi
Lex:Please provide me your eid
User:e123456
Lex:Choose one of the impact below:
1.low 2.high 3.medium (in form of buttons)
User clicks on low
Lex:Thanks,your ticket has been raised(expected)
What happens:
User:Hi
Lex:Please provide me your eid
User:e123456
Lex:Choose one of the impact below:
1.low 2.high 3.medium
User clicks on low
Lex:Please provide me your eid(goes back and asks the first slot value)
Here is my code:
import json
import logging
import re
import http.client
import mimetypes
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
def elicit_slot_response(output_session_attributes,intent_name,slot_to_elicit,message):
responses= {
'dialogAction': {
'type': 'ElicitSlot',
'slottoElicit':'slot_to_elicit',
'message': {
'contentType': 'PlainText',
'content': message
},
'responseCard': {
'version': '0',
'contentType': 'application/vnd.amazonaws.card.generic',
'genericAttachments': [
{
'title': 'title1',
'subTitle': 'subtitle',
"buttons":[
{
"text":"button 1",
"value":"value 1"
},
{
"text":"button 2",
"value":"value 2"
},
{
"text":"button 3",
"value":"value 3"
}
]
}
]
}
}
}
return responses
def close():
val= {
"dialogAction":
{
"fulfillmentState":"Fulfilled",
"type":"Close",
"message":
{
"contentType":"PlainText",
"content":"Hey your ticket has been raised"
}
}
}
print(val)
return val
def lambda_handler(event, context):
val = ""
slots = event['currentIntent']['slots']
empidemployee= event['currentIntent']["slots"]["empidemployee"]
latestdesc= event['currentIntent']["slots"]["latestdesc"]
latestimpact= event['currentIntent']["slots"]["latestimpact"]
output_session_attributes = event['sessionAttributes'] if event['sessionAttributes'] is not None else {}
elicit_slot_response(output_session_attributes,'latestdetails','latestimpact',"impact")
val=close()
return val

The conversation flow restarts because in the ElicitSlot response from the Lambda function containing the response cards, you are not returning the slots parameter which would contain the slot values already taken as an input from the user.
So, include the slots parameter in the response the value for which could be event['currentIntent']['slots'].

Related

AWS lex bot calling a Lambda function boto3 always returns "Intent FindWeather is fulfilled" Lambda works fine

I created a simple bot to find the weather in a city.
I have a lambda that calls an API and gets the weather of a city. I tested the lambda and it works fine. I configured the lex bot to call the lambda. I am going to post the lambda code, bot screeen shots and testing put that I used to test my lambda
from urllib.request import Request, urlopen
import json
from pprint import pprint
import urllib3
def lambda_handler(event, context):
pprint('received request: ' + str(event))
city = event['currentIntent']['slots']['city']
#print(city)
citytemperature = get_city_temperature(city)
#print('city temp is ' + str(citytemperature))
response = {
"dialogAction": {
"type": "Close",
"fulfillmentState": "Fulfilled",
"message": {
"contentType": "SSML",
"content": format(citytemperature)
},
}
}
#print('result = ' + str(response))
return response
def get_city_temperature(city):
print('weather of the city , city = ' + str(city))
api_key = 'myapikeyjkjkjkj'
base_url = 'http://api.openweathermap.org/data/2.5/weather?'
finalurl = base_url + 'appid=' + api_key + '&q=' + city
#print(finalurl)
httprequest = urllib3.PoolManager()
response = httprequest.request('GET',finalurl)
weather_status = json.loads(response.data.decode('utf-8'))
return weather_status["main"]["temp"]
This is the test data I used to test the lambda and it works fine when I run the lambda by itself. When I call this lambda from the lex bot, I don't see it being invoked at all. In the cloud watch logs I see this error:
[ERROR] KeyError: 'currentIntent'
Traceback (most recent call last):
File "/var/task/lambda_function.py", line 8, in lambda_handler
city = event['currentIntent']['slots']['city']
[ERROR] KeyError: 'currentIntent' Traceback (most recent call last): File
"/var/task/lambda_function.py", line 8, in lambda_handler city =
event['currentIntent']['slots']['city']
This is the documentation that says what should be sent as an input into Lambda and what should the response from lambda to the bot should look like.
https://docs.aws.amazon.com/lex/latest/dg/lambda-input-response-format.html
This is the test data to test the bot in lambda. Lambda works fine. If you change city name to something, it finds the temperature of the city
{
"messageVersion": "1.0",
"invocationSource": "FulfillmentCodeHook",
"userId": "AROAVNZMIA3MR7EYI4M7O",
"sessionAttributes": {},
"requestAttributes": "None",
"bot": {
"name": "Weather",
"alias": "$LATEST",
"version": "$LATEST"
},
"outputDialogMode": "Text",
"currentIntent": {
"name": "FindWeather",
"slots": {
"city": "pomona"
},
"slotDetails": {
"city": {
"resolutions": [],
"originalValue": "pomona"
}
},
"confirmationStatus": "None"
},
"inputTranscript": "whats the temperature in pomona?"
}
[![enter image description here][1]][1]
I believe your issue is a simple one. You have coded your Lambda function against Version 1 of Lex lambda schema.
The input and output message formats for Lex V2 are considerably different. You'll find the sample request and response formats here: https://docs.aws.amazon.com/lexv2/latest/dg/lambda.html#lambda-input-format
In particular, you will find the currentIntent equivalent within sessionState in the V2 input payload. So, your code to retrieve the users value for city should look like this:
city = event['sessionState']['intent']['slots']['city']['interpretedValue']
Also, you will need to change your response message to ensure it matches with what Lex V2 expects. It should look something like this:
event['sessionState']['intent']['state'] = 'Fulfilled'
return {
'sessionState': {
'sessionAttributes': session_attributes,
'dialogAction': {
'type': 'Close'
},
'intent': event['sessionState']['intent']
},
'messages': [message],
'sessionId': event['sessionId'],
'requestAttributes': event['requestAttributes'] if 'requestAttributes' in event else None
}
Here's the guide for the output format for V2: https://docs.aws.amazon.com/lexv2/latest/dg/lambda.html#lambda-response-format

Passing diffrent time slots in same field Django Rest framework

I want to send 3 diffrent time slots in a field ,But do not getting the diffrent slots,but getting error-->"message": "JSON parse error - Expecting property name enclosed in double quotes: line 3 column 9 (char 27)",
models.py
class Slot(models.Model):
time=models.TimeField(auto_now=False, auto_now_add=False,null=True,blank=True)
def __str__(self):
return str(self.time)
views.py
class Available(viewsets.ViewSet):
def create(self, request):
try:
data=request.data
timings=data.get('schedule')
for i in range(3):
time_obj=Slot()
time_obj.time=timings[i]['time']
time_obj.save()
return Response({"message":"Data delivered","success": True}, status=status.HTTP_200_OK)
except Exception as error:
traceback.print_exc()
return Response({"message": str(error), "success": False}, status=status.HTTP_200_OK)
postman response
{
"schedule":{
{
"time":"12:00"
},
{
"time":"12:10"
},
{
"time":"15:00"
}
}
}
looks like the data sent is not valid JSON it should be something like
{
"schedule":[
{
"time":"12:00"
},
{
"time":"12:10"
},
{
"time":"15:00"
}
]
}

Response cards not showing -Amazon lex

I have created a lex chatbot and integrated it into website .Its working fine.I got to know that I have to invoke response cards from lambda .I did that too.Also,I enabled repsonse card checkbox in lex console.After all this,I am not able too see the buttons in the website.Is there any other way to display the buttons other than response cards?
Below is the code:Here,after the fulfillment,I have given the response card which means that after the message "Hey your ticket has been raised",the buttons will be displayed.This displays in lex test chatbot.
import json
import logging
import re
import http.client
import mimetypes
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
def close():
val= {
"dialogAction":
{
"fulfillmentState":"Fulfilled",
"type":"Close",
"message":
{
"contentType":"PlainText",
"content":"Hey your ticket has been raised"
},
'responseCard': {
'version': '0',
'contentType': 'application/vnd.amazonaws.card.generic',
'genericAttachments': [
{
'title': 'title1',
'subTitle': 'subtitle',
"buttons":[
{
"text":"button 1",
"value":"value 1"
},
{
"text":"button 2",
"value":"value 2"
},
{
"text":"button 3",
"value":"value 3"
}
]
}
]
}
}
}
print(val)
return val
def lambda_handler(event, context):
slots = event['currentIntent']['slots']
empidemployee= event['currentIntent']["slots"]["empidemployee"]
latestdesc= event['currentIntent']["slots"]["latestdesc"]
latestservice= event['currentIntent']["slots"]["latestservice"]
latestimpactvalue= event['currentIntent']["slots"]["latestimpactvalue"]
latesturgency= event['currentIntent']["slots"]["latesturgency"]
basicinfo=event['currentIntent']["slots"]["basicinfo"]
val=close()
return val
I believe your problem is the version number. Try setting it to 1 or '1'.
I couldn't find a clear explanation as to why, but here are some evidences at least:
From the AWS example doc: Generating Response Cards Dynamically
responseCard: {
"version": 1,
...
}
I also looked deeper into the lex-web-ui files you are using and in the lex-web-ui.js file it has this:
shouldDisplayResponseCard: function shouldDisplayResponseCard() {
return this.message.responseCard && (this.message.responseCard.version === '1' || this.message.responseCard.version === 1) && this.message.responseCard.contentType === 'application/vnd.amazonaws.card.generic' && 'genericAttachments' in this.message.responseCard && this.message.responseCard.genericAttachments instanceof Array;
},
And that specifically checks for (this.message.responseCard.version === '1' || this.message.responseCard.version === 1) in order to display.

Multiple response cards unable to be shown for Amazon lex chatbot

I am currently using Amazon lex to create a chatbot and want to be able to post multiple response cards at once. The question asked by the chatbot will be "Do you have an integrated Shield Plan currently?" and followed will be multiple response cards where it will show a list of plans from different brands. But if the user does not have a plan, there will be an option called "No" on the response card.
But if I publish the chatbot let's say on Slack, not even one response card is shown. How do I fix this problem?
You have not specified the Card Image URL, this is why there is no card.
I have just now tested it, without Image Card URL ResponseCard will not be shown on Facebook or Slack if we are setting it using console.
However if you are setting Response Cards in Lambda function, then we can choose not to have an image. You can check that slot is filled or not in the DialogCodeHook and display the ResponseCard accordingly.
Below is sample code to display ResponseCard without an image:
{
'dialogAction': {
'type': 'Close',
'fulfillmentState': 'Fulfilled',
'message': {
'contentType': 'PlainText',
'content': message
},
'responseCard': {
'version': '0',
'contentType': 'application/vnd.amazonaws.card.generic',
'genericAttachments': [
{
'title': 'title1',
'subTitle': 'subtitle',
"buttons":[
{
"text":"button 1",
"value":"value 1"
},
{
"text":"button 2",
"value":"value 2"
},
{
"text":"button 3",
"value":"value 3"
}
]
}
}
}
}
Hope it helps.

Google Classroom API patch

When executing the courses.courseWork.studentSubmissions.patch method in the Google Classroom API, a 403 error is returned when I try to update the student's submission. Below is my code.
from googleapiclient.discovery import build
from oauth2client import client
import simplejson as json
class Google:
SCOPE = {
"profile": {"scope": "profile email", "access_type": "offline"},
"classroom": {"scope": 'https://www.googleapis.com/auth/classroom.courses.readonly '
'https://www.googleapis.com/auth/classroom.rosters.readonly '
'https://www.googleapis.com/auth/classroom.profile.emails '
'https://www.googleapis.com/auth/classroom.profile.photos ',
"access_type": "offline"},
"classwork":{
"scope": "https://www.googleapis.com/auth/classroom.coursework.students https://www.googleapis.com/auth/classroom.coursework.me",
"access_type":"offline"
},
"submission":{
"scope": "https://www.googleapis.com/auth/classroom.coursework.me https://www.googleapis.com/auth/classroom.coursework.students profile email",
"access_type":"offline"
}
}
ERRORS = {
"invalid_request":{"code":"invalid_request","msg":"Invalid request. Please Try with login again."},
"account_used":{"code":"account_used","msg":"Google account is already configured with different PracTutor Account."},
"assignment_permission_denied":{"code":"assignment_permission_denied","msg":"permission denied"},
"unknown_error":{"code":"unknown_error","msg":"something went wrong."}
}
def __init__(self, code = "", genFor = "profile"):
if code:
genFor = genFor if genFor else "profile"
self.credentials = client.credentials_from_clientsecrets_and_code(pConfig['googleOauthSecretFile'],self.SCOPE[genFor]["scope"], code)
self.http_auth = self.credentials.authorize(httplib2.Http())
cred_json = self.credentials.to_json()
idinfo = json.loads(cred_json)["id_token"]
else:
raise ValueError(Google.ERRORS["invalid_request"])
def getUserInfo(self):
service = build(serviceName='oauth2', version='v2', http=self.http_auth)
idinfo = service.userinfo().get().execute()
return idinfo
def getClasses(self):
courses = []
page_token = None
service = build('classroom', 'v1', http=self.http_auth)
while True:
response = service.courses().list(teacherId="me",pageToken=page_token,
pageSize=100).execute()
courses.extend(response.get('courses', []))
page_token = response.get('nextPageToken', None)
if not page_token:
break
return courses
def getStudent(self,course_id):
students = []
page_token = None
service = build('classroom', 'v1', http=self.http_auth)
while True:
response = service.courses().students().list(courseId=course_id, pageToken=page_token,
pageSize=100).execute()
students.extend(response.get('students', []))
page_token = response.get('nextPageToken', None)
if not page_token:
break
return students
def createAssignment(self,course_id,**kwargs):
service = build('classroom', 'v1', http=self.http_auth)
date, time = kwargs["dueDate"].split(" ")
yy,mm,dd = date.split("-")
h,m,s = time.split(":")
courseWork = {
'title': kwargs["title"],
'description': kwargs["desc"],
'materials': [
{'link': { 'url': kwargs["link"] } },
],
'dueDate': {
"month": mm,
"year": yy,
"day": dd
},
'dueTime':{
"hours": h,
"minutes": m,
"seconds": s
},
'workType': 'ASSIGNMENT',
'state': 'PUBLISHED',
}
courseWork = service.courses().courseWork().create(courseId=course_id, body=courseWork).execute()
return courseWork
def submitAssignment(self,**kwargs):
service = build('classroom', 'v1', http=self.http_auth)
course_id = kwargs["courseId"]
courseWorkId = kwargs["courseWorkId"]
score = kwargs["score"]
studentSubmission = {
'assignedGrade': score,
'draftGrade': score,
'assignmentSubmission': {
'attachments': [
{
'link': {
"url": "demo.com",
"title": "Assignment1",
"thumbnailUrl": "demo.com",
}
}
],
},
'state': 'TURNED_IN',
}
gCredentials = json.loads(self.credentials.to_json())
userGId = gCredentials["id_token"]["sub"]
studentSubmissionsData = service.courses().courseWork().studentSubmissions().list(
courseId=course_id,
courseWorkId=courseWorkId,
userId=userGId).execute()
studentSubmissionId = studentSubmissionsData["studentSubmissions"][0]["id"]
courseWorkRes = service.courses().courseWork().studentSubmissions().patch(
courseId=course_id,
courseWorkId=courseWorkId,
id=studentSubmissionId,
updateMask='assignedGrade,draftGrade',
body=studentSubmission).execute()
return courseWorkRes
Method Calling
g = Google()
kwargs = {"courseId":courseId,"courseWorkId":courseWorkId,"score":80}
courseworkResponse = g.submitAssignment(**kwargs)
Error:
https://classroom.googleapis.com/v1/courses/{courses_id}/courseWork/{courseWork_id}/studentSubmissions/{studentSubmissions_id}?alt=json&updateMask=assignedGrade%2CdraftGrade
returned "The caller does not have permission">
Student's submission contains following fields assignedGrade, draftGrade, attachments (Link resource) and state.
The call is being made from an authenticated student account. The Developer Console project has the Google Classroom API enabled, and other calls to the Google Classroom API are working fine, such as courses.courseWork.create and courses.courseWork.studentSubmissions.list. Also I am making request from the same Developer Console project from course work item is associated/created.
The same error 403 error with different message is returned when I am trying from Google API explorer.
{
"error": {
"code": 403,
"message": "#ProjectPermissionDenied The Developer Console project is not permitted to make this request.",
"status": "PERMISSION_DENIED"
}
}
Any help would be appreciated, thank you
That error message basically means that you don't have permission to do what it is you are trying to do. The permissions are related to what scopes you have authenticated the user with. here is a full list of scopes
Method: courses.courseWork.studentSubmis.patch requires the following scopes.
Authorization
Requires one of the following OAuth scopes:
https://www.googleapis.com/auth/classroom.coursework.students
https://www.googleapis.com/auth/classroom.coursework.me
Use List and Get before patch
Use list and get before patch to be sure that you have the corect ids.
If you have the user preform a list first then find the one you are after then preform a get you can make changes to the object in the get then run your update on that. Doing it this way ensures that all the ids you are passing are correct and that the user does in fact have access to what they are trying to update.

Resources