rasa-pro 3.13.1a18__py3-none-any.whl → 3.13.1a20__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/__main__.py +8 -0
- rasa/builder/auth.py +71 -0
- rasa/builder/config.py +16 -0
- rasa/builder/copilot/constants.py +15 -0
- rasa/builder/copilot/copilot.py +342 -0
- rasa/builder/copilot/copilot_response_handler.py +471 -0
- rasa/builder/copilot/exceptions.py +20 -0
- rasa/builder/copilot/models.py +344 -0
- rasa/builder/copilot/prompts/copilot_system_prompt.jinja2 +495 -0
- rasa/builder/copilot/telemetry.py +195 -0
- rasa/builder/document_retrieval/__init__.py +0 -0
- rasa/builder/document_retrieval/constants.py +16 -0
- rasa/builder/{inkeep_document_retrieval.py → document_retrieval/inkeep_document_retrieval.py} +53 -44
- rasa/builder/document_retrieval/models.py +62 -0
- rasa/builder/download.py +140 -0
- rasa/builder/guardrails/__init__.py +1 -0
- rasa/builder/guardrails/constants.py +4 -0
- rasa/builder/guardrails/exceptions.py +4 -0
- rasa/builder/guardrails/lakera.py +188 -0
- rasa/builder/guardrails/models.py +199 -0
- rasa/builder/guardrails/utils.py +305 -0
- rasa/builder/job_manager.py +87 -0
- rasa/builder/jobs.py +232 -0
- rasa/builder/llm_service.py +89 -173
- rasa/builder/logging_utils.py +162 -4
- rasa/builder/main.py +29 -16
- rasa/builder/models.py +93 -121
- rasa/builder/project_generator.py +91 -7
- rasa/builder/scrape_rasa_docs.py +1 -1
- rasa/builder/service.py +650 -452
- rasa/builder/shared/tracker_context.py +212 -0
- rasa/builder/validation_service.py +4 -4
- rasa/cli/data.py +8 -3
- rasa/cli/project_templates/basic/actions/action_api.py +15 -0
- rasa/cli/project_templates/basic/actions/action_human_handoff.py +44 -0
- rasa/cli/project_templates/basic/config.yml +23 -0
- rasa/cli/project_templates/{plain → basic}/credentials.yml +8 -7
- rasa/cli/project_templates/basic/data/general/feedback.yml +20 -0
- rasa/cli/project_templates/basic/data/general/goodbye.yml +6 -0
- rasa/cli/project_templates/basic/data/general/hello.yml +7 -0
- rasa/cli/project_templates/basic/data/general/help.yml +6 -0
- rasa/cli/project_templates/basic/data/general/human_handoff.yml +16 -0
- rasa/cli/project_templates/basic/data/general/welcome.yml +9 -0
- rasa/cli/project_templates/{finance/data/patterns → basic/data/system}/pattern_completed.yml +2 -1
- rasa/cli/project_templates/basic/data/system/pattern_correction.yml +7 -0
- rasa/cli/project_templates/basic/data/system/pattern_search.yml +8 -0
- rasa/cli/project_templates/basic/data/system/pattern_session_start.yml +8 -0
- rasa/cli/project_templates/basic/docs/rasa_assistant_qa.txt +65 -0
- rasa/cli/project_templates/basic/docs/template.txt +7 -0
- rasa/cli/project_templates/basic/domain/general/assistant_details.yml +12 -0
- rasa/cli/project_templates/basic/domain/general/bot_identity.yml +5 -0
- rasa/cli/project_templates/basic/domain/general/cannot_handle.yml +5 -0
- rasa/cli/project_templates/basic/domain/general/feedback.yml +28 -0
- rasa/cli/project_templates/basic/domain/general/goodbye.yml +7 -0
- rasa/cli/project_templates/basic/domain/general/help.yml +5 -0
- rasa/cli/project_templates/basic/domain/general/human_handoff_domain.yml +35 -0
- rasa/cli/project_templates/{finance/domain/default_actions.yml → basic/domain/general/utils.yml} +0 -3
- rasa/cli/project_templates/basic/domain/general/welcome.yml +7 -0
- rasa/cli/project_templates/{plain → basic}/endpoints.yml +42 -27
- rasa/cli/project_templates/basic/prompts/rephraser_demo_personality_prompt.jinja2 +19 -0
- rasa/cli/project_templates/defaults.py +25 -3
- rasa/cli/project_templates/finance/actions/__init__.py +46 -0
- rasa/cli/project_templates/finance/actions/accounts/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/{action_ask_account.py → accounts/action_ask_account.py} +6 -9
- rasa/cli/project_templates/finance/actions/{action_check_balance.py → accounts/action_check_balance.py} +4 -4
- rasa/cli/project_templates/finance/actions/action_session_start.py +11 -6
- rasa/cli/project_templates/finance/actions/cards/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/{action_ask_card.py → cards/action_ask_card.py} +4 -3
- rasa/cli/project_templates/finance/actions/{action_check_card_existence.py → cards/action_check_card_existence.py} +4 -3
- rasa/cli/project_templates/finance/actions/{action_update_card_status.py → cards/action_update_card_status.py} +18 -9
- rasa/cli/project_templates/finance/actions/database.py +1 -0
- rasa/cli/project_templates/finance/actions/transfers/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/{action_add_payee.py → transfers/action_add_payee.py} +8 -3
- rasa/cli/project_templates/finance/actions/{action_ask_account_from.py → transfers/action_ask_account_from.py} +5 -4
- rasa/cli/project_templates/finance/actions/{action_check_payee_existence.py → transfers/action_check_payee_existence.py} +3 -3
- rasa/cli/project_templates/finance/actions/{action_check_sufficient_funds.py → transfers/action_check_sufficient_funds.py} +3 -4
- rasa/cli/project_templates/finance/actions/{action_list_payees.py → transfers/action_list_payees.py} +4 -3
- rasa/cli/project_templates/finance/actions/{action_remove_payee.py → transfers/action_remove_payee.py} +4 -4
- rasa/cli/project_templates/finance/config.yml +8 -19
- rasa/cli/project_templates/finance/credentials.yml +6 -7
- rasa/cli/project_templates/finance/csvs/cards.csv +10 -10
- rasa/cli/project_templates/finance/csvs/payees.csv +10 -9
- rasa/cli/project_templates/finance/data/{flows → accounts}/check_balance.yml +2 -1
- rasa/cli/project_templates/finance/data/general/bot_identity.yml +6 -0
- rasa/cli/project_templates/finance/data/general/feedback.yml +20 -0
- rasa/cli/project_templates/finance/data/general/goodbye.yml +6 -0
- rasa/cli/project_templates/finance/data/general/hello.yml +7 -0
- rasa/cli/project_templates/finance/data/{flows/welcome.yml → general/help.yml} +2 -7
- rasa/cli/project_templates/finance/data/general/human_handoff.yml +16 -0
- rasa/cli/project_templates/finance/data/general/welcome.yml +9 -0
- rasa/cli/project_templates/finance/data/{patterns → system/patterns}/pattern_chitchat.yml +0 -2
- rasa/cli/project_templates/finance/data/system/patterns/pattern_completed.yml +7 -0
- rasa/cli/project_templates/finance/data/system/patterns/pattern_correction.yml +7 -0
- rasa/cli/project_templates/finance/data/system/patterns/pattern_search.yml +8 -0
- rasa/cli/project_templates/finance/data/{patterns → system/patterns}/pattern_session_start.yml +0 -1
- rasa/cli/project_templates/finance/domain/{check_balance.yml → accounts/check_balance.yml} +2 -0
- rasa/cli/project_templates/finance/domain/general/assistant_details.yml +12 -0
- rasa/cli/project_templates/finance/domain/general/bot_identity.yml +5 -0
- rasa/cli/project_templates/finance/domain/general/cannot_handle.yml +5 -0
- rasa/cli/project_templates/finance/domain/general/defaults.yml +24 -0
- rasa/cli/project_templates/finance/domain/general/feedback.yml +28 -0
- rasa/cli/project_templates/finance/domain/general/goodbye.yml +7 -0
- rasa/cli/project_templates/finance/domain/general/help.yml +5 -0
- rasa/cli/project_templates/finance/domain/general/human_handoff.yml +30 -0
- rasa/cli/project_templates/finance/domain/general/utils.yml +13 -0
- rasa/cli/project_templates/finance/domain/general/welcome.yml +8 -0
- rasa/cli/project_templates/finance/endpoints.yml +1 -0
- rasa/cli/project_templates/finance/prompts/rephraser_demo_personality_prompt.jinja2 +3 -3
- rasa/cli/project_templates/telco/actions/actions_billing.py +24 -17
- rasa/cli/project_templates/telco/actions/actions_get_data_from_db.py +6 -1
- rasa/cli/project_templates/telco/actions/actions_run_diagnostics.py +6 -1
- rasa/cli/project_templates/telco/actions/actions_session_start.py +6 -1
- rasa/cli/project_templates/tutorial/config.yml +2 -1
- rasa/cli/scaffold.py +27 -2
- rasa/cli/train.py +8 -0
- rasa/cli/utils.py +31 -15
- rasa/core/actions/action.py +28 -41
- rasa/core/actions/action_run_slot_rejections.py +1 -1
- rasa/core/channels/development_inspector.py +47 -14
- rasa/core/channels/inspector/dist/assets/{arc-371401b1.js → arc-1ddec37b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-3f126156.js → blockDiagram-38ab4fdb-18af387c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-12f22eb7.js → c4Diagram-3d4e48cf-250127a3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-59f6d54b.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-03b1d386.js → classDiagram-70f12bd4-c3388b34.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-84f69d63.js → classDiagram-v2-f2320105-9c893a82.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-26177ddb.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-ca47fd38.js → createText-2e5e7dd3-c111213b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-f837ca8a.js → edges-e0da2a9e-812a729d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-8717ac54.js → erDiagram-9861fffd-fd5051bc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-94f38b83.js → flowDb-956e92f1-3287ac02.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-b616f9fb.js → flowDiagram-66a62f08-692fb0b2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-29c03f5a.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-f5d24bb8.js → flowchart-elk-definition-4a651766-008376f1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-b43ba8d9.js → ganttDiagram-c361ad54-df330a69.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-c3aafaa5.js → gitGraphDiagram-72cf32ee-e03676fb.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-0d0a2c10.js → graph-46fad2ba.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-58ea0305.js → index-3862675e-a484ac55.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-cce6f8a1.js → index-a003633f.js} +179 -179
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-b8f60461.js → infoDiagram-f8f76790-3f9e6ec2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-95be5545.js → journeyDiagram-49397b02-79f72383.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-da885b9b.js → layout-aad098e5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-f1c817d3.js → line-219ab7ae.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-d42801e6.js → linear-2cddbe62.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-a38923a6.js → mindmap-definition-fc14e90a-1d41ed99.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-ca6e71e9.js → pieDiagram-8a3498a8-cc496ee8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-b290dae9.js → quadrantDiagram-120e2f19-84d32884.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-03f02ceb.js → requirementDiagram-deff3bca-c0deb984.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-c49eee40.js → sankeyDiagram-04a897e0-b9d7fd62.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-b2cd6a3d.js → sequenceDiagram-704730f1-7d517565.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-e53a2028.js → stateDiagram-587899a1-98ef9b27.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-e1982a03.js → stateDiagram-v2-d93cdb3a-cee70748.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-d0226ca5.js → styles-6aaf32cf-3f9d1c96.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-0e21dc00.js → styles-9a916d00-67471923.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-9588494e.js → styles-c10674c1-bd093fb7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-be478d4f.js → svgDrawCommon-08f97a94-675794e8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-74631749.js → timeline-definition-85554ec2-0ac67617.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-a043552f.js → xychartDiagram-e933f94c-c018dc37.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +2 -2
- rasa/core/channels/inspector/index.html +1 -1
- rasa/core/channels/inspector/package.json +4 -3
- rasa/core/channels/inspector/src/App.tsx +53 -7
- rasa/core/channels/inspector/src/components/Chat.tsx +3 -2
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +1 -1
- rasa/core/channels/inspector/src/components/LatencyDisplay.tsx +268 -0
- rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +6 -2
- rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +8 -3
- rasa/core/channels/inspector/src/types.ts +8 -0
- rasa/core/channels/inspector/yarn.lock +12 -12
- rasa/core/channels/studio_chat.py +119 -34
- rasa/core/channels/voice_ready/twilio_voice.py +1 -1
- rasa/core/channels/voice_stream/asr/asr_engine.py +5 -1
- rasa/core/channels/voice_stream/asr/deepgram.py +5 -0
- rasa/core/channels/voice_stream/audiocodes.py +16 -8
- rasa/core/channels/voice_stream/browser_audio.py +39 -4
- rasa/core/channels/voice_stream/call_state.py +13 -2
- rasa/core/channels/voice_stream/genesys.py +16 -13
- rasa/core/channels/voice_stream/jambonz.py +14 -12
- rasa/core/channels/voice_stream/twilio_media_streams.py +14 -13
- rasa/core/channels/voice_stream/util.py +11 -1
- rasa/core/channels/voice_stream/voice_channel.py +108 -29
- rasa/core/nlg/callback.py +1 -1
- rasa/core/nlg/contextual_response_rephraser.py +19 -9
- rasa/core/nlg/generator.py +21 -5
- rasa/core/nlg/response.py +43 -6
- rasa/core/nlg/translate.py +8 -0
- rasa/core/policies/enterprise_search_policy.py +16 -21
- rasa/dialogue_understanding/commands/correct_slots_command.py +38 -10
- rasa/dialogue_understanding/generator/command_generator.py +5 -5
- rasa/dialogue_understanding/generator/command_parser.py +9 -13
- rasa/dialogue_understanding/processor/command_processor.py +149 -55
- rasa/dialogue_understanding/stack/utils.py +13 -3
- rasa/dialogue_understanding_test/du_test_schema.yml +3 -3
- rasa/dialogue_understanding_test/validation.py +9 -10
- rasa/e2e_test/e2e_config.py +18 -11
- rasa/e2e_test/e2e_test_schema.yml +3 -3
- rasa/e2e_test/utils/validation.py +17 -19
- rasa/engine/validation.py +86 -91
- rasa/exceptions.py +26 -1
- rasa/model_manager/model_api.py +2 -2
- rasa/model_manager/socket_bridge.py +8 -2
- rasa/shared/providers/_configs/default_litellm_client_config.py +3 -7
- rasa/shared/utils/cli.py +2 -0
- rasa/shared/utils/common.py +2 -1
- rasa/shared/utils/health_check/health_check.py +10 -14
- rasa/studio/upload.py +6 -2
- rasa/studio/utils.py +33 -22
- rasa/telemetry.py +95 -22
- rasa/utils/licensing.py +21 -10
- rasa/utils/log_utils.py +1 -1
- rasa/utils/tensorflow/transformer.py +3 -3
- rasa/validator.py +7 -5
- rasa/version.py +1 -1
- {rasa_pro-3.13.1a18.dist-info → rasa_pro-3.13.1a20.dist-info}/METADATA +7 -7
- {rasa_pro-3.13.1a18.dist-info → rasa_pro-3.13.1a20.dist-info}/RECORD +242 -203
- rasa/builder/create_openai_vector_store.py +0 -228
- rasa/builder/llm-helper-schema.json +0 -69
- rasa/builder/llm_context.py +0 -81
- rasa/builder/llm_helper_prompt.jinja2 +0 -245
- rasa/cli/project_templates/finance/data/nlu.yml +0 -29
- rasa/cli/project_templates/finance/data/patterns/pattern_search.yml +0 -5
- rasa/cli/project_templates/finance/domain/default_flows.yml +0 -33
- rasa/cli/project_templates/finance/prompts/command-generator.jinja2 +0 -57
- rasa/cli/project_templates/finance/tests/conversation_repair/cancellations.yml +0 -12
- rasa/cli/project_templates/finance/tests/conversation_repair/cannot_handle.yml +0 -7
- rasa/cli/project_templates/finance/tests/conversation_repair/chitchat.yml +0 -7
- rasa/cli/project_templates/finance/tests/conversation_repair/clarification.yml +0 -9
- rasa/cli/project_templates/finance/tests/conversation_repair/completion.yml +0 -18
- rasa/cli/project_templates/finance/tests/conversation_repair/corrections.yml +0 -17
- rasa/cli/project_templates/finance/tests/conversation_repair/digressions.yml +0 -32
- rasa/cli/project_templates/finance/tests/conversation_repair/human_handoff.yml +0 -21
- rasa/cli/project_templates/finance/tests/conversation_repair/skipping_collect_steps.yml +0 -16
- rasa/cli/project_templates/finance/tests/demo_scripts/main.yml +0 -16
- rasa/cli/project_templates/finance/tests/happy_paths/balance_verification.yml +0 -15
- rasa/cli/project_templates/finance/tests/happy_paths/banking_questions.yml +0 -12
- rasa/cli/project_templates/finance/tests/happy_paths/card_blocking.yml +0 -52
- rasa/cli/project_templates/finance/tests/happy_paths/money_transfer.yml +0 -136
- rasa/cli/project_templates/finance/tests/happy_paths/payee_management.yml +0 -27
- rasa/cli/project_templates/finance/tests/happy_paths/user_greeted.yml +0 -5
- rasa/cli/project_templates/plain/config.yml +0 -17
- rasa/cli/project_templates/plain/data/patterns/pattern_session_start.yml +0 -7
- rasa/cli/project_templates/plain/domain.yml +0 -5
- rasa/core/channels/inspector/dist/assets/channel-f1efda17.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-fdf164e2.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-7d7a1629.js +0 -1
- rasa/shared/importers/static.py +0 -63
- /rasa/{cli/project_templates/plain/actions → builder/copilot}/__init__.py +0 -0
- /rasa/builder/{inkeep-rag-response-schema.json → document_retrieval/inkeep-rag-response-schema.json} +0 -0
- /rasa/cli/project_templates/finance/actions/{action_process_immediate_payment.py → transfers/action_process_immediate_payment.py} +0 -0
- /rasa/cli/project_templates/finance/actions/{action_schedule_payment.py → transfers/action_schedule_payment.py} +0 -0
- /rasa/cli/project_templates/finance/actions/{action_validate_payment_date.py → transfers/action_validate_payment_date.py} +0 -0
- /rasa/cli/project_templates/finance/data/{flows → cards}/block_card.yml +0 -0
- /rasa/cli/project_templates/finance/data/{flows → cards}/select_card.yml +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/accounts.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/advisors.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/appointments.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/branches.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/cards.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/payees.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/transactions.json +0 -0
- /rasa/cli/project_templates/finance/data/{source → system/source}/users.json +0 -0
- /rasa/cli/project_templates/finance/data/{flows → transfers}/add_payee.yml +0 -0
- /rasa/cli/project_templates/finance/data/{flows → transfers}/list_payees.yml +0 -0
- /rasa/cli/project_templates/finance/data/{flows → transfers}/remove_payee.yml +0 -0
- /rasa/cli/project_templates/finance/data/{flows → transfers}/transfer_money.yml +0 -0
- /rasa/cli/project_templates/finance/domain/{block_card.yml → cards/block_card.yml} +0 -0
- /rasa/cli/project_templates/finance/domain/{select_card.yml → cards/select_card.yml} +0 -0
- /rasa/cli/project_templates/finance/domain/{add_payee.yml → transfers/add_payee.yml} +0 -0
- /rasa/cli/project_templates/finance/domain/{list_payees.yml → transfers/list_payees.yml} +0 -0
- /rasa/cli/project_templates/finance/domain/{remove_payee.yml → transfers/remove_payee.yml} +0 -0
- /rasa/cli/project_templates/finance/domain/{transfer_money.yml → transfers/transfer_money.yml} +0 -0
- {rasa_pro-3.13.1a18.dist-info → rasa_pro-3.13.1a20.dist-info}/NOTICE +0 -0
- {rasa_pro-3.13.1a18.dist-info → rasa_pro-3.13.1a20.dist-info}/WHEEL +0 -0
- {rasa_pro-3.13.1a18.dist-info → rasa_pro-3.13.1a20.dist-info}/entry_points.txt +0 -0
|
@@ -26,6 +26,7 @@ from rasa.core.channels.voice_ready.utils import (
|
|
|
26
26
|
from rasa.core.channels.voice_stream.audio_bytes import RasaAudioBytes
|
|
27
27
|
from rasa.core.channels.voice_stream.call_state import call_state
|
|
28
28
|
from rasa.core.channels.voice_stream.tts.tts_engine import TTSEngine
|
|
29
|
+
from rasa.core.channels.voice_stream.util import repack_voice_credentials
|
|
29
30
|
from rasa.core.channels.voice_stream.voice_channel import (
|
|
30
31
|
ContinueConversationAction,
|
|
31
32
|
EndConversationAction,
|
|
@@ -120,20 +121,20 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
120
121
|
cls,
|
|
121
122
|
credentials: Optional[Dict[str, Any]],
|
|
122
123
|
) -> VoiceInputChannel:
|
|
123
|
-
credentials
|
|
124
|
+
cls.validate_credentials(credentials)
|
|
125
|
+
new_creds = repack_voice_credentials(credentials)
|
|
126
|
+
return cls(**new_creds)
|
|
124
127
|
|
|
125
|
-
|
|
126
|
-
|
|
128
|
+
@classmethod
|
|
129
|
+
def validate_credentials(
|
|
130
|
+
cls,
|
|
131
|
+
credentials: Optional[Dict[str, Any]],
|
|
132
|
+
) -> None:
|
|
133
|
+
cls.validate_basic_credentials(credentials)
|
|
134
|
+
username = credentials.get("username") if credentials else None
|
|
135
|
+
password = credentials.get("password") if credentials else None
|
|
127
136
|
validate_username_password_credentials(username, password, "TwilioMediaStreams")
|
|
128
137
|
|
|
129
|
-
return cls(
|
|
130
|
-
credentials["server_url"],
|
|
131
|
-
credentials["asr"],
|
|
132
|
-
credentials["tts"],
|
|
133
|
-
username=username,
|
|
134
|
-
password=password,
|
|
135
|
-
)
|
|
136
|
-
|
|
137
138
|
@classmethod
|
|
138
139
|
def name(cls) -> str:
|
|
139
140
|
return "twilio_media_streams"
|
|
@@ -175,14 +176,14 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
175
176
|
elif data["event"] == "mark":
|
|
176
177
|
if data["mark"]["name"] == call_state.latest_bot_audio_id:
|
|
177
178
|
# Just finished streaming last audio bytes
|
|
178
|
-
call_state.is_bot_speaking = False
|
|
179
|
+
call_state.is_bot_speaking = False
|
|
179
180
|
if call_state.should_hangup:
|
|
180
181
|
logger.debug(
|
|
181
182
|
"twilio_streams.hangup", marker=call_state.latest_bot_audio_id
|
|
182
183
|
)
|
|
183
184
|
return EndConversationAction()
|
|
184
185
|
else:
|
|
185
|
-
call_state.is_bot_speaking = True
|
|
186
|
+
call_state.is_bot_speaking = True
|
|
186
187
|
return ContinueConversationAction()
|
|
187
188
|
|
|
188
189
|
def create_output_channel(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import audioop
|
|
2
2
|
import wave
|
|
3
3
|
from dataclasses import asdict, dataclass
|
|
4
|
-
from typing import Optional, Type, TypeVar
|
|
4
|
+
from typing import Dict, Optional, Type, TypeVar
|
|
5
5
|
|
|
6
6
|
import structlog
|
|
7
7
|
|
|
@@ -55,3 +55,13 @@ class MergeableConfig:
|
|
|
55
55
|
@classmethod
|
|
56
56
|
def from_dict(cls: Type[T], data: dict[str, Optional[str]]) -> T:
|
|
57
57
|
return cls(**data)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def repack_voice_credentials(
|
|
61
|
+
credentials: Dict[str, str],
|
|
62
|
+
) -> Dict[str, str]:
|
|
63
|
+
"""Repack voice credentials to ensure they are in the correct format."""
|
|
64
|
+
new_creds = {**credentials}
|
|
65
|
+
new_creds["asr_config"] = new_creds.pop("asr", None)
|
|
66
|
+
new_creds["tts_config"] = new_creds.pop("tts", None)
|
|
67
|
+
return new_creds
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import asyncio
|
|
2
4
|
import copy
|
|
5
|
+
import time
|
|
3
6
|
from dataclasses import asdict, dataclass
|
|
4
7
|
from typing import Any, AsyncIterator, Awaitable, Callable, Dict, List, Optional, Tuple
|
|
5
8
|
|
|
@@ -189,7 +192,7 @@ class VoiceOutputChannel(OutputChannel):
|
|
|
189
192
|
def update_silence_timeout(self) -> None:
|
|
190
193
|
"""Updates the silence timeout for the session."""
|
|
191
194
|
if self.tracker_state:
|
|
192
|
-
call_state.silence_timeout = self.tracker_state["slots"][
|
|
195
|
+
call_state.silence_timeout = self.tracker_state["slots"][
|
|
193
196
|
SILENCE_TIMEOUT_SLOT
|
|
194
197
|
]
|
|
195
198
|
logger.debug(
|
|
@@ -207,22 +210,63 @@ class VoiceOutputChannel(OutputChannel):
|
|
|
207
210
|
"""Uses the concise button output format for voice channels."""
|
|
208
211
|
await self.send_text_with_buttons_concise(recipient_id, text, buttons, **kwargs)
|
|
209
212
|
|
|
213
|
+
def _track_rasa_processing_latency(self) -> None:
|
|
214
|
+
"""Track and log Rasa processing completion latency."""
|
|
215
|
+
if call_state.rasa_processing_start_time:
|
|
216
|
+
call_state.rasa_processing_latency_ms = (
|
|
217
|
+
time.time() - call_state.rasa_processing_start_time
|
|
218
|
+
) * 1000
|
|
219
|
+
logger.debug(
|
|
220
|
+
"voice_channel.rasa_processing_latency",
|
|
221
|
+
latency_ms=call_state.rasa_processing_latency_ms,
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
def _track_tts_first_byte_latency(self) -> None:
|
|
225
|
+
"""Track and log TTS first byte latency."""
|
|
226
|
+
if call_state.tts_start_time:
|
|
227
|
+
call_state.tts_first_byte_latency_ms = (
|
|
228
|
+
time.time() - call_state.tts_start_time
|
|
229
|
+
) * 1000
|
|
230
|
+
logger.debug(
|
|
231
|
+
"voice_channel.tts_first_byte_latency",
|
|
232
|
+
latency_ms=call_state.tts_first_byte_latency_ms,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
def _track_tts_complete_latency(self) -> None:
|
|
236
|
+
"""Track and log TTS completion latency."""
|
|
237
|
+
if call_state.tts_start_time:
|
|
238
|
+
call_state.tts_complete_latency_ms = (
|
|
239
|
+
time.time() - call_state.tts_start_time
|
|
240
|
+
) * 1000
|
|
241
|
+
logger.debug(
|
|
242
|
+
"voice_channel.tts_complete_latency",
|
|
243
|
+
latency_ms=call_state.tts_complete_latency_ms,
|
|
244
|
+
)
|
|
245
|
+
|
|
210
246
|
async def send_text_message(
|
|
211
247
|
self, recipient_id: str, text: str, **kwargs: Any
|
|
212
248
|
) -> None:
|
|
213
249
|
text = remove_emojis(text)
|
|
214
250
|
self.update_silence_timeout()
|
|
251
|
+
|
|
252
|
+
# Track Rasa processing completion
|
|
253
|
+
self._track_rasa_processing_latency()
|
|
254
|
+
|
|
255
|
+
# Track TTS start time
|
|
256
|
+
call_state.tts_start_time = time.time()
|
|
257
|
+
|
|
215
258
|
cached_audio_bytes = self.tts_cache.get(text)
|
|
216
259
|
collected_audio_bytes = RasaAudioBytes(b"")
|
|
217
260
|
seconds_marker = -1
|
|
218
261
|
last_sent_offset = 0
|
|
262
|
+
first_audio_sent = False
|
|
219
263
|
logger.debug("voice_channel.sending_audio", text=text)
|
|
220
264
|
|
|
221
265
|
# Send start marker before first chunk
|
|
222
266
|
try:
|
|
223
267
|
await self.send_start_marker(recipient_id)
|
|
224
268
|
except (WebsocketClosed, ServerError):
|
|
225
|
-
call_state.connection_failed = True
|
|
269
|
+
call_state.connection_failed = True
|
|
226
270
|
|
|
227
271
|
if cached_audio_bytes:
|
|
228
272
|
audio_stream = self.chunk_audio(cached_audio_bytes)
|
|
@@ -244,6 +288,11 @@ class VoiceOutputChannel(OutputChannel):
|
|
|
244
288
|
|
|
245
289
|
if should_send:
|
|
246
290
|
try:
|
|
291
|
+
# Track TTS first byte time
|
|
292
|
+
if not first_audio_sent:
|
|
293
|
+
self._track_tts_first_byte_latency()
|
|
294
|
+
first_audio_sent = True
|
|
295
|
+
|
|
247
296
|
# Send only the new bytes since last send
|
|
248
297
|
new_bytes = RasaAudioBytes(collected_audio_bytes[last_sent_offset:])
|
|
249
298
|
await self.send_audio_bytes(recipient_id, new_bytes)
|
|
@@ -256,24 +305,31 @@ class VoiceOutputChannel(OutputChannel):
|
|
|
256
305
|
|
|
257
306
|
except (WebsocketClosed, ServerError):
|
|
258
307
|
# ignore sending error, and keep collecting and caching audio bytes
|
|
259
|
-
call_state.connection_failed = True
|
|
308
|
+
call_state.connection_failed = True
|
|
260
309
|
|
|
261
310
|
# Send any remaining audio not yet sent
|
|
262
311
|
remaining_bytes = len(collected_audio_bytes) - last_sent_offset
|
|
263
312
|
if remaining_bytes > 0:
|
|
264
313
|
try:
|
|
314
|
+
# Track TTS first byte time if not already tracked
|
|
315
|
+
if not first_audio_sent:
|
|
316
|
+
self._track_tts_first_byte_latency()
|
|
317
|
+
|
|
265
318
|
new_bytes = RasaAudioBytes(collected_audio_bytes[last_sent_offset:])
|
|
266
319
|
await self.send_audio_bytes(recipient_id, new_bytes)
|
|
267
320
|
except (WebsocketClosed, ServerError):
|
|
268
321
|
# ignore sending error
|
|
269
|
-
call_state.connection_failed = True
|
|
322
|
+
call_state.connection_failed = True
|
|
323
|
+
|
|
324
|
+
# Track TTS completion time
|
|
325
|
+
self._track_tts_complete_latency()
|
|
270
326
|
|
|
271
327
|
try:
|
|
272
328
|
await self.send_end_marker(recipient_id)
|
|
273
329
|
except (WebsocketClosed, ServerError):
|
|
274
330
|
# ignore sending error
|
|
275
331
|
pass
|
|
276
|
-
call_state.latest_bot_audio_id = self.latest_message_id
|
|
332
|
+
call_state.latest_bot_audio_id = self.latest_message_id
|
|
277
333
|
|
|
278
334
|
if not cached_audio_bytes:
|
|
279
335
|
self.tts_cache.put(text, collected_audio_bytes)
|
|
@@ -298,7 +354,7 @@ class VoiceOutputChannel(OutputChannel):
|
|
|
298
354
|
return
|
|
299
355
|
|
|
300
356
|
async def hangup(self, recipient_id: str, **kwargs: Any) -> None:
|
|
301
|
-
call_state.should_hangup = True
|
|
357
|
+
call_state.should_hangup = True
|
|
302
358
|
|
|
303
359
|
|
|
304
360
|
class VoiceInputChannel(InputChannel):
|
|
@@ -345,32 +401,32 @@ class VoiceInputChannel(InputChannel):
|
|
|
345
401
|
if call_state.silence_timeout_watcher:
|
|
346
402
|
logger.debug("voice_channel.cancelling_current_timeout_watcher_task")
|
|
347
403
|
call_state.silence_timeout_watcher.cancel()
|
|
348
|
-
call_state.silence_timeout_watcher = None
|
|
404
|
+
call_state.silence_timeout_watcher = None
|
|
349
405
|
|
|
350
406
|
@classmethod
|
|
351
|
-
def
|
|
352
|
-
|
|
353
|
-
credentials: Optional[Dict[str, Any]],
|
|
354
|
-
) -> InputChannel:
|
|
407
|
+
def validate_basic_credentials(cls, credentials: Optional[Dict[str, Any]]) -> None:
|
|
408
|
+
"""Validate the basic credentials for the voice channel."""
|
|
355
409
|
if not credentials:
|
|
356
410
|
cls.raise_missing_credentials_exception()
|
|
357
|
-
|
|
358
|
-
if not credentials.get("server_url"):
|
|
359
|
-
raise InvalidConfigException("No server_url provided in credentials.")
|
|
360
|
-
if not credentials.get("asr"):
|
|
411
|
+
if not isinstance(credentials, dict):
|
|
361
412
|
raise InvalidConfigException(
|
|
362
|
-
"
|
|
413
|
+
"Credentials must be a dictionary for voice channel."
|
|
363
414
|
)
|
|
364
|
-
|
|
415
|
+
|
|
416
|
+
required_keys = {"server_url", "asr", "tts"}
|
|
417
|
+
credentials_keys = set(credentials.keys())
|
|
418
|
+
if not required_keys.issubset(credentials_keys):
|
|
419
|
+
missing_fields = required_keys - credentials_keys
|
|
365
420
|
raise InvalidConfigException(
|
|
366
|
-
"
|
|
421
|
+
f"Missing required fields in credentials: {', '.join(missing_fields)} "
|
|
422
|
+
f"for channel {cls.name()}"
|
|
367
423
|
)
|
|
368
424
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
425
|
+
@classmethod
|
|
426
|
+
def from_credentials(
|
|
427
|
+
cls, credentials: Optional[Dict[str, Any]]
|
|
428
|
+
) -> VoiceInputChannel:
|
|
429
|
+
raise NotImplementedError
|
|
374
430
|
|
|
375
431
|
def channel_bytes_to_rasa_audio_bytes(self, input_bytes: bytes) -> RasaAudioBytes:
|
|
376
432
|
raise NotImplementedError
|
|
@@ -439,10 +495,8 @@ class VoiceInputChannel(InputChannel):
|
|
|
439
495
|
if was_bot_speaking_before and not is_bot_speaking_after:
|
|
440
496
|
logger.debug("voice_channel.bot_stopped_speaking")
|
|
441
497
|
self._cancel_silence_timeout_watcher()
|
|
442
|
-
call_state.silence_timeout_watcher = (
|
|
443
|
-
|
|
444
|
-
self.monitor_silence_timeout(asr_event_queue)
|
|
445
|
-
)
|
|
498
|
+
call_state.silence_timeout_watcher = asyncio.create_task(
|
|
499
|
+
self.monitor_silence_timeout(asr_event_queue)
|
|
446
500
|
)
|
|
447
501
|
if isinstance(channel_action, NewAudioAction):
|
|
448
502
|
await asr_engine.send_audio_chunks(channel_action.audio_bytes)
|
|
@@ -468,10 +522,17 @@ class VoiceInputChannel(InputChannel):
|
|
|
468
522
|
call_parameters,
|
|
469
523
|
)
|
|
470
524
|
|
|
525
|
+
async def asr_keep_alive_task() -> None:
|
|
526
|
+
interval = getattr(asr_engine.config, "keep_alive_interval", 5)
|
|
527
|
+
while True:
|
|
528
|
+
await asyncio.sleep(interval)
|
|
529
|
+
await asr_engine.send_keep_alive()
|
|
530
|
+
|
|
471
531
|
tasks = [
|
|
472
532
|
asyncio.create_task(consume_audio_bytes()),
|
|
473
533
|
asyncio.create_task(receive_asr_events()),
|
|
474
534
|
asyncio.create_task(handle_asr_events()),
|
|
535
|
+
asyncio.create_task(asr_keep_alive_task()),
|
|
475
536
|
]
|
|
476
537
|
await asyncio.wait(
|
|
477
538
|
tasks,
|
|
@@ -491,6 +552,16 @@ class VoiceInputChannel(InputChannel):
|
|
|
491
552
|
"""Create a matching voice output channel for this voice input channel."""
|
|
492
553
|
raise NotImplementedError
|
|
493
554
|
|
|
555
|
+
def _track_asr_latency(self) -> None:
|
|
556
|
+
"""Track and log ASR processing latency."""
|
|
557
|
+
if call_state.user_speech_start_time:
|
|
558
|
+
call_state.asr_latency_ms = (
|
|
559
|
+
time.time() - call_state.user_speech_start_time
|
|
560
|
+
) * 1000
|
|
561
|
+
logger.debug(
|
|
562
|
+
"voice_channel.asr_latency", latency_ms=call_state.asr_latency_ms
|
|
563
|
+
)
|
|
564
|
+
|
|
494
565
|
async def handle_asr_event(
|
|
495
566
|
self,
|
|
496
567
|
e: ASREvent,
|
|
@@ -504,7 +575,12 @@ class VoiceInputChannel(InputChannel):
|
|
|
504
575
|
logger.debug(
|
|
505
576
|
"VoiceInputChannel.handle_asr_event.new_transcript", transcript=e.text
|
|
506
577
|
)
|
|
507
|
-
call_state.is_user_speaking = False
|
|
578
|
+
call_state.is_user_speaking = False
|
|
579
|
+
|
|
580
|
+
# Track ASR and Rasa latencies
|
|
581
|
+
self._track_asr_latency()
|
|
582
|
+
call_state.rasa_processing_start_time = time.time()
|
|
583
|
+
|
|
508
584
|
output_channel = self.create_output_channel(voice_websocket, tts_engine)
|
|
509
585
|
message = UserMessage(
|
|
510
586
|
text=e.text,
|
|
@@ -515,8 +591,11 @@ class VoiceInputChannel(InputChannel):
|
|
|
515
591
|
)
|
|
516
592
|
await on_new_message(message)
|
|
517
593
|
elif isinstance(e, UserIsSpeaking):
|
|
594
|
+
# Track when user starts speaking for ASR latency calculation
|
|
595
|
+
if not call_state.is_user_speaking:
|
|
596
|
+
call_state.user_speech_start_time = time.time()
|
|
518
597
|
self._cancel_silence_timeout_watcher()
|
|
519
|
-
call_state.is_user_speaking = True
|
|
598
|
+
call_state.is_user_speaking = True
|
|
520
599
|
elif isinstance(e, UserSilence):
|
|
521
600
|
output_channel = self.create_output_channel(voice_websocket, tts_engine)
|
|
522
601
|
message = UserMessage(
|
rasa/core/nlg/callback.py
CHANGED
|
@@ -19,7 +19,7 @@ def nlg_response_format_spec() -> Dict[Text, Any]:
|
|
|
19
19
|
return {
|
|
20
20
|
"type": "object",
|
|
21
21
|
"properties": {
|
|
22
|
-
"text": {"type": "string"},
|
|
22
|
+
"text": {"type": ["string", "null"]},
|
|
23
23
|
"id": {"type": ["string", "null"]},
|
|
24
24
|
"buttons": {"type": ["array", "null"], "items": {"type": "object"}},
|
|
25
25
|
"elements": {"type": ["array", "null"], "items": {"type": "object"}},
|
|
@@ -24,6 +24,7 @@ from rasa.shared.constants import (
|
|
|
24
24
|
)
|
|
25
25
|
from rasa.shared.core.domain import KEY_RESPONSES_TEXT, Domain
|
|
26
26
|
from rasa.shared.core.events import BotUttered, UserUttered
|
|
27
|
+
from rasa.shared.core.flows.constants import KEY_TRANSLATION
|
|
27
28
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
28
29
|
from rasa.shared.nlu.constants import (
|
|
29
30
|
KEY_COMPONENT_NAME,
|
|
@@ -224,8 +225,10 @@ class ContextualResponseRephraser(
|
|
|
224
225
|
|
|
225
226
|
@measure_llm_latency
|
|
226
227
|
async def _generate_llm_response(self, prompt: str) -> Optional[LLMResponse]:
|
|
227
|
-
"""Use LLM to generate a response
|
|
228
|
-
|
|
228
|
+
"""Use LLM to generate a response.
|
|
229
|
+
|
|
230
|
+
Returns an LLMResponse object containing both the generated text
|
|
231
|
+
(choices) and metadata.
|
|
229
232
|
|
|
230
233
|
Args:
|
|
231
234
|
prompt: The prompt to send to the LLM.
|
|
@@ -305,7 +308,12 @@ class ContextualResponseRephraser(
|
|
|
305
308
|
Returns:
|
|
306
309
|
The response with the rephrased text.
|
|
307
310
|
"""
|
|
308
|
-
|
|
311
|
+
translation_response = response.get(KEY_TRANSLATION) or {}
|
|
312
|
+
lang_code = getattr(tracker.current_language, "code", None)
|
|
313
|
+
response_text = translation_response.get(
|
|
314
|
+
lang_code, response.get(KEY_RESPONSES_TEXT)
|
|
315
|
+
)
|
|
316
|
+
if not response_text:
|
|
309
317
|
return response
|
|
310
318
|
|
|
311
319
|
prompt_template_text = self._template_for_response_rephrasing(response)
|
|
@@ -367,12 +375,17 @@ class ContextualResponseRephraser(
|
|
|
367
375
|
return response
|
|
368
376
|
|
|
369
377
|
updated_text = llm_response.choices[0]
|
|
378
|
+
|
|
379
|
+
if lang_code in translation_response:
|
|
380
|
+
response[KEY_TRANSLATION][lang_code] = updated_text
|
|
381
|
+
else:
|
|
382
|
+
response[KEY_RESPONSES_TEXT] = updated_text
|
|
383
|
+
|
|
370
384
|
structlogger.debug(
|
|
371
385
|
"nlg.rewrite.complete",
|
|
372
386
|
response_text=response_text,
|
|
373
387
|
updated_text=updated_text,
|
|
374
388
|
)
|
|
375
|
-
response[KEY_RESPONSES_TEXT] = updated_text
|
|
376
389
|
return response
|
|
377
390
|
|
|
378
391
|
def does_response_allow_rephrasing(self, template: Dict[Text, Any]) -> bool:
|
|
@@ -406,12 +419,9 @@ class ContextualResponseRephraser(
|
|
|
406
419
|
Returns:
|
|
407
420
|
The generated response.
|
|
408
421
|
"""
|
|
409
|
-
|
|
410
|
-
stack_context = tracker.stack.current_context()
|
|
411
|
-
templated_response = self.generate_from_slots(
|
|
422
|
+
templated_response = await super().generate(
|
|
412
423
|
utter_action=utter_action,
|
|
413
|
-
|
|
414
|
-
stack_context=stack_context,
|
|
424
|
+
tracker=tracker,
|
|
415
425
|
output_channel=output_channel,
|
|
416
426
|
**kwargs,
|
|
417
427
|
)
|
rasa/core/nlg/generator.py
CHANGED
|
@@ -6,6 +6,8 @@ from pypred import Predicate
|
|
|
6
6
|
|
|
7
7
|
import rasa.shared.utils.common
|
|
8
8
|
import rasa.shared.utils.io
|
|
9
|
+
from rasa.core.nlg.translate import has_translation
|
|
10
|
+
from rasa.engine.language import Language
|
|
9
11
|
from rasa.shared.constants import CHANNEL, RESPONSE_CONDITION
|
|
10
12
|
from rasa.shared.core.domain import Domain
|
|
11
13
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
@@ -131,11 +133,23 @@ class ResponseVariationFilter:
|
|
|
131
133
|
|
|
132
134
|
return True
|
|
133
135
|
|
|
136
|
+
def _filter_by_language(
|
|
137
|
+
self, responses: List[Dict[Text, Any]], language: Optional[Language] = None
|
|
138
|
+
) -> List[Dict[Text, Any]]:
|
|
139
|
+
if not language:
|
|
140
|
+
return responses
|
|
141
|
+
|
|
142
|
+
if filtered := [r for r in responses if has_translation(r, language)]:
|
|
143
|
+
return filtered
|
|
144
|
+
# if no translation is found, return the original response variations
|
|
145
|
+
return responses
|
|
146
|
+
|
|
134
147
|
def responses_for_utter_action(
|
|
135
148
|
self,
|
|
136
149
|
utter_action: Text,
|
|
137
150
|
output_channel: Text,
|
|
138
151
|
filled_slots: Dict[Text, Any],
|
|
152
|
+
language: Optional[Language] = None,
|
|
139
153
|
) -> List[Dict[Text, Any]]:
|
|
140
154
|
"""Returns array of responses that fit the channel, action and condition."""
|
|
141
155
|
# filter responses without a condition
|
|
@@ -176,16 +190,16 @@ class ResponseVariationFilter:
|
|
|
176
190
|
)
|
|
177
191
|
|
|
178
192
|
if conditional_channel:
|
|
179
|
-
return conditional_channel
|
|
193
|
+
return self._filter_by_language(conditional_channel, language)
|
|
180
194
|
|
|
181
195
|
if default_channel:
|
|
182
|
-
return default_channel
|
|
196
|
+
return self._filter_by_language(default_channel, language)
|
|
183
197
|
|
|
184
198
|
if conditional_no_channel:
|
|
185
|
-
return conditional_no_channel
|
|
199
|
+
return self._filter_by_language(conditional_no_channel, language)
|
|
186
200
|
|
|
187
201
|
if default_no_channel:
|
|
188
|
-
return default_no_channel
|
|
202
|
+
return self._filter_by_language(default_no_channel, language)
|
|
189
203
|
|
|
190
204
|
# if there is no response variation selected,
|
|
191
205
|
# return the internal error response to prevent
|
|
@@ -198,7 +212,9 @@ class ResponseVariationFilter:
|
|
|
198
212
|
f"a default variation and that all the conditions are valid. "
|
|
199
213
|
f"Returning the internal error response.",
|
|
200
214
|
)
|
|
201
|
-
return self.
|
|
215
|
+
return self._filter_by_language(
|
|
216
|
+
self.responses.get("utter_internal_error_rasa", []), language
|
|
217
|
+
)
|
|
202
218
|
|
|
203
219
|
def get_response_variation_id(
|
|
204
220
|
self,
|
rasa/core/nlg/response.py
CHANGED
|
@@ -5,8 +5,11 @@ from typing import Any, Dict, List, Optional, Text
|
|
|
5
5
|
from rasa.core.constants import DEFAULT_TEMPLATE_ENGINE, TEMPLATE_ENGINE_CONFIG_KEY
|
|
6
6
|
from rasa.core.nlg import interpolator
|
|
7
7
|
from rasa.core.nlg.generator import NaturalLanguageGenerator, ResponseVariationFilter
|
|
8
|
-
from rasa.
|
|
8
|
+
from rasa.core.nlg.translate import get_translated_buttons, get_translated_text
|
|
9
|
+
from rasa.engine.language import Language
|
|
10
|
+
from rasa.shared.constants import BUTTONS, RESPONSE_CONDITION, TEXT
|
|
9
11
|
from rasa.shared.core.domain import RESPONSE_KEYS_TO_INTERPOLATE
|
|
12
|
+
from rasa.shared.core.flows.constants import KEY_TRANSLATION
|
|
10
13
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
11
14
|
from rasa.shared.nlu.constants import METADATA
|
|
12
15
|
|
|
@@ -30,7 +33,11 @@ class TemplatedNaturalLanguageGenerator(NaturalLanguageGenerator):
|
|
|
30
33
|
|
|
31
34
|
# noinspection PyUnusedLocal
|
|
32
35
|
def _random_response_for(
|
|
33
|
-
self,
|
|
36
|
+
self,
|
|
37
|
+
utter_action: Text,
|
|
38
|
+
output_channel: Text,
|
|
39
|
+
filled_slots: Dict[Text, Any],
|
|
40
|
+
language: Optional[Language] = None,
|
|
34
41
|
) -> Optional[Dict[Text, Any]]:
|
|
35
42
|
"""Select random response for the utter action from available ones.
|
|
36
43
|
|
|
@@ -42,7 +49,7 @@ class TemplatedNaturalLanguageGenerator(NaturalLanguageGenerator):
|
|
|
42
49
|
if utter_action in self.responses:
|
|
43
50
|
response_filter = ResponseVariationFilter(self.responses)
|
|
44
51
|
suitable_responses = response_filter.responses_for_utter_action(
|
|
45
|
-
utter_action, output_channel, filled_slots
|
|
52
|
+
utter_action, output_channel, filled_slots, language
|
|
46
53
|
)
|
|
47
54
|
|
|
48
55
|
if suitable_responses:
|
|
@@ -75,9 +82,36 @@ class TemplatedNaturalLanguageGenerator(NaturalLanguageGenerator):
|
|
|
75
82
|
"""Generate a response for the requested utter action."""
|
|
76
83
|
filled_slots = tracker.current_slot_values()
|
|
77
84
|
stack_context = tracker.stack.current_context()
|
|
78
|
-
|
|
79
|
-
utter_action,
|
|
85
|
+
response = self.generate_from_slots(
|
|
86
|
+
utter_action,
|
|
87
|
+
filled_slots,
|
|
88
|
+
stack_context,
|
|
89
|
+
output_channel,
|
|
90
|
+
tracker.current_language,
|
|
91
|
+
**kwargs,
|
|
80
92
|
)
|
|
93
|
+
if response is not None:
|
|
94
|
+
return self.translate_response(response, tracker.current_language)
|
|
95
|
+
return None
|
|
96
|
+
|
|
97
|
+
def translate_response(
|
|
98
|
+
self, response: Dict[Text, Any], language: Optional[Language] = None
|
|
99
|
+
) -> Dict[Text, Any]:
|
|
100
|
+
message_copy = copy.deepcopy(response)
|
|
101
|
+
|
|
102
|
+
text = get_translated_text(
|
|
103
|
+
text=message_copy.pop(TEXT, None),
|
|
104
|
+
translation=message_copy.pop(KEY_TRANSLATION, {}),
|
|
105
|
+
language=language,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
buttons = get_translated_buttons(
|
|
109
|
+
buttons=message_copy.pop(BUTTONS, None), language=language
|
|
110
|
+
)
|
|
111
|
+
message_copy[TEXT] = text
|
|
112
|
+
if buttons:
|
|
113
|
+
message_copy[BUTTONS] = buttons
|
|
114
|
+
return message_copy
|
|
81
115
|
|
|
82
116
|
def generate_from_slots(
|
|
83
117
|
self,
|
|
@@ -85,12 +119,15 @@ class TemplatedNaturalLanguageGenerator(NaturalLanguageGenerator):
|
|
|
85
119
|
filled_slots: Dict[Text, Any],
|
|
86
120
|
stack_context: Dict[Text, Any],
|
|
87
121
|
output_channel: Text,
|
|
122
|
+
language: Optional[Language] = None,
|
|
88
123
|
**kwargs: Any,
|
|
89
124
|
) -> Optional[Dict[Text, Any]]:
|
|
90
125
|
"""Generate a response for the requested utter action."""
|
|
91
126
|
# Fetching a random response for the passed utter action
|
|
92
127
|
r = copy.deepcopy(
|
|
93
|
-
self._random_response_for(
|
|
128
|
+
self._random_response_for(
|
|
129
|
+
utter_action, output_channel, filled_slots, language
|
|
130
|
+
)
|
|
94
131
|
)
|
|
95
132
|
# Filling the slots in the response with placeholders and returning the response
|
|
96
133
|
if r is not None:
|
rasa/core/nlg/translate.py
CHANGED
|
@@ -23,6 +23,14 @@ def get_translated_text(
|
|
|
23
23
|
return translation.get(language_code, text)
|
|
24
24
|
|
|
25
25
|
|
|
26
|
+
def has_translation(
|
|
27
|
+
message: Dict[Text, Any], language: Optional[Language] = None
|
|
28
|
+
) -> bool:
|
|
29
|
+
"""Check if the message has a translation for the given language."""
|
|
30
|
+
language_code = language.code if language else None
|
|
31
|
+
return language_code in message.get(KEY_TRANSLATION, {})
|
|
32
|
+
|
|
33
|
+
|
|
26
34
|
def get_translated_buttons(
|
|
27
35
|
buttons: Optional[List[Dict[Text, Any]]], language: Optional[Language] = None
|
|
28
36
|
) -> Optional[List[Dict[Text, Any]]]:
|
|
@@ -50,6 +50,7 @@ from rasa.engine.graph import ExecutionContext
|
|
|
50
50
|
from rasa.engine.recipes.default_recipe import DefaultV1Recipe
|
|
51
51
|
from rasa.engine.storage.resource import Resource
|
|
52
52
|
from rasa.engine.storage.storage import ModelStorage
|
|
53
|
+
from rasa.exceptions import EnterpriseSearchPolicyError
|
|
53
54
|
from rasa.graph_components.providers.forms_provider import Forms
|
|
54
55
|
from rasa.graph_components.providers.responses_provider import Responses
|
|
55
56
|
from rasa.shared.constants import (
|
|
@@ -82,7 +83,6 @@ from rasa.shared.providers.embedding._langchain_embedding_client_adapter import
|
|
|
82
83
|
_LangchainEmbeddingClientAdapter,
|
|
83
84
|
)
|
|
84
85
|
from rasa.shared.providers.llm.llm_response import LLMResponse, measure_llm_latency
|
|
85
|
-
from rasa.shared.utils.cli import print_error_and_exit
|
|
86
86
|
from rasa.shared.utils.constants import (
|
|
87
87
|
LOG_COMPONENT_SOURCE_METHOD_FINGERPRINT_ADDON,
|
|
88
88
|
LOG_COMPONENT_SOURCE_METHOD_INIT,
|
|
@@ -343,14 +343,11 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
343
343
|
try:
|
|
344
344
|
embeddings = self._create_plain_embedder(self.embeddings_config)
|
|
345
345
|
except (ValidationError, Exception) as e:
|
|
346
|
-
|
|
347
|
-
"enterprise_search_policy.train
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
print_error_and_exit(
|
|
352
|
-
"Unable to create embedder. Please make sure you specified the "
|
|
353
|
-
f"required environment variables. Error: {e}"
|
|
346
|
+
raise EnterpriseSearchPolicyError(
|
|
347
|
+
code="core.policies.enterprise_search_policy.train"
|
|
348
|
+
".embedder_instantiation_failed",
|
|
349
|
+
event_info=f"Unable to create embedder. Please make sure you "
|
|
350
|
+
f"specified the required environment variables. Error: {e}",
|
|
354
351
|
)
|
|
355
352
|
|
|
356
353
|
if self.vector_store_type == DEFAULT_VECTOR_STORE_TYPE:
|
|
@@ -679,7 +676,7 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
679
676
|
answer_relevant = not _ENTERPRISE_SEARCH_ANSWER_NOT_RELEVANT_PATTERN.search(
|
|
680
677
|
llm_answer
|
|
681
678
|
)
|
|
682
|
-
|
|
679
|
+
|
|
683
680
|
return _RelevancyCheckResponse(
|
|
684
681
|
answer=llm_answer if answer_relevant else None,
|
|
685
682
|
relevant=answer_relevant,
|
|
@@ -788,25 +785,23 @@ class EnterpriseSearchPolicy(LLMHealthCheckMixin, EmbeddingsHealthCheckMixin, Po
|
|
|
788
785
|
"Please specify a valid path to the documents source directory in the "
|
|
789
786
|
"vector_store configuration."
|
|
790
787
|
)
|
|
791
|
-
|
|
792
|
-
"enterprise_search_policy.train
|
|
793
|
-
|
|
794
|
-
docs_folder={os.path.abspath(docs_folder)},
|
|
795
|
-
configuration_value=docs_folder,
|
|
788
|
+
error_code = (
|
|
789
|
+
"core.policies.enterprise_search_policy.train"
|
|
790
|
+
".faiss.invalid_source_directory"
|
|
796
791
|
)
|
|
797
|
-
|
|
792
|
+
raise EnterpriseSearchPolicyError(code=error_code, event_info=error_message)
|
|
798
793
|
|
|
799
|
-
docs = glob.glob(os.path.join(docs_folder, "
|
|
794
|
+
docs = glob.glob(os.path.join(docs_folder, "**", "*.txt"), recursive=True)
|
|
800
795
|
if not docs or len(docs) < 1:
|
|
801
796
|
error_message = (
|
|
802
797
|
f"Document source directory is empty: '{docs_folder}'. "
|
|
803
798
|
"Please add documents to this directory or specify a different one."
|
|
804
799
|
)
|
|
805
|
-
|
|
806
|
-
"enterprise_search_policy.train
|
|
807
|
-
|
|
800
|
+
error_code = (
|
|
801
|
+
"core.policies.enterprise_search_policy.train"
|
|
802
|
+
".faiss.source_directory_empty"
|
|
808
803
|
)
|
|
809
|
-
|
|
804
|
+
raise EnterpriseSearchPolicyError(code=error_code, event_info=error_message)
|
|
810
805
|
|
|
811
806
|
@classmethod
|
|
812
807
|
def load(
|