rasa-pro 3.9.18__py3-none-any.whl → 3.10.16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rasa-pro might be problematic. Click here for more details.
- README.md +0 -374
- rasa/__init__.py +1 -2
- rasa/__main__.py +5 -0
- rasa/anonymization/anonymization_rule_executor.py +2 -2
- rasa/api.py +27 -23
- rasa/cli/arguments/data.py +27 -2
- rasa/cli/arguments/default_arguments.py +25 -3
- rasa/cli/arguments/run.py +9 -9
- rasa/cli/arguments/train.py +11 -3
- rasa/cli/data.py +70 -8
- rasa/cli/e2e_test.py +104 -431
- rasa/cli/evaluate.py +1 -1
- rasa/cli/interactive.py +1 -0
- rasa/cli/llm_fine_tuning.py +398 -0
- rasa/cli/project_templates/calm/endpoints.yml +1 -1
- rasa/cli/project_templates/tutorial/endpoints.yml +1 -1
- rasa/cli/run.py +15 -14
- rasa/cli/scaffold.py +10 -8
- rasa/cli/studio/studio.py +35 -5
- rasa/cli/train.py +56 -8
- rasa/cli/utils.py +22 -5
- rasa/cli/x.py +1 -1
- rasa/constants.py +7 -1
- rasa/core/actions/action.py +98 -49
- rasa/core/actions/action_run_slot_rejections.py +4 -1
- rasa/core/actions/custom_action_executor.py +9 -6
- rasa/core/actions/direct_custom_actions_executor.py +80 -0
- rasa/core/actions/e2e_stub_custom_action_executor.py +68 -0
- rasa/core/actions/grpc_custom_action_executor.py +2 -2
- rasa/core/actions/http_custom_action_executor.py +6 -5
- rasa/core/agent.py +21 -17
- rasa/core/channels/__init__.py +2 -0
- rasa/core/channels/audiocodes.py +1 -16
- rasa/core/channels/voice_aware/__init__.py +0 -0
- rasa/core/channels/voice_aware/jambonz.py +103 -0
- rasa/core/channels/voice_aware/jambonz_protocol.py +344 -0
- rasa/core/channels/voice_aware/utils.py +20 -0
- rasa/core/channels/voice_native/__init__.py +0 -0
- rasa/core/constants.py +6 -1
- rasa/core/information_retrieval/faiss.py +7 -4
- rasa/core/information_retrieval/information_retrieval.py +8 -0
- rasa/core/information_retrieval/milvus.py +9 -2
- rasa/core/information_retrieval/qdrant.py +1 -1
- rasa/core/nlg/contextual_response_rephraser.py +32 -10
- rasa/core/nlg/summarize.py +4 -3
- rasa/core/policies/enterprise_search_policy.py +113 -45
- rasa/core/policies/flows/flow_executor.py +122 -76
- rasa/core/policies/intentless_policy.py +83 -29
- rasa/core/processor.py +72 -54
- rasa/core/run.py +5 -4
- rasa/core/tracker_store.py +8 -4
- rasa/core/training/interactive.py +1 -1
- rasa/core/utils.py +56 -57
- rasa/dialogue_understanding/coexistence/llm_based_router.py +53 -13
- rasa/dialogue_understanding/commands/__init__.py +6 -0
- rasa/dialogue_understanding/commands/restart_command.py +58 -0
- rasa/dialogue_understanding/commands/session_start_command.py +59 -0
- rasa/dialogue_understanding/commands/utils.py +40 -0
- rasa/dialogue_understanding/generator/constants.py +10 -3
- rasa/dialogue_understanding/generator/flow_retrieval.py +21 -5
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +13 -3
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +134 -90
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +47 -7
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +127 -41
- rasa/dialogue_understanding/patterns/restart.py +37 -0
- rasa/dialogue_understanding/patterns/session_start.py +37 -0
- rasa/dialogue_understanding/processor/command_processor.py +16 -3
- rasa/dialogue_understanding/processor/command_processor_component.py +6 -2
- rasa/e2e_test/aggregate_test_stats_calculator.py +134 -0
- rasa/e2e_test/assertions.py +1223 -0
- rasa/e2e_test/assertions_schema.yml +106 -0
- rasa/e2e_test/constants.py +20 -0
- rasa/e2e_test/e2e_config.py +220 -0
- rasa/e2e_test/e2e_config_schema.yml +26 -0
- rasa/e2e_test/e2e_test_case.py +131 -8
- rasa/e2e_test/e2e_test_converter.py +363 -0
- rasa/e2e_test/e2e_test_converter_prompt.jinja2 +70 -0
- rasa/e2e_test/e2e_test_coverage_report.py +364 -0
- rasa/e2e_test/e2e_test_result.py +26 -6
- rasa/e2e_test/e2e_test_runner.py +493 -71
- rasa/e2e_test/e2e_test_schema.yml +96 -0
- rasa/e2e_test/pykwalify_extensions.py +39 -0
- rasa/e2e_test/stub_custom_action.py +70 -0
- rasa/e2e_test/utils/__init__.py +0 -0
- rasa/e2e_test/utils/e2e_yaml_utils.py +55 -0
- rasa/e2e_test/utils/io.py +598 -0
- rasa/e2e_test/utils/validation.py +80 -0
- rasa/engine/graph.py +9 -3
- rasa/engine/recipes/default_components.py +0 -2
- rasa/engine/recipes/default_recipe.py +10 -2
- rasa/engine/storage/local_model_storage.py +40 -12
- rasa/engine/validation.py +78 -1
- rasa/env.py +9 -0
- rasa/graph_components/providers/story_graph_provider.py +59 -6
- rasa/llm_fine_tuning/__init__.py +0 -0
- rasa/llm_fine_tuning/annotation_module.py +241 -0
- rasa/llm_fine_tuning/conversations.py +144 -0
- rasa/llm_fine_tuning/llm_data_preparation_module.py +178 -0
- rasa/llm_fine_tuning/notebooks/unsloth_finetuning.ipynb +407 -0
- rasa/llm_fine_tuning/paraphrasing/__init__.py +0 -0
- rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +281 -0
- rasa/llm_fine_tuning/paraphrasing/default_rephrase_prompt_template.jina2 +44 -0
- rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +121 -0
- rasa/llm_fine_tuning/paraphrasing/rephrased_user_message.py +10 -0
- rasa/llm_fine_tuning/paraphrasing_module.py +128 -0
- rasa/llm_fine_tuning/storage.py +174 -0
- rasa/llm_fine_tuning/train_test_split_module.py +441 -0
- rasa/model_training.py +56 -16
- rasa/nlu/persistor.py +157 -36
- rasa/server.py +45 -10
- rasa/shared/constants.py +76 -16
- rasa/shared/core/domain.py +27 -19
- rasa/shared/core/events.py +28 -2
- rasa/shared/core/flows/flow.py +208 -13
- rasa/shared/core/flows/flow_path.py +84 -0
- rasa/shared/core/flows/flows_list.py +33 -11
- rasa/shared/core/flows/flows_yaml_schema.json +269 -193
- rasa/shared/core/flows/validation.py +112 -25
- rasa/shared/core/flows/yaml_flows_io.py +149 -10
- rasa/shared/core/trackers.py +6 -0
- rasa/shared/core/training_data/structures.py +20 -0
- rasa/shared/core/training_data/visualization.html +2 -2
- rasa/shared/exceptions.py +4 -0
- rasa/shared/importers/importer.py +64 -16
- rasa/shared/nlu/constants.py +2 -0
- rasa/shared/providers/_configs/__init__.py +0 -0
- rasa/shared/providers/_configs/azure_openai_client_config.py +183 -0
- rasa/shared/providers/_configs/client_config.py +57 -0
- rasa/shared/providers/_configs/default_litellm_client_config.py +130 -0
- rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +234 -0
- rasa/shared/providers/_configs/openai_client_config.py +175 -0
- rasa/shared/providers/_configs/self_hosted_llm_client_config.py +176 -0
- rasa/shared/providers/_configs/utils.py +101 -0
- rasa/shared/providers/_ssl_verification_utils.py +124 -0
- rasa/shared/providers/embedding/__init__.py +0 -0
- rasa/shared/providers/embedding/_base_litellm_embedding_client.py +259 -0
- rasa/shared/providers/embedding/_langchain_embedding_client_adapter.py +74 -0
- rasa/shared/providers/embedding/azure_openai_embedding_client.py +277 -0
- rasa/shared/providers/embedding/default_litellm_embedding_client.py +102 -0
- rasa/shared/providers/embedding/embedding_client.py +90 -0
- rasa/shared/providers/embedding/embedding_response.py +41 -0
- rasa/shared/providers/embedding/huggingface_local_embedding_client.py +191 -0
- rasa/shared/providers/embedding/openai_embedding_client.py +172 -0
- rasa/shared/providers/llm/__init__.py +0 -0
- rasa/shared/providers/llm/_base_litellm_client.py +251 -0
- rasa/shared/providers/llm/azure_openai_llm_client.py +338 -0
- rasa/shared/providers/llm/default_litellm_llm_client.py +84 -0
- rasa/shared/providers/llm/llm_client.py +76 -0
- rasa/shared/providers/llm/llm_response.py +50 -0
- rasa/shared/providers/llm/openai_llm_client.py +155 -0
- rasa/shared/providers/llm/self_hosted_llm_client.py +293 -0
- rasa/shared/providers/mappings.py +75 -0
- rasa/shared/utils/cli.py +30 -0
- rasa/shared/utils/io.py +65 -2
- rasa/shared/utils/llm.py +246 -200
- rasa/shared/utils/yaml.py +121 -15
- rasa/studio/auth.py +6 -4
- rasa/studio/config.py +13 -4
- rasa/studio/constants.py +1 -0
- rasa/studio/data_handler.py +10 -3
- rasa/studio/download.py +19 -13
- rasa/studio/train.py +2 -3
- rasa/studio/upload.py +19 -11
- rasa/telemetry.py +113 -58
- rasa/tracing/instrumentation/attribute_extractors.py +32 -17
- rasa/utils/common.py +18 -19
- rasa/utils/endpoints.py +7 -4
- rasa/utils/json_utils.py +60 -0
- rasa/utils/licensing.py +9 -1
- rasa/utils/ml_utils.py +4 -2
- rasa/validator.py +213 -3
- rasa/version.py +1 -1
- rasa_pro-3.10.16.dist-info/METADATA +196 -0
- {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/RECORD +179 -113
- rasa/nlu/classifiers/llm_intent_classifier.py +0 -519
- rasa/shared/providers/openai/clients.py +0 -43
- rasa/shared/providers/openai/session_handler.py +0 -110
- rasa_pro-3.9.18.dist-info/METADATA +0 -563
- /rasa/{shared/providers/openai → cli/project_templates/tutorial/actions}/__init__.py +0 -0
- /rasa/cli/project_templates/tutorial/{actions.py → actions/actions.py} +0 -0
- {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/NOTICE +0 -0
- {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/WHEEL +0 -0
- {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
from typing import (
|
|
3
|
+
Any,
|
|
4
|
+
Dict,
|
|
5
|
+
Text,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
import structlog
|
|
9
|
+
|
|
10
|
+
from rasa.core.actions.custom_action_executor import (
|
|
11
|
+
CustomActionExecutor,
|
|
12
|
+
)
|
|
13
|
+
from rasa.shared.core.domain import Domain
|
|
14
|
+
from rasa.shared.core.trackers import DialogueStateTracker
|
|
15
|
+
from rasa.shared.exceptions import RasaException
|
|
16
|
+
from rasa.utils.endpoints import EndpointConfig
|
|
17
|
+
|
|
18
|
+
if typing.TYPE_CHECKING:
|
|
19
|
+
from rasa.e2e_test.stub_custom_action import StubCustomAction
|
|
20
|
+
|
|
21
|
+
structlogger = structlog.get_logger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class E2EStubCustomActionExecutor(CustomActionExecutor):
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
action_name: str,
|
|
28
|
+
action_endpoint: EndpointConfig,
|
|
29
|
+
):
|
|
30
|
+
"""Initializes the e2e stub custom action executor.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
action_name: Name of the custom action.
|
|
34
|
+
action_endpoint: The endpoint to execute custom actions.
|
|
35
|
+
"""
|
|
36
|
+
self.action_name = action_name
|
|
37
|
+
self.action_endpoint = action_endpoint
|
|
38
|
+
self.stub_custom_action = self.get_stub_custom_action()
|
|
39
|
+
|
|
40
|
+
def get_stub_custom_action(self) -> "StubCustomAction":
|
|
41
|
+
from rasa.e2e_test.stub_custom_action import get_stub_custom_action
|
|
42
|
+
|
|
43
|
+
stub_custom_action = get_stub_custom_action(
|
|
44
|
+
self.action_endpoint, self.action_name
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
if stub_custom_action:
|
|
48
|
+
return stub_custom_action
|
|
49
|
+
|
|
50
|
+
# TODO Update message below with reference to the docs
|
|
51
|
+
raise RasaException(
|
|
52
|
+
f"You are using custom action stubs, however action `{self.action_name}` "
|
|
53
|
+
f"has not been stubbed. Note that you cannot stub some custom actions "
|
|
54
|
+
f"while running an action server instance, you must stub all custom "
|
|
55
|
+
f"actions called by the tests in the provided test path."
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
async def run(
|
|
59
|
+
self,
|
|
60
|
+
tracker: "DialogueStateTracker",
|
|
61
|
+
domain: "Domain",
|
|
62
|
+
include_domain: bool = False,
|
|
63
|
+
) -> Dict[Text, Any]:
|
|
64
|
+
structlogger.debug(
|
|
65
|
+
"action.e2e_stub_custom_action_executor.run",
|
|
66
|
+
action_name=self.action_name,
|
|
67
|
+
)
|
|
68
|
+
return self.stub_custom_action.as_dict()
|
|
@@ -97,7 +97,7 @@ class GRPCCustomActionExecutor(CustomActionExecutor):
|
|
|
97
97
|
Args:
|
|
98
98
|
tracker: Tracker for the current conversation.
|
|
99
99
|
domain: Domain of the assistant.
|
|
100
|
-
include_domain: If True, the domain
|
|
100
|
+
include_domain: If True, the domain is included in the request.
|
|
101
101
|
|
|
102
102
|
Returns:
|
|
103
103
|
Response from the action server.
|
|
@@ -184,7 +184,7 @@ class GRPCCustomActionExecutor(CustomActionExecutor):
|
|
|
184
184
|
Args:
|
|
185
185
|
tracker: Tracker for the current conversation.
|
|
186
186
|
domain: Domain of the assistant.
|
|
187
|
-
include_domain: If True, the domain
|
|
187
|
+
include_domain: If True, the domain is included in the request.
|
|
188
188
|
|
|
189
189
|
Returns:
|
|
190
190
|
gRPC payload for the action server.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import Any, Dict, Optional, TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
import aiohttp
|
|
6
6
|
|
|
@@ -14,14 +14,16 @@ from rasa.core.constants import (
|
|
|
14
14
|
DEFAULT_COMPRESS_ACTION_SERVER_REQUEST,
|
|
15
15
|
DEFAULT_REQUEST_TIMEOUT,
|
|
16
16
|
)
|
|
17
|
+
from rasa.shared.core.domain import Domain
|
|
18
|
+
from rasa.shared.core.trackers import DialogueStateTracker
|
|
17
19
|
from rasa.shared.exceptions import RasaException
|
|
18
20
|
from rasa.utils.common import get_bool_env_variable
|
|
19
|
-
from rasa.utils.endpoints import ClientResponseError, EndpointConfig
|
|
20
21
|
|
|
21
22
|
if TYPE_CHECKING:
|
|
22
23
|
from rasa.shared.core.domain import Domain
|
|
23
24
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
24
25
|
|
|
26
|
+
from rasa.utils.endpoints import ClientResponseError, EndpointConfig
|
|
25
27
|
|
|
26
28
|
logger = logging.getLogger(__name__)
|
|
27
29
|
|
|
@@ -48,7 +50,7 @@ class HTTPCustomActionExecutor(CustomActionExecutor):
|
|
|
48
50
|
async def run(
|
|
49
51
|
self,
|
|
50
52
|
tracker: "DialogueStateTracker",
|
|
51
|
-
domain: "Domain",
|
|
53
|
+
domain: Optional["Domain"] = None,
|
|
52
54
|
include_domain: bool = False,
|
|
53
55
|
) -> Dict[str, Any]:
|
|
54
56
|
"""Execute the custom action using an HTTP POST request.
|
|
@@ -56,8 +58,7 @@ class HTTPCustomActionExecutor(CustomActionExecutor):
|
|
|
56
58
|
Args:
|
|
57
59
|
tracker: The current state of the dialogue.
|
|
58
60
|
domain: The domain object containing domain-specific information.
|
|
59
|
-
include_domain: If
|
|
60
|
-
is included in the request.
|
|
61
|
+
include_domain: If True, the domain is included in the request.
|
|
61
62
|
|
|
62
63
|
Returns:
|
|
63
64
|
A dictionary containing the response from the custom action endpoint.
|
rasa/core/agent.py
CHANGED
|
@@ -1,38 +1,42 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import functools
|
|
4
4
|
import logging
|
|
5
5
|
import os
|
|
6
|
+
import uuid
|
|
7
|
+
from asyncio import AbstractEventLoop, CancelledError
|
|
6
8
|
from pathlib import Path
|
|
7
9
|
from typing import Any, Callable, Dict, List, Optional, Text, Union
|
|
8
|
-
import uuid
|
|
9
10
|
|
|
10
11
|
import aiohttp
|
|
11
12
|
from aiohttp import ClientError
|
|
12
13
|
|
|
14
|
+
import rasa.shared.utils.io
|
|
13
15
|
from rasa.core import jobs
|
|
14
16
|
from rasa.core.channels.channel import OutputChannel, UserMessage
|
|
15
17
|
from rasa.core.constants import DEFAULT_REQUEST_TIMEOUT
|
|
16
|
-
from rasa.core.http_interpreter import RasaNLUHttpInterpreter
|
|
17
|
-
from rasa.shared.core.domain import Domain
|
|
18
18
|
from rasa.core.exceptions import AgentNotReady
|
|
19
|
-
from rasa.
|
|
19
|
+
from rasa.core.http_interpreter import RasaNLUHttpInterpreter
|
|
20
20
|
from rasa.core.lock_store import InMemoryLockStore, LockStore
|
|
21
21
|
from rasa.core.nlg import NaturalLanguageGenerator, TemplatedNaturalLanguageGenerator
|
|
22
22
|
from rasa.core.policies.policy import PolicyPrediction
|
|
23
23
|
from rasa.core.processor import MessageProcessor
|
|
24
|
-
from rasa.core.tracker_store import
|
|
25
|
-
|
|
24
|
+
from rasa.core.tracker_store import (
|
|
25
|
+
FailSafeTrackerStore,
|
|
26
|
+
InMemoryTrackerStore,
|
|
27
|
+
TrackerStore,
|
|
28
|
+
)
|
|
29
|
+
from rasa.core.utils import AvailableEndpoints
|
|
26
30
|
from rasa.exceptions import ModelNotFound
|
|
31
|
+
from rasa.nlu.persistor import StorageType
|
|
27
32
|
from rasa.nlu.utils import is_url
|
|
33
|
+
from rasa.shared.constants import DEFAULT_SENDER_ID
|
|
34
|
+
from rasa.shared.core.domain import Domain
|
|
35
|
+
from rasa.shared.core.trackers import DialogueStateTracker, EventVerbosity
|
|
28
36
|
from rasa.shared.exceptions import RasaException
|
|
29
|
-
import rasa.shared.utils.io
|
|
30
37
|
from rasa.utils.common import TempDirectoryPath, get_temp_dir_name
|
|
31
38
|
from rasa.utils.endpoints import EndpointConfig
|
|
32
39
|
|
|
33
|
-
from rasa.core.tracker_store import TrackerStore
|
|
34
|
-
from rasa.core.utils import AvailableEndpoints
|
|
35
|
-
|
|
36
40
|
logger = logging.getLogger(__name__)
|
|
37
41
|
|
|
38
42
|
|
|
@@ -194,7 +198,7 @@ async def _schedule_model_pulling(
|
|
|
194
198
|
async def load_agent(
|
|
195
199
|
model_path: Optional[Text] = None,
|
|
196
200
|
model_server: Optional[EndpointConfig] = None,
|
|
197
|
-
remote_storage: Optional[
|
|
201
|
+
remote_storage: Optional[StorageType] = None,
|
|
198
202
|
endpoints: Optional[AvailableEndpoints] = None,
|
|
199
203
|
loop: Optional[AbstractEventLoop] = None,
|
|
200
204
|
) -> Agent:
|
|
@@ -203,15 +207,15 @@ async def load_agent(
|
|
|
203
207
|
Args:
|
|
204
208
|
model_path: Path to the model if it's on disk.
|
|
205
209
|
model_server: Configuration for a potential server which serves the model.
|
|
206
|
-
remote_storage:
|
|
210
|
+
remote_storage: Remote storage to use for loading the model.
|
|
207
211
|
endpoints: Endpoint configuration.
|
|
208
212
|
loop: Optional async loop to pass to broker creation.
|
|
209
213
|
|
|
210
214
|
Returns:
|
|
211
215
|
The instantiated `Agent` or `None`.
|
|
212
216
|
"""
|
|
213
|
-
from rasa.core.tracker_store import TrackerStore
|
|
214
217
|
from rasa.core.brokers.broker import EventBroker
|
|
218
|
+
from rasa.core.tracker_store import TrackerStore
|
|
215
219
|
|
|
216
220
|
tracker_store = None
|
|
217
221
|
lock_store = None
|
|
@@ -299,7 +303,7 @@ class Agent:
|
|
|
299
303
|
action_endpoint: Optional[EndpointConfig] = None,
|
|
300
304
|
fingerprint: Optional[Text] = None,
|
|
301
305
|
model_server: Optional[EndpointConfig] = None,
|
|
302
|
-
remote_storage: Optional[
|
|
306
|
+
remote_storage: Optional[StorageType] = None,
|
|
303
307
|
http_interpreter: Optional[RasaNLUHttpInterpreter] = None,
|
|
304
308
|
endpoints: Optional[AvailableEndpoints] = None,
|
|
305
309
|
):
|
|
@@ -329,11 +333,11 @@ class Agent:
|
|
|
329
333
|
action_endpoint: Optional[EndpointConfig] = None,
|
|
330
334
|
fingerprint: Optional[Text] = None,
|
|
331
335
|
model_server: Optional[EndpointConfig] = None,
|
|
332
|
-
remote_storage: Optional[
|
|
336
|
+
remote_storage: Optional[StorageType] = None,
|
|
333
337
|
http_interpreter: Optional[RasaNLUHttpInterpreter] = None,
|
|
334
338
|
endpoints: Optional[AvailableEndpoints] = None,
|
|
335
339
|
) -> Agent:
|
|
336
|
-
"""Constructs a new agent and loads the
|
|
340
|
+
"""Constructs a new agent and loads the processor and model."""
|
|
337
341
|
agent = Agent(
|
|
338
342
|
domain=domain,
|
|
339
343
|
generator=generator,
|
rasa/core/channels/__init__.py
CHANGED
|
@@ -22,6 +22,7 @@ from rasa.core.channels.slack import SlackInput
|
|
|
22
22
|
from rasa.core.channels.telegram import TelegramInput
|
|
23
23
|
from rasa.core.channels.twilio import TwilioInput
|
|
24
24
|
from rasa.core.channels.twilio_voice import TwilioVoiceInput
|
|
25
|
+
from rasa.core.channels.voice_aware.jambonz import JambonzVoiceAwareInput
|
|
25
26
|
from rasa.core.channels.webexteams import WebexTeamsInput
|
|
26
27
|
from rasa.core.channels.hangouts import HangoutsInput
|
|
27
28
|
from rasa.core.channels.audiocodes import AudiocodesInput
|
|
@@ -47,6 +48,7 @@ input_channel_classes: List[Type[InputChannel]] = [
|
|
|
47
48
|
AudiocodesInput,
|
|
48
49
|
DevelopmentInspectInput,
|
|
49
50
|
CVGInput,
|
|
51
|
+
JambonzVoiceAwareInput,
|
|
50
52
|
]
|
|
51
53
|
|
|
52
54
|
# Mapping from an input channel name to its class to allow name based lookup.
|
rasa/core/channels/audiocodes.py
CHANGED
|
@@ -9,6 +9,7 @@ import structlog
|
|
|
9
9
|
from jsonschema import ValidationError, validate
|
|
10
10
|
from rasa.core import jobs
|
|
11
11
|
from rasa.core.channels.channel import InputChannel, OutputChannel, UserMessage
|
|
12
|
+
from rasa.core.channels.voice_aware.utils import validate_voice_license_scope
|
|
12
13
|
from rasa.shared.constants import INTENT_MESSAGE_PREFIX
|
|
13
14
|
from rasa.shared.exceptions import RasaException
|
|
14
15
|
from sanic import Blueprint, response
|
|
@@ -16,11 +17,6 @@ from sanic.exceptions import NotFound, SanicException, ServerError
|
|
|
16
17
|
from sanic.request import Request
|
|
17
18
|
from sanic.response import HTTPResponse
|
|
18
19
|
|
|
19
|
-
from rasa.utils.licensing import (
|
|
20
|
-
PRODUCT_AREA,
|
|
21
|
-
VOICE_SCOPE,
|
|
22
|
-
validate_license_from_env,
|
|
23
|
-
)
|
|
24
20
|
|
|
25
21
|
logger = logging.getLogger(__name__)
|
|
26
22
|
structlogger = structlog.get_logger()
|
|
@@ -30,17 +26,6 @@ KEEP_ALIVE_SECONDS = 120
|
|
|
30
26
|
KEEP_ALIVE_EXPIRATION_FACTOR = 1.5
|
|
31
27
|
|
|
32
28
|
|
|
33
|
-
def validate_voice_license_scope() -> None:
|
|
34
|
-
"""Validate that the correct license scope is present."""
|
|
35
|
-
logger.info(
|
|
36
|
-
f"Validating current Rasa Pro license scope which must include "
|
|
37
|
-
f"the '{VOICE_SCOPE}' scope to use the voice channel."
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
voice_product_scope = PRODUCT_AREA + " " + VOICE_SCOPE
|
|
41
|
-
validate_license_from_env(product_area=voice_product_scope)
|
|
42
|
-
|
|
43
|
-
|
|
44
29
|
class Unauthorized(SanicException):
|
|
45
30
|
"""**Status**: 401 Not Authorized."""
|
|
46
31
|
|
|
File without changes
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from typing import Any, Awaitable, Callable, Dict, Optional, Text
|
|
2
|
+
|
|
3
|
+
import structlog
|
|
4
|
+
from rasa.core.channels.channel import InputChannel, OutputChannel, UserMessage
|
|
5
|
+
from rasa.core.channels.voice_aware.jambonz_protocol import (
|
|
6
|
+
send_ws_text_message,
|
|
7
|
+
websocket_message_handler,
|
|
8
|
+
)
|
|
9
|
+
from rasa.core.channels.voice_aware.utils import validate_voice_license_scope
|
|
10
|
+
from rasa.shared.exceptions import RasaException
|
|
11
|
+
from sanic import Blueprint, response, Websocket # type: ignore[attr-defined]
|
|
12
|
+
from sanic.request import Request
|
|
13
|
+
from sanic.response import HTTPResponse
|
|
14
|
+
|
|
15
|
+
from rasa.shared.utils.common import mark_as_experimental_feature
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
structlogger = structlog.get_logger()
|
|
19
|
+
|
|
20
|
+
CHANNEL_NAME = "jambonz"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class JambonzVoiceAwareInput(InputChannel):
|
|
24
|
+
"""Connector for the Jambonz platform."""
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def name(cls) -> Text:
|
|
28
|
+
return CHANNEL_NAME
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def from_credentials(cls, credentials: Optional[Dict[Text, Any]]) -> InputChannel:
|
|
32
|
+
return cls()
|
|
33
|
+
|
|
34
|
+
def __init__(self) -> None:
|
|
35
|
+
"""Initializes the JambonzVoiceAwareInput channel."""
|
|
36
|
+
mark_as_experimental_feature("Jambonz Channel")
|
|
37
|
+
validate_voice_license_scope()
|
|
38
|
+
|
|
39
|
+
def blueprint(
|
|
40
|
+
self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
|
|
41
|
+
) -> Blueprint:
|
|
42
|
+
jambonz_webhook = Blueprint("jambonz_webhook", __name__)
|
|
43
|
+
|
|
44
|
+
@jambonz_webhook.route("/", methods=["GET"])
|
|
45
|
+
async def health(request: Request) -> HTTPResponse:
|
|
46
|
+
"""Server health route."""
|
|
47
|
+
return response.json({"status": "ok"})
|
|
48
|
+
|
|
49
|
+
@jambonz_webhook.websocket("/websocket", subprotocols=["ws.jambonz.org"]) # type: ignore
|
|
50
|
+
async def websocket(request: Request, ws: Websocket) -> None:
|
|
51
|
+
"""Triggered on new websocket connection."""
|
|
52
|
+
async for message in ws:
|
|
53
|
+
await websocket_message_handler(message, on_new_message, ws)
|
|
54
|
+
|
|
55
|
+
return jambonz_webhook
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class JambonzWebsocketOutput(OutputChannel):
|
|
59
|
+
@classmethod
|
|
60
|
+
def name(cls) -> Text:
|
|
61
|
+
return CHANNEL_NAME
|
|
62
|
+
|
|
63
|
+
def __init__(self, ws: Any, conversation_id: Text) -> None:
|
|
64
|
+
self.ws = ws
|
|
65
|
+
self.conversation_id = conversation_id
|
|
66
|
+
|
|
67
|
+
async def add_message(self, message: Dict) -> None:
|
|
68
|
+
"""Add metadata and add message.
|
|
69
|
+
|
|
70
|
+
Message is added to the list of
|
|
71
|
+
activities to be sent to the Jambonz Websocket server.
|
|
72
|
+
"""
|
|
73
|
+
text_message = message.get("text", "")
|
|
74
|
+
structlogger.debug(
|
|
75
|
+
"jambonz.add.message",
|
|
76
|
+
class_name=self.__class__.__name__,
|
|
77
|
+
message=text_message,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# send message to jambonz
|
|
81
|
+
await send_ws_text_message(self.ws, message.get("text"))
|
|
82
|
+
|
|
83
|
+
async def send_text_message(
|
|
84
|
+
self, recipient_id: Text, text: Text, **kwargs: Any
|
|
85
|
+
) -> None:
|
|
86
|
+
"""Send a text message."""
|
|
87
|
+
await self.add_message({"type": "message", "text": text})
|
|
88
|
+
|
|
89
|
+
async def send_image_url(
|
|
90
|
+
self, recipient_id: Text, image: Text, **kwargs: Any
|
|
91
|
+
) -> None:
|
|
92
|
+
raise RasaException("Images are not supported by this channel")
|
|
93
|
+
|
|
94
|
+
async def send_attachment(
|
|
95
|
+
self, recipient_id: Text, attachment: Text, **kwargs: Any
|
|
96
|
+
) -> None:
|
|
97
|
+
raise RasaException("Attachments are not supported by this channel")
|
|
98
|
+
|
|
99
|
+
async def send_custom_json(
|
|
100
|
+
self, recipient_id: Text, json_message: Dict[Text, Any], **kwargs: Any
|
|
101
|
+
) -> None:
|
|
102
|
+
"""Send an activity."""
|
|
103
|
+
await self.add_message(json_message)
|