rasa-pro 3.12.18.dev1__py3-none-any.whl → 3.13.0a1.dev2__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 (341) hide show
  1. rasa/__init__.py +0 -6
  2. rasa/__main__.py +3 -4
  3. rasa/api.py +1 -1
  4. rasa/builder/create_openai_vector_store.py +69 -0
  5. rasa/builder/llm-helper-schema.json +69 -0
  6. rasa/builder/prompt_to_bot.py +650 -0
  7. rasa/builder/scrape_rasa_docs.py +97 -0
  8. rasa/builder/skill_to_bot_prompt.jinja +158 -0
  9. rasa/cli/dialogue_understanding_test.py +1 -1
  10. rasa/cli/e2e_test.py +1 -1
  11. rasa/cli/evaluate.py +2 -2
  12. rasa/cli/export.py +3 -3
  13. rasa/cli/llm_fine_tuning.py +1 -1
  14. rasa/cli/project_templates/default/config.yml +5 -32
  15. rasa/cli/project_templates/{calm → default}/e2e_tests/cancelations/user_cancels_during_a_correction.yml +1 -1
  16. rasa/cli/project_templates/{calm → default}/e2e_tests/cancelations/user_changes_mind_on_a_whim.yml +1 -1
  17. rasa/cli/project_templates/{calm → default}/e2e_tests/corrections/user_corrects_contact_handle.yml +1 -1
  18. rasa/cli/project_templates/{calm → default}/e2e_tests/corrections/user_corrects_contact_name.yml +1 -1
  19. rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_adds_contact_to_their_list.yml +1 -1
  20. rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_lists_contacts.yml +1 -1
  21. rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_removes_contact.yml +1 -1
  22. rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_removes_contact_from_list.yml +1 -1
  23. rasa/cli/project_templates/default/endpoints.yml +18 -2
  24. rasa/cli/project_templates/defaults.py +133 -0
  25. rasa/cli/run.py +1 -1
  26. rasa/cli/scaffold.py +2 -3
  27. rasa/cli/studio/download.py +1 -1
  28. rasa/cli/studio/link.py +53 -0
  29. rasa/cli/studio/pull.py +78 -0
  30. rasa/cli/studio/push.py +78 -0
  31. rasa/cli/studio/studio.py +12 -0
  32. rasa/cli/studio/upload.py +5 -3
  33. rasa/cli/train.py +1 -1
  34. rasa/cli/utils.py +1 -1
  35. rasa/cli/x.py +1 -1
  36. rasa/constants.py +2 -0
  37. rasa/core/__init__.py +0 -16
  38. rasa/core/actions/action.py +42 -31
  39. rasa/core/actions/action_repeat_bot_messages.py +18 -22
  40. rasa/core/actions/action_run_slot_rejections.py +1 -2
  41. rasa/core/agent.py +18 -3
  42. rasa/core/available_endpoints.py +146 -0
  43. rasa/core/brokers/kafka.py +4 -0
  44. rasa/core/brokers/pika.py +5 -2
  45. rasa/core/brokers/sql.py +1 -1
  46. rasa/core/channels/botframework.py +2 -2
  47. rasa/core/channels/channel.py +2 -2
  48. rasa/core/channels/development_inspector.py +1 -1
  49. rasa/core/channels/facebook.py +1 -4
  50. rasa/core/channels/hangouts.py +8 -5
  51. rasa/core/channels/inspector/.eslintrc.cjs +12 -6
  52. rasa/core/channels/inspector/.prettierrc +5 -0
  53. rasa/core/channels/inspector/README.md +11 -5
  54. rasa/core/channels/inspector/dist/assets/{arc-9f75cc3b.js → arc-02053cc1.js} +1 -1
  55. rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-7f34db23.js → blockDiagram-38ab4fdb-008b6289.js} +1 -1
  56. rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-948bab2c.js → c4Diagram-3d4e48cf-fb2597be.js} +1 -1
  57. rasa/core/channels/inspector/dist/assets/channel-078dada8.js +1 -0
  58. rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-53b0dd0e.js → classDiagram-70f12bd4-7f847e00.js} +1 -1
  59. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-fdf789e7.js → classDiagram-v2-f2320105-ba1d689b.js} +1 -1
  60. rasa/core/channels/inspector/dist/assets/clone-5b4516de.js +1 -0
  61. rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-87c4ece5.js → createText-2e5e7dd3-dd8e67c4.js} +1 -1
  62. rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-5a8b0749.js → edges-e0da2a9e-10784939.js} +1 -1
  63. rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-66da90e2.js → erDiagram-9861fffd-24947ae6.js} +1 -1
  64. rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-10044f05.js → flowDb-956e92f1-a9ced505.js} +1 -1
  65. rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-f338f66a.js → flowDiagram-66a62f08-afda9c7c.js} +1 -1
  66. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-f9613071.js +1 -0
  67. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-b13140aa.js → flowchart-elk-definition-4a651766-6ef530b8.js} +1 -1
  68. rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-f2b4a55a.js → ganttDiagram-c361ad54-0c7dd39a.js} +1 -1
  69. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-dedc298d.js → gitGraphDiagram-72cf32ee-b57239d6.js} +1 -1
  70. rasa/core/channels/inspector/dist/assets/{graph-4ede11ff.js → graph-9ed57cec.js} +1 -1
  71. rasa/core/channels/inspector/dist/assets/{index-3862675e-65549d37.js → index-3862675e-233090de.js} +1 -1
  72. rasa/core/channels/inspector/dist/assets/{index-3a23e736.js → index-72184470.js} +123 -123
  73. rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-65439671.js → infoDiagram-f8f76790-aa116649.js} +1 -1
  74. rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-56d03d98.js → journeyDiagram-49397b02-e51877cc.js} +1 -1
  75. rasa/core/channels/inspector/dist/assets/{layout-dd48f7f4.js → layout-3ca3798c.js} +1 -1
  76. rasa/core/channels/inspector/dist/assets/{line-1569ad2c.js → line-26ee10d3.js} +1 -1
  77. rasa/core/channels/inspector/dist/assets/{linear-48bf4935.js → linear-aedded32.js} +1 -1
  78. rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-688504c1.js → mindmap-definition-fc14e90a-d8957261.js} +1 -1
  79. rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-78b6d7e6.js → pieDiagram-8a3498a8-d771f885.js} +1 -1
  80. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-048b84b3.js → quadrantDiagram-120e2f19-09fdf50c.js} +1 -1
  81. rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-dd67f107.js → requirementDiagram-deff3bca-9f0af02e.js} +1 -1
  82. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-8128436e.js → sankeyDiagram-04a897e0-84415b37.js} +1 -1
  83. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-1a0d1461.js → sequenceDiagram-704730f1-8dec4055.js} +1 -1
  84. rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-46d388ed.js → stateDiagram-587899a1-c5431d07.js} +1 -1
  85. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-ea42951a.js → stateDiagram-v2-d93cdb3a-274e77d9.js} +1 -1
  86. rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-7427ed0c.js → styles-6aaf32cf-e364a1d7.js} +1 -1
  87. rasa/core/channels/inspector/dist/assets/{styles-9a916d00-ff5e5a16.js → styles-9a916d00-0dae36f6.js} +1 -1
  88. rasa/core/channels/inspector/dist/assets/{styles-c10674c1-7b3680cf.js → styles-c10674c1-c4641675.js} +1 -1
  89. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-f860f2ad.js → svgDrawCommon-08f97a94-831fe9a1.js} +1 -1
  90. rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-2eebf0c8.js → timeline-definition-85554ec2-c3304b3a.js} +1 -1
  91. rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-5d7f4e96.js → xychartDiagram-e933f94c-da799369.js} +1 -1
  92. rasa/core/channels/inspector/dist/index.html +1 -1
  93. rasa/core/channels/inspector/package.json +3 -1
  94. rasa/core/channels/inspector/src/App.tsx +91 -90
  95. rasa/core/channels/inspector/src/components/Chat.tsx +45 -41
  96. rasa/core/channels/inspector/src/components/DiagramFlow.tsx +40 -40
  97. rasa/core/channels/inspector/src/components/DialogueInformation.tsx +57 -57
  98. rasa/core/channels/inspector/src/components/DialogueStack.tsx +36 -27
  99. rasa/core/channels/inspector/src/components/ExpandIcon.tsx +4 -4
  100. rasa/core/channels/inspector/src/components/FullscreenButton.tsx +7 -7
  101. rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +28 -12
  102. rasa/core/channels/inspector/src/components/NoActiveFlow.tsx +9 -9
  103. rasa/core/channels/inspector/src/components/RasaLogo.tsx +5 -5
  104. rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +55 -60
  105. rasa/core/channels/inspector/src/components/SaraDiagrams.tsx +5 -5
  106. rasa/core/channels/inspector/src/components/Slots.tsx +22 -22
  107. rasa/core/channels/inspector/src/components/Welcome.tsx +28 -31
  108. rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +245 -0
  109. rasa/core/channels/inspector/src/helpers/audio/microphone-processor.js +12 -0
  110. rasa/core/channels/inspector/src/helpers/audio/playback-processor.js +36 -0
  111. rasa/core/channels/inspector/src/helpers/conversation.ts +7 -7
  112. rasa/core/channels/inspector/src/helpers/formatters.test.ts +181 -181
  113. rasa/core/channels/inspector/src/helpers/formatters.ts +111 -111
  114. rasa/core/channels/inspector/src/helpers/utils.ts +78 -61
  115. rasa/core/channels/inspector/src/main.tsx +8 -8
  116. rasa/core/channels/inspector/src/theme/Button/Button.ts +8 -8
  117. rasa/core/channels/inspector/src/theme/Heading/Heading.ts +7 -7
  118. rasa/core/channels/inspector/src/theme/Input/Input.ts +9 -9
  119. rasa/core/channels/inspector/src/theme/Link/Link.ts +6 -6
  120. rasa/core/channels/inspector/src/theme/Modal/Modal.ts +13 -13
  121. rasa/core/channels/inspector/src/theme/Table/Table.tsx +10 -10
  122. rasa/core/channels/inspector/src/theme/Tooltip/Tooltip.ts +5 -5
  123. rasa/core/channels/inspector/src/theme/base/breakpoints.ts +7 -7
  124. rasa/core/channels/inspector/src/theme/base/colors.ts +64 -64
  125. rasa/core/channels/inspector/src/theme/base/fonts/fontFaces.css +21 -18
  126. rasa/core/channels/inspector/src/theme/base/radii.ts +8 -8
  127. rasa/core/channels/inspector/src/theme/base/shadows.ts +5 -5
  128. rasa/core/channels/inspector/src/theme/base/sizes.ts +5 -5
  129. rasa/core/channels/inspector/src/theme/base/space.ts +12 -12
  130. rasa/core/channels/inspector/src/theme/base/styles.ts +5 -5
  131. rasa/core/channels/inspector/src/theme/base/typography.ts +12 -12
  132. rasa/core/channels/inspector/src/theme/base/zIndices.ts +3 -3
  133. rasa/core/channels/inspector/src/theme/index.ts +38 -38
  134. rasa/core/channels/inspector/src/types.ts +56 -50
  135. rasa/core/channels/inspector/yarn.lock +5 -0
  136. rasa/core/channels/mattermost.py +1 -1
  137. rasa/core/channels/rasa_chat.py +2 -4
  138. rasa/core/channels/rest.py +5 -4
  139. rasa/core/channels/socketio.py +56 -41
  140. rasa/core/channels/studio_chat.py +337 -71
  141. rasa/core/channels/vier_cvg.py +1 -2
  142. rasa/core/channels/voice_ready/audiocodes.py +4 -11
  143. rasa/core/channels/voice_stream/audiocodes.py +8 -5
  144. rasa/core/channels/voice_stream/browser_audio.py +1 -1
  145. rasa/core/channels/voice_stream/genesys.py +2 -2
  146. rasa/core/channels/voice_stream/tts/__init__.py +8 -0
  147. rasa/core/channels/voice_stream/twilio_media_streams.py +10 -5
  148. rasa/core/channels/voice_stream/voice_channel.py +65 -23
  149. rasa/core/concurrent_lock_store.py +24 -10
  150. rasa/core/evaluation/marker_tracker_loader.py +1 -1
  151. rasa/core/exporter.py +1 -1
  152. rasa/core/http_interpreter.py +3 -7
  153. rasa/core/information_retrieval/faiss.py +18 -11
  154. rasa/core/information_retrieval/ingestion/__init__.py +0 -0
  155. rasa/core/information_retrieval/ingestion/faq_parser.py +158 -0
  156. rasa/core/jobs.py +2 -1
  157. rasa/core/lock_store.py +151 -60
  158. rasa/core/nlg/contextual_response_rephraser.py +17 -7
  159. rasa/core/nlg/generator.py +5 -22
  160. rasa/core/nlg/interpolator.py +2 -3
  161. rasa/core/nlg/response.py +6 -43
  162. rasa/core/nlg/summarize.py +1 -1
  163. rasa/core/nlg/translate.py +0 -8
  164. rasa/core/policies/enterprise_search_policy.py +262 -62
  165. rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +63 -0
  166. rasa/core/policies/flow_policy.py +1 -1
  167. rasa/core/policies/flows/flow_executor.py +96 -17
  168. rasa/core/policies/intentless_policy.py +57 -20
  169. rasa/core/processor.py +114 -54
  170. rasa/core/run.py +33 -11
  171. rasa/core/tracker_stores/__init__.py +0 -0
  172. rasa/core/{auth_retry_tracker_store.py → tracker_stores/auth_retry_tracker_store.py} +5 -1
  173. rasa/core/tracker_stores/dynamo_tracker_store.py +218 -0
  174. rasa/core/tracker_stores/mongo_tracker_store.py +206 -0
  175. rasa/core/tracker_stores/redis_tracker_store.py +219 -0
  176. rasa/core/tracker_stores/sql_tracker_store.py +555 -0
  177. rasa/core/tracker_stores/tracker_store.py +805 -0
  178. rasa/core/training/interactive.py +1 -1
  179. rasa/core/utils.py +24 -95
  180. rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -1
  181. rasa/dialogue_understanding/coexistence/llm_based_router.py +10 -6
  182. rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -0
  183. rasa/dialogue_understanding/commands/cancel_flow_command.py +5 -1
  184. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -0
  185. rasa/dialogue_understanding/commands/clarify_command.py +4 -0
  186. rasa/dialogue_understanding/commands/command_syntax_manager.py +1 -0
  187. rasa/dialogue_understanding/commands/correct_slots_command.py +1 -3
  188. rasa/dialogue_understanding/commands/human_handoff_command.py +2 -0
  189. rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -0
  190. rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +2 -0
  191. rasa/dialogue_understanding/commands/set_slot_command.py +10 -0
  192. rasa/dialogue_understanding/commands/skip_question_command.py +2 -0
  193. rasa/dialogue_understanding/commands/start_flow_command.py +4 -0
  194. rasa/dialogue_understanding/commands/utils.py +26 -2
  195. rasa/dialogue_understanding/generator/__init__.py +7 -1
  196. rasa/dialogue_understanding/generator/command_generator.py +4 -2
  197. rasa/dialogue_understanding/generator/command_parser.py +2 -2
  198. rasa/dialogue_understanding/generator/command_parser_validator.py +63 -0
  199. rasa/dialogue_understanding/generator/llm_based_command_generator.py +5 -17
  200. rasa/dialogue_understanding/generator/llm_command_generator.py +1 -3
  201. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +4 -44
  202. rasa/dialogue_understanding/generator/nlu_command_adapter.py +2 -2
  203. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +78 -0
  204. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +26 -474
  205. rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +147 -0
  206. rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +477 -0
  207. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +11 -64
  208. rasa/dialogue_understanding/patterns/cancel.py +1 -2
  209. rasa/dialogue_understanding/patterns/clarify.py +1 -1
  210. rasa/dialogue_understanding/patterns/correction.py +2 -2
  211. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +37 -25
  212. rasa/dialogue_understanding/patterns/domain_for_patterns.py +190 -0
  213. rasa/dialogue_understanding/processor/command_processor.py +6 -7
  214. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +17 -4
  215. rasa/dialogue_understanding/stack/utils.py +3 -1
  216. rasa/dialogue_understanding/utils.py +68 -12
  217. rasa/dialogue_understanding_test/command_metric_calculation.py +7 -40
  218. rasa/dialogue_understanding_test/command_metrics.py +38 -0
  219. rasa/dialogue_understanding_test/du_test_case.py +58 -25
  220. rasa/dialogue_understanding_test/du_test_result.py +228 -132
  221. rasa/dialogue_understanding_test/du_test_runner.py +11 -2
  222. rasa/dialogue_understanding_test/io.py +35 -8
  223. rasa/e2e_test/e2e_test_runner.py +1 -1
  224. rasa/engine/constants.py +1 -1
  225. rasa/engine/graph.py +2 -2
  226. rasa/engine/recipes/default_recipe.py +1 -1
  227. rasa/engine/validation.py +3 -2
  228. rasa/hooks.py +2 -85
  229. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +1 -5
  230. rasa/llm_fine_tuning/utils.py +2 -4
  231. rasa/model_manager/model_api.py +90 -2
  232. rasa/model_manager/socket_bridge.py +0 -7
  233. rasa/model_manager/trainer_service.py +15 -12
  234. rasa/plugin.py +2 -15
  235. rasa/privacy/__init__.py +0 -0
  236. rasa/privacy/constants.py +83 -0
  237. rasa/privacy/event_broker_utils.py +77 -0
  238. rasa/privacy/privacy_config.py +281 -0
  239. rasa/privacy/privacy_config_schema.json +86 -0
  240. rasa/privacy/privacy_filter.py +340 -0
  241. rasa/privacy/privacy_manager.py +576 -0
  242. rasa/server.py +23 -2
  243. rasa/shared/constants.py +13 -4
  244. rasa/shared/core/command_payload_reader.py +1 -5
  245. rasa/shared/core/constants.py +4 -3
  246. rasa/shared/core/domain.py +172 -11
  247. rasa/shared/core/events.py +100 -6
  248. rasa/shared/core/flows/flow.py +35 -8
  249. rasa/shared/core/flows/flow_step.py +26 -4
  250. rasa/shared/core/flows/flow_step_links.py +15 -0
  251. rasa/shared/core/flows/flow_step_sequence.py +6 -0
  252. rasa/shared/core/flows/flows_yaml_schema.json +3 -0
  253. rasa/shared/core/flows/nlu_trigger.py +13 -0
  254. rasa/shared/core/flows/steps/action.py +7 -4
  255. rasa/shared/core/flows/steps/call.py +11 -4
  256. rasa/shared/core/flows/steps/collect.py +71 -6
  257. rasa/shared/core/flows/steps/internal.py +6 -1
  258. rasa/shared/core/flows/steps/link.py +7 -4
  259. rasa/shared/core/flows/steps/no_operation.py +7 -4
  260. rasa/shared/core/flows/steps/set_slots.py +8 -4
  261. rasa/shared/core/flows/validation.py +16 -3
  262. rasa/shared/core/flows/yaml_flows_io.py +106 -5
  263. rasa/shared/core/slots.py +33 -1
  264. rasa/shared/core/trackers.py +4 -10
  265. rasa/shared/core/training_data/story_reader/yaml_story_reader.py +1 -4
  266. rasa/shared/importers/importer.py +14 -0
  267. rasa/shared/importers/static.py +63 -0
  268. rasa/shared/providers/constants.py +0 -9
  269. rasa/shared/providers/llm/_base_litellm_client.py +4 -14
  270. rasa/shared/providers/llm/default_litellm_llm_client.py +2 -2
  271. rasa/shared/providers/llm/litellm_router_llm_client.py +7 -17
  272. rasa/shared/providers/llm/llm_client.py +15 -24
  273. rasa/shared/providers/llm/self_hosted_llm_client.py +2 -10
  274. rasa/shared/utils/common.py +43 -1
  275. rasa/shared/utils/llm.py +155 -3
  276. rasa/shared/utils/yaml.py +32 -0
  277. rasa/studio/data_handler.py +3 -3
  278. rasa/studio/download/__init__.py +0 -0
  279. rasa/studio/download/domains.py +49 -0
  280. rasa/studio/download/download.py +416 -0
  281. rasa/studio/download/flows.py +351 -0
  282. rasa/studio/link.py +200 -0
  283. rasa/studio/pull.py +94 -0
  284. rasa/studio/push.py +131 -0
  285. rasa/studio/results_logger.py +6 -1
  286. rasa/studio/upload.py +185 -71
  287. rasa/telemetry.py +83 -26
  288. rasa/tracing/config.py +4 -5
  289. rasa/tracing/constants.py +19 -1
  290. rasa/tracing/instrumentation/attribute_extractors.py +49 -11
  291. rasa/tracing/instrumentation/instrumentation.py +54 -3
  292. rasa/tracing/instrumentation/metrics.py +98 -15
  293. rasa/tracing/metric_instrument_provider.py +75 -3
  294. rasa/utils/common.py +37 -27
  295. rasa/utils/endpoints.py +22 -1
  296. rasa/utils/licensing.py +2 -3
  297. rasa/utils/log_utils.py +1 -45
  298. rasa/validator.py +9 -11
  299. rasa/version.py +1 -1
  300. {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev2.dist-info}/METADATA +12 -14
  301. {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev2.dist-info}/RECORD +318 -294
  302. rasa/anonymization/__init__.py +0 -2
  303. rasa/anonymization/anonymisation_rule_yaml_reader.py +0 -91
  304. rasa/anonymization/anonymization_pipeline.py +0 -286
  305. rasa/anonymization/anonymization_rule_executor.py +0 -266
  306. rasa/anonymization/anonymization_rule_orchestrator.py +0 -119
  307. rasa/anonymization/schemas/config.yml +0 -47
  308. rasa/anonymization/utils.py +0 -118
  309. rasa/cli/project_templates/calm/config.yml +0 -10
  310. rasa/cli/project_templates/calm/credentials.yml +0 -33
  311. rasa/cli/project_templates/calm/endpoints.yml +0 -58
  312. rasa/cli/project_templates/default/actions/actions.py +0 -27
  313. rasa/cli/project_templates/default/data/nlu.yml +0 -91
  314. rasa/cli/project_templates/default/data/rules.yml +0 -13
  315. rasa/cli/project_templates/default/data/stories.yml +0 -30
  316. rasa/cli/project_templates/default/domain.yml +0 -34
  317. rasa/cli/project_templates/default/tests/test_stories.yml +0 -91
  318. rasa/core/channels/inspector/dist/assets/channel-dfa68278.js +0 -1
  319. rasa/core/channels/inspector/dist/assets/clone-edb7f119.js +0 -1
  320. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-65e7c670.js +0 -1
  321. rasa/core/channels/inspector/src/helpers/audiostream.ts +0 -191
  322. rasa/core/tracker_store.py +0 -1792
  323. rasa/monkey_patches.py +0 -91
  324. rasa/studio/download.py +0 -489
  325. /rasa/{cli/project_templates/calm/actions → builder}/__init__.py +0 -0
  326. /rasa/cli/project_templates/{calm → default}/actions/action_template.py +0 -0
  327. /rasa/cli/project_templates/{calm → default}/actions/add_contact.py +0 -0
  328. /rasa/cli/project_templates/{calm → default}/actions/db.py +0 -0
  329. /rasa/cli/project_templates/{calm → default}/actions/list_contacts.py +0 -0
  330. /rasa/cli/project_templates/{calm → default}/actions/remove_contact.py +0 -0
  331. /rasa/cli/project_templates/{calm → default}/data/flows/add_contact.yml +0 -0
  332. /rasa/cli/project_templates/{calm → default}/data/flows/list_contacts.yml +0 -0
  333. /rasa/cli/project_templates/{calm → default}/data/flows/remove_contact.yml +0 -0
  334. /rasa/cli/project_templates/{calm → default}/db/contacts.json +0 -0
  335. /rasa/cli/project_templates/{calm → default}/domain/add_contact.yml +0 -0
  336. /rasa/cli/project_templates/{calm → default}/domain/list_contacts.yml +0 -0
  337. /rasa/cli/project_templates/{calm → default}/domain/remove_contact.yml +0 -0
  338. /rasa/cli/project_templates/{calm → default}/domain/shared.yml +0 -0
  339. {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev2.dist-info}/NOTICE +0 -0
  340. {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev2.dist-info}/WHEEL +0 -0
  341. {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev2.dist-info}/entry_points.txt +0 -0
@@ -1,5 +1,8 @@
1
1
  import asyncio
2
+ import audioop
3
+ import base64
2
4
  import json
5
+ import uuid
3
6
  from functools import partial
4
7
  from typing import (
5
8
  TYPE_CHECKING,
@@ -10,13 +13,25 @@ from typing import (
10
13
  List,
11
14
  Optional,
12
15
  Text,
16
+ Tuple,
13
17
  )
14
18
 
15
19
  import structlog
16
- from sanic import Sanic
17
20
 
21
+ from rasa.core.channels import UserMessage
18
22
  from rasa.core.channels.socketio import SocketBlueprint, SocketIOInput
19
- from rasa.core.exceptions import AgentNotReady
23
+ from rasa.core.channels.voice_ready.utils import CallParameters
24
+ from rasa.core.channels.voice_stream.audio_bytes import RasaAudioBytes
25
+ from rasa.core.channels.voice_stream.call_state import call_state
26
+ from rasa.core.channels.voice_stream.tts import TTSEngine
27
+ from rasa.core.channels.voice_stream.voice_channel import (
28
+ ContinueConversationAction,
29
+ EndConversationAction,
30
+ NewAudioAction,
31
+ VoiceChannelAction,
32
+ VoiceInputChannel,
33
+ VoiceOutputChannel,
34
+ )
20
35
  from rasa.hooks import hookimpl
21
36
  from rasa.plugin import plugin_manager
22
37
  from rasa.shared.core.constants import ACTION_LISTEN_NAME
@@ -24,14 +39,17 @@ from rasa.shared.core.events import ActionExecuted
24
39
  from rasa.shared.core.trackers import EventVerbosity
25
40
 
26
41
  if TYPE_CHECKING:
27
- from rasa.core.channels.channel import UserMessage
42
+ from sanic import Sanic, Websocket # type: ignore[attr-defined]
43
+ from socketio import AsyncServer
44
+
45
+ from rasa.core.channels.channel import InputChannel, UserMessage
28
46
  from rasa.shared.core.trackers import DialogueStateTracker
29
47
 
30
48
 
31
49
  structlogger = structlog.get_logger()
32
50
 
33
51
 
34
- def tracker_as_dump(tracker: "DialogueStateTracker") -> str:
52
+ def tracker_as_dump(tracker: "DialogueStateTracker") -> Dict[str, Any]:
35
53
  """Create a dump of the tracker state."""
36
54
  from rasa.shared.core.trackers import get_trackers_for_conversation_sessions
37
55
 
@@ -42,8 +60,9 @@ def tracker_as_dump(tracker: "DialogueStateTracker") -> str:
42
60
  else:
43
61
  last_tracker = multiple_tracker_sessions[-1]
44
62
 
45
- state = last_tracker.current_state(EventVerbosity.AFTER_RESTART)
46
- return json.dumps(state)
63
+ # TODO: this is a bug: the bridge converts this back to json, but it
64
+ # should be json in the first place
65
+ return last_tracker.current_state(EventVerbosity.AFTER_RESTART)
47
66
 
48
67
 
49
68
  def does_need_action_prediction(tracker: "DialogueStateTracker") -> bool:
@@ -84,7 +103,9 @@ class StudioTrackerUpdatePlugin:
84
103
 
85
104
  def handle_tracker_update(self, tracker: "DialogueStateTracker") -> None:
86
105
  """Handles a tracker update when triggered by a hook."""
87
- structlogger.info("studio_chat.after_tracker_update", tracker=tracker)
106
+ structlogger.info(
107
+ "studio_chat.after_tracker_update", sender_id=tracker.sender_id
108
+ )
88
109
  # directly create a dump to avoid the tracker getting modified by another
89
110
  # function before it gets published (since the publishing is scheduled
90
111
  # as an async task)
@@ -101,43 +122,101 @@ class StudioTrackerUpdatePlugin:
101
122
  self._cancel_tasks()
102
123
 
103
124
 
104
- class StudioChatInput(SocketIOInput):
125
+ class StudioChatInput(SocketIOInput, VoiceInputChannel):
105
126
  """Input channel for the communication between Rasa Studio and Rasa Pro."""
106
127
 
128
+ requires_voice_license = False
129
+
107
130
  @classmethod
108
131
  def name(cls) -> Text:
109
132
  return "studio_chat"
110
133
 
111
134
  def __init__(
112
135
  self,
113
- *args: Any,
114
- **kwargs: Any,
136
+ server_url: str,
137
+ asr_config: Dict,
138
+ tts_config: Dict,
139
+ user_message_evt: Text = "user_uttered",
140
+ bot_message_evt: Text = "bot_uttered",
141
+ namespace: Optional[Text] = None,
142
+ session_persistence: bool = False,
143
+ socketio_path: Optional[Text] = "/socket.io",
144
+ jwt_key: Optional[Text] = None,
145
+ jwt_method: Optional[Text] = "HS256",
146
+ metadata_key: Optional[Text] = "metadata",
115
147
  ) -> None:
116
- """Creates a ``SocketIOInput`` object."""
148
+ """Creates a `StudioChatInput` object."""
117
149
  from rasa.core.agent import Agent
118
150
 
119
- super().__init__(*args, **kwargs)
120
151
  self.agent: Optional[Agent] = None
152
+ self.latest_tracker_session_id = None
153
+
154
+ # Initialize the SocketIO input channel
155
+ SocketIOInput.__init__(
156
+ self,
157
+ user_message_evt=user_message_evt,
158
+ bot_message_evt=bot_message_evt,
159
+ namespace=namespace,
160
+ session_persistence=session_persistence,
161
+ socketio_path=socketio_path,
162
+ jwt_key=jwt_key,
163
+ jwt_method=jwt_method,
164
+ metadata_key=metadata_key,
165
+ )
166
+
167
+ # Initialize the Voice Input Channel
168
+ VoiceInputChannel.__init__(
169
+ self,
170
+ server_url=server_url,
171
+ asr_config=asr_config,
172
+ tts_config=tts_config,
173
+ )
174
+
175
+ # Dictionaries to manage active connections and background tasks
176
+ # `active_connections` holds the active voice sessions
177
+ # `background_tasks` holds the asyncio tasks for voice streaming
178
+ self.active_connections: Dict[str, SocketIOVoiceWebsocketAdapter] = {}
179
+ self.background_tasks: Dict[str, asyncio.Task] = {}
121
180
 
122
181
  self._register_tracker_update_hook()
123
182
 
124
- async def emit(self, event: str, data: Dict, room: str) -> None:
125
- """Emits an event to the websocket."""
126
- if not self.sio:
127
- structlogger.error("studio_chat.emit.sio_not_initialized")
128
- return
129
- await self.sio.emit(event, data, room=room)
183
+ @classmethod
184
+ def from_credentials(cls, credentials: Optional[Dict[Text, Any]]) -> "InputChannel":
185
+ """Creates a StudioChatInput channel from credentials."""
186
+ credentials = credentials or {}
187
+
188
+ return cls(
189
+ # Voice specific parameters
190
+ server_url=credentials.get("server_url", ""),
191
+ asr_config=credentials.get("asr", {}),
192
+ tts_config=credentials.get("tts", {}),
193
+ # SocketIO parameters
194
+ user_message_evt=credentials.get("user_message_evt", "user_uttered"),
195
+ bot_message_evt=credentials.get("bot_message_evt", "bot_uttered"),
196
+ namespace=credentials.get("namespace"),
197
+ session_persistence=credentials.get("session_persistence", False),
198
+ socketio_path=credentials.get("socketio_path", "/socket.io"),
199
+ jwt_key=credentials.get("jwt_key"),
200
+ jwt_method=credentials.get("jwt_method", "HS256"),
201
+ metadata_key=credentials.get("metadata_key", "metadata"),
202
+ )
130
203
 
131
204
  def _register_tracker_update_hook(self) -> None:
132
205
  plugin_manager().register(StudioTrackerUpdatePlugin(self))
133
206
 
134
207
  async def on_tracker_updated(self, tracker: "DialogueStateTracker") -> None:
135
208
  """Triggers a tracker update notification after a change to the tracker."""
209
+ # we need the latest session id to use it for the llm helper to get the
210
+ # most recent conversation the user had with the bot.
211
+ self.latest_tracker_session_id = tracker.sender_id
136
212
  await self.publish_tracker_update(tracker.sender_id, tracker_as_dump(tracker))
137
213
 
138
214
  async def publish_tracker_update(self, sender_id: str, tracker_dump: Dict) -> None:
139
215
  """Publishes a tracker update notification to the websocket."""
140
- await self.emit("tracker", tracker_dump, room=sender_id)
216
+ if not self.sio:
217
+ structlogger.error("studio_chat.on_tracker_updated.sio_not_initialized")
218
+ return
219
+ await self.sio.emit("tracker", tracker_dump, room=sender_id)
141
220
 
142
221
  async def on_message_proxy(
143
222
  self,
@@ -150,15 +229,8 @@ class StudioChatInput(SocketIOInput):
150
229
  """
151
230
  await on_new_message(message)
152
231
 
153
- if not self.agent or not self.agent.is_ready():
232
+ if not self.agent:
154
233
  structlogger.error("studio_chat.on_message_proxy.agent_not_initialized")
155
- await self.emit_error(
156
- "The Rasa Pro model could not be loaded. "
157
- "Please check the training and deployment logs "
158
- "for more information.",
159
- message.sender_id,
160
- AgentNotReady("The Rasa Pro model could not be loaded."),
161
- )
162
234
  return
163
235
 
164
236
  tracker = await self.agent.tracker_store.retrieve(message.sender_id)
@@ -168,17 +240,6 @@ class StudioChatInput(SocketIOInput):
168
240
 
169
241
  await self.on_tracker_updated(tracker)
170
242
 
171
- async def emit_error(self, message: str, room: str, e: Exception) -> None:
172
- await self.emit(
173
- "error",
174
- {
175
- "message": message,
176
- "error": str(e),
177
- "exception": str(type(e).__name__),
178
- },
179
- room=room,
180
- )
181
-
182
243
  async def handle_tracker_update(self, sid: str, data: Dict) -> None:
183
244
  from rasa.shared.core.trackers import DialogueStateTracker
184
245
 
@@ -195,44 +256,134 @@ class StudioChatInput(SocketIOInput):
195
256
  structlogger.error("studio_chat.sio.domain_not_initialized")
196
257
  return None
197
258
 
198
- tracker: Optional[DialogueStateTracker] = None
199
-
200
259
  async with self.agent.lock_store.lock(data["sender_id"]):
201
- try:
202
- tracker = DialogueStateTracker.from_dict(
203
- data["sender_id"], data["events"], domain.slots
204
- )
260
+ tracker = DialogueStateTracker.from_dict(
261
+ data["sender_id"], data["events"], domain.slots
262
+ )
263
+
264
+ # will override an existing tracker with the same id!
265
+ await self.agent.tracker_store.save(tracker)
205
266
 
206
- # will override an existing tracker with the same id!
267
+ processor = self.agent.processor
268
+ if processor and does_need_action_prediction(tracker):
269
+ output_channel = self.get_output_channel()
270
+
271
+ await processor._run_prediction_loop(output_channel, tracker)
207
272
  await self.agent.tracker_store.save(tracker)
208
273
 
209
- processor = self.agent.processor
210
- if processor and does_need_action_prediction(tracker):
211
- output_channel = self.get_output_channel()
212
-
213
- await processor._run_prediction_loop(output_channel, tracker)
214
- await processor.run_anonymization_pipeline(tracker)
215
- await self.agent.tracker_store.save(tracker)
216
- except Exception as e:
217
- structlogger.error(
218
- "studio_chat.sio.handle_tracker_update.error",
219
- error=e,
220
- sender_id=data["sender_id"],
221
- )
222
- await self.emit_error(
223
- "An error occurred while updating the conversation.",
224
- data["sender_id"],
225
- e,
226
- )
227
-
228
- if not tracker:
229
- # in case the tracker couldn't be updated, we retrieve the prior
230
- # version and use that to populate the update
231
- tracker = await self.agent.tracker_store.get_or_create_tracker(
232
- data["sender_id"]
233
- )
234
274
  await self.on_tracker_updated(tracker)
235
275
 
276
+ def channel_bytes_to_rasa_audio_bytes(self, input_bytes: bytes) -> RasaAudioBytes:
277
+ """Voice method to convert channel bytes to RasaAudioBytes."""
278
+ return RasaAudioBytes(audioop.lin2ulaw(input_bytes, 4))
279
+
280
+ async def collect_call_parameters(
281
+ self, channel_websocket: "Websocket"
282
+ ) -> Optional[CallParameters]:
283
+ """Voice method to collect call parameters."""
284
+ session_id = channel_websocket.session_id
285
+ return CallParameters(session_id, "local", "local", stream_id=session_id)
286
+
287
+ def map_input_message(
288
+ self,
289
+ message: Any,
290
+ ws: "Websocket",
291
+ ) -> VoiceChannelAction:
292
+ """Voice method to map websocket messages to actions."""
293
+ if "audio" in message:
294
+ channel_bytes = base64.b64decode(message["audio"])
295
+ audio_bytes = self.channel_bytes_to_rasa_audio_bytes(channel_bytes)
296
+ return NewAudioAction(audio_bytes)
297
+ elif "marker" in message:
298
+ if message["marker"] == call_state.latest_bot_audio_id:
299
+ # Just finished streaming last audio bytes
300
+ call_state.is_bot_speaking = False # type: ignore[attr-defined]
301
+ if call_state.should_hangup:
302
+ structlogger.debug(
303
+ "studio_chat.hangup", marker=call_state.latest_bot_audio_id
304
+ )
305
+ return EndConversationAction()
306
+ else:
307
+ call_state.is_bot_speaking = True # type: ignore[attr-defined]
308
+ return ContinueConversationAction()
309
+
310
+ def create_output_channel(
311
+ self, voice_websocket: "Websocket", tts_engine: TTSEngine
312
+ ) -> VoiceOutputChannel:
313
+ """Create a voice output channel."""
314
+ return StudioVoiceOutputChannel(
315
+ voice_websocket,
316
+ tts_engine,
317
+ self.tts_cache,
318
+ )
319
+
320
+ def _start_voice_session(
321
+ self,
322
+ session_id: str,
323
+ sid: str,
324
+ on_new_message: Callable[[UserMessage], Awaitable[Any]],
325
+ ) -> None:
326
+ """Create SocketIO WebSocket Adaptor & start async task for voice streaming."""
327
+ if sid in self.active_connections:
328
+ structlogger.warning(
329
+ "studio_chat._start_voice_session.session_already_active",
330
+ session_id=sid,
331
+ )
332
+ return
333
+
334
+ structlogger.info(
335
+ "studio_chat._start_voice_session.starting_session", session_id=sid
336
+ )
337
+
338
+ # Create a websocket adapter for this connection
339
+ ws_adapter = SocketIOVoiceWebsocketAdapter(
340
+ sio=self.sio,
341
+ session_id=session_id,
342
+ sid=sid,
343
+ bot_message_evt=self.bot_message_evt,
344
+ )
345
+ self.active_connections[sid] = ws_adapter
346
+
347
+ # Start voice streaming in an async task
348
+ task = asyncio.create_task(
349
+ self._handle_voice_streaming(on_new_message, ws_adapter, sid)
350
+ )
351
+ self.background_tasks[sid] = task
352
+ task.add_done_callback(lambda _: self._cleanup_tasks_for_sid(sid))
353
+
354
+ async def _handle_voice_streaming(
355
+ self,
356
+ on_new_message: Callable[[UserMessage], Awaitable[Any]],
357
+ ws_adapter: "Websocket",
358
+ sid: str,
359
+ ) -> None:
360
+ """Handle voice streaming for a Socket.IO connection."""
361
+ try:
362
+ await self.run_audio_streaming(on_new_message, ws_adapter)
363
+ except Exception as e:
364
+ structlogger.exception(
365
+ "studio_voice.voice_streaming.error",
366
+ error=str(e),
367
+ sid=sid,
368
+ )
369
+ if sid in self.active_connections:
370
+ del self.active_connections[sid]
371
+
372
+ def _cleanup_tasks_for_sid(self, sid: str) -> None:
373
+ if sid in self.background_tasks:
374
+ task = self.background_tasks.pop(sid)
375
+ task.cancel()
376
+ if sid in self.active_connections:
377
+ del self.active_connections[sid]
378
+
379
+ @hookimpl # type: ignore[misc]
380
+ def after_server_stop(self) -> None:
381
+ """Cleanup background tasks and active connections when the server stops."""
382
+ structlogger.info("studio_chat.after_server_stop.cleanup")
383
+ self.active_connections.clear()
384
+ for task in self.background_tasks.values():
385
+ task.cancel()
386
+
236
387
  def blueprint(
237
388
  self, on_new_message: Callable[["UserMessage"], Awaitable[Any]]
238
389
  ) -> SocketBlueprint:
@@ -245,11 +396,126 @@ class StudioChatInput(SocketIOInput):
245
396
  return socket_blueprint
246
397
 
247
398
  @socket_blueprint.listener("after_server_start") # type: ignore[misc]
248
- async def after_server_start(app: Sanic, _: asyncio.AbstractEventLoop) -> None:
399
+ async def after_server_start(
400
+ app: "Sanic", _: asyncio.AbstractEventLoop
401
+ ) -> None:
249
402
  self.agent = app.ctx.agent
250
403
 
404
+ @self.sio.on("disconnect", namespace=self.namespace)
405
+ async def disconnect(sid: Text) -> None:
406
+ structlogger.debug("studio_chat.sio.disconnect", sid=sid)
407
+ self._cleanup_tasks_for_sid(sid)
408
+
409
+ @self.sio.on("session_request", namespace=self.namespace)
410
+ async def session_request(sid: Text, data: Optional[Dict]) -> None:
411
+ """Overrides the base SocketIOInput session_request handler.
412
+
413
+ Args:
414
+ sid: ID of the session (from SocketIO).
415
+ data:
416
+ - session_id: Studio Chat channel is used with a Bridge Architecture
417
+ (Model Service's Socket Bridge), so we use session_id to remain
418
+ consistent across the bridge. Session ID becomes the sender_id
419
+ for the UserMessage.
420
+ - is_voice: Boolean indicating if its a voice session.
421
+ """
422
+ # Call parent session_request handler first
423
+ await self.handle_session_request(sid, data)
424
+
425
+ # start a voice session if requested
426
+ if data and data.get("is_voice", False):
427
+ self._start_voice_session(data["session_id"], sid, on_new_message)
428
+
429
+ @self.sio.on(self.user_message_evt, namespace=self.namespace)
430
+ async def handle_message(sid: Text, data: Dict) -> None:
431
+ """Overrides the base SocketIOInput handle_message handler."""
432
+ # Handle voice messages
433
+ if "audio" in data or "marker" in data:
434
+ if sid in self.active_connections:
435
+ # Route audio messages to the voice adapter queue
436
+ ws = self.active_connections[sid]
437
+ ws.put_message(data)
438
+ return
439
+
440
+ # Handle text messages
441
+ await self.handle_user_message(sid, data, on_new_message)
442
+
251
443
  @self.sio.on("update_tracker", namespace=self.namespace)
252
444
  async def on_update_tracker(sid: Text, data: Dict) -> None:
253
445
  await self.handle_tracker_update(sid, data)
254
446
 
255
447
  return socket_blueprint
448
+
449
+
450
+ class StudioVoiceOutputChannel(VoiceOutputChannel):
451
+ @classmethod
452
+ def name(cls) -> str:
453
+ return "studio_chat"
454
+
455
+ def rasa_audio_bytes_to_channel_bytes(
456
+ self, rasa_audio_bytes: RasaAudioBytes
457
+ ) -> bytes:
458
+ return audioop.ulaw2lin(rasa_audio_bytes, 4)
459
+
460
+ def channel_bytes_to_message(self, recipient_id: str, channel_bytes: bytes) -> str:
461
+ return json.dumps({"audio": base64.b64encode(channel_bytes).decode("utf-8")})
462
+
463
+ def create_marker_message(self, recipient_id: str) -> Tuple[str, str]:
464
+ message_id = uuid.uuid4().hex
465
+ return json.dumps({"marker": message_id}), message_id
466
+
467
+
468
+ class SocketIOVoiceWebsocketAdapter:
469
+ """Adapter to make Socket.IO work like a Sanic WebSocket for voice channels."""
470
+
471
+ def __init__(
472
+ self, sio: "AsyncServer", session_id: str, sid: str, bot_message_evt: str
473
+ ) -> None:
474
+ self.sio = sio
475
+ self.bot_message_evt = bot_message_evt
476
+ self._closed = False
477
+ self._receive_queue: asyncio.Queue[Any] = asyncio.Queue()
478
+
479
+ # the messages need to be emitted on room=sid
480
+ self.sid = sid
481
+
482
+ # used by collect_call_parameters
483
+ # ultimately, this becomes the sender_id
484
+ self.session_id = session_id
485
+
486
+ @property
487
+ def closed(self) -> bool:
488
+ return self._closed
489
+
490
+ async def send(self, data: Any) -> None:
491
+ """Send data to the client."""
492
+ if not self.closed:
493
+ await self.sio.emit(self.bot_message_evt, data, room=self.sid)
494
+
495
+ async def recv(self) -> Any:
496
+ """Receive data from the client."""
497
+ if self.closed:
498
+ raise ConnectionError("WebSocket is closed")
499
+ return await self._receive_queue.get()
500
+
501
+ def put_message(self, message: Any) -> None:
502
+ """Put message in the internal receive queue."""
503
+ self._receive_queue.put_nowait(message)
504
+
505
+ async def close(self, code: int = 1000, reason: str = "") -> None:
506
+ """Close the connection."""
507
+ self._closed = True
508
+ # at this point, the client should have disconnected
509
+
510
+ def __aiter__(self) -> "SocketIOVoiceWebsocketAdapter":
511
+ """Allow the adapter to be used in an async for loop."""
512
+ return self
513
+
514
+ async def __anext__(self) -> Any:
515
+ if self.closed:
516
+ raise StopAsyncIteration
517
+ try:
518
+ message = await self.recv()
519
+ return message
520
+ except Exception:
521
+ raise StopAsyncIteration
@@ -129,9 +129,8 @@ class CVGOutput(OutputChannel):
129
129
  )
130
130
 
131
131
  logger.info(
132
- "Creating incoming UserMessage: {text=%s, output_channel=%s, sender_id=%s, metadata=%s}" # noqa: E501
132
+ "Creating incoming UserMessage: {output_channel=%s, sender_id=%s, metadata=%s}" # noqa: E501
133
133
  % (
134
- user_message.text,
135
134
  user_message.output_channel,
136
135
  user_message.sender_id,
137
136
  user_message.metadata,
@@ -149,7 +149,7 @@ class Conversation:
149
149
  structlogger.warning(
150
150
  "audiocodes.handle.activities.empty_input_channel_name",
151
151
  event_info=(
152
- "Audiocodes input channel name is empty "
152
+ f"Audiocodes input channel name is empty "
153
153
  f"for conversation {self.conversation_id}"
154
154
  ),
155
155
  )
@@ -177,7 +177,7 @@ class Conversation:
177
177
  else:
178
178
  structlogger.warning(
179
179
  "audiocodes.handle.activities.unknown_activity_type",
180
- activity=activity,
180
+ activity_type=activity["type"],
181
181
  )
182
182
  continue
183
183
 
@@ -193,16 +193,9 @@ class Conversation:
193
193
  try:
194
194
  await on_new_message(user_msg)
195
195
  except Exception as e: # skipcq: PYL-W0703
196
- if isinstance(user_msg.text, dict):
197
- anonymized_info = json.dumps(user_msg.text)
198
- elif isinstance(user_msg.text, str):
199
- anonymized_info = user_msg.text
200
- else:
201
- anonymized_info = INFO_UNKNOWN
202
-
203
196
  structlogger.exception(
204
197
  "audiocodes.handle.activities.failure",
205
- user_message=copy.deepcopy(anonymized_info),
198
+ sender_id=self.conversation_id,
206
199
  error=e,
207
200
  exc_info=True,
208
201
  )
@@ -495,8 +488,8 @@ class AudiocodesInput(InputChannel):
495
488
  await on_new_message(
496
489
  UserMessage(
497
490
  text=f"{INTENT_MESSAGE_PREFIX}session_end",
498
- input_channel=self.name(),
499
491
  output_channel=None,
492
+ input_channel=self.name(),
500
493
  sender_id=conversation_id,
501
494
  metadata=reason,
502
495
  )
@@ -108,15 +108,19 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
108
108
  server_url: str,
109
109
  asr_config: Dict,
110
110
  tts_config: Dict,
111
- monitor_silence: bool = False,
112
111
  ):
113
112
  mark_as_beta_feature("Audiocodes (audiocodes_stream) Channel")
114
- super().__init__(server_url, asr_config, tts_config, monitor_silence)
113
+ super().__init__(
114
+ server_url=server_url,
115
+ asr_config=asr_config,
116
+ tts_config=tts_config,
117
+ )
115
118
  self.token = token
116
119
 
117
120
  @classmethod
118
121
  def from_credentials(
119
- cls, credentials: Optional[Dict[str, Any]]
122
+ cls,
123
+ credentials: Optional[Dict[str, Any]],
120
124
  ) -> VoiceInputChannel:
121
125
  if not credentials:
122
126
  raise ValueError("No credentials given for Audiocodes voice channel.")
@@ -126,7 +130,6 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
126
130
  server_url=credentials["server_url"],
127
131
  asr_config=credentials["asr"],
128
132
  tts_config=credentials["tts"],
129
- monitor_silence=credentials.get("monitor_silence", False),
130
133
  )
131
134
 
132
135
  def channel_bytes_to_rasa_audio_bytes(self, input_bytes: bytes) -> RasaAudioBytes:
@@ -292,7 +295,7 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
292
295
  def blueprint(
293
296
  self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
294
297
  ) -> Blueprint:
295
- """Defines a Sanic bluelogger.debug."""
298
+ """Defines a Sanic blueprint"""
296
299
  blueprint = Blueprint("audiocodes_stream", __name__)
297
300
 
298
301
  @blueprint.route("/", methods=["GET"])
@@ -97,7 +97,7 @@ class BrowserAudioInputChannel(VoiceInputChannel):
97
97
  def blueprint(
98
98
  self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
99
99
  ) -> Blueprint:
100
- """Defines a Sanic bluelogger.debug."""
100
+ """Defines a Sanic blueprint"""
101
101
  blueprint = Blueprint("browser_audio", __name__)
102
102
 
103
103
  @blueprint.route("/", methods=["GET"])
@@ -99,7 +99,8 @@ class GenesysInputChannel(VoiceInputChannel):
99
99
 
100
100
  @classmethod
101
101
  def from_credentials(
102
- cls, credentials: Optional[Dict[str, Any]]
102
+ cls,
103
+ credentials: Optional[Dict[str, Any]],
103
104
  ) -> VoiceInputChannel:
104
105
  if not credentials:
105
106
  raise ValueError("No credentials given for Genesys voice channel.")
@@ -113,7 +114,6 @@ class GenesysInputChannel(VoiceInputChannel):
113
114
  server_url=credentials["server_url"],
114
115
  asr_config=credentials["asr"],
115
116
  tts_config=credentials["tts"],
116
- monitor_silence=credentials.get("monitor_silence", False),
117
117
  )
118
118
 
119
119
  def _ensure_channel_data_initialized(self) -> None:
@@ -0,0 +1,8 @@
1
+ from rasa.core.channels.voice_stream.tts.tts_cache import TTSCache
2
+ from rasa.core.channels.voice_stream.tts.tts_engine import (
3
+ TTSEngine,
4
+ TTSEngineConfig,
5
+ TTSError,
6
+ )
7
+
8
+ __all__ = ["TTSEngine", "TTSEngineConfig", "TTSError", "TTSCache"]