def fall_back(intent_request): # if no prev intent or prev intent is asking for symptoms session_attributes = helper.get_attribute(intent_request, 'sessionAttributes') current_intent = helper.get_attribute(intent_request, 'currentIntent') slots = helper.get_attribute(current_intent, 'slots') confirmation_status = helper.get_attribute(current_intent, 'confirmationStatus') # TODO: if prev intent is asking for body part # TODO: too many failed attempts should terminate. if confirmation_status == helper.ConfirmationStatus.NONE.value: user_utterance = intent_request['inputTranscript'] if user_utterance == '': return helper.elicit_slot(session_attributes, INTENT_REPORT_SYMPTOM, slots, SLOT_SYMPTOM_ONE, msg_strings.get('CLARIFICATION')) message = f"your said '{user_utterance}', is that right?" slots[SLOT_SYMPTOM_ONE] = user_utterance helper.append_session_attr(session_attributes, UNKNOWN_SYMPTOM_ATTR, user_utterance) return helper.confirm_intent(session_attributes, INTENT_REPORT_SYMPTOM, slots, message_content=message, message_type='PlainText') elif confirmation_status == helper.ConfirmationStatus.DENIED.value: return helper.elicit_slot(session_attributes, INTENT_REPORT_SYMPTOM, slots, SLOT_SYMPTOM_ONE, msg_strings.get('AFTER_SYMPTOM_DENY')) else: return helper.elicit_slot(session_attributes, INTENT_REPORT_SYMPTOM, slots, SLOT_SYMPTOM_ONE, msg_strings.get('CLARIFICATION'))
def no_symptom(intent_request): session_attributes = helper.get_attribute(intent_request, 'sessionAttributes') symptoms = helper.get_list_from_session(session_attributes, SYMPTOM_ATTR) current_intent = helper.get_attribute(intent_request, 'currentIntent') slots = helper.get_attribute(current_intent, 'slots') confirmation_status = helper.get_attribute(current_intent, 'confirmationStatus') intent_name = helper.get_attribute(current_intent, 'name') if confirmation_status == helper.ConfirmationStatus.NONE.value: if len(symptoms) == 0: # add confirmation for no symptoms return helper.confirm_intent(session_attributes, intent_name, slots, message_content=msg_strings.get('NO_SYMPTOM_CONFIRM')) elif confirmation_status == helper.ConfirmationStatus.DENIED.value: return helper.elicit_slot(session_attributes, INTENT_REPORT_SYMPTOM, slots, SLOT_SYMPTOM_ONE, message_content=msg_strings.get('ASK_SYMPTOM_DETAIL')) # ready to log symptoms user = helper.lookup_user(session_attributes) local_time_reported = get_current_time_for_user(user) unknown_symptoms = helper.get_list_from_session(session_attributes, UNKNOWN_SYMPTOM_ATTR) symptom_reporter.report(user.uid, local_time_reported, symptoms, unknown_symptoms) update_survey_completion(user.uid, local_time_reported, BOT_SYMPTOM_NAME) session_attributes['NextBot'] = get_next_survey_bot(user.uid, local_time_reported) return helper.close(session_attributes, helper.FulfillmentState.FULFILLED, message_content=msg_strings.get('FINISH_SYMPTOM_REPORT'))
def verify_identity(intent_request): """ Handler for the verifying identity :param intent_request: :return: """ session_attributes = helper.get_attribute(intent_request, 'sessionAttributes') current_intent = helper.get_attribute(intent_request, 'currentIntent') slots = helper.get_attribute(current_intent, 'slots') user = helper.lookup_user(session_attributes) zipcode_input = helper.get_attribute(slots, SLOT_ZIPCODE, None) if zipcode_input == user.zip_code: logger.info('zip code match!') user_local_tz = pytz.timezone(user.timezone) today = datetime.now(tz=timezone.utc).astimezone(user_local_tz) session_attributes['NextBot'] = get_next_survey_bot(user.uid, today) session_attributes[AUTH_RESULT_ATTR] = 'AuthSuccess' msg = verify_success_msg(user) return helper.close(session_attributes, helper.FulfillmentState.FULFILLED, message_content=msg, message_type='PlainText') else: logger.info('zip code mismatch!') msg = msg_strings.get('ZIP_CODE_MISMATCH').format(zipcode_input) attempt_count = int( helper.get_attribute(session_attributes, ATTEMPT_COUNT_ATTR, "1")) if attempt_count >= MAX_RETRY: msg += msg_strings.get('ZIP_CODE_GOODBYE') logger.info( f'attempt count ({attempt_count}) reached max retry count. failed authentication.' ) session_attributes[AUTH_RESULT_ATTR] = 'AuthFail' return helper.close(session_attributes, helper.FulfillmentState.FULFILLED, message_content=helper.wrap_ssml_tag(msg), message_type='SSML') else: session_attributes[ATTEMPT_COUNT_ATTR] = attempt_count + 1 msg += msg_strings.get('ZIP_CODE_RETRY') logger.info( f'attempt count ({attempt_count}) less than max retry count {MAX_RETRY}.' ) return helper.elicit_slot( session_attributes, INTENT_VERIFY_IDENTITY, slots, SLOT_ZIPCODE, message_content=helper.wrap_ssml_tag(msg), message_type='SSML')
def yes_med(intent_request): session_attributes = helper.get_attribute(intent_request, 'sessionAttributes') current_intent = helper.get_attribute(intent_request, 'currentIntent') slots = helper.get_attribute(current_intent, 'slots') return helper.elicit_slot( session_attributes, INTENT_MEDICATION_TIME, slots, SLOT_MED_TIME, '<speak>Great. When did you take your medication today?</speak>', message_type='SSML')
def medication_time(intent_request): """ Handler for the medication time intent :param intent_request: lex intent request :return: """ session_attributes = helper.get_attribute(intent_request, 'sessionAttributes') current_intent = helper.get_attribute(intent_request, 'currentIntent') slots = helper.get_attribute(current_intent, 'slots') slot_details = helper.get_attribute(current_intent, 'slotDetails') intent_name = helper.get_attribute(current_intent, 'name') if helper.is_validation_request(intent_request): return validate_medication_time(intent_name, session_attributes, slot_details, slots) med_taken_time = slots[SLOT_MED_TIME] hh = int(med_taken_time.split(':')[0]) mm = int(med_taken_time.split(':')[1]) user = helper.lookup_user(session_attributes) local_time_reported = get_current_time_for_user(user) now_with_no_timezone = datetime.now() med_taken_datetime = now_with_no_timezone.replace(hour=hh, minute=mm, second=0) local_med_time = pytz.timezone(user.timezone).localize(med_taken_datetime) # TODO: for production, handle cases when user reported the same info multiple times. med_diary.log_med(user.uid, time_reported=local_time_reported, med_taken=True, time_taken=local_med_time) update_survey_completion(user.uid, local_time_reported, BOT_MEDICATION_NAME) session_attributes['NextBot'] = get_next_survey_bot( user.uid, local_time_reported) return helper.close(session_attributes, helper.FulfillmentState.FULFILLED, message_content=msg_strings.get('FINISH_MED_DIARY'))
def decorate_transcript(intent_request): logger.debug("spoken text: {}".format( intent_request['inputTranscript'])) # consider using a intercepter for this intent_request['sessionAttributes'] = helper.get_attribute( intent_request, 'sessionAttributes') conversation_history_serialized = intent_request[ 'sessionAttributes'].get('transcripts', '[]') conversation_history = json.loads(conversation_history_serialized) conversation_history.append({ 'time': datetime.now().isoformat(), 'user': intent_request['inputTranscript'] }) intent_request['sessionAttributes']['transcripts'] = json.dumps( conversation_history)
def validate_symptom_input(intent_name, session_attributes, slot_details, slots): symptom_name = slots.get(SLOT_SYMPTOM_ONE, None) # TODO: add support for multiple symptoms if not symptom_name: # did not get symptom symptom_slot_detail = helper.get_attribute(slot_details, SLOT_SYMPTOM_ONE, {}) unknown_symptom = symptom_slot_detail.get('originalValue', None) if unknown_symptom: logger.info(f'encountered unknown symptom: {unknown_symptom}') helper.append_session_attr(session_attributes, UNKNOWN_SYMPTOM_ATTR, unknown_symptom) symptom_name = unknown_symptom slots[SLOT_SYMPTOM_ONE] = symptom_name else: return helper.elicit_slot(session_attributes, intent_name, slots, SLOT_SYMPTOM_ONE, msg_strings.get('ASK_SYMPTOM')) pain_level = slots.get(SLOT_PAIN_LEVEL, None) if symptom_name in intensity_symptom and pain_level: try: int(pain_level) except ValueError: return helper.elicit_slot(session_attributes, intent_name, slots, SLOT_PAIN_LEVEL, msg_strings.get('PAIN_LEVEL_VALIDATION_FAILED').format(symptom_name)) # verify within range if int(pain_level) < 0 or int(pain_level) > 10: return helper.elicit_slot(session_attributes, intent_name, slots, SLOT_PAIN_LEVEL, msg_strings.get('PAIN_LEVEL_VALIDATION_FAILED').format(symptom_name)) else: # confirm intensity level if it's above threshold if int(pain_level) >= INTENSITY_THRESHOLD: msg = msg_strings.get('CONFIRM_INTENSITY').format(symptom_name, pain_level) return helper.confirm_intent(session_attributes, intent_name, slots, msg) return helper.delegate(session_attributes, slots) else: if symptom_name in localized_symptom: # need to distinguish which body part has the symptom body_part = slots.get(SLOT_BODY_PART, None) if not body_part: return helper.elicit_slot(session_attributes, intent_name, slots, SLOT_BODY_PART, msg_strings.get('ASK_SYMPTOM_BODY_PART').format(symptom_name)) else: modifier = slots.get(SLOT_BODY_PART_MODIFIER, None) return confirm_symptom(session_attributes, intent_name, slots, symptom_name, body_part, modifier) else: return confirm_symptom(session_attributes, intent_name, slots, symptom_name)
def no_med(intent_request): session_attributes = helper.get_attribute(intent_request, 'sessionAttributes') user = helper.lookup_user(session_attributes) current_time = get_current_time_for_user(user) if user.caretaker_num: logger.info( f'Will send notification to care taker: {user.caretaker_num}') time_str = format_only_time_to_str(current_time) msg = CARETAKER_MED_MISSING_MESSAGE.format(user.uid, time_str) send_sms(user.caretaker_num, msg) else: logger.info('No caretaker to notify.') med_diary.log_med(user.uid, time_reported=current_time, med_taken=False) update_survey_completion(user.uid, current_time, BOT_MEDICATION_NAME) session_attributes['NextBot'] = get_next_survey_bot(user.uid, current_time) return helper.close(session_attributes, helper.FulfillmentState.FULFILLED, message_content=msg_strings.get('DID_NOT_TAKE_MED'))
def no_later(intent_request): session_attributes = helper.get_attribute(intent_request, 'sessionAttributes') return helper.close(session_attributes, helper.FulfillmentState.FULFILLED, message_content=msg_strings.get('AFTER_USER_DENY_TIME'))
def report_symptom(intent_request): """ Handler for the medication time intent :param intent_request: lex intent request :return: """ session_attributes = helper.get_attribute(intent_request, 'sessionAttributes') current_intent = helper.get_attribute(intent_request, 'currentIntent') slots = helper.get_attribute(current_intent, 'slots') slot_details = helper.get_attribute(current_intent, 'slotDetails') intent_name = helper.get_attribute(current_intent, 'name') confirmation_status = helper.get_attribute(current_intent, 'confirmationStatus') symptom = slots.get(SLOT_SYMPTOM_ONE, None) body_part = slots.get(SLOT_BODY_PART, None) modifier = slots.get(SLOT_BODY_PART_MODIFIER, None) intensity = slots.get(SLOT_PAIN_LEVEL, None) unknown_symptoms = helper.get_list_from_session(session_attributes, UNKNOWN_SYMPTOM_ATTR) if confirmation_status == helper.ConfirmationStatus.NONE.value: if helper.is_validation_request(intent_request): return validate_symptom_input(intent_name, session_attributes, slot_details, slots) elif confirmation_status == helper.ConfirmationStatus.DENIED.value: # deny could be for intensity level or for symptoms if symptom == unknown_symptoms[-1]: unknown_symptoms.pop() session_attributes[UNKNOWN_SYMPTOM_ATTR] = json.dumps(unknown_symptoms) slots = {} return helper.elicit_slot(session_attributes, intent_name, slots, SLOT_SYMPTOM_ONE, msg_strings.get('AFTER_SYMPTOM_DENY')) msg = '' # after confirming the first symptom, say sorry to hear to show sympathy. However, only say this once per session if not helper.get_attribute(session_attributes, 'alreadySaidSorry'): if symptom in unknown_symptoms: msg += 'Sorry to hear that. ' else: msg += 'Sorry to hear that you ' + find_descriptor_for_symptom(symptom) + ". " session_attributes['alreadySaidSorry'] = 'true' if symptom in intensity_symptom: # gather pain level if not intensity: msg += msg_strings.get('RATE_PAIN_PROMPT') return helper.elicit_slot(session_attributes, intent_name, slots, SLOT_PAIN_LEVEL, msg) elif int(intensity) >= INTENSITY_THRESHOLD: user = helper.lookup_user(session_attributes) local_time_reported = get_current_time_for_user(user) symptom_reporter.severe_symptom_report(user, local_time_reported, body_part, intensity) msg += f'We will notify your medical provider of your {symptom}. ' else: msg += f"Got it. That's a {intensity} out of 10. " symptom_obj = {'symptom': symptom} if body_part: symptom_obj['bodyPart'] = body_part if modifier: symptom_obj['modifier'] = modifier if intensity: symptom_obj['intensity'] = int(intensity) helper.append_session_attr(session_attributes, SYMPTOM_ATTR, symptom_obj) msg += msg_strings.get('ADDITIONAL_SYMPTOM_QUERY') return helper.elicit_intent(session_attributes, message_content=msg)
def yes_symptom(intent_request): session_attributes = helper.get_attribute(intent_request, 'sessionAttributes') symptoms = helper.get_list_from_session(session_attributes, SYMPTOM_ATTR) msg = msg_strings.get('ASK_SYMPTOM_FOLLOW_UP') if symptoms else msg_strings.get('ASK_SYMPTOM_DETAIL') return helper.elicit_intent(session_attributes, message_content=msg)
def not_supported_intent_handler(intent_request): session_attributes = helper.get_attribute(intent_request, 'sessionAttributes') return helper.close(session_attributes, helper.FulfillmentState.FAILED, message_content=msg_strings.get('NOT_SUPPORTED'))