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.

Files changed (183) hide show
  1. README.md +0 -374
  2. rasa/__init__.py +1 -2
  3. rasa/__main__.py +5 -0
  4. rasa/anonymization/anonymization_rule_executor.py +2 -2
  5. rasa/api.py +27 -23
  6. rasa/cli/arguments/data.py +27 -2
  7. rasa/cli/arguments/default_arguments.py +25 -3
  8. rasa/cli/arguments/run.py +9 -9
  9. rasa/cli/arguments/train.py +11 -3
  10. rasa/cli/data.py +70 -8
  11. rasa/cli/e2e_test.py +104 -431
  12. rasa/cli/evaluate.py +1 -1
  13. rasa/cli/interactive.py +1 -0
  14. rasa/cli/llm_fine_tuning.py +398 -0
  15. rasa/cli/project_templates/calm/endpoints.yml +1 -1
  16. rasa/cli/project_templates/tutorial/endpoints.yml +1 -1
  17. rasa/cli/run.py +15 -14
  18. rasa/cli/scaffold.py +10 -8
  19. rasa/cli/studio/studio.py +35 -5
  20. rasa/cli/train.py +56 -8
  21. rasa/cli/utils.py +22 -5
  22. rasa/cli/x.py +1 -1
  23. rasa/constants.py +7 -1
  24. rasa/core/actions/action.py +98 -49
  25. rasa/core/actions/action_run_slot_rejections.py +4 -1
  26. rasa/core/actions/custom_action_executor.py +9 -6
  27. rasa/core/actions/direct_custom_actions_executor.py +80 -0
  28. rasa/core/actions/e2e_stub_custom_action_executor.py +68 -0
  29. rasa/core/actions/grpc_custom_action_executor.py +2 -2
  30. rasa/core/actions/http_custom_action_executor.py +6 -5
  31. rasa/core/agent.py +21 -17
  32. rasa/core/channels/__init__.py +2 -0
  33. rasa/core/channels/audiocodes.py +1 -16
  34. rasa/core/channels/voice_aware/__init__.py +0 -0
  35. rasa/core/channels/voice_aware/jambonz.py +103 -0
  36. rasa/core/channels/voice_aware/jambonz_protocol.py +344 -0
  37. rasa/core/channels/voice_aware/utils.py +20 -0
  38. rasa/core/channels/voice_native/__init__.py +0 -0
  39. rasa/core/constants.py +6 -1
  40. rasa/core/information_retrieval/faiss.py +7 -4
  41. rasa/core/information_retrieval/information_retrieval.py +8 -0
  42. rasa/core/information_retrieval/milvus.py +9 -2
  43. rasa/core/information_retrieval/qdrant.py +1 -1
  44. rasa/core/nlg/contextual_response_rephraser.py +32 -10
  45. rasa/core/nlg/summarize.py +4 -3
  46. rasa/core/policies/enterprise_search_policy.py +113 -45
  47. rasa/core/policies/flows/flow_executor.py +122 -76
  48. rasa/core/policies/intentless_policy.py +83 -29
  49. rasa/core/processor.py +72 -54
  50. rasa/core/run.py +5 -4
  51. rasa/core/tracker_store.py +8 -4
  52. rasa/core/training/interactive.py +1 -1
  53. rasa/core/utils.py +56 -57
  54. rasa/dialogue_understanding/coexistence/llm_based_router.py +53 -13
  55. rasa/dialogue_understanding/commands/__init__.py +6 -0
  56. rasa/dialogue_understanding/commands/restart_command.py +58 -0
  57. rasa/dialogue_understanding/commands/session_start_command.py +59 -0
  58. rasa/dialogue_understanding/commands/utils.py +40 -0
  59. rasa/dialogue_understanding/generator/constants.py +10 -3
  60. rasa/dialogue_understanding/generator/flow_retrieval.py +21 -5
  61. rasa/dialogue_understanding/generator/llm_based_command_generator.py +13 -3
  62. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +134 -90
  63. rasa/dialogue_understanding/generator/nlu_command_adapter.py +47 -7
  64. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +127 -41
  65. rasa/dialogue_understanding/patterns/restart.py +37 -0
  66. rasa/dialogue_understanding/patterns/session_start.py +37 -0
  67. rasa/dialogue_understanding/processor/command_processor.py +16 -3
  68. rasa/dialogue_understanding/processor/command_processor_component.py +6 -2
  69. rasa/e2e_test/aggregate_test_stats_calculator.py +134 -0
  70. rasa/e2e_test/assertions.py +1223 -0
  71. rasa/e2e_test/assertions_schema.yml +106 -0
  72. rasa/e2e_test/constants.py +20 -0
  73. rasa/e2e_test/e2e_config.py +220 -0
  74. rasa/e2e_test/e2e_config_schema.yml +26 -0
  75. rasa/e2e_test/e2e_test_case.py +131 -8
  76. rasa/e2e_test/e2e_test_converter.py +363 -0
  77. rasa/e2e_test/e2e_test_converter_prompt.jinja2 +70 -0
  78. rasa/e2e_test/e2e_test_coverage_report.py +364 -0
  79. rasa/e2e_test/e2e_test_result.py +26 -6
  80. rasa/e2e_test/e2e_test_runner.py +493 -71
  81. rasa/e2e_test/e2e_test_schema.yml +96 -0
  82. rasa/e2e_test/pykwalify_extensions.py +39 -0
  83. rasa/e2e_test/stub_custom_action.py +70 -0
  84. rasa/e2e_test/utils/__init__.py +0 -0
  85. rasa/e2e_test/utils/e2e_yaml_utils.py +55 -0
  86. rasa/e2e_test/utils/io.py +598 -0
  87. rasa/e2e_test/utils/validation.py +80 -0
  88. rasa/engine/graph.py +9 -3
  89. rasa/engine/recipes/default_components.py +0 -2
  90. rasa/engine/recipes/default_recipe.py +10 -2
  91. rasa/engine/storage/local_model_storage.py +40 -12
  92. rasa/engine/validation.py +78 -1
  93. rasa/env.py +9 -0
  94. rasa/graph_components/providers/story_graph_provider.py +59 -6
  95. rasa/llm_fine_tuning/__init__.py +0 -0
  96. rasa/llm_fine_tuning/annotation_module.py +241 -0
  97. rasa/llm_fine_tuning/conversations.py +144 -0
  98. rasa/llm_fine_tuning/llm_data_preparation_module.py +178 -0
  99. rasa/llm_fine_tuning/notebooks/unsloth_finetuning.ipynb +407 -0
  100. rasa/llm_fine_tuning/paraphrasing/__init__.py +0 -0
  101. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +281 -0
  102. rasa/llm_fine_tuning/paraphrasing/default_rephrase_prompt_template.jina2 +44 -0
  103. rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +121 -0
  104. rasa/llm_fine_tuning/paraphrasing/rephrased_user_message.py +10 -0
  105. rasa/llm_fine_tuning/paraphrasing_module.py +128 -0
  106. rasa/llm_fine_tuning/storage.py +174 -0
  107. rasa/llm_fine_tuning/train_test_split_module.py +441 -0
  108. rasa/model_training.py +56 -16
  109. rasa/nlu/persistor.py +157 -36
  110. rasa/server.py +45 -10
  111. rasa/shared/constants.py +76 -16
  112. rasa/shared/core/domain.py +27 -19
  113. rasa/shared/core/events.py +28 -2
  114. rasa/shared/core/flows/flow.py +208 -13
  115. rasa/shared/core/flows/flow_path.py +84 -0
  116. rasa/shared/core/flows/flows_list.py +33 -11
  117. rasa/shared/core/flows/flows_yaml_schema.json +269 -193
  118. rasa/shared/core/flows/validation.py +112 -25
  119. rasa/shared/core/flows/yaml_flows_io.py +149 -10
  120. rasa/shared/core/trackers.py +6 -0
  121. rasa/shared/core/training_data/structures.py +20 -0
  122. rasa/shared/core/training_data/visualization.html +2 -2
  123. rasa/shared/exceptions.py +4 -0
  124. rasa/shared/importers/importer.py +64 -16
  125. rasa/shared/nlu/constants.py +2 -0
  126. rasa/shared/providers/_configs/__init__.py +0 -0
  127. rasa/shared/providers/_configs/azure_openai_client_config.py +183 -0
  128. rasa/shared/providers/_configs/client_config.py +57 -0
  129. rasa/shared/providers/_configs/default_litellm_client_config.py +130 -0
  130. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +234 -0
  131. rasa/shared/providers/_configs/openai_client_config.py +175 -0
  132. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +176 -0
  133. rasa/shared/providers/_configs/utils.py +101 -0
  134. rasa/shared/providers/_ssl_verification_utils.py +124 -0
  135. rasa/shared/providers/embedding/__init__.py +0 -0
  136. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +259 -0
  137. rasa/shared/providers/embedding/_langchain_embedding_client_adapter.py +74 -0
  138. rasa/shared/providers/embedding/azure_openai_embedding_client.py +277 -0
  139. rasa/shared/providers/embedding/default_litellm_embedding_client.py +102 -0
  140. rasa/shared/providers/embedding/embedding_client.py +90 -0
  141. rasa/shared/providers/embedding/embedding_response.py +41 -0
  142. rasa/shared/providers/embedding/huggingface_local_embedding_client.py +191 -0
  143. rasa/shared/providers/embedding/openai_embedding_client.py +172 -0
  144. rasa/shared/providers/llm/__init__.py +0 -0
  145. rasa/shared/providers/llm/_base_litellm_client.py +251 -0
  146. rasa/shared/providers/llm/azure_openai_llm_client.py +338 -0
  147. rasa/shared/providers/llm/default_litellm_llm_client.py +84 -0
  148. rasa/shared/providers/llm/llm_client.py +76 -0
  149. rasa/shared/providers/llm/llm_response.py +50 -0
  150. rasa/shared/providers/llm/openai_llm_client.py +155 -0
  151. rasa/shared/providers/llm/self_hosted_llm_client.py +293 -0
  152. rasa/shared/providers/mappings.py +75 -0
  153. rasa/shared/utils/cli.py +30 -0
  154. rasa/shared/utils/io.py +65 -2
  155. rasa/shared/utils/llm.py +246 -200
  156. rasa/shared/utils/yaml.py +121 -15
  157. rasa/studio/auth.py +6 -4
  158. rasa/studio/config.py +13 -4
  159. rasa/studio/constants.py +1 -0
  160. rasa/studio/data_handler.py +10 -3
  161. rasa/studio/download.py +19 -13
  162. rasa/studio/train.py +2 -3
  163. rasa/studio/upload.py +19 -11
  164. rasa/telemetry.py +113 -58
  165. rasa/tracing/instrumentation/attribute_extractors.py +32 -17
  166. rasa/utils/common.py +18 -19
  167. rasa/utils/endpoints.py +7 -4
  168. rasa/utils/json_utils.py +60 -0
  169. rasa/utils/licensing.py +9 -1
  170. rasa/utils/ml_utils.py +4 -2
  171. rasa/validator.py +213 -3
  172. rasa/version.py +1 -1
  173. rasa_pro-3.10.16.dist-info/METADATA +196 -0
  174. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/RECORD +179 -113
  175. rasa/nlu/classifiers/llm_intent_classifier.py +0 -519
  176. rasa/shared/providers/openai/clients.py +0 -43
  177. rasa/shared/providers/openai/session_handler.py +0 -110
  178. rasa_pro-3.9.18.dist-info/METADATA +0 -563
  179. /rasa/{shared/providers/openai → cli/project_templates/tutorial/actions}/__init__.py +0 -0
  180. /rasa/cli/project_templates/tutorial/{actions.py → actions/actions.py} +0 -0
  181. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/NOTICE +0 -0
  182. {rasa_pro-3.9.18.dist-info → rasa_pro-3.10.16.dist-info}/WHEEL +0 -0
  183. {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 information is included in the request.
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 information is included in the request.
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 TYPE_CHECKING, Any, Dict
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 `True`, the domain information
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
- from asyncio import AbstractEventLoop, CancelledError
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.shared.constants import DEFAULT_SENDER_ID
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 FailSafeTrackerStore, InMemoryTrackerStore
25
- from rasa.shared.core.trackers import DialogueStateTracker, EventVerbosity
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[Text] = None,
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: URL of remote storage for model.
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[Text] = None,
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[Text] = None,
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 processer and model."""
340
+ """Constructs a new agent and loads the processor and model."""
337
341
  agent = Agent(
338
342
  domain=domain,
339
343
  generator=generator,
@@ -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.
@@ -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)