def test_state_none_name(self): # Arrange dictionary = {} user_state = UserState(MemoryStorage(dictionary)) # Act with self.assertRaises(TypeError) as _: user_state.create_property(None)
async def test_user_state_bad_from_throws(self): dictionary = {} user_state = UserState(MemoryStorage(dictionary)) context = TestUtilities.create_empty_context() context.activity.from_property = None test_property = user_state.create_property("test") with self.assertRaises(AttributeError): await test_property.get(context)
async def test_state_set_no_load(self): """Should be able to set a property with no Load""" # Arrange dictionary = {} user_state = UserState(MemoryStorage(dictionary)) context = TestUtilities.create_empty_context() # Act property_a = user_state.create_property("property_a") await property_a.set(context, "hello")
async def test_state_multiple_loads(self): """Should be able to load multiple times""" # Arrange dictionary = {} user_state = UserState(MemoryStorage(dictionary)) context = TestUtilities.create_empty_context() # Act user_state.create_property("property_a") await user_state.load(context) await user_state.load(context)
async def test_state_get_no_load_with_default(self): """Should be able to get a property with no Load and default""" # Arrange dictionary = {} user_state = UserState(MemoryStorage(dictionary)) context = TestUtilities.create_empty_context() # Act property_a = user_state.create_property("property_a") value_a = await property_a.get(context, lambda: "Default!") self.assertEqual("Default!", value_a)
async def test_state_get_no_load_no_default(self): """Cannot get a string with no default set""" # Arrange dictionary = {} user_state = UserState(MemoryStorage(dictionary)) context = TestUtilities.create_empty_context() # Act property_a = user_state.create_property("property_a") value_a = await property_a.get(context) # Assert self.assertIsNone(value_a)
async def test_state_bool_no_default(self): """Cannot get a bool with no default set""" # Arange dictionary = {} user_state = UserState(MemoryStorage(dictionary)) context = TestUtilities.create_empty_context() # Act test_property = user_state.create_property("test") value = await test_property.get(context) # Assert self.assertFalse(value)
async def test_storage_not_called_no_changes(self): """Verify storage not called when no changes are made""" # Mock a storage provider, which counts read/writes dictionary = {} async def mock_write_result(self): # pylint: disable=unused-argument return async def mock_read_result(self): # pylint: disable=unused-argument return {} mock_storage = MemoryStorage(dictionary) mock_storage.write = MagicMock(side_effect=mock_write_result) mock_storage.read = MagicMock(side_effect=mock_read_result) # Arrange user_state = UserState(mock_storage) context = TestUtilities.create_empty_context() # Act property_a = user_state.create_property("property_a") self.assertEqual(mock_storage.write.call_count, 0) await user_state.save_changes(context) await property_a.set(context, "hello") self.assertEqual(mock_storage.read.call_count, 1) # Initial save bumps count self.assertEqual(mock_storage.write.call_count, 0) # Initial save bumps count await property_a.set(context, "there") self.assertEqual(mock_storage.write.call_count, 0) # Set on property should not bump await user_state.save_changes(context) self.assertEqual(mock_storage.write.call_count, 1) # Explicit save should bump value_a = await property_a.get(context) self.assertEqual("there", value_a) self.assertEqual(mock_storage.write.call_count, 1) # Gets should not bump await user_state.save_changes(context) self.assertEqual(mock_storage.write.call_count, 1) await property_a.delete(context) # Delete alone no bump self.assertEqual(mock_storage.write.call_count, 1) await user_state.save_changes(context) # Save when dirty should bump self.assertEqual(mock_storage.write.call_count, 2) self.assertEqual(mock_storage.read.call_count, 1) await user_state.save_changes(context ) # Save not dirty should not bump self.assertEqual(mock_storage.write.call_count, 2) self.assertEqual(mock_storage.read.call_count, 1)
def __init__(self, user_state: UserState): super(WaterfallMain, self).__init__(WaterfallMain.__name__) self.user_profile_accessor = user_state.create_property("UserProfile") luisRecognizer = CalcoloImportoRecognizer(configuration=DefaultConfig) calcoloDialog = CalcoloDialog() cancellaDialogo = CancellaDialogo() self.add_dialog( WaterfallQuery(luis_recognizer=luisRecognizer, calcolo_dialog=calcoloDialog, cancella_dialogo=cancellaDialogo)) self.add_dialog(WaterfallPhoto(WaterfallPhoto.__name__)) self.add_dialog(WaterfallText(WaterfallText.__name__)) self.add_dialog( WaterfallDialog( WaterfallDialog.__name__, [ self.what_step, self.summary_step, self.replace_step, ], )) self.add_dialog(ChoicePrompt(ChoicePrompt.__name__)) self.initial_dialog_id = WaterfallDialog.__name__
def __init__(self, user_state: UserState): super(UserProfileDialog, self).__init__(UserProfileDialog.__name__) self.user_profile_accessor = user_state.create_property("UserProfile") self.add_dialog( WaterfallDialog( WaterfallDialog.__name__, [ self.first_step, self.second_step, self.third_step, self.fourth_step, self.fifth_step, self.sixth_step, self.seventh_step, self.eighth_step, ], )) self.add_dialog(TextPrompt(TextPrompt.__name__)) self.add_dialog( NumberPrompt(NumberPrompt.__name__, UserProfileDialog.age_prompt_validator)) self.add_dialog(ChoicePrompt(ChoicePrompt.__name__)) self.add_dialog(ConfirmPrompt(ConfirmPrompt.__name__)) self.add_dialog( AttachmentPrompt(AttachmentPrompt.__name__, UserProfileDialog.picture_prompt_validator)) self.initial_dialog_id = WaterfallDialog.__name__
def main(): parse_command_line() # Create adapter. # See https://aka.ms/about-bot-adapter to learn more about how bots work. settings = BotFrameworkAdapterSettings(options.app_id, options.app_password) # Create MemoryStorage, UserState and ConversationState memory = MemoryStorage() user_state = UserState(memory) conversation_state = ConversationState(memory) # Create adapter. # See https://aka.ms/about-bot-adapter to learn more about how bots work. adapter = AdapterWithErrorHandler(settings, conversation_state) # Create dialogs and Bot recognizer = FlightBookingRecognizer(options) booking_dialog = BookingDialog() dialog = MainDialog(recognizer, booking_dialog) bot = DialogAndWelcomeBot(conversation_state, user_state, dialog) app = tornado.web.Application( [ (r"/api/messages", MessageHandler, dict(adapter=adapter, bot=bot)), ], debug=options.debug, ) app.listen(options.port) tornado.ioloop.IOLoop.current().start()
def __init__( self, config: DefaultConfig, conversation_state: ConversationState, user_state: UserState, dialog: Dialog ): luis_application = LuisApplication( config.LUIS_APP_ID, config.LUIS_API_KEY, "https://" + config.LUIS_API_HOST_NAME ) luis_options = LuisPredictionOptions(include_all_intents=True, include_instance_data=True) self.recognizer = LuisRecognizer(luis_application, luis_options, True) self.subscription_key = config.LUIS_API_KEY self.version_id = config.LUIS_APP_VERSION_ID # 可空白或直接填寫一個現有的luis app,不過需要注意其version_id是否與config.py裡的一樣 self.luis_appid = '' # 激活dialog_data.py裡的資訊 self.user_profile_accessor = user_state.create_property("DialogData") if conversation_state is None: raise TypeError("[DialogBot]: Missing parameter. conversation_state is required but None was given") if user_state is None: raise TypeError("[DialogBot]: Missing parameter. user_state is required but None was given") if dialog is None: raise Exception("[DialogBot]: Missing parameter. dialog is required") self.conversation_state = conversation_state self.user_state = user_state self.dialog = dialog
def __init__(self, user_state: UserState, luis_recognizer: InsuranceQueryRecognizer, insurance_renewal_dialog: InsuranceRenewalDialog, reservation_booking_dialog: ReservationBookingDialog): super(MainDialog, self).__init__(MainDialog.__name__) self.qna_maker = QnAMaker( QnAMakerEndpoint(knowledge_base_id=config.QNA_KNOWLEDGEBASE_ID, endpoint_key=config.QNA_ENDPOINT_KEY, host=config.QNA_ENDPOINT_HOST)) self.user_profile_accessor = user_state.create_property("UserData") self.insurance_renewal_dialog_id = insurance_renewal_dialog.id self.reservation_booking_dialog_id = reservation_booking_dialog.id self._luis_recognizer = luis_recognizer self.user_state = user_state self.add_dialog(TextPrompt(TextPrompt.__name__)) self.add_dialog(ChoicePrompt(INS_PROMPT_OPTIONS)) self.add_dialog(insurance_renewal_dialog) self.add_dialog(reservation_booking_dialog) self.add_dialog( WaterfallDialog("WFDialog", [ self.intro_step, self.name_process_step, self.luis_query_step, self.closing_step ])) self.initial_dialog_id = "WFDialog"
def __init__(self, nlu_recognizer: NLU, user_state: UserState): super(BookingRoomDialog, self).__init__(BookingRoomDialog.__name__) # Load the NLU module self._nlu_recognizer = nlu_recognizer # Load the RoomReservation class self.room_reservation_accessor = user_state.create_property( "RoomReservation") # Setup the waterfall dialog self.add_dialog( WaterfallDialog("WFBookingDialog", [ self.people_step, self.duration_step, self.breakfast_step, self.summary_step, ])) # Append the prompts and custom prompts self.add_dialog( NumberPrompt("PeoplePrompt", BookingRoomDialog.people_prompt_validator)) self.add_dialog( NumberPrompt("DurationPrompt", BookingRoomDialog.duration_prompt_validator)) self.add_dialog(ConfirmPrompt("IsTakingBreakfastPrompt")) self.initial_dialog_id = "WFBookingDialog"
def __init__(self, user_state: UserState, course: Course, luis_recognizer: Recognizer, dialog_id: str = None): super(StudentProfileDialog, self).__init__(dialog_id or StudentProfileDialog.__name__) self.course = course self.luis_recognizer = luis_recognizer # create accessor self.student_profile_accessor: StatePropertyAccessor = user_state.create_property("StudentProfile") # add dialogs self.add_dialog( WaterfallDialog( WaterfallDialog.__name__, [ self.name_step, self.admission_number_step, self.picture_step, self.courses_step, self.summary_step ] ), ) self.add_dialog(TextPrompt(TextPrompt.__name__)) self.add_dialog(ChoicePrompt(ChoicePrompt.__name__)) self.add_dialog(ConfirmPrompt(ConfirmPrompt.__name__)) self.add_dialog(AttachmentPrompt(AttachmentPrompt.__name__, StudentProfileDialog.picture_prompt_validator)) self.add_dialog(CourseQueryDialog(course, luis_recognizer, CourseQueryDialog.__name__)) self.initial_dialog_id = WaterfallDialog.__name__
class BotConfig(AppConfig): """ Bot initialization """ name = 'bots' appConfig = config.DefaultConfig SETTINGS = BotFrameworkAdapterSettings(appConfig.APP_ID, appConfig.APP_PASSWORD) ADAPTER = BotFrameworkAdapter(SETTINGS) LOOP = asyncio.get_event_loop() # Create MemoryStorage, UserState and ConversationState memory = MemoryStorage() user_state = UserState(memory) conversation_state = ConversationState(memory) dialog = MainDialog(appConfig) bot = DialogAndWelcomeBot(conversation_state, user_state, dialog) async def on_error(self, context: TurnContext, error: Exception): """ Catch-all for errors. This check writes out errors to console log NOTE: In production environment, you should consider logging this to Azure application insights. """ print(f'\n [on_turn_error]: { error }', file=sys.stderr) # Send a message to the user await context.send_activity('Oops. Something went wrong!') # Clear out state await self.conversation_state.delete(context) def ready(self): self.ADAPTER.on_turn_error = self.on_error
def __init__(self, user_state: UserState): super(UserProfileDialog, self).__init__(UserProfileDialog.__name__) self.user_profile_accessor = user_state.create_property("UserProfile") self.add_dialog( WaterfallDialog( WaterfallDialog.__name__, [ self.transport_step, self.name_step, self.name_confirm_step, self.age_step, self.picture_step, self.confirm_step, self.summary_step, ], )) self.add_dialog(TextPrompt(TextPrompt.__name__)) self.add_dialog( NumberPrompt(NumberPrompt.__name__, UserProfileDialog.age_prompt_validator)) self.add_dialog(ChoicePrompt(ChoicePrompt.__name__)) self.add_dialog(ConfirmPrompt(ConfirmPrompt.__name__)) self.add_dialog( AttachmentPrompt(AttachmentPrompt.__name__, UserProfileDialog.picture_prompt_validator)) self.initial_dialog_id = WaterfallDialog.__name__
def __init__(self, dialog_id: str, connection_name: str, user_state: UserState, logged_users: Dict[str, str]): super(LogoutDialog, self).__init__(dialog_id) self.connection_name = connection_name self.user_profile_accessor = user_state.create_property("UserProfile") self.logged_users = logged_users
async def test_state_set_after_save(self): """Verify setting property after save""" # Arrange dictionary = {} user_state = UserState(MemoryStorage(dictionary)) context = TestUtilities.create_empty_context() # Act property_a = user_state.create_property("property-a") property_b = user_state.create_property("property-b") await user_state.load(context) await property_a.set(context, "hello") await property_b.set(context, "world") await user_state.save_changes(context) await property_a.set(context, "hello2")
def create_test_flow(self, dialog: Dialog, test_case: FlowTestCase) -> TestFlow: conversation_id = str(uuid.uuid4()) storage = MemoryStorage() convo_state = ConversationState(storage) user_state = UserState(storage) async def logic(context: TurnContext): if test_case != FlowTestCase.root_bot_only: claims_identity = ClaimsIdentity( { AuthenticationConstants.VERSION_CLAIM: "2.0", AuthenticationConstants.AUDIENCE_CLAIM: self.skill_bot_id, AuthenticationConstants.AUTHORIZED_PARTY: self.parent_bot_id, }, True, ) context.turn_state[ BotAdapter.BOT_IDENTITY_KEY] = claims_identity if test_case == FlowTestCase.root_bot_consuming_skill: context.turn_state[ SkillHandler. SKILL_CONVERSATION_REFERENCE_KEY] = SkillConversationReference( None, AuthenticationConstants. TO_CHANNEL_FROM_BOT_OAUTH_SCOPE) if test_case == FlowTestCase.middle_skill: context.turn_state[ SkillHandler. SKILL_CONVERSATION_REFERENCE_KEY] = SkillConversationReference( None, self.parent_bot_id) async def capture_eoc(inner_context: TurnContext, activities: List[Activity], next): # pylint: disable=unused-argument for activity in activities: if activity.type == ActivityTypes.end_of_conversation: self.eoc_sent = activity break return await next() context.on_send_activities(capture_eoc) await DialogExtensions.run_dialog( dialog, context, convo_state.create_property("DialogState")) adapter = TestAdapter( logic, TestAdapter.create_conversation_reference(conversation_id)) AdapterExtensions.use_storage(adapter, storage) AdapterExtensions.use_bot_state(adapter, user_state, convo_state) adapter.use(TranscriptLoggerMiddleware(ConsoleTranscriptLogger())) return TestFlow(None, adapter)
async def test_load_set_save(self): # Arrange dictionary = {} user_state = UserState(MemoryStorage(dictionary)) context = TestUtilities.create_empty_context() # Act property_a = user_state.create_property("property-a") property_b = user_state.create_property("property-b") await user_state.load(context) await property_a.set(context, "hello") await property_b.set(context, "world") await user_state.save_changes(context) # Assert obj = dictionary["EmptyContext/users/[email protected]"] self.assertEqual("hello", obj["property-a"]) self.assertEqual("world", obj["property-b"])
async def test_state_multiple_save(self): """Verify multiple saves""" # Arrange dictionary = {} user_state = UserState(MemoryStorage(dictionary)) context = TestUtilities.create_empty_context() # Act property_a = user_state.create_property("property-a") property_b = user_state.create_property("property-b") await user_state.load(context) await property_a.set(context, "hello") await property_b.set(context, "world") await user_state.save_changes(context) await property_a.set(context, "hello2") await user_state.save_changes(context) value_a = await property_a.get(context) self.assertEqual("hello2", value_a)
class TestUserState(aiounittest.AsyncTestCase): storage = MemoryStorage() adapter = TestAdapter() context = TurnContext(adapter, RECEIVED_MESSAGE) user_state = UserState(storage) async def test_should_load_and_save_state_from_storage(self): await self.user_state.load(self.context) key = self.user_state.get_storage_key(self.context) state = self.user_state.get(self.context) assert state is not None, 'State not loaded' assert key, 'Key not found' state['test'] = 'foo' await self.user_state.save_changes(self.context) items = await self.storage.read([key]) assert key in items, 'Saved state not found in storage' assert items[key][ 'test'] == 'foo', 'Missing saved value in stored storage' async def test_should_reject_with_error_if_channel_id_is_missing(self): context = TurnContext(self.adapter, MISSING_CHANNEL_ID) async def next_middleware(): assert False, 'Should not have called next_middleware' try: await self.user_state.on_process_request(context, next_middleware) except AttributeError: pass else: raise AssertionError( 'Should not have completed and not raised AttributeError.') async def test_should_reject_with_error_if_from_property_is_missing(self): context = TurnContext(self.adapter, MISSING_FROM_PROPERTY) async def next_middleware(): assert False, 'Should not have called next_middleware' try: await self.user_state.on_process_request(context, next_middleware) except AttributeError: pass else: raise AssertionError( 'Should not have completed and not raised AttributeError.')
class TestUserState: storage = MemoryStorage() adapter = TestAdapter() context = TurnContext(adapter, RECEIVED_MESSAGE) middleware = UserState(storage) @pytest.mark.asyncio async def test_should_load_and_save_state_from_storage(self): async def next_middleware(): state = await self.middleware.get(self.context) assert isinstance(state, StoreItem), 'State not loaded' state.test = 'foo' await self.middleware.on_process_request(self.context, next_middleware) key = self.middleware.get_storage_key(self.context) assert type(key) == str, 'Key not found' items = await self.storage.read([key]) assert key in items, 'Saved state not found in storage' assert items[key].test == 'foo', 'Missing test value in stored state.' @pytest.mark.asyncio async def test_should_reject_with_error_if_channel_id_is_missing(self): context = TurnContext(self.adapter, MISSING_CHANNEL_ID) async def next_middleware(): assert False, 'Should not have called next_middleware' try: await self.middleware.on_process_request(context, next_middleware) except AttributeError: pass else: raise AssertionError( 'Should not have completed and not raised AttributeError.') @pytest.mark.asyncio async def test_should_reject_with_error_if_from_property_is_missing(self): context = TurnContext(self.adapter, MISSING_FROM_PROPERTY) async def next_middleware(): assert False, 'Should not have called next_middleware' try: await self.middleware.on_process_request(context, next_middleware) except AttributeError: pass else: raise AssertionError( 'Should not have completed and not raised AttributeError.')
def __init__(self, user_state: UserState): super(AddUtteranceDialog, self).__init__(AddUtteranceDialog.__name__) self.user_profile_accessor = user_state.create_property("DialogData") ### add_dialog --> 增加來回對話的round self.add_dialog( WaterfallDialog(WaterfallDialog.__name__, [ self.enter_a_training_utterance, self.enter_the_specified_intent, self.enter_the_specified_entity, self.enter_the_tagged_entity, self.inquire_keep_going_or_not, self.final_step ])) #依照本次dialog對話需要的方法,增加方法(yes/no問題、選項問題、純文字題等等) self.add_dialog(TextPrompt(TextPrompt.__name__)) self.add_dialog(ConfirmPrompt(ConfirmPrompt.__name__))
def __init__(self, user_state: UserState): super(Dialog, self).__init__(Dialog.__name__) self.user_profile_accesor = user_state.create_property("UserProfile") self.add_dialog( WaterfallDialog( WaterfallDialog.__name__, [ self.options_step, ], ) ) self.add_dialog(ChoicePrompt("options_step")) self.add_dialog(ChoicePrompt(ChoicePrompt.__name__)) self.add_dialog(ConfirmPrompt(ConfirmPrompt.__name__)) self.initial_dialog_id = WaterfallDialog.__name__ self.add_dialog(TextPrompt(TextPrompt.__name__))
def __init__(self, user_state: UserState): super(OrderDialog, self).__init__(OrderDialog.__name__) self.current_order: Order = None self.order_list: List[Order] = list() self.user_profile_accesor = user_state.create_property("UserProfile") self.add_dialog( WaterfallDialog( WaterfallDialog.__name__, [ self.options_step, self.interpret_user_intention, self.goodbye_step, ], )) self.add_dialog(ChoicePrompt("options_step")) self.add_dialog(TextPrompt("interpret_user_intention")) self.add_dialog(ChoicePrompt(ChoicePrompt.__name__)) self.add_dialog(ConfirmPrompt(ConfirmPrompt.__name__)) self.initial_dialog_id = WaterfallDialog.__name__ self.add_dialog(TextPrompt(TextPrompt.__name__))
def __init__( self, user_state: UserState, connection_name: str, site_url: str, ): if user_state is None: raise Exception( "[TeamsMessagingExtensionsSearchAuthConfigBot]: Missing parameter. user_state is required" ) if connection_name is None: raise Exception( "[TeamsMessagingExtensionsSearchAuthConfigBot]: Missing parameter. connection_name is required" ) if site_url is None: raise Exception( "[TeamsMessagingExtensionsSearchAuthConfigBot]: Missing parameter. site_url is required" ) self.user_state = user_state self.connection_name = connection_name self.site_url = site_url self.user_config_property = user_state.create_property( "UserConfiguration")
async def test_LoadSetSaveTwice(self): # Arrange dictionary = {} context = TestUtilities.create_empty_context() # Act user_state = UserState(MemoryStorage(dictionary)) property_a = user_state.create_property("property-a") property_b = user_state.create_property("property-b") propertyC = user_state.create_property("property-c") await user_state.load(context) await property_a.set(context, "hello") await property_b.set(context, "world") await propertyC.set(context, "test") await user_state.save_changes(context) # Assert obj = dictionary["EmptyContext/users/[email protected]"] self.assertEqual("hello", obj["property-a"]) self.assertEqual("world", obj["property-b"]) # Act 2 user_state2 = UserState(MemoryStorage(dictionary)) property_a2 = user_state2.create_property("property-a") property_b2 = user_state2.create_property("property-b") await user_state2.load(context) await property_a2.set(context, "hello-2") await property_b2.set(context, "world-2") await user_state2.save_changes(context) # Assert 2 obj2 = dictionary["EmptyContext/users/[email protected]"] self.assertEqual("hello-2", obj2["property-a"]) self.assertEqual("world-2", obj2["property-b"]) self.assertEqual("test", obj2["property-c"])
async def test_load_save_delete(self): # Arrange dictionary = {} context = TestUtilities.create_empty_context() # Act user_state = UserState(MemoryStorage(dictionary)) property_a = user_state.create_property("property-a") property_b = user_state.create_property("property-b") await user_state.load(context) await property_a.set(context, "hello") await property_b.set(context, "world") await user_state.save_changes(context) # Assert obj = dictionary["EmptyContext/users/[email protected]"] self.assertEqual("hello", obj["property-a"]) self.assertEqual("world", obj["property-b"]) # Act 2 user_state2 = UserState(MemoryStorage(dictionary)) property_a2 = user_state2.create_property("property-a") property_b2 = user_state2.create_property("property-b") await user_state2.load(context) await property_a2.set(context, "hello-2") await property_b2.delete(context) await user_state2.save_changes(context) # Assert 2 obj2 = dictionary["EmptyContext/users/[email protected]"] self.assertEqual("hello-2", obj2["property-a"]) with self.assertRaises(KeyError) as _: obj2["property-b"] # pylint: disable=pointless-statement