def get_crime_incidents_intent(mycity_request): """ Populate MyCityResponseDataModel with crime incidents response information. :param mycity_request: MyCityRequestDataModel object :return: MyCityResponseDataModel object """ logger.debug('[method: get_crime_incidents_intent]') coordinates = {} current_address = None if intent_constants.CURRENT_ADDRESS_KEY not in \ mycity_request.session_attributes: coordinates = get_address_coordinates_from_geolocation(mycity_request) if not coordinates: if mycity_request.device_has_geolocation: return request_geolocation_permission_response() # Try getting registered device address mycity_request, location_permissions \ = get_address_from_user_device(mycity_request) if not location_permissions: return request_device_address_permission_response() # Convert address to coordinates if we only have user address if intent_constants.CURRENT_ADDRESS_KEY \ in mycity_request.session_attributes: current_address = mycity_request.session_attributes[ intent_constants.CURRENT_ADDRESS_KEY] coordinates = gis_utils.geocode_address(current_address) # If we don't have coordinates by now, and we have all required # permissions, ask the user for an address if not coordinates: return request_user_address_response(mycity_request) mycity_response = MyCityResponseDataModel() # If our address/coordinates are not in Boston, send a response letting # the user know the intent only works in Boston. if not is_location_in_city(current_address, coordinates): mycity_response.output_speech = NOT_IN_BOSTON_SPEECH else: response = get_crime_incident_response(coordinates) mycity_response.output_speech = \ _build_text_from_response(response) # 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_CRIME mycity_response.should_end_session = True return mycity_response
def _get_coordinates_for_address(address): """ Populates the GPS coordinates for the provided address :param address: address to query :return: a tuple of the form (lat, long) """ coordinates = geocode_address(address) logger.debug("Got coordinates: {}".format(coordinates)) _lat = "{:.2f}".format(float(coordinates[1])) _long = "{:.2f}".format(float(coordinates[0])) return (_lat, _long)
def get_address_coordinates_from_session(mycity_request) -> dict: """ Gets coordinates of the provided address from the session attributes. Returns None if no address is available. :param mycity_request: MyCityRequestDataModel for the current request :return dict: Dictionary containing coordinates of the address """ user_address = None if intent_constants.CURRENT_ADDRESS_KEY in mycity_request.session_attributes: current_address = mycity_request.session_attributes[ intent_constants.CURRENT_ADDRESS_KEY] parsed_address = StreetAddressParser().parse(current_address) address = " ".join([ parsed_address["house"], parsed_address["street_name"], parsed_address["street_type"] ]) user_address = gis_utils.geocode_address(address) return user_address
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
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
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
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