diff --git a/mycity/mycity/intents/feedback_intent.py b/mycity/mycity/intents/feedback_intent.py index 187fd6e1..13fa0530 100644 --- a/mycity/mycity/intents/feedback_intent.py +++ b/mycity/mycity/intents/feedback_intent.py @@ -4,12 +4,13 @@ """ from mycity.mycity_response_data_model import MyCityResponseDataModel +import mycity.intents.speech_constants.feedback_intent as speech_constants import requests import json import os SLACK_WEBHOOKS_URL = os.environ['SLACK_WEBHOOKS_URL'] - +CARD_TITLE = "Feedback" def submit_feedback(mycity_request): """ @@ -49,13 +50,12 @@ def submit_feedback(mycity_request): build_slack_message(feedback_type, feedback_text) ) if status == 200: - mycity_response.output_speech = 'Thanks for your feedback.' + mycity_response.output_speech = speech_constants.BIG_THANKS else: - mycity_response.output_speech = \ - 'There was a problem with your feedback. Please try again.' + mycity_response.output_speech = speech_constants.PROBLEM_SAVING_FEEDBACK mycity_response.reprompt_text = None mycity_response.session_attributes = mycity_request.session_attributes - mycity_response.card_title = "Feedback" + mycity_response.card_title = CARD_TITLE return mycity_response diff --git a/mycity/mycity/intents/get_alerts_intent.py b/mycity/mycity/intents/get_alerts_intent.py index 08cc7b6f..0e3a780c 100644 --- a/mycity/mycity/intents/get_alerts_intent.py +++ b/mycity/mycity/intents/get_alerts_intent.py @@ -20,6 +20,7 @@ from urllib import request from enum import Enum from mycity.mycity_response_data_model import MyCityResponseDataModel +import mycity.intents.speech_constants.get_alerts_intent as constants class Services(Enum): @@ -46,6 +47,7 @@ class Services(Enum): HEADER_2 = "str str--r m-v300" HEADER_3 = "t--sans t--cb lh--000 m-b500" +ALERTS_INTENT_CARD_TITLE = "City Alerts" def get_alerts_intent(mycity_request): """ @@ -66,7 +68,7 @@ def get_alerts_intent(mycity_request): alerts = prune_normal_responses(alerts) print("[dictionary after pruning]:\n" + str(alerts)) mycity_response.session_attributes = mycity_request.session_attributes - mycity_response.card_title = "City Alerts" + mycity_response.card_title = ALERTS_INTENT_CARD_TITLE mycity_response.reprompt_text = None mycity_response.output_speech = alerts_to_speech_output(alerts) mycity_response.should_end_session = True # leave this as True for right now @@ -89,7 +91,7 @@ def alerts_to_speech_output(alerts): for alert in alerts.values(): all_alerts += alert + ' ' if all_alerts.strip() == "": # this is a kludgy fix for the {'alert header': ''} bug - return "There are no alerts. City services are running on normal schedules." + return constants.NO_ALERTS else: return all_alerts diff --git a/mycity/mycity/intents/snow_parking_intent.py b/mycity/mycity/intents/snow_parking_intent.py index d7771dd9..2808c40a 100644 --- a/mycity/mycity/intents/snow_parking_intent.py +++ b/mycity/mycity/intents/snow_parking_intent.py @@ -2,24 +2,12 @@ import mycity.intents.intent_constants as intent_constants -import mycity.utilities.google_maps_utils as g_maps_utils +import mycity.intents.speech_constants.snow_parking_intent as constants from mycity.utilities.finder.FinderCSV import FinderCSV from mycity.mycity_response_data_model import MyCityResponseDataModel - - - - -# Constants -PARKING_INFO_URL = ("http://bostonopendata-boston.opendata.arcgis.com/datasets/" - "53ebc23fcc654111b642f70e61c63852_0.csv") -DRIVING_DIST = g_maps_utils.DRIVING_DISTANCE_TEXT_KEY -DRIVING_TIME = g_maps_utils.DRIVING_TIME_TEXT_KEY -OUTPUT_SPEECH_FORMAT = \ - ("The closest snow emergency parking lot, {Name}, is at " - "{Address}. It is {" + DRIVING_DIST + "} away and should take " - "you {" + DRIVING_TIME + "} to drive there. The lot has " - "{Spaces} spaces when empty. {Fee} {Comments} {Phone}") +PARKING_INFO_URL = "http://bostonopendata-boston.opendata.arcgis.com/datasets/53ebc23fcc654111b642f70e61c63852_0.csv" +SNOW_PARKING_CARD_TITLE = "Snow Parking" ADDRESS_KEY = "Address" @@ -32,10 +20,10 @@ def format_record_fields(record): fields from the closest record :return: None """ - record["Phone"] = "Call {} for information.".format(record["Phone"]) \ - if record["Phone"].strip() != "" else "" - record["Fee"] = " The fee is {}. ".format(record["Fee"]) \ - if record["Fee"] != "No Charge" else " There is no fee. " + record["Phone"] = constants.PHONE_PREPARED_STRING.format(record["Phone"]) \ + if record["Phone"].strip() != "" else constants.NO_PHONE + record["Fee"] = constants.FEE_PREPARED_STRING.format(record["Fee"]) \ + if record["Fee"] != "No Charge" else constants.NO_FEE def get_snow_emergency_parking_intent(mycity_request): @@ -54,22 +42,20 @@ def get_snow_emergency_parking_intent(mycity_request): mycity_response = MyCityResponseDataModel() if intent_constants.CURRENT_ADDRESS_KEY in mycity_request.session_attributes: finder = FinderCSV(mycity_request, PARKING_INFO_URL, ADDRESS_KEY, - OUTPUT_SPEECH_FORMAT, format_record_fields) + constants.OUTPUT_SPEECH_FORMAT, format_record_fields) print("Finding snow emergency parking for {}".format(finder.origin_address)) finder.start() mycity_response.output_speech = finder.get_output_speech() else: print("Error: Called snow_parking_intent with no address") - mycity_response.output_speech = "I need a valid address to find the closest parking" + mycity_response.output_speech = constants.ERROR_SPEECH # 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 = "Snow Parking" + mycity_response.card_title = SNOW_PARKING_CARD_TITLE return mycity_response - - diff --git a/mycity/mycity/intents/speech_constants/README.md b/mycity/mycity/intents/speech_constants/README.md new file mode 100644 index 00000000..28415e64 --- /dev/null +++ b/mycity/mycity/intents/speech_constants/README.md @@ -0,0 +1 @@ +To make testing easier, put any utterances for your intent here \ No newline at end of file diff --git a/mycity/mycity/intents/speech_constants/__init__.py b/mycity/mycity/intents/speech_constants/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mycity/mycity/intents/speech_constants/feedback_intent.py b/mycity/mycity/intents/speech_constants/feedback_intent.py new file mode 100644 index 00000000..908fb263 --- /dev/null +++ b/mycity/mycity/intents/speech_constants/feedback_intent.py @@ -0,0 +1,7 @@ +""" +Speech constants for feedback_intent.py + +""" + +BIG_THANKS = "Thanks for your feedback." +PROBLEM_SAVING_FEEDBACK = "There was a problem with your feedback. Please try again." diff --git a/mycity/mycity/intents/speech_constants/get_alerts_intent.py b/mycity/mycity/intents/speech_constants/get_alerts_intent.py new file mode 100644 index 00000000..a52297ed --- /dev/null +++ b/mycity/mycity/intents/speech_constants/get_alerts_intent.py @@ -0,0 +1,6 @@ +""" +Speech utterances for get_alerts_intent.py + +""" + +NO_ALERTS = "There are no alerts. City services are running on normal schedules." diff --git a/mycity/mycity/intents/speech_constants/snow_parking_intent.py b/mycity/mycity/intents/speech_constants/snow_parking_intent.py new file mode 100644 index 00000000..b90a0e92 --- /dev/null +++ b/mycity/mycity/intents/speech_constants/snow_parking_intent.py @@ -0,0 +1,20 @@ +""" +Speech utterances for snow_parking_intent.py + +""" + +import mycity.utilities.google_maps_utils as g_maps_utils + +OUTPUT_SPEECH_FORMAT = \ + ("The closest snow emergency parking lot, {Name}, is at " + "{Address}. It is {" + g_maps_utils.DRIVING_DISTANCE_TEXT_KEY + "} away and should take " + "you {" + g_maps_utils.DRIVING_TIME_TEXT_KEY + "} to drive there. The lot has " + "{Spaces} spaces when empty. {Fee} {Comments} {Phone}") + +# Formatted strings for the phone number and fee for the parking lot +PHONE_PREPARED_STRING = "Call {} for information." +FEE_PREPARED_STRING = " The fee is {}. " +NO_PHONE = "" +NO_FEE = " There is no fee. " + +ERROR_SPEECH = "I need a valid address to find the closest parking" diff --git a/mycity/mycity/intents/speech_constants/trash_intent.py b/mycity/mycity/intents/speech_constants/trash_intent.py new file mode 100644 index 00000000..c265dd64 --- /dev/null +++ b/mycity/mycity/intents/speech_constants/trash_intent.py @@ -0,0 +1,10 @@ +""" +Speech constants for the trash day intent + +""" + +PICK_UP_DAY = "Trash and recycling is picked up on {}." +ADDRESS_NOT_FOUND = "I can't seem to find {}. Try another address" +BAD_API_RESPONSE = "Hmm something went wrong. Maybe try again?" +MULTIPLE_ADDRESS_ERROR = "I found multiple places with the address {}. What's the zip code?" +ADDRESS_NOT_UNDERSTOOD = "I didn't understand that address, please try again" diff --git a/mycity/mycity/intents/speech_constants/unhandled_intent.py b/mycity/mycity/intents/speech_constants/unhandled_intent.py new file mode 100644 index 00000000..0bc76e18 --- /dev/null +++ b/mycity/mycity/intents/speech_constants/unhandled_intent.py @@ -0,0 +1,7 @@ +""" +Speech constants for unhandled_intent.py + +""" + +REPROMPT_TEXT = "So, what can I help you with today?" +OUTPUT_SPEECH = "I'm not sure what you're asking me. Please ask again." diff --git a/mycity/mycity/intents/trash_intent.py b/mycity/mycity/intents/trash_intent.py index 4b8b7c14..15029241 100644 --- a/mycity/mycity/intents/trash_intent.py +++ b/mycity/mycity/intents/trash_intent.py @@ -9,7 +9,9 @@ import re import requests from . import intent_constants +import mycity.intents.speech_constants.trash_intent as speech_constants +CARD_TITLE = "Trash Day" def get_trash_day_info(mycity_request): """ @@ -48,45 +50,39 @@ def get_trash_day_info(mycity_request): trash_days = get_trash_and_recycling_days(address, zip_code) trash_days_speech = build_speech_from_list_of_days(trash_days) - mycity_response.output_speech = "Trash and recycling is picked up on {}."\ - .format(trash_days_speech) + mycity_response.output_speech = speech_constants.PICK_UP_DAY.format(trash_days_speech) except InvalidAddressError: address_string = address if zip_code: address_string = address_string + " with zip code {}"\ .format(zip_code) - mycity_response.output_speech =\ - "I can't seem to find {}. Try another address"\ - .format(address_string) + 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 = "Trash Day" + 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?" + mycity_response.output_speech = speech_constants.BAD_API_RESPONSE except MultipleAddressError: - mycity_response.output_speech \ - = "I found multiple places with the address {}. " \ - "What's the zip code?".format(address) + mycity_response.output_speech = speech_constants.MULTIPLE_ADDRESS_ERROR.format(address) mycity_response.dialog_directive = "ElicitSlotZipCode" mycity_response.should_end_session = False else: print("Error: Called trash_day_intent with no address") - mycity_response.output_speech = "I didn't understand that address, please try again" + mycity_response.output_speech = speech_constants.ADDRESS_NOT_UNDERSTOOD # 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 = "Trash Day" + mycity_response.card_title = CARD_TITLE return mycity_response diff --git a/mycity/mycity/intents/unhandled_intent.py b/mycity/mycity/intents/unhandled_intent.py index d2e27f74..4381d3b0 100644 --- a/mycity/mycity/intents/unhandled_intent.py +++ b/mycity/mycity/intents/unhandled_intent.py @@ -3,6 +3,9 @@ """ from mycity.mycity_response_data_model import MyCityResponseDataModel +import mycity.intents.speech_constants.unhandled_intent as speech_constants + +CARD_TITLE = "Unhandled" def unhandled_intent(mycity_request): """ @@ -19,10 +22,9 @@ def unhandled_intent(mycity_request): ) mycity_response = MyCityResponseDataModel() mycity_response.session_attributes = mycity_request.session_attributes - mycity_response.card_title = "Unhandled" - mycity_response.reprompt_text = "So, what can I help you with today?" - mycity_response.output_speech = "I'm not sure what you're asking me. " \ - "Please ask again." + mycity_response.card_title = CARD_TITLE + mycity_response.reprompt_text = speech_constants.REPROMPT_TEXT + mycity_response.output_speech = speech_constants.OUTPUT_SPEECH mycity_response.should_end_session = False return mycity_response diff --git a/mycity/mycity/test/integration_tests/test_get_alerts.py b/mycity/mycity/test/integration_tests/test_get_alerts.py index 7d895581..a0c37dac 100644 --- a/mycity/mycity/test/integration_tests/test_get_alerts.py +++ b/mycity/mycity/test/integration_tests/test_get_alerts.py @@ -2,6 +2,8 @@ import mycity.test.integration_tests.intent_test_mixins as mix_ins import mycity.test.integration_tests.intent_base_case as base_case import mycity.test.test_constants as test_constants +import mycity.intents.get_alerts_intent as get_alerts +import mycity.intents.speech_constants.get_alerts_intent as get_alerts_speech_constants ######################################## @@ -13,7 +15,7 @@ class GetAlertsTestCase(mix_ins.RepromptTextTestMixIn, base_case.IntentBaseCase): intent_to_test = "GetAlertsIntent" - expected_title = 'City Alerts' + expected_title = get_alerts.ALERTS_INTENT_CARD_TITLE returns_reprompt_text = False # if we don't create copies of these dictionaries we'll create empty # dictionary errors after successive setUps and tearDowns @@ -42,7 +44,7 @@ def tearDown(self): return_value=no_alerts.copy()) def test_response_with_no_alerts(self, mock_get_alerts): response = self.controller.on_intent(self.request) - expected_response = test_constants.GET_ALERTS_EXPECTED_RESPONSE + expected_response = get_alerts_speech_constants.NO_ALERTS self.assertEqual(response.output_speech, expected_response) @mock.patch('mycity.intents.get_alerts_intent.get_alerts', diff --git a/mycity/mycity/test/integration_tests/test_snow_emergency_parking.py b/mycity/mycity/test/integration_tests/test_snow_emergency_parking.py index 0950839c..f4e8f22e 100644 --- a/mycity/mycity/test/integration_tests/test_snow_emergency_parking.py +++ b/mycity/mycity/test/integration_tests/test_snow_emergency_parking.py @@ -3,6 +3,7 @@ import mycity.test.integration_tests.intent_test_mixins as mix_ins import mycity.test.integration_tests.intent_base_case as base_case import mycity.test.test_constants as test_constants +import mycity.intents.snow_parking_intent as snow_parking ########################################## @@ -15,9 +16,9 @@ class SnowEmergencyTestCase(mix_ins.RepromptTextTestMixIn, base_case.IntentBaseCase): intent_to_test = "SnowParkingIntent" - expected_title = "Snow Parking" + expected_title = snow_parking.SNOW_PARKING_CARD_TITLE returns_reprompt_text = False - expected_card_title = "Snow Parking" + expected_card_title = snow_parking.SNOW_PARKING_CARD_TITLE def setUp(self): """ @@ -45,8 +46,7 @@ def fake_filter(record): test_constants.CLOSEST_PARKING_DRIVING_DATA self.get_driving_info_patch = \ mock.patch( - ('mycity.intents.snow_parking_intent.g_maps_utils' - '._get_driving_info'), + 'mycity.utilities.finder.Finder.g_maps_utils._get_driving_info', return_value=mock_get_driving_info_return ) self.mock_filtered_record.start() diff --git a/mycity/mycity/test/integration_tests/test_trash_intent.py b/mycity/mycity/test/integration_tests/test_trash_intent.py index bed2c516..c3925b4b 100644 --- a/mycity/mycity/test/integration_tests/test_trash_intent.py +++ b/mycity/mycity/test/integration_tests/test_trash_intent.py @@ -2,6 +2,7 @@ import mycity.test.test_constants as test_constants import mycity.test.integration_tests.intent_base_case as base_case import mycity.test.integration_tests.intent_test_mixins as mix_ins +import mycity.intents.trash_intent as trash_intent ################################### @@ -14,9 +15,9 @@ class TrashDayTestCase(mix_ins.RepromptTextTestMixIn, base_case.IntentBaseCase): intent_to_test = "TrashDayIntent" - expected_title = "Trash Day" + expected_title = trash_intent.CARD_TITLE returns_reprompt_text = False - expected_card_title = "Trash Day" + expected_card_title = trash_intent.CARD_TITLE def setUp(self): """ diff --git a/mycity/mycity/test/integration_tests/test_unhandled_intent.py b/mycity/mycity/test/integration_tests/test_unhandled_intent.py index b451c39f..865d409f 100644 --- a/mycity/mycity/test/integration_tests/test_unhandled_intent.py +++ b/mycity/mycity/test/integration_tests/test_unhandled_intent.py @@ -1,5 +1,6 @@ import mycity.test.integration_tests.intent_test_mixins as mix_ins import mycity.test.integration_tests.intent_base_case as base_case +import mycity.intents.unhandled_intent as unhandled_intent ######################################## @@ -13,6 +14,6 @@ class UnhandledIntentTestCase(mix_ins.RepromptTextTestMixIn, base_case.IntentBaseCase): intent_to_test = "UnhandledIntent" - expected_title = "Unhandled" + expected_title = unhandled_intent.CARD_TITLE returns_reprompt_text = True - expected_card_title = "Unhandled" + expected_card_title = unhandled_intent.CARD_TITLE diff --git a/mycity/mycity/test/test_constants.py b/mycity/mycity/test/test_constants.py index b57bf61e..aca783d5 100644 --- a/mycity/mycity/test/test_constants.py +++ b/mycity/mycity/test/test_constants.py @@ -850,8 +850,6 @@ 'Alert header': 'Godzilla inbound!' } -GET_ALERTS_EXPECTED_RESPONSE = "There are no alerts. City services are running on normal schedules." - # get_open_spaces intent OPEN_SPACES_TEST_CSV = os.getcwd() + "/mycity/test/test_data/.csv"