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
rasa/cli/inspect.py
CHANGED
|
@@ -9,10 +9,6 @@ from rasa import telemetry
|
|
|
9
9
|
from rasa.cli import SubParsersAction
|
|
10
10
|
from rasa.cli.arguments import shell as arguments
|
|
11
11
|
from rasa.core import constants
|
|
12
|
-
from rasa.engine.storage.local_model_storage import LocalModelStorage
|
|
13
|
-
from rasa.exceptions import ModelNotFound
|
|
14
|
-
from rasa.model import get_local_model
|
|
15
|
-
from rasa.shared.utils.cli import print_error
|
|
16
12
|
from rasa.utils.cli import remove_argument_from_parser
|
|
17
13
|
|
|
18
14
|
|
|
@@ -59,8 +55,6 @@ async def open_inspector_in_browser(server_url: Text, voice: bool = False) -> No
|
|
|
59
55
|
def inspect(args: argparse.Namespace) -> None:
|
|
60
56
|
"""Inspect the bot using the most recent model."""
|
|
61
57
|
import rasa.cli.run
|
|
62
|
-
from rasa.cli.utils import get_validated_path
|
|
63
|
-
from rasa.shared.constants import DEFAULT_MODELS_PATH
|
|
64
58
|
|
|
65
59
|
async def after_start_hook_open_inspector(_: Sanic, __: AbstractEventLoop) -> None:
|
|
66
60
|
"""Hook to open the browser on server start."""
|
|
@@ -77,18 +71,5 @@ def inspect(args: argparse.Namespace) -> None:
|
|
|
77
71
|
args.credentials = None
|
|
78
72
|
args.server_listeners = [(after_start_hook_open_inspector, "after_server_start")]
|
|
79
73
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
try:
|
|
83
|
-
model = get_local_model(model)
|
|
84
|
-
except ModelNotFound:
|
|
85
|
-
print_error(
|
|
86
|
-
"No model found. Train a model before running the "
|
|
87
|
-
"server using `rasa train`."
|
|
88
|
-
)
|
|
89
|
-
return
|
|
90
|
-
|
|
91
|
-
metadata = LocalModelStorage.metadata_from_archive(model)
|
|
92
|
-
|
|
93
|
-
telemetry.track_inspect_started(args.connector, metadata.assistant_id)
|
|
74
|
+
telemetry.track_inspect_started(args.connector)
|
|
94
75
|
rasa.cli.run.run(args)
|
rasa/cli/shell.py
CHANGED
|
@@ -95,7 +95,7 @@ def shell_nlu(args: argparse.Namespace) -> None:
|
|
|
95
95
|
)
|
|
96
96
|
return
|
|
97
97
|
|
|
98
|
-
telemetry.track_shell_started("nlu"
|
|
98
|
+
telemetry.track_shell_started("nlu")
|
|
99
99
|
rasa.nlu.run.run_cmdline(model)
|
|
100
100
|
|
|
101
101
|
|
|
@@ -129,12 +129,12 @@ def shell(args: argparse.Namespace) -> None:
|
|
|
129
129
|
if metadata.training_type == TrainingType.NLU:
|
|
130
130
|
import rasa.nlu.run
|
|
131
131
|
|
|
132
|
-
telemetry.track_shell_started("nlu"
|
|
132
|
+
telemetry.track_shell_started("nlu")
|
|
133
133
|
|
|
134
134
|
rasa.nlu.run.run_cmdline(model)
|
|
135
135
|
else:
|
|
136
136
|
import rasa.cli.run
|
|
137
137
|
|
|
138
|
-
telemetry.track_shell_started("rasa"
|
|
138
|
+
telemetry.track_shell_started("rasa")
|
|
139
139
|
|
|
140
140
|
rasa.cli.run.run(args)
|
rasa/core/actions/action.py
CHANGED
|
@@ -73,9 +73,9 @@ from rasa.shared.core.constants import (
|
|
|
73
73
|
ACTION_VALIDATE_SLOT_MAPPINGS,
|
|
74
74
|
DEFAULT_SLOT_NAMES,
|
|
75
75
|
KNOWLEDGE_BASE_SLOT_NAMES,
|
|
76
|
+
MAPPING_TYPE,
|
|
76
77
|
REQUESTED_SLOT,
|
|
77
78
|
USER_INTENT_OUT_OF_SCOPE,
|
|
78
|
-
SetSlotExtractor,
|
|
79
79
|
SlotMappingType,
|
|
80
80
|
)
|
|
81
81
|
from rasa.shared.core.domain import Domain
|
|
@@ -111,7 +111,6 @@ if TYPE_CHECKING:
|
|
|
111
111
|
from rasa.core.channels.channel import OutputChannel
|
|
112
112
|
from rasa.core.nlg import NaturalLanguageGenerator
|
|
113
113
|
from rasa.shared.core.events import IntentPrediction
|
|
114
|
-
from rasa.shared.core.slot_mappings import SlotMapping
|
|
115
114
|
|
|
116
115
|
logger = logging.getLogger(__name__)
|
|
117
116
|
|
|
@@ -119,10 +118,6 @@ logger = logging.getLogger(__name__)
|
|
|
119
118
|
def default_actions(action_endpoint: Optional[EndpointConfig] = None) -> List["Action"]:
|
|
120
119
|
"""List default actions."""
|
|
121
120
|
from rasa.core.actions.action_clean_stack import ActionCleanStack
|
|
122
|
-
from rasa.core.actions.action_handle_digressions import (
|
|
123
|
-
ActionBlockDigressions,
|
|
124
|
-
ActionContinueDigression,
|
|
125
|
-
)
|
|
126
121
|
from rasa.core.actions.action_hangup import ActionHangup
|
|
127
122
|
from rasa.core.actions.action_repeat_bot_messages import ActionRepeatBotMessages
|
|
128
123
|
from rasa.core.actions.action_run_slot_rejections import ActionRunSlotRejections
|
|
@@ -157,8 +152,6 @@ def default_actions(action_endpoint: Optional[EndpointConfig] = None) -> List["A
|
|
|
157
152
|
ActionResetRouting(),
|
|
158
153
|
ActionHangup(),
|
|
159
154
|
ActionRepeatBotMessages(),
|
|
160
|
-
ActionBlockDigressions(),
|
|
161
|
-
ActionContinueDigression(),
|
|
162
155
|
]
|
|
163
156
|
|
|
164
157
|
|
|
@@ -947,14 +940,7 @@ class RemoteAction(Action):
|
|
|
947
940
|
)
|
|
948
941
|
|
|
949
942
|
events = rasa.shared.core.events.deserialise_events(events_json)
|
|
950
|
-
|
|
951
|
-
processed_events = []
|
|
952
|
-
for event in events:
|
|
953
|
-
if isinstance(event, SlotSet) and event.filled_by is None:
|
|
954
|
-
event.filled_by = SetSlotExtractor.CUSTOM.value
|
|
955
|
-
processed_events.append(event)
|
|
956
|
-
|
|
957
|
-
return cast(List[Event], bot_messages) + processed_events
|
|
943
|
+
return cast(List[Event], bot_messages) + events
|
|
958
944
|
|
|
959
945
|
def name(self) -> Text:
|
|
960
946
|
return self._name
|
|
@@ -1222,7 +1208,7 @@ class ActionExtractSlots(Action):
|
|
|
1222
1208
|
|
|
1223
1209
|
async def _execute_custom_action(
|
|
1224
1210
|
self,
|
|
1225
|
-
mapping:
|
|
1211
|
+
mapping: Dict[Text, Any],
|
|
1226
1212
|
executed_custom_actions: Set[Text],
|
|
1227
1213
|
output_channel: "OutputChannel",
|
|
1228
1214
|
nlg: "NaturalLanguageGenerator",
|
|
@@ -1230,7 +1216,7 @@ class ActionExtractSlots(Action):
|
|
|
1230
1216
|
domain: "Domain",
|
|
1231
1217
|
calm_custom_action_names: Optional[Set[str]] = None,
|
|
1232
1218
|
) -> Tuple[List[Event], Set[Text]]:
|
|
1233
|
-
custom_action = mapping.
|
|
1219
|
+
custom_action = mapping.get("action")
|
|
1234
1220
|
|
|
1235
1221
|
if not custom_action or custom_action in executed_custom_actions:
|
|
1236
1222
|
return [], executed_custom_actions
|
|
@@ -1331,9 +1317,10 @@ class ActionExtractSlots(Action):
|
|
|
1331
1317
|
slot_events.append(SlotSet(slot.name, slot_value))
|
|
1332
1318
|
|
|
1333
1319
|
for mapping in slot.mappings:
|
|
1334
|
-
|
|
1320
|
+
mapping_type = SlotMappingType(mapping.get(MAPPING_TYPE))
|
|
1321
|
+
should_fill_custom_slot = mapping_type == SlotMappingType.CUSTOM
|
|
1335
1322
|
|
|
1336
|
-
if
|
|
1323
|
+
if should_fill_custom_slot:
|
|
1337
1324
|
(
|
|
1338
1325
|
custom_evts,
|
|
1339
1326
|
executed_custom_actions,
|
rasa/core/actions/forms.py
CHANGED
|
@@ -2,7 +2,7 @@ import copy
|
|
|
2
2
|
import itertools
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import Any, Dict, List, Optional, Set, Text, Union
|
|
6
6
|
|
|
7
7
|
import structlog
|
|
8
8
|
|
|
@@ -16,7 +16,7 @@ from rasa.shared.constants import UTTER_PREFIX
|
|
|
16
16
|
from rasa.shared.core.constants import (
|
|
17
17
|
ACTION_EXTRACT_SLOTS,
|
|
18
18
|
ACTION_LISTEN_NAME,
|
|
19
|
-
|
|
19
|
+
MAPPING_TYPE,
|
|
20
20
|
REQUESTED_SLOT,
|
|
21
21
|
SLOT_MAPPINGS,
|
|
22
22
|
SlotMappingType,
|
|
@@ -35,9 +35,6 @@ from rasa.shared.core.slots import ListSlot
|
|
|
35
35
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
36
36
|
from rasa.utils.endpoints import EndpointConfig
|
|
37
37
|
|
|
38
|
-
if TYPE_CHECKING:
|
|
39
|
-
from rasa.shared.core.slot_mappings import SlotMapping
|
|
40
|
-
|
|
41
38
|
logger = logging.getLogger(__name__)
|
|
42
39
|
structlogger = structlog.get_logger()
|
|
43
40
|
|
|
@@ -161,9 +158,7 @@ class FormAction(LoopAction):
|
|
|
161
158
|
domain_slots = domain.as_dict().get(KEY_SLOTS, {})
|
|
162
159
|
for slot in domain.required_slots_for_form(self.name()):
|
|
163
160
|
for slot_mapping in domain_slots.get(slot, {}).get(SLOT_MAPPINGS, []):
|
|
164
|
-
if slot_mapping.get(
|
|
165
|
-
SlotMappingType.FROM_ENTITY
|
|
166
|
-
):
|
|
161
|
+
if slot_mapping.get(MAPPING_TYPE) == str(SlotMappingType.FROM_ENTITY):
|
|
167
162
|
mapping_as_string = json.dumps(slot_mapping, sort_keys=True)
|
|
168
163
|
if mapping_as_string in unique_entity_slot_mappings:
|
|
169
164
|
unique_entity_slot_mappings.remove(mapping_as_string)
|
|
@@ -174,7 +169,7 @@ class FormAction(LoopAction):
|
|
|
174
169
|
return unique_entity_slot_mappings
|
|
175
170
|
|
|
176
171
|
def entity_mapping_is_unique(
|
|
177
|
-
self, slot_mapping:
|
|
172
|
+
self, slot_mapping: Dict[Text, Any], domain: Domain
|
|
178
173
|
) -> bool:
|
|
179
174
|
"""Verifies if the from_entity mapping is unique."""
|
|
180
175
|
if not self._have_unique_entity_mappings_been_initialized:
|
|
@@ -182,7 +177,7 @@ class FormAction(LoopAction):
|
|
|
182
177
|
self._unique_entity_mappings = self._create_unique_entity_mappings(domain)
|
|
183
178
|
self._have_unique_entity_mappings_been_initialized = True
|
|
184
179
|
|
|
185
|
-
mapping_as_string = json.dumps(slot_mapping
|
|
180
|
+
mapping_as_string = json.dumps(slot_mapping, sort_keys=True)
|
|
186
181
|
return mapping_as_string in self._unique_entity_mappings
|
|
187
182
|
|
|
188
183
|
@staticmethod
|
rasa/core/channels/__init__.py
CHANGED
|
@@ -32,7 +32,6 @@ from rasa.core.channels.vier_cvg import CVGInput
|
|
|
32
32
|
from rasa.core.channels.voice_stream.twilio_media_streams import (
|
|
33
33
|
TwilioMediaStreamsInputChannel,
|
|
34
34
|
)
|
|
35
|
-
from rasa.core.channels.voice_stream.genesys import GenesysInputChannel
|
|
36
35
|
from rasa.core.channels.studio_chat import StudioChatInput
|
|
37
36
|
|
|
38
37
|
input_channel_classes: List[Type[InputChannel]] = [
|
|
@@ -56,7 +55,6 @@ input_channel_classes: List[Type[InputChannel]] = [
|
|
|
56
55
|
JambonzVoiceReadyInput,
|
|
57
56
|
TwilioMediaStreamsInputChannel,
|
|
58
57
|
BrowserAudioInputChannel,
|
|
59
|
-
GenesysInputChannel,
|
|
60
58
|
StudioChatInput,
|
|
61
59
|
]
|
|
62
60
|
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import asyncio
|
|
2
1
|
import copy
|
|
3
2
|
import json
|
|
4
3
|
import uuid
|
|
5
|
-
from collections import defaultdict
|
|
6
4
|
from dataclasses import asdict
|
|
7
5
|
from datetime import datetime, timedelta, timezone
|
|
8
|
-
from typing import Any, Awaitable, Callable, Dict, List, Optional,
|
|
6
|
+
from typing import Any, Awaitable, Callable, Dict, List, Optional, Text, Union
|
|
9
7
|
|
|
10
8
|
import structlog
|
|
11
9
|
from jsonschema import ValidationError, validate
|
|
@@ -225,16 +223,6 @@ class AudiocodesInput(InputChannel):
|
|
|
225
223
|
self.scheduler_job = None
|
|
226
224
|
self.keep_alive = keep_alive
|
|
227
225
|
self.keep_alive_expiration_factor = keep_alive_expiration_factor
|
|
228
|
-
self.background_tasks: Dict[Text, Set[asyncio.Task]] = defaultdict(set)
|
|
229
|
-
|
|
230
|
-
def _create_task(self, conversation_id: Text, coro: Awaitable[Any]) -> asyncio.Task:
|
|
231
|
-
"""Create and track an asyncio task for a conversation."""
|
|
232
|
-
task: asyncio.Task = asyncio.create_task(coro)
|
|
233
|
-
self.background_tasks[conversation_id].add(task)
|
|
234
|
-
task.add_done_callback(
|
|
235
|
-
lambda t: self.background_tasks[conversation_id].discard(t)
|
|
236
|
-
)
|
|
237
|
-
return task
|
|
238
226
|
|
|
239
227
|
async def _set_scheduler_job(self) -> None:
|
|
240
228
|
if self.scheduler_job:
|
|
@@ -263,20 +251,11 @@ class AudiocodesInput(InputChannel):
|
|
|
263
251
|
)
|
|
264
252
|
now = datetime.now(timezone.utc)
|
|
265
253
|
delta = timedelta(seconds=self.keep_alive * self.keep_alive_expiration_factor)
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
if not conv.is_active_conversation(now, delta)
|
|
272
|
-
]
|
|
273
|
-
|
|
274
|
-
# cancel tasks and remove conversations
|
|
275
|
-
for conv_id in inactive:
|
|
276
|
-
for task in self.background_tasks[conv_id]:
|
|
277
|
-
task.cancel()
|
|
278
|
-
self.background_tasks.pop(conv_id, None)
|
|
279
|
-
self.conversations.pop(conv_id, None)
|
|
254
|
+
self.conversations = {
|
|
255
|
+
k: v
|
|
256
|
+
for k, v in self.conversations.items()
|
|
257
|
+
if v.is_active_conversation(now, delta)
|
|
258
|
+
}
|
|
280
259
|
|
|
281
260
|
def handle_start_conversation(self, body: Dict[Text, Any]) -> Dict[Text, Any]:
|
|
282
261
|
conversation_id = body["conversation"]
|
|
@@ -368,29 +347,31 @@ class AudiocodesInput(InputChannel):
|
|
|
368
347
|
structlogger.debug("audiocodes.on_activities", conversation=conversation_id)
|
|
369
348
|
conversation = self._get_conversation(request.token, conversation_id)
|
|
370
349
|
if conversation is None:
|
|
371
|
-
structlogger.warning(
|
|
372
|
-
"audiocodes.on_activities.no_conversation", request=request.json
|
|
373
|
-
)
|
|
374
350
|
return response.json({})
|
|
375
351
|
elif conversation.ws:
|
|
376
352
|
ac_output: Union[WebsocketOutput, AudiocodesOutput] = WebsocketOutput(
|
|
377
353
|
conversation.ws, conversation_id
|
|
378
354
|
)
|
|
379
|
-
|
|
355
|
+
await conversation.handle_activities(
|
|
356
|
+
request.json,
|
|
357
|
+
output_channel=ac_output,
|
|
358
|
+
on_new_message=on_new_message,
|
|
359
|
+
)
|
|
360
|
+
return response.json({})
|
|
380
361
|
else:
|
|
381
362
|
# handle non websocket case where messages get returned in json
|
|
382
363
|
ac_output = AudiocodesOutput()
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
364
|
+
await conversation.handle_activities(
|
|
365
|
+
request.json,
|
|
366
|
+
output_channel=ac_output,
|
|
367
|
+
on_new_message=on_new_message,
|
|
368
|
+
)
|
|
369
|
+
return response.json(
|
|
370
|
+
{
|
|
371
|
+
"conversation": conversation_id,
|
|
372
|
+
"activities": ac_output.messages,
|
|
373
|
+
}
|
|
374
|
+
)
|
|
394
375
|
|
|
395
376
|
@ac_webhook.route(
|
|
396
377
|
"/conversation/<conversation_id>/disconnect", methods=["POST"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from contextvars import ContextVar
|
|
3
|
-
from dataclasses import dataclass
|
|
3
|
+
from dataclasses import dataclass
|
|
4
4
|
from typing import Optional
|
|
5
5
|
|
|
6
6
|
from werkzeug.local import LocalProxy
|
|
@@ -19,12 +19,6 @@ class CallState:
|
|
|
19
19
|
should_hangup: bool = False
|
|
20
20
|
connection_failed: bool = False
|
|
21
21
|
|
|
22
|
-
# Genesys requires the server and client each maintain a
|
|
23
|
-
# monotonically increasing message sequence number.
|
|
24
|
-
client_sequence_number: int = 0
|
|
25
|
-
server_sequence_number: int = 0
|
|
26
|
-
audio_buffer: bytearray = field(default_factory=bytearray)
|
|
27
|
-
|
|
28
22
|
|
|
29
23
|
_call_state: ContextVar[CallState] = ContextVar("call_state")
|
|
30
24
|
call_state = LocalProxy(_call_state)
|
|
@@ -81,8 +81,7 @@ class AzureTTS(TTSEngine[AzureTTSConfig]):
|
|
|
81
81
|
@staticmethod
|
|
82
82
|
def create_request_body(text: str, conf: AzureTTSConfig) -> str:
|
|
83
83
|
return f"""
|
|
84
|
-
<speak version='1.0' xml:lang='{conf.language}'
|
|
85
|
-
xmlns='http://www.w3.org/2001/10/synthesis'>
|
|
84
|
+
<speak version='1.0' xml:lang='{conf.language}'>
|
|
86
85
|
<voice xml:lang='{conf.language}' name='{conf.voice}'>
|
|
87
86
|
{text}
|
|
88
87
|
</voice>
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import base64
|
|
2
|
-
import json
|
|
3
1
|
import os
|
|
4
2
|
from dataclasses import dataclass
|
|
5
3
|
from typing import AsyncIterator, Dict, Optional
|
|
@@ -41,7 +39,7 @@ class CartesiaTTS(TTSEngine[CartesiaTTSConfig]):
|
|
|
41
39
|
@staticmethod
|
|
42
40
|
def get_tts_endpoint() -> str:
|
|
43
41
|
"""Create the endpoint string for cartesia."""
|
|
44
|
-
return "https://api.cartesia.ai/tts/
|
|
42
|
+
return "https://api.cartesia.ai/tts/bytes"
|
|
45
43
|
|
|
46
44
|
@staticmethod
|
|
47
45
|
def get_request_body(text: str, config: CartesiaTTSConfig) -> Dict:
|
|
@@ -87,19 +85,8 @@ class CartesiaTTS(TTSEngine[CartesiaTTSConfig]):
|
|
|
87
85
|
url, headers=headers, json=payload, chunked=True
|
|
88
86
|
) as response:
|
|
89
87
|
if 200 <= response.status < 300:
|
|
90
|
-
async for
|
|
91
|
-
|
|
92
|
-
# b"data: {..., data: <base64 encoded audio bytes> ...}"
|
|
93
|
-
# and extract the audio bytes from that
|
|
94
|
-
if chunk.startswith(b"data: "):
|
|
95
|
-
json_bytes = chunk[5:-1]
|
|
96
|
-
json_data = json.loads(json_bytes.decode())
|
|
97
|
-
if "data" in json_data:
|
|
98
|
-
base64_encoded_bytes = json_data["data"]
|
|
99
|
-
channel_bytes = base64.b64decode(base64_encoded_bytes)
|
|
100
|
-
yield self.engine_bytes_to_rasa_audio_bytes(
|
|
101
|
-
channel_bytes
|
|
102
|
-
)
|
|
88
|
+
async for data in response.content.iter_chunked(1024):
|
|
89
|
+
yield self.engine_bytes_to_rasa_audio_bytes(data)
|
|
103
90
|
return
|
|
104
91
|
else:
|
|
105
92
|
structlogger.error(
|
|
@@ -98,7 +98,6 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
98
98
|
def map_input_message(
|
|
99
99
|
self,
|
|
100
100
|
message: Any,
|
|
101
|
-
ws: Websocket,
|
|
102
101
|
) -> VoiceChannelAction:
|
|
103
102
|
data = json.loads(message)
|
|
104
103
|
if data["event"] == "media":
|
|
@@ -143,7 +142,7 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
143
142
|
def blueprint(
|
|
144
143
|
self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
|
|
145
144
|
) -> Blueprint:
|
|
146
|
-
"""Defines a Sanic
|
|
145
|
+
"""Defines a Sanic bluelogger.debug."""
|
|
147
146
|
blueprint = Blueprint("twilio_media_streams", __name__)
|
|
148
147
|
|
|
149
148
|
@blueprint.route("/", methods=["GET"])
|
|
@@ -315,7 +315,6 @@ class VoiceInputChannel(InputChannel):
|
|
|
315
315
|
def map_input_message(
|
|
316
316
|
self,
|
|
317
317
|
message: Any,
|
|
318
|
-
ws: Websocket,
|
|
319
318
|
) -> VoiceChannelAction:
|
|
320
319
|
"""Map a channel input message to a voice channel action."""
|
|
321
320
|
raise NotImplementedError
|
|
@@ -341,7 +340,7 @@ class VoiceInputChannel(InputChannel):
|
|
|
341
340
|
async def consume_audio_bytes() -> None:
|
|
342
341
|
async for message in channel_websocket:
|
|
343
342
|
is_bot_speaking_before = call_state.is_bot_speaking
|
|
344
|
-
channel_action = self.map_input_message(message
|
|
343
|
+
channel_action = self.map_input_message(message)
|
|
345
344
|
is_bot_speaking_after = call_state.is_bot_speaking
|
|
346
345
|
|
|
347
346
|
if not is_bot_speaking_before and is_bot_speaking_after:
|
rasa/core/migrate.py
CHANGED
|
@@ -14,7 +14,7 @@ from rasa.shared.constants import (
|
|
|
14
14
|
)
|
|
15
15
|
from rasa.shared.core.constants import (
|
|
16
16
|
ACTIVE_LOOP,
|
|
17
|
-
|
|
17
|
+
MAPPING_TYPE,
|
|
18
18
|
REQUESTED_SLOT,
|
|
19
19
|
SLOT_MAPPINGS,
|
|
20
20
|
SlotMappingType,
|
|
@@ -43,7 +43,7 @@ def _create_back_up(domain_file: Path, backup_location: Path) -> Dict[Text, Any]
|
|
|
43
43
|
def _get_updated_mapping_condition(
|
|
44
44
|
condition: Dict[Text, Text], mapping: Dict[Text, Any], slot_name: Text
|
|
45
45
|
) -> Dict[Text, Text]:
|
|
46
|
-
if mapping.get(
|
|
46
|
+
if mapping.get(MAPPING_TYPE) not in [
|
|
47
47
|
str(SlotMappingType.FROM_ENTITY),
|
|
48
48
|
str(SlotMappingType.FROM_TRIGGER_INTENT),
|
|
49
49
|
]:
|
|
@@ -23,7 +23,6 @@ from rasa.core.policies.flows.flow_step_result import (
|
|
|
23
23
|
)
|
|
24
24
|
from rasa.dialogue_understanding.commands import CancelFlowCommand
|
|
25
25
|
from rasa.dialogue_understanding.patterns.cancel import CancelPatternFlowStackFrame
|
|
26
|
-
from rasa.dialogue_understanding.patterns.clarify import ClarifyPatternFlowStackFrame
|
|
27
26
|
from rasa.dialogue_understanding.patterns.collect_information import (
|
|
28
27
|
CollectInformationPatternFlowStackFrame,
|
|
29
28
|
)
|
|
@@ -51,12 +50,9 @@ from rasa.dialogue_understanding.stack.frames.flow_stack_frame import (
|
|
|
51
50
|
)
|
|
52
51
|
from rasa.dialogue_understanding.stack.utils import (
|
|
53
52
|
top_user_flow_frame,
|
|
54
|
-
user_flows_on_the_stack,
|
|
55
53
|
)
|
|
56
54
|
from rasa.shared.constants import RASA_PATTERN_HUMAN_HANDOFF
|
|
57
|
-
from rasa.shared.core.constants import
|
|
58
|
-
ACTION_LISTEN_NAME,
|
|
59
|
-
)
|
|
55
|
+
from rasa.shared.core.constants import ACTION_LISTEN_NAME, SlotMappingType
|
|
60
56
|
from rasa.shared.core.events import (
|
|
61
57
|
Event,
|
|
62
58
|
FlowCompleted,
|
|
@@ -276,28 +272,6 @@ def trigger_pattern_continue_interrupted(
|
|
|
276
272
|
return events
|
|
277
273
|
|
|
278
274
|
|
|
279
|
-
def trigger_pattern_clarification(
|
|
280
|
-
current_frame: DialogueStackFrame, stack: DialogueStack, flows: FlowsList
|
|
281
|
-
) -> None:
|
|
282
|
-
"""Trigger the pattern to clarify which topic to continue if needed."""
|
|
283
|
-
if not isinstance(current_frame, UserFlowStackFrame):
|
|
284
|
-
return None
|
|
285
|
-
|
|
286
|
-
if current_frame.frame_type == FlowStackFrameType.CALL:
|
|
287
|
-
# we want to return to the flow that called the current flow
|
|
288
|
-
return None
|
|
289
|
-
|
|
290
|
-
pending_flows = [
|
|
291
|
-
flows.flow_by_id(frame.flow_id)
|
|
292
|
-
for frame in stack.frames
|
|
293
|
-
if isinstance(frame, UserFlowStackFrame)
|
|
294
|
-
and frame.flow_id != current_frame.flow_id
|
|
295
|
-
]
|
|
296
|
-
|
|
297
|
-
flow_names = [flow.readable_name() for flow in pending_flows if flow is not None]
|
|
298
|
-
stack.push(ClarifyPatternFlowStackFrame(names=flow_names))
|
|
299
|
-
|
|
300
|
-
|
|
301
275
|
def trigger_pattern_completed(
|
|
302
276
|
current_frame: DialogueStackFrame, stack: DialogueStack, flows: FlowsList
|
|
303
277
|
) -> None:
|
|
@@ -566,6 +540,38 @@ def cancel_flow_and_push_internal_error(stack: DialogueStack, flow_name: str) ->
|
|
|
566
540
|
stack.push(InternalErrorPatternFlowStackFrame())
|
|
567
541
|
|
|
568
542
|
|
|
543
|
+
def validate_custom_slot_mappings(
|
|
544
|
+
step: CollectInformationFlowStep,
|
|
545
|
+
stack: DialogueStack,
|
|
546
|
+
tracker: DialogueStateTracker,
|
|
547
|
+
available_actions: List[str],
|
|
548
|
+
flow_name: str,
|
|
549
|
+
) -> bool:
|
|
550
|
+
"""Validate a slot with custom mappings.
|
|
551
|
+
|
|
552
|
+
If invalid, trigger pattern_internal_error and return False.
|
|
553
|
+
"""
|
|
554
|
+
slot = tracker.slots.get(step.collect, None)
|
|
555
|
+
slot_mappings = slot.mappings if slot else []
|
|
556
|
+
for mapping in slot_mappings:
|
|
557
|
+
if (
|
|
558
|
+
mapping.get("type") == SlotMappingType.CUSTOM.value
|
|
559
|
+
and mapping.get("action") is None
|
|
560
|
+
):
|
|
561
|
+
# this is a slot that must be filled by a custom action
|
|
562
|
+
# check if collect_action exists
|
|
563
|
+
if step.collect_action not in available_actions:
|
|
564
|
+
structlogger.error(
|
|
565
|
+
"flow.step.run.collect_action_not_found_for_custom_slot_mapping",
|
|
566
|
+
action=step.collect_action,
|
|
567
|
+
collect=step.collect,
|
|
568
|
+
)
|
|
569
|
+
cancel_flow_and_push_internal_error(stack, flow_name)
|
|
570
|
+
return False
|
|
571
|
+
|
|
572
|
+
return True
|
|
573
|
+
|
|
574
|
+
|
|
569
575
|
def attach_stack_metadata_to_events(
|
|
570
576
|
step_id: str,
|
|
571
577
|
flow_id: str,
|
|
@@ -663,15 +669,7 @@ def _run_end_step(
|
|
|
663
669
|
structlogger.debug("flow.step.run.flow_end")
|
|
664
670
|
current_frame = stack.pop()
|
|
665
671
|
trigger_pattern_completed(current_frame, stack, flows)
|
|
666
|
-
resumed_events =
|
|
667
|
-
if len(user_flows_on_the_stack(stack)) > 1:
|
|
668
|
-
# if there are more user flows on the stack,
|
|
669
|
-
# we need to trigger the pattern clarify
|
|
670
|
-
trigger_pattern_clarification(current_frame, stack, flows)
|
|
671
|
-
else:
|
|
672
|
-
resumed_events = trigger_pattern_continue_interrupted(
|
|
673
|
-
current_frame, stack, flows
|
|
674
|
-
)
|
|
672
|
+
resumed_events = trigger_pattern_continue_interrupted(current_frame, stack, flows)
|
|
675
673
|
reset_events: List[Event] = reset_scoped_slots(current_frame, flow, tracker)
|
|
676
674
|
return ContinueFlowWithNextStep(
|
|
677
675
|
events=initial_events + reset_events + resumed_events, has_flow_ended=True
|
|
@@ -762,6 +760,14 @@ def _run_collect_information_step(
|
|
|
762
760
|
# if we return any other FlowStepResult, the assistant will stay silent
|
|
763
761
|
# instead of triggering the internal error pattern
|
|
764
762
|
return ContinueFlowWithNextStep(events=initial_events)
|
|
763
|
+
is_mapping_valid = validate_custom_slot_mappings(
|
|
764
|
+
step, stack, tracker, available_actions, flow_name
|
|
765
|
+
)
|
|
766
|
+
|
|
767
|
+
if not is_mapping_valid:
|
|
768
|
+
# if we return any other FlowStepResult, the assistant will stay silent
|
|
769
|
+
# instead of triggering the internal error pattern
|
|
770
|
+
return ContinueFlowWithNextStep(events=initial_events)
|
|
765
771
|
|
|
766
772
|
structlogger.debug("flow.step.run.collect")
|
|
767
773
|
trigger_pattern_ask_collect_information(
|
rasa/core/run.py
CHANGED
|
@@ -283,10 +283,9 @@ def serve_application(
|
|
|
283
283
|
endpoints.lock_store if endpoints else None
|
|
284
284
|
)
|
|
285
285
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
)
|
|
286
|
+
telemetry.track_server_start(
|
|
287
|
+
input_channels, endpoints, model_path, number_of_workers, enable_api
|
|
288
|
+
)
|
|
290
289
|
|
|
291
290
|
rasa.utils.common.update_sanic_log_level(
|
|
292
291
|
log_file, use_syslog, syslog_address, syslog_port, syslog_protocol
|
|
@@ -74,7 +74,7 @@ class CannotHandleCommand(Command):
|
|
|
74
74
|
|
|
75
75
|
def to_dsl(self) -> str:
|
|
76
76
|
"""Converts the command to a DSL string."""
|
|
77
|
-
return "
|
|
77
|
+
return "cannot handle"
|
|
78
78
|
|
|
79
79
|
@classmethod
|
|
80
80
|
def from_dsl(cls, match: re.Match, **kwargs: Any) -> CannotHandleCommand:
|
|
@@ -86,4 +86,4 @@ class CannotHandleCommand(Command):
|
|
|
86
86
|
|
|
87
87
|
@staticmethod
|
|
88
88
|
def regex_pattern() -> str:
|
|
89
|
-
return r"
|
|
89
|
+
return r"^cannot handle$"
|