rasa-pro 3.12.0.dev11__py3-none-any.whl → 3.12.0.dev12__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.
- rasa/cli/inspect.py +1 -20
- rasa/cli/shell.py +3 -3
- rasa/core/actions/action.py +7 -20
- rasa/core/actions/forms.py +5 -10
- rasa/core/channels/__init__.py +0 -2
- rasa/core/channels/voice_ready/audiocodes.py +23 -42
- rasa/core/channels/voice_stream/browser_audio.py +0 -1
- rasa/core/channels/voice_stream/call_state.py +1 -7
- rasa/core/channels/voice_stream/tts/azure.py +1 -2
- rasa/core/channels/voice_stream/tts/cartesia.py +3 -16
- rasa/core/channels/voice_stream/twilio_media_streams.py +1 -2
- rasa/core/channels/voice_stream/voice_channel.py +1 -2
- rasa/core/migrate.py +2 -2
- rasa/core/policies/flows/flow_executor.py +42 -36
- rasa/core/run.py +3 -4
- rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -2
- rasa/dialogue_understanding/commands/cancel_flow_command.py +4 -62
- rasa/dialogue_understanding/commands/change_flow_command.py +2 -2
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -2
- rasa/dialogue_understanding/commands/clarify_command.py +2 -2
- rasa/dialogue_understanding/commands/correct_slots_command.py +2 -11
- rasa/dialogue_understanding/commands/human_handoff_command.py +2 -2
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -2
- rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +2 -2
- rasa/dialogue_understanding/commands/set_slot_command.py +15 -7
- rasa/dialogue_understanding/commands/skip_question_command.py +2 -2
- rasa/dialogue_understanding/commands/start_flow_command.py +2 -43
- rasa/dialogue_understanding/commands/utils.py +1 -1
- rasa/dialogue_understanding/constants.py +0 -1
- rasa/dialogue_understanding/generator/command_generator.py +73 -110
- rasa/dialogue_understanding/generator/command_parser.py +1 -1
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +3 -161
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +2 -10
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +3 -44
- rasa/dialogue_understanding/generator/single_step/command_prompt_template.jinja2 +79 -53
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +19 -11
- rasa/dialogue_understanding/generator/utils.py +1 -32
- rasa/dialogue_understanding/patterns/correction.py +1 -13
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +2 -62
- rasa/dialogue_understanding/processor/command_processor.py +28 -115
- rasa/dialogue_understanding/utils.py +0 -31
- rasa/dialogue_understanding_test/README.md +0 -50
- rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +3 -3
- rasa/model_service.py +0 -4
- rasa/model_training.py +27 -24
- rasa/shared/core/constants.py +3 -28
- rasa/shared/core/domain.py +20 -13
- rasa/shared/core/events.py +2 -13
- rasa/shared/core/flows/flow.py +0 -17
- rasa/shared/core/flows/flows_yaml_schema.json +0 -38
- rasa/shared/core/flows/steps/collect.py +1 -18
- rasa/shared/core/flows/utils.py +1 -16
- rasa/shared/core/slot_mappings.py +108 -144
- rasa/shared/core/slots.py +2 -23
- rasa/shared/core/trackers.py +1 -3
- rasa/shared/nlu/constants.py +0 -1
- rasa/shared/utils/llm.py +1 -1
- rasa/shared/utils/schemas/domain.yml +1 -0
- rasa/telemetry.py +13 -43
- rasa/utils/common.py +1 -0
- rasa/validator.py +82 -189
- rasa/version.py +1 -1
- {rasa_pro-3.12.0.dev11.dist-info → rasa_pro-3.12.0.dev12.dist-info}/METADATA +1 -1
- {rasa_pro-3.12.0.dev11.dist-info → rasa_pro-3.12.0.dev12.dist-info}/RECORD +67 -71
- rasa/core/actions/action_handle_digressions.py +0 -142
- rasa/core/channels/voice_stream/genesys.py +0 -331
- rasa/dialogue_understanding/commands/handle_digressions_command.py +0 -150
- rasa/dialogue_understanding/patterns/handle_digressions.py +0 -81
- {rasa_pro-3.12.0.dev11.dist-info → rasa_pro-3.12.0.dev12.dist-info}/NOTICE +0 -0
- {rasa_pro-3.12.0.dev11.dist-info → rasa_pro-3.12.0.dev12.dist-info}/WHEEL +0 -0
- {rasa_pro-3.12.0.dev11.dist-info → rasa_pro-3.12.0.dev12.dist-info}/entry_points.txt +0 -0
|
@@ -1,20 +1,15 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import copy
|
|
4
1
|
import logging
|
|
5
|
-
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Text, Tuple,
|
|
6
|
-
|
|
7
|
-
from pydantic import BaseModel, Field
|
|
2
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Text, Tuple, cast
|
|
8
3
|
|
|
9
4
|
import rasa.shared.utils.io
|
|
10
5
|
from rasa.shared.constants import DOCS_URL_NLU_BASED_SLOTS, IGNORED_INTENTS
|
|
11
6
|
from rasa.shared.core.constants import (
|
|
7
|
+
ACTIVE_FLOW,
|
|
12
8
|
ACTIVE_LOOP,
|
|
13
|
-
KEY_ACTION,
|
|
14
|
-
KEY_MAPPING_TYPE,
|
|
15
|
-
KEY_RUN_ACTION_EVERY_TURN,
|
|
16
9
|
MAPPING_CONDITIONS,
|
|
10
|
+
MAPPING_TYPE,
|
|
17
11
|
REQUESTED_SLOT,
|
|
12
|
+
SLOT_MAPPINGS,
|
|
18
13
|
SlotMappingType,
|
|
19
14
|
)
|
|
20
15
|
from rasa.shared.core.slots import ListSlot, Slot
|
|
@@ -26,6 +21,7 @@ from rasa.shared.nlu.constants import (
|
|
|
26
21
|
ENTITY_ATTRIBUTE_VALUE,
|
|
27
22
|
INTENT,
|
|
28
23
|
INTENT_NAME_KEY,
|
|
24
|
+
NOT_INTENT,
|
|
29
25
|
TEXT,
|
|
30
26
|
)
|
|
31
27
|
|
|
@@ -39,81 +35,11 @@ if TYPE_CHECKING:
|
|
|
39
35
|
logger = logging.getLogger(__name__)
|
|
40
36
|
|
|
41
37
|
|
|
42
|
-
class
|
|
43
|
-
"""Defines a condition for a slot mapping."""
|
|
44
|
-
|
|
45
|
-
active_loop: Optional[str]
|
|
46
|
-
requested_slot: Optional[str] = None
|
|
47
|
-
active_flow: Optional[str] = None
|
|
48
|
-
|
|
49
|
-
@staticmethod
|
|
50
|
-
def from_dict(data: Dict[str, Any]) -> SlotMappingCondition:
|
|
51
|
-
# we allow None as a valid value for active_loop
|
|
52
|
-
# therefore we need to set a different default value
|
|
53
|
-
active_loop = data.pop(ACTIVE_LOOP, "")
|
|
54
|
-
|
|
55
|
-
return SlotMappingCondition(active_loop=active_loop, **data)
|
|
56
|
-
|
|
57
|
-
def as_dict(self) -> Dict[str, Any]:
|
|
58
|
-
return self.model_dump(exclude_none=True)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
class SlotMapping(BaseModel):
|
|
38
|
+
class SlotMapping:
|
|
62
39
|
"""Defines functionality for the available slot mappings."""
|
|
63
40
|
|
|
64
|
-
type: SlotMappingType
|
|
65
|
-
conditions: List[SlotMappingCondition] = Field(default_factory=list)
|
|
66
|
-
entity: Optional[str] = None
|
|
67
|
-
intent: Optional[Union[str, List[str]]] = None
|
|
68
|
-
role: Optional[str] = None
|
|
69
|
-
group: Optional[str] = None
|
|
70
|
-
not_intent: Optional[Union[str, List[str]]] = None
|
|
71
|
-
value: Optional[Any] = None
|
|
72
|
-
allow_nlu_correction: Optional[bool] = None
|
|
73
|
-
run_action_every_turn: Optional[str] = None
|
|
74
|
-
|
|
75
|
-
@staticmethod
|
|
76
|
-
def from_dict(data: Dict[str, Any], slot_name: str) -> SlotMapping:
|
|
77
|
-
data_copy = copy.deepcopy(data)
|
|
78
|
-
mapping_type = SlotMapping.validate_mapping(data_copy, slot_name)
|
|
79
|
-
conditions = [
|
|
80
|
-
SlotMappingCondition.from_dict(condition)
|
|
81
|
-
for condition in data_copy.pop(MAPPING_CONDITIONS, [])
|
|
82
|
-
]
|
|
83
|
-
|
|
84
|
-
deprecated_action = data_copy.pop(KEY_ACTION, None)
|
|
85
|
-
if deprecated_action:
|
|
86
|
-
rasa.shared.utils.io.raise_deprecation_warning(
|
|
87
|
-
f"The `{KEY_ACTION}` key in slot mappings is deprecated and "
|
|
88
|
-
f"will be removed in Rasa Pro 4.0.0. "
|
|
89
|
-
f"Please use the `{KEY_RUN_ACTION_EVERY_TURN}` key instead.",
|
|
90
|
-
)
|
|
91
|
-
data_copy[KEY_RUN_ACTION_EVERY_TURN] = deprecated_action
|
|
92
|
-
|
|
93
|
-
run_action_every_turn = data_copy.pop(KEY_RUN_ACTION_EVERY_TURN, None)
|
|
94
|
-
|
|
95
|
-
return SlotMapping(
|
|
96
|
-
type=mapping_type,
|
|
97
|
-
conditions=conditions,
|
|
98
|
-
run_action_every_turn=run_action_every_turn,
|
|
99
|
-
**data_copy,
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
def as_dict(self) -> Dict[str, Any]:
|
|
103
|
-
data = self.model_dump(mode="json", exclude_none=True)
|
|
104
|
-
data[KEY_MAPPING_TYPE] = self.type.value
|
|
105
|
-
|
|
106
|
-
if self.conditions:
|
|
107
|
-
data[MAPPING_CONDITIONS] = [
|
|
108
|
-
condition.as_dict() for condition in self.conditions
|
|
109
|
-
]
|
|
110
|
-
else:
|
|
111
|
-
data.pop(MAPPING_CONDITIONS, None)
|
|
112
|
-
|
|
113
|
-
return data
|
|
114
|
-
|
|
115
41
|
@staticmethod
|
|
116
|
-
def
|
|
42
|
+
def validate(mapping: Dict[Text, Any], slot_name: Text) -> None:
|
|
117
43
|
"""Validates a slot mapping.
|
|
118
44
|
|
|
119
45
|
Args:
|
|
@@ -132,22 +58,12 @@ class SlotMapping(BaseModel):
|
|
|
132
58
|
f"{DOCS_URL_NLU_BASED_SLOTS} for more information."
|
|
133
59
|
)
|
|
134
60
|
|
|
135
|
-
mapping_raw = mapping.pop(KEY_MAPPING_TYPE, SlotMappingType.FROM_LLM.value)
|
|
136
|
-
|
|
137
|
-
if mapping_raw == "custom":
|
|
138
|
-
rasa.shared.utils.io.raise_deprecation_warning(
|
|
139
|
-
"The `custom` slot mapping type is deprecated and "
|
|
140
|
-
"will be removed in Rasa Pro 4.0.0. "
|
|
141
|
-
"Please use the `controlled` slot mapping type instead.",
|
|
142
|
-
)
|
|
143
|
-
mapping_raw = "controlled"
|
|
144
|
-
|
|
145
61
|
try:
|
|
146
|
-
mapping_type = SlotMappingType(
|
|
62
|
+
mapping_type = SlotMappingType(mapping.get(MAPPING_TYPE))
|
|
147
63
|
except ValueError:
|
|
148
64
|
raise InvalidDomain(
|
|
149
65
|
f"Your domain uses an invalid slot mapping of type "
|
|
150
|
-
f"'{
|
|
66
|
+
f"'{mapping.get(MAPPING_TYPE)}' for slot '{slot_name}'. Please see "
|
|
151
67
|
f"{DOCS_URL_NLU_BASED_SLOTS} for more information."
|
|
152
68
|
)
|
|
153
69
|
|
|
@@ -156,7 +72,7 @@ class SlotMapping(BaseModel):
|
|
|
156
72
|
SlotMappingType.FROM_INTENT: ["value"],
|
|
157
73
|
SlotMappingType.FROM_TRIGGER_INTENT: ["value"],
|
|
158
74
|
SlotMappingType.FROM_TEXT: [],
|
|
159
|
-
SlotMappingType.
|
|
75
|
+
SlotMappingType.CUSTOM: [],
|
|
160
76
|
SlotMappingType.FROM_LLM: [],
|
|
161
77
|
}
|
|
162
78
|
|
|
@@ -170,18 +86,19 @@ class SlotMapping(BaseModel):
|
|
|
170
86
|
f"{DOCS_URL_NLU_BASED_SLOTS} for more information."
|
|
171
87
|
)
|
|
172
88
|
|
|
173
|
-
|
|
174
|
-
|
|
89
|
+
@staticmethod
|
|
175
90
|
def _get_active_loop_ignored_intents(
|
|
176
|
-
|
|
91
|
+
mapping: Dict[Text, Any], domain: "Domain", active_loop_name: Text
|
|
177
92
|
) -> List[Text]:
|
|
178
|
-
|
|
93
|
+
from rasa.shared.core.constants import ACTIVE_LOOP
|
|
94
|
+
|
|
95
|
+
mapping_conditions = mapping.get(MAPPING_CONDITIONS)
|
|
179
96
|
active_loop_match = True
|
|
180
97
|
ignored_intents = []
|
|
181
98
|
|
|
182
99
|
if mapping_conditions:
|
|
183
100
|
match_list = [
|
|
184
|
-
condition.
|
|
101
|
+
condition.get(ACTIVE_LOOP) == active_loop_name
|
|
185
102
|
for condition in mapping_conditions
|
|
186
103
|
]
|
|
187
104
|
active_loop_match = any(match_list)
|
|
@@ -194,21 +111,24 @@ class SlotMapping(BaseModel):
|
|
|
194
111
|
|
|
195
112
|
return ignored_intents
|
|
196
113
|
|
|
114
|
+
@staticmethod
|
|
197
115
|
def intent_is_desired(
|
|
198
|
-
|
|
116
|
+
mapping: Dict[Text, Any],
|
|
199
117
|
tracker: "DialogueStateTracker",
|
|
200
118
|
domain: "Domain",
|
|
201
119
|
message: Optional["Message"] = None,
|
|
202
120
|
) -> bool:
|
|
203
121
|
"""Checks whether user intent matches slot mapping intent specifications."""
|
|
204
|
-
mapping_intents = SlotMapping.to_list(
|
|
205
|
-
mapping_not_intents = SlotMapping.to_list(
|
|
122
|
+
mapping_intents = SlotMapping.to_list(mapping.get(INTENT, []))
|
|
123
|
+
mapping_not_intents = SlotMapping.to_list(mapping.get(NOT_INTENT, []))
|
|
206
124
|
|
|
207
125
|
active_loop_name = tracker.active_loop_name
|
|
208
126
|
if active_loop_name:
|
|
209
127
|
mapping_not_intents = (
|
|
210
128
|
mapping_not_intents
|
|
211
|
-
+
|
|
129
|
+
+ SlotMapping._get_active_loop_ignored_intents(
|
|
130
|
+
mapping, domain, active_loop_name
|
|
131
|
+
)
|
|
212
132
|
)
|
|
213
133
|
|
|
214
134
|
if message is not None:
|
|
@@ -235,14 +155,16 @@ class SlotMapping(BaseModel):
|
|
|
235
155
|
|
|
236
156
|
return x
|
|
237
157
|
|
|
158
|
+
@staticmethod
|
|
238
159
|
def entity_is_desired(
|
|
239
|
-
|
|
160
|
+
mapping: Dict[Text, Any],
|
|
240
161
|
tracker: "DialogueStateTracker",
|
|
241
162
|
message: Optional["Message"] = None,
|
|
242
163
|
) -> List[str]:
|
|
243
164
|
"""Checks whether slot should be filled by an entity in the input or not.
|
|
244
165
|
|
|
245
166
|
Args:
|
|
167
|
+
mapping: Slot mapping.
|
|
246
168
|
tracker: The tracker.
|
|
247
169
|
message: The message being processed.
|
|
248
170
|
|
|
@@ -254,16 +176,19 @@ class SlotMapping(BaseModel):
|
|
|
254
176
|
matching_values = [
|
|
255
177
|
cast(Text, entity[ENTITY_ATTRIBUTE_VALUE])
|
|
256
178
|
for entity in extracted_entities
|
|
257
|
-
if entity.get(ENTITY_ATTRIBUTE_TYPE)
|
|
258
|
-
|
|
259
|
-
and entity.get(
|
|
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)
|
|
260
185
|
]
|
|
261
186
|
elif tracker.latest_message and tracker.latest_message.text is not None:
|
|
262
187
|
matching_values = list(
|
|
263
188
|
tracker.get_latest_entity_values(
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
189
|
+
mapping.get(ENTITY_ATTRIBUTE_TYPE),
|
|
190
|
+
mapping.get(ENTITY_ATTRIBUTE_ROLE),
|
|
191
|
+
mapping.get(ENTITY_ATTRIBUTE_GROUP),
|
|
267
192
|
)
|
|
268
193
|
)
|
|
269
194
|
else:
|
|
@@ -271,38 +196,45 @@ class SlotMapping(BaseModel):
|
|
|
271
196
|
|
|
272
197
|
return matching_values
|
|
273
198
|
|
|
199
|
+
@staticmethod
|
|
274
200
|
def check_mapping_validity(
|
|
275
|
-
self,
|
|
276
201
|
slot_name: Text,
|
|
202
|
+
mapping_type: SlotMappingType,
|
|
203
|
+
mapping: Dict[Text, Any],
|
|
277
204
|
domain: "Domain",
|
|
278
205
|
) -> bool:
|
|
279
206
|
"""Checks the mapping for validity.
|
|
280
207
|
|
|
281
208
|
Args:
|
|
282
209
|
slot_name: The name of the slot to be validated.
|
|
210
|
+
mapping_type: The type of the slot mapping.
|
|
211
|
+
mapping: Slot mapping.
|
|
283
212
|
domain: The domain to check against.
|
|
284
213
|
|
|
285
214
|
Returns:
|
|
286
215
|
True, if intent and entity specified in a mapping exist in domain.
|
|
287
216
|
"""
|
|
288
217
|
if (
|
|
289
|
-
|
|
290
|
-
and
|
|
218
|
+
mapping_type == SlotMappingType.FROM_ENTITY
|
|
219
|
+
and mapping.get(ENTITY_ATTRIBUTE_TYPE) not in domain.entities
|
|
291
220
|
):
|
|
292
221
|
rasa.shared.utils.io.raise_warning(
|
|
293
222
|
f"Slot '{slot_name}' uses a 'from_entity' mapping "
|
|
294
|
-
f"for a non-existent entity '{
|
|
223
|
+
f"for a non-existent entity '{mapping.get(ENTITY_ATTRIBUTE_TYPE)}'. "
|
|
295
224
|
f"Skipping slot extraction because of invalid mapping."
|
|
296
225
|
)
|
|
297
226
|
return False
|
|
298
227
|
|
|
299
|
-
if
|
|
300
|
-
|
|
228
|
+
if (
|
|
229
|
+
mapping_type == SlotMappingType.FROM_INTENT
|
|
230
|
+
and mapping.get(INTENT) is not None
|
|
231
|
+
):
|
|
232
|
+
intent_list = SlotMapping.to_list(mapping.get(INTENT))
|
|
301
233
|
for intent in intent_list:
|
|
302
234
|
if intent and intent not in domain.intents:
|
|
303
235
|
rasa.shared.utils.io.raise_warning(
|
|
304
236
|
f"Slot '{slot_name}' uses a 'from_intent' mapping for "
|
|
305
|
-
f"a non-existent intent '{intent}'. "
|
|
237
|
+
f"a non-existent intent '{mapping.get('intent')}'. "
|
|
306
238
|
f"Skipping slot extraction because of invalid mapping."
|
|
307
239
|
)
|
|
308
240
|
return False
|
|
@@ -310,6 +242,22 @@ class SlotMapping(BaseModel):
|
|
|
310
242
|
return True
|
|
311
243
|
|
|
312
244
|
|
|
245
|
+
def validate_slot_mappings(domain_slots: Dict[Text, Any]) -> None:
|
|
246
|
+
"""Raises InvalidDomain exception if slot mappings are invalid."""
|
|
247
|
+
rasa.shared.utils.io.raise_warning(
|
|
248
|
+
f"Slot auto-fill has been removed in 3.0 and replaced with a "
|
|
249
|
+
f"new explicit mechanism to set slots. "
|
|
250
|
+
f"Please refer to {DOCS_URL_NLU_BASED_SLOTS} to learn more.",
|
|
251
|
+
UserWarning,
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
for slot_name, properties in domain_slots.items():
|
|
255
|
+
mappings = properties.get(SLOT_MAPPINGS, [])
|
|
256
|
+
|
|
257
|
+
for slot_mapping in mappings:
|
|
258
|
+
SlotMapping.validate(slot_mapping, slot_name)
|
|
259
|
+
|
|
260
|
+
|
|
313
261
|
class SlotFillingManager:
|
|
314
262
|
"""Manages slot filling based on conversation context."""
|
|
315
263
|
|
|
@@ -328,34 +276,41 @@ class SlotFillingManager:
|
|
|
328
276
|
def is_slot_mapping_valid(
|
|
329
277
|
self,
|
|
330
278
|
slot_name: str,
|
|
331
|
-
|
|
279
|
+
mapping_type: SlotMappingType,
|
|
280
|
+
mapping: Dict[str, Any],
|
|
332
281
|
) -> bool:
|
|
333
282
|
"""Check if a slot mapping is valid."""
|
|
334
|
-
return
|
|
283
|
+
return SlotMapping.check_mapping_validity(
|
|
335
284
|
slot_name=slot_name,
|
|
285
|
+
mapping_type=mapping_type,
|
|
286
|
+
mapping=mapping,
|
|
336
287
|
domain=self.domain,
|
|
337
288
|
)
|
|
338
289
|
|
|
339
|
-
def is_intent_desired(self, mapping:
|
|
290
|
+
def is_intent_desired(self, mapping: Dict[str, Any]) -> bool:
|
|
340
291
|
"""Check if the intent matches the one indicated in the slot mapping."""
|
|
341
|
-
return
|
|
292
|
+
return SlotMapping.intent_is_desired(
|
|
293
|
+
mapping=mapping,
|
|
342
294
|
tracker=self.tracker,
|
|
343
295
|
domain=self.domain,
|
|
344
296
|
message=self.message,
|
|
345
297
|
)
|
|
346
298
|
|
|
347
|
-
def _verify_mapping_conditions(
|
|
348
|
-
|
|
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(
|
|
349
303
|
SlotMappingType.FROM_TRIGGER_INTENT
|
|
350
304
|
):
|
|
351
|
-
|
|
305
|
+
if not self._matches_mapping_conditions(mapping, slot_name):
|
|
306
|
+
return False
|
|
352
307
|
|
|
353
308
|
return True
|
|
354
309
|
|
|
355
310
|
def _matches_mapping_conditions(
|
|
356
|
-
self, mapping:
|
|
311
|
+
self, mapping: Dict[Text, Any], slot_name: Text
|
|
357
312
|
) -> bool:
|
|
358
|
-
slot_mapping_conditions = mapping.
|
|
313
|
+
slot_mapping_conditions = mapping.get(MAPPING_CONDITIONS)
|
|
359
314
|
|
|
360
315
|
if not slot_mapping_conditions:
|
|
361
316
|
return True
|
|
@@ -373,20 +328,20 @@ class SlotFillingManager:
|
|
|
373
328
|
@staticmethod
|
|
374
329
|
def _mapping_conditions_match_flow(
|
|
375
330
|
active_flow: str,
|
|
376
|
-
slot_mapping_conditions: List[
|
|
331
|
+
slot_mapping_conditions: List[Dict[str, str]],
|
|
377
332
|
) -> bool:
|
|
378
333
|
active_flow_conditions = list(
|
|
379
|
-
filter(lambda x: x.
|
|
334
|
+
filter(lambda x: x.get(ACTIVE_FLOW) is not None, slot_mapping_conditions)
|
|
380
335
|
)
|
|
381
336
|
return any(
|
|
382
337
|
[
|
|
383
|
-
condition.
|
|
338
|
+
condition.get(ACTIVE_FLOW) == active_flow
|
|
384
339
|
for condition in active_flow_conditions
|
|
385
340
|
]
|
|
386
341
|
)
|
|
387
342
|
|
|
388
343
|
def _mapping_conditions_match_form(
|
|
389
|
-
self, slot_name: str, slot_mapping_conditions: List[
|
|
344
|
+
self, slot_name: str, slot_mapping_conditions: List[Dict[str, str]]
|
|
390
345
|
) -> bool:
|
|
391
346
|
if (
|
|
392
347
|
self.tracker.is_active_loop_rejected
|
|
@@ -396,10 +351,12 @@ class SlotFillingManager:
|
|
|
396
351
|
|
|
397
352
|
# check if found mapping conditions matches form
|
|
398
353
|
for condition in slot_mapping_conditions:
|
|
399
|
-
|
|
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, "")
|
|
400
357
|
|
|
401
358
|
if active_loop and active_loop == self.tracker.active_loop_name:
|
|
402
|
-
condition_requested_slot = condition.
|
|
359
|
+
condition_requested_slot = condition.get(REQUESTED_SLOT)
|
|
403
360
|
if not condition_requested_slot:
|
|
404
361
|
return True
|
|
405
362
|
if condition_requested_slot == self.tracker.get_slot(REQUESTED_SLOT):
|
|
@@ -413,11 +370,11 @@ class SlotFillingManager:
|
|
|
413
370
|
def _fails_unique_entity_mapping_check(
|
|
414
371
|
self,
|
|
415
372
|
slot_name: Text,
|
|
416
|
-
mapping:
|
|
373
|
+
mapping: Dict[Text, Any],
|
|
417
374
|
) -> bool:
|
|
418
375
|
from rasa.core.actions.forms import FormAction
|
|
419
376
|
|
|
420
|
-
if mapping
|
|
377
|
+
if mapping[MAPPING_TYPE] != str(SlotMappingType.FROM_ENTITY):
|
|
421
378
|
return False
|
|
422
379
|
|
|
423
380
|
form_name = self.tracker.active_loop_name
|
|
@@ -438,9 +395,12 @@ class SlotFillingManager:
|
|
|
438
395
|
|
|
439
396
|
return True
|
|
440
397
|
|
|
441
|
-
def _is_trigger_intent_mapping_condition_met(
|
|
398
|
+
def _is_trigger_intent_mapping_condition_met(
|
|
399
|
+
self, mapping: Dict[Text, Any]
|
|
400
|
+
) -> bool:
|
|
442
401
|
active_loops_in_mapping_conditions = [
|
|
443
|
-
condition.
|
|
402
|
+
condition.get(ACTIVE_LOOP)
|
|
403
|
+
for condition in mapping.get(MAPPING_CONDITIONS, [])
|
|
444
404
|
]
|
|
445
405
|
|
|
446
406
|
trigger_mapping_condition_met = True
|
|
@@ -461,7 +421,7 @@ class SlotFillingManager:
|
|
|
461
421
|
def extract_slot_value_from_predefined_mapping(
|
|
462
422
|
self,
|
|
463
423
|
mapping_type: SlotMappingType,
|
|
464
|
-
mapping:
|
|
424
|
+
mapping: Dict[Text, Any],
|
|
465
425
|
) -> List[Any]:
|
|
466
426
|
"""Extracts slot value if slot has an applicable predefined mapping."""
|
|
467
427
|
if (
|
|
@@ -494,9 +454,9 @@ class SlotFillingManager:
|
|
|
494
454
|
value: List[Any] = []
|
|
495
455
|
|
|
496
456
|
if should_fill_entity_slot:
|
|
497
|
-
value =
|
|
457
|
+
value = SlotMapping.entity_is_desired(mapping, self.tracker, self.message)
|
|
498
458
|
elif should_fill_intent_slot or should_fill_trigger_slot:
|
|
499
|
-
value = [mapping.value]
|
|
459
|
+
value = [mapping.get("value")]
|
|
500
460
|
elif should_fill_text_slot:
|
|
501
461
|
value = [self.message.get(TEXT)] if self.message is not None else []
|
|
502
462
|
if not value:
|
|
@@ -508,9 +468,11 @@ class SlotFillingManager:
|
|
|
508
468
|
|
|
509
469
|
return value
|
|
510
470
|
|
|
511
|
-
def should_fill_slot(
|
|
471
|
+
def should_fill_slot(
|
|
472
|
+
self, slot_name: str, mapping_type: SlotMappingType, mapping: Dict[Text, Any]
|
|
473
|
+
) -> bool:
|
|
512
474
|
"""Checks if a slot should be filled based on the conversation context."""
|
|
513
|
-
if not self.is_slot_mapping_valid(slot_name, mapping):
|
|
475
|
+
if not self.is_slot_mapping_valid(slot_name, mapping_type, mapping):
|
|
514
476
|
return False
|
|
515
477
|
|
|
516
478
|
if not self.is_intent_desired(mapping):
|
|
@@ -532,12 +494,14 @@ def extract_slot_value(
|
|
|
532
494
|
is_extracted = False
|
|
533
495
|
|
|
534
496
|
for mapping in slot.mappings:
|
|
535
|
-
mapping_type =
|
|
497
|
+
mapping_type = SlotMappingType(
|
|
498
|
+
mapping.get(MAPPING_TYPE, SlotMappingType.FROM_LLM.value)
|
|
499
|
+
)
|
|
536
500
|
|
|
537
|
-
if mapping_type in [SlotMappingType.FROM_LLM, SlotMappingType.
|
|
501
|
+
if mapping_type in [SlotMappingType.FROM_LLM, SlotMappingType.CUSTOM]:
|
|
538
502
|
continue
|
|
539
503
|
|
|
540
|
-
if not slot_filling_manager.should_fill_slot(slot.name, mapping):
|
|
504
|
+
if not slot_filling_manager.should_fill_slot(slot.name, mapping_type, mapping):
|
|
541
505
|
continue
|
|
542
506
|
|
|
543
507
|
value: List[Any] = (
|
rasa/shared/core/slots.py
CHANGED
|
@@ -41,7 +41,6 @@ class Slot(ABC):
|
|
|
41
41
|
influence_conversation: bool = True,
|
|
42
42
|
is_builtin: bool = False,
|
|
43
43
|
shared_for_coexistence: bool = False,
|
|
44
|
-
filled_by: Optional[str] = None,
|
|
45
44
|
) -> None:
|
|
46
45
|
"""Create a Slot.
|
|
47
46
|
|
|
@@ -58,12 +57,9 @@ class Slot(ABC):
|
|
|
58
57
|
such as `return_value`.
|
|
59
58
|
shared_for_coexistence: If `True` the slot is not forgotten after either
|
|
60
59
|
dm1 or CALM finishes.
|
|
61
|
-
filled_by: The name of the extractor that fills the slot.
|
|
62
60
|
"""
|
|
63
|
-
from rasa.shared.core.slot_mappings import SlotMapping
|
|
64
|
-
|
|
65
61
|
self.name = name
|
|
66
|
-
self.mappings =
|
|
62
|
+
self.mappings = mappings
|
|
67
63
|
self._value = initial_value
|
|
68
64
|
self.initial_value = initial_value
|
|
69
65
|
self._value_reset_delay = value_reset_delay
|
|
@@ -71,7 +67,6 @@ class Slot(ABC):
|
|
|
71
67
|
self._has_been_set = False
|
|
72
68
|
self.is_builtin = is_builtin
|
|
73
69
|
self.shared_for_coexistence = shared_for_coexistence
|
|
74
|
-
self._filled_by = filled_by
|
|
75
70
|
|
|
76
71
|
def feature_dimensionality(self) -> int:
|
|
77
72
|
"""How many features this single slot creates.
|
|
@@ -137,16 +132,6 @@ class Slot(ABC):
|
|
|
137
132
|
self._value = value
|
|
138
133
|
self._has_been_set = True
|
|
139
134
|
|
|
140
|
-
@property
|
|
141
|
-
def filled_by(self) -> Optional[str]:
|
|
142
|
-
"""Gets the slot's latest value extractor."""
|
|
143
|
-
return self._filled_by
|
|
144
|
-
|
|
145
|
-
@filled_by.setter
|
|
146
|
-
def filled_by(self, extractor: str) -> None:
|
|
147
|
-
"""Sets the slot's latest value extractor."""
|
|
148
|
-
self._filled_by = extractor
|
|
149
|
-
|
|
150
135
|
def has_same_coerced_value(self, other_value: Any) -> bool:
|
|
151
136
|
"""Checks if the coerced value of is the same as the slot value.
|
|
152
137
|
|
|
@@ -195,7 +180,7 @@ class Slot(ABC):
|
|
|
195
180
|
"type": rasa.shared.utils.common.module_path_from_instance(self),
|
|
196
181
|
"initial_value": self.initial_value,
|
|
197
182
|
"influence_conversation": self.influence_conversation,
|
|
198
|
-
"mappings":
|
|
183
|
+
"mappings": self.mappings,
|
|
199
184
|
}
|
|
200
185
|
|
|
201
186
|
def fingerprint(self) -> Text:
|
|
@@ -230,7 +215,6 @@ class FloatSlot(Slot):
|
|
|
230
215
|
influence_conversation: bool = True,
|
|
231
216
|
is_builtin: bool = False,
|
|
232
217
|
shared_for_coexistence: bool = False,
|
|
233
|
-
filled_by: Optional[str] = None,
|
|
234
218
|
) -> None:
|
|
235
219
|
"""Creates a FloatSlot.
|
|
236
220
|
|
|
@@ -246,7 +230,6 @@ class FloatSlot(Slot):
|
|
|
246
230
|
influence_conversation,
|
|
247
231
|
is_builtin,
|
|
248
232
|
shared_for_coexistence,
|
|
249
|
-
filled_by=filled_by,
|
|
250
233
|
)
|
|
251
234
|
self.max_value = max_value
|
|
252
235
|
self.min_value = min_value
|
|
@@ -404,7 +387,6 @@ class CategoricalSlot(Slot):
|
|
|
404
387
|
influence_conversation: bool = True,
|
|
405
388
|
is_builtin: bool = False,
|
|
406
389
|
shared_for_coexistence: bool = False,
|
|
407
|
-
filled_by: Optional[str] = None,
|
|
408
390
|
) -> None:
|
|
409
391
|
"""Creates a `Categorical Slot` (see parent class for detailed docstring)."""
|
|
410
392
|
super().__init__(
|
|
@@ -415,7 +397,6 @@ class CategoricalSlot(Slot):
|
|
|
415
397
|
influence_conversation,
|
|
416
398
|
is_builtin,
|
|
417
399
|
shared_for_coexistence,
|
|
418
|
-
filled_by=filled_by,
|
|
419
400
|
)
|
|
420
401
|
if values and None in values:
|
|
421
402
|
rasa.shared.utils.io.raise_warning(
|
|
@@ -626,7 +607,6 @@ class AnySlot(Slot):
|
|
|
626
607
|
influence_conversation: bool = False,
|
|
627
608
|
is_builtin: bool = False,
|
|
628
609
|
shared_for_coexistence: bool = False,
|
|
629
|
-
filled_by: Optional[str] = None,
|
|
630
610
|
) -> None:
|
|
631
611
|
"""Creates an `Any Slot` (see parent class for detailed docstring).
|
|
632
612
|
|
|
@@ -650,7 +630,6 @@ class AnySlot(Slot):
|
|
|
650
630
|
influence_conversation,
|
|
651
631
|
is_builtin,
|
|
652
632
|
shared_for_coexistence,
|
|
653
|
-
filled_by=filled_by,
|
|
654
633
|
)
|
|
655
634
|
|
|
656
635
|
def __eq__(self, other: Any) -> bool:
|
rasa/shared/core/trackers.py
CHANGED
|
@@ -916,13 +916,11 @@ class DialogueStateTracker:
|
|
|
916
916
|
continue
|
|
917
917
|
slot.reset()
|
|
918
918
|
|
|
919
|
-
def _set_slot(self, key: Text, value: Any
|
|
919
|
+
def _set_slot(self, key: Text, value: Any) -> None:
|
|
920
920
|
"""Sets the value of a slot if that slot exists."""
|
|
921
921
|
if key in self.slots:
|
|
922
922
|
slot = self.slots[key]
|
|
923
923
|
slot.value = value
|
|
924
|
-
if filled_by is not None:
|
|
925
|
-
slot.filled_by = filled_by
|
|
926
924
|
else:
|
|
927
925
|
logger.error(
|
|
928
926
|
f"Tried to set non existent slot '{key}'. Make sure you "
|
rasa/shared/nlu/constants.py
CHANGED
rasa/shared/utils/llm.py
CHANGED
|
@@ -680,7 +680,7 @@ def allowed_values_for_slot(slot: Slot) -> Union[str, None]:
|
|
|
680
680
|
if isinstance(slot, BooleanSlot):
|
|
681
681
|
return str([True, False])
|
|
682
682
|
if isinstance(slot, CategoricalSlot):
|
|
683
|
-
return str([v for v in slot.values if v != "__other__"])
|
|
683
|
+
return str([v for v in slot.values if v != "__other__"] + ["other"])
|
|
684
684
|
else:
|
|
685
685
|
return None
|
|
686
686
|
|