

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 在对话期间使用拼写样式捕获槽位值
<a name="spelling-styles"></a>

Amazon Lex V2 提供内置槽位，用于捕获用户特定的信息，例如名字、姓氏、电子邮件地址或字母数字标识符。例如，您可以使用 `AMAZON.LastName` 槽位捕获诸如“Jackson”或“Garcia”等姓氏。但是，Amazon Lex V2 可能会混淆难以发音或在对应区域设置中不常见的姓氏，例如“Xiulan”。要捕获此类姓氏，您可以要求用户以*逐个字母拼写*或*逐个单词拼写*样式提供输入。

Amazon Lex V2 提供了三种*槽位引发样式*供您使用。您设置槽位引发样式后，会改变 Amazon Lex V2 解释用户输入的方式。

**逐个字母拼写**：您可以使用此样式，以指示机器人听拼写而不是整个短语。例如，要捕获诸如“Xiulan”等姓氏，您可以指示用户逐个字母地说出自己的姓氏。机器人将捕获该拼写并将这些字母解析为单词。例如，如果用户说“x i u l a n”，则机器人会将姓氏捕获为“xiulan”。

**逐个单词拼写**：在语音对话中，尤其是在使用电话时，有几个字母会听起来相似，例如“t”、“b”、“p”。当捕获字母数字值或拼写名称导致值不正确时，您可以提示用户输入该字母的同时提供识别词。例如，如果对预订 ID 请求的语音响应为“abp123”，则您的机器人可能会改为识别短语“ab**b**123”。如果该值不正确，您可以指示用户将输入提供为“a as in alpha b as in boy p as in peter one two three”（alpha 的 a，boy 的 b，peter 的 p，然后是 123）。机器人会将输入解析为“abp123”。

使用逐个单词的拼写样式时，您可以使用以下格式：
+ “as in”(a as in apple)
+ “for”(a for apple)
+ “like”(a like apple)

**默认**：使用单词发音进行槽位捕获的自然样式。例如，可以自然地捕获诸如“John Stiles”等姓名。如果未指定槽位引发样式，则机器人将使用默认样式。对于 `AMAZON.AlphaNumeric` 和 `AMAZON.UKPostal` 代码槽位类型，默认样式支持逐个字母拼写的输入。

如果使用字母和单词组合说出名字“Xiulan”，例如“x as in x-ray i u l as in lion a n”，则必须将槽位引发样式设置为逐个单词拼写的样式。使用逐个字母拼写的样式将无法识别该名字。

请创建一个语音界面，用于以自然对话样式来捕获槽位值，以获得更好的体验。对于使用自然样式无法正确捕获的输入，您可以重新提示用户，并将槽位引发样式设置为逐个字母拼写或逐个单词拼写。

对于英语（美国）、英语（英国）和英语（澳大利亚），您可以对以下槽位类型使用逐个单词拼写以及逐个字母拼写样式：
+  [AMAZON.AlphaNumeric](built-in-slot-alphanumeric.md) 
+  [AMAZON.EmailAddress](built-in-slot-email.md) 
+  [AMAZON.FirstName](built-in-slot-first-name.md) 
+  [AMAZON.LastName](built-in-slot-last-name.md) 
+  [AMAZON.UKPostalCode](built-in-slot-uk-postal-code.md) 
+  [自定义槽位类型](custom-slot-types.md) 

## 启用拼写
<a name="spelling-enable"></a>

您可以在运行时启用在从用户引发槽位时的逐个字母拼写以及逐个单词拼写。您可以使用 [PutSession](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_PutSession.html)、[RecognizeText](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_RecognizeText.html)、[RecognizeUtterance](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_RecognizeUtterance.html) 或 [StartConversation](https://docs.aws.amazon.com/lexv2/latest/APIReference/API_runtime_StartConversation.html) 操作来设置拼写样式。您还可以使用 Lambda 函数启用逐个字母拼写以及逐个单词拼写。

在上述任一 API 操作的请求中或配置 Lambda 响应时，您可以使用 `sessionState` 字段的 `dialogAction` 字段来设置拼写样式（有关更多信息，请参阅[AWS LambdaLex V2 的响应格式](lambda-response-format.md)）。只有当对话框操作类型为 `ElicitSlot` 并且要引发的槽位是支持的槽位类型之一时，您才能设置样式。

以下 JSON 代码显示了设置为使用逐个单词拼写样式的 `dialogAction` 字段：

```
"dialogAction": {
    "slotElicitationStyle": "SpellByWord",
    "slotToElicit": "BookingId",
    "type": "ElicitSlot"
}
```

`slotElicitationStyle` 字段可设置为 `SpellByLetter`、`SpellByWord` 或 `Default`。如果您不指定值，则值设置为 `Default`。

**注意**  
您无法通过控制台启用逐个字母拼写或逐个单词拼写的引发样式。

## 使用 Lambda 和 Lex V2 的示例代码
<a name="spelling-example"></a>

如果第一次尝试解析槽位值不起作用，则通常会更改拼写样式。以下代码示例是一个 Python Lambda 函数，在第二次尝试解析槽位时使用逐个单词拼写样式。

要使用示例代码，您必须满足以下条件：
+ 拥有单语言，即英语（英国）(en\$1GB) 的机器人。
+ 拥有一个意图“CheckAccount”，该意图中具有示例言语：“I would like to check my account”。确保在意图定义的**代码挂钩**部分中选中**使用 Lambda 函数进行初始化和验证**。
+ 意图应该有 `AMAZON.UKPostalCode` 内置类型的槽位“PostalCode”。
+ 拥有定义了 Lambda 函数的别名。有关更多信息，请参阅 [为你的 Amazon Lex V2 机器人创建AWS Lambda函数](lambda-attach.md)。



```
import json
import time
import os
import logging

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

# --- Helpers that build all of the responses ---

def get_slots(intent_request):
    return intent_request['sessionState']['intent']['slots']

def get_session_attributes(intent_request):
    sessionState = intent_request['sessionState']
    if 'sessionAttributes' in sessionState:
        return sessionState['sessionAttributes']
    return {}

def get_slot(intent_request, slotName):
    slots = get_slots(intent_request)
    if slots is not None and slotName in slots and slots[slotName] is not None:
        logger.debug('resolvedValue={}'.format(slots[slotName]['value']['resolvedValues']))
        return slots[slotName]['value']['resolvedValues']
    else:
        return None

def elicit_slot(session_attributes, intent_request, slots, slot_to_elicit, slot_elicitation_style, message):
    return {'sessionState': {'dialogAction': {'type': 'ElicitSlot',
                                              'slotToElicit': slot_to_elicit,
                                              'slotElicitationStyle': slot_elicitation_style
                                              },
                             'intent': {'name': intent_request['sessionState']['intent']['name'],
                                        'slots': slots,
                                        'state': 'InProgress'
                                        },
                             'sessionAttributes': session_attributes,
                             'originatingRequestId': 'REQUESTID'
                             },
            'sessionId': intent_request['sessionId'],
            'messages': [ message ],
            'requestAttributes': intent_request['requestAttributes']
            if 'requestAttributes' in intent_request else None
            }

def build_validation_result(isvalid, violated_slot, slot_elicitation_style, message_content):
    return {'isValid': isvalid,
            'violatedSlot': violated_slot,
            'slotElicitationStyle': slot_elicitation_style,
            'message': {'contentType': 'PlainText', 
            'content': message_content}
            }

def GetItemInDatabase(postal_code):
    """
    Perform database check for transcribed postal code. This is a no-op
    check that shows that postal_code can't be found in the database.
    """
    return None

def validate_postal_code(intent_request):

    postal_code = get_slot(intent_request, 'PostalCode')

    if GetItemInDatabase(postal_code) is None:
        return build_validation_result(
            False,
            'PostalCode',
            'SpellByWord',
            "Sorry, I can't find your information. " +
            "To try again, spell out your postal " +
            "code using words, like a as in apple."
        )
    return {'isValid': True}

def check_account(intent_request):
    """
    Performs dialog management and fulfillment for checking an account
    with a postal code. Besides fulfillment, the implementation for this 
    intent demonstrates the following:
    1) Use of elicitSlot in slot validation and re-prompting.
    2) Use of sessionAttributes to pass information that can be used to
        guide a conversation.
    """
    slots = get_slots(intent_request)
    postal_code = get_slot(intent_request, 'PostalCode')
    session_attributes = get_session_attributes(intent_request)

    if intent_request['invocationSource'] == 'DialogCodeHook':
        # Validate the PostalCode slot. If any aren't valid, 
        # re-elicit for the value.
        validation_result = validate_postal_code(intent_request)
        if not validation_result['isValid']:
            slots[validation_result['violatedSlot']] = None
            return elicit_slot(
                session_attributes,
                intent_request,
                slots,
                validation_result['violatedSlot'],
                validation_result['slotElicitationStyle'],
                validation_result['message']
            )
    
        return close(
            intent_request,
            session_attributes,
            'Fulfilled',
            {'contentType': 'PlainText',
             'content': 'Thanks'
             }
        )

def close(intent_request, session_attributes, fulfillment_state, message):
    intent_request['sessionState']['intent']['state'] = fulfillment_state
    return {
        'sessionState': {
            'sessionAttributes': session_attributes,
            'dialogAction': {
                'type': 'Close'
            },
            'intent': intent_request['sessionState']['intent'],
            'originatingRequestId': 'xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
        },
        'messages': [ message ],
        'sessionId': intent_request['sessionId'],
        'requestAttributes': intent_request['requestAttributes'] if 'requestAttributes' in intent_request else None
    }

# --- Intents ---

def dispatch(intent_request):
    """
    Called when the user specifies an intent for this bot.
    """
    intent_name = intent_request['sessionState']['intent']['name']
    response = None

    # Dispatch to your bot's intent handlers
    if intent_name == 'CheckAccount':
        response = check_account(intent_request)

    return response

# --- Main handler ---

def lambda_handler(event, context):
    """
    Route the incoming request based on the intent.

    The JSON body of the request is provided in the event slot.
    """

    # By default, treat the user request as coming from 
    # Eastern Standard Time.
    os.environ['TZ'] = 'America/New_York'
    time.tzset()

    logger.debug('event={}'.format(json.dumps(event)))
    response = dispatch(event)
    logger.debug("response={}".format(json.dumps(response)))

    return response
```