rasa-pro 3.11.4__py3-none-any.whl → 3.12.0__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 (580) hide show
  1. README.md +10 -13
  2. rasa/__main__.py +7 -7
  3. rasa/anonymization/anonymisation_rule_yaml_reader.py +1 -1
  4. rasa/anonymization/anonymization_pipeline.py +3 -3
  5. rasa/anonymization/anonymization_rule_executor.py +17 -11
  6. rasa/anonymization/anonymization_rule_orchestrator.py +2 -3
  7. rasa/cli/arguments/data.py +2 -2
  8. rasa/cli/arguments/default_arguments.py +1 -1
  9. rasa/cli/arguments/evaluate.py +2 -1
  10. rasa/cli/arguments/interactive.py +1 -1
  11. rasa/cli/arguments/run.py +1 -1
  12. rasa/cli/arguments/test.py +7 -5
  13. rasa/cli/arguments/train.py +3 -3
  14. rasa/cli/arguments/visualize.py +2 -2
  15. rasa/cli/arguments/x.py +1 -0
  16. rasa/cli/data.py +20 -3
  17. rasa/cli/dialogue_understanding_test.py +386 -0
  18. rasa/cli/evaluate.py +1 -1
  19. rasa/cli/export.py +6 -6
  20. rasa/cli/inspect.py +20 -1
  21. rasa/cli/interactive.py +4 -5
  22. rasa/cli/llm_fine_tuning.py +51 -16
  23. rasa/cli/markers.py +1 -2
  24. rasa/cli/project_templates/calm/actions/add_contact.py +1 -1
  25. rasa/cli/project_templates/calm/config.yml +2 -2
  26. rasa/cli/project_templates/calm/domain/list_contacts.yml +1 -2
  27. rasa/cli/project_templates/calm/domain/remove_contact.yml +1 -2
  28. rasa/cli/project_templates/calm/domain/shared.yml +1 -4
  29. rasa/cli/project_templates/calm/endpoints.yml +2 -2
  30. rasa/cli/project_templates/tutorial/actions/actions.py +3 -2
  31. rasa/cli/shell.py +5 -6
  32. rasa/cli/studio/download.py +1 -2
  33. rasa/cli/studio/studio.py +2 -3
  34. rasa/cli/studio/train.py +0 -1
  35. rasa/cli/telemetry.py +2 -2
  36. rasa/cli/test.py +11 -11
  37. rasa/cli/train.py +3 -0
  38. rasa/cli/utils.py +25 -5
  39. rasa/constants.py +0 -1
  40. rasa/core/__init__.py +0 -1
  41. rasa/core/actions/action.py +137 -208
  42. rasa/core/actions/action_handle_digressions.py +164 -0
  43. rasa/core/actions/action_hangup.py +1 -1
  44. rasa/core/actions/action_repeat_bot_messages.py +2 -2
  45. rasa/core/actions/action_run_slot_rejections.py +18 -6
  46. rasa/core/actions/action_trigger_chitchat.py +1 -1
  47. rasa/core/actions/action_trigger_flow.py +5 -5
  48. rasa/core/actions/action_trigger_search.py +1 -1
  49. rasa/core/actions/custom_action_executor.py +1 -1
  50. rasa/core/actions/direct_custom_actions_executor.py +1 -0
  51. rasa/core/actions/forms.py +22 -15
  52. rasa/core/actions/http_custom_action_executor.py +8 -1
  53. rasa/core/actions/loops.py +3 -3
  54. rasa/core/actions/two_stage_fallback.py +13 -13
  55. rasa/core/auth_retry_tracker_store.py +1 -2
  56. rasa/core/brokers/broker.py +2 -1
  57. rasa/core/brokers/file.py +1 -1
  58. rasa/core/brokers/kafka.py +8 -8
  59. rasa/core/brokers/pika.py +8 -9
  60. rasa/core/brokers/sql.py +4 -3
  61. rasa/core/channels/__init__.py +7 -0
  62. rasa/core/channels/botframework.py +2 -2
  63. rasa/core/channels/callback.py +4 -4
  64. rasa/core/channels/channel.py +11 -11
  65. rasa/core/channels/console.py +0 -1
  66. rasa/core/channels/development_inspector.py +80 -24
  67. rasa/core/channels/facebook.py +5 -5
  68. rasa/core/channels/hangouts.py +7 -8
  69. rasa/core/channels/inspector/dist/assets/Tableau10-1b767f5e.js +1 -0
  70. rasa/core/channels/inspector/dist/assets/arc-9f1365dc.js +1 -0
  71. rasa/core/channels/inspector/dist/assets/blockDiagram-38ab4fdb-e0f81b12.js +118 -0
  72. rasa/core/channels/inspector/dist/assets/c4Diagram-3d4e48cf-9deaee1c.js +10 -0
  73. rasa/core/channels/inspector/dist/assets/channel-44956714.js +1 -0
  74. rasa/core/channels/inspector/dist/assets/classDiagram-70f12bd4-20450a96.js +2 -0
  75. rasa/core/channels/inspector/dist/assets/classDiagram-v2-f2320105-749d2abf.js +2 -0
  76. rasa/core/channels/inspector/dist/assets/clone-a9475142.js +1 -0
  77. rasa/core/channels/inspector/dist/assets/{createText-62fc7601-89c73b31.js → createText-2e5e7dd3-bef0b38c.js} +1 -1
  78. rasa/core/channels/inspector/dist/assets/edges-e0da2a9e-943801a7.js +4 -0
  79. rasa/core/channels/inspector/dist/assets/{erDiagram-9d236eb7-907e0440.js → erDiagram-9861fffd-d523a948.js} +4 -4
  80. rasa/core/channels/inspector/dist/assets/flowDb-956e92f1-54e4cf19.js +10 -0
  81. rasa/core/channels/inspector/dist/assets/flowDiagram-66a62f08-48bfbbe8.js +4 -0
  82. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-43fa749a.js +1 -0
  83. rasa/core/channels/inspector/dist/assets/flowchart-elk-definition-4a651766-17c30827.js +139 -0
  84. rasa/core/channels/inspector/dist/assets/ganttDiagram-c361ad54-43086f2d.js +257 -0
  85. rasa/core/channels/inspector/dist/assets/gitGraphDiagram-72cf32ee-5c8b693e.js +70 -0
  86. rasa/core/channels/inspector/dist/assets/graph-41a90d26.js +1 -0
  87. rasa/core/channels/inspector/dist/assets/index-3862675e-b43eeae9.js +1 -0
  88. rasa/core/channels/inspector/dist/assets/{index-e793d777.js → index-e8affe45.js} +201 -196
  89. rasa/core/channels/inspector/dist/assets/{infoDiagram-736b4530-8ceba4db.js → infoDiagram-f8f76790-0b20676b.js} +1 -1
  90. rasa/core/channels/inspector/dist/assets/{journeyDiagram-df861f2b-960d3809.js → journeyDiagram-49397b02-39bce7b5.js} +4 -4
  91. rasa/core/channels/inspector/dist/assets/katex-498eb57e.js +261 -0
  92. rasa/core/channels/inspector/dist/assets/layout-dc8eeea4.js +1 -0
  93. rasa/core/channels/inspector/dist/assets/{line-eeccc4e2.js → line-c4d2e756.js} +1 -1
  94. rasa/core/channels/inspector/dist/assets/linear-86f6f2d9.js +1 -0
  95. rasa/core/channels/inspector/dist/assets/mindmap-definition-fc14e90a-4216f771.js +312 -0
  96. rasa/core/channels/inspector/dist/assets/{pieDiagram-dbbf0591-dc9b5e1b.js → pieDiagram-8a3498a8-1a0cfa96.js} +7 -7
  97. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-4d7f4fd6-a08cba6d.js → quadrantDiagram-120e2f19-f91e67cf.js} +1 -1
  98. rasa/core/channels/inspector/dist/assets/{requirementDiagram-6fc4c22a-87242b9e.js → requirementDiagram-deff3bca-d4046bed.js} +2 -2
  99. rasa/core/channels/inspector/dist/assets/sankeyDiagram-04a897e0-2cf6d1d7.js +8 -0
  100. rasa/core/channels/inspector/dist/assets/sequenceDiagram-704730f1-751ac4f5.js +122 -0
  101. rasa/core/channels/inspector/dist/assets/stateDiagram-587899a1-f734f4d4.js +1 -0
  102. rasa/core/channels/inspector/dist/assets/stateDiagram-v2-d93cdb3a-91c65710.js +1 -0
  103. rasa/core/channels/inspector/dist/assets/{styles-9c745c82-cef936a6.js → styles-6aaf32cf-e0cff7be.js} +1 -1
  104. rasa/core/channels/inspector/dist/assets/styles-9a916d00-c8029e5d.js +160 -0
  105. rasa/core/channels/inspector/dist/assets/styles-c10674c1-114f312a.js +116 -0
  106. rasa/core/channels/inspector/dist/assets/svgDrawCommon-08f97a94-b7b9dc00.js +1 -0
  107. rasa/core/channels/inspector/dist/assets/{timeline-definition-5b62e21b-0d39bdb2.js → timeline-definition-85554ec2-9536d189.js} +3 -3
  108. rasa/core/channels/inspector/dist/assets/{xychartDiagram-2b33534f-a03fa445.js → xychartDiagram-e933f94c-bf3b0f36.js} +3 -3
  109. rasa/core/channels/inspector/dist/index.html +1 -1
  110. rasa/core/channels/inspector/package.json +11 -3
  111. rasa/core/channels/inspector/src/App.tsx +15 -2
  112. rasa/core/channels/inspector/src/components/RasaLogo.tsx +31 -0
  113. rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +68 -0
  114. rasa/core/channels/inspector/src/components/Welcome.tsx +19 -13
  115. rasa/core/channels/inspector/yarn.lock +94 -99
  116. rasa/core/channels/mattermost.py +4 -4
  117. rasa/core/channels/rasa_chat.py +4 -4
  118. rasa/core/channels/rest.py +11 -12
  119. rasa/core/channels/rocketchat.py +4 -3
  120. rasa/core/channels/slack.py +6 -5
  121. rasa/core/channels/socketio.py +8 -28
  122. rasa/core/channels/studio_chat.py +212 -0
  123. rasa/core/channels/telegram.py +105 -55
  124. rasa/core/channels/twilio.py +3 -3
  125. rasa/core/channels/vier_cvg.py +2 -2
  126. rasa/core/channels/voice_ready/audiocodes.py +51 -32
  127. rasa/core/channels/voice_ready/jambonz.py +5 -5
  128. rasa/core/channels/voice_ready/jambonz_protocol.py +3 -4
  129. rasa/core/channels/voice_ready/twilio_voice.py +9 -8
  130. rasa/core/channels/voice_ready/utils.py +2 -2
  131. rasa/core/channels/voice_stream/asr/asr_engine.py +12 -6
  132. rasa/core/channels/voice_stream/asr/asr_event.py +5 -0
  133. rasa/core/channels/voice_stream/asr/azure.py +16 -3
  134. rasa/core/channels/voice_stream/asr/deepgram.py +76 -19
  135. rasa/core/channels/voice_stream/audiocodes.py +292 -0
  136. rasa/core/channels/voice_stream/browser_audio.py +14 -7
  137. rasa/core/channels/voice_stream/call_state.py +6 -2
  138. rasa/core/channels/voice_stream/genesys.py +320 -0
  139. rasa/core/channels/voice_stream/tts/azure.py +13 -5
  140. rasa/core/channels/voice_stream/tts/cartesia.py +34 -14
  141. rasa/core/channels/voice_stream/tts/tts_cache.py +3 -2
  142. rasa/core/channels/voice_stream/tts/tts_engine.py +1 -1
  143. rasa/core/channels/voice_stream/twilio_media_streams.py +12 -8
  144. rasa/core/channels/voice_stream/util.py +1 -1
  145. rasa/core/channels/voice_stream/voice_channel.py +100 -56
  146. rasa/core/channels/webexteams.py +3 -4
  147. rasa/core/constants.py +2 -0
  148. rasa/core/evaluation/marker.py +7 -6
  149. rasa/core/evaluation/marker_base.py +15 -16
  150. rasa/core/evaluation/marker_stats.py +3 -4
  151. rasa/core/evaluation/marker_tracker_loader.py +5 -4
  152. rasa/core/exporter.py +4 -4
  153. rasa/core/featurizers/precomputation.py +8 -8
  154. rasa/core/featurizers/single_state_featurizer.py +7 -7
  155. rasa/core/featurizers/tracker_featurizers.py +13 -13
  156. rasa/core/http_interpreter.py +3 -4
  157. rasa/core/information_retrieval/__init__.py +1 -1
  158. rasa/core/information_retrieval/faiss.py +4 -4
  159. rasa/core/information_retrieval/information_retrieval.py +2 -2
  160. rasa/core/information_retrieval/milvus.py +3 -3
  161. rasa/core/information_retrieval/qdrant.py +3 -3
  162. rasa/core/jobs.py +1 -0
  163. rasa/core/lock.py +2 -3
  164. rasa/core/lock_store.py +3 -3
  165. rasa/core/migrate.py +12 -9
  166. rasa/core/nlg/__init__.py +1 -1
  167. rasa/core/nlg/callback.py +2 -3
  168. rasa/core/nlg/contextual_response_rephraser.py +82 -14
  169. rasa/core/nlg/generator.py +85 -17
  170. rasa/core/nlg/interpolator.py +4 -3
  171. rasa/core/nlg/response.py +9 -7
  172. rasa/core/nlg/summarize.py +1 -0
  173. rasa/core/nlg/translate.py +55 -0
  174. rasa/core/persistor.py +3 -3
  175. rasa/core/policies/ensemble.py +10 -9
  176. rasa/core/policies/enterprise_search_policy.py +87 -21
  177. rasa/core/policies/enterprise_search_prompt_with_citation_template.jinja2 +1 -1
  178. rasa/core/policies/flow_policy.py +13 -14
  179. rasa/core/policies/flows/flow_executor.py +85 -55
  180. rasa/core/policies/intentless_policy.py +6 -7
  181. rasa/core/policies/memoization.py +22 -20
  182. rasa/core/policies/policy.py +24 -22
  183. rasa/core/policies/rule_policy.py +37 -36
  184. rasa/core/policies/ted_policy.py +87 -85
  185. rasa/core/policies/unexpected_intent_policy.py +77 -75
  186. rasa/core/processor.py +167 -74
  187. rasa/core/run.py +5 -4
  188. rasa/core/secrets_manager/endpoints.py +2 -3
  189. rasa/core/secrets_manager/factory.py +2 -3
  190. rasa/core/secrets_manager/secret_manager.py +2 -3
  191. rasa/core/secrets_manager/vault.py +2 -2
  192. rasa/core/test.py +30 -30
  193. rasa/core/tracker_store.py +138 -49
  194. rasa/core/train.py +1 -1
  195. rasa/core/training/__init__.py +2 -2
  196. rasa/core/training/converters/responses_prefix_converter.py +1 -2
  197. rasa/core/training/interactive.py +13 -13
  198. rasa/core/training/story_conflict.py +4 -5
  199. rasa/core/training/training.py +3 -5
  200. rasa/core/utils.py +5 -5
  201. rasa/core/visualize.py +1 -1
  202. rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -2
  203. rasa/dialogue_understanding/coexistence/llm_based_router.py +5 -5
  204. rasa/dialogue_understanding/commands/__init__.py +22 -22
  205. rasa/dialogue_understanding/commands/can_not_handle_command.py +38 -1
  206. rasa/dialogue_understanding/commands/cancel_flow_command.py +96 -9
  207. rasa/dialogue_understanding/commands/change_flow_command.py +36 -2
  208. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +36 -4
  209. rasa/dialogue_understanding/commands/clarify_command.py +46 -4
  210. rasa/dialogue_understanding/commands/command.py +3 -2
  211. rasa/dialogue_understanding/commands/command_syntax_manager.py +55 -0
  212. rasa/dialogue_understanding/commands/correct_slots_command.py +14 -5
  213. rasa/dialogue_understanding/commands/error_command.py +1 -1
  214. rasa/dialogue_understanding/commands/free_form_answer_command.py +2 -1
  215. rasa/dialogue_understanding/commands/handle_code_change_command.py +2 -2
  216. rasa/dialogue_understanding/commands/handle_digressions_command.py +144 -0
  217. rasa/dialogue_understanding/commands/human_handoff_command.py +34 -4
  218. rasa/dialogue_understanding/commands/knowledge_answer_command.py +36 -4
  219. rasa/dialogue_understanding/commands/noop_command.py +2 -1
  220. rasa/dialogue_understanding/commands/prompt_command.py +94 -0
  221. rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +34 -4
  222. rasa/dialogue_understanding/commands/restart_command.py +2 -5
  223. rasa/dialogue_understanding/commands/session_end_command.py +3 -5
  224. rasa/dialogue_understanding/commands/session_start_command.py +3 -5
  225. rasa/dialogue_understanding/commands/set_slot_command.py +55 -16
  226. rasa/dialogue_understanding/commands/skip_question_command.py +34 -4
  227. rasa/dialogue_understanding/commands/start_flow_command.py +78 -2
  228. rasa/dialogue_understanding/commands/user_silence_command.py +3 -5
  229. rasa/dialogue_understanding/commands/utils.py +126 -43
  230. rasa/dialogue_understanding/constants.py +2 -0
  231. rasa/dialogue_understanding/generator/__init__.py +2 -0
  232. rasa/dialogue_understanding/generator/command_generator.py +120 -79
  233. rasa/dialogue_understanding/generator/command_parser.py +245 -0
  234. rasa/dialogue_understanding/generator/constants.py +12 -4
  235. rasa/dialogue_understanding/generator/flow_retrieval.py +7 -7
  236. rasa/dialogue_understanding/generator/llm_based_command_generator.py +187 -59
  237. rasa/dialogue_understanding/generator/llm_command_generator.py +6 -3
  238. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +106 -110
  239. rasa/dialogue_understanding/generator/nlu_command_adapter.py +53 -11
  240. rasa/dialogue_understanding/generator/prompt_templates/__init__.py +0 -0
  241. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +58 -0
  242. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +57 -0
  243. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +574 -0
  244. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +41 -386
  245. rasa/dialogue_understanding/generator/utils.py +76 -0
  246. rasa/dialogue_understanding/patterns/cancel.py +2 -1
  247. rasa/dialogue_understanding/patterns/cannot_handle.py +1 -0
  248. rasa/dialogue_understanding/patterns/chitchat.py +1 -1
  249. rasa/dialogue_understanding/patterns/clarify.py +2 -1
  250. rasa/dialogue_understanding/patterns/code_change.py +2 -0
  251. rasa/dialogue_understanding/patterns/collect_information.py +7 -4
  252. rasa/dialogue_understanding/patterns/completed.py +1 -1
  253. rasa/dialogue_understanding/patterns/continue_interrupted.py +1 -1
  254. rasa/dialogue_understanding/patterns/correction.py +17 -3
  255. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +78 -2
  256. rasa/dialogue_understanding/patterns/handle_digressions.py +81 -0
  257. rasa/dialogue_understanding/patterns/human_handoff.py +1 -1
  258. rasa/dialogue_understanding/patterns/internal_error.py +1 -0
  259. rasa/dialogue_understanding/patterns/search.py +1 -1
  260. rasa/dialogue_understanding/patterns/session_start.py +1 -1
  261. rasa/dialogue_understanding/patterns/skip_question.py +1 -0
  262. rasa/dialogue_understanding/patterns/user_silence.py +1 -1
  263. rasa/dialogue_understanding/patterns/validate_slot.py +65 -0
  264. rasa/dialogue_understanding/processor/command_processor.py +193 -43
  265. rasa/dialogue_understanding/processor/command_processor_component.py +1 -1
  266. rasa/dialogue_understanding/stack/dialogue_stack.py +4 -3
  267. rasa/dialogue_understanding/stack/frames/__init__.py +2 -2
  268. rasa/dialogue_understanding/stack/frames/chit_chat_frame.py +4 -1
  269. rasa/dialogue_understanding/stack/frames/dialogue_stack_frame.py +2 -3
  270. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +5 -2
  271. rasa/dialogue_understanding/stack/frames/search_frame.py +4 -1
  272. rasa/dialogue_understanding/stack/utils.py +56 -10
  273. rasa/dialogue_understanding/utils.py +164 -0
  274. rasa/dialogue_understanding_test/README.md +429 -0
  275. rasa/dialogue_understanding_test/__init__.py +0 -0
  276. rasa/dialogue_understanding_test/command_comparison.py +60 -0
  277. rasa/dialogue_understanding_test/command_metric_calculation.py +122 -0
  278. rasa/dialogue_understanding_test/constants.py +22 -0
  279. rasa/dialogue_understanding_test/du_test_case.py +448 -0
  280. rasa/dialogue_understanding_test/du_test_result.py +390 -0
  281. rasa/dialogue_understanding_test/du_test_runner.py +322 -0
  282. rasa/dialogue_understanding_test/du_test_schema.yml +161 -0
  283. rasa/dialogue_understanding_test/io.py +443 -0
  284. rasa/dialogue_understanding_test/test_case_simulation/__init__.py +0 -0
  285. rasa/dialogue_understanding_test/test_case_simulation/exception.py +28 -0
  286. rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +336 -0
  287. rasa/dialogue_understanding_test/utils.py +70 -0
  288. rasa/dialogue_understanding_test/validation.py +77 -0
  289. rasa/e2e_test/aggregate_test_stats_calculator.py +1 -1
  290. rasa/e2e_test/assertions.py +202 -175
  291. rasa/e2e_test/assertions_schema.yml +6 -0
  292. rasa/e2e_test/constants.py +16 -1
  293. rasa/e2e_test/e2e_config.py +102 -41
  294. rasa/e2e_test/e2e_config_schema.yml +28 -10
  295. rasa/e2e_test/e2e_test_case.py +5 -5
  296. rasa/e2e_test/e2e_test_converter.py +2 -3
  297. rasa/e2e_test/e2e_test_coverage_report.py +6 -6
  298. rasa/e2e_test/e2e_test_result.py +1 -1
  299. rasa/e2e_test/e2e_test_runner.py +143 -38
  300. rasa/e2e_test/llm_judge_prompts/answer_relevance_prompt_template.jinja2 +93 -0
  301. rasa/e2e_test/llm_judge_prompts/groundedness_prompt_template.jinja2 +169 -0
  302. rasa/e2e_test/stub_custom_action.py +1 -1
  303. rasa/e2e_test/utils/generative_assertions.py +243 -0
  304. rasa/e2e_test/utils/io.py +123 -93
  305. rasa/e2e_test/utils/validation.py +101 -3
  306. rasa/engine/caching.py +5 -7
  307. rasa/engine/constants.py +1 -1
  308. rasa/engine/graph.py +3 -2
  309. rasa/engine/language.py +182 -0
  310. rasa/engine/recipes/config_files/default_config.yml +4 -0
  311. rasa/engine/recipes/default_components.py +13 -15
  312. rasa/engine/recipes/default_recipe.py +65 -49
  313. rasa/engine/recipes/graph_recipe.py +10 -7
  314. rasa/engine/recipes/recipe.py +2 -2
  315. rasa/engine/runner/dask.py +2 -2
  316. rasa/engine/runner/interface.py +1 -0
  317. rasa/engine/storage/local_model_storage.py +6 -4
  318. rasa/engine/storage/resource.py +2 -1
  319. rasa/engine/storage/storage.py +8 -3
  320. rasa/engine/training/components.py +2 -1
  321. rasa/engine/training/fingerprinting.py +4 -2
  322. rasa/engine/training/graph_trainer.py +4 -4
  323. rasa/engine/training/hooks.py +2 -2
  324. rasa/engine/validation.py +36 -33
  325. rasa/exceptions.py +3 -2
  326. rasa/graph_components/converters/nlu_message_converter.py +3 -3
  327. rasa/graph_components/providers/domain_for_core_training_provider.py +3 -3
  328. rasa/graph_components/providers/domain_provider.py +3 -2
  329. rasa/graph_components/providers/flows_provider.py +2 -3
  330. rasa/graph_components/providers/forms_provider.py +4 -4
  331. rasa/graph_components/providers/nlu_training_data_provider.py +5 -3
  332. rasa/graph_components/providers/responses_provider.py +4 -4
  333. rasa/graph_components/providers/rule_only_provider.py +3 -2
  334. rasa/graph_components/providers/story_graph_provider.py +8 -8
  335. rasa/graph_components/providers/training_tracker_provider.py +3 -2
  336. rasa/graph_components/validators/default_recipe_validator.py +16 -16
  337. rasa/graph_components/validators/finetuning_validator.py +10 -8
  338. rasa/hooks.py +19 -14
  339. rasa/jupyter.py +2 -2
  340. rasa/llm_fine_tuning/annotation_module.py +4 -4
  341. rasa/llm_fine_tuning/conversations.py +5 -33
  342. rasa/llm_fine_tuning/llm_data_preparation_module.py +6 -4
  343. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +4 -4
  344. rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +18 -13
  345. rasa/llm_fine_tuning/paraphrasing_module.py +6 -2
  346. rasa/llm_fine_tuning/storage.py +3 -3
  347. rasa/llm_fine_tuning/train_test_split_module.py +27 -27
  348. rasa/llm_fine_tuning/utils.py +7 -0
  349. rasa/markers/marker.py +2 -3
  350. rasa/markers/marker_base.py +1 -2
  351. rasa/markers/upload.py +2 -2
  352. rasa/markers/validate.py +2 -3
  353. rasa/model.py +3 -5
  354. rasa/model_manager/config.py +1 -1
  355. rasa/model_manager/model_api.py +5 -4
  356. rasa/model_manager/runner_service.py +13 -10
  357. rasa/model_manager/socket_bridge.py +15 -9
  358. rasa/model_manager/studio_jwt_auth.py +1 -0
  359. rasa/model_manager/trainer_service.py +9 -7
  360. rasa/model_manager/utils.py +1 -1
  361. rasa/model_manager/warm_rasa_process.py +14 -9
  362. rasa/model_service.py +5 -6
  363. rasa/model_testing.py +13 -15
  364. rasa/model_training.py +29 -29
  365. rasa/nlu/classifiers/diet_classifier.py +72 -73
  366. rasa/nlu/classifiers/fallback_classifier.py +9 -8
  367. rasa/nlu/classifiers/keyword_intent_classifier.py +7 -6
  368. rasa/nlu/classifiers/logistic_regression_classifier.py +3 -3
  369. rasa/nlu/classifiers/mitie_intent_classifier.py +5 -4
  370. rasa/nlu/classifiers/regex_message_handler.py +3 -2
  371. rasa/nlu/classifiers/sklearn_intent_classifier.py +2 -2
  372. rasa/nlu/convert.py +2 -2
  373. rasa/nlu/emulators/dialogflow.py +3 -3
  374. rasa/nlu/emulators/luis.py +5 -5
  375. rasa/nlu/emulators/no_emulator.py +1 -0
  376. rasa/nlu/emulators/wit.py +4 -4
  377. rasa/nlu/extractors/crf_entity_extractor.py +11 -11
  378. rasa/nlu/extractors/duckling_entity_extractor.py +7 -6
  379. rasa/nlu/extractors/entity_synonyms.py +10 -9
  380. rasa/nlu/extractors/extractor.py +16 -16
  381. rasa/nlu/extractors/mitie_entity_extractor.py +10 -9
  382. rasa/nlu/extractors/regex_entity_extractor.py +11 -10
  383. rasa/nlu/extractors/spacy_entity_extractor.py +2 -2
  384. rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +15 -14
  385. rasa/nlu/featurizers/dense_featurizer/dense_featurizer.py +2 -1
  386. rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +10 -9
  387. rasa/nlu/featurizers/dense_featurizer/mitie_featurizer.py +9 -7
  388. rasa/nlu/featurizers/dense_featurizer/spacy_featurizer.py +13 -12
  389. rasa/nlu/featurizers/featurizer.py +5 -4
  390. rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +6 -6
  391. rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +4 -4
  392. rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +4 -4
  393. rasa/nlu/featurizers/sparse_featurizer/sparse_featurizer.py +2 -0
  394. rasa/nlu/model.py +0 -1
  395. rasa/nlu/selectors/response_selector.py +67 -68
  396. rasa/nlu/test.py +38 -38
  397. rasa/nlu/tokenizers/jieba_tokenizer.py +1 -2
  398. rasa/nlu/tokenizers/mitie_tokenizer.py +2 -2
  399. rasa/nlu/tokenizers/spacy_tokenizer.py +3 -3
  400. rasa/nlu/tokenizers/tokenizer.py +6 -7
  401. rasa/nlu/tokenizers/whitespace_tokenizer.py +1 -1
  402. rasa/nlu/utils/bilou_utils.py +7 -7
  403. rasa/nlu/utils/hugging_face/registry.py +22 -22
  404. rasa/nlu/utils/hugging_face/transformers_pre_post_processors.py +2 -1
  405. rasa/nlu/utils/mitie_utils.py +2 -1
  406. rasa/nlu/utils/pattern_utils.py +1 -1
  407. rasa/nlu/utils/spacy_utils.py +3 -3
  408. rasa/plugin.py +12 -1
  409. rasa/server.py +6 -3
  410. rasa/shared/constants.py +45 -18
  411. rasa/shared/core/command_payload_reader.py +15 -7
  412. rasa/shared/core/constants.py +34 -4
  413. rasa/shared/core/conversation.py +1 -2
  414. rasa/shared/core/domain.py +19 -20
  415. rasa/shared/core/events.py +60 -39
  416. rasa/shared/core/flows/__init__.py +0 -1
  417. rasa/shared/core/flows/constants.py +11 -0
  418. rasa/shared/core/flows/flow.py +107 -26
  419. rasa/shared/core/flows/flow_step.py +4 -3
  420. rasa/shared/core/flows/flow_step_links.py +1 -2
  421. rasa/shared/core/flows/flow_step_sequence.py +1 -1
  422. rasa/shared/core/flows/flows_list.py +3 -3
  423. rasa/shared/core/flows/flows_yaml_schema.json +69 -3
  424. rasa/shared/core/flows/nlu_trigger.py +1 -1
  425. rasa/shared/core/flows/steps/__init__.py +2 -2
  426. rasa/shared/core/flows/steps/action.py +1 -1
  427. rasa/shared/core/flows/steps/call.py +1 -1
  428. rasa/shared/core/flows/steps/collect.py +22 -40
  429. rasa/shared/core/flows/steps/internal.py +1 -1
  430. rasa/shared/core/flows/steps/link.py +1 -1
  431. rasa/shared/core/flows/steps/no_operation.py +2 -2
  432. rasa/shared/core/flows/steps/set_slots.py +1 -1
  433. rasa/shared/core/flows/utils.py +44 -4
  434. rasa/shared/core/flows/validation.py +4 -6
  435. rasa/shared/core/generator.py +20 -21
  436. rasa/shared/core/slot_mappings.py +360 -121
  437. rasa/shared/core/slots.py +163 -6
  438. rasa/shared/core/trackers.py +108 -33
  439. rasa/shared/core/training_data/loading.py +1 -1
  440. rasa/shared/core/training_data/story_reader/story_reader.py +3 -3
  441. rasa/shared/core/training_data/story_reader/story_step_builder.py +4 -4
  442. rasa/shared/core/training_data/story_reader/yaml_story_reader.py +29 -31
  443. rasa/shared/core/training_data/story_writer/yaml_story_writer.py +22 -24
  444. rasa/shared/core/training_data/structures.py +11 -12
  445. rasa/shared/core/training_data/visualization.py +10 -10
  446. rasa/shared/data.py +6 -6
  447. rasa/shared/engine/caching.py +0 -1
  448. rasa/shared/exceptions.py +2 -2
  449. rasa/shared/importers/importer.py +58 -2
  450. rasa/shared/importers/rasa.py +5 -6
  451. rasa/shared/importers/utils.py +1 -1
  452. rasa/shared/nlu/constants.py +9 -0
  453. rasa/shared/nlu/training_data/entities_parser.py +6 -6
  454. rasa/shared/nlu/training_data/features.py +3 -3
  455. rasa/shared/nlu/training_data/formats/__init__.py +1 -1
  456. rasa/shared/nlu/training_data/formats/dialogflow.py +4 -5
  457. rasa/shared/nlu/training_data/formats/luis.py +7 -8
  458. rasa/shared/nlu/training_data/formats/rasa.py +4 -5
  459. rasa/shared/nlu/training_data/formats/rasa_yaml.py +17 -16
  460. rasa/shared/nlu/training_data/formats/readerwriter.py +8 -11
  461. rasa/shared/nlu/training_data/formats/wit.py +3 -4
  462. rasa/shared/nlu/training_data/loading.py +4 -4
  463. rasa/shared/nlu/training_data/lookup_tables_parser.py +1 -1
  464. rasa/shared/nlu/training_data/message.py +13 -14
  465. rasa/shared/nlu/training_data/schemas/data_schema.py +1 -1
  466. rasa/shared/nlu/training_data/schemas/responses.yml +19 -11
  467. rasa/shared/nlu/training_data/synonyms_parser.py +3 -3
  468. rasa/shared/nlu/training_data/training_data.py +12 -13
  469. rasa/shared/nlu/training_data/util.py +11 -10
  470. rasa/shared/providers/_configs/azure_entra_id_config.py +541 -0
  471. rasa/shared/providers/_configs/azure_openai_client_config.py +150 -15
  472. rasa/shared/providers/_configs/client_config.py +3 -1
  473. rasa/shared/providers/_configs/default_litellm_client_config.py +9 -7
  474. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +13 -11
  475. rasa/shared/providers/_configs/litellm_router_client_config.py +12 -10
  476. rasa/shared/providers/_configs/model_group_config.py +8 -5
  477. rasa/shared/providers/_configs/oauth_config.py +33 -0
  478. rasa/shared/providers/_configs/openai_client_config.py +14 -12
  479. rasa/shared/providers/_configs/rasa_llm_client_config.py +5 -3
  480. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +12 -11
  481. rasa/shared/providers/_configs/utils.py +1 -0
  482. rasa/shared/providers/_ssl_verification_utils.py +5 -6
  483. rasa/shared/providers/_utils.py +5 -5
  484. rasa/shared/providers/constants.py +6 -0
  485. rasa/shared/providers/embedding/_base_litellm_embedding_client.py +1 -1
  486. rasa/shared/providers/embedding/azure_openai_embedding_client.py +32 -7
  487. rasa/shared/providers/embedding/embedding_client.py +1 -1
  488. rasa/shared/providers/embedding/litellm_router_embedding_client.py +5 -2
  489. rasa/shared/providers/llm/_base_litellm_client.py +43 -18
  490. rasa/shared/providers/llm/azure_openai_llm_client.py +90 -34
  491. rasa/shared/providers/llm/default_litellm_llm_client.py +4 -2
  492. rasa/shared/providers/llm/litellm_router_llm_client.py +32 -9
  493. rasa/shared/providers/llm/llm_client.py +24 -8
  494. rasa/shared/providers/llm/llm_response.py +61 -2
  495. rasa/shared/providers/llm/openai_llm_client.py +11 -5
  496. rasa/shared/providers/llm/rasa_llm_client.py +17 -14
  497. rasa/shared/providers/llm/self_hosted_llm_client.py +35 -15
  498. rasa/shared/providers/mappings.py +18 -19
  499. rasa/shared/providers/router/_base_litellm_router_client.py +48 -15
  500. rasa/shared/providers/router/router_client.py +3 -1
  501. rasa/shared/utils/cli.py +1 -1
  502. rasa/shared/utils/common.py +15 -1
  503. rasa/shared/utils/constants.py +3 -0
  504. rasa/shared/utils/health_check/embeddings_health_check_mixin.py +1 -1
  505. rasa/shared/utils/health_check/health_check.py +3 -3
  506. rasa/shared/utils/health_check/llm_health_check_mixin.py +1 -1
  507. rasa/shared/utils/io.py +1 -1
  508. rasa/shared/utils/llm.py +100 -18
  509. rasa/shared/utils/pykwalify_extensions.py +25 -1
  510. rasa/shared/utils/schemas/domain.yml +26 -1
  511. rasa/shared/utils/schemas/events.py +1 -1
  512. rasa/shared/utils/yaml.py +24 -20
  513. rasa/studio/auth.py +3 -3
  514. rasa/studio/config.py +1 -2
  515. rasa/studio/data_handler.py +3 -3
  516. rasa/studio/download.py +1 -1
  517. rasa/studio/results_logger.py +3 -3
  518. rasa/studio/upload.py +21 -5
  519. rasa/telemetry.py +127 -48
  520. rasa/tracing/config.py +5 -3
  521. rasa/tracing/constants.py +12 -0
  522. rasa/tracing/instrumentation/attribute_extractors.py +92 -14
  523. rasa/tracing/instrumentation/instrumentation.py +61 -5
  524. rasa/tracing/instrumentation/intentless_policy_instrumentation.py +1 -1
  525. rasa/tracing/instrumentation/metrics.py +52 -11
  526. rasa/tracing/metric_instrument_provider.py +54 -14
  527. rasa/utils/common.py +12 -24
  528. rasa/utils/endpoints.py +1 -1
  529. rasa/utils/io.py +7 -7
  530. rasa/utils/licensing.py +3 -4
  531. rasa/utils/log_utils.py +7 -6
  532. rasa/utils/ml_utils.py +1 -0
  533. rasa/utils/plotting.py +3 -3
  534. rasa/utils/sanic_error_handler.py +1 -1
  535. rasa/utils/tensorflow/callback.py +2 -2
  536. rasa/utils/tensorflow/crf.py +2 -2
  537. rasa/utils/tensorflow/data_generator.py +5 -5
  538. rasa/utils/tensorflow/environment.py +3 -3
  539. rasa/utils/tensorflow/feature_array.py +2 -3
  540. rasa/utils/tensorflow/layers.py +18 -12
  541. rasa/utils/tensorflow/layers_utils.py +2 -1
  542. rasa/utils/tensorflow/metrics.py +2 -2
  543. rasa/utils/tensorflow/model_data.py +7 -7
  544. rasa/utils/tensorflow/model_data_utils.py +10 -9
  545. rasa/utils/tensorflow/models.py +31 -32
  546. rasa/utils/tensorflow/rasa_layers.py +20 -19
  547. rasa/utils/tensorflow/types.py +2 -1
  548. rasa/utils/train_utils.py +23 -21
  549. rasa/utils/url_tools.py +1 -1
  550. rasa/validator.py +594 -115
  551. rasa/version.py +1 -1
  552. {rasa_pro-3.11.4.dist-info → rasa_pro-3.12.0.dist-info}/METADATA +23 -26
  553. rasa_pro-3.12.0.dist-info/RECORD +829 -0
  554. rasa/core/channels/inspector/dist/assets/arc-632a63ec.js +0 -1
  555. rasa/core/channels/inspector/dist/assets/c4Diagram-d0fbc5ce-081e0df4.js +0 -10
  556. rasa/core/channels/inspector/dist/assets/classDiagram-936ed81e-3df0afc2.js +0 -2
  557. rasa/core/channels/inspector/dist/assets/classDiagram-v2-c3cb15f1-8c5ed31e.js +0 -2
  558. rasa/core/channels/inspector/dist/assets/edges-f2ad444c-4fc48c3e.js +0 -4
  559. rasa/core/channels/inspector/dist/assets/flowDb-1972c806-9ec53a3c.js +0 -6
  560. rasa/core/channels/inspector/dist/assets/flowDiagram-7ea5b25a-41da787a.js +0 -4
  561. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-8bea338b.js +0 -1
  562. rasa/core/channels/inspector/dist/assets/flowchart-elk-definition-abe16c3d-ce370633.js +0 -139
  563. rasa/core/channels/inspector/dist/assets/ganttDiagram-9b5ea136-90a36523.js +0 -266
  564. rasa/core/channels/inspector/dist/assets/gitGraphDiagram-99d0ae7c-41e1aa3f.js +0 -70
  565. rasa/core/channels/inspector/dist/assets/index-2c4b9a3b-e6f2af62.js +0 -1
  566. rasa/core/channels/inspector/dist/assets/layout-498807d8.js +0 -1
  567. rasa/core/channels/inspector/dist/assets/linear-8a078617.js +0 -1
  568. rasa/core/channels/inspector/dist/assets/mindmap-definition-beec6740-396d17dd.js +0 -109
  569. rasa/core/channels/inspector/dist/assets/sankeyDiagram-8f13d901-53f6f391.js +0 -8
  570. rasa/core/channels/inspector/dist/assets/sequenceDiagram-b655622a-715c9c20.js +0 -122
  571. rasa/core/channels/inspector/dist/assets/stateDiagram-59f0c015-2e8fb31f.js +0 -1
  572. rasa/core/channels/inspector/dist/assets/stateDiagram-v2-2b26beab-7e2d2aa0.js +0 -1
  573. rasa/core/channels/inspector/dist/assets/styles-080da4f6-4420cea6.js +0 -110
  574. rasa/core/channels/inspector/dist/assets/styles-3dcbcfbf-28676cf4.js +0 -159
  575. rasa/core/channels/inspector/dist/assets/svgDrawCommon-4835440b-151251e9.js +0 -1
  576. rasa_pro-3.11.4.dist-info/RECORD +0 -779
  577. /rasa/dialogue_understanding/generator/{single_step → prompt_templates}/command_prompt_template.jinja2 +0 -0
  578. {rasa_pro-3.11.4.dist-info → rasa_pro-3.12.0.dist-info}/NOTICE +0 -0
  579. {rasa_pro-3.11.4.dist-info → rasa_pro-3.12.0.dist-info}/WHEEL +0 -0
  580. {rasa_pro-3.11.4.dist-info → rasa_pro-3.12.0.dist-info}/entry_points.txt +0 -0
@@ -1,18 +1,18 @@
1
1
  from typing import Any, Awaitable, Callable, Dict, List, Optional, Text
2
2
 
3
3
  import structlog
4
+ from sanic import Blueprint, Websocket, response # type: ignore[attr-defined]
5
+ from sanic.request import Request
6
+ from sanic.response import HTTPResponse
7
+
4
8
  from rasa.core.channels.channel import InputChannel, OutputChannel, UserMessage
5
9
  from rasa.core.channels.voice_ready.jambonz_protocol import (
10
+ send_ws_hangup_message,
6
11
  send_ws_text_message,
7
12
  websocket_message_handler,
8
- send_ws_hangup_message,
9
13
  )
10
14
  from rasa.core.channels.voice_ready.utils import validate_voice_license_scope
11
15
  from rasa.shared.exceptions import RasaException
12
- from sanic import Blueprint, response, Websocket # type: ignore[attr-defined]
13
- from sanic.request import Request
14
- from sanic.response import HTTPResponse
15
-
16
16
  from rasa.shared.utils.common import mark_as_beta_feature
17
17
  from rasa.utils.io import remove_emojis
18
18
 
@@ -1,14 +1,13 @@
1
- from dataclasses import dataclass, field
2
1
  import json
3
2
  import uuid
3
+ from dataclasses import asdict, dataclass, field
4
4
  from typing import Any, Awaitable, Callable, Dict, List, Text
5
5
 
6
6
  import structlog
7
- from rasa.core.channels.channel import UserMessage
8
- from rasa.core.channels.voice_ready.utils import CallParameters
9
- from dataclasses import asdict
10
7
  from sanic import Websocket # type: ignore[attr-defined]
11
8
 
9
+ from rasa.core.channels.channel import UserMessage
10
+ from rasa.core.channels.voice_ready.utils import CallParameters
12
11
 
13
12
  structlogger = structlog.get_logger()
14
13
 
@@ -1,21 +1,22 @@
1
+ from dataclasses import asdict
2
+ from typing import Any, Awaitable, Callable, Dict, List, Optional, Text
3
+
4
+ import structlog
1
5
  from sanic import Blueprint, response
2
6
  from sanic.request import Request, RequestParameters
3
7
  from sanic.response import HTTPResponse
4
- from twilio.twiml.voice_response import VoiceResponse, Gather
5
- from typing import Text, Callable, Awaitable, List, Any, Dict, Optional
6
- from dataclasses import asdict
8
+ from twilio.twiml.voice_response import Gather, VoiceResponse
7
9
 
8
- import structlog
9
- import rasa.utils.io
10
10
  import rasa.shared.utils.io
11
- from rasa.shared.core.events import BotUttered
12
- from rasa.shared.exceptions import InvalidConfigException
11
+ import rasa.utils.io
13
12
  from rasa.core.channels.channel import (
14
- InputChannel,
15
13
  CollectingOutputChannel,
14
+ InputChannel,
16
15
  UserMessage,
17
16
  )
18
17
  from rasa.core.channels.voice_ready.utils import CallParameters
18
+ from rasa.shared.core.events import BotUttered
19
+ from rasa.shared.exceptions import InvalidConfigException
19
20
 
20
21
  logger = structlog.get_logger(__name__)
21
22
 
@@ -1,7 +1,7 @@
1
- import structlog
2
1
  from dataclasses import dataclass
3
2
  from typing import Optional
4
3
 
4
+ import structlog
5
5
 
6
6
  structlogger = structlog.get_logger()
7
7
 
@@ -29,7 +29,7 @@ class CallParameters:
29
29
 
30
30
  call_id: str
31
31
  user_phone: str
32
- bot_phone: str
32
+ bot_phone: Optional[str] = None
33
33
  user_name: Optional[str] = None
34
34
  user_host: Optional[str] = None
35
35
  bot_host: Optional[str] = None
@@ -1,8 +1,8 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import (
3
- Dict,
4
- AsyncIterator,
5
3
  Any,
4
+ AsyncIterator,
5
+ Dict,
6
6
  Generic,
7
7
  Optional,
8
8
  Tuple,
@@ -10,6 +10,7 @@ from typing import (
10
10
  TypeVar,
11
11
  )
12
12
 
13
+ import structlog
13
14
  from websockets.legacy.client import WebSocketClientProtocol
14
15
 
15
16
  from rasa.core.channels.voice_stream.asr.asr_event import ASREvent
@@ -20,6 +21,7 @@ from rasa.shared.utils.common import validate_environment
20
21
 
21
22
  T = TypeVar("T", bound="ASREngineConfig")
22
23
  E = TypeVar("E", bound="ASREngine")
24
+ logger = structlog.get_logger(__name__)
23
25
 
24
26
 
25
27
  @dataclass
@@ -74,10 +76,14 @@ class ASREngine(Generic[T]):
74
76
  """Stream the events returned by the ASR system as it is fed audio bytes."""
75
77
  if self.asr_socket is None:
76
78
  raise ConnectionException("Websocket not connected.")
77
- async for message in self.asr_socket:
78
- asr_event = self.engine_event_to_asr_event(message)
79
- if asr_event:
80
- yield asr_event
79
+
80
+ try:
81
+ async for message in self.asr_socket:
82
+ asr_event = self.engine_event_to_asr_event(message)
83
+ if asr_event:
84
+ yield asr_event
85
+ except Exception as e:
86
+ logger.warning(f"Error while streaming ASR events: {e}")
81
87
 
82
88
  def engine_event_to_asr_event(self, e: Any) -> Optional[ASREvent]:
83
89
  """Translate an engine event to a common ASREvent."""
@@ -16,3 +16,8 @@ class NewTranscript(ASREvent):
16
16
  @dataclass
17
17
  class UserIsSpeaking(ASREvent):
18
18
  pass
19
+
20
+
21
+ @dataclass
22
+ class UserSilence(ASREvent):
23
+ pass
@@ -1,7 +1,7 @@
1
+ import asyncio
1
2
  import os
2
3
  from dataclasses import dataclass
3
- from typing import Any, Dict, Optional, AsyncIterator
4
- import asyncio
4
+ from typing import Any, AsyncIterator, Dict, Optional
5
5
 
6
6
  from rasa.core.channels.voice_stream.asr.asr_engine import ASREngine, ASREngineConfig
7
7
  from rasa.core.channels.voice_stream.asr.asr_event import (
@@ -18,6 +18,8 @@ from rasa.shared.exceptions import ConnectionException
18
18
  class AzureASRConfig(ASREngineConfig):
19
19
  language: Optional[str] = None
20
20
  speech_region: Optional[str] = None
21
+ speech_host: Optional[str] = None
22
+ speech_endpoint: Optional[str] = None
21
23
 
22
24
 
23
25
  class AzureASR(ASREngine[AzureASRConfig]):
@@ -52,9 +54,18 @@ class AzureASR(ASREngine[AzureASRConfig]):
52
54
  async def connect(self) -> None:
53
55
  import azure.cognitiveservices.speech as speechsdk
54
56
 
57
+ # connecting to eastus by default
58
+ if (
59
+ self.config.speech_region is None
60
+ and self.config.speech_host is None
61
+ and self.config.speech_endpoint is None
62
+ ):
63
+ self.config.speech_region = "eastus"
55
64
  speech_config = speechsdk.SpeechConfig(
56
65
  subscription=os.environ[AZURE_SPEECH_API_KEY_ENV_VAR],
57
66
  region=self.config.speech_region,
67
+ endpoint=self.config.speech_endpoint,
68
+ host=self.config.speech_host,
58
69
  )
59
70
  audio_format = speechsdk.audio.AudioStreamFormat(
60
71
  samples_per_second=HERTZ,
@@ -123,7 +134,9 @@ class AzureASR(ASREngine[AzureASRConfig]):
123
134
 
124
135
  @staticmethod
125
136
  def get_default_config() -> AzureASRConfig:
126
- return AzureASRConfig("en-US", "germanywestcentral")
137
+ return AzureASRConfig(
138
+ language=None, speech_region=None, speech_host=None, speech_endpoint=None
139
+ )
127
140
 
128
141
  @classmethod
129
142
  def from_config_dict(cls, config: Dict) -> "AzureASR":
@@ -1,9 +1,12 @@
1
- from dataclasses import dataclass
2
- from typing import Any, Dict, Optional
3
1
  import json
4
2
  import os
3
+ from dataclasses import dataclass
4
+ from typing import Any, Dict, Optional
5
+ from urllib.parse import urlencode
5
6
 
7
+ import structlog
6
8
  import websockets
9
+ import websockets.exceptions
7
10
  from websockets.legacy.client import WebSocketClientProtocol
8
11
 
9
12
  from rasa.core.channels.voice_stream.asr.asr_engine import ASREngine, ASREngineConfig
@@ -15,15 +18,20 @@ from rasa.core.channels.voice_stream.asr.asr_event import (
15
18
  from rasa.core.channels.voice_stream.audio_bytes import HERTZ, RasaAudioBytes
16
19
  from rasa.shared.constants import DEEPGRAM_API_KEY_ENV_VAR
17
20
 
21
+ logger = structlog.get_logger(__name__)
22
+
18
23
 
19
24
  @dataclass
20
25
  class DeepgramASRConfig(ASREngineConfig):
21
26
  endpoint: Optional[str] = None
22
- # number of miliseconds of silence to determine end of speech
27
+ # number of milliseconds of silence to determine end of speech
23
28
  endpointing: Optional[int] = None
24
29
  language: Optional[str] = None
25
30
  model: Optional[str] = None
26
31
  smart_format: Optional[bool] = None
32
+ # number of milliseconds of no new transcript to determine end of speech
33
+ # should be at least 1000 according to docs
34
+ utterance_end_ms: Optional[int] = None
27
35
 
28
36
 
29
37
  class DeepgramASR(ASREngine[DeepgramASRConfig]):
@@ -37,22 +45,47 @@ class DeepgramASR(ASREngine[DeepgramASRConfig]):
37
45
  """Connect to the ASR system."""
38
46
  deepgram_api_key = os.environ[DEEPGRAM_API_KEY_ENV_VAR]
39
47
  extra_headers = {"Authorization": f"Token {deepgram_api_key}"}
40
- api_url = self._get_api_url()
41
- query_params = self._get_query_params()
42
- return await websockets.connect( # type: ignore
43
- api_url + query_params,
44
- extra_headers=extra_headers,
45
- )
48
+ try:
49
+ return await websockets.connect( # type: ignore
50
+ self._get_api_url_with_query_params(),
51
+ extra_headers=extra_headers,
52
+ )
53
+ except websockets.exceptions.InvalidStatusCode as e:
54
+ if e.status_code == 401:
55
+ error_msg = "Please make sure your Deepgram API key is correct."
56
+ else:
57
+ error_msg = "Connection to Deepgram failed."
58
+ logger.error(
59
+ "deepgram.connection.failed",
60
+ status_code=e.status_code,
61
+ error=error_msg,
62
+ )
63
+ raise
64
+
65
+ def _get_api_url_with_query_params(self) -> str:
66
+ """Combine api url and query params."""
67
+ return self._get_api_url() + self._get_query_params()
46
68
 
47
69
  def _get_api_url(self) -> str:
70
+ """Get the api url with the configured endpoint."""
48
71
  return f"wss://{self.config.endpoint}/v1/listen?"
49
72
 
50
73
  def _get_query_params(self) -> str:
51
- return (
52
- f"encoding=mulaw&sample_rate={HERTZ}&endpointing={self.config.endpointing}"
53
- f"&vad_events=true&language={self.config.language}&interim_results=true"
54
- f"&model={self.config.model}&smart_format={str(self.config.smart_format).lower()}"
55
- )
74
+ """Get the configured query parameters for the api."""
75
+ query_params = {
76
+ "encoding": "mulaw",
77
+ "sample_rate": HERTZ,
78
+ "endpointing": self.config.endpointing,
79
+ "vad_events": "true",
80
+ "language": self.config.language,
81
+ "interim_results": "true",
82
+ "model": self.config.model,
83
+ "smart_format": str(self.config.smart_format).lower(),
84
+ }
85
+ if self.config.utterance_end_ms and self.config.utterance_end_ms > 0:
86
+ query_params["utterance_end_ms"] = self.config.utterance_end_ms
87
+
88
+ return urlencode(query_params)
56
89
 
57
90
  async def signal_audio_done(self) -> None:
58
91
  """Signal to the ASR Api that you are done sending data."""
@@ -67,24 +100,48 @@ class DeepgramASR(ASREngine[DeepgramASRConfig]):
67
100
  def engine_event_to_asr_event(self, e: Any) -> Optional[ASREvent]:
68
101
  """Translate an engine event to a common ASREvent."""
69
102
  data = json.loads(e)
70
- if "is_final" in data:
71
- transcript = data["channel"]["alternatives"][0]["transcript"]
103
+ data_type = data["type"]
104
+ if data_type == "Results":
105
+ transcript_data = data["channel"]["alternatives"][0]
106
+ transcript = transcript_data["transcript"]
72
107
  if data["is_final"]:
73
108
  if data.get("speech_final"):
74
- full_transcript = self.accumulated_transcript + transcript
109
+ full_transcript = self.concatenate_transcripts(
110
+ self.accumulated_transcript, transcript
111
+ )
75
112
  self.accumulated_transcript = ""
76
113
  if full_transcript:
77
114
  return NewTranscript(full_transcript)
78
115
  else:
79
- self.accumulated_transcript += transcript
116
+ self.accumulated_transcript = self.concatenate_transcripts(
117
+ self.accumulated_transcript, transcript
118
+ )
80
119
  elif transcript:
81
120
  return UserIsSpeaking()
121
+ # event that comes after utterance_end_ms of no new transcript
122
+ elif data_type == "UtteranceEnd":
123
+ if self.accumulated_transcript:
124
+ transcript = self.accumulated_transcript
125
+ self.accumulated_transcript = ""
126
+ return NewTranscript(transcript)
82
127
  return None
83
128
 
84
129
  @staticmethod
85
130
  def get_default_config() -> DeepgramASRConfig:
86
- return DeepgramASRConfig("api.deepgram.com", 400, "en", "nova-2-general", True)
131
+ return DeepgramASRConfig(
132
+ endpoint="api.deepgram.com",
133
+ endpointing=400,
134
+ language="en",
135
+ model="nova-2-general",
136
+ smart_format=True,
137
+ utterance_end_ms=1000,
138
+ )
87
139
 
88
140
  @classmethod
89
141
  def from_config_dict(cls, config: Dict) -> "DeepgramASR":
90
142
  return DeepgramASR(DeepgramASRConfig.from_dict(config))
143
+
144
+ @staticmethod
145
+ def concatenate_transcripts(t1: str, t2: str) -> str:
146
+ """Concatenate two transcripts making sure there is a space between them."""
147
+ return (t1.strip() + " " + t2.strip()).strip()
@@ -0,0 +1,292 @@
1
+ import asyncio
2
+ import base64
3
+ import json
4
+ from typing import Any, Awaitable, Callable, Dict, Optional, Text
5
+
6
+ import structlog
7
+ from sanic import ( # type: ignore[attr-defined]
8
+ Blueprint,
9
+ HTTPResponse,
10
+ Request,
11
+ Websocket,
12
+ response,
13
+ )
14
+
15
+ from rasa.core.channels import UserMessage
16
+ from rasa.core.channels.voice_ready.audiocodes import map_call_params
17
+ from rasa.core.channels.voice_ready.utils import CallParameters
18
+ from rasa.core.channels.voice_stream.audio_bytes import RasaAudioBytes
19
+ from rasa.core.channels.voice_stream.call_state import (
20
+ call_state,
21
+ )
22
+ from rasa.core.channels.voice_stream.tts.tts_engine import TTSEngine
23
+ from rasa.core.channels.voice_stream.voice_channel import (
24
+ ContinueConversationAction,
25
+ EndConversationAction,
26
+ NewAudioAction,
27
+ VoiceChannelAction,
28
+ VoiceInputChannel,
29
+ VoiceOutputChannel,
30
+ )
31
+ from rasa.shared.utils.common import mark_as_beta_feature
32
+
33
+ logger = structlog.get_logger(__name__)
34
+ PREFERRED_AUDIO_FORMAT = "raw/mulaw"
35
+
36
+
37
+ class AudiocodesVoiceOutputChannel(VoiceOutputChannel):
38
+ @classmethod
39
+ def name(cls) -> str:
40
+ return "audiocodes_stream"
41
+
42
+ def _ensure_stream_id(self) -> None:
43
+ """Audiocodes requires a stream ID with playStream messages."""
44
+ if "stream_id" not in call_state.channel_data:
45
+ call_state.channel_data["stream_id"] = 0
46
+
47
+ def _increment_stream_id(self) -> None:
48
+ self._ensure_stream_id()
49
+ call_state.channel_data["stream_id"] += 1
50
+
51
+ def _get_stream_id(self) -> str:
52
+ self._ensure_stream_id()
53
+ return str(call_state.channel_data["stream_id"])
54
+
55
+ def rasa_audio_bytes_to_channel_bytes(
56
+ self, rasa_audio_bytes: RasaAudioBytes
57
+ ) -> bytes:
58
+ return base64.b64encode(rasa_audio_bytes)
59
+
60
+ def channel_bytes_to_message(self, recipient_id: str, channel_bytes: bytes) -> str:
61
+ media_message = json.dumps(
62
+ {
63
+ "type": "playStream.chunk",
64
+ "streamId": self._get_stream_id(),
65
+ "audioChunk": channel_bytes.decode("utf-8"),
66
+ }
67
+ )
68
+ return media_message
69
+
70
+ async def send_start_marker(self, recipient_id: str) -> None:
71
+ """Send playStream.start before first audio chunk."""
72
+ self._increment_stream_id()
73
+ media_message = json.dumps(
74
+ {
75
+ "type": "playStream.start",
76
+ "streamId": self._get_stream_id(),
77
+ "mediaFormat": PREFERRED_AUDIO_FORMAT,
78
+ }
79
+ )
80
+ logger.debug("Sending start marker", stream_id=self._get_stream_id())
81
+ await self.voice_websocket.send(media_message)
82
+
83
+ async def send_intermediate_marker(self, recipient_id: str) -> None:
84
+ """Audiocodes doesn't need intermediate markers, so do nothing."""
85
+ pass
86
+
87
+ async def send_end_marker(self, recipient_id: str) -> None:
88
+ """Send playStream.stop after last audio chunk."""
89
+ media_message = json.dumps(
90
+ {
91
+ "type": "playStream.stop",
92
+ "streamId": self._get_stream_id(),
93
+ }
94
+ )
95
+ logger.debug("Sending end marker", stream_id=self._get_stream_id())
96
+ await self.voice_websocket.send(media_message)
97
+
98
+
99
+ class AudiocodesVoiceInputChannel(VoiceInputChannel):
100
+ @classmethod
101
+ def name(cls) -> str:
102
+ return "audiocodes_stream"
103
+
104
+ def __init__(
105
+ self,
106
+ server_url: str,
107
+ asr_config: Dict,
108
+ tts_config: Dict,
109
+ monitor_silence: bool = False,
110
+ ):
111
+ mark_as_beta_feature("Audiocodes (audiocodes_stream) Channel")
112
+ super().__init__(server_url, asr_config, tts_config, monitor_silence)
113
+
114
+ def channel_bytes_to_rasa_audio_bytes(self, input_bytes: bytes) -> RasaAudioBytes:
115
+ return RasaAudioBytes(base64.b64decode(input_bytes))
116
+
117
+ async def collect_call_parameters(
118
+ self, channel_websocket: Websocket
119
+ ) -> Optional[CallParameters]:
120
+ async for message in channel_websocket:
121
+ data = json.loads(message)
122
+ if data["type"] == "session.initiate":
123
+ # contains info about mediaformats
124
+ logger.info(
125
+ "audiocodes_stream.collect_call_parameters.session.initiate",
126
+ data=data,
127
+ )
128
+ self._send_accepted(channel_websocket, data)
129
+ elif data["type"] == "activities":
130
+ activities = data["activities"]
131
+ for activity in activities:
132
+ logger.debug(
133
+ "audiocodes_stream.collect_call_parameters.activity",
134
+ data=activity,
135
+ )
136
+ if activity["name"] == "start":
137
+ return map_call_params(activity["parameters"])
138
+ else:
139
+ logger.warning("audiocodes_stream.unknown_message", data=data)
140
+ return None
141
+
142
+ def map_input_message(
143
+ self,
144
+ message: Any,
145
+ ws: Websocket,
146
+ ) -> VoiceChannelAction:
147
+ data = json.loads(message)
148
+ if data["type"] == "activities":
149
+ activities = data["activities"]
150
+ for activity in activities:
151
+ logger.debug("audiocodes_stream.activity", data=activity)
152
+ if activity["name"] == "start":
153
+ # already handled in collect_call_parameters
154
+ pass
155
+ elif activity["name"] == "dtmf":
156
+ # TODO: handle DTMF input
157
+ pass
158
+ elif activity["name"] == "playFinished":
159
+ logger.debug("audiocodes_stream.playFinished", data=activity)
160
+ if call_state.should_hangup:
161
+ logger.info("audiocodes.hangup")
162
+ self._send_hangup(ws, data)
163
+ # the conversation should continue until
164
+ # we receive a end message from audiocodes
165
+ pass
166
+ else:
167
+ logger.warning("audiocodes_stream.unknown_activity", data=activity)
168
+ elif data["type"] == "userStream.start":
169
+ logger.debug("audiocodes_stream.userStream.start", data=data)
170
+ self._send_recognition_started(ws, data)
171
+ elif data["type"] == "userStream.chunk":
172
+ audio_bytes = self.channel_bytes_to_rasa_audio_bytes(data["audioChunk"])
173
+ return NewAudioAction(audio_bytes)
174
+ elif data["type"] == "userStream.stop":
175
+ logger.debug("audiocodes_stream.stop_recognition", data=data)
176
+ self._send_recognition_ended(ws, data)
177
+ elif data["type"] == "session.resume":
178
+ logger.debug("audiocodes_stream.resume", data=data)
179
+ self._send_accepted(ws, data)
180
+ elif data["type"] == "session.end":
181
+ logger.debug("audiocodes_stream.end", data=data)
182
+ return EndConversationAction()
183
+ elif data["type"] == "connection.validate":
184
+ # not part of call flow; only sent when integration is created
185
+ self._send_validated(ws, data)
186
+ else:
187
+ logger.warning("audiocodes_stream.unknown_message", data=data)
188
+
189
+ return ContinueConversationAction()
190
+
191
+ def _send_accepted(self, ws: Websocket, data: Dict[Text, Any]) -> None:
192
+ supported_formats = data.get("supportedMediaFormats", [])
193
+ preferred_format = PREFERRED_AUDIO_FORMAT
194
+
195
+ if preferred_format not in supported_formats:
196
+ logger.warning(
197
+ "audiocodes_stream.format_not_supported",
198
+ supported_formats=supported_formats,
199
+ preferred_format=preferred_format,
200
+ )
201
+ raise
202
+
203
+ payload = {
204
+ "type": "session.accepted",
205
+ "mediaFormat": PREFERRED_AUDIO_FORMAT,
206
+ }
207
+ _schedule_async_task(ws.send(json.dumps(payload)))
208
+
209
+ def _send_recognition_started(self, ws: Websocket, data: Dict[Text, Any]) -> None:
210
+ payload = {"type": "userStream.started"}
211
+ _schedule_async_task(ws.send(json.dumps(payload)))
212
+
213
+ def _send_recognition_ended(self, ws: Websocket, data: Dict[Text, Any]) -> None:
214
+ payload = {"type": "userStream.stopped"}
215
+ _schedule_async_task(ws.send(json.dumps(payload)))
216
+
217
+ def _send_hypothesis(self, ws: Websocket, data: Dict[Text, Any]) -> None:
218
+ """
219
+ TODO: The hypothesis message is sent by the bot to provide partial
220
+ recognition results. Using this message is recommended,
221
+ as VAIC relies on it for performing barge-in.
222
+ """
223
+ pass
224
+
225
+ def _send_recognition(self, ws: Websocket, data: Dict[Text, Any]) -> None:
226
+ """
227
+ TODO: The recognition message is sent by the bot to provide
228
+ the final recognition result. Using this message is recommended
229
+ mainly for logging purposes.
230
+ """
231
+ pass
232
+
233
+ def _send_hangup(self, ws: Websocket, data: Dict[Text, Any]) -> None:
234
+ payload = {
235
+ "conversationId": data["conversationId"],
236
+ "type": "activities",
237
+ "activities": [{"type": "event", "name": "hangup"}],
238
+ }
239
+ _schedule_async_task(ws.send(json.dumps(payload)))
240
+
241
+ def _send_validated(self, ws: Websocket, data: Dict[Text, Any]) -> None:
242
+ payload = {
243
+ "type": "connection.validated",
244
+ "success": True,
245
+ }
246
+ _schedule_async_task(ws.send(json.dumps(payload)))
247
+
248
+ def create_output_channel(
249
+ self, voice_websocket: Websocket, tts_engine: TTSEngine
250
+ ) -> VoiceOutputChannel:
251
+ return AudiocodesVoiceOutputChannel(
252
+ voice_websocket,
253
+ tts_engine,
254
+ self.tts_cache,
255
+ )
256
+
257
+ def blueprint(
258
+ self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
259
+ ) -> Blueprint:
260
+ """Defines a Sanic bluelogger.debug."""
261
+ blueprint = Blueprint("audiocodes_stream", __name__)
262
+
263
+ @blueprint.route("/", methods=["GET"])
264
+ async def health(_: Request) -> HTTPResponse:
265
+ return response.json({"status": "ok"})
266
+
267
+ @blueprint.websocket("/websocket") # type: ignore
268
+ async def receive(request: Request, ws: Websocket) -> None:
269
+ # TODO: validate API key header
270
+ logger.info("audiocodes.receive", message="Starting audio streaming")
271
+ try:
272
+ await self.run_audio_streaming(on_new_message, ws)
273
+ except Exception as e:
274
+ logger.exception(
275
+ "audiocodes.receive",
276
+ message="Error during audio streaming",
277
+ error=e,
278
+ )
279
+ # return 500 error
280
+ raise
281
+
282
+ return blueprint
283
+
284
+
285
+ def _schedule_async_task(coro: Awaitable[Any]) -> None:
286
+ """Helper function to schedule a coroutine in the event loop.
287
+
288
+ Args:
289
+ coro: The coroutine to schedule
290
+ """
291
+ loop = asyncio.get_running_loop()
292
+ loop.call_soon_threadsafe(lambda: loop.create_task(coro))
@@ -1,20 +1,23 @@
1
1
  import audioop
2
2
  import base64
3
3
  import json
4
-
5
- import structlog
6
4
  import uuid
7
5
  from typing import Any, Awaitable, Callable, Optional, Tuple
8
6
 
9
- from sanic import Blueprint, HTTPResponse, Request, response
10
- from sanic import Websocket # type: ignore
11
-
7
+ import structlog
8
+ from sanic import ( # type: ignore[attr-defined]
9
+ Blueprint,
10
+ HTTPResponse,
11
+ Request,
12
+ Websocket,
13
+ response,
14
+ )
12
15
 
13
16
  from rasa.core.channels import UserMessage
14
17
  from rasa.core.channels.voice_ready.utils import CallParameters
18
+ from rasa.core.channels.voice_stream.audio_bytes import RasaAudioBytes
15
19
  from rasa.core.channels.voice_stream.call_state import call_state
16
20
  from rasa.core.channels.voice_stream.tts.tts_engine import TTSEngine
17
- from rasa.core.channels.voice_stream.audio_bytes import RasaAudioBytes
18
21
  from rasa.core.channels.voice_stream.voice_channel import (
19
22
  ContinueConversationAction,
20
23
  EndConversationAction,
@@ -62,6 +65,7 @@ class BrowserAudioInputChannel(VoiceInputChannel):
62
65
  def map_input_message(
63
66
  self,
64
67
  message: Any,
68
+ ws: Websocket,
65
69
  ) -> VoiceChannelAction:
66
70
  data = json.loads(message)
67
71
  if "audio" in data:
@@ -102,6 +106,9 @@ class BrowserAudioInputChannel(VoiceInputChannel):
102
106
 
103
107
  @blueprint.websocket("/websocket") # type: ignore
104
108
  async def handle_message(request: Request, ws: Websocket) -> None:
105
- await self.run_audio_streaming(on_new_message, ws)
109
+ try:
110
+ await self.run_audio_streaming(on_new_message, ws)
111
+ except Exception as e:
112
+ logger.error("browser_audio.handle_message.error", error=e)
106
113
 
107
114
  return blueprint