Карточка с несколькими подсказками в Slack

В настоящее время я делаю чат-бот на amazon lex и развернул его в slack. Но каким-то образом всякий раз, когда вы пытаетесь это сделать, и он достигает вопроса с ответной карточкой, он публикует повторный вопрос с подсказкой. Как сделать, чтобы он подсказывал только один раз или это просто проблема со Slack?

введите здесь описание изображения

введите здесь описание изображения

Вот мой код, используемый в aws lambda, однако я сделал настройки для карточки ответа на lex и ничего не сделал на aws lambda:

import json
import datetime
import time
import os
import dateutil.parser
import logging
import urllib.request

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

# --- Helpers that build all of the responses ---


def elicit_slot(session_attributes, intent_name, slots, slot_to_elicit, message):
    return {
        'sessionAttributes': session_attributes,
        'dialogAction': {
            'type': 'ElicitSlot',
            'intentName': intent_name,
            'slots': slots,
            'slotToElicit': slot_to_elicit,
            'message': message
        }
    }


def confirm_intent(session_attributes, intent_name, slots, message):
    return {
        'sessionAttributes': session_attributes,
        'dialogAction': {
            'type': 'ConfirmIntent',
            'intentName': intent_name,
            'slots': slots,
            'message': message
        }
    }


def close(session_attributes, fulfillment_state, message):
    response = {
        'sessionAttributes': session_attributes,
        'dialogAction': {
            'type': 'Close',
            'fulfillmentState': fulfillment_state,
            'message': message
        }
    }

    return response

def delegate(session_attributes, slots):
    return {
        'sessionAttributes': session_attributes,
        'dialogAction': {
            'type': 'Delegate',
            'slots': slots
        }
    }

# --- Helper Functions ---

def safe_int(n):
    """
    Safely convert n value to int.
    """
    if n is not None:
        return int(n)
    return n


def try_ex(func):
    """
    Call passed in function in try block. If KeyError is encountered return None.
    This function is intended to be used to safely access dictionary.

    Note that this function would have negative impact on performance.
    """

    try:
        return func()
    except KeyError:
        return None

def calculate_age(birthday, combine):
    today = datetime.date.today()
    birthdate = datetime.datetime.strptime(birthday, '%Y-%m-%d')
    age = today.year - birthdate.year - ((today.month, today.day) < (birthdate.month, birthdate.day))
    age = age + 1

    age2 = age + 10

    request = urllib.request.Request('https://insuranceproject-ae18a.firebaseio.com/%d/%s.json' % (age, combine[0].replace(' ', '')))
    response = urllib.request.urlopen(request)
    str_response = response.read()
    info = json.loads(str_response.decode("utf-8"))

    request = urllib.request.Request('https://insuranceproject-ae18a.firebaseio.com/%d/%s.json' % (age2, combine[0].replace(' ', '')))
    response = urllib.request.urlopen(request)
    str_response = response.read()
    info2 = json.loads(str_response.decode("utf-8"))    

    abc = [info, str(age), info2]

    return abc

def cash_outlay(abc):
    age = int(abc[1])
    if (age <= 40):
        awl = 300
    elif(age <= 70):
        awl = 600
    else:
        awl = 900

    premium = int(abc[0])
    if (premium > awl):
        cash_outlay = premium - awl
        say = " Since your premium is more than your AWL (Additional Withdrawal Limit), u only need to pay the remaining which is $" + str(cash_outlay)
    else:
        cash_outlay = 0
        say = " Since your premium is less than AWL (Additional Withdrawal Limit), everything is settled by Medisave"

    return say

def generate_rec_plan(ward_type, compensation, period, limit):
    if(ward_type == 'Private' and period == '4' and limit == 'Yes'):
        plan_type = 'AXA Shield Plan A'
        link = 'https://www.axa.com.sg/our-solutions/personal/health/axa-shield'
    elif(ward_type == 'Private' and period == '4' and limit == 'No'):
        plan_type = 'PRUshield A Premier'
        link = 'https://www.prudential.com.sg/en/our-solutions/products/prushield/'
    elif(ward_type == 'Private' and period == '3' and limit == 'Yes'):
        plan_type = 'Supreme Health P Plus'
        link = 'https://www.greateasternlife.com/sg/en/personal-insurance/find-the-right-plan/protect-myself-and-my-family/health-protection/supremehealth.html'
    elif(ward_type == 'Private' and period == '3' and limit == 'No'):
        plan_type = 'My Shield Plan 1'
        link = 'https://www.aviva.com.sg/en/insurance/life-and-health/my-shield/'
    elif(ward_type == 'Private' and period == '2'):
        plan_type = 'Preferred'
        link = 'https://www.income.com.sg/insurance/health-insurance/enhanced-incomeshield'
    elif(ward_type == 'Private' and period == '1'):
        plan_type = 'AIA Health Shield Gold Max A'
        link = 'https://www.aia.com.sg/en/our-products/medical-protection/aia-healthshield-gold-max.html'
    elif(ward_type == 'A ward' and period == '4' and limit == 'Yes'):
        plan_type = 'PRUshield A Plus'
        link = 'https://www.prudential.com.sg/en/our-solutions/products/prushield/'
    elif(ward_type == 'A ward' and period == '4' and limit == 'No'):
        plan_type = 'AXA Shield Plan B'
        link = 'https://www.axa.com.sg/our-solutions/personal/health/axa-shield'
    elif(ward_type == 'A ward' and period == '3'):
        plan_type = 'Supreme Health A Plus'
        link = 'https://www.greateasternlife.com/sg/en/personal-insurance/find-the-right-plan/protect-myself-and-my-family/health-protection/supremehealth.html'
    elif(ward_type == 'A ward' and period == '2'):
        plan_type = 'AIA Health Shield Gold Max B'
        link = 'https://www.aia.com.sg/en/our-products/medical-protection/aia-healthshield-gold-max.html'
    elif(ward_type == 'A ward' and period == '1' and limit == 'Yes'):
        plan_type = 'MyShield Plan 2'
        link = 'https://www.aviva.com.sg/en/insurance/life-and-health/my-shield/'
    elif(ward_type == 'A ward' and period == '1' and limit == 'No'):
        plan_type = 'Advantage'
        link = 'https://www.income.com.sg/insurance/health-insurance/enhanced-incomeshield'
    elif(ward_type == 'B1 ward' and compensation == 'As Charged' and (period == '4' or period == '3')):
        plan_type = 'Supreme Health B Plus'
        link = 'https://www.greateasternlife.com/sg/en/personal-insurance/find-the-right-plan/protect-myself-and-my-family/health-protection/supremehealth.html'
    elif(ward_type == 'B1 ward' and compensation == 'As Charged' and period == '2'):
        plan_type = 'AIA Health Shield Gold Max B Lite'
        link = 'https://www.aia.com.sg/en/our-products/medical-protection/aia-healthshield-gold-max.html'
    elif(ward_type == 'B1 ward' and compensation == 'As Charged' and period == '1' and limit == 'Yes'):
        plan_type = 'My Shield Plan 3'
        link = 'https://www.aviva.com.sg/en/insurance/life-and-health/my-shield/'
    elif(ward_type == 'B1 ward' and compensation == 'As Charged' and period == '1' and limit == 'No'):
        plan_type = 'Basic - SG'
        link = 'https://www.income.com.sg/insurance/health-insurance/enhanced-incomeshield'
    elif(ward_type == 'B1 ward' and compensation == 'Limits'):
        plan_type = 'AXA Standard Plan'
        link = 'https://www.axa.com.sg/our-solutions/personal/health/axa-shield'
    elif(ward_type == 'B2 or C ward' and compensation == 'As Charged'):
        plan_type = 'Enhanced C - SG'
        link = 'https://www.income.com.sg/insurance/health-insurance/enhanced-incomeshield'
    elif(ward_type == 'B2 or C ward' and compensation == 'Limits'):
        plan_type = 'Medishield Life'
        link = 'https://www.moh.gov.sg/content/moh_web/medishield-life/about-medishield-life/medishield-life-benefits.html'
    combine = [plan_type, link]

    return combine

def isvalid_date(date):
    try:
        dateutil.parser.parse(date)
        return True
    except ValueError:
        return False

def isvalid_nationality(nationality):
    nationality_types = ['Singapore Citizen', 'Permanent Resident', 'Foreigner']
    return nationality in nationality_types

def isvalid_compensation(compensation):
    compensations = ['Limits', 'As Charged']
    return compensation in compensations

def isvalid_period(period):
    periods = [1, 2, 3, 4]
    return int(period) in periods

def isvalid_limit(limit):
    limits = ['Yes', 'No']
    return limit in limits

def build_validation_result(isvalid, violated_slot, message_content):
    return {
        'isValid': isvalid,
        'violatedSlot': violated_slot,
        'message': {'contentType': 'PlainText', 'content': message_content}
    }    

def validate_insurance_plan(slots):
    birthday = try_ex(lambda: slots['birth'])
    nationality = try_ex(lambda: slots['nation'])
    isp = try_ex(lambda: slots['isp'])
    ward_type = try_ex(lambda: slots['ward'])
    compensation = try_ex(lambda: slots['compensation'])
    period = try_ex(lambda: slots['period'])
    limit = try_ex(lambda: slots['limits'])    

    if birthday:
        if not isvalid_date(birthday):
            return build_validation_result(
                False, 
                'birth', 
                'I did not understand your birthdate. When were you born?'
                )
        if datetime.datetime.strptime(birthday, '%Y-%m-%d').date() > datetime.date.today():
            return build_validation_result(
                False, 
                'birth', 
                'You are not even born yet, how is this possible. Please tell me your correct birthdate.'
                )

    if nationality and not isvalid_nationality(nationality):
        return build_validation_result(
            False,
            'nation',
            'Sorry but the stated nationality does not exist, please choose from ones stated [Singapore Citizen, Permanent Resident, Foreigner]'
        )

    if compensation and not isvalid_compensation(compensation):
        return build_validation_result(
            False,
            'compensation',
            'Sorry but that plan does not exist, please choose either a plan with "As Charged" coverage or a plan with "Limits".'
            )

    if period and not isvalid_period(period):
        return build_validation_result(
            False,
            'period',
            'Please choose a number between 1-4'
        )

    if limit and not isvalid_limit(limit):
        return build_validation_result(
            False,
            'limits',
            'Please answer Yes/No, it"s that simple.'
        )

    return {'isValid': True}


""" --- Functions that control the bot's behavior --- """
def introduction(intent_request):

    session_attributes = intent_request['sessionAttributes'] if intent_request['sessionAttributes'] is not None else {}

    return close(
        session_attributes,
        'Fulfilled',
        {
            'contentType': 'PlainText',
            'content': 'Hey there! Try asking me "Which integrated Shield Plan is right for me?" to find out your recommended Insurance Plan!'
        }
    )


def insurance_bot(intent_request):

    birthday = try_ex(lambda: intent_request['currentIntent']['slots']['birth'])
    nationality = try_ex(lambda: intent_request['currentIntent']['slots']['nation'])
    isp = try_ex(lambda: intent_request['currentIntent']['slots']['isp'])
    ward_type = try_ex(lambda: intent_request['currentIntent']['slots']['ward'])
    compensation = try_ex(lambda: intent_request['currentIntent']['slots']['compensation'])
    period = try_ex(lambda: intent_request['currentIntent']['slots']['period'])
    limit = try_ex(lambda: intent_request['currentIntent']['slots']['limits']) 

    session_attributes = intent_request['sessionAttributes'] if intent_request['sessionAttributes'] is not None else {}

    last_confirmed_insurance = try_ex(lambda: session_attributes['lastConfirmedInsurance'])
    if last_confirmed_insurance:
        last_confirmed_insurance = json.loads(last_confirmed_insurance)
    confirmation_context = try_ex(lambda: session_attributes['confirmationContext'])

    # Load confirmation history and track the current reservation.
    insurance = json.dumps({
        'birth': birthday,
        'nation': nationality,
        'isp': isp,
        'ward': ward_type,
        'compensation': compensation,
        'period': period,
        'limits': limit
    })

    session_attributes['currentInsurance'] = insurance

    if intent_request['invocationSource'] == 'DialogCodeHook':
        # Validate any slots which have been specified.  If any are invalid, re-elicit for their value
        validation_result = validate_insurance_plan(intent_request['currentIntent']['slots'])
        if not validation_result['isValid']:
            slots = intent_request['currentIntent']['slots']
            slots[validation_result['violatedSlot']] = None

            return elicit_slot(
                session_attributes,
                intent_request['currentIntent']['name'],
                slots,
                validation_result['violatedSlot'],
                validation_result['message']
            )

        #If user is foreigner, straight away end chat
        if nationality == 'Foreigner':

            try_ex(lambda: session_attributes.pop('currentInsurance'))
            session_attributes['lastConfirmedInsurance'] = insurance            

            return close(
                session_attributes,
                'Fulfilled',
                {
                    'contentType': 'PlainText',
                    'content': 'I am sorry but foreigners currently cannot apply for an insurance plan in Sg.'
                    + ' It it still under development '
                    + 'so look out for it in the future! Thank you and have a nice day!'
                }
            )

        #Getting recommended plan, age and premium info
        if birthday and ward_type and compensation and period and limit:
           plan = generate_rec_plan(ward_type, compensation, period, limit)
           session_attributes['recPlan'] = plan[0]
           session_attributes['planLink'] = plan[1]

           info = calculate_age(birthday, plan)
           session_attributes['premium'] = info[0]
           session_attributes['age'] = info[1] 
           session_attributes['age2'] = info[2]

           outlay = cash_outlay(info)
           session_attributes['cashOutlay'] = outlay 
        else:
            try_ex(lambda: session_attributes.pop('recPlan'))
            try_ex(lambda: session_attributes.pop('planLink'))
            try_ex(lambda: session_attributes.pop('premium'))
            try_ex(lambda: session_attributes.pop('age'))
            try_ex(lambda: session_attributes.pop('age2'))
            try_ex(lambda: session_attributes.pop('cashOutlay'))

        session_attributes['currentInsurance'] = insurance
        return delegate(session_attributes, intent_request['currentIntent']['slots'])

    # Booking the hotel.  In a real application, this would likely involve a call to a backend service.
    logger.debug('InsurPlan under={}'.format(insurance))

    try_ex(lambda: session_attributes.pop('currentInsurance'))
    session_attributes['lastConfirmedInsurance'] = insurance

    return close(
        session_attributes,
        'Fulfilled',
        {
            'contentType': 'PlainText',
            'content': 'Your recommended plan would be ' + session_attributes['recPlan'] 
            + '! And since you are ' + session_attributes['age'] 
            + ' next year, you will be given a premium of about $'  + session_attributes['premium']
            + '. '
            + session_attributes['cashOutlay']
            + '. But in 10 years, your premium will be $' + session_attributes['age2'] 
            + '. If you want to know more about this insurance plan, you can go to ' 
            + session_attributes['planLink'] + ' for more details!'
        }
    )


# --- Intents ---


def dispatch(intent_request):
    """
    Called when the user specifies an intent for this bot.
    """

    logger.debug('dispatch userId={}, intentName={}'.format(intent_request['userId'], intent_request['currentIntent']['name']))
    intent_name = intent_request['currentIntent']['name']

    # Dispatch to your bot's intent handlers
    if intent_name == 'InsurePlan':
        return insurance_bot(intent_request)
    elif intent_name == 'Intro':
        return introduction(intent_request)

    raise Exception('Intent with name ' + intent_name + ' not supported')


# --- Main handler ---

def lambda_handler(event, context):

    return dispatch(event)

введите здесь описание изображения


person Luqman NurHakim Samsul Kahar    schedule 28.12.2017    source источник
comment
все зависит от того, какое намерение отменяется вводом. проверьте свои журналы для деталей, это может помочь.   -  person sid8491    schedule 28.12.2017
comment
Я действительно не понимаю, что вы пытаетесь сказать здесь, поэтому причина, по которой он предлагает повторяющиеся времена, заключается в том, что существует более одного намерения?   -  person Luqman NurHakim Samsul Kahar    schedule 28.12.2017
comment
нет, я говорю, что, возможно, для этих входных данных вызывается одно и то же намерение, что приводит к этой карточке ответа. вам следует проверить журналы CloudWatch на наличие различных входных данных, чтобы увидеть, как происходит процесс.   -  person sid8491    schedule 28.12.2017
comment
опубликуйте свой код и журналы, чтобы люди могли помочь вам лучше, иначе мы все будем продолжать гадать.   -  person sid8491    schedule 28.12.2017
comment
Я уже добавил свои коды, но для карточки ответа я редактировал ее только на amazon lex, а не на aws lambda.   -  person Luqman NurHakim Samsul Kahar    schedule 28.12.2017
comment
проверяется ли слот isp для намерения InsurePlan как требуемый? это может вызывать это.   -  person sid8491    schedule 28.12.2017
comment
Ага, проверено. Так что я должен снять флажок тогда?   -  person Luqman NurHakim Samsul Kahar    schedule 28.12.2017
comment
да, подробности в ответе   -  person sid8491    schedule 28.12.2017


Ответы (1)


Похоже, что ваш слот isp для намерения InsurePlan проверен как требуется, поэтому при вызове намерения проверяется, что значение слота для isp не выполнено, и отображается подсказка (карточка ответа) в твоем случае.

Вы должны снять отметку со слота isp и проверить его значение в DialogCodeHook и предоставить ElicitSlot при необходимости. И попробуйте предоставить карточку ответа из кода, а не из консоли, это более настраиваемо.

Надеюсь, поможет.

person sid8491    schedule 28.12.2017