rasa-pro 3.12.18.dev1__py3-none-any.whl → 3.13.0a1.dev1__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.
- rasa/__init__.py +0 -6
- rasa/__main__.py +3 -4
- rasa/api.py +1 -1
- rasa/builder/create_openai_vector_store.py +69 -0
- rasa/builder/llm-helper-schema.json +69 -0
- rasa/builder/prompt_to_bot.py +645 -0
- rasa/builder/scrape_rasa_docs.py +97 -0
- rasa/builder/skill_to_bot_prompt.jinja +158 -0
- rasa/cli/dialogue_understanding_test.py +1 -1
- rasa/cli/e2e_test.py +1 -1
- rasa/cli/evaluate.py +2 -2
- rasa/cli/export.py +3 -3
- rasa/cli/llm_fine_tuning.py +1 -1
- rasa/cli/project_templates/default/config.yml +5 -32
- rasa/cli/project_templates/{calm → default}/e2e_tests/cancelations/user_cancels_during_a_correction.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/cancelations/user_changes_mind_on_a_whim.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/corrections/user_corrects_contact_handle.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/corrections/user_corrects_contact_name.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_adds_contact_to_their_list.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_lists_contacts.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_removes_contact.yml +1 -1
- rasa/cli/project_templates/{calm → default}/e2e_tests/happy_paths/user_removes_contact_from_list.yml +1 -1
- rasa/cli/project_templates/default/endpoints.yml +18 -2
- rasa/cli/project_templates/defaults.py +133 -0
- rasa/cli/run.py +1 -1
- rasa/cli/scaffold.py +2 -3
- rasa/cli/studio/download.py +1 -1
- rasa/cli/studio/link.py +53 -0
- rasa/cli/studio/pull.py +78 -0
- rasa/cli/studio/push.py +78 -0
- rasa/cli/studio/studio.py +12 -0
- rasa/cli/studio/upload.py +5 -3
- rasa/cli/train.py +1 -1
- rasa/cli/utils.py +1 -1
- rasa/cli/x.py +1 -1
- rasa/constants.py +2 -0
- rasa/core/__init__.py +0 -16
- rasa/core/actions/action.py +42 -31
- rasa/core/actions/action_repeat_bot_messages.py +18 -22
- rasa/core/actions/action_run_slot_rejections.py +1 -2
- rasa/core/agent.py +18 -3
- rasa/core/available_endpoints.py +146 -0
- rasa/core/brokers/kafka.py +4 -0
- rasa/core/brokers/pika.py +5 -2
- rasa/core/brokers/sql.py +1 -1
- rasa/core/channels/botframework.py +2 -2
- rasa/core/channels/channel.py +2 -2
- rasa/core/channels/development_inspector.py +1 -1
- rasa/core/channels/facebook.py +1 -4
- rasa/core/channels/hangouts.py +8 -5
- rasa/core/channels/inspector/.eslintrc.cjs +12 -6
- rasa/core/channels/inspector/.prettierrc +5 -0
- rasa/core/channels/inspector/README.md +11 -5
- rasa/core/channels/inspector/dist/assets/{arc-9f75cc3b.js → arc-02053cc1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-7f34db23.js → blockDiagram-38ab4fdb-008b6289.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-948bab2c.js → c4Diagram-3d4e48cf-fb2597be.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-078dada8.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-53b0dd0e.js → classDiagram-70f12bd4-7f847e00.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-fdf789e7.js → classDiagram-v2-f2320105-ba1d689b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-5b4516de.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-87c4ece5.js → createText-2e5e7dd3-dd8e67c4.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-5a8b0749.js → edges-e0da2a9e-10784939.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-66da90e2.js → erDiagram-9861fffd-24947ae6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-10044f05.js → flowDb-956e92f1-a9ced505.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-f338f66a.js → flowDiagram-66a62f08-afda9c7c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-f9613071.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-b13140aa.js → flowchart-elk-definition-4a651766-6ef530b8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-f2b4a55a.js → ganttDiagram-c361ad54-0c7dd39a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-dedc298d.js → gitGraphDiagram-72cf32ee-b57239d6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-4ede11ff.js → graph-9ed57cec.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-65549d37.js → index-3862675e-233090de.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3a23e736.js → index-72184470.js} +123 -123
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-65439671.js → infoDiagram-f8f76790-aa116649.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-56d03d98.js → journeyDiagram-49397b02-e51877cc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-dd48f7f4.js → layout-3ca3798c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-1569ad2c.js → line-26ee10d3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-48bf4935.js → linear-aedded32.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-688504c1.js → mindmap-definition-fc14e90a-d8957261.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-78b6d7e6.js → pieDiagram-8a3498a8-d771f885.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-048b84b3.js → quadrantDiagram-120e2f19-09fdf50c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-dd67f107.js → requirementDiagram-deff3bca-9f0af02e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-8128436e.js → sankeyDiagram-04a897e0-84415b37.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-1a0d1461.js → sequenceDiagram-704730f1-8dec4055.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-46d388ed.js → stateDiagram-587899a1-c5431d07.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-ea42951a.js → stateDiagram-v2-d93cdb3a-274e77d9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-7427ed0c.js → styles-6aaf32cf-e364a1d7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-ff5e5a16.js → styles-9a916d00-0dae36f6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-7b3680cf.js → styles-c10674c1-c4641675.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-f860f2ad.js → svgDrawCommon-08f97a94-831fe9a1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-2eebf0c8.js → timeline-definition-85554ec2-c3304b3a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-5d7f4e96.js → xychartDiagram-e933f94c-da799369.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/package.json +3 -1
- rasa/core/channels/inspector/src/App.tsx +91 -90
- rasa/core/channels/inspector/src/components/Chat.tsx +45 -41
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +40 -40
- rasa/core/channels/inspector/src/components/DialogueInformation.tsx +57 -57
- rasa/core/channels/inspector/src/components/DialogueStack.tsx +36 -27
- rasa/core/channels/inspector/src/components/ExpandIcon.tsx +4 -4
- rasa/core/channels/inspector/src/components/FullscreenButton.tsx +7 -7
- rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +28 -12
- rasa/core/channels/inspector/src/components/NoActiveFlow.tsx +9 -9
- rasa/core/channels/inspector/src/components/RasaLogo.tsx +5 -5
- rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +55 -60
- rasa/core/channels/inspector/src/components/SaraDiagrams.tsx +5 -5
- rasa/core/channels/inspector/src/components/Slots.tsx +22 -22
- rasa/core/channels/inspector/src/components/Welcome.tsx +28 -31
- rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +245 -0
- rasa/core/channels/inspector/src/helpers/audio/microphone-processor.js +12 -0
- rasa/core/channels/inspector/src/helpers/audio/playback-processor.js +36 -0
- rasa/core/channels/inspector/src/helpers/conversation.ts +7 -7
- rasa/core/channels/inspector/src/helpers/formatters.test.ts +181 -181
- rasa/core/channels/inspector/src/helpers/formatters.ts +111 -111
- rasa/core/channels/inspector/src/helpers/utils.ts +78 -61
- rasa/core/channels/inspector/src/main.tsx +8 -8
- rasa/core/channels/inspector/src/theme/Button/Button.ts +8 -8
- rasa/core/channels/inspector/src/theme/Heading/Heading.ts +7 -7
- rasa/core/channels/inspector/src/theme/Input/Input.ts +9 -9
- rasa/core/channels/inspector/src/theme/Link/Link.ts +6 -6
- rasa/core/channels/inspector/src/theme/Modal/Modal.ts +13 -13
- rasa/core/channels/inspector/src/theme/Table/Table.tsx +10 -10
- rasa/core/channels/inspector/src/theme/Tooltip/Tooltip.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/breakpoints.ts +7 -7
- rasa/core/channels/inspector/src/theme/base/colors.ts +64 -64
- rasa/core/channels/inspector/src/theme/base/fonts/fontFaces.css +21 -18
- rasa/core/channels/inspector/src/theme/base/radii.ts +8 -8
- rasa/core/channels/inspector/src/theme/base/shadows.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/sizes.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/space.ts +12 -12
- rasa/core/channels/inspector/src/theme/base/styles.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/typography.ts +12 -12
- rasa/core/channels/inspector/src/theme/base/zIndices.ts +3 -3
- rasa/core/channels/inspector/src/theme/index.ts +38 -38
- rasa/core/channels/inspector/src/types.ts +56 -50
- rasa/core/channels/inspector/yarn.lock +5 -0
- rasa/core/channels/mattermost.py +1 -1
- rasa/core/channels/rasa_chat.py +2 -4
- rasa/core/channels/rest.py +5 -4
- rasa/core/channels/socketio.py +56 -41
- rasa/core/channels/studio_chat.py +337 -71
- rasa/core/channels/vier_cvg.py +1 -2
- rasa/core/channels/voice_ready/audiocodes.py +4 -11
- rasa/core/channels/voice_stream/audiocodes.py +8 -5
- rasa/core/channels/voice_stream/browser_audio.py +1 -1
- rasa/core/channels/voice_stream/genesys.py +2 -2
- rasa/core/channels/voice_stream/tts/__init__.py +8 -0
- rasa/core/channels/voice_stream/twilio_media_streams.py +10 -5
- rasa/core/channels/voice_stream/voice_channel.py +65 -23
- rasa/core/concurrent_lock_store.py +24 -10
- rasa/core/evaluation/marker_tracker_loader.py +1 -1
- rasa/core/exporter.py +1 -1
- rasa/core/http_interpreter.py +3 -7
- rasa/core/information_retrieval/faiss.py +18 -11
- rasa/core/information_retrieval/ingestion/__init__.py +0 -0
- rasa/core/information_retrieval/ingestion/faq_parser.py +158 -0
- rasa/core/jobs.py +2 -1
- rasa/core/lock_store.py +151 -60
- rasa/core/nlg/contextual_response_rephraser.py +17 -7
- rasa/core/nlg/generator.py +5 -22
- rasa/core/nlg/interpolator.py +2 -3
- rasa/core/nlg/response.py +6 -43
- rasa/core/nlg/summarize.py +1 -1
- rasa/core/nlg/translate.py +0 -8
- rasa/core/policies/enterprise_search_policy.py +262 -62
- rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +63 -0
- rasa/core/policies/flow_policy.py +1 -1
- rasa/core/policies/flows/flow_executor.py +96 -17
- rasa/core/policies/intentless_policy.py +57 -20
- rasa/core/processor.py +114 -54
- rasa/core/run.py +33 -11
- rasa/core/tracker_stores/__init__.py +0 -0
- rasa/core/{auth_retry_tracker_store.py → tracker_stores/auth_retry_tracker_store.py} +5 -1
- rasa/core/tracker_stores/dynamo_tracker_store.py +218 -0
- rasa/core/tracker_stores/mongo_tracker_store.py +206 -0
- rasa/core/tracker_stores/redis_tracker_store.py +219 -0
- rasa/core/tracker_stores/sql_tracker_store.py +555 -0
- rasa/core/tracker_stores/tracker_store.py +805 -0
- rasa/core/training/interactive.py +1 -1
- rasa/core/utils.py +24 -95
- rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -1
- rasa/dialogue_understanding/coexistence/llm_based_router.py +10 -6
- rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -0
- rasa/dialogue_understanding/commands/cancel_flow_command.py +5 -1
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -0
- rasa/dialogue_understanding/commands/clarify_command.py +4 -0
- rasa/dialogue_understanding/commands/command_syntax_manager.py +1 -0
- rasa/dialogue_understanding/commands/correct_slots_command.py +1 -3
- rasa/dialogue_understanding/commands/human_handoff_command.py +2 -0
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -0
- rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +2 -0
- rasa/dialogue_understanding/commands/set_slot_command.py +10 -0
- rasa/dialogue_understanding/commands/skip_question_command.py +2 -0
- rasa/dialogue_understanding/commands/start_flow_command.py +4 -0
- rasa/dialogue_understanding/commands/utils.py +26 -2
- rasa/dialogue_understanding/generator/__init__.py +7 -1
- rasa/dialogue_understanding/generator/command_generator.py +4 -2
- rasa/dialogue_understanding/generator/command_parser.py +2 -2
- rasa/dialogue_understanding/generator/command_parser_validator.py +63 -0
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +5 -17
- rasa/dialogue_understanding/generator/llm_command_generator.py +1 -3
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +4 -44
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +2 -2
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +78 -0
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +26 -474
- rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +147 -0
- rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +477 -0
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +11 -64
- rasa/dialogue_understanding/patterns/cancel.py +1 -2
- rasa/dialogue_understanding/patterns/clarify.py +1 -1
- rasa/dialogue_understanding/patterns/correction.py +2 -2
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +37 -25
- rasa/dialogue_understanding/patterns/domain_for_patterns.py +190 -0
- rasa/dialogue_understanding/processor/command_processor.py +6 -7
- rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +17 -4
- rasa/dialogue_understanding/stack/utils.py +3 -1
- rasa/dialogue_understanding/utils.py +68 -12
- rasa/dialogue_understanding_test/command_metric_calculation.py +7 -40
- rasa/dialogue_understanding_test/command_metrics.py +38 -0
- rasa/dialogue_understanding_test/du_test_case.py +58 -25
- rasa/dialogue_understanding_test/du_test_result.py +228 -132
- rasa/dialogue_understanding_test/du_test_runner.py +11 -2
- rasa/dialogue_understanding_test/io.py +35 -8
- rasa/e2e_test/e2e_test_runner.py +1 -1
- rasa/engine/constants.py +1 -1
- rasa/engine/graph.py +2 -2
- rasa/engine/recipes/default_recipe.py +1 -1
- rasa/engine/validation.py +3 -2
- rasa/hooks.py +2 -85
- rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +1 -5
- rasa/llm_fine_tuning/utils.py +2 -4
- rasa/model_manager/model_api.py +90 -2
- rasa/model_manager/socket_bridge.py +0 -7
- rasa/model_manager/trainer_service.py +15 -12
- rasa/plugin.py +2 -15
- rasa/privacy/__init__.py +0 -0
- rasa/privacy/constants.py +83 -0
- rasa/privacy/event_broker_utils.py +77 -0
- rasa/privacy/privacy_config.py +281 -0
- rasa/privacy/privacy_config_schema.json +86 -0
- rasa/privacy/privacy_filter.py +340 -0
- rasa/privacy/privacy_manager.py +576 -0
- rasa/server.py +23 -2
- rasa/shared/constants.py +13 -4
- rasa/shared/core/command_payload_reader.py +1 -5
- rasa/shared/core/constants.py +4 -3
- rasa/shared/core/domain.py +172 -11
- rasa/shared/core/events.py +100 -6
- rasa/shared/core/flows/flow.py +35 -8
- rasa/shared/core/flows/flow_step.py +26 -4
- rasa/shared/core/flows/flow_step_links.py +15 -0
- rasa/shared/core/flows/flow_step_sequence.py +6 -0
- rasa/shared/core/flows/flows_yaml_schema.json +3 -0
- rasa/shared/core/flows/nlu_trigger.py +13 -0
- rasa/shared/core/flows/steps/action.py +7 -4
- rasa/shared/core/flows/steps/call.py +11 -4
- rasa/shared/core/flows/steps/collect.py +71 -6
- rasa/shared/core/flows/steps/internal.py +6 -1
- rasa/shared/core/flows/steps/link.py +7 -4
- rasa/shared/core/flows/steps/no_operation.py +7 -4
- rasa/shared/core/flows/steps/set_slots.py +8 -4
- rasa/shared/core/flows/validation.py +16 -3
- rasa/shared/core/flows/yaml_flows_io.py +106 -5
- rasa/shared/core/slots.py +33 -1
- rasa/shared/core/trackers.py +4 -10
- rasa/shared/core/training_data/story_reader/yaml_story_reader.py +1 -4
- rasa/shared/importers/importer.py +14 -0
- rasa/shared/importers/static.py +63 -0
- rasa/shared/providers/constants.py +0 -9
- rasa/shared/providers/llm/_base_litellm_client.py +4 -14
- rasa/shared/providers/llm/default_litellm_llm_client.py +2 -2
- rasa/shared/providers/llm/litellm_router_llm_client.py +7 -17
- rasa/shared/providers/llm/llm_client.py +15 -24
- rasa/shared/providers/llm/self_hosted_llm_client.py +2 -10
- rasa/shared/utils/common.py +43 -1
- rasa/shared/utils/llm.py +155 -3
- rasa/shared/utils/yaml.py +32 -0
- rasa/studio/data_handler.py +3 -3
- rasa/studio/download/__init__.py +0 -0
- rasa/studio/download/domains.py +49 -0
- rasa/studio/download/download.py +416 -0
- rasa/studio/download/flows.py +351 -0
- rasa/studio/link.py +200 -0
- rasa/studio/pull.py +94 -0
- rasa/studio/push.py +131 -0
- rasa/studio/results_logger.py +6 -1
- rasa/studio/upload.py +185 -71
- rasa/telemetry.py +83 -26
- rasa/tracing/config.py +4 -5
- rasa/tracing/constants.py +19 -1
- rasa/tracing/instrumentation/attribute_extractors.py +49 -11
- rasa/tracing/instrumentation/instrumentation.py +54 -3
- rasa/tracing/instrumentation/metrics.py +98 -15
- rasa/tracing/metric_instrument_provider.py +75 -3
- rasa/utils/common.py +37 -27
- rasa/utils/endpoints.py +22 -1
- rasa/utils/licensing.py +2 -3
- rasa/utils/log_utils.py +1 -45
- rasa/validator.py +9 -11
- rasa/version.py +1 -1
- {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/METADATA +12 -14
- {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/RECORD +318 -294
- rasa/anonymization/__init__.py +0 -2
- rasa/anonymization/anonymisation_rule_yaml_reader.py +0 -91
- rasa/anonymization/anonymization_pipeline.py +0 -286
- rasa/anonymization/anonymization_rule_executor.py +0 -266
- rasa/anonymization/anonymization_rule_orchestrator.py +0 -119
- rasa/anonymization/schemas/config.yml +0 -47
- rasa/anonymization/utils.py +0 -118
- rasa/cli/project_templates/calm/config.yml +0 -10
- rasa/cli/project_templates/calm/credentials.yml +0 -33
- rasa/cli/project_templates/calm/endpoints.yml +0 -58
- rasa/cli/project_templates/default/actions/actions.py +0 -27
- rasa/cli/project_templates/default/data/nlu.yml +0 -91
- rasa/cli/project_templates/default/data/rules.yml +0 -13
- rasa/cli/project_templates/default/data/stories.yml +0 -30
- rasa/cli/project_templates/default/domain.yml +0 -34
- rasa/cli/project_templates/default/tests/test_stories.yml +0 -91
- rasa/core/channels/inspector/dist/assets/channel-dfa68278.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-edb7f119.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-65e7c670.js +0 -1
- rasa/core/channels/inspector/src/helpers/audiostream.ts +0 -191
- rasa/core/tracker_store.py +0 -1792
- rasa/monkey_patches.py +0 -91
- rasa/studio/download.py +0 -489
- /rasa/{cli/project_templates/calm/actions → builder}/__init__.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/action_template.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/add_contact.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/db.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/list_contacts.py +0 -0
- /rasa/cli/project_templates/{calm → default}/actions/remove_contact.py +0 -0
- /rasa/cli/project_templates/{calm → default}/data/flows/add_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/data/flows/list_contacts.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/data/flows/remove_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/db/contacts.json +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/add_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/list_contacts.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/remove_contact.yml +0 -0
- /rasa/cli/project_templates/{calm → default}/domain/shared.yml +0 -0
- {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/NOTICE +0 -0
- {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/WHEEL +0 -0
- {rasa_pro-3.12.18.dev1.dist-info → rasa_pro-3.13.0a1.dev1.dist-info}/entry_points.txt +0 -0
|
@@ -14,7 +14,7 @@ from sanic import ( # type: ignore[attr-defined]
|
|
|
14
14
|
response,
|
|
15
15
|
)
|
|
16
16
|
|
|
17
|
-
from rasa.core.channels import
|
|
17
|
+
from rasa.core.channels import UserMessage
|
|
18
18
|
from rasa.core.channels.channel import (
|
|
19
19
|
create_auth_requested_response_provider,
|
|
20
20
|
requires_basic_auth,
|
|
@@ -102,16 +102,22 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
102
102
|
server_url: str,
|
|
103
103
|
asr_config: Dict,
|
|
104
104
|
tts_config: Dict,
|
|
105
|
-
monitor_silence: bool = False,
|
|
106
105
|
username: Optional[Text] = None,
|
|
107
106
|
password: Optional[Text] = None,
|
|
108
107
|
):
|
|
109
|
-
super().__init__(
|
|
108
|
+
super().__init__(
|
|
109
|
+
server_url=server_url,
|
|
110
|
+
asr_config=asr_config,
|
|
111
|
+
tts_config=tts_config,
|
|
112
|
+
)
|
|
110
113
|
self.username = username
|
|
111
114
|
self.password = password
|
|
112
115
|
|
|
113
116
|
@classmethod
|
|
114
|
-
def from_credentials(
|
|
117
|
+
def from_credentials(
|
|
118
|
+
cls,
|
|
119
|
+
credentials: Optional[Dict[str, Any]],
|
|
120
|
+
) -> VoiceInputChannel:
|
|
115
121
|
credentials = credentials or {}
|
|
116
122
|
|
|
117
123
|
username = credentials.get("username")
|
|
@@ -126,7 +132,6 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
126
132
|
credentials["server_url"],
|
|
127
133
|
credentials["asr"],
|
|
128
134
|
credentials["tts"],
|
|
129
|
-
credentials.get("monitor_silence", False),
|
|
130
135
|
username=username,
|
|
131
136
|
password=password,
|
|
132
137
|
)
|
|
@@ -31,8 +31,10 @@ from rasa.core.channels.voice_stream.tts.azure import AzureTTS
|
|
|
31
31
|
from rasa.core.channels.voice_stream.tts.cartesia import CartesiaTTS
|
|
32
32
|
from rasa.core.channels.voice_stream.tts.tts_cache import TTSCache
|
|
33
33
|
from rasa.core.channels.voice_stream.tts.tts_engine import TTSEngine, TTSError
|
|
34
|
-
from rasa.core.channels.voice_stream.util import
|
|
35
|
-
|
|
34
|
+
from rasa.core.channels.voice_stream.util import (
|
|
35
|
+
generate_silence,
|
|
36
|
+
)
|
|
37
|
+
from rasa.shared.core.constants import SILENCE_TIMEOUT_SLOT
|
|
36
38
|
from rasa.shared.utils.cli import print_error_and_exit
|
|
37
39
|
from rasa.shared.utils.common import (
|
|
38
40
|
class_from_module_path,
|
|
@@ -42,6 +44,11 @@ from rasa.utils.io import remove_emojis
|
|
|
42
44
|
|
|
43
45
|
logger = structlog.get_logger(__name__)
|
|
44
46
|
|
|
47
|
+
# define constants for the voice channel
|
|
48
|
+
USER_CONVERSATION_SESSION_END = "/session_end"
|
|
49
|
+
USER_CONVERSATION_SESSION_START = "/session_start"
|
|
50
|
+
USER_CONVERSATION_SILENCE_TIMEOUT = "/silence_timeout"
|
|
51
|
+
|
|
45
52
|
|
|
46
53
|
@dataclass
|
|
47
54
|
class VoiceChannelAction:
|
|
@@ -166,8 +173,12 @@ class VoiceOutputChannel(OutputChannel):
|
|
|
166
173
|
def update_silence_timeout(self) -> None:
|
|
167
174
|
"""Updates the silence timeout for the session."""
|
|
168
175
|
if self.tracker_state:
|
|
169
|
-
call_state.silence_timeout =
|
|
170
|
-
|
|
176
|
+
call_state.silence_timeout = self.tracker_state["slots"][ # type: ignore[attr-defined]
|
|
177
|
+
SILENCE_TIMEOUT_SLOT
|
|
178
|
+
]
|
|
179
|
+
logger.debug(
|
|
180
|
+
"voice_channel.silence_timeout_updated",
|
|
181
|
+
silence_timeout=call_state.silence_timeout,
|
|
171
182
|
)
|
|
172
183
|
|
|
173
184
|
async def send_text_with_buttons(
|
|
@@ -189,6 +200,7 @@ class VoiceOutputChannel(OutputChannel):
|
|
|
189
200
|
collected_audio_bytes = RasaAudioBytes(b"")
|
|
190
201
|
seconds_marker = -1
|
|
191
202
|
last_sent_offset = 0
|
|
203
|
+
logger.debug("voice_channel.sending_audio", text=text)
|
|
192
204
|
|
|
193
205
|
# Send start marker before first chunk
|
|
194
206
|
try:
|
|
@@ -274,26 +286,34 @@ class VoiceOutputChannel(OutputChannel):
|
|
|
274
286
|
|
|
275
287
|
|
|
276
288
|
class VoiceInputChannel(InputChannel):
|
|
289
|
+
# All children of this class require a voice license to be used.
|
|
290
|
+
requires_voice_license = True
|
|
291
|
+
|
|
277
292
|
def __init__(
|
|
278
293
|
self,
|
|
279
294
|
server_url: str,
|
|
280
295
|
asr_config: Dict,
|
|
281
296
|
tts_config: Dict,
|
|
282
|
-
monitor_silence: bool = False,
|
|
283
297
|
):
|
|
284
|
-
|
|
298
|
+
if self.requires_voice_license:
|
|
299
|
+
validate_voice_license_scope()
|
|
300
|
+
|
|
285
301
|
self.server_url = server_url
|
|
286
302
|
self.asr_config = asr_config
|
|
287
303
|
self.tts_config = tts_config
|
|
288
|
-
self.monitor_silence = monitor_silence
|
|
289
304
|
self.tts_cache = TTSCache(tts_config.get("cache_size", 1000))
|
|
290
305
|
|
|
306
|
+
logger.info(
|
|
307
|
+
"voice_channel.initialized",
|
|
308
|
+
server_url=self.server_url,
|
|
309
|
+
asr_config=self.asr_config,
|
|
310
|
+
tts_config=self.tts_config,
|
|
311
|
+
)
|
|
312
|
+
|
|
291
313
|
async def monitor_silence_timeout(self, asr_event_queue: asyncio.Queue) -> None:
|
|
292
314
|
timeout = call_state.silence_timeout
|
|
293
315
|
if not timeout:
|
|
294
316
|
return
|
|
295
|
-
if not self.monitor_silence:
|
|
296
|
-
return
|
|
297
317
|
logger.debug("voice_channel.silence_timeout_watch_started", timeout=timeout)
|
|
298
318
|
await asyncio.sleep(timeout)
|
|
299
319
|
await asr_event_queue.put(UserSilence())
|
|
@@ -308,13 +328,15 @@ class VoiceInputChannel(InputChannel):
|
|
|
308
328
|
call_state.silence_timeout_watcher = None # type: ignore[attr-defined]
|
|
309
329
|
|
|
310
330
|
@classmethod
|
|
311
|
-
def from_credentials(
|
|
331
|
+
def from_credentials(
|
|
332
|
+
cls,
|
|
333
|
+
credentials: Optional[Dict[str, Any]],
|
|
334
|
+
) -> InputChannel:
|
|
312
335
|
credentials = credentials or {}
|
|
313
336
|
return cls(
|
|
314
337
|
credentials["server_url"],
|
|
315
338
|
credentials["asr"],
|
|
316
339
|
credentials["tts"],
|
|
317
|
-
credentials.get("monitor_silence", False),
|
|
318
340
|
)
|
|
319
341
|
|
|
320
342
|
def channel_bytes_to_rasa_audio_bytes(self, input_bytes: bytes) -> RasaAudioBytes:
|
|
@@ -334,9 +356,9 @@ class VoiceInputChannel(InputChannel):
|
|
|
334
356
|
) -> None:
|
|
335
357
|
output_channel = self.create_output_channel(channel_websocket, tts_engine)
|
|
336
358
|
message = UserMessage(
|
|
337
|
-
|
|
338
|
-
output_channel,
|
|
339
|
-
call_parameters.stream_id,
|
|
359
|
+
text=USER_CONVERSATION_SESSION_START,
|
|
360
|
+
output_channel=output_channel,
|
|
361
|
+
sender_id=call_parameters.stream_id,
|
|
340
362
|
input_channel=self.name(),
|
|
341
363
|
metadata=asdict(call_parameters),
|
|
342
364
|
)
|
|
@@ -371,17 +393,17 @@ class VoiceInputChannel(InputChannel):
|
|
|
371
393
|
|
|
372
394
|
async def consume_audio_bytes() -> None:
|
|
373
395
|
async for message in channel_websocket:
|
|
374
|
-
|
|
396
|
+
was_bot_speaking_before = call_state.is_bot_speaking
|
|
375
397
|
channel_action = self.map_input_message(message, channel_websocket)
|
|
376
398
|
is_bot_speaking_after = call_state.is_bot_speaking
|
|
377
399
|
|
|
378
|
-
if not
|
|
400
|
+
if not was_bot_speaking_before and is_bot_speaking_after:
|
|
379
401
|
logger.debug("voice_channel.bot_started_speaking")
|
|
380
402
|
# relevant when the bot speaks multiple messages in one turn
|
|
381
403
|
self._cancel_silence_timeout_watcher()
|
|
382
404
|
|
|
383
405
|
# we just stopped speaking, starting a watcher for silence timeout
|
|
384
|
-
if
|
|
406
|
+
if was_bot_speaking_before and not is_bot_speaking_after:
|
|
385
407
|
logger.debug("voice_channel.bot_stopped_speaking")
|
|
386
408
|
self._cancel_silence_timeout_watcher()
|
|
387
409
|
call_state.silence_timeout_watcher = ( # type: ignore[attr-defined]
|
|
@@ -393,6 +415,9 @@ class VoiceInputChannel(InputChannel):
|
|
|
393
415
|
await asr_engine.send_audio_chunks(channel_action.audio_bytes)
|
|
394
416
|
elif isinstance(channel_action, EndConversationAction):
|
|
395
417
|
# end stream event came from the other side
|
|
418
|
+
await self.handle_disconnect(
|
|
419
|
+
channel_websocket, on_new_message, tts_engine, call_parameters
|
|
420
|
+
)
|
|
396
421
|
break
|
|
397
422
|
|
|
398
423
|
async def receive_asr_events() -> None:
|
|
@@ -449,9 +474,9 @@ class VoiceInputChannel(InputChannel):
|
|
|
449
474
|
call_state.is_user_speaking = False # type: ignore[attr-defined]
|
|
450
475
|
output_channel = self.create_output_channel(voice_websocket, tts_engine)
|
|
451
476
|
message = UserMessage(
|
|
452
|
-
e.text,
|
|
453
|
-
output_channel,
|
|
454
|
-
call_parameters.stream_id,
|
|
477
|
+
text=e.text,
|
|
478
|
+
output_channel=output_channel,
|
|
479
|
+
sender_id=call_parameters.stream_id,
|
|
455
480
|
input_channel=self.name(),
|
|
456
481
|
metadata=asdict(call_parameters),
|
|
457
482
|
)
|
|
@@ -462,10 +487,27 @@ class VoiceInputChannel(InputChannel):
|
|
|
462
487
|
elif isinstance(e, UserSilence):
|
|
463
488
|
output_channel = self.create_output_channel(voice_websocket, tts_engine)
|
|
464
489
|
message = UserMessage(
|
|
465
|
-
|
|
466
|
-
output_channel,
|
|
467
|
-
call_parameters.stream_id,
|
|
490
|
+
text=USER_CONVERSATION_SILENCE_TIMEOUT,
|
|
491
|
+
output_channel=output_channel,
|
|
492
|
+
sender_id=call_parameters.stream_id,
|
|
468
493
|
input_channel=self.name(),
|
|
469
494
|
metadata=asdict(call_parameters),
|
|
470
495
|
)
|
|
471
496
|
await on_new_message(message)
|
|
497
|
+
|
|
498
|
+
async def handle_disconnect(
|
|
499
|
+
self,
|
|
500
|
+
channel_websocket: Websocket,
|
|
501
|
+
on_new_message: Callable[[UserMessage], Awaitable[Any]],
|
|
502
|
+
tts_engine: TTSEngine,
|
|
503
|
+
call_parameters: CallParameters,
|
|
504
|
+
) -> None:
|
|
505
|
+
"""Handle disconnection from the channel."""
|
|
506
|
+
output_channel = self.create_output_channel(channel_websocket, tts_engine)
|
|
507
|
+
message = UserMessage(
|
|
508
|
+
text=USER_CONVERSATION_SESSION_END,
|
|
509
|
+
output_channel=output_channel,
|
|
510
|
+
sender_id=call_parameters.stream_id,
|
|
511
|
+
input_channel=self.name(),
|
|
512
|
+
)
|
|
513
|
+
await on_new_message(message)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import json
|
|
2
|
-
import logging
|
|
3
2
|
import time
|
|
4
3
|
from collections import deque
|
|
5
4
|
from typing import Deque, Optional, Text
|
|
6
5
|
|
|
6
|
+
import structlog
|
|
7
|
+
|
|
7
8
|
from rasa.core.lock import Ticket, TicketLock
|
|
8
9
|
from rasa.core.lock_store import (
|
|
9
10
|
DEFAULT_SOCKET_TIMEOUT_IN_SECONDS,
|
|
@@ -19,7 +20,7 @@ DEFAULT_PORT = 6379
|
|
|
19
20
|
|
|
20
21
|
DEFAULT_HOSTNAME = "localhost"
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
structlogger = structlog.getLogger(__name__)
|
|
23
24
|
|
|
24
25
|
LAST_ISSUED_TICKET_NUMBER_SUFFIX = "last_issued_ticket_number"
|
|
25
26
|
|
|
@@ -105,7 +106,10 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
105
106
|
|
|
106
107
|
self.key_prefix = DEFAULT_CONCURRENT_REDIS_LOCK_STORE_KEY_PREFIX
|
|
107
108
|
if key_prefix:
|
|
108
|
-
|
|
109
|
+
structlogger.debug(
|
|
110
|
+
"concurrent_redis_lock_store._set_key_prefix.non_default_key_prefix",
|
|
111
|
+
event_info=f"Setting non-default redis key prefix: '{key_prefix}'.",
|
|
112
|
+
)
|
|
109
113
|
self._set_key_prefix(key_prefix)
|
|
110
114
|
|
|
111
115
|
super().__init__()
|
|
@@ -116,9 +120,13 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
116
120
|
key_prefix + ":" + DEFAULT_CONCURRENT_REDIS_LOCK_STORE_KEY_PREFIX
|
|
117
121
|
)
|
|
118
122
|
else:
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
123
|
+
structlogger.warning(
|
|
124
|
+
"concurrent_redis_lock_store._set_key_prefix.default_instead_of_invalid_key_prefix",
|
|
125
|
+
event_info=(
|
|
126
|
+
f"Omitting provided non-alphanumeric "
|
|
127
|
+
f"redis key prefix: '{key_prefix}'. "
|
|
128
|
+
f"Using default '{self.key_prefix}' instead."
|
|
129
|
+
),
|
|
122
130
|
)
|
|
123
131
|
|
|
124
132
|
def issue_ticket(
|
|
@@ -129,7 +137,10 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
129
137
|
It's configured with `lock_lifetime` and associated with `conversation_id`.
|
|
130
138
|
Creates a new lock if none is found.
|
|
131
139
|
"""
|
|
132
|
-
|
|
140
|
+
structlogger.debug(
|
|
141
|
+
"concurrent_redis_lock_store.issue_ticket",
|
|
142
|
+
event_info=f"Issuing ticket for conversation '{conversation_id}'.",
|
|
143
|
+
)
|
|
133
144
|
try:
|
|
134
145
|
lock = self.get_or_create_lock(conversation_id)
|
|
135
146
|
lock.remove_expired_tickets()
|
|
@@ -164,9 +175,12 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
164
175
|
redis_keys = self.red.keys(pattern)
|
|
165
176
|
|
|
166
177
|
if not redis_keys:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
178
|
+
structlogger.debug(
|
|
179
|
+
"concurrent_redis_lock_store.delete_lock_key_not_found",
|
|
180
|
+
event_info=(
|
|
181
|
+
f"The lock store does not contain any key-value "
|
|
182
|
+
f"items for conversation '{conversation_id}'."
|
|
183
|
+
),
|
|
170
184
|
)
|
|
171
185
|
return None
|
|
172
186
|
|
|
@@ -2,7 +2,7 @@ import random
|
|
|
2
2
|
from typing import Any, AsyncIterator, Iterable, List, Optional, Text
|
|
3
3
|
|
|
4
4
|
import rasa.shared.utils.io
|
|
5
|
-
from rasa.core.tracker_store import TrackerStore
|
|
5
|
+
from rasa.core.tracker_stores.tracker_store import TrackerStore
|
|
6
6
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
7
7
|
from rasa.shared.exceptions import RasaException
|
|
8
8
|
|
rasa/core/exporter.py
CHANGED
|
@@ -10,7 +10,7 @@ import rasa.shared.utils.io
|
|
|
10
10
|
from rasa.core.brokers.broker import EventBroker
|
|
11
11
|
from rasa.core.brokers.pika import PikaEventBroker
|
|
12
12
|
from rasa.core.constants import RASA_EXPORT_PROCESS_ID_HEADER_NAME
|
|
13
|
-
from rasa.core.tracker_store import TrackerStore
|
|
13
|
+
from rasa.core.tracker_stores.tracker_store import TrackerStore
|
|
14
14
|
from rasa.exceptions import (
|
|
15
15
|
NoConversationsInTrackerStoreError,
|
|
16
16
|
NoEventsToMigrateError,
|
rasa/core/http_interpreter.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import copy
|
|
2
1
|
import logging
|
|
3
2
|
from typing import Any, Dict, Optional, Text
|
|
4
3
|
|
|
@@ -49,7 +48,6 @@ class RasaNLUHttpInterpreter:
|
|
|
49
48
|
if not self.endpoint_config or self.endpoint_config.url is None:
|
|
50
49
|
structlogger.error(
|
|
51
50
|
"http.parse.text",
|
|
52
|
-
text=copy.deepcopy(text),
|
|
53
51
|
event_info="No rasa NLU server specified!",
|
|
54
52
|
)
|
|
55
53
|
return None
|
|
@@ -71,18 +69,16 @@ class RasaNLUHttpInterpreter:
|
|
|
71
69
|
if resp.status == 200:
|
|
72
70
|
return await resp.json()
|
|
73
71
|
else:
|
|
74
|
-
response_text = await resp.text()
|
|
75
72
|
structlogger.error(
|
|
76
73
|
"http.parse.text.failure",
|
|
77
|
-
|
|
78
|
-
response_text=copy.deepcopy(response_text),
|
|
74
|
+
event_info="Failed to parse text",
|
|
79
75
|
)
|
|
80
76
|
return None
|
|
81
|
-
except Exception: # skipcq: PYL-W0703
|
|
77
|
+
except Exception as e: # skipcq: PYL-W0703
|
|
82
78
|
# need to catch all possible exceptions when doing http requests
|
|
83
79
|
# (timeouts, value errors, parser errors, ...)
|
|
84
80
|
structlogger.exception(
|
|
85
81
|
"http.parse.text.exception",
|
|
86
|
-
text
|
|
82
|
+
event_info=f"Exception occurred while parsing text. Error: {e}",
|
|
87
83
|
)
|
|
88
84
|
return None
|
|
@@ -12,6 +12,7 @@ from rasa.core.information_retrieval import (
|
|
|
12
12
|
InformationRetrievalException,
|
|
13
13
|
SearchResultList,
|
|
14
14
|
)
|
|
15
|
+
from rasa.core.information_retrieval.ingestion.faq_parser import _format_faq_documents
|
|
15
16
|
from rasa.utils.endpoints import EndpointConfig
|
|
16
17
|
from rasa.utils.ml_utils import persist_faiss_vector_store
|
|
17
18
|
|
|
@@ -31,10 +32,12 @@ class FAISS_Store(InformationRetrieval):
|
|
|
31
32
|
index_path: str,
|
|
32
33
|
docs_folder: Optional[str],
|
|
33
34
|
create_index: Optional[bool] = False,
|
|
35
|
+
parse_as_faq_pairs: Optional[bool] = False,
|
|
34
36
|
):
|
|
35
37
|
"""Initializes the FAISS Store."""
|
|
36
38
|
self.chunk_size = 1000
|
|
37
39
|
self.chunk_overlap = 20
|
|
40
|
+
self.parse_as_faq_pairs = parse_as_faq_pairs
|
|
38
41
|
|
|
39
42
|
path = Path(index_path) / "documents_faiss"
|
|
40
43
|
if create_index:
|
|
@@ -86,21 +89,25 @@ class FAISS_Store(InformationRetrieval):
|
|
|
86
89
|
if not docs_folder:
|
|
87
90
|
raise ValueError("parameter `docs_folder` needs to be specified")
|
|
88
91
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
documents = self.load_documents(docs_folder)
|
|
93
|
+
|
|
94
|
+
if not self.parse_as_faq_pairs:
|
|
95
|
+
splitter = RecursiveCharacterTextSplitter(
|
|
96
|
+
chunk_size=self.chunk_size,
|
|
97
|
+
chunk_overlap=self.chunk_overlap,
|
|
98
|
+
length_function=len,
|
|
99
|
+
)
|
|
100
|
+
parsed_documents = splitter.split_documents(documents)
|
|
101
|
+
else:
|
|
102
|
+
parsed_documents = _format_faq_documents(documents)
|
|
96
103
|
|
|
97
104
|
logger.info(
|
|
98
105
|
"information_retrieval.faiss_store._create_document_index",
|
|
99
|
-
len_chunks=len(
|
|
106
|
+
len_chunks=len(parsed_documents),
|
|
100
107
|
)
|
|
101
|
-
if
|
|
102
|
-
texts = [
|
|
103
|
-
metadatas = [
|
|
108
|
+
if parsed_documents:
|
|
109
|
+
texts = [document.page_content for document in parsed_documents]
|
|
110
|
+
metadatas = [document.metadata for document in parsed_documents]
|
|
104
111
|
return FAISS.from_texts(texts, embedding, metadatas=metadatas, ids=None)
|
|
105
112
|
else:
|
|
106
113
|
raise ValueError(f"No documents found at '{docs_folder}'.")
|
|
File without changes
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""Utilities for parsing FAQ-style documents (Q/A pairs) used in extractive search."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from collections import defaultdict
|
|
5
|
+
from typing import TYPE_CHECKING, List
|
|
6
|
+
|
|
7
|
+
import structlog
|
|
8
|
+
|
|
9
|
+
from rasa.shared.constants import (
|
|
10
|
+
DOCUMENT_TYPE_FAQ,
|
|
11
|
+
FAQ_DOCUMENT_ENTRY_SEPARATOR,
|
|
12
|
+
FAQ_DOCUMENT_LINE_SEPARATOR,
|
|
13
|
+
FAQ_DOCUMENT_METADATA_ANSWER,
|
|
14
|
+
FAQ_DOCUMENT_METADATA_TITLE,
|
|
15
|
+
FAQ_DOCUMENT_METADATA_TYPE,
|
|
16
|
+
FAQ_INPUT_DATA_ANSWER_LINE_PREFIX,
|
|
17
|
+
FAQ_INPUT_DATA_QUESTION_LINE_PREFIX,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from langchain.schema import Document
|
|
22
|
+
|
|
23
|
+
_FAQ_PAIR_PATTERN = re.compile(
|
|
24
|
+
rf"{re.escape(FAQ_INPUT_DATA_QUESTION_LINE_PREFIX)}\s*"
|
|
25
|
+
rf"(?P<question>.*?)\s*{FAQ_DOCUMENT_LINE_SEPARATOR}\s*"
|
|
26
|
+
rf"{re.escape(FAQ_INPUT_DATA_ANSWER_LINE_PREFIX)}\s*"
|
|
27
|
+
rf"(?P<answer>.*)",
|
|
28
|
+
re.DOTALL,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
structlogger = structlog.get_logger()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _format_faq_documents(documents: List["Document"]) -> List["Document"]:
|
|
36
|
+
"""Splits each loaded file into individual FAQs.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
documents: Documents representing whole files containing FAQs.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
List of Document objects, each containing a separate FAQ.
|
|
43
|
+
|
|
44
|
+
Examples:
|
|
45
|
+
An example of a file containing FAQs:
|
|
46
|
+
|
|
47
|
+
Q: Who is Finley?
|
|
48
|
+
A: Finley is your smart assistant for the FinX App. You can add him to your
|
|
49
|
+
favorite messenger and tell him what you need help with.
|
|
50
|
+
|
|
51
|
+
Q: How does Finley work?
|
|
52
|
+
A: Finley is powered by the latest chatbot technology leveraging a unique
|
|
53
|
+
interplay of large language models and secure logic.
|
|
54
|
+
|
|
55
|
+
More details in documentation: https://rasa.com/docs/reference/config/policies/extractive-search/
|
|
56
|
+
"""
|
|
57
|
+
structured_faqs = []
|
|
58
|
+
from langchain.schema import Document
|
|
59
|
+
|
|
60
|
+
for document in documents:
|
|
61
|
+
chunks = document.page_content.strip().split(FAQ_DOCUMENT_ENTRY_SEPARATOR)
|
|
62
|
+
|
|
63
|
+
for chunk in chunks:
|
|
64
|
+
match = _FAQ_PAIR_PATTERN.match(chunk.strip())
|
|
65
|
+
|
|
66
|
+
if not match:
|
|
67
|
+
structlogger.warning(
|
|
68
|
+
"faq_parser.format_faq_documents.invalid_chunk_skipped",
|
|
69
|
+
event_info=(
|
|
70
|
+
"Chunk does not match expected QA format. "
|
|
71
|
+
"Please refer to the documentation: "
|
|
72
|
+
"https://rasa.com/docs/reference/config/"
|
|
73
|
+
"policies/extractive-search/"
|
|
74
|
+
),
|
|
75
|
+
chunk_preview=chunk[:100],
|
|
76
|
+
)
|
|
77
|
+
continue
|
|
78
|
+
|
|
79
|
+
question = match.group("question").strip()
|
|
80
|
+
answer = match.group("answer").strip()
|
|
81
|
+
title = _sanitize_title(question)
|
|
82
|
+
|
|
83
|
+
formatted_document = Document(
|
|
84
|
+
page_content=question,
|
|
85
|
+
metadata={
|
|
86
|
+
FAQ_DOCUMENT_METADATA_TITLE: title,
|
|
87
|
+
FAQ_DOCUMENT_METADATA_TYPE: DOCUMENT_TYPE_FAQ,
|
|
88
|
+
FAQ_DOCUMENT_METADATA_ANSWER: answer,
|
|
89
|
+
},
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
structured_faqs.append(formatted_document)
|
|
93
|
+
|
|
94
|
+
structlogger.debug(
|
|
95
|
+
"faq_parser.format_faq_documents.parsed_chunk",
|
|
96
|
+
event_info="Parsed chunk.",
|
|
97
|
+
title=title,
|
|
98
|
+
question=question,
|
|
99
|
+
answer=answer,
|
|
100
|
+
parsed_chunk_preview=chunk[:100],
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
structlogger.debug(
|
|
104
|
+
"faq_parser.format_faq_documents.parsed_chunks",
|
|
105
|
+
event_info=(
|
|
106
|
+
f"Retrieved {len(structured_faqs)} FAQ pair(s)"
|
|
107
|
+
f"from {len(documents)} document(s)."
|
|
108
|
+
),
|
|
109
|
+
num_structured_faqs=len(structured_faqs),
|
|
110
|
+
num_documents=len(documents),
|
|
111
|
+
)
|
|
112
|
+
_check_and_parsed_faq_documents_for_duplicates(structured_faqs)
|
|
113
|
+
return structured_faqs
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _sanitize_title(title: str) -> str:
|
|
117
|
+
title = title.lower()
|
|
118
|
+
# Remove all whitespaces with "_"
|
|
119
|
+
title = re.sub(r"\s+", "_", title)
|
|
120
|
+
# Remove all non alpha-numeric characters
|
|
121
|
+
title = re.sub(r"[^\w]", "", title)
|
|
122
|
+
# Collapse multiple "_"
|
|
123
|
+
title = re.sub(r"_+", "_", title)
|
|
124
|
+
# Clean up edges
|
|
125
|
+
return title.strip("_")
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _check_and_parsed_faq_documents_for_duplicates(documents: List["Document"]) -> None:
|
|
129
|
+
seen_qa_pairs = set()
|
|
130
|
+
seen_questions: defaultdict = defaultdict(list)
|
|
131
|
+
|
|
132
|
+
for doc in documents:
|
|
133
|
+
question = doc.page_content.strip()
|
|
134
|
+
answer = doc.metadata.get(FAQ_DOCUMENT_METADATA_ANSWER, "").strip()
|
|
135
|
+
|
|
136
|
+
if not question or not answer:
|
|
137
|
+
continue
|
|
138
|
+
|
|
139
|
+
if (question, answer) in seen_qa_pairs:
|
|
140
|
+
structlogger.warning(
|
|
141
|
+
"faq_parser.duplicate_qa_pair_found",
|
|
142
|
+
event_info="Duplicate QA pair found.",
|
|
143
|
+
question=question,
|
|
144
|
+
answer_preview=answer,
|
|
145
|
+
)
|
|
146
|
+
continue
|
|
147
|
+
|
|
148
|
+
if question in seen_questions and seen_questions[question] != answer:
|
|
149
|
+
structlogger.warning(
|
|
150
|
+
"faq_parser.inconsistent_answer",
|
|
151
|
+
event_info="Duplicate question with different answer found.",
|
|
152
|
+
question=question,
|
|
153
|
+
previous_answers=seen_questions[question],
|
|
154
|
+
new_answer=answer,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
seen_qa_pairs.add((question, answer))
|
|
158
|
+
seen_questions[question].append(answer)
|
rasa/core/jobs.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import logging
|
|
3
|
+
from typing import Optional
|
|
3
4
|
|
|
4
5
|
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
|
5
6
|
from pytz import UnknownTimeZoneError, utc
|
|
6
7
|
|
|
7
8
|
import rasa.shared.utils.io
|
|
8
9
|
|
|
9
|
-
__scheduler = None
|
|
10
|
+
__scheduler: Optional[AsyncIOScheduler] = None
|
|
10
11
|
|
|
11
12
|
logger = logging.getLogger(__name__)
|
|
12
13
|
|