rasa-pro 3.12.21__py3-none-any.whl → 3.13.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 (354) hide show
  1. rasa/__main__.py +3 -4
  2. rasa/api.py +1 -1
  3. rasa/cli/dialogue_understanding_test.py +1 -1
  4. rasa/cli/e2e_test.py +1 -8
  5. rasa/cli/evaluate.py +2 -2
  6. rasa/cli/export.py +5 -3
  7. rasa/cli/inspect.py +7 -0
  8. rasa/cli/llm_fine_tuning.py +1 -1
  9. rasa/cli/project_templates/default/config.yml +5 -32
  10. rasa/cli/project_templates/{calm → default}/e2e_tests/cancelations/user_cancels_during_a_correction.yml +1 -1
  11. rasa/cli/project_templates/{calm → default}/e2e_tests/cancelations/user_changes_mind_on_a_whim.yml +1 -1
  12. rasa/cli/project_templates/{calm → default}/e2e_tests/corrections/user_corrects_contact_handle.yml +1 -1
  13. rasa/cli/project_templates/{calm → default}/e2e_tests/corrections/user_corrects_contact_name.yml +1 -1
  14. rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_adds_contact_to_their_list.yml +1 -1
  15. rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_lists_contacts.yml +1 -1
  16. rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_removes_contact.yml +1 -1
  17. rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_removes_contact_from_list.yml +1 -1
  18. rasa/cli/project_templates/default/endpoints.yml +18 -2
  19. rasa/cli/project_templates/defaults.py +133 -0
  20. rasa/cli/project_templates/tutorial/config.yml +1 -1
  21. rasa/cli/project_templates/tutorial/endpoints.yml +1 -1
  22. rasa/cli/run.py +1 -1
  23. rasa/cli/scaffold.py +2 -3
  24. rasa/cli/shell.py +6 -1
  25. rasa/cli/studio/download.py +0 -22
  26. rasa/cli/studio/link.py +36 -0
  27. rasa/cli/studio/pull.py +79 -0
  28. rasa/cli/studio/push.py +78 -0
  29. rasa/cli/studio/studio.py +12 -0
  30. rasa/cli/studio/train.py +1 -5
  31. rasa/cli/studio/upload.py +6 -4
  32. rasa/cli/train.py +5 -1
  33. rasa/cli/utils.py +1 -1
  34. rasa/cli/x.py +1 -1
  35. rasa/constants.py +2 -0
  36. rasa/core/__init__.py +0 -16
  37. rasa/core/actions/action.py +43 -29
  38. rasa/core/actions/action_repeat_bot_messages.py +18 -22
  39. rasa/core/actions/action_run_slot_rejections.py +1 -2
  40. rasa/core/agent.py +24 -3
  41. rasa/core/available_endpoints.py +146 -0
  42. rasa/core/brokers/kafka.py +4 -0
  43. rasa/core/brokers/pika.py +5 -2
  44. rasa/core/brokers/sql.py +1 -1
  45. rasa/core/channels/__init__.py +3 -0
  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-371401b1.js} +1 -1
  55. rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-7f34db23.js → blockDiagram-38ab4fdb-3f126156.js} +1 -1
  56. rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-948bab2c.js → c4Diagram-3d4e48cf-12f22eb7.js} +1 -1
  57. rasa/core/channels/inspector/dist/assets/channel-f1efda17.js +1 -0
  58. rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-53b0dd0e.js → classDiagram-70f12bd4-03b1d386.js} +1 -1
  59. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-fdf789e7.js → classDiagram-v2-f2320105-84f69d63.js} +1 -1
  60. rasa/core/channels/inspector/dist/assets/clone-fdf164e2.js +1 -0
  61. rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-87c4ece5.js → createText-2e5e7dd3-ca47fd38.js} +1 -1
  62. rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-5a8b0749.js → edges-e0da2a9e-f837ca8a.js} +1 -1
  63. rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-66da90e2.js → erDiagram-9861fffd-8717ac54.js} +1 -1
  64. rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-10044f05.js → flowDb-956e92f1-94f38b83.js} +1 -1
  65. rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-f338f66a.js → flowDiagram-66a62f08-b616f9fb.js} +1 -1
  66. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-7d7a1629.js +1 -0
  67. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-b13140aa.js → flowchart-elk-definition-4a651766-f5d24bb8.js} +1 -1
  68. rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-f2b4a55a.js → ganttDiagram-c361ad54-b43ba8d9.js} +1 -1
  69. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-dedc298d.js → gitGraphDiagram-72cf32ee-c3aafaa5.js} +1 -1
  70. rasa/core/channels/inspector/dist/assets/{graph-4ede11ff.js → graph-0d0a2c10.js} +1 -1
  71. rasa/core/channels/inspector/dist/assets/{index-3862675e-65549d37.js → index-3862675e-58ea0305.js} +1 -1
  72. rasa/core/channels/inspector/dist/assets/{index-3a23e736.js → index-cce6f8a1.js} +123 -123
  73. rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-65439671.js → infoDiagram-f8f76790-b8f60461.js} +1 -1
  74. rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-56d03d98.js → journeyDiagram-49397b02-95be5545.js} +1 -1
  75. rasa/core/channels/inspector/dist/assets/{layout-dd48f7f4.js → layout-da885b9b.js} +1 -1
  76. rasa/core/channels/inspector/dist/assets/{line-1569ad2c.js → line-f1c817d3.js} +1 -1
  77. rasa/core/channels/inspector/dist/assets/{linear-48bf4935.js → linear-d42801e6.js} +1 -1
  78. rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-688504c1.js → mindmap-definition-fc14e90a-a38923a6.js} +1 -1
  79. rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-78b6d7e6.js → pieDiagram-8a3498a8-ca6e71e9.js} +1 -1
  80. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-048b84b3.js → quadrantDiagram-120e2f19-b290dae9.js} +1 -1
  81. rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-dd67f107.js → requirementDiagram-deff3bca-03f02ceb.js} +1 -1
  82. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-8128436e.js → sankeyDiagram-04a897e0-c49eee40.js} +1 -1
  83. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-1a0d1461.js → sequenceDiagram-704730f1-b2cd6a3d.js} +1 -1
  84. rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-46d388ed.js → stateDiagram-587899a1-e53a2028.js} +1 -1
  85. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-ea42951a.js → stateDiagram-v2-d93cdb3a-e1982a03.js} +1 -1
  86. rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-7427ed0c.js → styles-6aaf32cf-d0226ca5.js} +1 -1
  87. rasa/core/channels/inspector/dist/assets/{styles-9a916d00-ff5e5a16.js → styles-9a916d00-0e21dc00.js} +1 -1
  88. rasa/core/channels/inspector/dist/assets/{styles-c10674c1-7b3680cf.js → styles-c10674c1-9588494e.js} +1 -1
  89. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-f860f2ad.js → svgDrawCommon-08f97a94-be478d4f.js} +1 -1
  90. rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-2eebf0c8.js → timeline-definition-85554ec2-74631749.js} +1 -1
  91. rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-5d7f4e96.js → xychartDiagram-e933f94c-a043552f.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 +329 -68
  141. rasa/core/channels/vier_cvg.py +1 -2
  142. rasa/core/channels/voice_ready/audiocodes.py +4 -11
  143. rasa/core/channels/voice_ready/jambonz.py +5 -6
  144. rasa/core/channels/voice_ready/twilio_voice.py +13 -12
  145. rasa/core/channels/voice_ready/utils.py +22 -0
  146. rasa/core/channels/voice_stream/audiocodes.py +13 -16
  147. rasa/core/channels/voice_stream/browser_audio.py +1 -1
  148. rasa/core/channels/voice_stream/genesys.py +37 -18
  149. rasa/core/channels/voice_stream/jambonz.py +232 -0
  150. rasa/core/channels/voice_stream/tts/__init__.py +8 -0
  151. rasa/core/channels/voice_stream/twilio_media_streams.py +15 -12
  152. rasa/core/channels/voice_stream/voice_channel.py +71 -27
  153. rasa/core/concurrent_lock_store.py +24 -10
  154. rasa/core/evaluation/marker_tracker_loader.py +1 -1
  155. rasa/core/exporter.py +37 -1
  156. rasa/core/http_interpreter.py +3 -7
  157. rasa/core/information_retrieval/faiss.py +18 -11
  158. rasa/core/information_retrieval/ingestion/faq_parser.py +158 -0
  159. rasa/core/jobs.py +2 -1
  160. rasa/core/lock_store.py +151 -60
  161. rasa/core/nlg/contextual_response_rephraser.py +17 -7
  162. rasa/core/nlg/generator.py +5 -22
  163. rasa/core/nlg/interpolator.py +2 -3
  164. rasa/core/nlg/response.py +6 -43
  165. rasa/core/nlg/summarize.py +1 -1
  166. rasa/core/nlg/translate.py +0 -8
  167. rasa/core/policies/enterprise_search_policy.py +305 -189
  168. rasa/core/policies/enterprise_search_policy_config.py +241 -0
  169. rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +67 -0
  170. rasa/core/policies/flow_policy.py +1 -1
  171. rasa/core/policies/flows/flow_executor.py +102 -17
  172. rasa/core/policies/intentless_policy.py +56 -17
  173. rasa/core/processor.py +70 -49
  174. rasa/core/run.py +33 -11
  175. rasa/core/tracker_stores/__init__.py +0 -0
  176. rasa/core/{auth_retry_tracker_store.py → tracker_stores/auth_retry_tracker_store.py} +66 -1
  177. rasa/core/tracker_stores/dynamo_tracker_store.py +256 -0
  178. rasa/core/tracker_stores/mongo_tracker_store.py +223 -0
  179. rasa/core/tracker_stores/redis_tracker_store.py +252 -0
  180. rasa/core/tracker_stores/sql_tracker_store.py +582 -0
  181. rasa/core/tracker_stores/tracker_store.py +839 -0
  182. rasa/core/training/interactive.py +1 -1
  183. rasa/core/utils.py +24 -95
  184. rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -1
  185. rasa/dialogue_understanding/coexistence/llm_based_router.py +13 -11
  186. rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -0
  187. rasa/dialogue_understanding/commands/cancel_flow_command.py +3 -1
  188. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -0
  189. rasa/dialogue_understanding/commands/clarify_command.py +6 -2
  190. rasa/dialogue_understanding/commands/command_syntax_manager.py +1 -0
  191. rasa/dialogue_understanding/commands/correct_slots_command.py +5 -6
  192. rasa/dialogue_understanding/commands/error_command.py +1 -1
  193. rasa/dialogue_understanding/commands/human_handoff_command.py +3 -3
  194. rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -0
  195. rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +2 -0
  196. rasa/dialogue_understanding/commands/set_slot_command.py +8 -4
  197. rasa/dialogue_understanding/commands/skip_question_command.py +3 -3
  198. rasa/dialogue_understanding/commands/start_flow_command.py +7 -3
  199. rasa/dialogue_understanding/generator/__init__.py +7 -1
  200. rasa/dialogue_understanding/generator/command_generator.py +4 -2
  201. rasa/dialogue_understanding/generator/command_parser.py +2 -2
  202. rasa/dialogue_understanding/generator/command_parser_validator.py +63 -0
  203. rasa/dialogue_understanding/generator/llm_based_command_generator.py +1 -2
  204. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +3 -2
  205. rasa/dialogue_understanding/generator/nlu_command_adapter.py +2 -2
  206. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_template.jinja2 +0 -2
  207. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +1 -0
  208. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +1 -0
  209. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +79 -0
  210. rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +79 -0
  211. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +26 -461
  212. rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +147 -0
  213. rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +461 -0
  214. rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +20 -64
  215. rasa/dialogue_understanding/patterns/cancel.py +1 -2
  216. rasa/dialogue_understanding/patterns/clarify.py +1 -1
  217. rasa/dialogue_understanding/patterns/correction.py +2 -2
  218. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +42 -27
  219. rasa/dialogue_understanding/patterns/domain_for_patterns.py +190 -0
  220. rasa/dialogue_understanding/processor/command_processor.py +6 -7
  221. rasa/dialogue_understanding_test/command_metric_calculation.py +7 -40
  222. rasa/dialogue_understanding_test/command_metrics.py +38 -0
  223. rasa/dialogue_understanding_test/du_test_case.py +58 -25
  224. rasa/dialogue_understanding_test/du_test_result.py +228 -132
  225. rasa/dialogue_understanding_test/du_test_runner.py +11 -2
  226. rasa/dialogue_understanding_test/du_test_schema.yml +3 -3
  227. rasa/dialogue_understanding_test/io.py +35 -8
  228. rasa/e2e_test/constants.py +1 -1
  229. rasa/e2e_test/e2e_test_runner.py +1 -1
  230. rasa/e2e_test/e2e_test_schema.yml +3 -3
  231. rasa/engine/constants.py +1 -1
  232. rasa/engine/graph.py +2 -2
  233. rasa/engine/recipes/default_recipe.py +1 -1
  234. rasa/engine/validation.py +3 -2
  235. rasa/hooks.py +2 -30
  236. rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +2 -6
  237. rasa/model_manager/model_api.py +89 -1
  238. rasa/model_manager/runner_service.py +20 -4
  239. rasa/model_manager/socket_bridge.py +0 -7
  240. rasa/model_manager/trainer_service.py +10 -4
  241. rasa/plugin.py +2 -15
  242. rasa/privacy/__init__.py +0 -0
  243. rasa/privacy/constants.py +83 -0
  244. rasa/privacy/event_broker_utils.py +77 -0
  245. rasa/privacy/privacy_config.py +281 -0
  246. rasa/privacy/privacy_config_schema.json +86 -0
  247. rasa/privacy/privacy_filter.py +393 -0
  248. rasa/privacy/privacy_manager.py +594 -0
  249. rasa/server.py +23 -2
  250. rasa/shared/constants.py +17 -0
  251. rasa/shared/core/command_payload_reader.py +1 -5
  252. rasa/shared/core/constants.py +4 -3
  253. rasa/shared/core/domain.py +172 -11
  254. rasa/shared/core/events.py +100 -6
  255. rasa/shared/core/flows/flow.py +30 -5
  256. rasa/shared/core/flows/flow_step.py +19 -3
  257. rasa/shared/core/flows/flow_step_links.py +15 -0
  258. rasa/shared/core/flows/flow_step_sequence.py +6 -0
  259. rasa/shared/core/flows/flows_yaml_schema.json +3 -0
  260. rasa/shared/core/flows/nlu_trigger.py +13 -0
  261. rasa/shared/core/flows/steps/action.py +7 -4
  262. rasa/shared/core/flows/steps/call.py +11 -4
  263. rasa/shared/core/flows/steps/collect.py +71 -6
  264. rasa/shared/core/flows/steps/internal.py +6 -1
  265. rasa/shared/core/flows/steps/link.py +7 -4
  266. rasa/shared/core/flows/steps/no_operation.py +7 -4
  267. rasa/shared/core/flows/steps/set_slots.py +8 -4
  268. rasa/shared/core/flows/validation.py +25 -5
  269. rasa/shared/core/flows/yaml_flows_io.py +106 -5
  270. rasa/shared/core/slots.py +29 -1
  271. rasa/shared/core/trackers.py +21 -10
  272. rasa/shared/core/training_data/story_reader/yaml_story_reader.py +1 -4
  273. rasa/shared/importers/importer.py +8 -0
  274. rasa/shared/providers/_configs/azure_openai_client_config.py +2 -2
  275. rasa/shared/providers/_configs/default_litellm_client_config.py +1 -1
  276. rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +1 -1
  277. rasa/shared/providers/_configs/openai_client_config.py +1 -1
  278. rasa/shared/providers/_configs/rasa_llm_client_config.py +1 -1
  279. rasa/shared/providers/_configs/self_hosted_llm_client_config.py +1 -1
  280. rasa/shared/providers/_configs/utils.py +0 -99
  281. rasa/shared/providers/llm/default_litellm_llm_client.py +2 -2
  282. rasa/shared/utils/common.py +43 -1
  283. rasa/shared/utils/configs.py +110 -0
  284. rasa/shared/utils/constants.py +0 -3
  285. rasa/shared/utils/llm.py +245 -8
  286. rasa/shared/utils/pykwalify_extensions.py +0 -9
  287. rasa/shared/utils/yaml.py +32 -0
  288. rasa/studio/constants.py +1 -0
  289. rasa/studio/data_handler.py +33 -12
  290. rasa/studio/download.py +117 -435
  291. rasa/studio/link.py +211 -0
  292. rasa/studio/prompts.py +221 -0
  293. rasa/studio/pull/__init__.py +0 -0
  294. rasa/studio/pull/data.py +222 -0
  295. rasa/studio/pull/domains.py +60 -0
  296. rasa/studio/pull/pull.py +239 -0
  297. rasa/studio/push.py +138 -0
  298. rasa/studio/results_logger.py +6 -1
  299. rasa/studio/train.py +1 -1
  300. rasa/studio/upload.py +243 -72
  301. rasa/studio/utils.py +33 -0
  302. rasa/telemetry.py +83 -26
  303. rasa/tracing/config.py +4 -5
  304. rasa/tracing/constants.py +19 -1
  305. rasa/tracing/instrumentation/attribute_extractors.py +68 -16
  306. rasa/tracing/instrumentation/instrumentation.py +54 -3
  307. rasa/tracing/instrumentation/metrics.py +98 -15
  308. rasa/tracing/metric_instrument_provider.py +75 -3
  309. rasa/utils/common.py +43 -22
  310. rasa/utils/endpoints.py +22 -1
  311. rasa/utils/licensing.py +2 -3
  312. rasa/utils/log_utils.py +1 -45
  313. rasa/validator.py +2 -8
  314. rasa/version.py +1 -1
  315. {rasa_pro-3.12.21.dist-info → rasa_pro-3.13.0.dist-info}/METADATA +13 -14
  316. {rasa_pro-3.12.21.dist-info → rasa_pro-3.13.0.dist-info}/RECORD +333 -309
  317. rasa/anonymization/__init__.py +0 -2
  318. rasa/anonymization/anonymisation_rule_yaml_reader.py +0 -91
  319. rasa/anonymization/anonymization_pipeline.py +0 -286
  320. rasa/anonymization/anonymization_rule_executor.py +0 -266
  321. rasa/anonymization/anonymization_rule_orchestrator.py +0 -119
  322. rasa/anonymization/schemas/config.yml +0 -47
  323. rasa/anonymization/utils.py +0 -118
  324. rasa/cli/project_templates/calm/config.yml +0 -10
  325. rasa/cli/project_templates/calm/credentials.yml +0 -33
  326. rasa/cli/project_templates/calm/endpoints.yml +0 -58
  327. rasa/cli/project_templates/default/actions/actions.py +0 -27
  328. rasa/cli/project_templates/default/data/nlu.yml +0 -91
  329. rasa/cli/project_templates/default/data/rules.yml +0 -13
  330. rasa/cli/project_templates/default/data/stories.yml +0 -30
  331. rasa/cli/project_templates/default/domain.yml +0 -34
  332. rasa/cli/project_templates/default/tests/test_stories.yml +0 -91
  333. rasa/core/channels/inspector/dist/assets/channel-dfa68278.js +0 -1
  334. rasa/core/channels/inspector/dist/assets/clone-edb7f119.js +0 -1
  335. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-65e7c670.js +0 -1
  336. rasa/core/channels/inspector/src/helpers/audiostream.ts +0 -191
  337. rasa/core/tracker_store.py +0 -1792
  338. /rasa/cli/project_templates/{calm → default}/actions/action_template.py +0 -0
  339. /rasa/cli/project_templates/{calm → default}/actions/add_contact.py +0 -0
  340. /rasa/cli/project_templates/{calm → default}/actions/db.py +0 -0
  341. /rasa/cli/project_templates/{calm → default}/actions/list_contacts.py +0 -0
  342. /rasa/cli/project_templates/{calm → default}/actions/remove_contact.py +0 -0
  343. /rasa/cli/project_templates/{calm → default}/data/flows/add_contact.yml +0 -0
  344. /rasa/cli/project_templates/{calm → default}/data/flows/list_contacts.yml +0 -0
  345. /rasa/cli/project_templates/{calm → default}/data/flows/remove_contact.yml +0 -0
  346. /rasa/cli/project_templates/{calm → default}/db/contacts.json +0 -0
  347. /rasa/cli/project_templates/{calm → default}/domain/add_contact.yml +0 -0
  348. /rasa/cli/project_templates/{calm → default}/domain/list_contacts.yml +0 -0
  349. /rasa/cli/project_templates/{calm → default}/domain/remove_contact.yml +0 -0
  350. /rasa/cli/project_templates/{calm → default}/domain/shared.yml +0 -0
  351. /rasa/{cli/project_templates/calm/actions → core/information_retrieval/ingestion}/__init__.py +0 -0
  352. {rasa_pro-3.12.21.dist-info → rasa_pro-3.13.0.dist-info}/NOTICE +0 -0
  353. {rasa_pro-3.12.21.dist-info → rasa_pro-3.13.0.dist-info}/WHEEL +0 -0
  354. {rasa_pro-3.12.21.dist-info → rasa_pro-3.13.0.dist-info}/entry_points.txt +0 -0
rasa/studio/download.py CHANGED
@@ -1,489 +1,171 @@
1
1
  import argparse
2
- import logging
2
+ import shutil
3
3
  from pathlib import Path
4
- from typing import Any, Dict, List, Optional, Set, Tuple
4
+ from typing import Dict
5
5
 
6
6
  import questionary
7
7
  import structlog
8
+ from ruamel import yaml
9
+ from ruamel.yaml.scalarstring import LiteralScalarString
8
10
 
9
11
  import rasa.cli.utils
10
12
  import rasa.shared.utils.cli
11
13
  from rasa.shared.constants import (
12
14
  DEFAULT_CONFIG_PATH,
13
15
  DEFAULT_DATA_PATH,
14
- DEFAULT_DOMAIN_PATH,
15
16
  DEFAULT_ENDPOINTS_PATH,
16
17
  )
17
- from rasa.shared.core.domain import Domain
18
- from rasa.shared.core.flows.yaml_flows_io import YamlFlowsWriter
19
- from rasa.shared.importers.importer import TrainingDataImporter
20
- from rasa.shared.utils.yaml import read_yaml
21
- from rasa.studio import data_handler
22
- from rasa.studio.config import StudioConfig
23
- from rasa.studio.constants import (
24
- STUDIO_DOMAIN_FILENAME,
25
- STUDIO_FLOWS_FILENAME,
26
- STUDIO_NLU_FILENAME,
27
- )
28
- from rasa.studio.data_handler import (
29
- StudioDataHandler,
30
- import_data_from_studio,
18
+ from rasa.shared.core.flows.yaml_flows_io import FlowsList
19
+ from rasa.shared.nlu.training_data.training_data import (
20
+ DEFAULT_TRAINING_DATA_OUTPUT_PATH,
31
21
  )
32
- from rasa.utils.mapper import RasaPrimitiveStorageMapper
22
+ from rasa.shared.utils.yaml import read_yaml, write_yaml
23
+ from rasa.studio.config import StudioConfig
24
+ from rasa.studio.constants import DOMAIN_FILENAME
25
+ from rasa.studio.data_handler import StudioDataHandler
26
+ from rasa.studio.prompts import handle_prompts
27
+ from rasa.studio.pull.data import _dump_flows_as_separate_files
28
+ from rasa.studio.utils import validate_argument_paths
33
29
 
34
- logger = logging.getLogger(__name__)
35
- structlogger = structlog.getLogger(__name__)
30
+ structlogger = structlog.get_logger()
36
31
 
37
32
 
38
- def _handle_file_overwrite(
39
- file_path: Optional[str], default_path: str, file_type: str
40
- ) -> Tuple[Optional[Path], bool]:
41
- """Handles the logic for determining whether to
42
- overwrite an existing file or create a new one.
43
- Works for config and endpoints at this moment
33
+ def handle_download(args: argparse.Namespace) -> None:
34
+ """Download an assistant from Studio and store it in `<assistant_name>/`.
44
35
 
45
36
  Args:
46
- file_path (Optional[str]): The path to the file
47
- provided by the user. Can be None.
48
- default_path (str): The default path to use if `file_path`
49
- is None or invalid. Must be a file path.
50
- file_type (str): The type of the file (e.g., "config",
51
- "endpoints") for logging and messaging purposes.
52
-
53
- Returns:
54
- tuple[Optional[Path], bool]: A tuple containing the
55
- resolved file path and a boolean
56
- indicating whether to write the file.
37
+ args: The command line arguments.
57
38
  """
58
- file_already_exists = rasa.cli.utils.get_validated_path(
59
- file_path, file_type, default_path, none_is_valid=True
39
+ validate_argument_paths(args)
40
+ assistant_name = args.assistant_name
41
+ target_root = _prepare_target_directory(assistant_name)
42
+
43
+ handler = StudioDataHandler(
44
+ studio_config=StudioConfig.read_config(), assistant_name=assistant_name
60
45
  )
61
- write_file = False
62
- path = None
63
- file_or_default_path = file_path or default_path
46
+ handler.request_all_data()
64
47
 
65
- if file_already_exists is None:
66
- path = Path(file_or_default_path)
67
- if path.is_dir():
68
- path = path / default_path
69
- return path, True
48
+ _handle_config(handler, target_root)
49
+ _handle_endpoints(handler, target_root)
50
+ _handle_domain(handler, target_root)
51
+ _handle_data(handler, target_root)
70
52
 
71
- if questionary.confirm(
72
- f"{file_type.capitalize()} file '{file_or_default_path}' "
73
- f"already exists. Do you want to overwrite it?"
74
- ).ask():
75
- write_file = True
76
- path = Path(file_or_default_path)
77
- return path, write_file
53
+ if prompts := handler.get_prompts():
54
+ handle_prompts(prompts, target_root)
55
+
56
+ structlogger.info(
57
+ "studio.download.success",
58
+ event_info=f"Downloaded assistant '{assistant_name}' from Studio.",
59
+ assistant_name=assistant_name,
60
+ )
61
+ rasa.shared.utils.cli.print_success(
62
+ f"Downloaded assistant '{assistant_name}' from Studio."
63
+ )
78
64
 
79
65
 
80
- def _prepare_data_and_domain_paths(args: argparse.Namespace) -> Tuple[Path, List[Path]]:
81
- """Handles the logic for preparing the domain and data paths
82
- based on the provided arguments.
66
+ def _prepare_target_directory(assistant_name: str) -> Path:
67
+ """Create (or overwrite) the directory where everything is stored.
83
68
 
84
69
  Args:
85
- args (argparse.Namespace): The parsed arguments.
70
+ assistant_name: The name of the assistant to download.
86
71
 
87
72
  Returns:
88
- tuple[Path, list[Path]]: A tuple containing the domain path
89
- and a list of data paths.
73
+ The path to the target directory where the assistant will be stored.
90
74
  """
91
- # prepare domain
92
- domain_path = rasa.cli.utils.get_validated_path(
93
- args.domain, "domain", DEFAULT_DOMAIN_PATH, none_is_valid=True
94
- )
95
- domain_or_default_path = args.domain or DEFAULT_DOMAIN_PATH
96
-
97
- if domain_path is None:
98
- # If the path is None, use the provided domain path
99
- domain_path = Path(domain_or_default_path)
100
- domain_path.touch()
75
+ target_root = Path(assistant_name)
101
76
 
102
- if isinstance(domain_path, str):
103
- domain_path = Path(domain_path)
77
+ if target_root.exists():
78
+ overwrite = questionary.confirm(
79
+ f"Directory '{assistant_name}' already exists. Overwrite it?"
80
+ ).ask()
81
+ if not overwrite:
82
+ rasa.shared.utils.cli.print_error_and_exit("Download cancelled.")
104
83
 
105
- if domain_path.is_file():
106
- if not args.overwrite:
107
- domain_path.unlink()
108
- domain_path.touch()
84
+ shutil.rmtree(target_root)
109
85
 
110
- if domain_path.is_dir():
111
- if not args.overwrite:
112
- domain_path = domain_path / STUDIO_DOMAIN_FILENAME
113
- domain_path.touch()
86
+ target_root.mkdir(parents=True, exist_ok=True)
87
+ return target_root
114
88
 
115
- # prepare data
116
- data_paths = []
117
89
 
118
- for f in args.data:
119
- data_path = rasa.cli.utils.get_validated_path(
120
- f, "data", DEFAULT_DATA_PATH, none_is_valid=True
121
- )
90
+ def _handle_config(handler: StudioDataHandler, root: Path) -> None:
91
+ """Download and persist the assistant’s config file.
122
92
 
123
- if data_path is None:
124
- # If the path is None, use the default data path
125
- data_path = Path(f)
126
- data_path.mkdir(parents=True, exist_ok=True)
127
- else:
128
- data_path = Path(data_path)
129
-
130
- if data_path.is_file() or data_path.is_dir():
131
- # If it's a file, add it directly
132
- data_paths.append(data_path)
133
- else:
134
- # If it doesn't exist, create the directory
135
- data_path.mkdir(parents=True, exist_ok=True)
136
- data_paths.append(data_path)
93
+ Args:
94
+ handler: The data handler to retrieve the config from.
95
+ root: The root directory where the config file will be stored.
96
+ """
97
+ config_data = handler.get_config()
98
+ if not config_data:
99
+ rasa.shared.utils.cli.print_error_and_exit("No config data found.")
137
100
 
138
- # Remove duplicates while preserving order
139
- data_paths = list(dict.fromkeys(data_paths))
101
+ config_path = root / DEFAULT_CONFIG_PATH
102
+ config_path.write_text(config_data, encoding="utf-8")
140
103
 
141
- return domain_path, data_paths
142
104
 
105
+ def _handle_endpoints(handler: StudioDataHandler, root: Path) -> None:
106
+ """Download and persist the assistant’s endpoints file.
143
107
 
144
- def handle_download(args: argparse.Namespace) -> None:
145
- handler = StudioDataHandler(
146
- studio_config=StudioConfig.read_config(), assistant_name=args.assistant_name[0]
147
- )
148
- handler.request_all_data()
108
+ Args:
109
+ handler: The data handler to retrieve the endpoints from.
110
+ root: The root directory where the endpoints file will be stored.
111
+ """
112
+ endpoints_data = handler.get_endpoints()
113
+ if not endpoints_data:
114
+ rasa.shared.utils.cli.print_error_and_exit("No endpoints data found.")
149
115
 
150
- domain_path, data_paths = _prepare_data_and_domain_paths(args)
116
+ endpoints_path = root / DEFAULT_ENDPOINTS_PATH
117
+ endpoints_path.write_text(endpoints_data, encoding="utf-8")
151
118
 
152
- # handle config and endpoints
153
- config_path, write_config = _handle_file_overwrite(
154
- args.config, DEFAULT_CONFIG_PATH, "config"
155
- )
156
- endpoints_path, write_endpoints = _handle_file_overwrite(
157
- args.endpoints, DEFAULT_ENDPOINTS_PATH, "endpoints"
158
- )
159
119
 
160
- # generate log message if we write the config or endpoints
161
- message_parts = []
162
-
163
- config_path = config_path if write_config else None
164
- endpoints_path = endpoints_path if write_endpoints else None
165
-
166
- if config_path:
167
- config_data = handler.get_config()
168
- if not config_data:
169
- rasa.shared.utils.cli.print_error_and_exit("No config data found.")
170
- with open(config_path, "w") as f:
171
- f.write(config_data)
172
- message_parts.append(f"config to '{config_path}'")
173
-
174
- if endpoints_path:
175
- endpoints_data = handler.get_endpoints()
176
- if not endpoints_data:
177
- raise ValueError("No endpoints data found.")
178
-
179
- with open(endpoints_path, "w") as f:
180
- f.write(endpoints_data)
181
- message_parts.append(f"endpoints to '{endpoints_path}'")
182
-
183
- if message_parts:
184
- message = "Downloaded " + " and ".join(message_parts)
185
- structlogger.info("studio.download.config_endpoints", event_info=message)
186
-
187
- if not args.overwrite:
188
- _handle_download_no_overwrite(
189
- handler=handler,
190
- domain_path=domain_path,
191
- data_paths=data_paths,
192
- )
193
- else:
194
- _handle_download_with_overwrite(
195
- handler=handler,
196
- domain_path=domain_path,
197
- data_paths=data_paths,
198
- )
199
-
200
-
201
- def _handle_download_no_overwrite(
202
- handler: StudioDataHandler,
203
- domain_path: Path,
204
- data_paths: List[Path],
205
- ) -> None:
206
- data_from_studio, data_original = import_data_from_studio(
207
- handler, domain_path, data_paths
208
- )
120
+ def _handle_domain(handler: StudioDataHandler, root: Path) -> None:
121
+ """Persist the assistant’s domain file.
209
122
 
210
- if domain_path.is_dir():
211
- studio_domain_path = domain_path / STUDIO_DOMAIN_FILENAME
212
- new_domain_data = data_handler.combine_domains(
213
- data_from_studio.get_user_domain().as_dict(),
214
- data_original.get_user_domain().as_dict(),
215
- )
216
- studio_domain = Domain.from_dict(new_domain_data)
217
- if not studio_domain.is_empty():
218
- studio_domain.persist(studio_domain_path)
219
- else:
220
- logger.warning("No additional domain data found.")
221
- elif domain_path.is_file():
222
- domain_merged = data_original.get_user_domain().merge(
223
- data_from_studio.get_user_domain()
224
- )
225
- domain_merged.persist(domain_path)
226
-
227
- if len(data_paths) == 1 and data_paths[0].is_file():
228
- data_path = data_paths[0]
229
- if handler.has_nlu():
230
- data_nlu = data_original.get_nlu_data().merge(
231
- data_from_studio.get_nlu_data()
232
- )
233
- data_nlu.persist_nlu(data_path)
234
- if handler.has_flows():
235
- data_flows = data_original.get_user_flows().merge(
236
- data_from_studio.get_user_flows()
237
- )
238
- YamlFlowsWriter.dump(data_flows.underlying_flows, data_path)
239
-
240
- elif len(data_paths) == 1 and data_paths[0].is_dir():
241
- if handler.has_nlu():
242
- data_path = data_paths[0] / Path(STUDIO_NLU_FILENAME)
243
- _persist_nlu_diff(data_original, data_from_studio, data_path)
244
- if handler.has_flows():
245
- data_path = data_paths[0] / Path(STUDIO_FLOWS_FILENAME)
246
- _persist_flows_diff(data_original, data_from_studio, data_path)
247
- else:
248
- if data_paths[0].is_dir():
249
- logger.info(f"Saving data to {data_paths[0]}.")
250
- data_path = data_paths[0] / Path(STUDIO_NLU_FILENAME)
251
- else:
252
- logger.info(f"Saving data to {STUDIO_NLU_FILENAME}.")
253
- data_path = Path(STUDIO_NLU_FILENAME)
254
- if handler.has_nlu():
255
- _persist_nlu_diff(data_original, data_from_studio, data_path)
256
- if handler.has_flows():
257
- _persist_flows_diff(data_original, data_from_studio, data_path)
258
-
259
-
260
- def _persist_nlu_diff(
261
- data_original: TrainingDataImporter,
262
- data_from_studio: TrainingDataImporter,
263
- data_path: Path,
264
- ) -> None:
265
- """Creates a new nlu file from the diff of original and studio data."""
266
- new_nlu_data = data_handler.create_new_nlu_from_diff(
267
- read_yaml(data_from_studio.get_nlu_data().nlu_as_yaml()),
268
- read_yaml(data_original.get_nlu_data().nlu_as_yaml()),
269
- )
270
- if new_nlu_data["nlu"]:
271
- pretty_write_nlu_yaml(new_nlu_data, data_path)
272
- else:
273
- logger.warning("No additional nlu data found.")
274
-
275
-
276
- def _persist_flows_diff(
277
- data_original: TrainingDataImporter,
278
- data_from_studio: TrainingDataImporter,
279
- data_path: Path,
280
- ) -> None:
281
- """Creates a new flows file from the diff of original and studio data."""
282
- new_flows_data = data_handler.create_new_flows_from_diff(
283
- data_from_studio.get_user_flows().underlying_flows,
284
- data_original.get_user_flows().underlying_flows,
123
+ Args:
124
+ handler: The data handler to retrieve the domain from.
125
+ root: The root directory where the domain file will be stored.
126
+ """
127
+ domain_yaml = handler.domain
128
+ data = read_yaml(domain_yaml)
129
+ target = root / DOMAIN_FILENAME
130
+ write_yaml(
131
+ data=data,
132
+ target=target,
133
+ should_preserve_key_order=True,
285
134
  )
286
- if new_flows_data:
287
- YamlFlowsWriter.dump(new_flows_data, data_path)
288
- else:
289
- logger.warning("No additional flows data found.")
290
135
 
291
136
 
292
- def pretty_write_nlu_yaml(data: Dict, file: Path) -> None:
293
- """Writes the nlu yaml in a pretty way.
137
+ def _handle_data(handler: StudioDataHandler, root: Path) -> None:
138
+ """Persist NLU data and flows.
294
139
 
295
140
  Args:
296
- data: The data to write.
297
- file: The file to write to.
141
+ handler: The data handler to retrieve the NLU data and flows from.
142
+ root: The root directory where the NLU data and flows will be stored.
298
143
  """
299
- from ruamel import yaml
300
- from ruamel.yaml.scalarstring import LiteralScalarString
144
+ data_path = root / DEFAULT_DATA_PATH
145
+ data_path.mkdir(parents=True, exist_ok=True)
146
+
147
+ if handler.has_nlu():
148
+ nlu_yaml = handler.nlu
149
+ nlu_data = read_yaml(nlu_yaml)
150
+ if nlu_data.get("nlu"):
151
+ pretty_write_nlu_yaml(
152
+ nlu_data, data_path / DEFAULT_TRAINING_DATA_OUTPUT_PATH
153
+ )
154
+
155
+ if handler.has_flows():
156
+ flows_yaml = handler.flows
157
+ data = read_yaml(flows_yaml)
158
+ flows_data = data.get("flows", {})
159
+ flows_list = FlowsList.from_json(flows_data)
160
+ _dump_flows_as_separate_files(flows_list.underlying_flows, data_path)
301
161
 
302
- dumper = yaml.YAML()
303
- for item in data["nlu"]:
304
- if item.get("examples"):
305
- item["examples"] = LiteralScalarString(item["examples"])
306
162
 
163
+ def pretty_write_nlu_yaml(data: Dict, file: Path) -> None:
164
+ """Writes the NLU YAML in a pretty way."""
165
+ dumper = yaml.YAML()
166
+ if nlu_data := data.get("nlu"):
167
+ for item in nlu_data:
168
+ if item.get("examples"):
169
+ item["examples"] = LiteralScalarString(item["examples"])
307
170
  with file.open("w", encoding="utf-8") as outfile:
308
171
  dumper.dump(data, outfile)
309
-
310
-
311
- def _handle_download_with_overwrite(
312
- handler: StudioDataHandler,
313
- domain_path: Path,
314
- data_paths: List[Path],
315
- ) -> None:
316
- data_from_studio, data_original = import_data_from_studio(
317
- handler, domain_path, data_paths
318
- )
319
- mapper = RasaPrimitiveStorageMapper(
320
- domain_path=domain_path, training_data_paths=data_paths
321
- )
322
-
323
- if domain_path.is_file():
324
- domain_merged = data_from_studio.get_user_domain().merge(
325
- data_original.get_user_domain()
326
- )
327
- domain_merged.persist(domain_path)
328
- elif domain_path.is_dir():
329
- default = domain_path / Path(STUDIO_DOMAIN_FILENAME)
330
- studio_domain = data_from_studio.get_user_domain()
331
-
332
- paths = get_domain_path(domain_path, data_from_studio, mapper)
333
-
334
- _persist_domain_part(
335
- {"intents": studio_domain.as_dict().get("intents", [])},
336
- default,
337
- paths["intent_path"],
338
- )
339
- _persist_domain_part(
340
- {"entities": studio_domain.as_dict().get("entities", [])},
341
- default,
342
- paths["entities_path"],
343
- )
344
- _persist_domain_part(
345
- {"actions": studio_domain.as_dict().get("actions", [])},
346
- default,
347
- paths["action_path"],
348
- )
349
- _persist_domain_part(
350
- {"slots": studio_domain.as_dict().get("slots", {})},
351
- default,
352
- paths["slot_path"],
353
- )
354
- _persist_domain_part(
355
- {"responses": studio_domain.as_dict().get("responses", {})},
356
- default,
357
- paths["response_path"],
358
- )
359
-
360
- if len(data_paths) == 1 and data_paths[0].is_file():
361
- if handler.has_nlu():
362
- nlu_data_merged = data_from_studio.get_nlu_data().merge(
363
- data_original.get_nlu_data()
364
- )
365
- nlu_data_merged.persist_nlu(data_paths[0])
366
- if handler.has_flows():
367
- flows_data_merged = data_from_studio.get_user_flows().merge(
368
- data_original.get_user_flows()
369
- )
370
- YamlFlowsWriter.dump(flows_data_merged.underlying_flows, data_paths[0])
371
- elif len(data_paths) == 1 and data_paths[0].is_dir():
372
- data_path = data_paths[0]
373
- paths = get_training_path(data_path, data_original, mapper)
374
- if handler.has_nlu():
375
- nlu_data = data_from_studio.get_nlu_data()
376
- if paths["nlu_path"].exists():
377
- nlu_file = TrainingDataImporter.load_from_dict(
378
- training_data_paths=[str(paths["nlu_path"])]
379
- )
380
- nlu_data = nlu_data.merge(nlu_file.get_nlu_data())
381
- pretty_write_nlu_yaml(read_yaml(nlu_data.nlu_as_yaml()), paths["nlu_path"])
382
- if handler.has_flows():
383
- flows_data = data_from_studio.get_user_flows()
384
- if paths["flow_path"].exists():
385
- flows_file = TrainingDataImporter.load_from_dict(
386
- training_data_paths=[str(paths["flow_path"])]
387
- )
388
- flows_data = flows_data.merge(flows_file.get_user_flows())
389
- YamlFlowsWriter.dump(flows_data.underlying_flows, paths["flow_path"])
390
- else:
391
- # TODO: we are not handling the case of multiple data paths?
392
- raise NotImplementedError("Multiple data paths are not supported yet.")
393
-
394
-
395
- def _persist_domain_part(
396
- domain_part: Dict[str, Any], default: Path, path: Optional[Path]
397
- ) -> None:
398
- domain = Domain.from_dict(domain_part)
399
- if (path is not None) and path.exists():
400
- domain = Domain.from_file(path).merge(domain, override=True)
401
- domain.persist(path)
402
- else:
403
- domain.persist(default)
404
-
405
-
406
- def get_training_path(
407
- path: Path,
408
- data_original: TrainingDataImporter,
409
- mapper: RasaPrimitiveStorageMapper,
410
- ) -> Dict[str, Path]:
411
- nlu_paths = set()
412
- flow_paths = set()
413
- for intent in data_original.get_nlu_data().intents:
414
- for path in mapper.get_file(intent, "intents").get("training", []):
415
- nlu_paths.add(path)
416
- flows = [flow.id for flow in data_original.get_user_flows().underlying_flows]
417
- for flow in flows:
418
- for path in mapper.get_file(flow, "flows").get("training", []):
419
- flow_paths.add(path)
420
-
421
- return {
422
- "nlu_path": _select_path(nlu_paths, "nlu", path, STUDIO_NLU_FILENAME),
423
- "flow_path": _select_path(flow_paths, "flows", path, STUDIO_FLOWS_FILENAME),
424
- }
425
-
426
-
427
- def get_domain_path(
428
- domain_path: Path,
429
- data_from_studio: TrainingDataImporter,
430
- mapper: RasaPrimitiveStorageMapper,
431
- ) -> Dict[str, Path]:
432
- intent_paths = set()
433
- entities_paths = set()
434
- slot_paths = set()
435
- action_paths = set()
436
- response_paths = set()
437
- # nlu-based
438
- for intent in data_from_studio.get_domain().intents:
439
- for path in mapper.get_file(intent, "intents").get("domain", []):
440
- intent_paths.add(path)
441
- for entity in data_from_studio.get_domain().entities:
442
- for path in mapper.get_file(entity, "entities").get("domain", []):
443
- entities_paths.add(path)
444
- # flow-based
445
- slot_list = [slot.name for slot in data_from_studio.get_domain().slots]
446
- for slot in slot_list:
447
- for path in mapper.get_file(slot, "slots").get("domain", []):
448
- slot_paths.add(path)
449
- for action in data_from_studio.get_domain().action_names_or_texts:
450
- for path in mapper.get_file(action, "actions").get("domain", []):
451
- action_paths.add(path)
452
- for response in data_from_studio.get_domain().responses:
453
- for path in mapper.get_file(response, "responses").get("domain", []):
454
- response_paths.add(path)
455
-
456
- return {
457
- "intent_path": _select_path(
458
- intent_paths, "intents", domain_path, STUDIO_DOMAIN_FILENAME
459
- ),
460
- "entities_path": _select_path(
461
- entities_paths, "entities", domain_path, STUDIO_DOMAIN_FILENAME
462
- ),
463
- "slot_path": _select_path(
464
- slot_paths, "slots", domain_path, STUDIO_DOMAIN_FILENAME
465
- ),
466
- "action_path": _select_path(
467
- action_paths, "actions", domain_path, STUDIO_DOMAIN_FILENAME
468
- ),
469
- "response_path": _select_path(
470
- response_paths, "responses", domain_path, STUDIO_DOMAIN_FILENAME
471
- ),
472
- }
473
-
474
-
475
- def _select_path(
476
- paths: Set[Path], primitive_type: str, default_path: Path, default: str
477
- ) -> Path:
478
- if len(paths) == 1:
479
- path = paths.pop()
480
- elif len(paths) > 1:
481
- path = paths.pop()
482
- logger.warning(
483
- f"Saving {primitive_type} to {path}."
484
- f"Please keep Studio related {primitive_type} in a single file."
485
- )
486
- else: # no path in paths
487
- path = default_path / Path(default)
488
- logger.info(f"Saving {primitive_type} to {path}.")
489
- return path