def test_reading_of_trackers_with_legacy_form_events(): loop_name1 = "my loop" loop_name2 = "my form" tracker = DialogueStateTracker.from_dict( "sender", events_as_dict=[ { "event": ActiveLoop.type_name, "name": loop_name1 }, { "event": LegacyForm.type_name, "name": None }, { "event": LegacyForm.type_name, "name": loop_name2 }, ], ) expected_events = [ ActiveLoop(loop_name1), LegacyForm(None), LegacyForm(loop_name2) ] assert list(tracker.events) == expected_events assert tracker.active_loop["name"] == loop_name2
async def continue_training(request: Request): epochs = request.raw_args.get("epochs", 30) batch_size = request.raw_args.get("batch_size", 5) request_params = request.json sender_id = UserMessage.DEFAULT_SENDER_ID try: tracker = DialogueStateTracker.from_dict(sender_id, request_params, app.agent.domain.slots) except Exception as e: raise ErrorResponse(400, "InvalidParameter", "Supplied events are not valid. {}".format(e), { "parameter": "", "in": "body" }) try: # Fetches the appropriate bot response in a json format app.agent.continue_training([tracker], epochs=epochs, batch_size=batch_size) return response.text('', 204) except Exception as e: logger.exception("Caught an exception during prediction.") raise ErrorResponse(500, "TrainingException", "Server failure. Error: {}".format(e))
def retrieve(self, sender_id): """ Args: sender_id: the message owner ID Returns: `DialogueStateTracker` """ stored = self.conversations.find_one({"sender_id": sender_id}) # look for conversations which have used an `int` sender_id in the past # and update them. if stored is None and sender_id.isdigit(): from pymongo import ReturnDocument stored = self.conversations.find_one_and_update( {"sender_id": int(sender_id)}, {"$set": { "sender_id": str(sender_id) }}, return_document=ReturnDocument.AFTER, ) if stored is not None: return DialogueStateTracker.from_dict(sender_id, stored.get("events"), self.domain.slots) else: return None
async def replace_events(request: Request, conversation_id: Text): """Use a list of events to set a conversations tracker to a state.""" validate_request_body( request, "You must provide events in the request body to set the sate of the " "conversation tracker.", ) verbosity = event_verbosity_parameter(request, EventVerbosity.AFTER_RESTART) try: tracker = DialogueStateTracker.from_dict(conversation_id, request.json, app.agent.domain.slots) # will override an existing tracker with the same id! app.agent.tracker_store.save(tracker) return response.json(tracker.current_state(verbosity)) except Exception as e: logger.debug(traceback.format_exc()) raise ErrorResponse( 500, "ConversationError", "An unexpected error occurred. Error: {}".format(e), )
def retrieve(self, sender_id: Text) -> Optional[DialogueStateTracker]: """Create a tracker from all previously stored events.""" with self.session_scope() as session: query = session.query(self.SQLEvent) result = ( query.filter_by(sender_id=sender_id) .order_by(self.SQLEvent.timestamp) .all() ) events = [json.loads(event.data) for event in result] if self.domain and len(events) > 0: logger.debug(f"Recreating tracker from sender id '{sender_id}'") return DialogueStateTracker.from_dict( sender_id, events, self.domain.slots ) else: logger.debug( f"Can't retrieve tracker matching " f"sender id '{sender_id}' from SQL storage. " f"Returning `None` instead." ) return None
def retrieve(self, sender_id): stored = self.conversations.find_one({"sender_id": sender_id}) # look for conversations which have used an `int` sender_id in the past # and update them. if stored is None and sender_id.isdigit(): from pymongo import ReturnDocument stored = self.conversations.find_one_and_update( {"sender_id": int(sender_id)}, {"$set": { "sender_id": str(sender_id) }}, return_document=ReturnDocument.AFTER, ) if stored is not None: if self.domain: return DialogueStateTracker.from_dict(sender_id, stored.get("events"), self.domain.slots) else: logger.warning("Can't recreate tracker from mongo storage " "because no domain is set. Returning `None` " "instead.") return None else: return None
async def nlu_parse(url, message): tracker = DialogueStateTracker.from_dict("1", [], [Slot("requested_language")]) # we'll expect this value 'en' to be part of the result from the interpreter tracker._set_slot("requested_language", "en") inte = RasaNLUHttpInterpreter(EndpointConfig(url)) result = await inte.parse(message, tracker=tracker) return result
def retrieve(self, sender_id: Text) -> Optional[DialogueStateTracker]: tracker = asyncio.get_event_loop().run_until_complete( self.asm.memory.get("rasa_tracker", sender_id)) if tracker: _LOGGER.debug("Recreating tracker for id '{}'".format(sender_id)) if isinstance(tracker, dict): return DialogueStateTracker.from_dict(sender_id, tracker['events'], self.domain.slots) else: return DialogueStateTracker.from_dict( sender_id, tracker.getStore()['events'], self.domain.slots) else: _LOGGER.debug( "Creating a new tracker for id '{}'.".format(sender_id)) return None
def test_tracker_without_slots(key, value, caplog): event = SlotSet(key, value) tracker = DialogueStateTracker.from_dict("any", []) assert key in tracker.slots with caplog.at_level(logging.INFO): event.apply_to(tracker) v = tracker.get_slot(key) assert v == value assert len(caplog.records) == 0
def load_tracker_from_json(tracker_dump: Text, domain: Domain) -> DialogueStateTracker: """Read the json dump from the file and instantiate a tracker it.""" tracker_json = json.loads(rasa.utils.io.read_file(tracker_dump)) sender_id = tracker_json.get("sender_id", UserMessage.DEFAULT_SENDER_ID) return DialogueStateTracker.from_dict(sender_id, tracker_json.get("events", []), domain.slots)
def _convert_tracker(self, sender_id, tracker): if self.domain: return DialogueStateTracker.from_dict(sender_id, tracker["events"], self.domain.slots) else: logger.warning("Can't recreate tracker from mongo storage " "because no domain is set. Returning `None` " "instead.") return None
def test_current_state_no_events(default_agent): tracker_dump = "data/test_trackers/tracker_moodbot.json" tracker_json = json.loads(rasa.utils.io.read_file(tracker_dump)) tracker = DialogueStateTracker.from_dict(tracker_json.get("sender_id"), tracker_json.get("events", []), default_agent.domain.slots) state = tracker.current_state(EventVerbosity.NONE) assert state.get("events") is None
async def tracker_predict(request: Request): """ Given a list of events, predicts the next action""" validate_request_body( request, "No events defined in request_body. Add events to request body in order to " "predict the next action.", ) sender_id = UserMessage.DEFAULT_SENDER_ID request_id = UserMessage.DEFAULT_REQUEST_ID user_id = UserMessage.DEFAULT_USER_ID verbosity = event_verbosity_parameter(request, EventVerbosity.AFTER_RESTART) request_params = request.json try: tracker = DialogueStateTracker.from_dict(sender_id, request_id, user_id, request_params, app.agent.domain.slots) except Exception as e: logger.debug(traceback.format_exc()) raise ErrorResponse( 400, "BadRequest", "Supplied events are not valid. {}".format(e), { "parameter": "", "in": "body" }, ) try: policy_ensemble = app.agent.policy_ensemble probabilities, policy = policy_ensemble.probabilities_using_best_policy( tracker, app.agent.domain) scores = [{ "action": a, "score": p } for a, p in zip(app.agent.domain.action_names, probabilities)] return response.json({ "scores": scores, "policy": policy, "tracker": tracker.current_state(verbosity), }) except Exception as e: logger.debug(traceback.format_exc()) raise ErrorResponse( 500, "PredictionError", "An unexpected error occurred. Error: {}".format(e), )
async def replace_events(request: Request, sender_id: Text): """Use a list of events to set a conversations tracker to a state.""" request_params = request.json verbosity = event_verbosity_parameter(request, EventVerbosity.AFTER_RESTART) tracker = DialogueStateTracker.from_dict(sender_id, request_params, app.agent.domain.slots) # will override an existing tracker with the same id! app.agent.tracker_store.save(tracker) return response.json(tracker.current_state(verbosity))
async def generate_response(nlg_call, domain): """Mock response generator. Generates the responses from the bot's domain file. """ kwargs = nlg_call.get("arguments", {}) template = nlg_call.get("template") sender_id = nlg_call.get("tracker", {}).get("sender_id") events = nlg_call.get("tracker", {}).get("events") tracker = DialogueStateTracker.from_dict(sender_id, events, domain.slots) channel_name = nlg_call.get("channel") return await TemplatedNaturalLanguageGenerator(domain.templates).generate( template, tracker, channel_name, **kwargs)
def test_current_state_after_restart(default_agent): tracker_dump = "data/test_trackers/tracker_moodbot.json" tracker_json = json.loads(utils.read_file(tracker_dump)) tracker_json["events"].insert(3, {"event": "restart"}) tracker = DialogueStateTracker.from_dict(tracker_json.get("sender_id"), tracker_json.get("events", []), default_agent.domain.slots) events_after_restart = [e.as_dict() for e in list(tracker.events)[4:]] state = tracker.current_state(EventVerbosity.AFTER_RESTART) assert state.get("events") == events_after_restart
def new_form_and_tracker(form_spec, requested_slot, additional_slots=[]): form = ActionBotfrontForm(form_spec.get("form_name")) tracker = DialogueStateTracker.from_dict( "default", [], [ Slot(name=requested_slot), *[Slot(name=name) for name in additional_slots], Slot(name="requested_slot", initial_value=requested_slot), Slot(name="bf_forms", initial_value=[form_spec]), ], ) form.form_spec = form_spec # load spec manually return form, tracker
def test_current_state_all_events(default_agent): tracker_dump = "data/test_trackers/tracker_moodbot.json" tracker_json = json.loads(rasa.utils.io.read_file(tracker_dump)) tracker_json["events"].insert(3, {"event": "restart"}) tracker = DialogueStateTracker.from_dict(tracker_json.get("sender_id"), tracker_json.get("events", []), default_agent.domain.slots) evts = [e.as_dict() for e in tracker.events] state = tracker.current_state(EventVerbosity.ALL) assert state.get("events") == evts
def retrieve(self, sender_id: Text) -> Optional[DialogueStateTracker]: """Create a tracker from all previously stored events.""" # Retrieve dialogues for a sender_id in reverse chronological order based on the session_date sort key dialogues = self.db.query( KeyConditionExpression=Key("sender_id").eq(sender_id), Limit=1, ScanIndexForward=False, )["Items"] if dialogues: return DialogueStateTracker.from_dict(sender_id, dialogues[0].get("events"), self.domain.slots) else: return None
def retrieve(self, sender_id: Text) -> DialogueStateTracker: """Create a tracker from all previously stored events.""" query = self.session.query(self.SQLEvent) result = query.filter_by(sender_id=sender_id).all() events = [json.loads(event.data) for event in result] if self.domain and len(events) > 0: logger.debug( "Recreating tracker from sender id '{}'".format(sender_id)) return DialogueStateTracker.from_dict(sender_id, events, self.domain.slots) else: logger.debug("Can't retrieve tracker matching" "sender id '{}' from SQL storage. " "Returning `None` instead.".format(sender_id))
async def test_parsing_with_tracker(): tracker = DialogueStateTracker.from_dict("1", [], [Slot("requested_language")]) # we'll expect this value 'en' to be part of the result from the interpreter tracker._set_slot("requested_language", "en") endpoint = EndpointConfig("https://interpreter.com") with aioresponses() as mocked: mocked.post("https://interpreter.com/parse", repeat=True, status=200) # mock the parse function with the one defined for this test with patch.object(RasaNLUHttpInterpreter, "parse", mocked_parse): interpreter = RasaNLUHttpInterpreter(endpoint_config=endpoint) agent = Agent(None, None, interpreter) result = await agent.parse_message_using_nlu_interpreter("lunch?", tracker) assert result["requested_language"] == "en"
def test_current_state_applied_events(default_agent): tracker_dump = "data/test_trackers/tracker_moodbot.json" tracker_json = json.loads(rasa.utils.io.read_file(tracker_dump)) # add some events that result in other events not being applied anymore tracker_json["events"].insert(1, {"event": "restart"}) tracker_json["events"].insert(7, {"event": "rewind"}) tracker_json["events"].insert(8, {"event": "undo"}) tracker = DialogueStateTracker.from_dict(tracker_json.get("sender_id"), tracker_json.get("events", []), default_agent.domain.slots) evts = [e.as_dict() for e in tracker.events] applied_events = [evts[2], evts[9]] state = tracker.current_state(EventVerbosity.APPLIED) assert state.get("events") == applied_events
def test_session_started_not_part_of_applied_events(default_agent: Agent): # take tracker dump and insert a SessionStarted event sequence tracker_dump = "data/test_trackers/tracker_moodbot.json" tracker_json = json.loads(rasa.shared.utils.io.read_file(tracker_dump)) tracker_json["events"].insert( 4, {"event": ActionExecuted.type_name, "name": ACTION_SESSION_START_NAME} ) tracker_json["events"].insert(5, {"event": SessionStarted.type_name}) # initialise a tracker from this list of events tracker = DialogueStateTracker.from_dict( tracker_json.get("sender_id"), tracker_json.get("events", []), default_agent.domain.slots, ) # the SessionStart event was at index 5, the tracker's `applied_events()` should # be the same as the list of events from index 6 onwards assert tracker.applied_events() == list(tracker.events)[6:]
def retrieve(self, sender_id: Text) -> Optional[DialogueStateTracker]: """Create a tracker from all previously stored events.""" # Retrieve dialogues for a sender_id in reverse-chronological order based on # the session_date sort key dialogues = self.db.query( KeyConditionExpression=Key("sender_id").eq(sender_id), Limit=1, ScanIndexForward=False, )["Items"] if not dialogues: return None events = dialogues[0].get("events", []) # `float`s are stored as `Decimal` objects - we need to convert them back events_with_floats = core_utils.replace_decimals_with_floats(events) return DialogueStateTracker.from_dict(sender_id, events_with_floats, self.domain.slots)
def retrieve(self, sender_id: Text) -> Optional[DialogueStateTracker]: """Create a tracker from all previously stored events.""" # 基于数据库中记录的events,重放出一个tracker query = self.session.query(self.SQLEvent) result = query.filter_by(sender_id=sender_id).all() events = [json.loads(event.data) for event in result] if self.domain and len(events) > 0: # store定义了domain,并且存在至少一条event logger.debug( "Recreating tracker from sender id '{}'".format(sender_id)) return DialogueStateTracker.from_dict( sender_id, events, self.domain.slots) # 基于事件创建tracker else: # 要么store没定义domain, 要么对应sender id 没有事件 logger.debug("Can't retrieve tracker matching" "sender id '{}' from SQL storage. " "Returning `None` instead.".format(sender_id)) return None
def retrieve(self, sender_id: Text) -> Optional[DialogueStateTracker]: """Create a tracker from all previously stored events.""" import sqlalchemy as sa from rasa.core.events import SessionStarted with self.session_scope() as session: # Subquery to find the timestamp of the latest `SessionStarted` event session_start_sub_query = (session.query( sa.func.max( self.SQLEvent.timestamp).label("session_start")).filter( self.SQLEvent.sender_id == sender_id, self.SQLEvent.type_name == SessionStarted.type_name, ).subquery()) results = ( session.query(self.SQLEvent).filter( self.SQLEvent.sender_id == sender_id, # Find events after the latest `SessionStarted` event or return all # events sa.or_( self.SQLEvent.timestamp >= session_start_sub_query.c.session_start, session_start_sub_query.c.session_start.is_(None), ), ).order_by(self.SQLEvent.timestamp).all()) events = [json.loads(event.data) for event in results] if self.domain and len(events) > 0: logger.debug( f"Recreating tracker from sender id '{sender_id}'") return DialogueStateTracker.from_dict(sender_id, events, self.domain.slots) else: logger.debug(f"Can't retrieve tracker matching " f"sender id '{sender_id}' from SQL storage. " f"Returning `None` instead.") return None
async def retrieve_response_for_request(request: Request): message = request.args.get('say') sender_id = request.args.get('sender_id') print("printing sender id ", sender_id) print("printing message ", message) output_response = await app.agent.handle_text(message) print("printing output response for smalltalk", output_response) if output_response == []: final_output = { "id": sender_id, "messages": "Sorry, can you rephrase your question and ask again?" } return response.json(final_output) else: final_output = { "id": sender_id, "messages": output_response[0]['text'] } print("printing final output ", final_output) return response.json(final_output) #return response.text("Hi I am doing good. How about you? ") try: async with app.agent.lock_store.lock(conversation_id): tracker = DialogueStateTracker.from_dict( conversation_id, request.json, app.agent.domain.slots) # will override an existing tracker with the same id! app.agent.tracker_store.save(tracker) return response.json(tracker.current_state(verbosity)) except Exception as e: logger.debug(traceback.format_exc()) raise ErrorResponse( 500, "ConversationError", "An unexpected error occurred. Error: {}".format(e), )
async def tracker_predict(request: Request): """ Given a list of events, predicts the next action""" sender_id = UserMessage.DEFAULT_SENDER_ID request_params = request.json verbosity = event_verbosity_parameter(request, EventVerbosity.AFTER_RESTART) try: tracker = DialogueStateTracker.from_dict(sender_id, request_params, app.agent.domain.slots) except Exception as e: raise ErrorResponse( 400, "InvalidParameter", "Supplied events are not valid. {}".format(e), { "parameter": "", "in": "body" }, ) policy_ensemble = app.agent.policy_ensemble probabilities, policy = policy_ensemble.probabilities_using_best_policy( tracker, app.agent.domain) scores = [{ "action": a, "score": p } for a, p in zip(app.agent.domain.action_names, probabilities)] return response.json({ "scores": scores, "policy": policy, "tracker": tracker.current_state(verbosity), })
def retrieve(self, sender_id: Text) -> Optional[DialogueStateTracker]: """Create a tracker from all previously stored events.""" import sqlalchemy as sa from rasa.core.events import SessionStarted with self.session_scope() as session: serialised_events = self._event_query(session, sender_id).all() events = [json.loads(event.data) for event in serialised_events] if self.domain and len(events) > 0: logger.debug(f"Recreating tracker from sender id '{sender_id}'") return DialogueStateTracker.from_dict( sender_id, events, self.domain.slots ) else: logger.debug( f"Can't retrieve tracker matching " f"sender id '{sender_id}' from SQL storage. " f"Returning `None` instead." ) return None
def _chat_history_table(events: List[Dict[Text, Any]]) -> Text: """Create a table containing bot and user messages. Also includes additional information, like any events and prediction probabilities.""" def wrap(txt: Text, max_width: int) -> Text: return "\n".join(textwrap.wrap(txt, max_width, replace_whitespace=False)) def colored(txt: Text, color: Text) -> Text: return "{" + color + "}" + txt + "{/" + color + "}" def format_user_msg(user_event: UserUttered, max_width: int) -> Text: intent = user_event.intent or {} intent_name = intent.get("name", "") _confidence = intent.get("confidence", 1.0) _md = _as_md_message(user_event.parse_data) _lines = [ colored(wrap(_md, max_width), "hired"), "intent: {} {:03.2f}".format(intent_name, _confidence), ] return "\n".join(_lines) def bot_width(_table: AsciiTable) -> int: return _table.column_max_width(1) def user_width(_table: AsciiTable) -> int: return _table.column_max_width(3) def add_bot_cell(data, cell): data.append([len(data), Color(cell), "", ""]) def add_user_cell(data, cell): data.append([len(data), "", "", Color(cell)]) # prints the historical interactions between the bot and the user, # to help with correctly identifying the action table_data = [ [ "# ", Color(colored("Bot ", "autoblue")), " ", Color(colored("You ", "hired")), ] ] table = SingleTable(table_data, "Chat History") bot_column = [] tracker = DialogueStateTracker.from_dict("any", events) applied_events = tracker.applied_events() for idx, event in enumerate(applied_events): if isinstance(event, ActionExecuted): bot_column.append(colored(event.action_name, "autocyan")) if event.confidence is not None: bot_column[-1] += colored( " {:03.2f}".format(event.confidence), "autowhite" ) elif isinstance(event, UserUttered): if bot_column: text = "\n".join(bot_column) add_bot_cell(table_data, text) bot_column = [] msg = format_user_msg(event, user_width(table)) add_user_cell(table_data, msg) elif isinstance(event, BotUttered): wrapped = wrap(format_bot_output(event), bot_width(table)) bot_column.append(colored(wrapped, "autoblue")) else: if event.as_story_string(): bot_column.append(wrap(event.as_story_string(), bot_width(table))) if bot_column: text = "\n".join(bot_column) add_bot_cell(table_data, text) table.inner_heading_row_border = False table.inner_row_border = True table.inner_column_border = False table.outer_border = False table.justify_columns = {0: "left", 1: "left", 2: "center", 3: "right"} return table.table