Пример #1
0
def get_trash_pickup_info(mycity_request):
    """
    Generates a response to a trash day request

    :param mycity_request: MyCityRequestDataModel containing the user request
    :return: MyCityResponseDataModel containing the speech to return to the user
    """
    LOGGER.debug('Getting trash day information')

    response = MyCityResponseDataModel()
    set_address_in_session(mycity_request)
    current_address = \
            mycity_request.session_attributes.get(intent_constants.CURRENT_ADDRESS_KEY)
    if current_address is None:
        # Delegate to the Alexa interaction model for getting the user address
        LOGGER.debug('Requesting user address')
        response.dialog_directive = "Delegate"
    else:
        response.output_speech = _get_output_speech_for_address(
            current_address)
        response.card_title = CARD_TITLE_TRASH_DAY

    return response
Пример #2
0
def find_closest_police_station(mycity_request):
    """
    Finds the closest police station in Brookline
    to a given address

    :param mycity_request: MyCityRequestDataModel object
    :return: MyCityResponseDataModel object
    """
    logger.debug('Finding closest police station')

    response = MyCityResponseDataModel()
    set_address_in_session(mycity_request)
    current_address = mycity_request \
        .session_attributes \
        .get(intent_constants.CURRENT_ADDRESS_KEY)
    if current_address is None:
        response.dialog_directive = "Delegate"
    else:
        response.output_speech = _get_output_speech_for_address(current_address)
        response.card_title = CARD_TITLE_POLICE_STATION
        response.should_end_session = True

    return response
Пример #3
0
def find_closest_library(mycity_request):
    """
    Finds the closest library in Brookline to a given address

    :param mycity_request: MyCityRequestDataModel object
    :return MyCityResponseDataModel object
    """
    logger.debug('Finding closest library')

    response = MyCityResponseDataModel()
    set_address_in_session(mycity_request)
    current_address = \
            mycity_request.session_attributes.get(intent_constants.CURRENT_ADDRESS_KEY)
    if current_address is None:
        response.dialog_directive = "Delegate"
    else:
        response.output_speech = _get_output_speech_for_address(
            current_address)

    response.reprompt_text = None
    response.session_attributes = mycity_request.session_attributes
    response.card_title = CARD_TITLE_LIBRARY

    return response
def get_voting_precinct(mycity_request):
    """
    Generates a response to a voting precinct request

    :param mycity_request: MyCityRequestDataModel containing the user request
    :return: MyCityResponseDataModel containing the speech to return to the user
    """
    LOGGER.debug('Getting voting precinct information')

    response = MyCityResponseDataModel()
    set_address_in_session(mycity_request)
    current_address = \
            mycity_request.session_attributes.get(intent_constants.CURRENT_ADDRESS_KEY)
    if current_address is None:
        # Delegate to the Alexa interaction model for getting the user address
        LOGGER.debug('Requesting user address.')
        response.dialog_directive = "Delegate"
    else:
        response.output_speech = _get_output_speech_for_address(
            current_address, mycity_request)
        response.card_title = CARD_TITLE_VOTING
        response.should_end_session = True

    return response
Пример #5
0
def get_nearby_food_trucks(mycity_request):
    """
    Gets food truck info near an address

    :param mycity_request: MyCityRequestDataModel object
    :return: MyCityResponseObject
    """
    mycity_response = MyCityResponseDataModel()

    # Get current address location
    if CURRENT_ADDRESS_KEY in mycity_request.session_attributes:
        current_address = \
            mycity_request.session_attributes[CURRENT_ADDRESS_KEY]

        # Parsing street address using street-address package
        address_parser = StreetAddressParser()
        a = address_parser.parse(current_address)
        address = str(a["house"]) + " " + str(a["street_name"]) + " " \
                  + str(a["street_type"])

        # Parsing zip code
        zip_code = str(a["other"]).zfill(5) if a["other"] else None
        zip_code_key = intent_constants.ZIP_CODE_KEY
        if zip_code is None and zip_code_key in \
                mycity_request.session_attributes:
            zip_code = mycity_request.session_attributes[zip_code_key]

        # Get user's GIS Geocode Address and list of available trucks
        usr_addr = gis_utils.geocode_address(address)
        truck_unique_locations = get_truck_locations()
        nearby_food_trucks = []

        try:
            # Loop through food truck list and search for nearby food trucks
            # limit to 5 to speed up response
            counter = 0
            for t in truck_unique_locations:
                dist = gis_utils.calculate_distance(usr_addr, t)
                if dist <= MILE:
                    nearby_food_trucks.append(t)
                    counter += 1
                    if counter == FOOD_TRUCK_LIMIT:
                        break

            count = len(nearby_food_trucks)
            if count == 0:
                mycity_response.output_speech = "I didn't find any food trucks!"

            if count == 1:
                response = f"I found {count} food truck within a mile " \
                    "from your address! "
                response += add_response_text(nearby_food_trucks)
                mycity_response.output_speech = response

            if 1 < count <= 3:
                response = f"I found {count} food trucks within a mile " \
                    "from your address! "
                response += add_response_text(nearby_food_trucks)
                mycity_response.output_speech = response

            elif count > 3:
                response = f"There are at least {count} food trucks within " \
                           f"a mile from your address! Here are the first " \
                           + str(count) + ". "
                response += add_response_text(nearby_food_trucks)
                mycity_response.output_speech = response

        except InvalidAddressError:
            address_string = address
            if zip_code:
                address_string = address_string + " with zip code {}"\
                    .format(zip_code)
            mycity_response.output_speech = \
                speech_constants.ADDRESS_NOT_FOUND.format(address_string)
            mycity_response.dialog_directive = "ElicitSlotFoodTruck"
            mycity_response.reprompt_text = None
            mycity_response.session_attributes = \
                mycity_request.session_attributes
            mycity_response.card_title = "Food Trucks"
            mycity_request = clear_address_from_mycity_object(mycity_request)
            mycity_response = clear_address_from_mycity_object(mycity_response)
            return mycity_response

        except BadAPIResponse:
            mycity_response.output_speech = \
                "Hmm something went wrong. Maybe try again?"

        except MultipleAddressError:
            mycity_response.output_speech = \
                speech_constants.MULTIPLE_ADDRESS_ERROR.format(address)
            mycity_response.dialog_directive = "ElicitSlotZipCode"

    else:
        logger.error("Error: Called food_truck_intent with no address")
        mycity_response.output_speech = "I didn't understand that address, " \
                                        "please try again"

    # Setting reprompt_text to None signifies that we do not want to reprompt
    # the user. If the user does not respond or says something that is not
    # understood, the session will end.
    mycity_response.reprompt_text = None
    mycity_response.session_attributes = mycity_request.session_attributes
    mycity_response.card_title = "Food Trucks"

    return mycity_response
Пример #6
0
def get_trash_day_info(mycity_request):
    """
    Generates response object for a trash day inquiry.

    :param mycity_request: MyCityRequestDataModel object
    :return: MyCityResponseDataModel object
    """
    logger.debug('MyCityRequestDataModel received:' +
                 mycity_request.get_logger_string())

    mycity_response = MyCityResponseDataModel()

    # Determine if we have required address information. Request if we do not.
    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]

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

    # 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

    if not address_utils.is_address_valid(parsed_address):
        mycity_response.output_speech = speech_constants.ADDRESS_NOT_UNDERSTOOD
        mycity_response.dialog_directive = "ElicitSlotTrash"
        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)

    # currently assumes that trash day is the same for all units at
    # the same street address
    address = " ".join([
        parsed_address['AddressNumber'], parsed_address['StreetName'],
        parsed_address['StreetNamePostType']
    ])
    neighborhood = parsed_address["PlaceName"] \
        if "PlaceName" in parsed_address \
        and not parsed_address["PlaceName"].isdigit() \
        else None

    if "Neighborhood" in mycity_request.intent_variables and \
        "value" in mycity_request.intent_variables["Neighborhood"]:
        neighborhood = \
            mycity_request.intent_variables["Neighborhood"]["value"]

    try:
        trash_days = get_trash_and_recycling_days(address, neighborhood)
        trash_days_speech = build_speech_from_list_of_days(trash_days)

        mycity_response.output_speech = speech_constants.PICK_UP_DAY.format(
            trash_days_speech)
        mycity_response.should_end_session = True

    except InvalidAddressError:
        address_string = address
        mycity_response.output_speech = speech_constants.ADDRESS_NOT_FOUND.format(
            address_string)
        mycity_response.dialog_directive = "ElicitSlotTrash"
        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)

    except BadAPIResponse:
        mycity_response.output_speech = speech_constants.BAD_API_RESPONSE
        mycity_response.should_end_session = True

    except MultipleAddressError as error:
        addresses = [
            re.sub(r' \d{5}', '', address) for address in error.addresses
        ]
        address_list = ', '.join(addresses)
        mycity_response.output_speech = speech_constants.MULTIPLE_ADDRESS_ERROR.format(
            address_list)
        mycity_response.dialog_directive = "ElicitSlotNeighborhood"
        mycity_response.should_end_session = False

    # Setting reprompt_text to None signifies that we do not want to reprompt
    # the user. If the user does not respond or says something that is not
    # understood, the session will end.
    mycity_response.reprompt_text = None
    mycity_response.session_attributes = mycity_request.session_attributes
    mycity_response.card_title = CARD_TITLE
    return mycity_response
Пример #7
0
def get_trash_day_info(mycity_request):
    """
    Generates response object for a trash day inquiry.

    :param mycity_request: MyCityRequestDataModel object
    :return: MyCityResponseDataModel object
    """
    logger.debug('MyCityRequestDataModel received:' + mycity_request.get_logger_string())

    mycity_response = MyCityResponseDataModel()
    if intent_constants.CURRENT_ADDRESS_KEY in mycity_request.session_attributes:
        current_address = \
            mycity_request.session_attributes[intent_constants.CURRENT_ADDRESS_KEY]

        # grab relevant information from session address
        address_parser = StreetAddressParser()
        a = address_parser.parse(current_address)

        if not address_utils.is_address_valid(a):
            mycity_response.output_speech = speech_constants.ADDRESS_NOT_UNDERSTOOD
            mycity_response.dialog_directive = "ElicitSlotTrash"
            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)


        # currently assumes that trash day is the same for all units at
        # the same street address
        address = str(a['house']) + " " + str(a['street_full'])
        zip_code = str(a["other"]).zfill(5) if a["other"] and a["other"].isdigit() else None
        neighborhood = a["other"] if a["other"] and not a["other"].isdigit() else None

        zip_code_key = intent_constants.ZIP_CODE_KEY
        if zip_code is None and zip_code_key in \
                mycity_request.session_attributes:
            zip_code = mycity_request.session_attributes[zip_code_key]

        if "Neighborhood" in mycity_request.intent_variables and \
            "value" in mycity_request.intent_variables["Neighborhood"]:
            neighborhood = mycity_request.intent_variables["Neighborhood"]["value"]


        try:
            trash_days = get_trash_and_recycling_days(address, zip_code, neighborhood)
            trash_days_speech = build_speech_from_list_of_days(trash_days)

            mycity_response.output_speech = speech_constants.PICK_UP_DAY.format(trash_days_speech)
            mycity_response.should_end_session = True

        except InvalidAddressError:
            address_string = address
            if zip_code:
                address_string = address_string + " with zip code {}"\
                    .format(zip_code)
            mycity_response.output_speech = speech_constants.ADDRESS_NOT_FOUND.format(address_string)
            mycity_response.dialog_directive = "ElicitSlotTrash"
            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)

        except BadAPIResponse:
            mycity_response.output_speech = speech_constants.BAD_API_RESPONSE
            mycity_response.should_end_session = True
            
        except MultipleAddressError as error:
            addresses = [re.sub(r' \d{5}', '', address) for address in error.addresses]
            address_list = ', '.join(addresses)
            mycity_response.output_speech = speech_constants.MULTIPLE_ADDRESS_ERROR.format(address_list)
            mycity_response.dialog_directive = "ElicitSlotNeighborhood"
            mycity_response.should_end_session = False

    else:
        logger.error("Error: Called trash_day_intent with no address")
        mycity_response.output_speech = speech_constants.ADDRESS_NOT_UNDERSTOOD
        mycity_response.should_end_session = True

    # Setting reprompt_text to None signifies that we do not want to reprompt
    # the user. If the user does not respond or says something that is not
    # understood, the session will end.
    mycity_response.reprompt_text = None
    mycity_response.session_attributes = mycity_request.session_attributes
    mycity_response.card_title = CARD_TITLE
    return mycity_response
Пример #8
0
def get_nearby_food_trucks(mycity_request):
    """
    Gets food truck info near an address

    :param mycity_request: MyCityRequestDataModel object
    :return: MyCityResponseObject
    """
    mycity_response = MyCityResponseDataModel()

    # See if the user provided a custom address
    user_address = _get_address_coordinates_from_session(mycity_request)

    # If not, try to get user position from geolocation
    if not user_address:
        user_address = _get_address_coordinates_from_geolocation(
            mycity_request)

    if not user_address:
        # Couldn't get address. Request the to use geolocation if possible, fall back to
        # asking for speech input if device doesn't support it.
        if mycity_request.device_has_geolocation:
            return location_services_utils.request_geolocation_permission_response(
            )
        else:
            return request_user_address_response(mycity_request)

    # Get list of available trucks
    truck_unique_locations = get_truck_locations(user_address)

    # Create custom response based on number of trucks returned
    try:
        if len(truck_unique_locations) == 0:
            mycity_response.output_speech = "I didn't find any food trucks near you!"

        if len(truck_unique_locations) == 1:
            response = f"I found {len(truck_unique_locations)} food " \
                        f"truck within a mile from your address! "
            response += add_response_text(truck_unique_locations)
            mycity_response.output_speech = response

        if 1 < len(truck_unique_locations) <= 3:
            response = f"I found {len(truck_unique_locations)} food " \
                        f"trucks within a mile from your address! "
            response += add_response_text(truck_unique_locations)
            mycity_response.output_speech = response

        if len(truck_unique_locations) > 3:
            response = f"There are at least {len(truck_unique_locations)}" \
                        f" food trucks within a mile from your " \
                        f"address! Here are the first five. "
            response += add_response_text(truck_unique_locations)
            mycity_response.output_speech = response

    except InvalidAddressError:
        mycity_response.output_speech = \
            speech_constants.ADDRESS_NOT_FOUND.format("that address")
        mycity_response.dialog_directive = "ElicitSlotFoodTruck"
        mycity_response.reprompt_text = None
        mycity_response.session_attributes = \
            mycity_request.session_attributes
        mycity_response.card_title = CARD_TITLE
        mycity_request = clear_address_from_mycity_object(mycity_request)
        mycity_response = clear_address_from_mycity_object(mycity_response)
        mycity_response.should_end_session = True
        return mycity_response

    except BadAPIResponse:
        mycity_response.output_speech = \
            "Hmm something went wrong. Maybe try again?"

    except MultipleAddressError:
        mycity_response.output_speech = \
            speech_constants.MULTIPLE_ADDRESS_ERROR.format(address)
        mycity_response.dialog_directive = "ElicitSlotZipCode"

    # Setting reprompt_text to None signifies that we do not want to reprompt
    # the user. If the user does not respond or says something that is not
    # understood, the session will end.
    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 mycity_response
Пример #9
0
def get_nearby_food_trucks(mycity_request):
    """
    Gets food truck info near an address

    :param mycity_request: MyCityRequestDataModel object
    :return: MyCityResponseObject
    """
    mycity_response = MyCityResponseDataModel()

    coordinates = None
    user_address = None
    if intent_constants.CURRENT_ADDRESS_KEY not in \
            mycity_request.session_attributes:
        # If not provided, try to get the user address through
        # geolocation and device address

        coordinates = address_utils.\
            get_address_coordinates_from_geolocation(mycity_request)

        if not coordinates:
            if mycity_request.device_has_geolocation:
                return location_services_utils.\
                    request_geolocation_permission_response()

            # Try getting registered device address
            mycity_request, location_permissions = location_services_utils.\
                get_address_from_user_device(mycity_request)
            if not location_permissions:
                return location_services_utils.\
                    request_device_address_permission_response()

    if not coordinates:
        if intent_constants.CURRENT_ADDRESS_KEY \
            not in mycity_request.session_attributes:
            # We don't have coordinates or an address by now,
            # and we have all required permissions, ask the user
            return request_user_address_response(mycity_request)

        user_address = mycity_request.session_attributes[
            intent_constants.CURRENT_ADDRESS_KEY]
        coordinates = gis_utils.geocode_address(user_address)

    if not is_location_in_city(user_address, coordinates):
        mycity_response.output_speech = speech_const.NOT_IN_BOSTON_SPEECH
        mycity_response.should_end_session = True
        mycity_response.card_title = CARD_TITLE
        return mycity_response

    # Get list of available trucks
    truck_unique_locations = get_truck_locations(coordinates)

    # Create custom response based on number of trucks returned
    try:
        if len(truck_unique_locations) == 0:
            mycity_response.output_speech = "I didn't find any food " \
                                            "trucks near you!"

        if len(truck_unique_locations) == 1:
            response = f"I found {len(truck_unique_locations)} food " \
                        f"truck within a mile from your address! "
            response += add_response_text(truck_unique_locations)
            mycity_response.output_speech = response

        if 1 < len(truck_unique_locations) <= 3:
            response = f"I found {len(truck_unique_locations)} food " \
                        f"trucks within a mile from your address! "
            response += add_response_text(truck_unique_locations)
            mycity_response.output_speech = response

        if len(truck_unique_locations) > 3:
            response = f"There are at least {len(truck_unique_locations)}" \
                        f" food trucks within a mile from your " \
                        f"address! Here are the first five. "
            response += add_response_text(truck_unique_locations)
            mycity_response.output_speech = response

    except InvalidAddressError:
        mycity_response.output_speech = \
            ft_speech_constants.ADDRESS_NOT_FOUND.format("that address")
        mycity_response.dialog_directive = "ElicitSlotFoodTruck"
        mycity_response.reprompt_text = None
        mycity_response.session_attributes = \
            mycity_request.session_attributes
        mycity_response.card_title = CARD_TITLE
        mycity_request = clear_address_from_mycity_object(mycity_request)
        mycity_response = clear_address_from_mycity_object(mycity_response)
        mycity_response.should_end_session = True
        return mycity_response

    except BadAPIResponse:
        mycity_response.output_speech = \
            "Hmm something went wrong. Maybe try again?"

    # Setting reprompt_text to None signifies that we do not want to reprompt
    # the user. If the user does not respond or says something that is not
    # understood, the session will end.
    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 mycity_response
Пример #10
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
Пример #11
0
def get_nearby_food_trucks(mycity_request):
    """
    Gets food truck info near an address

    :param mycity_request: MyCityRequestDataModel object
    :return: MyCityResponseObject
    """
    mycity_response = MyCityResponseDataModel()

    # Get current address location
    if CURRENT_ADDRESS_KEY in mycity_request.session_attributes:
        current_address = \
            mycity_request.session_attributes[CURRENT_ADDRESS_KEY]

        # Parsing street address using street-address package
        address_parser = StreetAddressParser()
        a = address_parser.parse(current_address)
        address = str(a["house"]) + " " + str(a["street_name"]) + " " \
                  + str(a["street_type"])

        # Parsing zip code
        zip_code = str(a["other"]).zfill(5) if a["other"] else None
        zip_code_key = intent_constants.ZIP_CODE_KEY
        if zip_code is None and zip_code_key in \
                mycity_request.session_attributes:
            zip_code = mycity_request.session_attributes[zip_code_key]

        # Get user's GIS Geocode Address and list of available trucks
        usr_addr = gis_utils.geocode_address(address)
        truck_unique_locations = get_truck_locations(usr_addr)

        # Create custom response based on number of trucks returned
        try:
            if len(truck_unique_locations) == 0:
                mycity_response.output_speech = "I didn't find any food trucks!"

            if len(truck_unique_locations) == 1:
                response = f"I found {len(truck_unique_locations)} food " \
                           f"truck within a mile from your address! "
                response += add_response_text(truck_unique_locations)
                mycity_response.output_speech = response

            if 1 < len(truck_unique_locations) <= 3:
                response = f"I found {len(truck_unique_locations)} food " \
                           f"trucks within a mile from your address! "
                response += add_response_text(truck_unique_locations)
                mycity_response.output_speech = response

            if len(truck_unique_locations) > 3:
                response = f"There are at least {len(truck_unique_locations)}" \
                           f" food trucks within a mile from your " \
                           f"address! Here are the first five. "
                response += add_response_text(truck_unique_locations)
                mycity_response.output_speech = response

        except InvalidAddressError:
            address_string = address
            if zip_code:
                address_string = address_string + " with zip code {}"\
                    .format(zip_code)
            mycity_response.output_speech = \
                speech_constants.ADDRESS_NOT_FOUND.format(address_string)
            mycity_response.dialog_directive = "ElicitSlotFoodTruck"
            mycity_response.reprompt_text = None
            mycity_response.session_attributes = \
                mycity_request.session_attributes
            mycity_response.card_title = CARD_TITLE
            mycity_request = clear_address_from_mycity_object(mycity_request)
            mycity_response = clear_address_from_mycity_object(mycity_response)
            return mycity_response

        except BadAPIResponse:
            mycity_response.output_speech = \
                "Hmm something went wrong. Maybe try again?"

        except MultipleAddressError:
            mycity_response.output_speech = \
                speech_constants.MULTIPLE_ADDRESS_ERROR.format(address)
            mycity_response.dialog_directive = "ElicitSlotZipCode"

    else:
        logger.error("Error: Called food_truck_intent with no address")
        mycity_response.output_speech = "I didn't understand that address, " \
                                        "please try again"

    # Setting reprompt_text to None signifies that we do not want to reprompt
    # the user. If the user does not respond or says something that is not
    # understood, the session will end.
    mycity_response.reprompt_text = None
    mycity_response.session_attributes = mycity_request.session_attributes
    mycity_response.card_title = CARD_TITLE

    return mycity_response