I have 3 slots (account
, dollar_value
, recipient_first
) within my intent schema for an Alexa skill and I want to save whatever slots are provided by the speaker in the session Attributes.
I am using the following methods to set session attributes:
def create_dollar_value_attribute(dollar_value): return {"dollar_value": dollar_value} def create_account_attribute(account): return {"account": account} def create_recipient_first_attribute(recipient_first): return {"recipient_first": recipient_first}
However, as you may guess, if I want to save more than one slot as data in sessionAttributes
, the sessionAttributes
is overwritten as in the following case:
session_attributes = {} if session.get('attributes', {}) and "recipient_first" not in session.get('attributes', {}): recipient_first = intent['slots']['recipient_first']['value'] session_attributes = create_recipient_first_attribute(recipient_first) if session.get('attributes', {}) and "dollar_value" not in session.get('attributes', {}): dollar_value = intent['slots']['dollar_value']['value'] session_attributes = create_dollar_value_attribute(dollar_value)
The JSON response from my lambda function for a speech input in which two slots (dollar_value
and recipient_first
) were provided is as follows (my guess is that the create_dollar_value_attribute
method in the second if statement is overwriting the first):
{ "version": "1.0", "response": { "outputSpeech": { "type": "PlainText", "text": "Some text output" }, "card": { "content": "SessionSpeechlet - Some text output", "title": "SessionSpeechlet - Send Money", "type": "Simple" }, "reprompt": { "outputSpeech": { "type": "PlainText" } }, "shouldEndSession": false }, "sessionAttributes": { "dollar_value": "30" } }
The correct response for sessionAttributes
should be:
"sessionAttributes": { "dollar_value": "30", "recipient_first": "Some Name" },
How do I create this response? Is there a better way to add values to sessionAttributes
in the JSON response?
Advertisement
Answer
The easiest way to add sessionAttributes
with Python in my opinion seems to be by using a dictionary. For example, if you want to store some of the slots for future in the session attributes:
session['attributes']['slotKey'] = intent['slots']['slotKey']['value']
Next, you can just pass it on to the build response method:
buildResponse(session['attributes'], buildSpeechletResponse(title, output, reprompt, should_end_session))
The implementation in this case:
def buildSpeechletResponse(title, output, reprompt_text, should_end_session): return { 'outputSpeech': { 'type': 'PlainText', 'text': output }, 'card': { 'type': 'Simple', 'title': "SessionSpeechlet - " + title, 'content': "SessionSpeechlet - " + output }, 'reprompt': { 'outputSpeech': { 'type': 'PlainText', 'text': reprompt_text } }, 'shouldEndSession': should_end_session } def buildResponse(session_attributes, speechlet_response): return { 'version': '1.0', 'sessionAttributes': session_attributes, 'response': speechlet_response }
This creates the sessionAttributes in the recommended way in the Lambda response JSON.
Also just adding a new sessionAttribute doesn’t overwrite the last one if it doesn’t exist. It will just create a new key-value pair.
Do note, that this may work well in the service simulator but may return a key attribute error when testing on an actual Amazon Echo. According to this post,
On Service Simulator, sessions starts with Session:{ … Attributes:{}, … } When sessions start on the Echo, Session does not have an Attributes key at all.
The way I worked around this was to just manually create it in the lambda handler whenever a new session is created:
if event['session']['new']: event['session']['attributes'] = {} onSessionStarted( {'requestId': event['request']['requestId'] }, event['session']) if event['request']['type'] == 'IntentRequest': return onIntent(event['request'], event['session'])