rasa-pro 3.13.0.dev3__py3-none-any.whl → 3.13.0.dev7__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/__main__.py +3 -1
- rasa/api.py +4 -0
- rasa/cli/arguments/default_arguments.py +13 -1
- rasa/cli/arguments/train.py +2 -0
- rasa/cli/evaluate.py +1 -1
- rasa/cli/export.py +2 -2
- rasa/cli/inspect.py +8 -4
- rasa/cli/project_templates/default/config.yml +5 -32
- rasa/cli/project_templates/{calm → default}/e2e_tests/cancelations/user_cancels_during_a_correction.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/cancelations/user_changes_mind_on_a_whim.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/corrections/user_corrects_contact_handle.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/corrections/user_corrects_contact_name.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_adds_contact_to_their_list.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_lists_contacts.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_removes_contact.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_removes_contact_from_list.yml +1 -1
- rasa/cli/project_templates/default/endpoints.yml +18 -2
- rasa/cli/scaffold.py +3 -4
- rasa/cli/studio/download.py +1 -1
- rasa/cli/studio/upload.py +0 -6
- rasa/cli/train.py +1 -0
- rasa/constants.py +2 -0
- rasa/core/agent.py +2 -2
- rasa/core/brokers/kafka.py +4 -0
- rasa/core/brokers/pika.py +4 -0
- rasa/core/brokers/sql.py +1 -1
- rasa/core/channels/channel.py +68 -5
- rasa/core/channels/inspector/.eslintrc.cjs +12 -6
- rasa/core/channels/inspector/.prettierrc +5 -0
- rasa/core/channels/inspector/README.md +10 -4
- rasa/core/channels/inspector/dist/assets/{arc-c7691751.js → arc-c4b064fc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-ab99dff7.js → blockDiagram-38ab4fdb-215b5026.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-08c35a6b.js → c4Diagram-3d4e48cf-2b54a0a3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-3730f5fd.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-9e9c71c9.js → classDiagram-70f12bd4-daacea5f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-15e7e2bf.js → classDiagram-v2-f2320105-930d4dc2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-e847561e.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-9c105cb1.js → createText-2e5e7dd3-83c206ba.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-77e89e48.js → edges-e0da2a9e-b0eb01d0.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-7a011646.js → erDiagram-9861fffd-17586500.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-b6f105ac.js → flowDb-956e92f1-be2a1776.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-ce4f18c2.js → flowDiagram-66a62f08-c2120ebd.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-efbbfe00.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-cb5f6da4.js → flowchart-elk-definition-4a651766-a6ab5c48.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-e4d19e28.js → ganttDiagram-c361ad54-ef613457.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-727b1c33.js → gitGraphDiagram-72cf32ee-d59185b3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-6e2ab9a7.js → graph-0f155405.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-84ec700f.js → index-3862675e-d5f1d1b7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-098a1a24.js → index-47737d3a.js} +162 -149
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-78dda442.js → infoDiagram-f8f76790-b07d141f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-f1cc6dd1.js → journeyDiagram-49397b02-1936d429.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-d98dcd0c.js → layout-dde8d0f3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-838e3d82.js → line-0c2c7ee0.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-eae72406.js → linear-35dd89a4.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-c96fd84b.js → mindmap-definition-fc14e90a-56192851.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-c936d4e2.js → pieDiagram-8a3498a8-fc21ed78.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-b338eb8f.js → quadrantDiagram-120e2f19-25e98518.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-c6b6c0d5.js → requirementDiagram-deff3bca-546ff1f5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-b9372e19.js → sankeyDiagram-04a897e0-02d8b82d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-479e0a3f.js → sequenceDiagram-704730f1-3ca5a92e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-fd26eebc.js → stateDiagram-587899a1-128ea07c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-3233e0ae.js → stateDiagram-v2-d93cdb3a-95f290af.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-1fdd392b.js → styles-6aaf32cf-4984898a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-6d7bfa1b.js → styles-9a916d00-1bf266ba.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-f86aab11.js → styles-c10674c1-60521c63.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-e3e49d7a.js → svgDrawCommon-08f97a94-a25b6e12.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-6fe08b4d.js → timeline-definition-85554ec2-0fc086bf.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-c2e06fd6.js → xychartDiagram-e933f94c-44ee592e.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/package.json +3 -1
- rasa/core/channels/inspector/src/App.tsx +92 -90
- rasa/core/channels/inspector/src/components/Chat.tsx +61 -36
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +40 -43
- rasa/core/channels/inspector/src/components/DialogueInformation.tsx +57 -57
- rasa/core/channels/inspector/src/components/DialogueStack.tsx +36 -27
- rasa/core/channels/inspector/src/components/ExpandIcon.tsx +4 -4
- rasa/core/channels/inspector/src/components/FullscreenButton.tsx +7 -7
- rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +28 -12
- rasa/core/channels/inspector/src/components/NoActiveFlow.tsx +9 -9
- rasa/core/channels/inspector/src/components/RasaLogo.tsx +5 -5
- rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +55 -60
- rasa/core/channels/inspector/src/components/SaraDiagrams.tsx +5 -5
- rasa/core/channels/inspector/src/components/Slots.tsx +22 -22
- rasa/core/channels/inspector/src/components/Welcome.tsx +28 -31
- rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +245 -0
- rasa/core/channels/inspector/src/helpers/audio/microphone-processor.js +12 -0
- rasa/core/channels/inspector/src/helpers/audio/playback-processor.js +36 -0
- rasa/core/channels/inspector/src/helpers/conversation.ts +16 -0
- rasa/core/channels/inspector/src/helpers/formatters.test.ts +181 -181
- rasa/core/channels/inspector/src/helpers/formatters.ts +111 -111
- rasa/core/channels/inspector/src/helpers/utils.ts +78 -61
- rasa/core/channels/inspector/src/main.tsx +8 -8
- rasa/core/channels/inspector/src/theme/Button/Button.ts +8 -8
- rasa/core/channels/inspector/src/theme/Heading/Heading.ts +7 -7
- rasa/core/channels/inspector/src/theme/Input/Input.ts +9 -9
- rasa/core/channels/inspector/src/theme/Link/Link.ts +6 -6
- rasa/core/channels/inspector/src/theme/Modal/Modal.ts +13 -13
- rasa/core/channels/inspector/src/theme/Table/Table.tsx +10 -10
- rasa/core/channels/inspector/src/theme/Tooltip/Tooltip.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/breakpoints.ts +7 -7
- rasa/core/channels/inspector/src/theme/base/colors.ts +64 -64
- rasa/core/channels/inspector/src/theme/base/fonts/fontFaces.css +21 -18
- rasa/core/channels/inspector/src/theme/base/radii.ts +8 -8
- rasa/core/channels/inspector/src/theme/base/shadows.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/sizes.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/space.ts +12 -12
- rasa/core/channels/inspector/src/theme/base/styles.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/typography.ts +12 -12
- rasa/core/channels/inspector/src/theme/base/zIndices.ts +3 -3
- rasa/core/channels/inspector/src/theme/index.ts +38 -38
- rasa/core/channels/inspector/src/types.ts +56 -50
- rasa/core/channels/inspector/yarn.lock +5 -0
- rasa/core/channels/voice_ready/audiocodes.py +75 -32
- rasa/core/channels/voice_ready/twilio_voice.py +48 -1
- rasa/core/channels/voice_stream/tts/azure.py +11 -2
- rasa/core/channels/voice_stream/twilio_media_streams.py +101 -26
- rasa/core/channels/voice_stream/voice_channel.py +28 -2
- rasa/core/concurrent_lock_store.py +24 -10
- rasa/core/evaluation/marker_tracker_loader.py +1 -1
- rasa/core/exporter.py +1 -1
- rasa/core/lock_store.py +151 -60
- rasa/core/nlg/contextual_response_rephraser.py +4 -2
- rasa/core/nlg/summarize.py +1 -1
- rasa/core/persistor.py +55 -20
- rasa/core/policies/enterprise_search_policy.py +7 -4
- rasa/core/policies/intentless_policy.py +15 -9
- rasa/core/processor.py +2 -2
- rasa/core/run.py +7 -2
- rasa/core/{auth_retry_tracker_store.py → tracker_stores/auth_retry_tracker_store.py} +5 -1
- rasa/core/tracker_stores/dynamo_tracker_store.py +218 -0
- rasa/core/tracker_stores/mongo_tracker_store.py +206 -0
- rasa/core/tracker_stores/redis_tracker_store.py +219 -0
- rasa/core/tracker_stores/sql_tracker_store.py +555 -0
- rasa/core/tracker_stores/tracker_store.py +805 -0
- rasa/core/utils.py +6 -0
- rasa/dialogue_understanding/coexistence/llm_based_router.py +8 -3
- rasa/dialogue_understanding/commands/clarify_command.py +2 -2
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -2
- rasa/dialogue_understanding/generator/constants.py +2 -2
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +1 -1
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +33 -12
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +2 -2
- rasa/dialogue_understanding_test/du_test_case.py +16 -8
- rasa/hooks.py +2 -2
- rasa/keys +1 -0
- rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +4 -2
- rasa/model_manager/config.py +3 -1
- rasa/model_manager/model_api.py +1 -2
- rasa/model_manager/runner_service.py +8 -4
- rasa/model_manager/trainer_service.py +1 -0
- rasa/model_training.py +12 -3
- rasa/nlu/extractors/crf_entity_extractor.py +66 -16
- rasa/plugin.py +1 -4
- rasa/server.py +6 -2
- rasa/shared/constants.py +4 -0
- rasa/shared/core/domain.py +165 -11
- rasa/shared/core/events.py +68 -2
- rasa/shared/core/flows/flow.py +155 -131
- rasa/shared/core/flows/flow_step.py +19 -3
- rasa/shared/core/flows/flow_step_links.py +15 -0
- rasa/shared/core/flows/flow_step_sequence.py +6 -0
- rasa/shared/core/flows/nlu_trigger.py +13 -0
- rasa/shared/core/flows/steps/action.py +7 -4
- rasa/shared/core/flows/steps/call.py +11 -4
- rasa/shared/core/flows/steps/collect.py +27 -6
- rasa/shared/core/flows/steps/internal.py +6 -1
- rasa/shared/core/flows/steps/link.py +7 -4
- rasa/shared/core/flows/steps/no_operation.py +7 -4
- rasa/shared/core/flows/steps/set_slots.py +8 -4
- rasa/shared/core/flows/yaml_flows_io.py +106 -5
- rasa/shared/importers/importer.py +8 -0
- rasa/shared/providers/_configs/azure_openai_client_config.py +4 -0
- rasa/shared/providers/_configs/openai_client_config.py +4 -0
- rasa/shared/providers/_utils.py +83 -0
- rasa/shared/providers/embedding/_base_litellm_embedding_client.py +3 -0
- rasa/shared/providers/llm/_base_litellm_client.py +11 -5
- rasa/shared/providers/llm/azure_openai_llm_client.py +6 -68
- rasa/shared/providers/router/_base_litellm_router_client.py +53 -1
- rasa/shared/utils/common.py +42 -0
- rasa/studio/download/__init__.py +0 -0
- rasa/studio/download/domains.py +49 -0
- rasa/studio/download/download.py +439 -0
- rasa/studio/download/flows.py +359 -0
- rasa/studio/results_logger.py +6 -1
- rasa/studio/upload.py +69 -5
- rasa/telemetry.py +2 -2
- rasa/tracing/config.py +1 -1
- rasa/tracing/instrumentation/attribute_extractors.py +1 -1
- rasa/tracing/instrumentation/instrumentation.py +1 -1
- rasa/utils/common.py +36 -0
- rasa/utils/endpoints.py +22 -1
- rasa/utils/licensing.py +2 -3
- rasa/validator.py +1 -2
- rasa/version.py +1 -1
- {rasa_pro-3.13.0.dev3.dist-info → rasa_pro-3.13.0.dev7.dist-info}/METADATA +10 -10
- {rasa_pro-3.13.0.dev3.dist-info → rasa_pro-3.13.0.dev7.dist-info}/RECORD +213 -210
- rasa/cli/project_templates/calm/config.yml +0 -10
- rasa/cli/project_templates/calm/credentials.yml +0 -33
- rasa/cli/project_templates/calm/endpoints.yml +0 -58
- rasa/cli/project_templates/default/actions/actions.py +0 -27
- rasa/cli/project_templates/default/data/nlu.yml +0 -91
- rasa/cli/project_templates/default/data/rules.yml +0 -13
- rasa/cli/project_templates/default/data/stories.yml +0 -30
- rasa/cli/project_templates/default/domain.yml +0 -34
- rasa/cli/project_templates/default/tests/test_stories.yml +0 -91
- rasa/core/channels/inspector/dist/assets/channel-11268142.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-ff7f2ce7.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-cba7ae20.js +0 -1
- rasa/core/channels/inspector/src/helpers/audiostream.ts +0 -191
- rasa/core/tracker_store.py +0 -1792
- rasa/studio/download.py +0 -489
- /rasa/cli/project_templates/{calm → default}/actions/action_template.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/add_contact.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/db.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/list_contacts.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/remove_contact.py +0 -0
- /rasa/cli/project_templates/{calm → default}/data/flows/add_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/data/flows/list_contacts.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/data/flows/remove_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/db/contacts.json +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/add_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/list_contacts.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/remove_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/shared.yml +0 -0
- /rasa/{cli/project_templates/calm/actions → core/tracker_stores}/__init__.py +0 -0
- {rasa_pro-3.13.0.dev3.dist-info → rasa_pro-3.13.0.dev7.dist-info}/NOTICE +0 -0
- {rasa_pro-3.13.0.dev3.dist-info → rasa_pro-3.13.0.dev7.dist-info}/WHEEL +0 -0
- {rasa_pro-3.13.0.dev3.dist-info → rasa_pro-3.13.0.dev7.dist-info}/entry_points.txt +0 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import base64
|
|
2
4
|
import json
|
|
3
5
|
import uuid
|
|
4
|
-
from typing import Any, Awaitable, Callable, Dict, Optional, Text, Tuple
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, Optional, Text, Tuple
|
|
5
7
|
|
|
6
8
|
import structlog
|
|
7
9
|
from sanic import ( # type: ignore[attr-defined]
|
|
@@ -12,7 +14,11 @@ from sanic import ( # type: ignore[attr-defined]
|
|
|
12
14
|
response,
|
|
13
15
|
)
|
|
14
16
|
|
|
15
|
-
from rasa.core.channels import UserMessage
|
|
17
|
+
from rasa.core.channels import InputChannel, UserMessage
|
|
18
|
+
from rasa.core.channels.channel import (
|
|
19
|
+
create_auth_requested_response_provider,
|
|
20
|
+
requires_basic_auth,
|
|
21
|
+
)
|
|
16
22
|
from rasa.core.channels.voice_ready.utils import CallParameters
|
|
17
23
|
from rasa.core.channels.voice_stream.audio_bytes import RasaAudioBytes
|
|
18
24
|
from rasa.core.channels.voice_stream.call_state import call_state
|
|
@@ -25,10 +31,24 @@ from rasa.core.channels.voice_stream.voice_channel import (
|
|
|
25
31
|
VoiceInputChannel,
|
|
26
32
|
VoiceOutputChannel,
|
|
27
33
|
)
|
|
34
|
+
from rasa.shared.exceptions import RasaException
|
|
35
|
+
|
|
36
|
+
if TYPE_CHECKING:
|
|
37
|
+
from twilio.twiml.voice_response import VoiceResponse
|
|
28
38
|
|
|
29
39
|
logger = structlog.get_logger(__name__)
|
|
30
40
|
|
|
31
41
|
|
|
42
|
+
TWILIO_MEDIA_STREAMS_WEBHOOK_PATH = "webhooks/twilio_media_streams/webhook"
|
|
43
|
+
TWILIO_MEDIA_STREAMS_WEBSOCKET_PATH = "webhooks/twilio_media_streams/websocket"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
CALL_SID_REQUEST_KEY = "CallSid"
|
|
47
|
+
FROM_NUMBER_REQUEST_KEY = "From"
|
|
48
|
+
TO_NUMBER_REQUEST_KEY = "To"
|
|
49
|
+
DIRECTION_REQUEST_KEY = "Direction"
|
|
50
|
+
|
|
51
|
+
|
|
32
52
|
def map_call_params(data: Dict[Text, Any]) -> CallParameters:
|
|
33
53
|
"""Map the twilio stream parameters to the CallParameters dataclass."""
|
|
34
54
|
stream_sid = data["streamSid"]
|
|
@@ -77,6 +97,40 @@ class TwilioMediaStreamsOutputChannel(VoiceOutputChannel):
|
|
|
77
97
|
|
|
78
98
|
|
|
79
99
|
class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
100
|
+
def __init__(
|
|
101
|
+
self,
|
|
102
|
+
server_url: str,
|
|
103
|
+
asr_config: Dict,
|
|
104
|
+
tts_config: Dict,
|
|
105
|
+
monitor_silence: bool = False,
|
|
106
|
+
username: Optional[Text] = None,
|
|
107
|
+
password: Optional[Text] = None,
|
|
108
|
+
):
|
|
109
|
+
super().__init__(server_url, asr_config, tts_config, monitor_silence)
|
|
110
|
+
self.username = username
|
|
111
|
+
self.password = password
|
|
112
|
+
|
|
113
|
+
@classmethod
|
|
114
|
+
def from_credentials(cls, credentials: Optional[Dict[str, Any]]) -> InputChannel:
|
|
115
|
+
credentials = credentials or {}
|
|
116
|
+
|
|
117
|
+
username = credentials.get("username")
|
|
118
|
+
password = credentials.get("password")
|
|
119
|
+
if (username is None) != (password is None):
|
|
120
|
+
raise RasaException(
|
|
121
|
+
"In TwilioMediaStreams channel, either both username and password "
|
|
122
|
+
"or neither should be provided. "
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
return cls(
|
|
126
|
+
credentials["server_url"],
|
|
127
|
+
credentials["asr"],
|
|
128
|
+
credentials["tts"],
|
|
129
|
+
credentials.get("monitor_silence", False),
|
|
130
|
+
username=username,
|
|
131
|
+
password=password,
|
|
132
|
+
)
|
|
133
|
+
|
|
80
134
|
@classmethod
|
|
81
135
|
def name(cls) -> str:
|
|
82
136
|
return "twilio_media_streams"
|
|
@@ -130,16 +184,6 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
130
184
|
self.tts_cache,
|
|
131
185
|
)
|
|
132
186
|
|
|
133
|
-
def websocket_stream_url(self) -> str:
|
|
134
|
-
"""Returns the websocket stream URL."""
|
|
135
|
-
# depending on the config value, the url might contain http as a
|
|
136
|
-
# protocol or not - we'll make sure both work
|
|
137
|
-
if self.server_url.startswith("http"):
|
|
138
|
-
base_url = self.server_url.replace("http", "ws")
|
|
139
|
-
else:
|
|
140
|
-
base_url = f"wss://{self.server_url}"
|
|
141
|
-
return f"{base_url}/webhooks/twilio_media_streams/websocket"
|
|
142
|
-
|
|
143
187
|
def blueprint(
|
|
144
188
|
self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
|
|
145
189
|
) -> Blueprint:
|
|
@@ -151,22 +195,20 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
151
195
|
return response.json({"status": "ok"})
|
|
152
196
|
|
|
153
197
|
@blueprint.route("/webhook", methods=["POST"])
|
|
198
|
+
@requires_basic_auth(
|
|
199
|
+
username=self.username,
|
|
200
|
+
password=self.password,
|
|
201
|
+
auth_request_provider=create_auth_requested_response_provider(
|
|
202
|
+
realm=TWILIO_MEDIA_STREAMS_WEBHOOK_PATH
|
|
203
|
+
),
|
|
204
|
+
)
|
|
154
205
|
async def receive(request: Request) -> HTTPResponse:
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
voice_response = VoiceResponse()
|
|
158
|
-
start = Connect()
|
|
159
|
-
stream = start.stream(url=self.websocket_stream_url())
|
|
160
|
-
# pass information about the call to the webhook - so we can
|
|
161
|
-
# store it in the input channel
|
|
162
|
-
stream.parameter(name="call_id", value=request.form.get("CallSid", None))
|
|
163
|
-
stream.parameter(name="user_phone", value=request.form.get("From", None))
|
|
164
|
-
stream.parameter(name="bot_phone", value=request.form.get("To", None))
|
|
165
|
-
stream.parameter(
|
|
166
|
-
name="direction", value=request.form.get("Direction", None)
|
|
167
|
-
)
|
|
206
|
+
voice_response = self._build_twilio_response(request)
|
|
168
207
|
|
|
169
|
-
|
|
208
|
+
logger.debug(
|
|
209
|
+
"twilio_media_streams.webhook.twilio_response",
|
|
210
|
+
twilio_response=str(voice_response),
|
|
211
|
+
)
|
|
170
212
|
|
|
171
213
|
return response.text(str(voice_response), content_type="text/xml")
|
|
172
214
|
|
|
@@ -175,3 +217,36 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
175
217
|
await self.run_audio_streaming(on_new_message, ws)
|
|
176
218
|
|
|
177
219
|
return blueprint
|
|
220
|
+
|
|
221
|
+
def _websocket_stream_url(self) -> str:
|
|
222
|
+
"""Returns the websocket stream URL."""
|
|
223
|
+
# depending on the config value, the url might contain http as a
|
|
224
|
+
# protocol or not - we'll make sure both work
|
|
225
|
+
if self.server_url.startswith("http"):
|
|
226
|
+
base_url = self.server_url.replace("http", "ws")
|
|
227
|
+
else:
|
|
228
|
+
base_url = f"wss://{self.server_url}"
|
|
229
|
+
return f"{base_url}/{TWILIO_MEDIA_STREAMS_WEBSOCKET_PATH}"
|
|
230
|
+
|
|
231
|
+
def _build_twilio_response(self, request: Request) -> VoiceResponse:
|
|
232
|
+
from twilio.twiml.voice_response import Connect, VoiceResponse
|
|
233
|
+
|
|
234
|
+
voice_response = VoiceResponse()
|
|
235
|
+
start = Connect()
|
|
236
|
+
stream = start.stream(url=self._websocket_stream_url())
|
|
237
|
+
# pass information about the call to the webhook - so we can
|
|
238
|
+
# store it in the input channel
|
|
239
|
+
stream.parameter(
|
|
240
|
+
name="call_id", value=request.form.get(CALL_SID_REQUEST_KEY, None)
|
|
241
|
+
)
|
|
242
|
+
stream.parameter(
|
|
243
|
+
name="user_phone", value=request.form.get(FROM_NUMBER_REQUEST_KEY, None)
|
|
244
|
+
)
|
|
245
|
+
stream.parameter(
|
|
246
|
+
name="bot_phone", value=request.form.get(TO_NUMBER_REQUEST_KEY, None)
|
|
247
|
+
)
|
|
248
|
+
stream.parameter(
|
|
249
|
+
name="direction", value=request.form.get(DIRECTION_REQUEST_KEY, None)
|
|
250
|
+
)
|
|
251
|
+
voice_response.append(start)
|
|
252
|
+
return voice_response
|
|
@@ -42,6 +42,11 @@ from rasa.utils.io import remove_emojis
|
|
|
42
42
|
|
|
43
43
|
logger = structlog.get_logger(__name__)
|
|
44
44
|
|
|
45
|
+
# define constants for the voice channel
|
|
46
|
+
USER_CONVERSATION_SESSION_END = "/session_end"
|
|
47
|
+
USER_CONVERSATION_SESSION_START = "/session_start"
|
|
48
|
+
USER_CONVERSATION_SILENCE_TIMEOUT = "/silence_timeout"
|
|
49
|
+
|
|
45
50
|
|
|
46
51
|
@dataclass
|
|
47
52
|
class VoiceChannelAction:
|
|
@@ -189,6 +194,7 @@ class VoiceOutputChannel(OutputChannel):
|
|
|
189
194
|
collected_audio_bytes = RasaAudioBytes(b"")
|
|
190
195
|
seconds_marker = -1
|
|
191
196
|
last_sent_offset = 0
|
|
197
|
+
logger.debug("voice_channel.sending_audio", text=text)
|
|
192
198
|
|
|
193
199
|
# Send start marker before first chunk
|
|
194
200
|
try:
|
|
@@ -334,7 +340,7 @@ class VoiceInputChannel(InputChannel):
|
|
|
334
340
|
) -> None:
|
|
335
341
|
output_channel = self.create_output_channel(channel_websocket, tts_engine)
|
|
336
342
|
message = UserMessage(
|
|
337
|
-
|
|
343
|
+
USER_CONVERSATION_SESSION_START,
|
|
338
344
|
output_channel,
|
|
339
345
|
call_parameters.stream_id,
|
|
340
346
|
input_channel=self.name(),
|
|
@@ -393,6 +399,9 @@ class VoiceInputChannel(InputChannel):
|
|
|
393
399
|
await asr_engine.send_audio_chunks(channel_action.audio_bytes)
|
|
394
400
|
elif isinstance(channel_action, EndConversationAction):
|
|
395
401
|
# end stream event came from the other side
|
|
402
|
+
await self.handle_disconnect(
|
|
403
|
+
channel_websocket, on_new_message, tts_engine, call_parameters
|
|
404
|
+
)
|
|
396
405
|
break
|
|
397
406
|
|
|
398
407
|
async def receive_asr_events() -> None:
|
|
@@ -462,10 +471,27 @@ class VoiceInputChannel(InputChannel):
|
|
|
462
471
|
elif isinstance(e, UserSilence):
|
|
463
472
|
output_channel = self.create_output_channel(voice_websocket, tts_engine)
|
|
464
473
|
message = UserMessage(
|
|
465
|
-
|
|
474
|
+
USER_CONVERSATION_SILENCE_TIMEOUT,
|
|
466
475
|
output_channel,
|
|
467
476
|
call_parameters.stream_id,
|
|
468
477
|
input_channel=self.name(),
|
|
469
478
|
metadata=asdict(call_parameters),
|
|
470
479
|
)
|
|
471
480
|
await on_new_message(message)
|
|
481
|
+
|
|
482
|
+
async def handle_disconnect(
|
|
483
|
+
self,
|
|
484
|
+
channel_websocket: Websocket,
|
|
485
|
+
on_new_message: Callable[[UserMessage], Awaitable[Any]],
|
|
486
|
+
tts_engine: TTSEngine,
|
|
487
|
+
call_parameters: CallParameters,
|
|
488
|
+
) -> None:
|
|
489
|
+
"""Handle disconnection from the channel."""
|
|
490
|
+
output_channel = self.create_output_channel(channel_websocket, tts_engine)
|
|
491
|
+
message = UserMessage(
|
|
492
|
+
text=USER_CONVERSATION_SESSION_END,
|
|
493
|
+
output_channel=output_channel,
|
|
494
|
+
sender_id=call_parameters.stream_id,
|
|
495
|
+
input_channel=self.name(),
|
|
496
|
+
)
|
|
497
|
+
await on_new_message(message)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import json
|
|
2
|
-
import logging
|
|
3
2
|
import time
|
|
4
3
|
from collections import deque
|
|
5
4
|
from typing import Deque, Optional, Text
|
|
6
5
|
|
|
6
|
+
import structlog
|
|
7
|
+
|
|
7
8
|
from rasa.core.lock import Ticket, TicketLock
|
|
8
9
|
from rasa.core.lock_store import (
|
|
9
10
|
DEFAULT_SOCKET_TIMEOUT_IN_SECONDS,
|
|
@@ -19,7 +20,7 @@ DEFAULT_PORT = 6379
|
|
|
19
20
|
|
|
20
21
|
DEFAULT_HOSTNAME = "localhost"
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
structlogger = structlog.getLogger(__name__)
|
|
23
24
|
|
|
24
25
|
LAST_ISSUED_TICKET_NUMBER_SUFFIX = "last_issued_ticket_number"
|
|
25
26
|
|
|
@@ -105,7 +106,10 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
105
106
|
|
|
106
107
|
self.key_prefix = DEFAULT_CONCURRENT_REDIS_LOCK_STORE_KEY_PREFIX
|
|
107
108
|
if key_prefix:
|
|
108
|
-
|
|
109
|
+
structlogger.debug(
|
|
110
|
+
"concurrent_redis_lock_store._set_key_prefix.non_default_key_prefix",
|
|
111
|
+
event_info=f"Setting non-default redis key prefix: '{key_prefix}'.",
|
|
112
|
+
)
|
|
109
113
|
self._set_key_prefix(key_prefix)
|
|
110
114
|
|
|
111
115
|
super().__init__()
|
|
@@ -116,9 +120,13 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
116
120
|
key_prefix + ":" + DEFAULT_CONCURRENT_REDIS_LOCK_STORE_KEY_PREFIX
|
|
117
121
|
)
|
|
118
122
|
else:
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
123
|
+
structlogger.warning(
|
|
124
|
+
"concurrent_redis_lock_store._set_key_prefix.default_instead_of_invalid_key_prefix",
|
|
125
|
+
event_info=(
|
|
126
|
+
f"Omitting provided non-alphanumeric "
|
|
127
|
+
f"redis key prefix: '{key_prefix}'. "
|
|
128
|
+
f"Using default '{self.key_prefix}' instead."
|
|
129
|
+
),
|
|
122
130
|
)
|
|
123
131
|
|
|
124
132
|
def issue_ticket(
|
|
@@ -129,7 +137,10 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
129
137
|
It's configured with `lock_lifetime` and associated with `conversation_id`.
|
|
130
138
|
Creates a new lock if none is found.
|
|
131
139
|
"""
|
|
132
|
-
|
|
140
|
+
structlogger.debug(
|
|
141
|
+
"concurrent_redis_lock_store.issue_ticket",
|
|
142
|
+
event_info=f"Issuing ticket for conversation '{conversation_id}'.",
|
|
143
|
+
)
|
|
133
144
|
try:
|
|
134
145
|
lock = self.get_or_create_lock(conversation_id)
|
|
135
146
|
lock.remove_expired_tickets()
|
|
@@ -164,9 +175,12 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
164
175
|
redis_keys = self.red.keys(pattern)
|
|
165
176
|
|
|
166
177
|
if not redis_keys:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
178
|
+
structlogger.debug(
|
|
179
|
+
"concurrent_redis_lock_store.delete_lock_key_not_found",
|
|
180
|
+
event_info=(
|
|
181
|
+
f"The lock store does not contain any key-value "
|
|
182
|
+
f"items for conversation '{conversation_id}'."
|
|
183
|
+
),
|
|
170
184
|
)
|
|
171
185
|
return None
|
|
172
186
|
|
|
@@ -2,7 +2,7 @@ import random
|
|
|
2
2
|
from typing import Any, AsyncIterator, Iterable, List, Optional, Text
|
|
3
3
|
|
|
4
4
|
import rasa.shared.utils.io
|
|
5
|
-
from rasa.core.tracker_store import TrackerStore
|
|
5
|
+
from rasa.core.tracker_stores.tracker_store import TrackerStore
|
|
6
6
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
7
7
|
from rasa.shared.exceptions import RasaException
|
|
8
8
|
|
rasa/core/exporter.py
CHANGED
|
@@ -10,7 +10,7 @@ import rasa.shared.utils.io
|
|
|
10
10
|
from rasa.core.brokers.broker import EventBroker
|
|
11
11
|
from rasa.core.brokers.pika import PikaEventBroker
|
|
12
12
|
from rasa.core.constants import RASA_EXPORT_PROCESS_ID_HEADER_NAME
|
|
13
|
-
from rasa.core.tracker_store import TrackerStore
|
|
13
|
+
from rasa.core.tracker_stores.tracker_store import TrackerStore
|
|
14
14
|
from rasa.exceptions import (
|
|
15
15
|
NoConversationsInTrackerStoreError,
|
|
16
16
|
NoEventsToMigrateError,
|
rasa/core/lock_store.py
CHANGED
|
@@ -2,18 +2,27 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import json
|
|
5
|
-
import logging
|
|
6
5
|
import os
|
|
7
6
|
from contextlib import asynccontextmanager
|
|
8
|
-
from typing import AsyncGenerator, Dict, Optional, Text, Union
|
|
7
|
+
from typing import Any, AsyncGenerator, Dict, Literal, Optional, Text, Union
|
|
8
|
+
|
|
9
|
+
import structlog
|
|
10
|
+
from pydantic import (
|
|
11
|
+
AnyUrl,
|
|
12
|
+
BaseModel,
|
|
13
|
+
Field,
|
|
14
|
+
NonNegativeInt,
|
|
15
|
+
model_validator,
|
|
16
|
+
)
|
|
9
17
|
|
|
10
18
|
import rasa.shared.utils.common
|
|
11
19
|
from rasa.core.constants import DEFAULT_LOCK_LIFETIME
|
|
12
20
|
from rasa.core.lock import TicketLock
|
|
13
21
|
from rasa.shared.exceptions import ConnectionException, RasaException
|
|
22
|
+
from rasa.shared.utils.io import raise_deprecation_warning
|
|
14
23
|
from rasa.utils.endpoints import EndpointConfig
|
|
15
24
|
|
|
16
|
-
|
|
25
|
+
structlogger = structlog.getLogger(__name__)
|
|
17
26
|
|
|
18
27
|
|
|
19
28
|
def _get_lock_lifetime() -> int:
|
|
@@ -76,7 +85,10 @@ class LockStore:
|
|
|
76
85
|
|
|
77
86
|
Creates a new lock if none is found.
|
|
78
87
|
"""
|
|
79
|
-
|
|
88
|
+
structlogger.debug(
|
|
89
|
+
"lock_store.issue_ticket",
|
|
90
|
+
event_info=f"Issuing ticket for conversation '{conversation_id}'.",
|
|
91
|
+
)
|
|
80
92
|
try:
|
|
81
93
|
lock = self.get_or_create_lock(conversation_id)
|
|
82
94
|
ticket = lock.issue_ticket(lock_lifetime)
|
|
@@ -109,7 +121,10 @@ class LockStore:
|
|
|
109
121
|
async def _acquire_lock(
|
|
110
122
|
self, conversation_id: Text, ticket: int, wait_time_in_seconds: float
|
|
111
123
|
) -> TicketLock:
|
|
112
|
-
|
|
124
|
+
structlogger.debug(
|
|
125
|
+
"lock_store._acquiring_lock_for_conversation",
|
|
126
|
+
event_info=f"Acquiring lock for conversation '{conversation_id}'.",
|
|
127
|
+
)
|
|
113
128
|
while True:
|
|
114
129
|
# fetch lock in every iteration because lock might no longer exist
|
|
115
130
|
lock = self.get_lock(conversation_id)
|
|
@@ -120,16 +135,22 @@ class LockStore:
|
|
|
120
135
|
|
|
121
136
|
# acquire lock if it isn't locked
|
|
122
137
|
if not lock.is_locked(ticket):
|
|
123
|
-
|
|
138
|
+
structlogger.debug(
|
|
139
|
+
"lock_store._acquired_lock_for_conversation",
|
|
140
|
+
event_info=f"Acquired lock for conversation '{conversation_id}'.",
|
|
141
|
+
)
|
|
124
142
|
return lock
|
|
125
143
|
|
|
126
144
|
items_before_this = ticket - (lock.now_serving or 0)
|
|
127
145
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
146
|
+
structlogger.debug(
|
|
147
|
+
"lock_store._retrying_lock_acquisition",
|
|
148
|
+
event_info=(
|
|
149
|
+
f"Failed to acquire lock for conversation ID '{conversation_id}' "
|
|
150
|
+
f"because {items_before_this} other item(s) for this "
|
|
151
|
+
f"conversation ID have to be finished processing first. "
|
|
152
|
+
f"Retrying in {wait_time_in_seconds} seconds ..."
|
|
153
|
+
),
|
|
133
154
|
)
|
|
134
155
|
|
|
135
156
|
# sleep and update lock
|
|
@@ -186,9 +207,99 @@ class LockStore:
|
|
|
186
207
|
@staticmethod
|
|
187
208
|
def _log_deletion(conversation_id: Text, deletion_successful: bool) -> None:
|
|
188
209
|
if deletion_successful:
|
|
189
|
-
|
|
210
|
+
structlogger.debug(
|
|
211
|
+
"lock_store._deleted_lock_for_conversation",
|
|
212
|
+
event_info=f"Deleted lock for conversation '{conversation_id}'.",
|
|
213
|
+
)
|
|
190
214
|
else:
|
|
191
|
-
|
|
215
|
+
structlogger.debug(
|
|
216
|
+
"lock_store._failed_to_delete_lock_for_conversation",
|
|
217
|
+
event_info=(
|
|
218
|
+
f"Could not delete lock for conversation '{conversation_id}'."
|
|
219
|
+
),
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class RedisLockStoreConfig(BaseModel):
|
|
224
|
+
host: Union[AnyUrl, Literal["localhost"]] = Field(
|
|
225
|
+
default="localhost", description="The host of the redis server."
|
|
226
|
+
)
|
|
227
|
+
port: NonNegativeInt = Field(
|
|
228
|
+
default=6379, ge=0, le=65535, description="The port of the redis server."
|
|
229
|
+
)
|
|
230
|
+
db: NonNegativeInt = Field(
|
|
231
|
+
default=0,
|
|
232
|
+
ge=0,
|
|
233
|
+
description="The name of the database within Redis "
|
|
234
|
+
"which should be used by Rasa",
|
|
235
|
+
)
|
|
236
|
+
username: Optional[str] = Field(
|
|
237
|
+
default=None,
|
|
238
|
+
description="The username which should be used for "
|
|
239
|
+
"authentication with the Redis database.",
|
|
240
|
+
)
|
|
241
|
+
password: Optional[str] = Field(
|
|
242
|
+
default=None,
|
|
243
|
+
description="The username which should be used for "
|
|
244
|
+
"authentication with the Redis database.",
|
|
245
|
+
)
|
|
246
|
+
use_ssl: bool = Field(
|
|
247
|
+
default=False,
|
|
248
|
+
serialization_alias="ssl",
|
|
249
|
+
description="True if SSL should be used for the connection to Redis.",
|
|
250
|
+
)
|
|
251
|
+
ssl_certfile: Optional[str] = Field(
|
|
252
|
+
default=None,
|
|
253
|
+
description="Path to the SSL certificate file.",
|
|
254
|
+
)
|
|
255
|
+
ssl_keyfile: Optional[str] = Field(
|
|
256
|
+
default=None, description="Path to the SSL private key file."
|
|
257
|
+
)
|
|
258
|
+
ssl_ca_certs: Optional[str] = Field(
|
|
259
|
+
default=None, description="Path to the SSL CA certificate file."
|
|
260
|
+
)
|
|
261
|
+
key_prefix: Optional[str] = Field(
|
|
262
|
+
default=None,
|
|
263
|
+
description="Prefix to prepend to all keys "
|
|
264
|
+
"used by the lock store. Must be alphanumeric.",
|
|
265
|
+
)
|
|
266
|
+
socket_timeout: float = Field(
|
|
267
|
+
default=DEFAULT_SOCKET_TIMEOUT_IN_SECONDS,
|
|
268
|
+
description="Timeout in seconds after which an exception "
|
|
269
|
+
"will be raised in case Redis doesn't respond "
|
|
270
|
+
"within `socket_timeout` seconds.",
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
@model_validator(mode="before")
|
|
274
|
+
@classmethod
|
|
275
|
+
def validate_url_and_host_properties(cls, data: Any) -> Any:
|
|
276
|
+
if isinstance(data, dict):
|
|
277
|
+
if bool(data.get("url", None)) and bool(data.get("host", None)):
|
|
278
|
+
raise RasaException(
|
|
279
|
+
"You cannot specify both 'url' and 'host' in the Redis lock store "
|
|
280
|
+
"configuration. Please use only one of them."
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
if data.get("url", None):
|
|
284
|
+
raise_deprecation_warning(
|
|
285
|
+
"The 'url' property in the redis lock store "
|
|
286
|
+
"configuration is deprecated. Please use 'host' instead."
|
|
287
|
+
)
|
|
288
|
+
data["host"] = data.pop("url")
|
|
289
|
+
return data
|
|
290
|
+
|
|
291
|
+
@model_validator(mode="after")
|
|
292
|
+
def verify_username_password(self) -> RedisLockStoreConfig:
|
|
293
|
+
if bool(self.username) ^ bool(self.password):
|
|
294
|
+
raise ValueError(
|
|
295
|
+
f"Expected username and password. "
|
|
296
|
+
f"Found: username: {'<has value>' if self.username else '<N/A>'}, "
|
|
297
|
+
f"password: {'<has value>' if self.password else '<N/A>'}"
|
|
298
|
+
)
|
|
299
|
+
return self
|
|
300
|
+
|
|
301
|
+
def to_strict_redis(self) -> Dict[str, Any]:
|
|
302
|
+
return self.model_dump(by_alias=True, exclude={"key_prefix"})
|
|
192
303
|
|
|
193
304
|
|
|
194
305
|
class RedisLockStore(LockStore):
|
|
@@ -196,57 +307,28 @@ class RedisLockStore(LockStore):
|
|
|
196
307
|
|
|
197
308
|
def __init__(
|
|
198
309
|
self,
|
|
199
|
-
|
|
200
|
-
port: int = 6379,
|
|
201
|
-
db: int = 1,
|
|
202
|
-
username: Optional[Text] = None,
|
|
203
|
-
password: Optional[Text] = None,
|
|
204
|
-
use_ssl: bool = False,
|
|
205
|
-
ssl_certfile: Optional[Text] = None,
|
|
206
|
-
ssl_keyfile: Optional[Text] = None,
|
|
207
|
-
ssl_ca_certs: Optional[Text] = None,
|
|
208
|
-
key_prefix: Optional[Text] = None,
|
|
209
|
-
socket_timeout: float = DEFAULT_SOCKET_TIMEOUT_IN_SECONDS,
|
|
310
|
+
config: RedisLockStoreConfig = RedisLockStoreConfig(),
|
|
210
311
|
) -> None:
|
|
211
312
|
"""Create a lock store which uses Redis for persistence.
|
|
212
313
|
|
|
213
314
|
Args:
|
|
214
|
-
|
|
215
|
-
port: The port of the redis server.
|
|
216
|
-
db: The name of the database within Redis which should be used by Rasa
|
|
217
|
-
Open Source.
|
|
218
|
-
username: The username which should be used for authentication with the
|
|
219
|
-
Redis database.
|
|
220
|
-
password: The password which should be used for authentication with the
|
|
221
|
-
Redis database.
|
|
222
|
-
use_ssl: `True` if SSL should be used for the connection to Redis.
|
|
223
|
-
ssl_certfile: Path to the SSL certificate file.
|
|
224
|
-
ssl_keyfile: Path to the SSL private key file.
|
|
225
|
-
ssl_ca_certs: Path to the SSL CA certificate file.
|
|
226
|
-
key_prefix: prefix to prepend to all keys used by the lock store. Must be
|
|
227
|
-
alphanumeric.
|
|
228
|
-
socket_timeout: Timeout in seconds after which an exception will be raised
|
|
229
|
-
in case Redis doesn't respond within `socket_timeout` seconds.
|
|
315
|
+
config: Redis lock store configuration.
|
|
230
316
|
"""
|
|
231
317
|
import redis
|
|
232
318
|
|
|
233
|
-
self.
|
|
234
|
-
|
|
235
|
-
port=int(port),
|
|
236
|
-
db=int(db),
|
|
237
|
-
username=username,
|
|
238
|
-
password=password,
|
|
239
|
-
ssl=use_ssl,
|
|
240
|
-
ssl_certfile=ssl_certfile,
|
|
241
|
-
ssl_keyfile=ssl_keyfile,
|
|
242
|
-
ssl_ca_certs=ssl_ca_certs,
|
|
243
|
-
socket_timeout=socket_timeout,
|
|
244
|
-
)
|
|
319
|
+
self.config = config
|
|
320
|
+
self.red = redis.StrictRedis(**self.config.to_strict_redis())
|
|
245
321
|
|
|
246
322
|
self.key_prefix = DEFAULT_REDIS_LOCK_STORE_KEY_PREFIX
|
|
247
|
-
if key_prefix:
|
|
248
|
-
|
|
249
|
-
|
|
323
|
+
if self.config.key_prefix:
|
|
324
|
+
structlogger.debug(
|
|
325
|
+
"redis_lock_store._set_key_prefix.non_default_key_prefix",
|
|
326
|
+
event_info=(
|
|
327
|
+
f"Setting non-default "
|
|
328
|
+
f"redis key prefix: '{self.config.key_prefix}'.",
|
|
329
|
+
),
|
|
330
|
+
)
|
|
331
|
+
self._set_key_prefix(self.config.key_prefix)
|
|
250
332
|
|
|
251
333
|
super().__init__()
|
|
252
334
|
|
|
@@ -254,9 +336,13 @@ class RedisLockStore(LockStore):
|
|
|
254
336
|
if isinstance(key_prefix, str) and key_prefix.isalnum():
|
|
255
337
|
self.key_prefix = key_prefix + ":" + DEFAULT_REDIS_LOCK_STORE_KEY_PREFIX
|
|
256
338
|
else:
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
339
|
+
structlogger.warning(
|
|
340
|
+
"redis_lock_store._set_key_prefix.default_instead_of_invalid_key_prefix",
|
|
341
|
+
event_info=(
|
|
342
|
+
f"Omitting provided non-alphanumeric "
|
|
343
|
+
f"redis key prefix: '{key_prefix}'. "
|
|
344
|
+
f"Using default '{self.key_prefix}' instead."
|
|
345
|
+
),
|
|
260
346
|
)
|
|
261
347
|
|
|
262
348
|
def get_lock(self, conversation_id: Text) -> Optional[TicketLock]:
|
|
@@ -313,7 +399,9 @@ def _create_from_endpoint_config(
|
|
|
313
399
|
|
|
314
400
|
lock_store: LockStore = InMemoryLockStore()
|
|
315
401
|
elif endpoint_config.type == "redis":
|
|
316
|
-
|
|
402
|
+
config = RedisLockStoreConfig.model_validate(endpoint_config.to_dict())
|
|
403
|
+
|
|
404
|
+
lock_store = RedisLockStore(config)
|
|
317
405
|
elif endpoint_config.type == "concurrent_redis":
|
|
318
406
|
from rasa.core.concurrent_lock_store import ConcurrentRedisLockStore
|
|
319
407
|
|
|
@@ -321,7 +409,10 @@ def _create_from_endpoint_config(
|
|
|
321
409
|
else:
|
|
322
410
|
lock_store = _load_from_module_name_in_endpoint_config(endpoint_config)
|
|
323
411
|
|
|
324
|
-
|
|
412
|
+
structlogger.debug(
|
|
413
|
+
"lock_store._create_from_endpoint_config.lock_store_connected",
|
|
414
|
+
event_info=f"Connected to lock store '{lock_store.__class__.__name__}'.",
|
|
415
|
+
)
|
|
325
416
|
|
|
326
417
|
return lock_store
|
|
327
418
|
|
|
@@ -8,12 +8,14 @@ from rasa.core.nlg.response import TemplatedNaturalLanguageGenerator
|
|
|
8
8
|
from rasa.core.nlg.summarize import summarize_conversation
|
|
9
9
|
from rasa.shared.constants import (
|
|
10
10
|
LLM_CONFIG_KEY,
|
|
11
|
+
MAX_COMPLETION_TOKENS_CONFIG_KEY,
|
|
11
12
|
MODEL_CONFIG_KEY,
|
|
12
13
|
MODEL_GROUP_ID_CONFIG_KEY,
|
|
13
14
|
MODEL_NAME_CONFIG_KEY,
|
|
14
15
|
OPENAI_PROVIDER,
|
|
15
16
|
PROMPT_CONFIG_KEY,
|
|
16
17
|
PROVIDER_CONFIG_KEY,
|
|
18
|
+
TEMPERATURE_CONFIG_KEY,
|
|
17
19
|
TIMEOUT_CONFIG_KEY,
|
|
18
20
|
)
|
|
19
21
|
from rasa.shared.core.domain import KEY_RESPONSES_TEXT, Domain
|
|
@@ -57,8 +59,8 @@ DEFAULT_MAX_HISTORICAL_TURNS = 5
|
|
|
57
59
|
DEFAULT_LLM_CONFIG = {
|
|
58
60
|
PROVIDER_CONFIG_KEY: OPENAI_PROVIDER,
|
|
59
61
|
MODEL_CONFIG_KEY: DEFAULT_OPENAI_GENERATE_MODEL_NAME,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
TEMPERATURE_CONFIG_KEY: 0.3,
|
|
63
|
+
MAX_COMPLETION_TOKENS_CONFIG_KEY: DEFAULT_OPENAI_MAX_GENERATED_TOKENS,
|
|
62
64
|
TIMEOUT_CONFIG_KEY: 5,
|
|
63
65
|
}
|
|
64
66
|
|
rasa/core/nlg/summarize.py
CHANGED
|
@@ -3,7 +3,7 @@ from typing import Optional
|
|
|
3
3
|
import structlog
|
|
4
4
|
from jinja2 import Template
|
|
5
5
|
|
|
6
|
-
from rasa.core.
|
|
6
|
+
from rasa.shared.core.trackers import DialogueStateTracker
|
|
7
7
|
from rasa.shared.providers.llm.llm_client import LLMClient
|
|
8
8
|
from rasa.shared.utils.llm import (
|
|
9
9
|
tracker_as_readable_transcript,
|