rasa-pro 3.14.0.dev20250825__py3-none-any.whl → 3.14.0.dev20250922__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/builder/README.md +120 -0
- rasa/builder/__init__.py +0 -0
- rasa/builder/auth.py +176 -0
- rasa/builder/config.py +92 -0
- rasa/builder/copilot/__init__.py +0 -0
- rasa/builder/copilot/constants.py +31 -0
- rasa/builder/copilot/copilot.py +450 -0
- rasa/builder/copilot/copilot_response_handler.py +522 -0
- rasa/builder/copilot/copilot_templated_message_provider.py +58 -0
- rasa/builder/copilot/exceptions.py +32 -0
- rasa/builder/copilot/models.py +500 -0
- rasa/builder/copilot/prompts/__init__.py +0 -0
- rasa/builder/copilot/prompts/copilot_system_prompt.jinja2 +766 -0
- rasa/builder/copilot/prompts/latest_user_message_context_prompt.jinja2 +61 -0
- rasa/builder/copilot/signing.py +305 -0
- rasa/builder/copilot/telemetry.py +226 -0
- rasa/builder/copilot/templated_messages/__init__.py +0 -0
- rasa/builder/copilot/templated_messages/copilot_internal_messages_templates.yml +16 -0
- rasa/builder/copilot/templated_messages/copilot_templated_responses.yml +38 -0
- rasa/builder/document_retrieval/__init__.py +0 -0
- rasa/builder/document_retrieval/constants.py +15 -0
- rasa/builder/document_retrieval/inkeep-rag-response-schema.json +64 -0
- rasa/builder/document_retrieval/inkeep_document_retrieval.py +238 -0
- rasa/builder/document_retrieval/models.py +62 -0
- rasa/builder/download.py +140 -0
- rasa/builder/exceptions.py +91 -0
- rasa/builder/guardrails/__init__.py +1 -0
- rasa/builder/guardrails/constants.py +9 -0
- rasa/builder/guardrails/exceptions.py +4 -0
- rasa/builder/guardrails/lakera.py +206 -0
- rasa/builder/guardrails/models.py +231 -0
- rasa/builder/guardrails/store.py +238 -0
- rasa/builder/guardrails/utils.py +328 -0
- rasa/builder/job_manager.py +87 -0
- rasa/builder/jobs.py +282 -0
- rasa/builder/llm_service.py +246 -0
- rasa/builder/logging_utils.py +265 -0
- rasa/builder/main.py +234 -0
- rasa/builder/models.py +216 -0
- rasa/builder/project_generator.py +458 -0
- rasa/builder/project_info.py +72 -0
- rasa/builder/scrape_rasa_docs.py +97 -0
- rasa/builder/service.py +1350 -0
- rasa/builder/shared/tracker_context.py +212 -0
- rasa/builder/skill_to_bot_prompt.jinja2 +164 -0
- rasa/builder/template_cache.py +69 -0
- rasa/builder/training_service.py +194 -0
- rasa/builder/validation_service.py +97 -0
- rasa/cli/project_templates/basic/README.md +23 -0
- rasa/cli/project_templates/basic/actions/__init__ +0 -0
- rasa/cli/project_templates/basic/actions/action_human_handoff.py +40 -0
- rasa/cli/project_templates/basic/actions/actions.md +10 -0
- rasa/cli/project_templates/basic/config.yml +29 -0
- rasa/cli/project_templates/basic/credentials.yml +33 -0
- rasa/cli/project_templates/basic/data/data.md +8 -0
- rasa/cli/project_templates/basic/data/general/feedback.yml +21 -0
- rasa/cli/project_templates/basic/data/general/goodbye.yml +6 -0
- rasa/cli/project_templates/basic/data/general/hello.yml +6 -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/show_faqs.yml +6 -0
- rasa/cli/project_templates/basic/data/system/patterns/pattern_cannot_handle.yml +7 -0
- rasa/cli/project_templates/basic/data/system/patterns/pattern_completed.yml +7 -0
- rasa/cli/project_templates/basic/data/system/patterns/pattern_correction.yml +7 -0
- rasa/cli/project_templates/basic/data/system/patterns/pattern_search.yml +8 -0
- rasa/cli/project_templates/basic/data/system/patterns/pattern_session_start.yml +8 -0
- rasa/cli/project_templates/basic/docs/docs.md +5 -0
- rasa/cli/project_templates/basic/docs/template.txt +28 -0
- rasa/cli/project_templates/basic/domain/domain.md +11 -0
- rasa/cli/project_templates/basic/domain/general/feedback.yml +25 -0
- rasa/cli/project_templates/basic/domain/general/goodbye.yml +9 -0
- rasa/cli/project_templates/basic/domain/general/hello.yml +7 -0
- rasa/cli/project_templates/basic/domain/general/help.yml +21 -0
- rasa/cli/project_templates/basic/domain/general/human_handoff.yml +32 -0
- rasa/cli/project_templates/basic/domain/general/show_faqs.yml +14 -0
- rasa/cli/project_templates/basic/domain/system/patterns/pattern_cannot_handle.yml +5 -0
- rasa/cli/project_templates/basic/domain/system/patterns/pattern_session_start.yml +19 -0
- rasa/cli/project_templates/basic/endpoints.yml +67 -0
- rasa/cli/project_templates/basic/prompts/rephraser_demo_personality_prompt.jinja2 +38 -0
- rasa/cli/project_templates/default/config.yml +4 -0
- rasa/cli/project_templates/default/endpoints.yml +4 -0
- rasa/cli/project_templates/finance/README.md +26 -0
- rasa/cli/project_templates/finance/actions/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/accounts/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/accounts/check_balance.py +18 -0
- rasa/cli/project_templates/finance/actions/actions.md +15 -0
- rasa/cli/project_templates/finance/actions/cards/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/cards/check_that_card_exists.py +21 -0
- rasa/cli/project_templates/finance/actions/cards/list_cards.py +22 -0
- rasa/cli/project_templates/finance/actions/contacts/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/contacts/add_contact.py +30 -0
- rasa/cli/project_templates/finance/actions/contacts/list_contacts.py +22 -0
- rasa/cli/project_templates/finance/actions/contacts/remove_contact.py +35 -0
- rasa/cli/project_templates/finance/actions/db.py +117 -0
- rasa/cli/project_templates/finance/actions/general/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/general/action_human_handoff.py +49 -0
- rasa/cli/project_templates/finance/actions/transfers/__init__.py +0 -0
- rasa/cli/project_templates/finance/actions/transfers/check_transfer_funds.py +27 -0
- rasa/cli/project_templates/finance/actions/transfers/check_transfer_limit.py +36 -0
- rasa/cli/project_templates/finance/actions/transfers/execute_recurrent_payment.py +20 -0
- rasa/cli/project_templates/finance/actions/transfers/execute_transfer.py +45 -0
- rasa/cli/project_templates/finance/actions/transfers/list_transactions.py +32 -0
- rasa/cli/project_templates/finance/config.yml +29 -0
- rasa/cli/project_templates/finance/credentials.yml +33 -0
- rasa/cli/project_templates/finance/data/accounts/check_balance.yml +9 -0
- rasa/cli/project_templates/finance/data/accounts/download_statements.yml +26 -0
- rasa/cli/project_templates/finance/data/bills/bill_pay_reminder.yml +25 -0
- rasa/cli/project_templates/finance/data/cards/activate_card.yml +35 -0
- rasa/cli/project_templates/finance/data/cards/block_card.yml +45 -0
- rasa/cli/project_templates/finance/data/cards/list_cards.yml +14 -0
- rasa/cli/project_templates/finance/data/cards/replace_card.yml +16 -0
- rasa/cli/project_templates/finance/data/cards/replace_eligible_card.yml +29 -0
- rasa/cli/project_templates/finance/data/contacts/add_contact.yml +33 -0
- rasa/cli/project_templates/finance/data/contacts/list_contacts.yml +14 -0
- rasa/cli/project_templates/finance/data/contacts/remove_contact.yml +31 -0
- rasa/cli/project_templates/finance/data/data.md +14 -0
- rasa/cli/project_templates/finance/data/general/bot_challenge.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 +6 -0
- rasa/cli/project_templates/finance/data/general/help.yml +9 -0
- 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/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/system/patterns/pattern_session_start.yml +8 -0
- rasa/cli/project_templates/finance/data/transfers/check_transfer_limit.yml +18 -0
- rasa/cli/project_templates/finance/data/transfers/list_transactions.yml +46 -0
- rasa/cli/project_templates/finance/data/transfers/move_money_between_accounts.yml +51 -0
- rasa/cli/project_templates/finance/data/transfers/transfer_money.yml +34 -0
- rasa/cli/project_templates/finance/data/transfers/transfer_money_to_a_third_party.yml +175 -0
- rasa/cli/project_templates/finance/db/cards.json +18 -0
- rasa/cli/project_templates/finance/db/contacts.json +10 -0
- rasa/cli/project_templates/finance/db/my_account.json +6 -0
- rasa/cli/project_templates/finance/db/transactions.json +22 -0
- rasa/cli/project_templates/finance/docs/docs.md +8 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/account_features/budgeting_analytics.txt +22 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/account_features/multi_currency_accounts.txt +19 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/account_features/premium_benefits.txt +19 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/card_management/contactless_limits.txt +16 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/card_management/freeze_unfreeze_card.txt +16 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/card_management/lost_stolen_card.txt +19 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/money_transfers/instant_payments.txt +19 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/money_transfers/international_transfers.txt +19 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/security_fraud/fraud_protection.txt +22 -0
- rasa/cli/project_templates/finance/docs/fenlo_banking_faq/security_fraud/secure_payments.txt +22 -0
- rasa/cli/project_templates/finance/domain/accounts/check_balance.yml +15 -0
- rasa/cli/project_templates/finance/domain/accounts/download_statements.yml +40 -0
- rasa/cli/project_templates/finance/domain/bills/bill_pay_reminder.yml +49 -0
- rasa/cli/project_templates/finance/domain/cards/activate_card.yml +24 -0
- rasa/cli/project_templates/finance/domain/cards/block_card.yml +44 -0
- rasa/cli/project_templates/finance/domain/cards/list_cards.yml +16 -0
- rasa/cli/project_templates/finance/domain/cards/replace_card.yml +43 -0
- rasa/cli/project_templates/finance/domain/cards/shared.yml +15 -0
- rasa/cli/project_templates/finance/domain/contacts/add_contact.yml +37 -0
- rasa/cli/project_templates/finance/domain/contacts/list_contacts.yml +16 -0
- rasa/cli/project_templates/finance/domain/contacts/remove_contact.yml +32 -0
- rasa/cli/project_templates/finance/domain/domain.md +18 -0
- rasa/cli/project_templates/finance/domain/general/_shared.yml +39 -0
- rasa/cli/project_templates/finance/domain/general/bot_challenge.yml +4 -0
- rasa/cli/project_templates/finance/domain/general/cannot_handle.yml +8 -0
- rasa/cli/project_templates/finance/domain/general/feedback.yml +25 -0
- rasa/cli/project_templates/finance/domain/general/goodbye.yml +7 -0
- rasa/cli/project_templates/finance/domain/general/human_handoff.yml +31 -0
- rasa/cli/project_templates/finance/domain/general/welcome.yml +39 -0
- rasa/cli/project_templates/finance/domain/transfers/check_transfer_limit.yml +32 -0
- rasa/cli/project_templates/finance/domain/transfers/list_transactions.yml +44 -0
- rasa/cli/project_templates/finance/domain/transfers/shared.yml +17 -0
- rasa/cli/project_templates/finance/domain/transfers/transfer_money.yml +221 -0
- rasa/cli/project_templates/finance/endpoints.yml +67 -0
- rasa/cli/project_templates/finance/prompts/rephraser_demo_personality_prompt.jinja2 +38 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/accounts/check_balance.yml +9 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/accounts/download_statements.yml +43 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/cards/block_card.yml +55 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/bot_challenge.yml +8 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/feedback.yml +46 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/goodbye.yml +9 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/hello.yml +8 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/human_handoff.yml +35 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/general/patterns.yml +22 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/transfers/transfer_money.yml +56 -0
- rasa/cli/project_templates/telco/README.md +25 -0
- rasa/cli/project_templates/telco/actions/__init__.py +0 -0
- rasa/cli/project_templates/telco/actions/actions.md +12 -0
- rasa/cli/project_templates/telco/actions/billing/__init__.py +0 -0
- rasa/cli/project_templates/telco/actions/billing/actions_billing.py +204 -0
- rasa/cli/project_templates/telco/actions/general/__init__.py +0 -0
- rasa/cli/project_templates/telco/actions/general/action_human_handoff.py +49 -0
- rasa/cli/project_templates/telco/actions/network/__init__.py +0 -0
- rasa/cli/project_templates/telco/actions/network/actions_get_data_from_db.py +48 -0
- rasa/cli/project_templates/telco/actions/network/actions_run_diagnostics.py +28 -0
- rasa/cli/project_templates/telco/actions/network/actions_session_start.py +18 -0
- rasa/cli/project_templates/telco/config.yml +29 -0
- rasa/cli/project_templates/telco/credentials.yml +33 -0
- rasa/cli/project_templates/telco/csvs/billing.csv +19 -0
- rasa/cli/project_templates/telco/csvs/customers.csv +5 -0
- rasa/cli/project_templates/telco/data/billing/flow_understand_bill.yml +45 -0
- rasa/cli/project_templates/telco/data/data.md +11 -0
- rasa/cli/project_templates/telco/data/general/bot_challenge.yml +6 -0
- rasa/cli/project_templates/telco/data/general/feedback.yml +20 -0
- rasa/cli/project_templates/telco/data/general/goodbye.yml +6 -0
- rasa/cli/project_templates/telco/data/general/hello.yml +6 -0
- rasa/cli/project_templates/telco/data/general/human_handoff.yml +16 -0
- rasa/cli/project_templates/telco/data/general/patterns.yml +30 -0
- rasa/cli/project_templates/telco/data/network/flow_reboot_router.yml +8 -0
- rasa/cli/project_templates/telco/data/network/flow_reset_router.yml +7 -0
- rasa/cli/project_templates/telco/data/network/flow_solve_internet_issue.yml +73 -0
- rasa/cli/project_templates/telco/docs/docs.md +8 -0
- rasa/cli/project_templates/telco/docs/network/reset_vs_rboot_router.txt +1 -0
- rasa/cli/project_templates/telco/docs/network/restart_router.txt +6 -0
- rasa/cli/project_templates/telco/docs/network/run_speed_test.txt +6 -0
- rasa/cli/project_templates/telco/domain/billing/understand_bill.yml +102 -0
- rasa/cli/project_templates/telco/domain/domain.md +13 -0
- rasa/cli/project_templates/telco/domain/general/bot_challenge.yml +4 -0
- rasa/cli/project_templates/telco/domain/general/feedback.yml +25 -0
- rasa/cli/project_templates/telco/domain/general/goodbye.yml +7 -0
- rasa/cli/project_templates/telco/domain/general/hello.yml +5 -0
- rasa/cli/project_templates/telco/domain/general/human_handoff.yml +26 -0
- rasa/cli/project_templates/telco/domain/general/patterns.yml +33 -0
- rasa/cli/project_templates/telco/domain/network/reboot_router.yml +21 -0
- rasa/cli/project_templates/telco/domain/network/reset_router.yml +12 -0
- rasa/cli/project_templates/telco/domain/network/run_speed_test.yml +25 -0
- rasa/cli/project_templates/telco/domain/network/solve_internet_issue.yml +75 -0
- rasa/cli/project_templates/telco/domain/shared.yml +129 -0
- rasa/cli/project_templates/telco/endpoints.yml +67 -0
- rasa/cli/project_templates/telco/prompts/rephraser_demo_personality_prompt.jinja2 +40 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/billing/understand_bill.yml +67 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/general/bot_challenge.yml +8 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/general/feedback.yml +46 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/general/goodbye.yml +9 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/general/hello.yml +8 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/general/human_handoff.yml +35 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/general/patterns.yml +23 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/network/solve_internet_issue.yml +57 -0
- rasa/cli/project_templates/tutorial/config.yml +2 -1
- rasa/cli/scaffold.py +46 -2
- rasa/core/actions/action.py +0 -1
- rasa/core/actions/action_run_slot_rejections.py +1 -1
- rasa/core/actions/direct_custom_actions_executor.py +9 -2
- rasa/core/brokers/broker.py +1 -1
- rasa/core/brokers/kafka.py +52 -8
- rasa/core/channels/development_inspector.py +1 -21
- rasa/core/channels/hangouts.py +2 -2
- rasa/core/channels/inspector/dist/assets/{arc-1ddec37b.js → arc-35222594.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-18af387c.js → blockDiagram-38ab4fdb-a0efbfd3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-250127a3.js → c4Diagram-3d4e48cf-0584c0f2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-8e08bed9.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-c3388b34.js → classDiagram-70f12bd4-39f40dbe.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-9c893a82.js → classDiagram-v2-f2320105-1ad755f3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-78c82dea.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-c111213b.js → createText-2e5e7dd3-b0f4f0fe.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-812a729d.js → edges-e0da2a9e-9039bff9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-fd5051bc.js → erDiagram-9861fffd-65c9b127.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-3287ac02.js → flowDb-956e92f1-4f08b38e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-692fb0b2.js → flowDiagram-66a62f08-e95c362a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-2b08f601.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-008376f1.js → flowchart-elk-definition-4a651766-703c3015.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-df330a69.js → ganttDiagram-c361ad54-699328ea.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-e03676fb.js → gitGraphDiagram-72cf32ee-04cf4b05.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-46fad2ba.js → graph-ee94449e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-a484ac55.js → index-3862675e-940162b4.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-a003633f.js → index-c941dcb3.js} +239 -238
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-3f9e6ec2.js → infoDiagram-f8f76790-c79c2866.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-79f72383.js → journeyDiagram-49397b02-84489d30.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-aad098e5.js → layout-a9aa9858.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-219ab7ae.js → line-eb73cf26.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-2cddbe62.js → linear-b3399f9a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-1d41ed99.js → mindmap-definition-fc14e90a-b095bf1a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-cc496ee8.js → pieDiagram-8a3498a8-07644b66.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-84d32884.js → quadrantDiagram-120e2f19-573a3f9c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-c0deb984.js → requirementDiagram-deff3bca-d457e1e1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-b9d7fd62.js → sankeyDiagram-04a897e0-9d26e1a2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-7d517565.js → sequenceDiagram-704730f1-3a9cde10.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-98ef9b27.js → stateDiagram-587899a1-4f3e8cec.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-cee70748.js → stateDiagram-v2-d93cdb3a-e617e5bf.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-3f9d1c96.js → styles-6aaf32cf-eab30d2f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-67471923.js → styles-9a916d00-09994be2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-bd093fb7.js → styles-c10674c1-b7110364.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-675794e8.js → svgDrawCommon-08f97a94-3ebc92ad.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-0ac67617.js → timeline-definition-85554ec2-7d13d2f2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-c018dc37.js → xychartDiagram-e933f94c-488385e1.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +2 -2
- rasa/core/channels/inspector/index.html +1 -1
- rasa/core/channels/inspector/src/App.tsx +15 -42
- rasa/core/channels/inspector/src/components/Chat.tsx +2 -3
- rasa/core/channels/inspector/src/components/DialogueInformation.tsx +20 -3
- rasa/core/channels/inspector/src/components/LatencyDisplay.tsx +63 -35
- rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +14 -0
- rasa/core/channels/inspector/src/types.ts +32 -7
- rasa/core/channels/studio_chat.py +43 -43
- rasa/core/channels/voice_stream/asr/asr_event.py +1 -1
- rasa/core/channels/voice_stream/asr/azure.py +6 -3
- rasa/core/channels/voice_stream/asr/deepgram.py +1 -1
- rasa/core/channels/voice_stream/audiocodes.py +3 -0
- rasa/core/channels/voice_stream/browser_audio.py +55 -3
- rasa/core/channels/voice_stream/genesys.py +2 -1
- rasa/core/channels/voice_stream/jambonz.py +9 -1
- rasa/core/channels/voice_stream/twilio_media_streams.py +16 -0
- rasa/core/channels/voice_stream/voice_channel.py +61 -0
- rasa/core/concurrent_lock_store.py +66 -16
- rasa/core/constants.py +7 -0
- rasa/core/iam_credentials_providers/__init__.py +0 -0
- rasa/core/iam_credentials_providers/aws_iam_credentials_providers.py +226 -0
- rasa/core/iam_credentials_providers/credentials_provider_protocol.py +90 -0
- rasa/core/lock_store.py +46 -10
- rasa/core/nlg/generator.py +1 -1
- rasa/core/policies/enterprise_search_policy.py +4 -7
- rasa/core/policies/flows/flow_executor.py +9 -2
- rasa/core/processor.py +32 -0
- rasa/core/redis_connection_factory.py +469 -0
- rasa/core/tracker_stores/redis_tracker_store.py +32 -14
- rasa/core/tracker_stores/sql_tracker_store.py +57 -1
- rasa/dialogue_understanding/generator/flow_retrieval.py +10 -9
- rasa/engine/graph.py +5 -1
- rasa/engine/loader.py +12 -0
- rasa/engine/storage/local_model_storage.py +83 -3
- rasa/model_manager/model_api.py +1 -2
- rasa/model_manager/runner_service.py +1 -1
- rasa/model_manager/socket_bridge.py +1 -2
- rasa/model_manager/trainer_service.py +12 -9
- rasa/model_manager/utils.py +1 -29
- rasa/model_manager/warm_rasa_process.py +13 -3
- rasa/shared/core/constants.py +1 -0
- rasa/shared/core/domain.py +62 -15
- rasa/shared/core/events.py +2 -0
- rasa/shared/core/flows/flow.py +1 -1
- rasa/shared/core/flows/flow_step.py +7 -1
- rasa/shared/core/flows/steps/call.py +8 -1
- rasa/shared/core/flows/yaml_flows_io.py +16 -8
- rasa/shared/core/slots.py +4 -0
- rasa/shared/importers/importer.py +6 -0
- rasa/shared/importers/utils.py +77 -1
- rasa/shared/nlu/training_data/schemas/responses.yml +3 -0
- rasa/studio/upload.py +12 -46
- rasa/telemetry.py +97 -23
- rasa/utils/io.py +27 -9
- rasa/utils/json_utils.py +6 -1
- rasa/utils/log_utils.py +5 -1
- rasa/utils/openapi.py +144 -0
- rasa/utils/pypred.py +38 -0
- rasa/validator.py +19 -11
- rasa/version.py +1 -1
- {rasa_pro-3.14.0.dev20250825.dist-info → rasa_pro-3.14.0.dev20250922.dist-info}/METADATA +27 -25
- {rasa_pro-3.14.0.dev20250825.dist-info → rasa_pro-3.14.0.dev20250922.dist-info}/RECORD +348 -109
- rasa/core/channels/inspector/dist/assets/channel-59f6d54b.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-26177ddb.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-29c03f5a.js +0 -1
- {rasa_pro-3.14.0.dev20250825.dist-info → rasa_pro-3.14.0.dev20250922.dist-info}/NOTICE +0 -0
- {rasa_pro-3.14.0.dev20250825.dist-info → rasa_pro-3.14.0.dev20250922.dist-info}/WHEEL +0 -0
- {rasa_pro-3.14.0.dev20250825.dist-info → rasa_pro-3.14.0.dev20250922.dist-info}/entry_points.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import os
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Any, AsyncIterator, Dict, Optional
|
|
4
|
+
from typing import TYPE_CHECKING, Any, AsyncIterator, Dict, Optional
|
|
5
5
|
|
|
6
6
|
import structlog
|
|
7
7
|
|
|
@@ -15,6 +15,9 @@ from rasa.core.channels.voice_stream.audio_bytes import HERTZ, RasaAudioBytes
|
|
|
15
15
|
from rasa.shared.constants import AZURE_SPEECH_API_KEY_ENV_VAR
|
|
16
16
|
from rasa.shared.exceptions import ConnectionException
|
|
17
17
|
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from azure.cognitiveservices.speech import SpeechRecognitionEventArgs
|
|
20
|
+
|
|
18
21
|
logger = structlog.get_logger(__name__)
|
|
19
22
|
|
|
20
23
|
|
|
@@ -43,9 +46,9 @@ class AzureASR(ASREngine[AzureASRConfig]):
|
|
|
43
46
|
)
|
|
44
47
|
self.main_loop = asyncio.get_running_loop()
|
|
45
48
|
|
|
46
|
-
def signal_user_is_speaking(self, event:
|
|
49
|
+
def signal_user_is_speaking(self, event: "SpeechRecognitionEventArgs") -> None:
|
|
47
50
|
"""Replace the azure event with a generic is speaking event."""
|
|
48
|
-
self.fill_queue(UserIsSpeaking())
|
|
51
|
+
self.fill_queue(UserIsSpeaking(event.result.text))
|
|
49
52
|
|
|
50
53
|
def fill_queue(self, event: Any) -> None:
|
|
51
54
|
"""Either puts the event or a dedicated ASR Event into the queue."""
|
|
@@ -117,7 +117,7 @@ class DeepgramASR(ASREngine[DeepgramASRConfig]):
|
|
|
117
117
|
self.accumulated_transcript, transcript
|
|
118
118
|
)
|
|
119
119
|
elif transcript:
|
|
120
|
-
return UserIsSpeaking()
|
|
120
|
+
return UserIsSpeaking(transcript)
|
|
121
121
|
# event that comes after utterance_end_ms of no new transcript
|
|
122
122
|
elif data_type == "UtteranceEnd":
|
|
123
123
|
if self.accumulated_transcript:
|
|
@@ -89,6 +89,7 @@ class AudiocodesVoiceOutputChannel(VoiceOutputChannel):
|
|
|
89
89
|
# This is an approximation, as the bot will be sent the audio chunks next
|
|
90
90
|
# which are played to the user immediately.
|
|
91
91
|
call_state.is_bot_speaking = True
|
|
92
|
+
VoiceInputChannel._cancel_silence_timeout_watcher()
|
|
92
93
|
|
|
93
94
|
async def send_intermediate_marker(self, recipient_id: str) -> None:
|
|
94
95
|
"""Audiocodes doesn't need intermediate markers, so do nothing."""
|
|
@@ -116,6 +117,7 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
|
|
|
116
117
|
server_url: str,
|
|
117
118
|
asr_config: Dict,
|
|
118
119
|
tts_config: Dict,
|
|
120
|
+
interruptions: Optional[Dict[str, int]] = None,
|
|
119
121
|
token: Optional[Text] = None,
|
|
120
122
|
):
|
|
121
123
|
mark_as_beta_feature("Audiocodes (audiocodes_stream) Channel")
|
|
@@ -123,6 +125,7 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
|
|
|
123
125
|
server_url=server_url,
|
|
124
126
|
asr_config=asr_config,
|
|
125
127
|
tts_config=tts_config,
|
|
128
|
+
interruptions=interruptions,
|
|
126
129
|
)
|
|
127
130
|
self.token = token
|
|
128
131
|
|
|
@@ -3,7 +3,9 @@ from __future__ import annotations
|
|
|
3
3
|
import audioop
|
|
4
4
|
import base64
|
|
5
5
|
import json
|
|
6
|
+
import os
|
|
6
7
|
import uuid
|
|
8
|
+
import wave
|
|
7
9
|
from typing import Any, Awaitable, Callable, Dict, Optional, Tuple
|
|
8
10
|
|
|
9
11
|
import structlog
|
|
@@ -69,11 +71,48 @@ class BrowserAudioOutputChannel(VoiceOutputChannel):
|
|
|
69
71
|
|
|
70
72
|
|
|
71
73
|
class BrowserAudioInputChannel(VoiceInputChannel):
|
|
74
|
+
requires_voice_license = False
|
|
75
|
+
|
|
72
76
|
def __init__(
|
|
73
|
-
self,
|
|
77
|
+
self,
|
|
78
|
+
server_url: str,
|
|
79
|
+
asr_config: Dict[str, Any],
|
|
80
|
+
tts_config: Dict[str, Any],
|
|
81
|
+
recording: bool = False,
|
|
82
|
+
interruptions: Optional[Dict[str, int]] = None,
|
|
74
83
|
) -> None:
|
|
75
84
|
"""Initializes the browser audio input channel."""
|
|
76
|
-
super().__init__(server_url, asr_config, tts_config)
|
|
85
|
+
super().__init__(server_url, asr_config, tts_config, interruptions)
|
|
86
|
+
|
|
87
|
+
# For debugging, recording of user audio might be useful
|
|
88
|
+
# to identify audio quality issues or transcription errors
|
|
89
|
+
self._recording_enabled = recording
|
|
90
|
+
self._wav_file: Optional[wave.Wave_write] = None
|
|
91
|
+
|
|
92
|
+
def _start_recording(self, call_id: str, user_id: str) -> None:
|
|
93
|
+
os.makedirs("recordings", exist_ok=True)
|
|
94
|
+
filename = f"{user_id}_{call_id}.wav"
|
|
95
|
+
file_path = os.path.join("recordings", filename)
|
|
96
|
+
|
|
97
|
+
if not self._recording_enabled:
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
self._wav_file = wave.open(file_path, "wb")
|
|
101
|
+
self._wav_file.setnchannels(1) # Mono audio
|
|
102
|
+
self._wav_file.setsampwidth(4) # 32-bit audio (4 bytes)
|
|
103
|
+
self._wav_file.setframerate(8000) # 8kHz sample rate
|
|
104
|
+
logger.info("voice_channel.user_audio_recording.started", file_path=file_path)
|
|
105
|
+
|
|
106
|
+
def _append_audio_to_recording(self, audio_bytes: bytes) -> None:
|
|
107
|
+
if self._wav_file and self._recording_enabled:
|
|
108
|
+
self._wav_file.writeframes(audio_bytes)
|
|
109
|
+
|
|
110
|
+
def _stop_recording(self) -> None:
|
|
111
|
+
"""Close the recording file if it's open."""
|
|
112
|
+
if self._wav_file:
|
|
113
|
+
self._wav_file.close()
|
|
114
|
+
self._wav_file = None
|
|
115
|
+
logger.debug("voice_channel.user_audio_recording.stopped")
|
|
77
116
|
|
|
78
117
|
@classmethod
|
|
79
118
|
def name(cls) -> str:
|
|
@@ -94,7 +133,7 @@ class BrowserAudioInputChannel(VoiceInputChannel):
|
|
|
94
133
|
credentials: Optional[Dict[str, Any]],
|
|
95
134
|
) -> BrowserAudioInputChannel:
|
|
96
135
|
cls.validate_basic_credentials(credentials)
|
|
97
|
-
new_creds = repack_voice_credentials(credentials)
|
|
136
|
+
new_creds = repack_voice_credentials(credentials or {})
|
|
98
137
|
return cls(**new_creds)
|
|
99
138
|
|
|
100
139
|
def map_input_message(
|
|
@@ -105,6 +144,7 @@ class BrowserAudioInputChannel(VoiceInputChannel):
|
|
|
105
144
|
data = json.loads(message)
|
|
106
145
|
if "audio" in data:
|
|
107
146
|
channel_bytes = base64.b64decode(data["audio"])
|
|
147
|
+
self._append_audio_to_recording(channel_bytes)
|
|
108
148
|
audio_bytes = self.channel_bytes_to_rasa_audio_bytes(channel_bytes)
|
|
109
149
|
return NewAudioAction(audio_bytes)
|
|
110
150
|
elif "marker" in data:
|
|
@@ -120,6 +160,13 @@ class BrowserAudioInputChannel(VoiceInputChannel):
|
|
|
120
160
|
call_state.is_bot_speaking = True
|
|
121
161
|
return ContinueConversationAction()
|
|
122
162
|
|
|
163
|
+
async def interrupt_playback(
|
|
164
|
+
self, ws: Websocket, call_parameters: CallParameters
|
|
165
|
+
) -> None:
|
|
166
|
+
"""Interrupt the current playback of audio."""
|
|
167
|
+
logger.debug("browser_audio.interrupt_playback")
|
|
168
|
+
await ws.send(json.dumps({"interruptPlayback": True}))
|
|
169
|
+
|
|
123
170
|
def create_output_channel(
|
|
124
171
|
self, voice_websocket: Websocket, tts_engine: TTSEngine
|
|
125
172
|
) -> VoiceOutputChannel:
|
|
@@ -142,8 +189,13 @@ class BrowserAudioInputChannel(VoiceInputChannel):
|
|
|
142
189
|
@blueprint.websocket("/websocket") # type: ignore
|
|
143
190
|
async def handle_message(request: Request, ws: Websocket) -> None:
|
|
144
191
|
try:
|
|
192
|
+
call_parameters = await self.collect_call_parameters(ws)
|
|
193
|
+
if call_parameters and call_parameters.call_id:
|
|
194
|
+
self._start_recording(call_parameters.call_id, "local")
|
|
145
195
|
await self.run_audio_streaming(on_new_message, ws)
|
|
146
196
|
except Exception as e:
|
|
147
197
|
logger.error("browser_audio.handle_message.error", error=e)
|
|
198
|
+
finally:
|
|
199
|
+
self._stop_recording()
|
|
148
200
|
|
|
149
201
|
return blueprint
|
|
@@ -99,10 +99,11 @@ class GenesysInputChannel(VoiceInputChannel):
|
|
|
99
99
|
server_url: str,
|
|
100
100
|
asr_config: Dict,
|
|
101
101
|
tts_config: Dict,
|
|
102
|
+
interruptions: Optional[Dict[str, int]] = None,
|
|
102
103
|
api_key: Optional[Text] = None,
|
|
103
104
|
client_secret: Optional[Text] = None,
|
|
104
105
|
) -> None:
|
|
105
|
-
super().__init__(server_url, asr_config, tts_config)
|
|
106
|
+
super().__init__(server_url, asr_config, tts_config, interruptions)
|
|
106
107
|
self.api_key = api_key
|
|
107
108
|
self.client_secret = client_secret
|
|
108
109
|
|
|
@@ -81,6 +81,7 @@ class JambonzStreamInputChannel(VoiceInputChannel):
|
|
|
81
81
|
server_url: str,
|
|
82
82
|
asr_config: Dict,
|
|
83
83
|
tts_config: Dict,
|
|
84
|
+
interruptions: Optional[Dict[str, int]] = None,
|
|
84
85
|
username: Optional[Text] = None,
|
|
85
86
|
password: Optional[Text] = None,
|
|
86
87
|
) -> None:
|
|
@@ -90,7 +91,7 @@ class JambonzStreamInputChannel(VoiceInputChannel):
|
|
|
90
91
|
username: Optional username for basic auth
|
|
91
92
|
password: Optional password for basic auth
|
|
92
93
|
"""
|
|
93
|
-
super().__init__(server_url, asr_config, tts_config)
|
|
94
|
+
super().__init__(server_url, asr_config, tts_config, interruptions)
|
|
94
95
|
self.username = username
|
|
95
96
|
self.password = password
|
|
96
97
|
|
|
@@ -185,6 +186,13 @@ class JambonzStreamInputChannel(VoiceInputChannel):
|
|
|
185
186
|
self.tts_cache,
|
|
186
187
|
)
|
|
187
188
|
|
|
189
|
+
async def interrupt_playback(
|
|
190
|
+
self, ws: Websocket, call_parameters: CallParameters
|
|
191
|
+
) -> None:
|
|
192
|
+
"""Interrupt the current playback of audio."""
|
|
193
|
+
logger.debug("jambonz.interrupt_playback")
|
|
194
|
+
await ws.send(json.dumps({"type": "killAudio"}))
|
|
195
|
+
|
|
188
196
|
def blueprint(
|
|
189
197
|
self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
|
|
190
198
|
) -> Blueprint:
|
|
@@ -105,6 +105,7 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
105
105
|
server_url: str,
|
|
106
106
|
asr_config: Dict,
|
|
107
107
|
tts_config: Dict,
|
|
108
|
+
interruptions: Optional[Dict[str, int]] = None,
|
|
108
109
|
username: Optional[Text] = None,
|
|
109
110
|
password: Optional[Text] = None,
|
|
110
111
|
):
|
|
@@ -112,6 +113,7 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
112
113
|
server_url=server_url,
|
|
113
114
|
asr_config=asr_config,
|
|
114
115
|
tts_config=tts_config,
|
|
116
|
+
interruptions=interruptions,
|
|
115
117
|
)
|
|
116
118
|
self.username = username
|
|
117
119
|
self.password = password
|
|
@@ -195,6 +197,20 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
195
197
|
self.tts_cache,
|
|
196
198
|
)
|
|
197
199
|
|
|
200
|
+
async def interrupt_playback(
|
|
201
|
+
self, ws: Websocket, call_parameters: CallParameters
|
|
202
|
+
) -> None:
|
|
203
|
+
"""Interrupt the current playback of audio."""
|
|
204
|
+
logger.debug("twilio_media_streams.interrupt_playback")
|
|
205
|
+
await ws.send(
|
|
206
|
+
json.dumps(
|
|
207
|
+
{
|
|
208
|
+
"event": "clear",
|
|
209
|
+
"streamSid": call_parameters.stream_id,
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
)
|
|
213
|
+
|
|
198
214
|
def blueprint(
|
|
199
215
|
self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
|
|
200
216
|
) -> Blueprint:
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import copy
|
|
5
|
+
import string
|
|
5
6
|
import time
|
|
6
7
|
from dataclasses import asdict, dataclass
|
|
7
8
|
from typing import Any, AsyncIterator, Awaitable, Callable, Dict, List, Optional, Tuple
|
|
@@ -53,6 +54,13 @@ from rasa.utils.io import remove_emojis
|
|
|
53
54
|
logger = structlog.get_logger(__name__)
|
|
54
55
|
|
|
55
56
|
# define constants for the voice channel
|
|
57
|
+
DEFAULT_INTERRUPTION_MIN_WORDS = 3
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass
|
|
61
|
+
class InterruptionConfig:
|
|
62
|
+
enabled: bool = False
|
|
63
|
+
min_words: int = DEFAULT_INTERRUPTION_MIN_WORDS
|
|
56
64
|
|
|
57
65
|
|
|
58
66
|
@dataclass
|
|
@@ -270,6 +278,10 @@ class VoiceOutputChannel(OutputChannel):
|
|
|
270
278
|
except (WebsocketClosed, ServerError):
|
|
271
279
|
call_state.connection_failed = True
|
|
272
280
|
|
|
281
|
+
# Is the response interruptible?
|
|
282
|
+
allow_interruptions = kwargs.get("allow_interruptions", True)
|
|
283
|
+
call_state.channel_data["allow_interruptions"] = allow_interruptions
|
|
284
|
+
|
|
273
285
|
if cached_audio_bytes:
|
|
274
286
|
audio_stream = self.chunk_audio(cached_audio_bytes)
|
|
275
287
|
else:
|
|
@@ -368,6 +380,7 @@ class VoiceInputChannel(InputChannel):
|
|
|
368
380
|
server_url: str,
|
|
369
381
|
asr_config: Dict,
|
|
370
382
|
tts_config: Dict,
|
|
383
|
+
interruptions: Optional[Dict[str, Any]] = None,
|
|
371
384
|
):
|
|
372
385
|
if self.requires_voice_license:
|
|
373
386
|
validate_voice_license_scope()
|
|
@@ -376,12 +389,21 @@ class VoiceInputChannel(InputChannel):
|
|
|
376
389
|
self.asr_config = asr_config
|
|
377
390
|
self.tts_config = tts_config
|
|
378
391
|
self.tts_cache = TTSCache(tts_config.get("cache_size", 1000))
|
|
392
|
+
if interruptions:
|
|
393
|
+
self.interruption_config = InterruptionConfig(**interruptions)
|
|
394
|
+
else:
|
|
395
|
+
self.interruption_config = InterruptionConfig()
|
|
396
|
+
|
|
397
|
+
if self.interruption_config.enabled:
|
|
398
|
+
mark_as_beta_feature(f"Interruption Handling in {self.name()}")
|
|
379
399
|
|
|
380
400
|
logger.info(
|
|
381
401
|
"voice_channel.initialized",
|
|
402
|
+
name=self.name(),
|
|
382
403
|
server_url=self.server_url,
|
|
383
404
|
asr_config=self.asr_config,
|
|
384
405
|
tts_config=self.tts_config,
|
|
406
|
+
interruption_config=self.interruption_config,
|
|
385
407
|
)
|
|
386
408
|
|
|
387
409
|
def get_sender_id(self, call_parameters: CallParameters) -> str:
|
|
@@ -463,6 +485,43 @@ class VoiceInputChannel(InputChannel):
|
|
|
463
485
|
"""Map a channel input message to a voice channel action."""
|
|
464
486
|
raise NotImplementedError
|
|
465
487
|
|
|
488
|
+
def should_interrupt(self, e: ASREvent) -> bool:
|
|
489
|
+
"""Determine if the current ASR event should interrupt playback.
|
|
490
|
+
Returns True if the bot response is interruptible
|
|
491
|
+
And if the user spoke more than 3 words.
|
|
492
|
+
|
|
493
|
+
Arguments:
|
|
494
|
+
e: The ASR event to evaluate.
|
|
495
|
+
|
|
496
|
+
Returns:
|
|
497
|
+
True if the event should interrupt playback, False otherwise.
|
|
498
|
+
"""
|
|
499
|
+
# Are interruptions are enabled for the channel?
|
|
500
|
+
if not self.interruption_config.enabled:
|
|
501
|
+
return False
|
|
502
|
+
|
|
503
|
+
# Is the bot response interruptible?
|
|
504
|
+
if not call_state.channel_data.get("allow_interruptions", True):
|
|
505
|
+
return False
|
|
506
|
+
|
|
507
|
+
# Did the user speak more than 3 words?
|
|
508
|
+
min_words = self.interruption_config.min_words
|
|
509
|
+
if isinstance(e, UserIsSpeaking):
|
|
510
|
+
translator = str.maketrans("", "", string.punctuation)
|
|
511
|
+
words = e.text.translate(translator).split()
|
|
512
|
+
return len(words) >= min_words
|
|
513
|
+
return False
|
|
514
|
+
|
|
515
|
+
async def interrupt_playback(
|
|
516
|
+
self, ws: Websocket, call_parameters: CallParameters
|
|
517
|
+
) -> None:
|
|
518
|
+
"""Interrupt the current playback of audio.
|
|
519
|
+
|
|
520
|
+
This function is used for interruption handling.
|
|
521
|
+
As not all channels support flushing bot audio buffer,
|
|
522
|
+
if a channel does not implement it. It has no effect."""
|
|
523
|
+
pass
|
|
524
|
+
|
|
466
525
|
async def run_audio_streaming(
|
|
467
526
|
self,
|
|
468
527
|
on_new_message: Callable[[UserMessage], Awaitable[Any]],
|
|
@@ -598,6 +657,8 @@ class VoiceInputChannel(InputChannel):
|
|
|
598
657
|
call_state.user_speech_start_time = time.time()
|
|
599
658
|
self._cancel_silence_timeout_watcher()
|
|
600
659
|
call_state.is_user_speaking = True
|
|
660
|
+
if self.should_interrupt(e):
|
|
661
|
+
await self.interrupt_playback(voice_websocket, call_parameters)
|
|
601
662
|
elif isinstance(e, UserSilence):
|
|
602
663
|
output_channel = self.create_output_channel(voice_websocket, tts_engine)
|
|
603
664
|
message = UserMessage(
|
|
@@ -4,6 +4,7 @@ from collections import deque
|
|
|
4
4
|
from typing import Deque, Optional, Text
|
|
5
5
|
|
|
6
6
|
import structlog
|
|
7
|
+
from pydantic import ValidationError
|
|
7
8
|
|
|
8
9
|
from rasa.core.lock import Ticket, TicketLock
|
|
9
10
|
from rasa.core.lock_store import (
|
|
@@ -12,6 +13,12 @@ from rasa.core.lock_store import (
|
|
|
12
13
|
LockError,
|
|
13
14
|
LockStore,
|
|
14
15
|
)
|
|
16
|
+
from rasa.core.redis_connection_factory import (
|
|
17
|
+
DeploymentMode,
|
|
18
|
+
RedisConfig,
|
|
19
|
+
RedisConnectionFactory,
|
|
20
|
+
)
|
|
21
|
+
from rasa.shared.exceptions import RasaException
|
|
15
22
|
from rasa.utils.endpoints import EndpointConfig
|
|
16
23
|
|
|
17
24
|
DEFAULT_REDIS_DB = 1
|
|
@@ -74,9 +81,10 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
74
81
|
alphanumeric.
|
|
75
82
|
socket_timeout - Timeout in seconds after which an exception will be raised
|
|
76
83
|
in case Redis doesn't respond within `socket_timeout` seconds.
|
|
84
|
+
deployment_mode - Redis deployment mode: standard, cluster, or sentinel.
|
|
85
|
+
endpoints - List of endpoints for cluster/sentinel mode in host:port format.
|
|
86
|
+
sentinel_service - Sentinel service name.
|
|
77
87
|
"""
|
|
78
|
-
import redis
|
|
79
|
-
|
|
80
88
|
host = endpoint_config.kwargs.get("host", DEFAULT_HOSTNAME)
|
|
81
89
|
port = endpoint_config.kwargs.get("port", DEFAULT_PORT)
|
|
82
90
|
db = endpoint_config.kwargs.get("db", DEFAULT_REDIS_DB)
|
|
@@ -90,20 +98,33 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
90
98
|
socket_timeout = endpoint_config.kwargs.get(
|
|
91
99
|
"socket_timeout", DEFAULT_SOCKET_TIMEOUT_IN_SECONDS
|
|
92
100
|
)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
host=host,
|
|
96
|
-
port=int(port),
|
|
97
|
-
db=int(db),
|
|
98
|
-
username=username,
|
|
99
|
-
password=password,
|
|
100
|
-
ssl=use_ssl,
|
|
101
|
-
ssl_certfile=ssl_certfile,
|
|
102
|
-
ssl_keyfile=ssl_keyfile,
|
|
103
|
-
ssl_ca_certs=ssl_ca_certs,
|
|
104
|
-
socket_timeout=socket_timeout,
|
|
101
|
+
deployment_mode = endpoint_config.kwargs.get(
|
|
102
|
+
"deployment_mode", DeploymentMode.STANDARD.value
|
|
105
103
|
)
|
|
104
|
+
endpoints = endpoint_config.kwargs.get("endpoints", [])
|
|
105
|
+
sentinel_service = endpoint_config.kwargs.get("sentinel_service")
|
|
106
106
|
|
|
107
|
+
try:
|
|
108
|
+
redis_config = RedisConfig(
|
|
109
|
+
host=host,
|
|
110
|
+
port=port,
|
|
111
|
+
db=db,
|
|
112
|
+
username=username,
|
|
113
|
+
password=password,
|
|
114
|
+
use_ssl=use_ssl,
|
|
115
|
+
ssl_certfile=ssl_certfile,
|
|
116
|
+
ssl_keyfile=ssl_keyfile,
|
|
117
|
+
ssl_ca_certs=ssl_ca_certs,
|
|
118
|
+
socket_timeout=socket_timeout,
|
|
119
|
+
deployment_mode=deployment_mode,
|
|
120
|
+
endpoints=endpoints,
|
|
121
|
+
sentinel_service=sentinel_service,
|
|
122
|
+
)
|
|
123
|
+
self.red = RedisConnectionFactory.create_connection(redis_config)
|
|
124
|
+
except ValidationError as e:
|
|
125
|
+
raise RasaException(f"Invalid Redis configuration: {e}")
|
|
126
|
+
|
|
127
|
+
self.deployment_mode = deployment_mode
|
|
107
128
|
self.key_prefix = DEFAULT_CONCURRENT_REDIS_LOCK_STORE_KEY_PREFIX
|
|
108
129
|
if key_prefix:
|
|
109
130
|
structlogger.debug(
|
|
@@ -129,6 +150,32 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
129
150
|
),
|
|
130
151
|
)
|
|
131
152
|
|
|
153
|
+
def _get_keys_by_pattern(self, pattern: Text) -> list:
|
|
154
|
+
"""Get keys by pattern, using SCAN for cluster mode and KEYS for others."""
|
|
155
|
+
if self.deployment_mode == DeploymentMode.CLUSTER.value:
|
|
156
|
+
# In cluster mode, use SCAN to get keys more reliably
|
|
157
|
+
keys = []
|
|
158
|
+
cursor = 0
|
|
159
|
+
|
|
160
|
+
while True:
|
|
161
|
+
try:
|
|
162
|
+
cursor, batch_keys = self.red.scan(cursor, match=pattern, count=100)
|
|
163
|
+
keys.extend(batch_keys)
|
|
164
|
+
if cursor == 0:
|
|
165
|
+
break
|
|
166
|
+
except Exception as e:
|
|
167
|
+
structlogger.warning(
|
|
168
|
+
"concurrent_redis_lock_store._get_keys_by_pattern.scan_interrupted",
|
|
169
|
+
event_info=f"SCAN interrupted in cluster mode: {e}. "
|
|
170
|
+
f"Returning {len(keys)} keys found so far.",
|
|
171
|
+
)
|
|
172
|
+
break
|
|
173
|
+
else:
|
|
174
|
+
# Standard and sentinel modes use KEYS
|
|
175
|
+
keys = self.red.keys(pattern)
|
|
176
|
+
|
|
177
|
+
return keys
|
|
178
|
+
|
|
132
179
|
def issue_ticket(
|
|
133
180
|
self, conversation_id: Text, lock_lifetime: float = LOCK_LIFETIME
|
|
134
181
|
) -> int:
|
|
@@ -157,11 +204,14 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
157
204
|
tickets: Deque[Ticket] = deque()
|
|
158
205
|
|
|
159
206
|
pattern = self.key_prefix + conversation_id + ":" + "[0-9]*"
|
|
160
|
-
redis_keys = self.
|
|
207
|
+
redis_keys = self._get_keys_by_pattern(pattern)
|
|
161
208
|
|
|
162
209
|
for key in redis_keys:
|
|
163
210
|
serialised_ticket = self.red.get(key)
|
|
164
211
|
if serialised_ticket:
|
|
212
|
+
# Handle bytes to string conversion for JSON parsing
|
|
213
|
+
if isinstance(serialised_ticket, bytes):
|
|
214
|
+
serialised_ticket = serialised_ticket.decode("utf-8")
|
|
165
215
|
ticket = Ticket.from_dict(json.loads(serialised_ticket))
|
|
166
216
|
tickets.appendleft(ticket)
|
|
167
217
|
|
|
@@ -172,7 +222,7 @@ class ConcurrentRedisLockStore(LockStore):
|
|
|
172
222
|
def delete_lock(self, conversation_id: Text) -> None:
|
|
173
223
|
"""Deletes lock for conversation ID."""
|
|
174
224
|
pattern = self.key_prefix + conversation_id + ":*"
|
|
175
|
-
redis_keys = self.
|
|
225
|
+
redis_keys = self._get_keys_by_pattern(pattern)
|
|
176
226
|
|
|
177
227
|
if not redis_keys:
|
|
178
228
|
structlogger.debug(
|
rasa/core/constants.py
CHANGED
|
@@ -112,3 +112,10 @@ ACTIVE_FLOW_METADATA_KEY = "active_flow"
|
|
|
112
112
|
STEP_ID_METADATA_KEY = "step_id"
|
|
113
113
|
KEY_IS_CALM_SYSTEM = "is_calm_system"
|
|
114
114
|
KEY_IS_COEXISTENCE_ASSISTANT = "is_coexistence_assistant"
|
|
115
|
+
|
|
116
|
+
IAM_CLOUD_PROVIDER_ENV_VAR_NAME = "IAM_CLOUD_PROVIDER"
|
|
117
|
+
SQL_TRACKER_STORE_SSL_MODE_ENV_VAR_NAME = "SQL_TRACKER_STORE_SSL_MODE"
|
|
118
|
+
SQL_TRACKER_STORE_SSL_ROOT_CERTIFICATE_ENV_VAR_NAME = (
|
|
119
|
+
"SQL_TRACKER_STORE_SSL_ROOT_CERTIFICATE"
|
|
120
|
+
)
|
|
121
|
+
AWS_ELASTICACHE_CLUSTER_NAME_ENV_VAR_NAME = "AWS_ELASTICACHE_CLUSTER_NAME"
|
|
File without changes
|