

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# 会話中のスペルスタイルによるスロット値のキャプチャ
<a name="spelling-styles"></a>

Amazon Lex V2 には、名、姓、E メールアドレス、英数字の識別子などのユーザー固有の情報をキャプチャするための組み込みスロットが用意されています。例えば、`AMAZON.LastName` スロットを使用して「Jackson」や「Garcia」などの姓をキャプチャできます。ただし、Amazon Lex V2 は、「Xiulan」のように発音しにくい姓や、ロケールでは一般的ではない姓と混同されることがあります。このような名前をキャプチャするために、*文字単位のスペル* または *単語単位のスペル* でスペルアウトするスタイルで、ユーザーに入力を求めることができます。

Amazon Lex V2 では、3つの *スロットエリシテーションスタイル* を用意しています。スロットエリシテーションを設定すると、Amazon Lex V2 がユーザーからのスペルを解釈する方法が変わります。

**文字単位のスペル** — このスタイルでは、フレーズ全体ではなくスペルを聞くようにボットに指示できます。例えば、「Xiulan」などの姓をキャプチャするには、姓を一度に 1 文字ずつスペルアウトするようにユーザーに指示します。ボットはスペルをキャプチャし、文字を単語に変換します。例えば、ユーザーが「x i u l a n」と言うと、ボットは姓を「xiulan」としてキャプチャします。

**単語単位のスペル** — 特に電話での音声会話で、「t」、「b」、「p」など音が似ているものがあります。英数字の値またはスペリングをキャプチャして誤った値になる場合、その文字とともに識別語を入力するようユーザーに促すことができます。例えば、予約 ID のリクエストに対する音声応答が「abp 123」の場合、ボットは「ab**b** 123」というフレーズを認識してしまう可能性があります。これが間違った値である場合は、「alpha の a、boy の b、peter の P、one two three」と入力するようにユーザーに依頼できます。するとボットは「abp 123」と認識します。

単語単位のスペルを使用する場合は、以下の形式を使用できます。
+ 「as in」(as in apple)
+ 「for」(for apple)
+ 「like」(like apple)

**デフォルト** — これは、単語の発音を使用したスロットキャプチャの自然なスタイルです。例えば、「John Stiles」などの名前を自然にキャプチャできます。スロットエリシテーションスタイルが指定されていない場合、ボットはデフォルトのスタイルを使用します。`AMAZON.AlphaNumeric` および `AMAZON.UKPostal` コードスロットタイプでは、デフォルトのスタイルでは文字単位によるスペル入力がサポートされています。

「Xiulan」という名前が文字と単語を組み合わせで話される場合、「x-ray の x、i、u、lion の l、a、n」のように、スロットエリシテーションスタイルは単語単位のスペルスタイルに設定する必要があります。文字単位のスタイルでそれは認識されません。

より良いエクスペリエンスを得るには、自然な会話スタイルでスロット値をキャプチャする音声インターフェイスを作成する必要があります。ナチュラルスタイルを使用して正しくキャプチャされない入力については、ユーザーに再度プロンプトを表示して、スロットエリシテーションスタイルを文字単位または単語単位のスペルに設定できます。

英語 (US)、英語 (UK) および英語 (オーストラリア) の言語では、次のスロットタイプに単語単位のスペルと英字スタイルを使用できます。
+  [AMAZON.AlphaNumeric](built-in-slot-alphanumeric.md) 
+  [AMAZON.EmailAddress](built-in-slot-email.md) 
+  [AMAZON.FirstNameA](built-in-slot-first-name.md) 
+  [AMAZON.LastName](built-in-slot-last-name.md) 
+  [AMAZON.UK 郵便番号](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 関数で、2 回目のスロットの解決時に単語単位のスペルスタイルを使用します。

サンプルコードを使用するには、以下が必要です。
+ 1 つの言語を持つボット、英語 (GB) (en\$1GB)。
+ 1 つのインテント、「アカウントを確認したい」という 1 つのサンプル発話を含む「CheckAccount」。インテント定義の **[コードフック]** セクションで **[初期化と検証に Lambda 関数を使用する]**が選択されていることを確認してください。
+ インテントには、`AMAZON.UKPostalCode` 組み込みタイプのスロット「PostalCode」が 1 つ必要です。
+ 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
```