rasa-pro 3.11.0__py3-none-any.whl → 3.11.0a2__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 +396 -17
- rasa/__main__.py +15 -31
- rasa/api.py +1 -5
- rasa/cli/arguments/default_arguments.py +2 -1
- rasa/cli/arguments/shell.py +1 -5
- rasa/cli/arguments/train.py +0 -14
- rasa/cli/e2e_test.py +1 -1
- rasa/cli/evaluate.py +8 -8
- rasa/cli/inspect.py +5 -7
- rasa/cli/interactive.py +0 -1
- rasa/cli/llm_fine_tuning.py +1 -1
- rasa/cli/project_templates/calm/config.yml +7 -5
- rasa/cli/project_templates/calm/endpoints.yml +2 -15
- rasa/cli/project_templates/tutorial/config.yml +5 -8
- rasa/cli/project_templates/tutorial/data/flows.yml +1 -1
- rasa/cli/project_templates/tutorial/data/patterns.yml +0 -5
- rasa/cli/project_templates/tutorial/domain.yml +0 -14
- rasa/cli/project_templates/tutorial/endpoints.yml +0 -5
- rasa/cli/run.py +1 -1
- rasa/cli/scaffold.py +2 -4
- rasa/cli/studio/studio.py +8 -18
- rasa/cli/studio/upload.py +15 -0
- rasa/cli/train.py +0 -3
- rasa/cli/utils.py +1 -6
- rasa/cli/x.py +8 -8
- rasa/constants.py +1 -3
- rasa/core/actions/action.py +33 -75
- rasa/core/actions/e2e_stub_custom_action_executor.py +1 -5
- rasa/core/actions/http_custom_action_executor.py +0 -4
- rasa/core/channels/channel.py +0 -20
- rasa/core/channels/development_inspector.py +2 -8
- rasa/core/channels/inspector/dist/assets/{arc-bc141fb2.js → arc-6852c607.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-d0fbc5ce-be2db283.js → c4Diagram-d0fbc5ce-acc952b2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-936ed81e-55366915.js → classDiagram-936ed81e-848a7597.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-c3cb15f1-bb529518.js → classDiagram-v2-c3cb15f1-a73d3e68.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{createText-62fc7601-b0ec81d6.js → createText-62fc7601-e5ee049d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-f2ad444c-6166330c.js → edges-f2ad444c-771e517e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-5ccc6a8e.js → erDiagram-9d236eb7-aa347178.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-1972c806-fca3bfe4.js → flowDb-1972c806-651fc57d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-7ea5b25a-4739080f.js → flowDiagram-7ea5b25a-ca67804f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-587d82d8.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-abe16c3d-7c1b0e0f.js → flowchart-elk-definition-abe16c3d-2dbc568d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-9b5ea136-772fd050.js → ganttDiagram-9b5ea136-25a65bd8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-99d0ae7c-8eae1dc9.js → gitGraphDiagram-99d0ae7c-fdc7378d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-2c4b9a3b-f55afcdf.js → index-2c4b9a3b-6f1fd606.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-e7cef9de.js → index-efdd30c1.js} +68 -68
- rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-124d4a14.js → infoDiagram-736b4530-cb1a041a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-7c4fae44.js → journeyDiagram-df861f2b-14609879.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-b9885fb6.js → layout-2490f52b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-7c59abb6.js → line-40186f1f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-4776f780.js → linear-08814e93.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-beec6740-2332c46c.js → mindmap-definition-beec6740-1a534584.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-8fb39303.js → pieDiagram-dbbf0591-72397b61.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-3c7180a2.js → quadrantDiagram-4d7f4fd6-3bb0b6a3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-e910bcb8.js → requirementDiagram-6fc4c22a-57334f61.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-8f13d901-ead16c89.js → sankeyDiagram-8f13d901-111e1297.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-b655622a-29a02a19.js → sequenceDiagram-b655622a-10bcfe62.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-59f0c015-042b3137.js → stateDiagram-59f0c015-acaf7513.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-2b26beab-2178c0f3.js → stateDiagram-v2-2b26beab-3ec2a235.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-080da4f6-23ffa4fc.js → styles-080da4f6-62730289.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-3dcbcfbf-94f59763.js → styles-3dcbcfbf-5284ee76.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9c745c82-78a6bebc.js → styles-9c745c82-642435e3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-4835440b-eae2a6f6.js → svgDrawCommon-4835440b-b250a350.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-5c968d92.js → timeline-definition-5b62e21b-c2b147ed.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-fd3db0d5.js → xychartDiagram-2b33534f-f92cfea9.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/src/App.tsx +1 -1
- rasa/core/channels/inspector/src/helpers/audiostream.ts +16 -77
- rasa/core/channels/socketio.py +2 -7
- rasa/core/channels/telegram.py +1 -1
- rasa/core/channels/twilio.py +1 -1
- rasa/core/channels/voice_ready/audiocodes.py +4 -15
- rasa/core/channels/voice_ready/jambonz.py +4 -15
- rasa/core/channels/voice_ready/twilio_voice.py +21 -6
- rasa/core/channels/voice_ready/utils.py +5 -6
- rasa/core/channels/voice_stream/asr/asr_engine.py +1 -19
- rasa/core/channels/voice_stream/asr/asr_event.py +0 -5
- rasa/core/channels/voice_stream/asr/deepgram.py +15 -28
- rasa/core/channels/voice_stream/audio_bytes.py +0 -1
- rasa/core/channels/voice_stream/browser_audio.py +9 -32
- rasa/core/channels/voice_stream/tts/azure.py +3 -9
- rasa/core/channels/voice_stream/tts/cartesia.py +8 -12
- rasa/core/channels/voice_stream/tts/tts_engine.py +1 -11
- rasa/core/channels/voice_stream/twilio_media_streams.py +19 -28
- rasa/core/channels/voice_stream/util.py +4 -4
- rasa/core/channels/voice_stream/voice_channel.py +42 -222
- rasa/core/featurizers/single_state_featurizer.py +1 -22
- rasa/core/featurizers/tracker_featurizers.py +18 -115
- rasa/core/information_retrieval/qdrant.py +0 -1
- rasa/core/nlg/contextual_response_rephraser.py +25 -44
- rasa/core/persistor.py +34 -191
- rasa/core/policies/enterprise_search_policy.py +60 -119
- rasa/core/policies/flows/flow_executor.py +4 -7
- rasa/core/policies/intentless_policy.py +22 -82
- rasa/core/policies/ted_policy.py +33 -58
- rasa/core/policies/unexpected_intent_policy.py +7 -15
- rasa/core/processor.py +5 -32
- rasa/core/training/interactive.py +35 -34
- rasa/core/utils.py +22 -58
- rasa/dialogue_understanding/coexistence/llm_based_router.py +12 -39
- rasa/dialogue_understanding/commands/__init__.py +0 -4
- rasa/dialogue_understanding/commands/change_flow_command.py +0 -6
- rasa/dialogue_understanding/commands/utils.py +0 -5
- rasa/dialogue_understanding/generator/constants.py +0 -2
- rasa/dialogue_understanding/generator/flow_retrieval.py +4 -49
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +23 -37
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +10 -57
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +1 -19
- rasa/dialogue_understanding/generator/single_step/command_prompt_template.jinja2 +0 -3
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +10 -90
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +0 -53
- rasa/dialogue_understanding/processor/command_processor.py +1 -21
- rasa/e2e_test/assertions.py +16 -133
- rasa/e2e_test/assertions_schema.yml +0 -23
- rasa/e2e_test/e2e_test_case.py +6 -85
- rasa/e2e_test/e2e_test_runner.py +4 -6
- rasa/e2e_test/utils/io.py +1 -3
- rasa/engine/loader.py +0 -12
- rasa/engine/validation.py +11 -541
- rasa/keys +1 -0
- rasa/llm_fine_tuning/notebooks/unsloth_finetuning.ipynb +407 -0
- rasa/model_training.py +7 -29
- rasa/nlu/classifiers/diet_classifier.py +25 -38
- rasa/nlu/classifiers/logistic_regression_classifier.py +9 -22
- rasa/nlu/classifiers/sklearn_intent_classifier.py +16 -37
- rasa/nlu/extractors/crf_entity_extractor.py +50 -93
- rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +16 -45
- rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +17 -52
- rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +3 -5
- rasa/nlu/tokenizers/whitespace_tokenizer.py +14 -3
- rasa/server.py +1 -3
- rasa/shared/constants.py +0 -61
- rasa/shared/core/constants.py +0 -9
- rasa/shared/core/domain.py +5 -8
- rasa/shared/core/flows/flow.py +0 -5
- rasa/shared/core/flows/flows_list.py +1 -5
- rasa/shared/core/flows/flows_yaml_schema.json +0 -10
- rasa/shared/core/flows/validation.py +0 -96
- rasa/shared/core/flows/yaml_flows_io.py +4 -13
- rasa/shared/core/slots.py +0 -5
- rasa/shared/importers/importer.py +2 -19
- rasa/shared/importers/rasa.py +1 -5
- rasa/shared/nlu/training_data/features.py +2 -120
- rasa/shared/nlu/training_data/formats/rasa_yaml.py +3 -18
- rasa/shared/providers/_configs/azure_openai_client_config.py +3 -5
- rasa/shared/providers/_configs/openai_client_config.py +1 -1
- rasa/shared/providers/_configs/self_hosted_llm_client_config.py +0 -1
- rasa/shared/providers/_configs/utils.py +0 -16
- rasa/shared/providers/embedding/_base_litellm_embedding_client.py +29 -18
- rasa/shared/providers/embedding/azure_openai_embedding_client.py +21 -54
- rasa/shared/providers/embedding/default_litellm_embedding_client.py +0 -24
- rasa/shared/providers/llm/_base_litellm_client.py +31 -63
- rasa/shared/providers/llm/azure_openai_llm_client.py +29 -50
- rasa/shared/providers/llm/default_litellm_llm_client.py +0 -24
- rasa/shared/providers/llm/self_hosted_llm_client.py +29 -17
- rasa/shared/providers/mappings.py +0 -19
- rasa/shared/utils/common.py +2 -37
- rasa/shared/utils/io.py +6 -28
- rasa/shared/utils/llm.py +46 -353
- rasa/shared/utils/yaml.py +82 -181
- rasa/studio/auth.py +5 -3
- rasa/studio/config.py +4 -13
- rasa/studio/constants.py +0 -1
- rasa/studio/data_handler.py +4 -13
- rasa/studio/upload.py +80 -175
- rasa/telemetry.py +17 -94
- rasa/tracing/config.py +1 -3
- rasa/tracing/instrumentation/attribute_extractors.py +17 -94
- rasa/tracing/instrumentation/instrumentation.py +0 -121
- rasa/utils/common.py +0 -5
- rasa/utils/endpoints.py +1 -27
- rasa/utils/io.py +81 -7
- rasa/utils/log_utils.py +2 -9
- rasa/utils/tensorflow/model_data.py +193 -2
- rasa/validator.py +4 -110
- rasa/version.py +1 -1
- rasa_pro-3.11.0a2.dist-info/METADATA +576 -0
- {rasa_pro-3.11.0.dist-info → rasa_pro-3.11.0a2.dist-info}/RECORD +181 -213
- rasa/core/actions/action_repeat_bot_messages.py +0 -89
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-736177bf.js +0 -1
- rasa/core/channels/voice_stream/asr/azure.py +0 -129
- rasa/core/channels/voice_stream/call_state.py +0 -23
- rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +0 -60
- rasa/dialogue_understanding/commands/user_silence_command.py +0 -59
- rasa/dialogue_understanding/patterns/repeat.py +0 -37
- rasa/dialogue_understanding/patterns/user_silence.py +0 -37
- rasa/model_manager/__init__.py +0 -0
- rasa/model_manager/config.py +0 -40
- rasa/model_manager/model_api.py +0 -559
- rasa/model_manager/runner_service.py +0 -286
- rasa/model_manager/socket_bridge.py +0 -146
- rasa/model_manager/studio_jwt_auth.py +0 -86
- rasa/model_manager/trainer_service.py +0 -325
- rasa/model_manager/utils.py +0 -87
- rasa/model_manager/warm_rasa_process.py +0 -187
- rasa/model_service.py +0 -112
- rasa/shared/core/flows/utils.py +0 -39
- rasa/shared/providers/_configs/litellm_router_client_config.py +0 -220
- rasa/shared/providers/_configs/model_group_config.py +0 -167
- rasa/shared/providers/_configs/rasa_llm_client_config.py +0 -73
- rasa/shared/providers/_utils.py +0 -79
- rasa/shared/providers/embedding/litellm_router_embedding_client.py +0 -135
- rasa/shared/providers/llm/litellm_router_llm_client.py +0 -182
- rasa/shared/providers/llm/rasa_llm_client.py +0 -112
- rasa/shared/providers/router/__init__.py +0 -0
- rasa/shared/providers/router/_base_litellm_router_client.py +0 -183
- rasa/shared/providers/router/router_client.py +0 -73
- rasa/shared/utils/health_check/__init__.py +0 -0
- rasa/shared/utils/health_check/embeddings_health_check_mixin.py +0 -31
- rasa/shared/utils/health_check/health_check.py +0 -258
- rasa/shared/utils/health_check/llm_health_check_mixin.py +0 -31
- rasa/utils/sanic_error_handler.py +0 -32
- rasa/utils/tensorflow/feature_array.py +0 -366
- rasa_pro-3.11.0.dist-info/METADATA +0 -198
- {rasa_pro-3.11.0.dist-info → rasa_pro-3.11.0a2.dist-info}/NOTICE +0 -0
- {rasa_pro-3.11.0.dist-info → rasa_pro-3.11.0a2.dist-info}/WHEEL +0 -0
- {rasa_pro-3.11.0.dist-info → rasa_pro-3.11.0a2.dist-info}/entry_points.txt +0 -0
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import audioop
|
|
2
|
-
import base64
|
|
3
|
-
import json
|
|
4
|
-
|
|
5
2
|
import structlog
|
|
6
3
|
import uuid
|
|
7
|
-
from typing import Any, Awaitable, Callable,
|
|
4
|
+
from typing import Any, Awaitable, Callable, List, Optional
|
|
8
5
|
|
|
9
6
|
from sanic import Blueprint, HTTPResponse, Request, response
|
|
10
7
|
from sanic import Websocket # type: ignore
|
|
@@ -12,19 +9,16 @@ from sanic import Websocket # type: ignore
|
|
|
12
9
|
|
|
13
10
|
from rasa.core.channels import UserMessage
|
|
14
11
|
from rasa.core.channels.voice_ready.utils import CallParameters
|
|
15
|
-
from rasa.core.channels.voice_stream.call_state import call_state
|
|
16
12
|
from rasa.core.channels.voice_stream.tts.tts_engine import TTSEngine
|
|
17
13
|
from rasa.core.channels.voice_stream.audio_bytes import RasaAudioBytes
|
|
18
14
|
from rasa.core.channels.voice_stream.voice_channel import (
|
|
19
|
-
ContinueConversationAction,
|
|
20
|
-
EndConversationAction,
|
|
21
15
|
NewAudioAction,
|
|
22
16
|
VoiceChannelAction,
|
|
23
17
|
VoiceInputChannel,
|
|
24
18
|
VoiceOutputChannel,
|
|
25
19
|
)
|
|
26
20
|
|
|
27
|
-
|
|
21
|
+
structlogger = structlog.get_logger()
|
|
28
22
|
|
|
29
23
|
|
|
30
24
|
class BrowserAudioOutputChannel(VoiceOutputChannel):
|
|
@@ -37,12 +31,10 @@ class BrowserAudioOutputChannel(VoiceOutputChannel):
|
|
|
37
31
|
) -> bytes:
|
|
38
32
|
return audioop.ulaw2lin(rasa_audio_bytes, 4)
|
|
39
33
|
|
|
40
|
-
def
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
message_id = uuid.uuid4().hex
|
|
45
|
-
return json.dumps({"marker": message_id}), message_id
|
|
34
|
+
def channel_bytes_to_messages(
|
|
35
|
+
self, recipient_id: str, channel_bytes: bytes
|
|
36
|
+
) -> List[Any]:
|
|
37
|
+
return [channel_bytes]
|
|
46
38
|
|
|
47
39
|
|
|
48
40
|
class BrowserAudioInputChannel(VoiceInputChannel):
|
|
@@ -63,23 +55,8 @@ class BrowserAudioInputChannel(VoiceInputChannel):
|
|
|
63
55
|
self,
|
|
64
56
|
message: Any,
|
|
65
57
|
) -> VoiceChannelAction:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
channel_bytes = base64.b64decode(data["audio"])
|
|
69
|
-
audio_bytes = self.channel_bytes_to_rasa_audio_bytes(channel_bytes)
|
|
70
|
-
return NewAudioAction(audio_bytes)
|
|
71
|
-
elif "marker" in data:
|
|
72
|
-
if data["marker"] == call_state.latest_bot_audio_id:
|
|
73
|
-
# Just finished streaming last audio bytes
|
|
74
|
-
call_state.is_bot_speaking = False # type: ignore[attr-defined]
|
|
75
|
-
if call_state.should_hangup:
|
|
76
|
-
logger.debug(
|
|
77
|
-
"browser_audio.hangup", marker=call_state.latest_bot_audio_id
|
|
78
|
-
)
|
|
79
|
-
return EndConversationAction()
|
|
80
|
-
else:
|
|
81
|
-
call_state.is_bot_speaking = True # type: ignore[attr-defined]
|
|
82
|
-
return ContinueConversationAction()
|
|
58
|
+
audio_bytes = self.channel_bytes_to_rasa_audio_bytes(message)
|
|
59
|
+
return NewAudioAction(audio_bytes)
|
|
83
60
|
|
|
84
61
|
def create_output_channel(
|
|
85
62
|
self, voice_websocket: Websocket, tts_engine: TTSEngine
|
|
@@ -94,7 +71,7 @@ class BrowserAudioInputChannel(VoiceInputChannel):
|
|
|
94
71
|
self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
|
|
95
72
|
) -> Blueprint:
|
|
96
73
|
"""Defines a Sanic bluelogger.debug."""
|
|
97
|
-
blueprint = Blueprint("
|
|
74
|
+
blueprint = Blueprint("socketio_webhook", __name__)
|
|
98
75
|
|
|
99
76
|
@blueprint.route("/", methods=["GET"])
|
|
100
77
|
async def health(_: Request) -> HTTPResponse:
|
|
@@ -4,7 +4,7 @@ from dataclasses import dataclass
|
|
|
4
4
|
|
|
5
5
|
import aiohttp
|
|
6
6
|
import structlog
|
|
7
|
-
from aiohttp import ClientConnectorError
|
|
7
|
+
from aiohttp import ClientConnectorError
|
|
8
8
|
|
|
9
9
|
from rasa.core.channels.voice_stream.audio_bytes import RasaAudioBytes
|
|
10
10
|
from rasa.core.channels.voice_stream.tts.tts_engine import (
|
|
@@ -12,7 +12,6 @@ from rasa.core.channels.voice_stream.tts.tts_engine import (
|
|
|
12
12
|
TTSEngineConfig,
|
|
13
13
|
TTSError,
|
|
14
14
|
)
|
|
15
|
-
from rasa.shared.constants import AZURE_SPEECH_API_KEY_ENV_VAR
|
|
16
15
|
from rasa.shared.exceptions import ConnectionException
|
|
17
16
|
|
|
18
17
|
|
|
@@ -26,15 +25,13 @@ class AzureTTSConfig(TTSEngineConfig):
|
|
|
26
25
|
|
|
27
26
|
class AzureTTS(TTSEngine[AzureTTSConfig]):
|
|
28
27
|
session: Optional[aiohttp.ClientSession] = None
|
|
29
|
-
required_env_vars = (AZURE_SPEECH_API_KEY_ENV_VAR,)
|
|
30
28
|
|
|
31
29
|
def __init__(self, config: Optional[AzureTTSConfig] = None):
|
|
32
30
|
super().__init__(config)
|
|
33
|
-
timeout = ClientTimeout(total=self.config.timeout)
|
|
34
31
|
# Have to create this class-shared session lazily at run time otherwise
|
|
35
32
|
# the async event loop doesn't work
|
|
36
33
|
if self.__class__.session is None or self.__class__.session.closed:
|
|
37
|
-
self.__class__.session = aiohttp.ClientSession(
|
|
34
|
+
self.__class__.session = aiohttp.ClientSession()
|
|
38
35
|
|
|
39
36
|
async def synthesize(
|
|
40
37
|
self, text: str, config: Optional[AzureTTSConfig] = None
|
|
@@ -63,12 +60,10 @@ class AzureTTS(TTSEngine[AzureTTSConfig]):
|
|
|
63
60
|
raise TTSError(f"TTS failed: {response.text()}")
|
|
64
61
|
except ClientConnectorError as e:
|
|
65
62
|
raise TTSError(e)
|
|
66
|
-
except TimeoutError as e:
|
|
67
|
-
raise TTSError(e)
|
|
68
63
|
|
|
69
64
|
@staticmethod
|
|
70
65
|
def get_request_headers() -> dict[str, str]:
|
|
71
|
-
azure_speech_api_key = os.environ[
|
|
66
|
+
azure_speech_api_key = os.environ["AZURE_SPEECH_API_KEY"]
|
|
72
67
|
return {
|
|
73
68
|
"Ocp-Apim-Subscription-Key": azure_speech_api_key,
|
|
74
69
|
"Content-Type": "application/ssml+xml",
|
|
@@ -97,7 +92,6 @@ class AzureTTS(TTSEngine[AzureTTSConfig]):
|
|
|
97
92
|
return AzureTTSConfig(
|
|
98
93
|
language="en-US",
|
|
99
94
|
voice="en-US-JennyNeural",
|
|
100
|
-
timeout=10,
|
|
101
95
|
speech_region="germanywestcentral",
|
|
102
96
|
)
|
|
103
97
|
|
|
@@ -3,19 +3,20 @@ from typing import AsyncIterator, Dict, Optional
|
|
|
3
3
|
import os
|
|
4
4
|
import aiohttp
|
|
5
5
|
import structlog
|
|
6
|
-
from aiohttp import ClientConnectorError
|
|
6
|
+
from aiohttp import ClientConnectorError
|
|
7
7
|
|
|
8
8
|
from rasa.core.channels.voice_stream.tts.tts_engine import (
|
|
9
9
|
TTSEngineConfig,
|
|
10
10
|
)
|
|
11
11
|
|
|
12
|
-
from rasa.core.channels.voice_stream.audio_bytes import
|
|
12
|
+
from rasa.core.channels.voice_stream.audio_bytes import RasaAudioBytes
|
|
13
13
|
from rasa.core.channels.voice_stream.tts.tts_engine import TTSEngine, TTSError
|
|
14
|
-
from rasa.shared.constants import CARTESIA_API_KEY_ENV_VAR
|
|
15
14
|
from rasa.shared.exceptions import ConnectionException
|
|
16
15
|
|
|
17
16
|
structlogger = structlog.get_logger()
|
|
18
17
|
|
|
18
|
+
CARTESIA_API_KEY = "CARTESIA_API_KEY"
|
|
19
|
+
|
|
19
20
|
|
|
20
21
|
@dataclass
|
|
21
22
|
class CartesiaTTSConfig(TTSEngineConfig):
|
|
@@ -25,15 +26,13 @@ class CartesiaTTSConfig(TTSEngineConfig):
|
|
|
25
26
|
|
|
26
27
|
class CartesiaTTS(TTSEngine[CartesiaTTSConfig]):
|
|
27
28
|
session: Optional[aiohttp.ClientSession] = None
|
|
28
|
-
required_env_vars = (CARTESIA_API_KEY_ENV_VAR,)
|
|
29
29
|
|
|
30
30
|
def __init__(self, config: Optional[CartesiaTTSConfig] = None):
|
|
31
31
|
super().__init__(config)
|
|
32
|
-
timeout = ClientTimeout(total=self.config.timeout)
|
|
33
32
|
# Have to create this class-shared session lazily at run time otherwise
|
|
34
33
|
# the async event loop doesn't work
|
|
35
34
|
if self.__class__.session is None or self.__class__.session.closed:
|
|
36
|
-
self.__class__.session = aiohttp.ClientSession(
|
|
35
|
+
self.__class__.session = aiohttp.ClientSession()
|
|
37
36
|
|
|
38
37
|
@staticmethod
|
|
39
38
|
def get_tts_endpoint() -> str:
|
|
@@ -56,13 +55,13 @@ class CartesiaTTS(TTSEngine[CartesiaTTSConfig]):
|
|
|
56
55
|
"output_format": {
|
|
57
56
|
"container": "raw",
|
|
58
57
|
"encoding": "pcm_mulaw",
|
|
59
|
-
"sample_rate":
|
|
58
|
+
"sample_rate": 8000,
|
|
60
59
|
},
|
|
61
60
|
}
|
|
62
61
|
|
|
63
62
|
@staticmethod
|
|
64
63
|
def get_request_headers(config: CartesiaTTSConfig) -> dict[str, str]:
|
|
65
|
-
cartesia_api_key = os.environ
|
|
64
|
+
cartesia_api_key = os.environ.get(CARTESIA_API_KEY)
|
|
66
65
|
return {
|
|
67
66
|
"Cartesia-Version": str(config.version),
|
|
68
67
|
"Content-Type": "application/json",
|
|
@@ -89,15 +88,13 @@ class CartesiaTTS(TTSEngine[CartesiaTTSConfig]):
|
|
|
89
88
|
return
|
|
90
89
|
else:
|
|
91
90
|
structlogger.error(
|
|
92
|
-
"
|
|
91
|
+
"azure.synthesize.rest.failed",
|
|
93
92
|
status_code=response.status,
|
|
94
93
|
msg=response.text(),
|
|
95
94
|
)
|
|
96
95
|
raise TTSError(f"TTS failed: {response.text()}")
|
|
97
96
|
except ClientConnectorError as e:
|
|
98
97
|
raise TTSError(e)
|
|
99
|
-
except TimeoutError as e:
|
|
100
|
-
raise TTSError(e)
|
|
101
98
|
|
|
102
99
|
def engine_bytes_to_rasa_audio_bytes(self, chunk: bytes) -> RasaAudioBytes:
|
|
103
100
|
"""Convert the generated tts audio bytes into rasa audio bytes."""
|
|
@@ -108,7 +105,6 @@ class CartesiaTTS(TTSEngine[CartesiaTTSConfig]):
|
|
|
108
105
|
return CartesiaTTSConfig(
|
|
109
106
|
language="en",
|
|
110
107
|
voice="248be419-c632-4f23-adf1-5324ed7dbf1d",
|
|
111
|
-
timeout=10,
|
|
112
108
|
model_id="sonic-english",
|
|
113
109
|
version="2024-06-10",
|
|
114
110
|
)
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
from typing import AsyncIterator, Dict, Generic, Optional,
|
|
1
|
+
from typing import AsyncIterator, Dict, Generic, Optional, Type, TypeVar
|
|
2
2
|
from dataclasses import dataclass
|
|
3
3
|
|
|
4
4
|
from rasa.core.channels.voice_stream.audio_bytes import RasaAudioBytes
|
|
5
5
|
from rasa.core.channels.voice_stream.util import MergeableConfig
|
|
6
6
|
from rasa.shared.exceptions import RasaException
|
|
7
|
-
from rasa.shared.utils.common import validate_environment
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
class TTSError(RasaException):
|
|
@@ -19,20 +18,11 @@ E = TypeVar("E", bound="TTSEngine")
|
|
|
19
18
|
class TTSEngineConfig(MergeableConfig):
|
|
20
19
|
language: Optional[str] = None
|
|
21
20
|
voice: Optional[str] = None
|
|
22
|
-
timeout: Optional[int] = None
|
|
23
21
|
|
|
24
22
|
|
|
25
23
|
class TTSEngine(Generic[T]):
|
|
26
|
-
required_env_vars: Tuple[str, ...] = ()
|
|
27
|
-
required_packages: Tuple[str, ...] = ()
|
|
28
|
-
|
|
29
24
|
def __init__(self, config: Optional[T] = None):
|
|
30
25
|
self.config = self.get_default_config().merge(config)
|
|
31
|
-
validate_environment(
|
|
32
|
-
self.required_env_vars,
|
|
33
|
-
self.required_packages,
|
|
34
|
-
f"TTS Engine {self.__class__.__name__}",
|
|
35
|
-
)
|
|
36
26
|
|
|
37
27
|
async def close_connection(self) -> None:
|
|
38
28
|
"""Cleanup the connection if necessary."""
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import base64
|
|
2
2
|
import json
|
|
3
|
-
import uuid
|
|
4
|
-
|
|
5
3
|
import structlog
|
|
6
|
-
from typing import Any, Awaitable, Callable, Dict, Optional, Text
|
|
4
|
+
from typing import Any, Awaitable, Callable, Dict, List, Optional, Text
|
|
5
|
+
import uuid
|
|
7
6
|
|
|
8
7
|
from sanic import Blueprint, HTTPResponse, Request, response
|
|
9
8
|
from sanic import Websocket # type: ignore
|
|
@@ -11,7 +10,6 @@ from sanic import Websocket # type: ignore
|
|
|
11
10
|
|
|
12
11
|
from rasa.core.channels import UserMessage
|
|
13
12
|
from rasa.core.channels.voice_ready.utils import CallParameters
|
|
14
|
-
from rasa.core.channels.voice_stream.call_state import call_state
|
|
15
13
|
from rasa.core.channels.voice_stream.tts.tts_engine import TTSEngine
|
|
16
14
|
from rasa.core.channels.voice_stream.audio_bytes import RasaAudioBytes
|
|
17
15
|
from rasa.core.channels.voice_stream.voice_channel import (
|
|
@@ -23,7 +21,7 @@ from rasa.core.channels.voice_stream.voice_channel import (
|
|
|
23
21
|
VoiceOutputChannel,
|
|
24
22
|
)
|
|
25
23
|
|
|
26
|
-
|
|
24
|
+
structlogger = structlog.get_logger()
|
|
27
25
|
|
|
28
26
|
|
|
29
27
|
def map_call_params(data: Dict[Text, Any]) -> CallParameters:
|
|
@@ -49,18 +47,10 @@ class TwilioMediaStreamsOutputChannel(VoiceOutputChannel):
|
|
|
49
47
|
) -> bytes:
|
|
50
48
|
return base64.b64encode(rasa_audio_bytes)
|
|
51
49
|
|
|
52
|
-
def
|
|
50
|
+
def channel_bytes_to_messages(
|
|
51
|
+
self, recipient_id: str, channel_bytes: bytes
|
|
52
|
+
) -> List[Any]:
|
|
53
53
|
message_id = uuid.uuid4().hex
|
|
54
|
-
mark_message = json.dumps(
|
|
55
|
-
{
|
|
56
|
-
"event": "mark",
|
|
57
|
-
"streamSid": recipient_id,
|
|
58
|
-
"mark": {"name": message_id},
|
|
59
|
-
}
|
|
60
|
-
)
|
|
61
|
-
return mark_message, message_id
|
|
62
|
-
|
|
63
|
-
def channel_bytes_to_message(self, recipient_id: str, channel_bytes: bytes) -> str:
|
|
64
54
|
media_message = json.dumps(
|
|
65
55
|
{
|
|
66
56
|
"event": "media",
|
|
@@ -70,7 +60,15 @@ class TwilioMediaStreamsOutputChannel(VoiceOutputChannel):
|
|
|
70
60
|
},
|
|
71
61
|
}
|
|
72
62
|
)
|
|
73
|
-
|
|
63
|
+
mark_message = json.dumps(
|
|
64
|
+
{
|
|
65
|
+
"event": "mark",
|
|
66
|
+
"streamSid": recipient_id,
|
|
67
|
+
"mark": {"name": message_id},
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
self.latest_message_id = message_id
|
|
71
|
+
return [media_message, mark_message]
|
|
74
72
|
|
|
75
73
|
|
|
76
74
|
class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
@@ -105,16 +103,9 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
105
103
|
elif data["event"] == "stop":
|
|
106
104
|
return EndConversationAction()
|
|
107
105
|
elif data["event"] == "mark":
|
|
108
|
-
if data["mark"]["name"] ==
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if call_state.should_hangup:
|
|
112
|
-
logger.debug(
|
|
113
|
-
"twilio_streams.hangup", marker=call_state.latest_bot_audio_id
|
|
114
|
-
)
|
|
115
|
-
return EndConversationAction()
|
|
116
|
-
else:
|
|
117
|
-
call_state.is_bot_speaking = True # type: ignore[attr-defined]
|
|
106
|
+
if data["mark"]["name"] == self.hangup_after:
|
|
107
|
+
structlogger.debug("twilio_streams.hangup", marker=self.hangup_after)
|
|
108
|
+
return EndConversationAction()
|
|
118
109
|
return ContinueConversationAction()
|
|
119
110
|
|
|
120
111
|
def create_output_channel(
|
|
@@ -140,7 +131,7 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
140
131
|
self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
|
|
141
132
|
) -> Blueprint:
|
|
142
133
|
"""Defines a Sanic bluelogger.debug."""
|
|
143
|
-
blueprint = Blueprint("
|
|
134
|
+
blueprint = Blueprint("socketio_webhook", __name__)
|
|
144
135
|
|
|
145
136
|
@blueprint.route("/", methods=["GET"])
|
|
146
137
|
async def health(_: Request) -> HTTPResponse:
|
|
@@ -5,7 +5,7 @@ from typing import Optional, Type, TypeVar
|
|
|
5
5
|
|
|
6
6
|
import structlog
|
|
7
7
|
|
|
8
|
-
from rasa.core.channels.voice_stream.audio_bytes import
|
|
8
|
+
from rasa.core.channels.voice_stream.audio_bytes import RasaAudioBytes
|
|
9
9
|
from rasa.shared.exceptions import RasaException
|
|
10
10
|
|
|
11
11
|
structlogger = structlog.get_logger()
|
|
@@ -23,16 +23,16 @@ def read_wav_to_rasa_audio_bytes(file_name: str) -> Optional[RasaAudioBytes]:
|
|
|
23
23
|
wave_data = audioop.lin2lin(wave_data, wave_object.getsampwidth(), 1)
|
|
24
24
|
# 8 bit is unsigned
|
|
25
25
|
# wave_data = audioop.bias(wave_data, 1, 128)
|
|
26
|
-
if wave_object.getframerate() !=
|
|
26
|
+
if wave_object.getframerate() != 8000:
|
|
27
27
|
wave_data, _ = audioop.ratecv(
|
|
28
|
-
wave_data, 1, 1, wave_object.getframerate(),
|
|
28
|
+
wave_data, 1, 1, wave_object.getframerate(), 8000, None
|
|
29
29
|
)
|
|
30
30
|
wave_data = audioop.lin2ulaw(wave_data, 1)
|
|
31
31
|
return RasaAudioBytes(wave_data)
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
def generate_silence(length_in_seconds: float = 1.0) -> RasaAudioBytes:
|
|
35
|
-
return RasaAudioBytes(b"\00" * int(length_in_seconds *
|
|
35
|
+
return RasaAudioBytes(b"\00" * int(length_in_seconds * 8000))
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
T = TypeVar("T", bound="MergeableConfig")
|