rasa-pro 3.8.18__py3-none-any.whl → 3.9.15__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rasa-pro might be problematic. Click here for more details.
- README.md +6 -42
- rasa/__main__.py +14 -9
- rasa/anonymization/anonymization_pipeline.py +0 -1
- rasa/anonymization/anonymization_rule_executor.py +3 -3
- rasa/anonymization/utils.py +4 -3
- rasa/api.py +2 -2
- rasa/cli/arguments/default_arguments.py +1 -1
- rasa/cli/arguments/run.py +2 -2
- rasa/cli/arguments/test.py +1 -1
- rasa/cli/arguments/train.py +10 -10
- rasa/cli/e2e_test.py +27 -7
- rasa/cli/export.py +0 -1
- rasa/cli/license.py +3 -3
- rasa/cli/project_templates/calm/actions/action_template.py +1 -1
- rasa/cli/project_templates/calm/config.yml +1 -1
- rasa/cli/project_templates/calm/credentials.yml +1 -1
- rasa/cli/project_templates/calm/data/flows/add_contact.yml +1 -1
- rasa/cli/project_templates/calm/data/flows/remove_contact.yml +1 -1
- rasa/cli/project_templates/calm/domain/add_contact.yml +8 -2
- rasa/cli/project_templates/calm/domain/list_contacts.yml +3 -0
- rasa/cli/project_templates/calm/domain/remove_contact.yml +9 -2
- rasa/cli/project_templates/calm/domain/shared.yml +5 -0
- rasa/cli/project_templates/calm/endpoints.yml +4 -4
- rasa/cli/project_templates/default/actions/actions.py +1 -1
- rasa/cli/project_templates/default/config.yml +5 -5
- rasa/cli/project_templates/default/credentials.yml +1 -1
- rasa/cli/project_templates/default/endpoints.yml +4 -4
- rasa/cli/project_templates/default/tests/test_stories.yml +1 -1
- rasa/cli/project_templates/tutorial/config.yml +1 -1
- rasa/cli/project_templates/tutorial/credentials.yml +1 -1
- rasa/cli/project_templates/tutorial/data/patterns.yml +6 -0
- rasa/cli/project_templates/tutorial/domain.yml +4 -0
- rasa/cli/project_templates/tutorial/endpoints.yml +6 -6
- rasa/cli/run.py +0 -1
- rasa/cli/scaffold.py +3 -2
- rasa/cli/studio/download.py +11 -0
- rasa/cli/studio/studio.py +180 -24
- rasa/cli/studio/upload.py +0 -8
- rasa/cli/telemetry.py +18 -6
- rasa/cli/utils.py +21 -10
- rasa/cli/x.py +3 -2
- rasa/constants.py +1 -1
- rasa/core/actions/action.py +90 -315
- rasa/core/actions/action_exceptions.py +24 -0
- rasa/core/actions/constants.py +3 -0
- rasa/core/actions/custom_action_executor.py +188 -0
- rasa/core/actions/forms.py +11 -7
- rasa/core/actions/grpc_custom_action_executor.py +251 -0
- rasa/core/actions/http_custom_action_executor.py +140 -0
- rasa/core/actions/loops.py +3 -0
- rasa/core/actions/two_stage_fallback.py +1 -1
- rasa/core/agent.py +2 -4
- rasa/core/brokers/pika.py +1 -2
- rasa/core/channels/audiocodes.py +1 -1
- rasa/core/channels/botframework.py +0 -1
- rasa/core/channels/callback.py +0 -1
- rasa/core/channels/console.py +6 -8
- rasa/core/channels/development_inspector.py +1 -1
- rasa/core/channels/facebook.py +0 -3
- rasa/core/channels/hangouts.py +0 -6
- rasa/core/channels/inspector/dist/assets/{arc-5623b6dc.js → arc-b6e548fe.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-d0fbc5ce-685c106a.js → c4Diagram-d0fbc5ce-fa03ac9e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-936ed81e-8cbed007.js → classDiagram-936ed81e-ee67392a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-c3cb15f1-5889cf12.js → classDiagram-v2-c3cb15f1-9b283fae.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{createText-62fc7601-24c249d7.js → createText-62fc7601-8b6fcc2a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-f2ad444c-7dd06a75.js → edges-f2ad444c-22e77f4f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-62c1e54c.js → erDiagram-9d236eb7-60ffc87f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-1972c806-ce49b86f.js → flowDb-1972c806-9dd802e4.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-7ea5b25a-4067e48f.js → flowDiagram-7ea5b25a-5fa1912f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-1844e5a5.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-abe16c3d-59fe4051.js → flowchart-elk-definition-abe16c3d-622a1fd2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-9b5ea136-47e3a43b.js → ganttDiagram-9b5ea136-e285a63a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-99d0ae7c-5a2ac0d9.js → gitGraphDiagram-99d0ae7c-f237bdca.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-2c4b9a3b-dfb8efc4.js → index-2c4b9a3b-4b03d70e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-268a75c0.js → index-a5d3e69d.js} +4 -4
- rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-b0c470f2.js → infoDiagram-736b4530-72a0fa5f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-2edb829a.js → journeyDiagram-df861f2b-82218c41.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-b6873d69.js → layout-78cff630.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-1efc5781.js → line-5038b469.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-661e9b94.js → linear-c4fc4098.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-beec6740-2d2e727f.js → mindmap-definition-beec6740-c33c8ea6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-9d3ea93d.js → pieDiagram-dbbf0591-a8d03059.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-06a178a2.js → quadrantDiagram-4d7f4fd6-6a0e56b2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-0bfedffc.js → requirementDiagram-6fc4c22a-2dc7c7bd.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-8f13d901-d76d0a04.js → sankeyDiagram-8f13d901-2360fe39.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-b655622a-37bb4341.js → sequenceDiagram-b655622a-41b9f9ad.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-59f0c015-f52f7f57.js → stateDiagram-59f0c015-0aad326f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-2b26beab-4a986a20.js → stateDiagram-v2-2b26beab-9847d984.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-080da4f6-7dd9ae12.js → styles-080da4f6-564d890e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-3dcbcfbf-46e1ca14.js → styles-3dcbcfbf-38957613.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9c745c82-4a97439a.js → styles-9c745c82-f0fc6921.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-4835440b-823917a3.js → svgDrawCommon-4835440b-ef3c5a77.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-9ea72896.js → timeline-definition-5b62e21b-bf3e91c1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-b631a8b6.js → xychartDiagram-2b33534f-4d4026c0.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +10 -0
- rasa/core/channels/inspector/src/helpers/formatters.test.ts +4 -7
- rasa/core/channels/inspector/src/helpers/formatters.ts +3 -2
- rasa/core/channels/rest.py +36 -21
- rasa/core/channels/rocketchat.py +0 -1
- rasa/core/channels/socketio.py +1 -1
- rasa/core/channels/telegram.py +3 -3
- rasa/core/channels/webexteams.py +0 -1
- rasa/core/concurrent_lock_store.py +1 -1
- rasa/core/evaluation/marker_base.py +1 -3
- rasa/core/evaluation/marker_stats.py +1 -2
- rasa/core/featurizers/single_state_featurizer.py +3 -26
- rasa/core/featurizers/tracker_featurizers.py +18 -122
- rasa/core/information_retrieval/__init__.py +7 -0
- rasa/core/information_retrieval/faiss.py +9 -4
- rasa/core/information_retrieval/information_retrieval.py +64 -7
- rasa/core/information_retrieval/milvus.py +7 -14
- rasa/core/information_retrieval/qdrant.py +8 -15
- rasa/core/lock_store.py +0 -1
- rasa/core/migrate.py +1 -2
- rasa/core/nlg/callback.py +3 -4
- rasa/core/policies/enterprise_search_policy.py +86 -22
- rasa/core/policies/enterprise_search_prompt_template.jinja2 +4 -41
- rasa/core/policies/enterprise_search_prompt_with_citation_template.jinja2 +60 -0
- rasa/core/policies/flows/flow_executor.py +104 -2
- rasa/core/policies/intentless_policy.py +7 -9
- rasa/core/policies/memoization.py +3 -3
- rasa/core/policies/policy.py +18 -9
- rasa/core/policies/rule_policy.py +8 -11
- rasa/core/policies/ted_policy.py +61 -88
- rasa/core/policies/unexpected_intent_policy.py +8 -17
- rasa/core/processor.py +136 -47
- rasa/core/run.py +41 -25
- rasa/core/secrets_manager/endpoints.py +2 -2
- rasa/core/secrets_manager/vault.py +6 -8
- rasa/core/test.py +3 -5
- rasa/core/tracker_store.py +49 -14
- rasa/core/train.py +1 -3
- rasa/core/training/interactive.py +9 -6
- rasa/core/utils.py +5 -10
- rasa/dialogue_understanding/coexistence/intent_based_router.py +11 -4
- rasa/dialogue_understanding/coexistence/llm_based_router.py +2 -3
- rasa/dialogue_understanding/commands/__init__.py +4 -0
- rasa/dialogue_understanding/commands/can_not_handle_command.py +9 -0
- rasa/dialogue_understanding/commands/cancel_flow_command.py +9 -0
- rasa/dialogue_understanding/commands/change_flow_command.py +38 -0
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +9 -0
- rasa/dialogue_understanding/commands/clarify_command.py +9 -0
- rasa/dialogue_understanding/commands/correct_slots_command.py +9 -0
- rasa/dialogue_understanding/commands/error_command.py +12 -0
- rasa/dialogue_understanding/commands/handle_code_change_command.py +9 -0
- rasa/dialogue_understanding/commands/human_handoff_command.py +9 -0
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +9 -0
- rasa/dialogue_understanding/commands/noop_command.py +9 -0
- rasa/dialogue_understanding/commands/set_slot_command.py +38 -3
- rasa/dialogue_understanding/commands/skip_question_command.py +9 -0
- rasa/dialogue_understanding/commands/start_flow_command.py +9 -0
- rasa/dialogue_understanding/generator/__init__.py +16 -1
- rasa/dialogue_understanding/generator/command_generator.py +92 -6
- rasa/dialogue_understanding/generator/constants.py +18 -0
- rasa/dialogue_understanding/generator/flow_retrieval.py +7 -5
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +467 -0
- rasa/dialogue_understanding/generator/llm_command_generator.py +39 -609
- rasa/dialogue_understanding/generator/multi_step/__init__.py +0 -0
- rasa/dialogue_understanding/generator/multi_step/fill_slots_prompt.jinja2 +62 -0
- rasa/dialogue_understanding/generator/multi_step/handle_flows_prompt.jinja2 +38 -0
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +827 -0
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +69 -8
- rasa/dialogue_understanding/generator/single_step/__init__.py +0 -0
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +345 -0
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +36 -31
- rasa/dialogue_understanding/processor/command_processor.py +112 -3
- rasa/e2e_test/constants.py +1 -0
- rasa/e2e_test/e2e_test_case.py +44 -0
- rasa/e2e_test/e2e_test_runner.py +114 -11
- rasa/e2e_test/e2e_test_schema.yml +18 -0
- rasa/engine/caching.py +0 -1
- rasa/engine/graph.py +18 -6
- rasa/engine/recipes/config_files/default_config.yml +3 -3
- rasa/engine/recipes/default_components.py +1 -1
- rasa/engine/recipes/default_recipe.py +4 -5
- rasa/engine/recipes/recipe.py +1 -1
- rasa/engine/runner/dask.py +3 -9
- rasa/engine/storage/local_model_storage.py +0 -2
- rasa/engine/validation.py +179 -145
- rasa/exceptions.py +2 -2
- rasa/graph_components/validators/default_recipe_validator.py +3 -5
- rasa/hooks.py +0 -1
- rasa/model.py +1 -1
- rasa/model_training.py +1 -0
- rasa/nlu/classifiers/diet_classifier.py +33 -52
- rasa/nlu/classifiers/logistic_regression_classifier.py +9 -22
- rasa/nlu/classifiers/sklearn_intent_classifier.py +16 -37
- rasa/nlu/extractors/crf_entity_extractor.py +54 -97
- rasa/nlu/extractors/duckling_entity_extractor.py +1 -1
- rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +1 -5
- rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +0 -4
- rasa/nlu/featurizers/featurizer.py +1 -1
- rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +18 -49
- rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +26 -64
- rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +3 -5
- rasa/nlu/persistor.py +68 -26
- rasa/nlu/selectors/response_selector.py +7 -10
- rasa/nlu/test.py +0 -3
- rasa/nlu/utils/hugging_face/registry.py +1 -1
- rasa/nlu/utils/spacy_utils.py +1 -3
- rasa/server.py +22 -7
- rasa/shared/constants.py +12 -1
- rasa/shared/core/command_payload_reader.py +109 -0
- rasa/shared/core/constants.py +4 -5
- rasa/shared/core/domain.py +57 -56
- rasa/shared/core/events.py +4 -7
- rasa/shared/core/flows/flow.py +9 -0
- rasa/shared/core/flows/flows_list.py +12 -0
- rasa/shared/core/flows/steps/action.py +7 -2
- rasa/shared/core/generator.py +12 -11
- rasa/shared/core/slot_mappings.py +315 -24
- rasa/shared/core/slots.py +4 -2
- rasa/shared/core/trackers.py +32 -14
- rasa/shared/core/training_data/loading.py +0 -1
- rasa/shared/core/training_data/story_reader/story_reader.py +3 -3
- rasa/shared/core/training_data/story_reader/yaml_story_reader.py +11 -11
- rasa/shared/core/training_data/story_writer/yaml_story_writer.py +5 -3
- rasa/shared/core/training_data/structures.py +1 -1
- rasa/shared/core/training_data/visualization.py +1 -1
- rasa/shared/data.py +58 -1
- rasa/shared/exceptions.py +36 -2
- rasa/shared/importers/importer.py +1 -2
- rasa/shared/importers/rasa.py +0 -1
- rasa/shared/nlu/constants.py +2 -0
- rasa/shared/nlu/training_data/entities_parser.py +1 -2
- rasa/shared/nlu/training_data/features.py +2 -120
- rasa/shared/nlu/training_data/formats/dialogflow.py +3 -2
- rasa/shared/nlu/training_data/formats/rasa_yaml.py +3 -5
- rasa/shared/nlu/training_data/formats/readerwriter.py +0 -1
- rasa/shared/nlu/training_data/message.py +13 -0
- rasa/shared/nlu/training_data/training_data.py +0 -2
- rasa/shared/providers/openai/session_handler.py +2 -2
- rasa/shared/utils/constants.py +3 -0
- rasa/shared/utils/io.py +11 -1
- rasa/shared/utils/llm.py +1 -2
- rasa/shared/utils/pykwalify_extensions.py +1 -0
- rasa/shared/utils/schemas/domain.yml +3 -0
- rasa/shared/utils/yaml.py +44 -35
- rasa/studio/auth.py +26 -10
- rasa/studio/constants.py +2 -0
- rasa/studio/data_handler.py +114 -107
- rasa/studio/download.py +160 -27
- rasa/studio/results_logger.py +137 -0
- rasa/studio/train.py +6 -7
- rasa/studio/upload.py +159 -134
- rasa/telemetry.py +188 -34
- rasa/tracing/config.py +18 -3
- rasa/tracing/constants.py +26 -2
- rasa/tracing/instrumentation/attribute_extractors.py +50 -41
- rasa/tracing/instrumentation/instrumentation.py +290 -44
- rasa/tracing/instrumentation/intentless_policy_instrumentation.py +7 -5
- rasa/tracing/instrumentation/metrics.py +109 -21
- rasa/tracing/metric_instrument_provider.py +83 -3
- rasa/utils/cli.py +2 -1
- rasa/utils/common.py +1 -1
- rasa/utils/endpoints.py +1 -2
- rasa/utils/io.py +72 -6
- rasa/utils/licensing.py +246 -31
- rasa/utils/ml_utils.py +1 -1
- rasa/utils/tensorflow/data_generator.py +1 -1
- rasa/utils/tensorflow/environment.py +1 -1
- rasa/utils/tensorflow/model_data.py +201 -12
- rasa/utils/tensorflow/model_data_utils.py +499 -500
- rasa/utils/tensorflow/models.py +5 -6
- rasa/utils/tensorflow/rasa_layers.py +15 -15
- rasa/utils/train_utils.py +1 -1
- rasa/utils/url_tools.py +53 -0
- rasa/validator.py +305 -3
- rasa/version.py +1 -1
- {rasa_pro-3.8.18.dist-info → rasa_pro-3.9.15.dist-info}/METADATA +25 -61
- {rasa_pro-3.8.18.dist-info → rasa_pro-3.9.15.dist-info}/RECORD +276 -259
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-85583a23.js +0 -1
- rasa/utils/tensorflow/feature_array.py +0 -370
- /rasa/dialogue_understanding/generator/{command_prompt_template.jinja2 → single_step/command_prompt_template.jinja2} +0 -0
- {rasa_pro-3.8.18.dist-info → rasa_pro-3.9.15.dist-info}/NOTICE +0 -0
- {rasa_pro-3.8.18.dist-info → rasa_pro-3.9.15.dist-info}/WHEEL +0 -0
- {rasa_pro-3.8.18.dist-info → rasa_pro-3.9.15.dist-info}/entry_points.txt +0 -0
rasa/shared/core/generator.py
CHANGED
|
@@ -401,8 +401,9 @@ class TrainingDataGenerator:
|
|
|
401
401
|
|
|
402
402
|
if num_active_trackers:
|
|
403
403
|
logger.debug(
|
|
404
|
-
"Starting {} ... (with {} trackers)"
|
|
405
|
-
|
|
404
|
+
"Starting {} ... (with {} trackers)".format(
|
|
405
|
+
phase_name, num_active_trackers
|
|
406
|
+
)
|
|
406
407
|
)
|
|
407
408
|
else:
|
|
408
409
|
logger.debug(f"There are no trackers for {phase_name}")
|
|
@@ -516,14 +517,14 @@ class TrainingDataGenerator:
|
|
|
516
517
|
phase = 0
|
|
517
518
|
else:
|
|
518
519
|
logger.debug(
|
|
519
|
-
"Found {} unused checkpoints "
|
|
520
|
-
|
|
521
|
-
|
|
520
|
+
"Found {} unused checkpoints in current phase.".format(
|
|
521
|
+
len(unused_checkpoints)
|
|
522
|
+
)
|
|
522
523
|
)
|
|
523
524
|
logger.debug(
|
|
524
|
-
"Found {} active trackers "
|
|
525
|
-
|
|
526
|
-
|
|
525
|
+
"Found {} active trackers for these checkpoints.".format(
|
|
526
|
+
num_active_trackers
|
|
527
|
+
)
|
|
527
528
|
)
|
|
528
529
|
|
|
529
530
|
if everything_reachable_is_reached:
|
|
@@ -552,8 +553,9 @@ class TrainingDataGenerator:
|
|
|
552
553
|
augmented_trackers, self.config.max_number_of_augmented_trackers
|
|
553
554
|
)
|
|
554
555
|
logger.debug(
|
|
555
|
-
"Subsampled to {} augmented training trackers."
|
|
556
|
-
|
|
556
|
+
"Subsampled to {} augmented training trackers.".format(
|
|
557
|
+
len(augmented_trackers)
|
|
558
|
+
)
|
|
557
559
|
)
|
|
558
560
|
logger.debug(
|
|
559
561
|
"There are {} original trackers.".format(len(original_trackers))
|
|
@@ -672,7 +674,6 @@ class TrainingDataGenerator:
|
|
|
672
674
|
|
|
673
675
|
trackers = []
|
|
674
676
|
if events: # small optimization
|
|
675
|
-
|
|
676
677
|
# need to copy the tracker as multiple story steps
|
|
677
678
|
# might start with the same checkpoint and all of them
|
|
678
679
|
# will use the same set of incoming trackers
|
|
@@ -1,16 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Text, Dict, Any, List, Optional, TYPE_CHECKING, Tuple, cast
|
|
2
3
|
|
|
3
4
|
from rasa.shared.constants import DOCS_URL_NLU_BASED_SLOTS, IGNORED_INTENTS
|
|
4
5
|
import rasa.shared.utils.io
|
|
6
|
+
from rasa.shared.core.slots import ListSlot, Slot
|
|
5
7
|
from rasa.shared.nlu.constants import (
|
|
8
|
+
ENTITIES,
|
|
6
9
|
ENTITY_ATTRIBUTE_TYPE,
|
|
7
10
|
ENTITY_ATTRIBUTE_ROLE,
|
|
8
11
|
ENTITY_ATTRIBUTE_GROUP,
|
|
12
|
+
ENTITY_ATTRIBUTE_VALUE,
|
|
9
13
|
INTENT,
|
|
10
14
|
NOT_INTENT,
|
|
11
15
|
INTENT_NAME_KEY,
|
|
16
|
+
TEXT,
|
|
12
17
|
)
|
|
13
18
|
from rasa.shared.core.constants import (
|
|
19
|
+
ACTIVE_FLOW,
|
|
20
|
+
ACTIVE_LOOP,
|
|
21
|
+
REQUESTED_SLOT,
|
|
14
22
|
SLOT_MAPPINGS,
|
|
15
23
|
MAPPING_TYPE,
|
|
16
24
|
SlotMappingType,
|
|
@@ -20,6 +28,11 @@ from rasa.shared.core.constants import (
|
|
|
20
28
|
if TYPE_CHECKING:
|
|
21
29
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
22
30
|
from rasa.shared.core.domain import Domain
|
|
31
|
+
from rasa.shared.nlu.training_data.message import Message
|
|
32
|
+
from rasa.utils.endpoints import EndpointConfig
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
logger = logging.getLogger(__name__)
|
|
23
36
|
|
|
24
37
|
|
|
25
38
|
class SlotMapping:
|
|
@@ -60,6 +73,7 @@ class SlotMapping:
|
|
|
60
73
|
SlotMappingType.FROM_TRIGGER_INTENT: ["value"],
|
|
61
74
|
SlotMappingType.FROM_TEXT: [],
|
|
62
75
|
SlotMappingType.CUSTOM: [],
|
|
76
|
+
SlotMappingType.FROM_LLM: [],
|
|
63
77
|
}
|
|
64
78
|
|
|
65
79
|
required_keys = validations[mapping_type]
|
|
@@ -99,7 +113,10 @@ class SlotMapping:
|
|
|
99
113
|
|
|
100
114
|
@staticmethod
|
|
101
115
|
def intent_is_desired(
|
|
102
|
-
mapping: Dict[Text, Any],
|
|
116
|
+
mapping: Dict[Text, Any],
|
|
117
|
+
tracker: "DialogueStateTracker",
|
|
118
|
+
domain: "Domain",
|
|
119
|
+
message: Optional["Message"] = None,
|
|
103
120
|
) -> bool:
|
|
104
121
|
"""Checks whether user intent matches slot mapping intent specifications."""
|
|
105
122
|
mapping_intents = SlotMapping.to_list(mapping.get(INTENT, []))
|
|
@@ -114,7 +131,9 @@ class SlotMapping:
|
|
|
114
131
|
)
|
|
115
132
|
)
|
|
116
133
|
|
|
117
|
-
if
|
|
134
|
+
if message is not None:
|
|
135
|
+
intent = message.get(INTENT, {}).get("name")
|
|
136
|
+
elif tracker.latest_message:
|
|
118
137
|
intent = tracker.latest_message.intent.get(INTENT_NAME_KEY)
|
|
119
138
|
else:
|
|
120
139
|
intent = None
|
|
@@ -138,40 +157,44 @@ class SlotMapping:
|
|
|
138
157
|
|
|
139
158
|
@staticmethod
|
|
140
159
|
def entity_is_desired(
|
|
141
|
-
mapping: Dict[Text, Any],
|
|
142
|
-
|
|
160
|
+
mapping: Dict[Text, Any],
|
|
161
|
+
tracker: "DialogueStateTracker",
|
|
162
|
+
message: Optional["Message"] = None,
|
|
163
|
+
) -> List[str]:
|
|
143
164
|
"""Checks whether slot should be filled by an entity in the input or not.
|
|
144
165
|
|
|
145
166
|
Args:
|
|
146
167
|
mapping: Slot mapping.
|
|
147
168
|
tracker: The tracker.
|
|
169
|
+
message: The message being processed.
|
|
148
170
|
|
|
149
171
|
Returns:
|
|
150
|
-
|
|
172
|
+
A list of matching values.
|
|
151
173
|
"""
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
mapping.get(
|
|
161
|
-
and
|
|
162
|
-
==
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
174
|
+
if message is not None:
|
|
175
|
+
extracted_entities = message.get(ENTITIES, [])
|
|
176
|
+
matching_values = [
|
|
177
|
+
cast(Text, entity[ENTITY_ATTRIBUTE_VALUE])
|
|
178
|
+
for entity in extracted_entities
|
|
179
|
+
if entity.get(ENTITY_ATTRIBUTE_TYPE)
|
|
180
|
+
== mapping.get(ENTITY_ATTRIBUTE_TYPE)
|
|
181
|
+
and entity.get(ENTITY_ATTRIBUTE_GROUP)
|
|
182
|
+
== mapping.get(ENTITY_ATTRIBUTE_GROUP)
|
|
183
|
+
and entity.get(ENTITY_ATTRIBUTE_ROLE)
|
|
184
|
+
== mapping.get(ENTITY_ATTRIBUTE_ROLE)
|
|
185
|
+
]
|
|
186
|
+
elif tracker.latest_message and tracker.latest_message.text is not None:
|
|
187
|
+
matching_values = list(
|
|
188
|
+
tracker.get_latest_entity_values(
|
|
167
189
|
mapping.get(ENTITY_ATTRIBUTE_TYPE),
|
|
168
190
|
mapping.get(ENTITY_ATTRIBUTE_ROLE),
|
|
169
191
|
mapping.get(ENTITY_ATTRIBUTE_GROUP),
|
|
170
192
|
)
|
|
171
|
-
|
|
172
|
-
|
|
193
|
+
)
|
|
194
|
+
else:
|
|
195
|
+
matching_values = []
|
|
173
196
|
|
|
174
|
-
return
|
|
197
|
+
return matching_values
|
|
175
198
|
|
|
176
199
|
@staticmethod
|
|
177
200
|
def check_mapping_validity(
|
|
@@ -233,3 +256,271 @@ def validate_slot_mappings(domain_slots: Dict[Text, Any]) -> None:
|
|
|
233
256
|
|
|
234
257
|
for slot_mapping in mappings:
|
|
235
258
|
SlotMapping.validate(slot_mapping, slot_name)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class SlotFillingManager:
|
|
262
|
+
"""Manages slot filling based on conversation context."""
|
|
263
|
+
|
|
264
|
+
def __init__(
|
|
265
|
+
self,
|
|
266
|
+
domain: "Domain",
|
|
267
|
+
tracker: "DialogueStateTracker",
|
|
268
|
+
message: Optional["Message"] = None,
|
|
269
|
+
action_endpoint: Optional["EndpointConfig"] = None,
|
|
270
|
+
) -> None:
|
|
271
|
+
self.domain = domain
|
|
272
|
+
self.tracker = tracker
|
|
273
|
+
self.message = message
|
|
274
|
+
self._action_endpoint = action_endpoint
|
|
275
|
+
|
|
276
|
+
def is_slot_mapping_valid(
|
|
277
|
+
self,
|
|
278
|
+
slot_name: str,
|
|
279
|
+
mapping_type: SlotMappingType,
|
|
280
|
+
mapping: Dict[str, Any],
|
|
281
|
+
) -> bool:
|
|
282
|
+
"""Check if a slot mapping is valid."""
|
|
283
|
+
return SlotMapping.check_mapping_validity(
|
|
284
|
+
slot_name=slot_name,
|
|
285
|
+
mapping_type=mapping_type,
|
|
286
|
+
mapping=mapping,
|
|
287
|
+
domain=self.domain,
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
def is_intent_desired(self, mapping: Dict[str, Any]) -> bool:
|
|
291
|
+
"""Check if the intent matches the one indicated in the slot mapping."""
|
|
292
|
+
return SlotMapping.intent_is_desired(
|
|
293
|
+
mapping=mapping,
|
|
294
|
+
tracker=self.tracker,
|
|
295
|
+
domain=self.domain,
|
|
296
|
+
message=self.message,
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
def _verify_mapping_conditions(
|
|
300
|
+
self, mapping: Dict[Text, Any], slot_name: Text
|
|
301
|
+
) -> bool:
|
|
302
|
+
if mapping.get(MAPPING_CONDITIONS) and mapping[MAPPING_TYPE] != str(
|
|
303
|
+
SlotMappingType.FROM_TRIGGER_INTENT
|
|
304
|
+
):
|
|
305
|
+
if not self._matches_mapping_conditions(mapping, slot_name):
|
|
306
|
+
return False
|
|
307
|
+
|
|
308
|
+
return True
|
|
309
|
+
|
|
310
|
+
def _matches_mapping_conditions(
|
|
311
|
+
self, mapping: Dict[Text, Any], slot_name: Text
|
|
312
|
+
) -> bool:
|
|
313
|
+
slot_mapping_conditions = mapping.get(MAPPING_CONDITIONS)
|
|
314
|
+
|
|
315
|
+
if not slot_mapping_conditions:
|
|
316
|
+
return True
|
|
317
|
+
|
|
318
|
+
active_flow = self.tracker.active_flow
|
|
319
|
+
|
|
320
|
+
if active_flow:
|
|
321
|
+
return self._mapping_conditions_match_flow(
|
|
322
|
+
active_flow, slot_mapping_conditions
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
# if we are not in a flow, we could be in a form
|
|
326
|
+
return self._mapping_conditions_match_form(slot_name, slot_mapping_conditions)
|
|
327
|
+
|
|
328
|
+
@staticmethod
|
|
329
|
+
def _mapping_conditions_match_flow(
|
|
330
|
+
active_flow: str,
|
|
331
|
+
slot_mapping_conditions: List[Dict[str, str]],
|
|
332
|
+
) -> bool:
|
|
333
|
+
active_flow_conditions = list(
|
|
334
|
+
filter(lambda x: x.get(ACTIVE_FLOW) is not None, slot_mapping_conditions)
|
|
335
|
+
)
|
|
336
|
+
return any(
|
|
337
|
+
[
|
|
338
|
+
condition.get(ACTIVE_FLOW) == active_flow
|
|
339
|
+
for condition in active_flow_conditions
|
|
340
|
+
]
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
def _mapping_conditions_match_form(
|
|
344
|
+
self, slot_name: str, slot_mapping_conditions: List[Dict[str, str]]
|
|
345
|
+
) -> bool:
|
|
346
|
+
if (
|
|
347
|
+
self.tracker.is_active_loop_rejected
|
|
348
|
+
and self.tracker.get_slot(REQUESTED_SLOT) == slot_name
|
|
349
|
+
):
|
|
350
|
+
return False
|
|
351
|
+
|
|
352
|
+
# check if found mapping conditions matches form
|
|
353
|
+
for condition in slot_mapping_conditions:
|
|
354
|
+
# we allow None as a valid value for active_loop
|
|
355
|
+
# therefore we need to set a different default value
|
|
356
|
+
active_loop = condition.get(ACTIVE_LOOP, "")
|
|
357
|
+
|
|
358
|
+
if active_loop and active_loop == self.tracker.active_loop_name:
|
|
359
|
+
condition_requested_slot = condition.get(REQUESTED_SLOT)
|
|
360
|
+
if not condition_requested_slot:
|
|
361
|
+
return True
|
|
362
|
+
if condition_requested_slot == self.tracker.get_slot(REQUESTED_SLOT):
|
|
363
|
+
return True
|
|
364
|
+
|
|
365
|
+
if active_loop is None and self.tracker.active_loop_name is None:
|
|
366
|
+
return True
|
|
367
|
+
|
|
368
|
+
return False
|
|
369
|
+
|
|
370
|
+
def _fails_unique_entity_mapping_check(
|
|
371
|
+
self,
|
|
372
|
+
slot_name: Text,
|
|
373
|
+
mapping: Dict[Text, Any],
|
|
374
|
+
) -> bool:
|
|
375
|
+
from rasa.core.actions.forms import FormAction
|
|
376
|
+
|
|
377
|
+
if mapping[MAPPING_TYPE] != str(SlotMappingType.FROM_ENTITY):
|
|
378
|
+
return False
|
|
379
|
+
|
|
380
|
+
form_name = self.tracker.active_loop_name
|
|
381
|
+
|
|
382
|
+
if not form_name:
|
|
383
|
+
return False
|
|
384
|
+
|
|
385
|
+
if self.tracker.get_slot(REQUESTED_SLOT) == slot_name:
|
|
386
|
+
return False
|
|
387
|
+
|
|
388
|
+
form = FormAction(form_name, self._action_endpoint)
|
|
389
|
+
|
|
390
|
+
if slot_name not in form.required_slots(self.domain):
|
|
391
|
+
return False
|
|
392
|
+
|
|
393
|
+
if form.entity_mapping_is_unique(mapping, self.domain):
|
|
394
|
+
return False
|
|
395
|
+
|
|
396
|
+
return True
|
|
397
|
+
|
|
398
|
+
def _is_trigger_intent_mapping_condition_met(
|
|
399
|
+
self, mapping: Dict[Text, Any]
|
|
400
|
+
) -> bool:
|
|
401
|
+
active_loops_in_mapping_conditions = [
|
|
402
|
+
condition.get(ACTIVE_LOOP)
|
|
403
|
+
for condition in mapping.get(MAPPING_CONDITIONS, [])
|
|
404
|
+
]
|
|
405
|
+
|
|
406
|
+
trigger_mapping_condition_met = True
|
|
407
|
+
|
|
408
|
+
if self.tracker.active_loop_name is None:
|
|
409
|
+
trigger_mapping_condition_met = False
|
|
410
|
+
elif (
|
|
411
|
+
active_loops_in_mapping_conditions
|
|
412
|
+
and self.tracker.active_loop_name is not None
|
|
413
|
+
and (
|
|
414
|
+
self.tracker.active_loop_name not in active_loops_in_mapping_conditions
|
|
415
|
+
)
|
|
416
|
+
):
|
|
417
|
+
trigger_mapping_condition_met = False
|
|
418
|
+
|
|
419
|
+
return trigger_mapping_condition_met
|
|
420
|
+
|
|
421
|
+
def extract_slot_value_from_predefined_mapping(
|
|
422
|
+
self,
|
|
423
|
+
mapping_type: SlotMappingType,
|
|
424
|
+
mapping: Dict[Text, Any],
|
|
425
|
+
) -> List[Any]:
|
|
426
|
+
"""Extracts slot value if slot has an applicable predefined mapping."""
|
|
427
|
+
if (
|
|
428
|
+
self.message is None
|
|
429
|
+
and self.tracker.has_bot_message_after_latest_user_message()
|
|
430
|
+
):
|
|
431
|
+
# TODO: this needs further validation - not sure if this breaks something!!!
|
|
432
|
+
|
|
433
|
+
# If the bot sent a message after the user sent a message, we can't
|
|
434
|
+
# extract any slots from the user message. We assume that the user
|
|
435
|
+
# message was already processed by the bot and the slot value was
|
|
436
|
+
# already extracted (e.g. for a prior form slot).
|
|
437
|
+
return []
|
|
438
|
+
|
|
439
|
+
should_fill_entity_slot = mapping_type == SlotMappingType.FROM_ENTITY
|
|
440
|
+
|
|
441
|
+
should_fill_intent_slot = mapping_type == SlotMappingType.FROM_INTENT
|
|
442
|
+
|
|
443
|
+
should_fill_text_slot = mapping_type == SlotMappingType.FROM_TEXT
|
|
444
|
+
|
|
445
|
+
trigger_mapping_condition_met = self._is_trigger_intent_mapping_condition_met(
|
|
446
|
+
mapping
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
should_fill_trigger_slot = (
|
|
450
|
+
mapping_type == SlotMappingType.FROM_TRIGGER_INTENT
|
|
451
|
+
and trigger_mapping_condition_met
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
value: List[Any] = []
|
|
455
|
+
|
|
456
|
+
if should_fill_entity_slot:
|
|
457
|
+
value = SlotMapping.entity_is_desired(mapping, self.tracker, self.message)
|
|
458
|
+
elif should_fill_intent_slot or should_fill_trigger_slot:
|
|
459
|
+
value = [mapping.get("value")]
|
|
460
|
+
elif should_fill_text_slot:
|
|
461
|
+
value = [self.message.get(TEXT)] if self.message is not None else []
|
|
462
|
+
if not value:
|
|
463
|
+
value = [
|
|
464
|
+
self.tracker.latest_message.text
|
|
465
|
+
if self.tracker.latest_message is not None
|
|
466
|
+
else None
|
|
467
|
+
]
|
|
468
|
+
|
|
469
|
+
return value
|
|
470
|
+
|
|
471
|
+
def should_fill_slot(
|
|
472
|
+
self, slot_name: str, mapping_type: SlotMappingType, mapping: Dict[Text, Any]
|
|
473
|
+
) -> bool:
|
|
474
|
+
"""Checks if a slot should be filled based on the conversation context."""
|
|
475
|
+
if not self.is_slot_mapping_valid(slot_name, mapping_type, mapping):
|
|
476
|
+
return False
|
|
477
|
+
|
|
478
|
+
if not self.is_intent_desired(mapping):
|
|
479
|
+
return False
|
|
480
|
+
|
|
481
|
+
if not self._verify_mapping_conditions(mapping, slot_name):
|
|
482
|
+
return False
|
|
483
|
+
|
|
484
|
+
if self._fails_unique_entity_mapping_check(slot_name, mapping):
|
|
485
|
+
return False
|
|
486
|
+
|
|
487
|
+
return True
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
def extract_slot_value(
|
|
491
|
+
slot: Slot, slot_filling_manager: SlotFillingManager
|
|
492
|
+
) -> Tuple[Any, bool]:
|
|
493
|
+
"""Extracts the value of a slot based on the conversation context."""
|
|
494
|
+
is_extracted = False
|
|
495
|
+
|
|
496
|
+
for mapping in slot.mappings:
|
|
497
|
+
mapping_type = SlotMappingType(
|
|
498
|
+
mapping.get(MAPPING_TYPE, SlotMappingType.FROM_LLM.value)
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
if mapping_type in [SlotMappingType.FROM_LLM, SlotMappingType.CUSTOM]:
|
|
502
|
+
continue
|
|
503
|
+
|
|
504
|
+
if not slot_filling_manager.should_fill_slot(slot.name, mapping_type, mapping):
|
|
505
|
+
continue
|
|
506
|
+
|
|
507
|
+
value: List[Any] = (
|
|
508
|
+
slot_filling_manager.extract_slot_value_from_predefined_mapping(
|
|
509
|
+
mapping_type, mapping
|
|
510
|
+
)
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
if value:
|
|
514
|
+
if not isinstance(slot, ListSlot):
|
|
515
|
+
value = value[-1]
|
|
516
|
+
|
|
517
|
+
if (
|
|
518
|
+
value is not None
|
|
519
|
+
or slot_filling_manager.tracker.get_slot(slot.name) is not None
|
|
520
|
+
):
|
|
521
|
+
logger.debug(f"Extracted value '{value}' for slot '{slot.name}'.")
|
|
522
|
+
|
|
523
|
+
is_extracted = True
|
|
524
|
+
return value, is_extracted
|
|
525
|
+
|
|
526
|
+
return None, is_extracted
|
rasa/shared/core/slots.py
CHANGED
|
@@ -364,7 +364,7 @@ class ListSlot(Slot):
|
|
|
364
364
|
"""Sets the slot's value."""
|
|
365
365
|
# Call property setter of superclass
|
|
366
366
|
# FIXME: https://github.com/python/mypy/issues/8085
|
|
367
|
-
super(ListSlot, self.__class__).value.fset(self, self.coerce_value(value)) # type: ignore[attr-defined]
|
|
367
|
+
super(ListSlot, self.__class__).value.fset(self, self.coerce_value(value)) # type: ignore[attr-defined]
|
|
368
368
|
|
|
369
369
|
|
|
370
370
|
class CategoricalSlot(Slot):
|
|
@@ -579,7 +579,9 @@ class CategoricalSlot(Slot):
|
|
|
579
579
|
"""
|
|
580
580
|
# Call property setter of superclass
|
|
581
581
|
# FIXME: https://github.com/python/mypy/issues/8085
|
|
582
|
-
super(CategoricalSlot, self.__class__).value.fset(
|
|
582
|
+
super(CategoricalSlot, self.__class__).value.fset( # type: ignore[attr-defined]
|
|
583
|
+
self, self.coerce_value(value)
|
|
584
|
+
)
|
|
583
585
|
|
|
584
586
|
|
|
585
587
|
class AnySlot(Slot):
|
rasa/shared/core/trackers.py
CHANGED
|
@@ -289,7 +289,7 @@ class DialogueStateTracker:
|
|
|
289
289
|
parse_data_with_nlu_state = self.latest_message.parse_data.copy()
|
|
290
290
|
# Combine entities predicted by NLU with entities predicted by policies so that
|
|
291
291
|
# users can access them together via `latest_message` (e.g. in custom actions)
|
|
292
|
-
parse_data_with_nlu_state[ENTITIES] = self.latest_message.entities # type: ignore[literal-required]
|
|
292
|
+
parse_data_with_nlu_state[ENTITIES] = self.latest_message.entities # type: ignore[literal-required]
|
|
293
293
|
|
|
294
294
|
return parse_data_with_nlu_state
|
|
295
295
|
|
|
@@ -443,6 +443,12 @@ class DialogueStateTracker:
|
|
|
443
443
|
"""
|
|
444
444
|
return self._underlying_stack.copy()
|
|
445
445
|
|
|
446
|
+
@property
|
|
447
|
+
def active_flow(self) -> Optional[Text]:
|
|
448
|
+
"""Returns the name of the active flow."""
|
|
449
|
+
current_context = self.stack.current_context()
|
|
450
|
+
return current_context.get("flow_id")
|
|
451
|
+
|
|
446
452
|
@property
|
|
447
453
|
def has_coexistence_routing_slot(self) -> bool:
|
|
448
454
|
"""Returns whether the coexistence routing slot is present."""
|
|
@@ -482,8 +488,10 @@ class DialogueStateTracker:
|
|
|
482
488
|
entity_role: Optional[Text] = None,
|
|
483
489
|
entity_group: Optional[Text] = None,
|
|
484
490
|
) -> Iterator[Text]:
|
|
485
|
-
"""Get entity values
|
|
486
|
-
|
|
491
|
+
"""Get entity values for latest message.
|
|
492
|
+
|
|
493
|
+
Returns entity values found for the passed entity type and
|
|
494
|
+
optional role and group in latest message.
|
|
487
495
|
|
|
488
496
|
If you are only interested in the first entity of a given type use
|
|
489
497
|
`next(tracker.get_latest_entity_values(`"`my_entity_name`"`), None)`.
|
|
@@ -556,7 +564,6 @@ class DialogueStateTracker:
|
|
|
556
564
|
tracker = self.init_copy()
|
|
557
565
|
|
|
558
566
|
for event in self.applied_events(True):
|
|
559
|
-
|
|
560
567
|
if isinstance(event, ActionExecuted):
|
|
561
568
|
yield tracker, event.hide_rule_turn
|
|
562
569
|
|
|
@@ -718,7 +725,7 @@ class DialogueStateTracker:
|
|
|
718
725
|
|
|
719
726
|
def copy(self) -> "DialogueStateTracker":
|
|
720
727
|
"""Creates a duplicate of this tracker."""
|
|
721
|
-
return
|
|
728
|
+
return copy.deepcopy(self)
|
|
722
729
|
|
|
723
730
|
def travel_back_in_time(self, target_time: float) -> "DialogueStateTracker":
|
|
724
731
|
"""Creates a new tracker with a state at a specific timestamp.
|
|
@@ -999,8 +1006,9 @@ class DialogueStateTracker:
|
|
|
999
1006
|
flows: FlowsList,
|
|
1000
1007
|
max_turns: Optional[int] = 20,
|
|
1001
1008
|
) -> FlowsList:
|
|
1002
|
-
"""
|
|
1003
|
-
|
|
1009
|
+
"""Retrieves a list of previously started flows.
|
|
1010
|
+
|
|
1011
|
+
Returned flows have been started in the past within a given
|
|
1004
1012
|
number of conversation turns.
|
|
1005
1013
|
|
|
1006
1014
|
Args:
|
|
@@ -1015,7 +1023,6 @@ class DialogueStateTracker:
|
|
|
1015
1023
|
|
|
1016
1024
|
# cycle through events in reverse order (newest events are appended at the end)
|
|
1017
1025
|
for event in reversed(self.events):
|
|
1018
|
-
|
|
1019
1026
|
# check for FlowStarted event and append flow if it's in the flows lists
|
|
1020
1027
|
if (
|
|
1021
1028
|
isinstance(event, FlowStarted)
|
|
@@ -1033,8 +1040,9 @@ class DialogueStateTracker:
|
|
|
1033
1040
|
return FlowsList(underlying_flows=list(previously_started_flows.values()))
|
|
1034
1041
|
|
|
1035
1042
|
def get_startable_flows(self, flows: FlowsList) -> FlowsList:
|
|
1036
|
-
"""
|
|
1037
|
-
|
|
1043
|
+
"""Retrieves a list of flows that can be started.
|
|
1044
|
+
|
|
1045
|
+
Returned flows are startable given the current
|
|
1038
1046
|
state (context and slot values) of the tracker.
|
|
1039
1047
|
|
|
1040
1048
|
Args:
|
|
@@ -1048,9 +1056,15 @@ class DialogueStateTracker:
|
|
|
1048
1056
|
slots = self.slots
|
|
1049
1057
|
return flows.get_startable_flows(context, slots)
|
|
1050
1058
|
|
|
1059
|
+
@property
|
|
1060
|
+
def has_active_user_flow(self) -> bool:
|
|
1061
|
+
from rasa.dialogue_understanding.stack.utils import top_user_flow_frame
|
|
1062
|
+
|
|
1063
|
+
top_relevant_frame = top_user_flow_frame(self.stack)
|
|
1064
|
+
return bool(top_relevant_frame and top_relevant_frame.flow_id)
|
|
1065
|
+
|
|
1051
1066
|
def get_active_flows(self, flows: FlowsList) -> FlowsList:
|
|
1052
|
-
"""
|
|
1053
|
-
Retrieve a list of all currently active flows.
|
|
1067
|
+
"""Retrieve a list of all currently active flows.
|
|
1054
1068
|
|
|
1055
1069
|
Args:
|
|
1056
1070
|
flows: list of flows to check against for active flows.
|
|
@@ -1083,11 +1097,15 @@ class TrackerEventDiffEngine:
|
|
|
1083
1097
|
def event_difference(
|
|
1084
1098
|
original: DialogueStateTracker, tracker: DialogueStateTracker
|
|
1085
1099
|
) -> List[Event]:
|
|
1086
|
-
"""
|
|
1087
|
-
in the original tracker.
|
|
1100
|
+
"""Find all events in the tracker not present in the original tracker.
|
|
1088
1101
|
|
|
1089
1102
|
Args:
|
|
1103
|
+
original: Original tracker to compare against.
|
|
1090
1104
|
tracker: Tracker containing events from the current conversation session.
|
|
1105
|
+
|
|
1106
|
+
Returns:
|
|
1107
|
+
List of events from the new tracker which are not present
|
|
1108
|
+
in the original tracker.
|
|
1091
1109
|
"""
|
|
1092
1110
|
offset = len(original.events) if original else 0
|
|
1093
1111
|
events = tracker.events
|
|
@@ -83,8 +83,9 @@ class StoryReader:
|
|
|
83
83
|
)
|
|
84
84
|
if parsed_events is None:
|
|
85
85
|
raise StoryParseError(
|
|
86
|
-
"Unknown event '{}'. It is Neither an event "
|
|
87
|
-
|
|
86
|
+
"Unknown event '{}'. It is Neither an event nor an action).".format(
|
|
87
|
+
event_name
|
|
88
|
+
)
|
|
88
89
|
)
|
|
89
90
|
|
|
90
91
|
return parsed_events
|
|
@@ -110,7 +111,6 @@ class StoryReader:
|
|
|
110
111
|
def _add_checkpoint(
|
|
111
112
|
self, name: Text, conditions: Optional[Dict[Text, Any]]
|
|
112
113
|
) -> None:
|
|
113
|
-
|
|
114
114
|
# Ensure story part already has a name
|
|
115
115
|
if not self.current_step_builder:
|
|
116
116
|
raise StoryParseError(
|
|
@@ -87,6 +87,14 @@ CORE_SCHEMA_FILE = "shared/utils/schemas/stories.yml"
|
|
|
87
87
|
DEFAULT_VALUE_TEXT_SLOTS = "filled"
|
|
88
88
|
DEFAULT_VALUE_LIST_SLOTS = [DEFAULT_VALUE_TEXT_SLOTS]
|
|
89
89
|
|
|
90
|
+
INTENT_ENTITIES_PATTERN = (
|
|
91
|
+
f"^{INTENT_MESSAGE_PREFIX}"
|
|
92
|
+
f"(?P<{INTENT_NAME_KEY}>[^{{@]+)" # "{{" is a masked "{" in an f-string
|
|
93
|
+
f"(?P<{PREDICTED_CONFIDENCE_KEY}>@[0-9.]+)?"
|
|
94
|
+
f"(?P<{ENTITIES}>{{.+}})?" # "{{" is a masked "{" in an f-string
|
|
95
|
+
f"(?P<rest>.*)"
|
|
96
|
+
)
|
|
97
|
+
|
|
90
98
|
|
|
91
99
|
class YAMLStoryReader(StoryReader):
|
|
92
100
|
"""Class that reads Core training data and rule data in YAML format."""
|
|
@@ -444,7 +452,7 @@ class YAMLStoryReader(StoryReader):
|
|
|
444
452
|
f"{self._get_item_title()}:\n"
|
|
445
453
|
f"User intent '{user_intent}' is a full retrieval intent. "
|
|
446
454
|
f"Stories shouldn't contain full retrieval intents. "
|
|
447
|
-
f"Rasa
|
|
455
|
+
f"Rasa Pro will only use base intent '{base_intent}' "
|
|
448
456
|
f"for training.",
|
|
449
457
|
docs=self._get_docs_link(),
|
|
450
458
|
)
|
|
@@ -482,7 +490,7 @@ class YAMLStoryReader(StoryReader):
|
|
|
482
490
|
|
|
483
491
|
@staticmethod
|
|
484
492
|
def _parse_raw_entities(
|
|
485
|
-
raw_entities: Union[List[Dict[Text, Text]], List[Text]]
|
|
493
|
+
raw_entities: Union[List[Dict[Text, Text]], List[Text]],
|
|
486
494
|
) -> List[Dict[Text, Optional[Text]]]:
|
|
487
495
|
final_entities = []
|
|
488
496
|
for entity in raw_entities:
|
|
@@ -556,7 +564,6 @@ class YAMLStoryReader(StoryReader):
|
|
|
556
564
|
return default_value
|
|
557
565
|
|
|
558
566
|
def _parse_action(self, step: Dict[Text, Any]) -> None:
|
|
559
|
-
|
|
560
567
|
action_name = step.get(KEY_ACTION, "")
|
|
561
568
|
if not action_name:
|
|
562
569
|
rasa.shared.utils.io.raise_warning(
|
|
@@ -582,7 +589,6 @@ class YAMLStoryReader(StoryReader):
|
|
|
582
589
|
self._add_event(ActiveLoop.type_name, {LOOP_NAME: active_loop_name})
|
|
583
590
|
|
|
584
591
|
def _parse_checkpoint(self, step: Dict[Text, Any]) -> None:
|
|
585
|
-
|
|
586
592
|
checkpoint_name = step.get(KEY_CHECKPOINT, "")
|
|
587
593
|
slots = step.get(KEY_CHECKPOINT_SLOTS, [])
|
|
588
594
|
|
|
@@ -611,13 +617,7 @@ class YAMLStoryReader(StoryReader):
|
|
|
611
617
|
Returns:
|
|
612
618
|
pattern with named groups
|
|
613
619
|
"""
|
|
614
|
-
return re.compile(
|
|
615
|
-
f"^{INTENT_MESSAGE_PREFIX}"
|
|
616
|
-
f"(?P<{INTENT_NAME_KEY}>[^{{@]+)" # "{{" is a masked "{" in an f-string
|
|
617
|
-
f"(?P<{PREDICTED_CONFIDENCE_KEY}>@[0-9.]+)?"
|
|
618
|
-
f"(?P<{ENTITIES}>{{.+}})?" # "{{" is a masked "{" in an f-string
|
|
619
|
-
f"(?P<rest>.*)"
|
|
620
|
-
)
|
|
620
|
+
return re.compile(INTENT_ENTITIES_PATTERN)
|
|
621
621
|
|
|
622
622
|
@staticmethod
|
|
623
623
|
def unpack_regex_message(
|