rasa-pro 3.10.16__py3-none-any.whl → 3.11.0a1__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 +396 -17
- rasa/api.py +9 -3
- rasa/cli/arguments/default_arguments.py +23 -2
- rasa/cli/arguments/run.py +15 -0
- rasa/cli/arguments/train.py +3 -9
- rasa/cli/e2e_test.py +1 -1
- rasa/cli/evaluate.py +1 -1
- rasa/cli/inspect.py +8 -4
- rasa/cli/llm_fine_tuning.py +12 -15
- rasa/cli/run.py +8 -1
- rasa/cli/studio/studio.py +8 -18
- rasa/cli/train.py +11 -53
- rasa/cli/utils.py +8 -10
- rasa/cli/x.py +1 -1
- rasa/constants.py +1 -1
- rasa/core/actions/action.py +2 -0
- rasa/core/actions/action_hangup.py +29 -0
- rasa/core/agent.py +2 -2
- rasa/core/brokers/kafka.py +3 -1
- rasa/core/brokers/pika.py +3 -1
- rasa/core/channels/__init__.py +8 -6
- rasa/core/channels/channel.py +21 -4
- rasa/core/channels/development_inspector.py +143 -46
- rasa/core/channels/inspector/README.md +1 -1
- rasa/core/channels/inspector/dist/assets/{arc-b6e548fe.js → arc-86942a71.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-d0fbc5ce-fa03ac9e.js → c4Diagram-d0fbc5ce-b0290676.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-936ed81e-ee67392a.js → classDiagram-936ed81e-f6405f6e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-c3cb15f1-9b283fae.js → classDiagram-v2-c3cb15f1-ef61ac77.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{createText-62fc7601-8b6fcc2a.js → createText-62fc7601-f0411e58.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-f2ad444c-22e77f4f.js → edges-f2ad444c-7dcc4f3b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-60ffc87f.js → erDiagram-9d236eb7-e0c092d7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-1972c806-9dd802e4.js → flowDb-1972c806-fba2e3ce.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-7ea5b25a-5fa1912f.js → flowDiagram-7ea5b25a-7a70b71a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-24a5f41a.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-abe16c3d-622a1fd2.js → flowchart-elk-definition-abe16c3d-00a59b68.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-9b5ea136-e285a63a.js → ganttDiagram-9b5ea136-293c91fa.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-99d0ae7c-f237bdca.js → gitGraphDiagram-99d0ae7c-07b2d68c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-2c4b9a3b-4b03d70e.js → index-2c4b9a3b-bc959fbd.js} +1 -1
- rasa/core/channels/inspector/dist/assets/index-3a8a5a28.js +1317 -0
- rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-72a0fa5f.js → infoDiagram-736b4530-4a350f72.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-82218c41.js → journeyDiagram-df861f2b-af464fb7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-78cff630.js → layout-0071f036.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-5038b469.js → line-2f73cc83.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-c4fc4098.js → linear-f014b4cc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-beec6740-c33c8ea6.js → mindmap-definition-beec6740-d2426fb6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-a8d03059.js → pieDiagram-dbbf0591-776f01a2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-6a0e56b2.js → quadrantDiagram-4d7f4fd6-82e00b57.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-2dc7c7bd.js → requirementDiagram-6fc4c22a-ea13c6bb.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-8f13d901-2360fe39.js → sankeyDiagram-8f13d901-1feca7e9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-b655622a-41b9f9ad.js → sequenceDiagram-b655622a-070c61d2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-59f0c015-0aad326f.js → stateDiagram-59f0c015-24f46263.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-2b26beab-9847d984.js → stateDiagram-v2-2b26beab-c9056051.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-080da4f6-564d890e.js → styles-080da4f6-08abc34a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-3dcbcfbf-38957613.js → styles-3dcbcfbf-bc74c25a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9c745c82-f0fc6921.js → styles-9c745c82-4e5d66de.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-4835440b-ef3c5a77.js → svgDrawCommon-4835440b-849c4517.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-bf3e91c1.js → timeline-definition-5b62e21b-d0fb1598.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-4d4026c0.js → xychartDiagram-2b33534f-04d115e2.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +18 -17
- rasa/core/channels/inspector/index.html +17 -16
- rasa/core/channels/inspector/package.json +5 -1
- rasa/core/channels/inspector/src/App.tsx +117 -67
- rasa/core/channels/inspector/src/components/Chat.tsx +95 -0
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +11 -10
- rasa/core/channels/inspector/src/components/DialogueStack.tsx +10 -25
- rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +1 -1
- rasa/core/channels/inspector/src/helpers/formatters.test.ts +10 -0
- rasa/core/channels/inspector/src/helpers/formatters.ts +107 -41
- rasa/core/channels/inspector/src/helpers/utils.ts +92 -7
- rasa/core/channels/inspector/src/types.ts +21 -1
- rasa/core/channels/inspector/yarn.lock +94 -1
- rasa/core/channels/rest.py +51 -46
- rasa/core/channels/socketio.py +22 -0
- rasa/core/channels/{audiocodes.py → voice_ready/audiocodes.py} +110 -68
- rasa/core/channels/{voice_aware → voice_ready}/jambonz.py +11 -4
- rasa/core/channels/{voice_aware → voice_ready}/jambonz_protocol.py +57 -5
- rasa/core/channels/{twilio_voice.py → voice_ready/twilio_voice.py} +58 -7
- rasa/core/channels/{voice_aware → voice_ready}/utils.py +16 -0
- rasa/core/channels/voice_stream/asr/__init__.py +0 -0
- rasa/core/channels/voice_stream/asr/asr_engine.py +71 -0
- rasa/core/channels/voice_stream/asr/asr_event.py +13 -0
- rasa/core/channels/voice_stream/asr/deepgram.py +77 -0
- rasa/core/channels/voice_stream/audio_bytes.py +7 -0
- rasa/core/channels/voice_stream/tts/__init__.py +0 -0
- rasa/core/channels/voice_stream/tts/azure.py +100 -0
- rasa/core/channels/voice_stream/tts/cartesia.py +114 -0
- rasa/core/channels/voice_stream/tts/tts_cache.py +27 -0
- rasa/core/channels/voice_stream/tts/tts_engine.py +48 -0
- rasa/core/channels/voice_stream/twilio_media_streams.py +164 -0
- rasa/core/channels/voice_stream/util.py +57 -0
- rasa/core/channels/voice_stream/voice_channel.py +247 -0
- rasa/core/featurizers/single_state_featurizer.py +1 -22
- rasa/core/featurizers/tracker_featurizers.py +18 -115
- rasa/core/nlg/contextual_response_rephraser.py +11 -2
- rasa/{nlu → core}/persistor.py +16 -38
- rasa/core/policies/enterprise_search_policy.py +12 -15
- rasa/core/policies/flows/flow_executor.py +8 -18
- rasa/core/policies/intentless_policy.py +10 -15
- rasa/core/policies/ted_policy.py +33 -58
- rasa/core/policies/unexpected_intent_policy.py +7 -15
- rasa/core/processor.py +13 -64
- rasa/core/run.py +11 -1
- rasa/core/secrets_manager/constants.py +4 -0
- rasa/core/secrets_manager/factory.py +8 -0
- rasa/core/secrets_manager/vault.py +11 -1
- rasa/core/training/interactive.py +1 -1
- rasa/core/utils.py +1 -11
- rasa/dialogue_understanding/coexistence/llm_based_router.py +10 -10
- rasa/dialogue_understanding/commands/__init__.py +2 -0
- rasa/dialogue_understanding/commands/change_flow_command.py +0 -6
- rasa/dialogue_understanding/commands/session_end_command.py +61 -0
- rasa/dialogue_understanding/generator/flow_retrieval.py +0 -7
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +12 -3
- rasa/dialogue_understanding/generator/llm_command_generator.py +1 -1
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +3 -28
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +1 -19
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +4 -37
- rasa/e2e_test/aggregate_test_stats_calculator.py +1 -11
- rasa/e2e_test/assertions.py +6 -48
- rasa/e2e_test/e2e_test_runner.py +6 -9
- rasa/e2e_test/utils/e2e_yaml_utils.py +1 -1
- rasa/e2e_test/utils/io.py +1 -3
- rasa/engine/graph.py +3 -10
- rasa/engine/recipes/config_files/default_config.yml +0 -3
- rasa/engine/recipes/default_recipe.py +0 -1
- rasa/engine/recipes/graph_recipe.py +0 -1
- rasa/engine/runner/dask.py +2 -2
- rasa/engine/storage/local_model_storage.py +12 -42
- rasa/engine/storage/storage.py +1 -5
- rasa/engine/validation.py +1 -78
- rasa/keys +1 -0
- rasa/model_training.py +13 -16
- rasa/nlu/classifiers/diet_classifier.py +25 -38
- 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 +50 -93
- rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +16 -45
- rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +17 -52
- rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +3 -5
- rasa/server.py +1 -1
- rasa/shared/constants.py +3 -12
- rasa/shared/core/constants.py +4 -0
- rasa/shared/core/domain.py +101 -47
- rasa/shared/core/events.py +29 -0
- rasa/shared/core/flows/flows_list.py +20 -11
- rasa/shared/core/flows/validation.py +25 -0
- rasa/shared/core/flows/yaml_flows_io.py +3 -24
- rasa/shared/importers/importer.py +40 -39
- rasa/shared/importers/multi_project.py +23 -11
- rasa/shared/importers/rasa.py +7 -2
- rasa/shared/importers/remote_importer.py +196 -0
- rasa/shared/importers/utils.py +3 -1
- rasa/shared/nlu/training_data/features.py +2 -120
- rasa/shared/nlu/training_data/training_data.py +18 -19
- rasa/shared/providers/_configs/azure_openai_client_config.py +3 -5
- rasa/shared/providers/embedding/_base_litellm_embedding_client.py +1 -6
- rasa/shared/providers/llm/_base_litellm_client.py +11 -31
- rasa/shared/providers/llm/self_hosted_llm_client.py +3 -15
- rasa/shared/utils/common.py +3 -22
- rasa/shared/utils/io.py +0 -1
- rasa/shared/utils/llm.py +30 -27
- rasa/shared/utils/schemas/events.py +2 -0
- rasa/shared/utils/schemas/model_config.yml +0 -10
- rasa/shared/utils/yaml.py +44 -0
- rasa/studio/auth.py +5 -3
- rasa/studio/config.py +4 -13
- rasa/studio/constants.py +0 -1
- rasa/studio/data_handler.py +3 -10
- rasa/studio/upload.py +8 -17
- rasa/tracing/instrumentation/attribute_extractors.py +1 -1
- rasa/utils/io.py +66 -0
- rasa/utils/tensorflow/model_data.py +193 -2
- rasa/validator.py +0 -12
- rasa/version.py +1 -1
- rasa_pro-3.11.0a1.dist-info/METADATA +576 -0
- {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0a1.dist-info}/RECORD +181 -164
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-1844e5a5.js +0 -1
- rasa/core/channels/inspector/dist/assets/index-a5d3e69d.js +0 -1040
- rasa/utils/tensorflow/feature_array.py +0 -366
- rasa_pro-3.10.16.dist-info/METADATA +0 -196
- /rasa/core/channels/{voice_aware → voice_ready}/__init__.py +0 -0
- /rasa/core/channels/{voice_native → voice_stream}/__init__.py +0 -0
- {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0a1.dist-info}/NOTICE +0 -0
- {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0a1.dist-info}/WHEEL +0 -0
- {rasa_pro-3.10.16.dist-info → rasa_pro-3.11.0a1.dist-info}/entry_points.txt +0 -0
rasa/shared/core/domain.py
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import collections
|
|
2
4
|
import copy
|
|
3
5
|
import json
|
|
4
6
|
import os
|
|
5
7
|
from dataclasses import dataclass
|
|
8
|
+
from functools import cached_property
|
|
6
9
|
from pathlib import Path
|
|
7
10
|
from typing import (
|
|
8
11
|
TYPE_CHECKING,
|
|
9
12
|
Any,
|
|
10
13
|
Callable,
|
|
14
|
+
ClassVar,
|
|
11
15
|
Dict,
|
|
12
16
|
Iterable,
|
|
13
17
|
List,
|
|
18
|
+
MutableMapping,
|
|
14
19
|
NamedTuple,
|
|
15
20
|
NoReturn,
|
|
16
21
|
Optional,
|
|
@@ -19,7 +24,6 @@ from typing import (
|
|
|
19
24
|
Tuple,
|
|
20
25
|
Union,
|
|
21
26
|
cast,
|
|
22
|
-
MutableMapping,
|
|
23
27
|
)
|
|
24
28
|
|
|
25
29
|
import structlog
|
|
@@ -51,11 +55,11 @@ from rasa.shared.core.constants import (
|
|
|
51
55
|
)
|
|
52
56
|
from rasa.shared.core.events import SlotSet, UserUttered
|
|
53
57
|
from rasa.shared.core.slots import (
|
|
54
|
-
Slot,
|
|
55
|
-
CategoricalSlot,
|
|
56
|
-
TextSlot,
|
|
57
58
|
AnySlot,
|
|
59
|
+
CategoricalSlot,
|
|
58
60
|
ListSlot,
|
|
61
|
+
Slot,
|
|
62
|
+
TextSlot,
|
|
59
63
|
)
|
|
60
64
|
from rasa.shared.exceptions import (
|
|
61
65
|
RasaException,
|
|
@@ -63,21 +67,21 @@ from rasa.shared.exceptions import (
|
|
|
63
67
|
YamlSyntaxException,
|
|
64
68
|
)
|
|
65
69
|
from rasa.shared.nlu.constants import (
|
|
66
|
-
|
|
67
|
-
ENTITY_ATTRIBUTE_ROLE,
|
|
70
|
+
ENTITIES,
|
|
68
71
|
ENTITY_ATTRIBUTE_GROUP,
|
|
69
|
-
|
|
72
|
+
ENTITY_ATTRIBUTE_ROLE,
|
|
73
|
+
ENTITY_ATTRIBUTE_TYPE,
|
|
70
74
|
INTENT_NAME_KEY,
|
|
71
|
-
|
|
75
|
+
RESPONSE_IDENTIFIER_DELIMITER,
|
|
72
76
|
)
|
|
73
77
|
from rasa.shared.utils.cli import print_error_and_exit
|
|
74
78
|
from rasa.shared.utils.yaml import (
|
|
75
79
|
KEY_TRAINING_DATA_FORMAT_VERSION,
|
|
80
|
+
dump_obj_as_yaml_to_string,
|
|
76
81
|
read_yaml,
|
|
77
|
-
validate_training_data_format_version,
|
|
78
82
|
read_yaml_file,
|
|
79
|
-
dump_obj_as_yaml_to_string,
|
|
80
83
|
validate_raw_yaml_using_schema_file_with_responses,
|
|
84
|
+
validate_training_data_format_version,
|
|
81
85
|
)
|
|
82
86
|
|
|
83
87
|
if TYPE_CHECKING:
|
|
@@ -155,7 +159,7 @@ class SessionConfig(NamedTuple):
|
|
|
155
159
|
carry_over_slots: bool
|
|
156
160
|
|
|
157
161
|
@staticmethod
|
|
158
|
-
def default() ->
|
|
162
|
+
def default() -> SessionConfig:
|
|
159
163
|
"""Returns the SessionConfig with the default values."""
|
|
160
164
|
return SessionConfig(
|
|
161
165
|
DEFAULT_SESSION_EXPIRATION_TIME_IN_MINUTES,
|
|
@@ -191,13 +195,15 @@ class Domain:
|
|
|
191
195
|
and entities it can recognise.
|
|
192
196
|
"""
|
|
193
197
|
|
|
198
|
+
validate_yaml: ClassVar[bool] = True
|
|
199
|
+
|
|
194
200
|
@classmethod
|
|
195
|
-
def empty(cls) ->
|
|
201
|
+
def empty(cls) -> Domain:
|
|
196
202
|
"""Returns empty Domain."""
|
|
197
203
|
return Domain.from_dict({})
|
|
198
204
|
|
|
199
205
|
@classmethod
|
|
200
|
-
def load(cls, paths: Union[List[Union[Path, Text]], Text, Path]) ->
|
|
206
|
+
def load(cls, paths: Union[List[Union[Path, Text]], Text, Path]) -> Domain:
|
|
201
207
|
"""Returns loaded Domain after merging all domain files."""
|
|
202
208
|
if not paths:
|
|
203
209
|
raise InvalidDomain(
|
|
@@ -215,8 +221,15 @@ class Domain:
|
|
|
215
221
|
return domain
|
|
216
222
|
|
|
217
223
|
@classmethod
|
|
218
|
-
def from_path(cls, path: Union[Text, Path]) ->
|
|
219
|
-
"""Loads the `Domain` from a path.
|
|
224
|
+
def from_path(cls, path: Union[Text, Path]) -> Domain:
|
|
225
|
+
"""Loads the `Domain` from a path.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
path: Path to the domain file.
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
The instantiated `Domain` object.
|
|
232
|
+
"""
|
|
220
233
|
path = os.path.abspath(path)
|
|
221
234
|
|
|
222
235
|
if os.path.isfile(path):
|
|
@@ -232,17 +245,30 @@ class Domain:
|
|
|
232
245
|
return domain
|
|
233
246
|
|
|
234
247
|
@classmethod
|
|
235
|
-
def from_file(cls, path: Text) ->
|
|
236
|
-
"""Loads the `Domain` from a YAML file.
|
|
248
|
+
def from_file(cls, path: Text) -> Domain:
|
|
249
|
+
"""Loads the `Domain` from a YAML file.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
path: Path to the domain file.
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
The instantiated `Domain` object.
|
|
256
|
+
"""
|
|
237
257
|
return cls.from_yaml(rasa.shared.utils.io.read_file(path), path)
|
|
238
258
|
|
|
239
259
|
@classmethod
|
|
240
|
-
def from_yaml(cls, yaml: Text, original_filename: Text = "") ->
|
|
241
|
-
"""Loads the `Domain` from YAML text after validating it.
|
|
242
|
-
|
|
243
|
-
|
|
260
|
+
def from_yaml(cls, yaml: Text, original_filename: Text = "") -> Domain:
|
|
261
|
+
"""Loads the `Domain` from YAML text after validating it.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
yaml: The YAML string to load the domain from.
|
|
265
|
+
original_filename: The filename of the original YAML file.
|
|
244
266
|
|
|
245
|
-
|
|
267
|
+
Returns:
|
|
268
|
+
The instantiated `Domain` object.
|
|
269
|
+
"""
|
|
270
|
+
try:
|
|
271
|
+
data = cls._dict_from_raw_yaml_content(yaml)
|
|
246
272
|
if not validate_training_data_format_version(data, original_filename):
|
|
247
273
|
return Domain.empty()
|
|
248
274
|
return cls.from_dict(data)
|
|
@@ -251,7 +277,7 @@ class Domain:
|
|
|
251
277
|
raise e
|
|
252
278
|
|
|
253
279
|
@classmethod
|
|
254
|
-
def from_dict(cls, data: Dict) ->
|
|
280
|
+
def from_dict(cls, data: Dict) -> Domain:
|
|
255
281
|
"""Deserializes and creates domain.
|
|
256
282
|
|
|
257
283
|
Args:
|
|
@@ -282,8 +308,8 @@ class Domain:
|
|
|
282
308
|
_validate_forms(forms)
|
|
283
309
|
|
|
284
310
|
return cls(
|
|
285
|
-
intents=intents,
|
|
286
|
-
entities=data.get(KEY_ENTITIES,
|
|
311
|
+
intents=intents or [],
|
|
312
|
+
entities=data.get(KEY_ENTITIES, []),
|
|
287
313
|
slots=slots,
|
|
288
314
|
responses=responses,
|
|
289
315
|
action_names=actions,
|
|
@@ -308,8 +334,15 @@ class Domain:
|
|
|
308
334
|
return SessionConfig(session_expiration_time_min, carry_over_slots)
|
|
309
335
|
|
|
310
336
|
@classmethod
|
|
311
|
-
def from_directory(cls, path: Text) ->
|
|
312
|
-
"""Loads and merges multiple domain files recursively from a directory tree.
|
|
337
|
+
def from_directory(cls, path: Text) -> Domain:
|
|
338
|
+
"""Loads and merges multiple domain files recursively from a directory tree.
|
|
339
|
+
|
|
340
|
+
Args:
|
|
341
|
+
path: Path to the root directory.
|
|
342
|
+
|
|
343
|
+
Returns:
|
|
344
|
+
The instantiated `Domain` object.
|
|
345
|
+
"""
|
|
313
346
|
combined: Dict[Text, Any] = {}
|
|
314
347
|
duplicates: List[Dict[Text, List[Text]]] = []
|
|
315
348
|
|
|
@@ -319,10 +352,10 @@ class Domain:
|
|
|
319
352
|
if not Domain.is_domain_file(full_path):
|
|
320
353
|
continue
|
|
321
354
|
|
|
322
|
-
|
|
323
|
-
|
|
355
|
+
other_dict = cls._dict_from_raw_yaml_content(
|
|
356
|
+
rasa.shared.utils.io.read_file(full_path)
|
|
357
|
+
)
|
|
324
358
|
|
|
325
|
-
other_dict = read_yaml(rasa.shared.utils.io.read_file(full_path))
|
|
326
359
|
combined = Domain.merge_domain_dicts(other_dict, combined)
|
|
327
360
|
duplicates.append(combined.pop("duplicates", {}))
|
|
328
361
|
|
|
@@ -368,10 +401,10 @@ class Domain:
|
|
|
368
401
|
|
|
369
402
|
def merge(
|
|
370
403
|
self,
|
|
371
|
-
domain: Optional[
|
|
404
|
+
domain: Optional[Domain],
|
|
372
405
|
override: bool = False,
|
|
373
406
|
ignore_warnings_about_duplicates: bool = False,
|
|
374
|
-
) ->
|
|
407
|
+
) -> Domain:
|
|
375
408
|
"""Merges this domain dict with another one, combining their attributes.
|
|
376
409
|
|
|
377
410
|
This method merges domain dicts, and ensures all attributes (like ``intents``,
|
|
@@ -674,7 +707,7 @@ class Domain:
|
|
|
674
707
|
|
|
675
708
|
return intent
|
|
676
709
|
|
|
677
|
-
@
|
|
710
|
+
@cached_property
|
|
678
711
|
def retrieval_intents(self) -> List[Text]:
|
|
679
712
|
"""List retrieval intents present in the domain."""
|
|
680
713
|
return [
|
|
@@ -899,7 +932,7 @@ class Domain:
|
|
|
899
932
|
self.store_entities_as_slots = store_entities_as_slots
|
|
900
933
|
self._check_domain_sanity()
|
|
901
934
|
|
|
902
|
-
def __deepcopy__(self, memo: Optional[Dict[int, Any]]) ->
|
|
935
|
+
def __deepcopy__(self, memo: Optional[Dict[int, Any]]) -> Domain:
|
|
903
936
|
"""Enables making a deep copy of the `Domain` using `copy.deepcopy`.
|
|
904
937
|
|
|
905
938
|
See https://docs.python.org/3/library/copy.html#copy.deepcopy
|
|
@@ -1003,23 +1036,23 @@ class Domain:
|
|
|
1003
1036
|
sorted_intents = sorted(intents, key=sort)
|
|
1004
1037
|
return sorted_intents
|
|
1005
1038
|
|
|
1006
|
-
@
|
|
1039
|
+
@cached_property
|
|
1007
1040
|
def user_actions_and_forms(self) -> List[Text]:
|
|
1008
1041
|
"""Returns combination of user actions and forms."""
|
|
1009
1042
|
return self.user_actions + self.form_names
|
|
1010
1043
|
|
|
1011
|
-
@
|
|
1044
|
+
@cached_property
|
|
1012
1045
|
def num_actions(self) -> int:
|
|
1013
1046
|
"""Returns the number of available actions."""
|
|
1014
1047
|
# noinspection PyTypeChecker
|
|
1015
1048
|
return len(self.action_names_or_texts)
|
|
1016
1049
|
|
|
1017
|
-
@
|
|
1050
|
+
@cached_property
|
|
1018
1051
|
def num_states(self) -> int:
|
|
1019
1052
|
"""Number of used input states for the action prediction."""
|
|
1020
1053
|
return len(self.input_states)
|
|
1021
1054
|
|
|
1022
|
-
@
|
|
1055
|
+
@cached_property
|
|
1023
1056
|
def retrieval_intent_responses(self) -> Dict[Text, List[Dict[Text, Any]]]:
|
|
1024
1057
|
"""Return only the responses which are defined for retrieval intents."""
|
|
1025
1058
|
return dict(
|
|
@@ -1171,8 +1204,7 @@ class Domain:
|
|
|
1171
1204
|
f"Available actions are: \n{action_names}"
|
|
1172
1205
|
)
|
|
1173
1206
|
|
|
1174
|
-
|
|
1175
|
-
@rasa.shared.utils.common.lazy_property
|
|
1207
|
+
@cached_property
|
|
1176
1208
|
def slot_states(self) -> List[Text]:
|
|
1177
1209
|
"""Returns all available slot state strings."""
|
|
1178
1210
|
return [
|
|
@@ -1181,8 +1213,7 @@ class Domain:
|
|
|
1181
1213
|
for feature_index in range(0, slot.feature_dimensionality())
|
|
1182
1214
|
]
|
|
1183
1215
|
|
|
1184
|
-
|
|
1185
|
-
@rasa.shared.utils.common.lazy_property
|
|
1216
|
+
@cached_property
|
|
1186
1217
|
def entity_states(self) -> List[Text]:
|
|
1187
1218
|
"""Returns all available entity state strings."""
|
|
1188
1219
|
entity_states = copy.deepcopy(self.entities)
|
|
@@ -1230,12 +1261,12 @@ class Domain:
|
|
|
1230
1261
|
for entity_sub_label in entity_sub_labels
|
|
1231
1262
|
]
|
|
1232
1263
|
|
|
1233
|
-
@
|
|
1264
|
+
@cached_property
|
|
1234
1265
|
def input_state_map(self) -> Dict[Text, int]:
|
|
1235
1266
|
"""Provide a mapping from state names to indices."""
|
|
1236
1267
|
return {f: i for i, f in enumerate(self.input_states)}
|
|
1237
1268
|
|
|
1238
|
-
@
|
|
1269
|
+
@cached_property
|
|
1239
1270
|
def input_states(self) -> List[Text]:
|
|
1240
1271
|
"""Returns all available states."""
|
|
1241
1272
|
return (
|
|
@@ -1465,7 +1496,7 @@ class Domain:
|
|
|
1465
1496
|
ignore_rule_only_turns: bool = False,
|
|
1466
1497
|
rule_only_data: Optional[Dict[Text, Any]] = None,
|
|
1467
1498
|
) -> List[State]:
|
|
1468
|
-
"""List of states for each state of the
|
|
1499
|
+
"""List of states for each state of the tracker's history.
|
|
1469
1500
|
|
|
1470
1501
|
Args:
|
|
1471
1502
|
tracker: Dialogue state tracker containing the dialogue so far.
|
|
@@ -1682,12 +1713,12 @@ class Domain:
|
|
|
1682
1713
|
"""Return the configuration for an intent."""
|
|
1683
1714
|
return self.intent_properties.get(intent_name, {})
|
|
1684
1715
|
|
|
1685
|
-
@
|
|
1716
|
+
@cached_property
|
|
1686
1717
|
def intents(self) -> List[Text]:
|
|
1687
1718
|
"""Returns sorted list of intents."""
|
|
1688
1719
|
return sorted(self.intent_properties.keys())
|
|
1689
1720
|
|
|
1690
|
-
@
|
|
1721
|
+
@cached_property
|
|
1691
1722
|
def entities(self) -> List[Text]:
|
|
1692
1723
|
"""Returns sorted list of entities."""
|
|
1693
1724
|
return sorted(self.entity_properties.entities)
|
|
@@ -2055,6 +2086,29 @@ class Domain:
|
|
|
2055
2086
|
def is_custom_action(self, action_name: str) -> bool:
|
|
2056
2087
|
return action_name in self._custom_actions
|
|
2057
2088
|
|
|
2089
|
+
@classmethod
|
|
2090
|
+
def _dict_from_raw_yaml_content(cls, raw_yaml_content: Text) -> Any:
|
|
2091
|
+
"""Loads the Domain dict from raw YAML content.
|
|
2092
|
+
|
|
2093
|
+
Validates the raw YAML content using the schema file if `validate_yaml` is set
|
|
2094
|
+
to `True`.
|
|
2095
|
+
|
|
2096
|
+
Args:
|
|
2097
|
+
raw_yaml_content: The raw YAML content of the domain file.
|
|
2098
|
+
|
|
2099
|
+
Returns:
|
|
2100
|
+
The Domain dict.
|
|
2101
|
+
"""
|
|
2102
|
+
if cls.validate_yaml:
|
|
2103
|
+
structlogger.info(
|
|
2104
|
+
"domain.from_yaml.validating",
|
|
2105
|
+
)
|
|
2106
|
+
validate_raw_yaml_using_schema_file_with_responses(
|
|
2107
|
+
raw_yaml_content, DOMAIN_SCHEMA_FILE
|
|
2108
|
+
)
|
|
2109
|
+
|
|
2110
|
+
return read_yaml(raw_yaml_content)
|
|
2111
|
+
|
|
2058
2112
|
|
|
2059
2113
|
def warn_about_duplicates_found_during_domain_merging(
|
|
2060
2114
|
duplicates: Dict[Text, List[Text]],
|
rasa/shared/core/events.py
CHANGED
|
@@ -2528,3 +2528,32 @@ class FlowCancelled(SkipEventInMDStoryMixin):
|
|
|
2528
2528
|
)
|
|
2529
2529
|
except KeyError as e:
|
|
2530
2530
|
raise ValueError(f"Failed to parse flow_cancelled event. {e}")
|
|
2531
|
+
|
|
2532
|
+
|
|
2533
|
+
class SessionEnded(AlwaysEqualEventMixin):
|
|
2534
|
+
"""Mark the end of a conversation session."""
|
|
2535
|
+
|
|
2536
|
+
type_name = "session_ended"
|
|
2537
|
+
|
|
2538
|
+
def __hash__(self) -> int:
|
|
2539
|
+
"""Returns unique hash for event."""
|
|
2540
|
+
return hash(32143124321)
|
|
2541
|
+
|
|
2542
|
+
def __repr__(self) -> Text:
|
|
2543
|
+
"""Returns event as string for debugging."""
|
|
2544
|
+
return f"SessionEnded(type_name: {self.type_name})"
|
|
2545
|
+
|
|
2546
|
+
def __str__(self) -> Text:
|
|
2547
|
+
"""Returns event as human-readable string."""
|
|
2548
|
+
return f"{self.__class__.__name__}({self.type_name})"
|
|
2549
|
+
|
|
2550
|
+
def as_story_string(self) -> None:
|
|
2551
|
+
"""Skips representing event in stories."""
|
|
2552
|
+
logger.warning(
|
|
2553
|
+
f"'{self.type_name}' events cannot be serialised as story strings."
|
|
2554
|
+
)
|
|
2555
|
+
|
|
2556
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
2557
|
+
"""Applies event to current conversation state."""
|
|
2558
|
+
# noinspection PyProtectedMember
|
|
2559
|
+
tracker._reset()
|
|
@@ -16,6 +16,7 @@ from rasa.shared.core.flows.validation import (
|
|
|
16
16
|
validate_patterns_are_not_called_or_linked,
|
|
17
17
|
validate_patterns_are_not_calling_or_linking_other_flows,
|
|
18
18
|
validate_step_ids_are_unique,
|
|
19
|
+
DuplicatedFlowIdException,
|
|
19
20
|
)
|
|
20
21
|
from rasa.shared.core.slots import Slot
|
|
21
22
|
|
|
@@ -49,21 +50,31 @@ class FlowsList:
|
|
|
49
50
|
return len(self.underlying_flows) == 0
|
|
50
51
|
|
|
51
52
|
@classmethod
|
|
52
|
-
def from_multiple_flows_lists(
|
|
53
|
+
def from_multiple_flows_lists(
|
|
54
|
+
cls, *other: FlowsList, ignore_duplicates: bool = True
|
|
55
|
+
) -> FlowsList:
|
|
53
56
|
"""Merges multiple lists of flows into a single flow ensuring each flow is
|
|
54
57
|
unique, based on its ID.
|
|
55
58
|
|
|
56
59
|
Args:
|
|
57
60
|
other: Variable number of flow lists instances to be merged.
|
|
61
|
+
ignore_duplicates: Whether to ignore duplicate flow ids, or raise an error.
|
|
58
62
|
|
|
59
63
|
Returns:
|
|
60
64
|
Merged flow list.
|
|
61
65
|
"""
|
|
62
|
-
merged_flows = dict()
|
|
66
|
+
merged_flows: Dict[Text, Flow] = dict()
|
|
63
67
|
for flow_list in other:
|
|
64
68
|
for flow in flow_list:
|
|
65
|
-
if flow.id
|
|
66
|
-
|
|
69
|
+
if flow.id in merged_flows:
|
|
70
|
+
if ignore_duplicates:
|
|
71
|
+
continue
|
|
72
|
+
current_flow_path = flow.file_path
|
|
73
|
+
other_flow_path = merged_flows[flow.id].file_path
|
|
74
|
+
raise DuplicatedFlowIdException(
|
|
75
|
+
flow.id, current_flow_path, other_flow_path
|
|
76
|
+
)
|
|
77
|
+
merged_flows[flow.id] = flow
|
|
67
78
|
return FlowsList(list(merged_flows.values()))
|
|
68
79
|
|
|
69
80
|
@classmethod
|
|
@@ -118,9 +129,11 @@ class FlowsList:
|
|
|
118
129
|
flow_dicts = [flow.as_json() for flow in self.underlying_flows]
|
|
119
130
|
return rasa.shared.utils.io.get_list_fingerprint(flow_dicts)
|
|
120
131
|
|
|
121
|
-
def merge(self, other: FlowsList) -> FlowsList:
|
|
132
|
+
def merge(self, other: FlowsList, ignore_duplicates: bool = True) -> FlowsList:
|
|
122
133
|
"""Merges two lists of flows together."""
|
|
123
|
-
return FlowsList.from_multiple_flows_lists(
|
|
134
|
+
return FlowsList.from_multiple_flows_lists(
|
|
135
|
+
self, other, ignore_duplicates=ignore_duplicates
|
|
136
|
+
)
|
|
124
137
|
|
|
125
138
|
def flow_by_id(self, flow_id: Text) -> Optional[Flow]:
|
|
126
139
|
"""Return the flow with the given id."""
|
|
@@ -221,16 +234,12 @@ class FlowsList:
|
|
|
221
234
|
[f for f in self.underlying_flows if not f.is_startable_only_via_link()]
|
|
222
235
|
)
|
|
223
236
|
|
|
224
|
-
def available_slot_names(
|
|
225
|
-
self, ask_before_filling: Optional[bool] = None
|
|
226
|
-
) -> Set[str]:
|
|
237
|
+
def available_slot_names(self) -> Set[str]:
|
|
227
238
|
"""Get all slot names collected by flows."""
|
|
228
239
|
return {
|
|
229
240
|
step.collect
|
|
230
241
|
for flow in self.underlying_flows
|
|
231
242
|
for step in flow.get_collect_steps()
|
|
232
|
-
if ask_before_filling is None
|
|
233
|
-
or step.ask_before_filling == ask_before_filling
|
|
234
243
|
}
|
|
235
244
|
|
|
236
245
|
def available_custom_actions(self) -> Set[str]:
|
|
@@ -101,6 +101,31 @@ class DuplicatedStepIdException(RasaException):
|
|
|
101
101
|
)
|
|
102
102
|
|
|
103
103
|
|
|
104
|
+
class DuplicatedFlowIdException(RasaException):
|
|
105
|
+
"""Raised when a flow is using the same id as another flow."""
|
|
106
|
+
|
|
107
|
+
def __init__(
|
|
108
|
+
self, flow_id: str, first_file_path: str, second_file_path: str
|
|
109
|
+
) -> None:
|
|
110
|
+
"""Initializes the exception."""
|
|
111
|
+
self.flow_id = flow_id
|
|
112
|
+
self.first_file_path = first_file_path
|
|
113
|
+
self.second_file_path = second_file_path
|
|
114
|
+
|
|
115
|
+
def __str__(self) -> str:
|
|
116
|
+
"""Return a string representation of the exception."""
|
|
117
|
+
if self.first_file_path == self.second_file_path:
|
|
118
|
+
return (
|
|
119
|
+
f"Flow '{self.flow_id}' is used twice in `{self.first_file_path}`. "
|
|
120
|
+
f"Please make sure flow IDs are unique across all files."
|
|
121
|
+
)
|
|
122
|
+
return (
|
|
123
|
+
f"Flow '{self.flow_id}' is used in both "
|
|
124
|
+
f"`{self.first_file_path}` and `{self.second_file_path}`. "
|
|
125
|
+
f"Please make sure flow IDs are unique across all files."
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
104
129
|
class MissingElseBranchException(RasaException):
|
|
105
130
|
"""Raised when a flow step is missing an else branch."""
|
|
106
131
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import textwrap
|
|
2
1
|
from pathlib import Path
|
|
3
|
-
from typing import Any, Dict, List, Text, Union
|
|
2
|
+
from typing import Any, Dict, List, Optional, Text, Union
|
|
4
3
|
|
|
5
4
|
import jsonschema
|
|
6
5
|
import ruamel.yaml.nodes as yaml_nodes
|
|
@@ -12,12 +11,11 @@ import rasa.shared.utils.io
|
|
|
12
11
|
from rasa.shared.core.flows.flow import Flow
|
|
13
12
|
from rasa.shared.core.flows.flows_list import FlowsList
|
|
14
13
|
from rasa.shared.exceptions import RasaException, YamlException
|
|
15
|
-
from rasa.shared.importers.importer import FlowSyncImporter
|
|
16
14
|
from rasa.shared.utils.yaml import (
|
|
17
|
-
validate_yaml_with_jsonschema,
|
|
18
|
-
read_yaml,
|
|
19
15
|
dump_obj_as_yaml_to_string,
|
|
20
16
|
is_key_in_yaml,
|
|
17
|
+
read_yaml,
|
|
18
|
+
validate_yaml_with_jsonschema,
|
|
21
19
|
)
|
|
22
20
|
|
|
23
21
|
FLOWS_SCHEMA_FILE = "shared/core/flows/flows_yaml_schema.json"
|
|
@@ -262,25 +260,6 @@ class YamlFlowsWriter:
|
|
|
262
260
|
rasa.shared.utils.io.write_text_file(YamlFlowsWriter.dumps(flows), filename)
|
|
263
261
|
|
|
264
262
|
|
|
265
|
-
def flows_from_str(yaml_str: str) -> FlowsList:
|
|
266
|
-
"""Reads flows from a YAML string."""
|
|
267
|
-
flows = YAMLFlowsReader.read_from_string(
|
|
268
|
-
textwrap.dedent(yaml_str), add_line_numbers=False
|
|
269
|
-
)
|
|
270
|
-
flows.validate()
|
|
271
|
-
return flows
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
def flows_from_str_including_defaults(yaml_str: str) -> FlowsList:
|
|
275
|
-
"""Reads flows from a YAML string and combine them with default flows."""
|
|
276
|
-
flows = YAMLFlowsReader.read_from_string(
|
|
277
|
-
textwrap.dedent(yaml_str), add_line_numbers=False
|
|
278
|
-
)
|
|
279
|
-
all_flows = FlowSyncImporter.merge_with_default_flows(flows)
|
|
280
|
-
all_flows.validate()
|
|
281
|
-
return all_flows
|
|
282
|
-
|
|
283
|
-
|
|
284
263
|
def is_flows_file(file_path: Union[Text, Path]) -> bool:
|
|
285
264
|
"""Check if file contains Flow training data.
|
|
286
265
|
|