def get_alerts_intent(
    mycity_request: MyCityRequestDataModel,
    get_alerts_function_for_test: typing.Callable[[], typing.Dict] = None,
    prune_normal_responses_function_for_test: typing.Callable[
        [], typing.Dict] = None,
    alerts_to_speech_output_function_for_test: typing.Callable[
        [], typing.AnyStr] = None
) -> MyCityResponseDataModel:
    """
    Generate response object with information about citywide alerts

    :param mycity_request:                            MyCityRequestDataModel object
    :param get_alerts_function_for_test:              Injectable function for unit tests
    :param prune_normal_responses_function_for_test:  Injectable function for unit tests
    :param alerts_to_speech_output_function_for_test: Injectable function for unit tests
    :return:                                          MyCityResponseDataModel object
    """
    logger.debug('MyCityRequestDataModel received:' +
                 mycity_request.get_logger_string())

    alerts = get_alerts(
    ) if get_alerts_function_for_test is None else get_alerts_function_for_test(
    )
    logger.debug("[dictionary with alerts scraped from boston.gov]:\n" +
                 str(alerts))

    pruned_alerts = prune_normal_responses(alerts) \
        if prune_normal_responses_function_for_test is None else prune_normal_responses_function_for_test(alerts)
    logger.debug("[dictionary after pruning]:\n" + str(alerts))

    mycity_response = _create_response_object()
    mycity_response.output_speech = alerts_to_speech_output(pruned_alerts) \
        if alerts_to_speech_output_function_for_test is None else alerts_to_speech_output_function_for_test(pruned_alerts)
    return mycity_response
def get_inclement_weather_alert(
    mycity_request: MyCityRequestDataModel,
    get_alerts_function_for_test: typing.Callable[[], typing.Dict] = None,
) -> MyCityResponseDataModel:
    """
    Generates a response with information about any inclement weather alerts.

    :param mycity_request:                            MyCityRequestDataModel object
    :param get_alerts_function_for_test:              Injectable function for unit tests
    :return:                                          MyCityResponseDataModel object
    """
    logger.debug('MyCityRequestDataModel received:' +
                 mycity_request.get_logger_string())

    alerts = get_alerts(
    ) if get_alerts_function_for_test is None else get_alerts_function_for_test(
    )
    logger.debug("[dictionary with alerts scraped from boston.gov]:\n" +
                 str(alerts))

    logger.debug("filtering for inclement weather alerts")
    output_speech = constants.NO_INCLEMENT_WEATHER_ALERTS
    if Services.ALERT_HEADER.value in alerts:
        if any(query in alerts[Services.ALERT_HEADER.value].lower()
               for query in SNOW_ALERT_QUERY):
            logger.debug("inclement weather alert found")
            output_speech = alerts[Services.ALERT_HEADER.value]

    mycity_response = _create_response_object()
    mycity_response.session_attributes = mycity_request.session_attributes
    mycity_response.output_speech = output_speech
    return mycity_response
Ejemplo n.º 3
0
def get_alerts_intent(
        mycity_request: MyCityRequestDataModel,
        get_alerts_function_for_test: typing.Callable[[], typing.Dict] = None,
        prune_normal_responses_function_for_test:
        typing.Callable[[], typing.Dict] = None,
        alerts_to_speech_output_function_for_test:
        typing.Callable[[], typing.AnyStr] = None
) -> MyCityResponseDataModel:
    """
    Generate response object with information about citywide alerts

    :param mycity_request: MyCityRequestDataModel object
    :param get_alerts_function_for_test: Injectable function for unit tests
    :param prune_normal_responses_function_for_test: Injectable function
     for unit tests
    :param alerts_to_speech_output_function_for_test: Injectable function
    for unit tests
    :return: MyCityResponseDataModel object
    """
    logger.debug('MyCityRequestDataModel received:' +
                 mycity_request.get_logger_string())

    # get the intent_variables and sessions_attribute object from the request
    intent_variables = mycity_request.intent_variables
    session_attributes = mycity_request.session_attributes
    
    service_name = intent_variables['ServiceName'].get('value') \
        if 'ServiceName' in intent_variables else None
    if service_name:
        service_name = service_name.lower()

    session_alerts = session_attributes.get('alerts', None)
    if not session_alerts:
        session_alerts = get_pruned_alerts(
            get_alerts_function_for_test, prune_normal_responses_function_for_test)

    # Build the response.
    mycity_response = _create_response_object()
    mycity_response.session_attributes = session_attributes.copy()
    mycity_response.should_end_session = True

    if session_alerts is None:
        logger.debug(
            "Could not get alerts from session attributes or Boston webpage")
        mycity_response.should_end_session = False
        mycity_response.output_speech = constants.LAUNCH_REPROMPT_SPEECH
        return mycity_response

    if service_name is None:
        # If the user hasn't give us a service name, check if we should
        # list alerts if there are only a few, or ask the user to select one
        if len(session_alerts) > 1:
            mycity_response.session_attributes['alerts'] = session_alerts
            mycity_response.dialog_directive = "ElicitSlotServiceName"
            mycity_response.should_end_session = False
            mycity_response.output_speech = list_alerts_output(session_alerts)
        else:
            mycity_response.output_speech = \
                alerts_to_speech_output(session_alerts) \
                if alerts_to_speech_output_function_for_test is None \
                else alerts_to_speech_output_function_for_test(session_alerts)
    elif service_name == 'all':
        # Respond with all alert text
        mycity_response.output_speech = \
            alerts_to_speech_output(session_alerts) \
            if alerts_to_speech_output_function_for_test is None \
            else alerts_to_speech_output_function_for_test(session_alerts)
    elif service_name in session_alerts:
        # Grab the requested service alert
        alert = {service_name: session_alerts[service_name]}
        mycity_response.output_speech = alerts_to_speech_output(alert) \
            if alerts_to_speech_output_function_for_test is None \
            else alerts_to_speech_output_function_for_test(alert)
    else:
        # Service not found. Re-ask for the desired service.
        mycity_response.session_attributes['alerts'] = session_alerts
        mycity_response.should_end_session = False
        mycity_response.output_speech = constants.INVALID_SERVICE_NAME_SCRIPT
        mycity_response.output_speech += list_alerts_output(session_alerts)
        mycity_response.dialog_directive = "ElicitSlotServiceName"

    return mycity_response
Ejemplo n.º 4
0
def get_voting_location(mycity_request: MyCityRequestDataModel) -> \
        MyCityResponseDataModel:
    """
    Generates response object for a polling location inquiry which includes
    a user's location to vote.

    :param mycity_request: MyCityRequestDataModel object
    :return: MyCityResponseDataModel object
    """

    logger.debug('MyCityRequestDataModel received:' +
                 mycity_request.get_logger_string())
    mycity_response = MyCityResponseDataModel()
    mycity_response.card_title = CARD_TITLE

    # check for address for locating voting location
    if intent_constants.CURRENT_ADDRESS_KEY not in \
        mycity_request.session_attributes:
        mycity_request, location_permissions = \
            get_address_from_user_device(mycity_request)
        if not location_permissions:
            return request_device_address_permission_response()
        elif intent_constants.CURRENT_ADDRESS_KEY not in \
                mycity_request.session_attributes:
            return request_user_address_response(mycity_request)

    current_address = \
        mycity_request.session_attributes[intent_constants.CURRENT_ADDRESS_KEY]

    # If we have more specific info then just the street
    # address, make sure we are in Boston
    if not is_address_in_city(current_address):
        mycity_response.output_speech = NOT_IN_BOSTON_SPEECH
        mycity_response.should_end_session = True
        mycity_response.card_title = CARD_TITLE
        return mycity_response

    # grab relevant information from session address
    parsed_address, _ = usaddress.tag(current_address)

    if not is_address_valid(parsed_address):
        mycity_response.output_speech = ADDRESS_NOT_UNDERSTOOD
        mycity_response.dialog_directive = "ElicitSlotVotingIntent"
        mycity_response.reprompt_text = None
        mycity_response.session_attributes = mycity_request.session_attributes
        mycity_response.card_title = CARD_TITLE
        mycity_response.should_end_session = True
        return clear_address_from_mycity_object(mycity_response)

    zipcode = None
    if "Zipcode" in mycity_request.intent_variables and \
        "value" in mycity_request.intent_variables["Zipcode"]:
        zipcode = \
                mycity_request.intent_variables["Zipcode"]["value"].zfill(5)

    mycity_response.reprompt_text = None
    mycity_response.should_end_session = True

    try:
        top_candidate = gis_utils.geocode_address(current_address, zipcode)
        ward_precinct = vote_utils.get_ward_precinct_info(top_candidate)
        poll_location = vote_utils.get_polling_location(ward_precinct)
        output_speech = LOCATION_SPEECH. \
            format(poll_location[LOCATION_NAME], poll_location[LOCATION_ADDRESS])
        mycity_response.output_speech = output_speech
    except ParseError:
        mycity_response.output_speech = NO_WARD_OR_PRECINCT
    except BadAPIResponse:
        mycity_response.output_speech = BAD_API_RESPONSE
    except MultipleAddressError as error:
        address_list = ', '.join(error.addresses)
        mycity_response.output_speech = MULTIPLE_ADDRESS_ERROR
        mycity_response.dialog_directive = "ElicitSlotZipCode"
        mycity_response.should_end_session = False

    return mycity_response