在 Python 中为 Alexa 技能添加会话属性

Posted

技术标签:

【中文标题】在 Python 中为 Alexa 技能添加会话属性【英文标题】:Adding session attributes in Python for Alexa skills 【发布时间】:2017-08-16 23:28:12 【问题描述】:

我的意图架构中有 3 个插槽(accountdollar_valuerecipient_first)用于 Alexa 技能,我想保存演讲者在会话属性中提供的所有插槽。

我正在使用以下方法来设置会话属性:

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

但是,您可能猜到了,如果我想在sessionAttributes 中保存多个插槽作为数据,sessionAttributes 将被覆盖,如下所示:

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)

我的 lambda 函数对提供两个插槽(dollar_valuerecipient_first)的语音输入的 JSON 响应如下(我的猜测是第二个 if 语句中的 the create_dollar_value_attribute 方法覆盖了第一个):


  "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"
  

sessionAttributes 的正确响应应该是:

"sessionAttributes": 
    "dollar_value": "30",
    "recipient_first": "Some Name"
  ,

如何创建此响应?有没有更好的方法在 JSON 响应中向 sessionAttributes 添加值?

【问题讨论】:

【参考方案1】:

在我看来,用 Python 添加sessionAttributes 的最简单方法似乎是使用字典。例如,如果您想在会话属性中存储一些插槽以供将来使用:

session['attributes']['slotKey'] = intent['slots']['slotKey']['value']

接下来,您可以将其传递给构建响应方法:

buildResponse(session['attributes'], buildSpeechletResponse(title, output, reprompt, should_end_session))

本例中的实现:

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
    

这会在 Lambda 响应 JSON 中以推荐的方式创建 sessionAttributes。

此外,如果最后一个不存在,只需添加一个新的 sessionAttribute 并不会覆盖它。它只会创建一个新的键值对。

请注意,这可能在服务模拟器中运行良好,但在实际 Amazon Echo 上进行测试时可能会返回关键属性错误。根据这个post,

在服务模拟器上,会话以 Session: ... Attributes:, ... 开始 当会话在 Echo 上启动时,Session 根本没有 Attributes 键。

我解决此问题的方法是在创建新会话时在 lambda 处理程序中手动创建它:

 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'])

【讨论】:

我在event['session'] 中没有属性但是我不明白实例化这个event['session']['attributes'] = 将如何解决它? alexa/lambda 怎么知道? onSessionStarted 函数有什么作用?【参考方案2】:

首先,您必须定义 session_attributes。

session_attributes = 

然后代替使用

session_attributes = create_recipient_first_attribute(recipient_first)

你应该使用

session_attributes.update(create_recipient_first_attribute(recipient_first)).

您面临的问题是因为您正在重新分配 session_attributes。而不是这个,你应该只更新 session_attributes。

所以你的最终代码会变成:

session_attributes = 
if session.get('attributes', ) and "recipient_first" not in session.get('attributes', ):
    recipient_first = intent['slots']['recipient_first']['value']
    session_attributes.update(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.update(create_dollar_value_attribute(dollar_value))

【讨论】:

【参考方案3】:

ASK SDK for Python 提供了一个attribute manager,用于管理技能中的请求/会话/持久性级别属性。您可以查看color picker sample,了解如何在技能开发中使用这些属性。

【讨论】:

【参考方案4】:

请看下面:

account = intent['slots']['account']['value'] 
dollar_value = intent['slots']['dollar_value']['value'] 
recipient_first = intent['slots']['recipient_first']['value']  

# put your data in a dictionary
attributes =  
    'account':account, 
    'dollar_value':dollar_value, 
    'recipient_first':recipient_first

在您的回复中将 attributes 字典放入 'sessionAttributes' 中。一旦 Alexa 回复您,您应该在 'sessionAttributes' 中取回它。

希望这会有所帮助。

【讨论】:

【参考方案5】:

下面的代码 sn -p 也会防止覆盖会话属性:

session_attributes = session.get('attributes', )

if "recipient_first" not in session_attributes:
    session_attributes['recipient_first'] = intent['slots']['recipient_first']['value']

if "dollar_value" not in session_attributes:
    session_attributes['dollar_value'] =  = intent['slots']['dollar_value']['value']

【讨论】:

以上是关于在 Python 中为 Alexa 技能添加会话属性的主要内容,如果未能解决你的问题,请参考以下文章

为 Screen Sample App 添加新的 Alexa 技能

如何在 Alexa Skill 中使用 Java 获取亚马逊用户电子邮件

自定义 Alexa 技能的权限说 - “此语音模型不支持权限”

Alexa - 允许用户将商品添加到亚马逊购物篮/购物车。需要帮助

Alexa 技能包与 Alexa 语音服务

alexa 在技能调用时发送 SessionEndedRequest