Skip to content

Commit

Permalink
Stop flow action (#1306)
Browse files Browse the repository at this point in the history
* Updated stop flow action for multiflow stories

* Added and Updated Test Cases
  • Loading branch information
himanshugt16 authored Jul 2, 2024
1 parent 27f819d commit cbf8303
Show file tree
Hide file tree
Showing 23 changed files with 1,576 additions and 178 deletions.
22 changes: 21 additions & 1 deletion kairon/shared/data/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -1136,7 +1136,20 @@ def fetch_actions(self, bot: Text, status=True):
:return: list of actions
"""
actions = Actions.objects(bot=bot, status=status).values_list("name")
return list(actions)
actions_list = list(actions)

for story in Stories.objects(bot=bot, status=status):
for event in story.events:
if event.name == 'action_listen':
if 'action_listen' not in actions_list:
actions_list.append('action_listen')

for story in MultiflowStories.objects(bot=bot, status=status):
for event in story.events:
if event.step.name == 'stop_flow_action' and 'stop_flow_action' not in actions_list:
actions_list.append('stop_flow_action')

return actions_list

def __prepare_training_actions(self, bot: Text):
actions = self.fetch_actions(bot)
Expand Down Expand Up @@ -1698,6 +1711,10 @@ def __prepare_training_multiflow_story_events(self, events, metadata, timestamp)
story_events.append(
SlotSet(key=event.name, value=event.value, timestamp=timestamp)
)
elif event.step_type == StoryStepType.stop_flow_action.value:
story_events.append(
ActionExecuted(action_name=ACTION_LISTEN_NAME, timestamp=timestamp)
)
else:
story_events.append(
ActionExecuted(action_name=event.name, timestamp=timestamp)
Expand Down Expand Up @@ -3348,6 +3365,9 @@ def get_stories(self, bot: Text):
step["type"] = StoryStepType.web_search_action.value
elif event['name'] == 'live_agent_action':
step["type"] = StoryStepType.live_agent_action.value
elif event['name'] == 'action_listen':
step["type"] = StoryStepType.stop_flow_action.value
step["name"] = 'stop_flow_action'
elif str(event["name"]).startswith("utter_"):
step["type"] = StoryStepType.bot.value
else:
Expand Down
49 changes: 49 additions & 0 deletions kairon/shared/kairon_yaml_story_writer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from typing import List, Text, Any, Union
from collections import OrderedDict

from rasa.shared.core.training_data.story_writer.yaml_story_writer import YAMLStoryWriter
from rasa.shared.core.training_data.structures import StoryStep
from rasa.shared.core.events import Event


from rasa.shared.core.training_data.story_reader.yaml_story_reader import KEY_STORY_NAME, KEY_STEPS


class kaironYAMLStoryWriter(YAMLStoryWriter):
"""Custom YAML Story Writer with overridden _filter_event function."""

def process_story_step(self, story_step: StoryStep) -> OrderedDict:
"""Converts a single story step into an ordered dict with a custom filter."""
result: OrderedDict[Text, Any] = OrderedDict()
result[KEY_STORY_NAME] = story_step.block_name
steps = self.process_checkpoints(story_step.start_checkpoints)
for event in story_step.events:
if not self._filter_event(event):
continue
processed = self.process_event(event)
if processed:
steps.append(processed)

steps.extend(self.process_checkpoints(story_step.end_checkpoints))

result[KEY_STEPS] = steps

return result

@staticmethod
def _filter_event(event: Union["Event", List["Event"]]) -> bool:
"""Identifies if the event should be converted/written.
Args:
event: target event to check.
Returns:
`True` if the event should be converted/written, `False` otherwise.
"""
if isinstance(event, list):
return True

return (
not StoryStep.is_action_unlikely_intent(event)
and not StoryStep.is_action_session_start(event)
)
12 changes: 11 additions & 1 deletion kairon/shared/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
KAIRON_TWO_STAGE_FALLBACK,
SLOT_TYPE,
)
from kairon.shared.kairon_yaml_story_writer import kaironYAMLStoryWriter
from .data.dto import KaironStoryStep
from .models import StoryStepType, LlmPromptType, LlmPromptSource
from ..exceptions import AppException
Expand Down Expand Up @@ -1166,7 +1167,8 @@ def write_training_data(
yaml.safe_dump(domain, open(domain_path, "w"))
Utility.write_to_file(nlu_path, nlu_as_str)
Utility.write_to_file(config_path, config_as_str)
YAMLStoryWriter().dump(stories_path, stories.story_steps)
story_writer = kaironYAMLStoryWriter()
story_writer.dump(stories_path, stories.story_steps)
if rules:
YAMLStoryWriter().dump(rules_path, rules.story_steps)
if actions:
Expand Down Expand Up @@ -2271,6 +2273,12 @@ def validate_steps(steps: List, flow_metadata: List):
raise AppException(
"Intent can only have one connection of action type or slot type"
)
if [
successor
for successor in story_graph.successors(story_node)
if successor.step_type == "STOP_FLOW_ACTION"
]:
raise AppException("STOP_FLOW_ACTION cannot be a successor of an intent!")
if story_node.step_type == "SLOT" and story_node.value:
if story_node.value is not None and not isinstance(
story_node.value, (str, int, bool)
Expand All @@ -2286,6 +2294,8 @@ def validate_steps(steps: List, flow_metadata: List):
raise AppException("Slots cannot be leaf nodes!")
if story_node.step_type == "INTENT" and story_node.node_id in leaf_node_ids:
raise AppException("Leaf nodes cannot be intent")
if story_node.step_type == "STOP_FLOW_ACTION" and story_node.node_id not in leaf_node_ids:
raise AppException("STOP_FLOW_ACTION should be a leaf node!")
if flow_metadata:
for value in flow_metadata:
if value.get("flow_type") == "RULE":
Expand Down
Loading

0 comments on commit cbf8303

Please sign in to comment.