rasa-pro 3.13.11__py3-none-any.whl → 3.14.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rasa-pro might be problematic. Click here for more details.
- rasa/__main__.py +15 -3
- rasa/agents/__init__.py +0 -0
- rasa/agents/agent_factory.py +122 -0
- rasa/agents/agent_manager.py +213 -0
- rasa/agents/constants.py +43 -0
- rasa/agents/core/__init__.py +0 -0
- rasa/agents/core/agent_protocol.py +107 -0
- rasa/agents/core/types.py +81 -0
- rasa/agents/exceptions.py +38 -0
- rasa/agents/protocol/__init__.py +5 -0
- rasa/agents/protocol/a2a/__init__.py +0 -0
- rasa/agents/protocol/a2a/a2a_agent.py +889 -0
- rasa/agents/protocol/mcp/__init__.py +0 -0
- rasa/agents/protocol/mcp/mcp_base_agent.py +778 -0
- rasa/agents/protocol/mcp/mcp_open_agent.py +327 -0
- rasa/agents/protocol/mcp/mcp_task_agent.py +522 -0
- rasa/agents/schemas/__init__.py +13 -0
- rasa/agents/schemas/agent_input.py +38 -0
- rasa/agents/schemas/agent_output.py +26 -0
- rasa/agents/schemas/agent_tool_result.py +65 -0
- rasa/agents/schemas/agent_tool_schema.py +186 -0
- rasa/agents/templates/__init__.py +0 -0
- rasa/agents/templates/mcp_open_agent_prompt_template.jinja2 +20 -0
- rasa/agents/templates/mcp_task_agent_prompt_template.jinja2 +22 -0
- rasa/agents/utils.py +228 -0
- rasa/agents/validation.py +538 -0
- rasa/api.py +23 -9
- rasa/builder/README.md +120 -0
- rasa/builder/__init__.py +0 -0
- rasa/builder/auth.py +176 -0
- rasa/builder/config.py +96 -0
- rasa/builder/copilot/__init__.py +0 -0
- rasa/builder/copilot/constants.py +38 -0
- rasa/builder/copilot/copilot.py +562 -0
- rasa/builder/copilot/copilot_response_handler.py +522 -0
- rasa/builder/copilot/copilot_templated_message_provider.py +81 -0
- rasa/builder/copilot/exceptions.py +32 -0
- rasa/builder/copilot/models.py +690 -0
- rasa/builder/copilot/prompts/__init__.py +0 -0
- rasa/builder/copilot/prompts/copilot_system_prompt.jinja2 +787 -0
- rasa/builder/copilot/prompts/copilot_training_error_handler_prompt.jinja2 +53 -0
- rasa/builder/copilot/prompts/latest_user_message_context_prompt.jinja2 +91 -0
- rasa/builder/copilot/signing.py +305 -0
- rasa/builder/copilot/telemetry.py +234 -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 +41 -0
- rasa/builder/copilot/templated_messages/copilot_welcome_messages.yml +56 -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/clients.py +256 -0
- rasa/builder/guardrails/constants.py +12 -0
- rasa/builder/guardrails/exceptions.py +4 -0
- rasa/builder/guardrails/models.py +266 -0
- rasa/builder/guardrails/policy_checker.py +324 -0
- rasa/builder/guardrails/store.py +238 -0
- rasa/builder/guardrails/utils.py +94 -0
- rasa/builder/job_manager.py +87 -0
- rasa/builder/jobs.py +609 -0
- rasa/builder/llm_service.py +273 -0
- rasa/builder/logging_utils.py +265 -0
- rasa/builder/main.py +234 -0
- rasa/builder/models.py +229 -0
- rasa/builder/project_generator.py +463 -0
- rasa/builder/project_info.py +72 -0
- rasa/builder/service.py +1367 -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 +188 -0
- rasa/builder/validation_service.py +101 -0
- rasa/cli/arguments/data.py +9 -0
- rasa/cli/arguments/default_arguments.py +12 -0
- rasa/cli/arguments/run.py +2 -0
- rasa/cli/arguments/train.py +2 -0
- rasa/cli/data.py +78 -10
- rasa/cli/dialogue_understanding_test.py +11 -7
- rasa/cli/e2e_test.py +10 -6
- rasa/cli/evaluate.py +4 -2
- rasa/cli/export.py +5 -2
- rasa/cli/inspect.py +9 -4
- rasa/cli/interactive.py +8 -4
- rasa/cli/llm_fine_tuning.py +12 -6
- 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/basic/tests/e2e_test_cases/without_stub/general/feedback.yml +46 -0
- rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/goodbye.yml +9 -0
- rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/hello.yml +8 -0
- rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/help.yml +8 -0
- rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/human_handoff.yml +41 -0
- rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/patterns.yml +32 -0
- rasa/cli/project_templates/basic/tests/e2e_test_cases/without_stub/general/show_faqs.yml +8 -0
- rasa/cli/project_templates/default/config.yml +4 -0
- rasa/cli/project_templates/default/endpoints.yml +4 -0
- rasa/cli/project_templates/defaults.py +1 -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/help.yml +0 -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/without_stub/accounts/check_balance.yml +9 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/accounts/download_statements.yml +43 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/cards/block_card.yml +55 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/general/bot_challenge.yml +8 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/general/feedback.yml +46 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/general/goodbye.yml +9 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/general/hello.yml +8 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/general/human_handoff.yml +35 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/general/patterns.yml +22 -0
- rasa/cli/project_templates/finance/tests/e2e_test_cases/without_stub/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 +74 -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/with_stub/network/solve_internet_not_slow.yml +33 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/with_stub/network/solve_internet_slow.yml +47 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/without_stub/billing/understand_bill.yml +67 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/without_stub/general/bot_challenge.yml +8 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/without_stub/general/feedback.yml +46 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/without_stub/general/goodbye.yml +9 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/without_stub/general/hello.yml +8 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/without_stub/general/human_handoff.yml +35 -0
- rasa/cli/project_templates/telco/tests/e2e_test_cases/without_stub/general/patterns.yml +23 -0
- rasa/cli/project_templates/tutorial/config.yml +2 -1
- rasa/cli/project_templates/tutorial/credentials.yml +10 -0
- rasa/cli/run.py +8 -10
- rasa/cli/scaffold.py +50 -6
- rasa/cli/shell.py +10 -5
- rasa/cli/studio/studio.py +1 -1
- rasa/cli/test.py +34 -14
- rasa/cli/train.py +44 -30
- rasa/cli/utils.py +1 -393
- rasa/cli/validation/__init__.py +0 -0
- rasa/cli/validation/bot_config.py +232 -0
- rasa/cli/validation/config_path_validation.py +257 -0
- rasa/cli/x.py +8 -4
- rasa/constants.py +7 -1
- rasa/core/actions/action.py +53 -13
- rasa/core/actions/action_exceptions.py +1 -1
- rasa/core/actions/action_run_slot_rejections.py +1 -1
- rasa/core/actions/direct_custom_actions_executor.py +9 -2
- rasa/core/actions/grpc_custom_action_executor.py +1 -1
- rasa/core/agent.py +22 -2
- rasa/core/available_agents.py +239 -0
- rasa/core/brokers/broker.py +1 -1
- rasa/core/brokers/kafka.py +56 -8
- rasa/core/channels/__init__.py +82 -35
- rasa/core/channels/channel.py +4 -3
- rasa/core/channels/constants.py +3 -0
- rasa/core/channels/development_inspector.py +29 -16
- rasa/core/channels/hangouts.py +2 -2
- rasa/core/channels/inspector/README.md +25 -13
- rasa/core/channels/inspector/dist/assets/{arc-0b11fe30.js → arc-6177260a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-9eef30a7.js → blockDiagram-38ab4fdb-b054f038.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-03e94f28.js → c4Diagram-3d4e48cf-f25427d5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-bf9cbb34.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-95c09eba.js → classDiagram-70f12bd4-c7a2af53.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-38e8446c.js → classDiagram-v2-f2320105-58db65c0.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-8f9083bb.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-57dc3038.js → createText-2e5e7dd3-088372e2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-4bac0545.js → edges-e0da2a9e-58676240.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-81795c90.js → erDiagram-9861fffd-0c14d7c6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-89489ae6.js → flowDb-956e92f1-ea63f85c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-cd152627.js → flowDiagram-66a62f08-a2af48cd.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-9ecd5b59.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-3da369bc.js → flowchart-elk-definition-4a651766-6937abe7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-85ec16f8.js → ganttDiagram-c361ad54-7473f357.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-495bc140.js → gitGraphDiagram-72cf32ee-d0c9405e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-1ec4d266.js → graph-0a6f8466.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-0a0e97c9.js → index-3862675e-7610671a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/index-74e01d94.js +1354 -0
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-4d54bcde.js → infoDiagram-f8f76790-be397dc7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-dc097114.js → journeyDiagram-49397b02-4cefbf62.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-1a08981e.js → layout-e7fbc2bf.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-95f7f1d3.js → line-a8aa457c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-97e69543.js → linear-3351e0d2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-8c71ff03.js → mindmap-definition-fc14e90a-b8cbf605.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-f14c71c7.js → pieDiagram-8a3498a8-f327f774.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-f1d3c9ff.js → quadrantDiagram-120e2f19-2854c591.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-bfa2412f.js → requirementDiagram-deff3bca-964985d5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-53f2c97b.js → sankeyDiagram-04a897e0-edeb4f33.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-319d7c0e.js → sequenceDiagram-704730f1-fcf70125.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-76a09418.js → stateDiagram-587899a1-0e770395.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-a67f15d4.js → stateDiagram-v2-d93cdb3a-af8dcd22.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-0654e7c3.js → styles-6aaf32cf-36a9e70d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-1394bb9d.js → styles-9a916d00-884a8b5b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-e4c5bdae.js → styles-c10674c1-dc097813.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-50957104.js → svgDrawCommon-08f97a94-5a2c7eed.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-b0885a6a.js → timeline-definition-85554ec2-e89c4f6e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-79e6541a.js → xychartDiagram-e933f94c-afb6fe56.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/package.json +18 -18
- rasa/core/channels/inspector/src/App.tsx +56 -12
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +1 -1
- rasa/core/channels/inspector/src/components/DialogueAgentStack.tsx +108 -0
- rasa/core/channels/inspector/src/components/{DialogueStack.tsx → DialogueHistoryStack.tsx} +4 -2
- rasa/core/channels/inspector/src/components/DialogueInformation.tsx +20 -3
- rasa/core/channels/inspector/src/components/LatencyDisplay.tsx +296 -0
- rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +6 -2
- rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +26 -4
- rasa/core/channels/inspector/src/helpers/formatters.test.ts +4 -0
- rasa/core/channels/inspector/src/helpers/formatters.ts +24 -3
- rasa/core/channels/inspector/src/helpers/utils.test.ts +127 -0
- rasa/core/channels/inspector/src/helpers/utils.ts +66 -1
- rasa/core/channels/inspector/src/theme/base/styles.ts +19 -1
- rasa/core/channels/inspector/src/types.ts +55 -1
- rasa/core/channels/inspector/yarn.lock +336 -189
- rasa/core/channels/socketio.py +212 -51
- rasa/core/channels/studio_chat.py +82 -32
- rasa/core/channels/telegram.py +4 -9
- rasa/core/channels/voice_ready/twilio_voice.py +1 -1
- 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 +11 -6
- rasa/core/channels/voice_stream/browser_audio.py +91 -4
- rasa/core/channels/voice_stream/call_state.py +13 -2
- rasa/core/channels/voice_stream/genesys.py +19 -15
- rasa/core/channels/voice_stream/jambonz.py +22 -12
- rasa/core/channels/voice_stream/tts/deepgram.py +140 -0
- rasa/core/channels/voice_stream/twilio_media_streams.py +35 -14
- rasa/core/channels/voice_stream/util.py +11 -1
- rasa/core/channels/voice_stream/voice_channel.py +170 -32
- rasa/core/concurrent_lock_store.py +83 -16
- rasa/core/config/__init__.py +0 -0
- rasa/core/{available_endpoints.py → config/available_endpoints.py} +56 -18
- rasa/core/config/configuration.py +295 -0
- rasa/core/config/credentials.py +19 -0
- rasa/core/config/message_procesing_config.py +34 -0
- rasa/core/constants.py +17 -0
- rasa/core/exceptions.py +1 -1
- rasa/core/featurizers/tracker_featurizers.py +3 -2
- rasa/core/iam_credentials_providers/__init__.py +0 -0
- rasa/core/iam_credentials_providers/aws_iam_credentials_providers.py +291 -0
- rasa/core/iam_credentials_providers/credentials_provider_protocol.py +91 -0
- rasa/core/lock_store.py +50 -10
- rasa/core/nlg/contextual_response_rephraser.py +5 -0
- rasa/core/nlg/generator.py +1 -1
- rasa/core/persistor.py +7 -7
- rasa/core/policies/enterprise_search_policy.py +9 -10
- rasa/core/policies/flow_policy.py +4 -4
- rasa/core/policies/flows/agent_executor.py +720 -0
- rasa/core/policies/flows/flow_exceptions.py +5 -2
- rasa/core/policies/flows/flow_executor.py +146 -77
- rasa/core/policies/flows/mcp_tool_executor.py +304 -0
- rasa/core/policies/intentless_policy.py +1 -1
- rasa/core/policies/rule_policy.py +1 -1
- rasa/core/policies/ted_policy.py +20 -12
- rasa/core/policies/unexpected_intent_policy.py +6 -0
- rasa/core/processor.py +100 -44
- rasa/core/redis_connection_factory.py +474 -0
- rasa/core/run.py +49 -10
- rasa/core/test.py +4 -0
- rasa/core/tracker_stores/redis_tracker_store.py +36 -14
- rasa/core/tracker_stores/sql_tracker_store.py +59 -1
- rasa/core/tracker_stores/tracker_store.py +3 -7
- rasa/core/train.py +1 -1
- rasa/core/training/interactive.py +20 -18
- rasa/core/training/story_conflict.py +5 -5
- rasa/core/utils.py +22 -23
- rasa/dialogue_understanding/commands/__init__.py +8 -0
- rasa/dialogue_understanding/commands/cancel_flow_command.py +20 -6
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +21 -2
- rasa/dialogue_understanding/commands/clarify_command.py +20 -2
- rasa/dialogue_understanding/commands/continue_agent_command.py +91 -0
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +21 -2
- rasa/dialogue_understanding/commands/restart_agent_command.py +162 -0
- rasa/dialogue_understanding/commands/start_flow_command.py +75 -7
- rasa/dialogue_understanding/commands/utils.py +135 -2
- rasa/dialogue_understanding/generator/command_parser.py +4 -0
- rasa/dialogue_understanding/generator/flow_retrieval.py +0 -9
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +52 -12
- rasa/dialogue_understanding/generator/llm_command_generator.py +1 -1
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +1 -1
- rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +66 -0
- rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +66 -0
- rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +89 -0
- rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +88 -0
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +42 -7
- rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +40 -3
- rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +20 -3
- rasa/dialogue_understanding/patterns/cancel.py +27 -6
- rasa/dialogue_understanding/patterns/clarify.py +3 -14
- rasa/dialogue_understanding/patterns/continue_interrupted.py +239 -6
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +49 -9
- rasa/dialogue_understanding/processor/command_processor.py +136 -15
- rasa/dialogue_understanding/stack/dialogue_stack.py +98 -2
- rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +57 -0
- rasa/dialogue_understanding/stack/utils.py +57 -3
- rasa/dialogue_understanding/utils.py +24 -4
- rasa/dialogue_understanding_test/du_test_runner.py +8 -3
- rasa/e2e_test/e2e_test_runner.py +13 -3
- rasa/engine/caching.py +2 -2
- rasa/engine/constants.py +1 -1
- rasa/engine/graph.py +5 -1
- rasa/engine/loader.py +12 -0
- rasa/engine/recipes/default_components.py +138 -49
- rasa/engine/recipes/default_recipe.py +108 -11
- rasa/engine/runner/dask.py +8 -5
- rasa/engine/validation.py +25 -8
- rasa/graph_components/validators/default_recipe_validator.py +86 -28
- rasa/hooks.py +5 -5
- rasa/llm_fine_tuning/utils.py +2 -2
- rasa/model_manager/model_api.py +4 -5
- rasa/model_manager/runner_service.py +2 -2
- rasa/model_manager/socket_bridge.py +21 -17
- 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/model_training.py +60 -47
- rasa/nlu/classifiers/diet_classifier.py +198 -98
- rasa/nlu/classifiers/logistic_regression_classifier.py +1 -4
- rasa/nlu/classifiers/mitie_intent_classifier.py +3 -0
- rasa/nlu/classifiers/sklearn_intent_classifier.py +1 -3
- rasa/nlu/extractors/crf_entity_extractor.py +9 -10
- rasa/nlu/extractors/mitie_entity_extractor.py +3 -0
- rasa/nlu/extractors/spacy_entity_extractor.py +3 -0
- rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +4 -0
- rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +5 -0
- rasa/nlu/featurizers/dense_featurizer/mitie_featurizer.py +2 -0
- rasa/nlu/featurizers/dense_featurizer/spacy_featurizer.py +3 -0
- rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +4 -2
- rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +4 -0
- rasa/nlu/selectors/response_selector.py +10 -2
- rasa/nlu/tokenizers/jieba_tokenizer.py +3 -4
- rasa/nlu/tokenizers/mitie_tokenizer.py +3 -2
- rasa/nlu/tokenizers/spacy_tokenizer.py +3 -2
- rasa/nlu/utils/mitie_utils.py +3 -0
- rasa/nlu/utils/spacy_utils.py +3 -2
- rasa/plugin.py +8 -8
- rasa/privacy/privacy_config.py +1 -1
- rasa/privacy/privacy_manager.py +12 -3
- rasa/server.py +15 -3
- rasa/shared/agents/__init__.py +0 -0
- rasa/shared/agents/auth/__init__.py +0 -0
- rasa/shared/agents/auth/agent_auth_factory.py +105 -0
- rasa/shared/agents/auth/agent_auth_manager.py +92 -0
- rasa/shared/agents/auth/auth_strategy/__init__.py +19 -0
- rasa/shared/agents/auth/auth_strategy/agent_auth_strategy.py +52 -0
- rasa/shared/agents/auth/auth_strategy/api_key_auth_strategy.py +42 -0
- rasa/shared/agents/auth/auth_strategy/bearer_token_auth_strategy.py +28 -0
- rasa/shared/agents/auth/auth_strategy/oauth2_auth_strategy.py +170 -0
- rasa/shared/agents/auth/constants.py +13 -0
- rasa/shared/agents/auth/types.py +12 -0
- rasa/shared/agents/auth/utils.py +85 -0
- rasa/shared/agents/utils.py +35 -0
- rasa/shared/constants.py +11 -0
- rasa/shared/core/constants.py +17 -1
- rasa/shared/core/domain.py +62 -22
- rasa/shared/core/events.py +329 -0
- rasa/shared/core/flows/constants.py +5 -0
- rasa/shared/core/flows/flow.py +1 -1
- rasa/shared/core/flows/flow_step.py +7 -1
- rasa/shared/core/flows/flows_list.py +21 -5
- rasa/shared/core/flows/flows_yaml_schema.json +119 -184
- rasa/shared/core/flows/steps/call.py +57 -6
- rasa/shared/core/flows/steps/collect.py +98 -13
- rasa/shared/core/flows/validation.py +372 -8
- rasa/shared/core/flows/yaml_flows_io.py +19 -10
- rasa/shared/core/slots.py +6 -2
- rasa/shared/core/trackers.py +5 -2
- rasa/shared/core/training_data/story_reader/story_reader.py +1 -1
- rasa/shared/exceptions.py +39 -2
- rasa/shared/importers/importer.py +6 -0
- rasa/shared/importers/rasa.py +1 -1
- rasa/shared/importers/utils.py +86 -4
- rasa/shared/nlu/training_data/schemas/responses.yml +3 -0
- rasa/shared/providers/llm/_base_litellm_client.py +41 -9
- rasa/shared/providers/llm/litellm_router_llm_client.py +10 -6
- rasa/shared/providers/llm/llm_client.py +7 -3
- rasa/shared/providers/llm/llm_response.py +66 -0
- rasa/shared/providers/llm/self_hosted_llm_client.py +8 -4
- rasa/shared/utils/common.py +26 -1
- rasa/shared/utils/health_check/health_check.py +7 -3
- rasa/shared/utils/llm.py +92 -19
- rasa/shared/utils/mcp/__init__.py +0 -0
- rasa/shared/utils/mcp/server_connection.py +250 -0
- rasa/shared/utils/mcp/utils.py +20 -0
- rasa/shared/utils/schemas/events.py +42 -0
- rasa/shared/utils/yaml.py +3 -1
- rasa/studio/download.py +3 -0
- rasa/studio/prompts.py +1 -0
- rasa/studio/pull/pull.py +3 -2
- rasa/studio/train.py +8 -7
- rasa/studio/upload.py +19 -52
- rasa/telemetry.py +166 -28
- rasa/tracing/config.py +45 -12
- rasa/tracing/constants.py +14 -0
- rasa/tracing/instrumentation/attribute_extractors.py +142 -9
- rasa/tracing/instrumentation/instrumentation.py +626 -21
- rasa/tracing/instrumentation/intentless_policy_instrumentation.py +4 -4
- rasa/tracing/instrumentation/metrics.py +32 -0
- rasa/tracing/metric_instrument_provider.py +68 -0
- rasa/utils/common.py +92 -1
- rasa/utils/endpoints.py +11 -2
- rasa/utils/io.py +27 -9
- rasa/utils/json_utils.py +6 -1
- rasa/utils/licensing.py +21 -10
- rasa/utils/log_utils.py +121 -7
- rasa/utils/ml_utils.py +1 -1
- rasa/utils/openapi.py +144 -0
- rasa/utils/plotting.py +1 -1
- rasa/utils/pypred.py +45 -0
- rasa/utils/tensorflow/__init__.py +7 -0
- rasa/utils/tensorflow/callback.py +136 -101
- rasa/utils/tensorflow/crf.py +1 -1
- rasa/utils/tensorflow/data_generator.py +21 -8
- rasa/utils/tensorflow/layers.py +21 -11
- rasa/utils/tensorflow/metrics.py +7 -3
- rasa/utils/tensorflow/models.py +56 -8
- rasa/utils/tensorflow/rasa_layers.py +8 -6
- rasa/utils/tensorflow/transformer.py +2 -3
- rasa/utils/train_utils.py +54 -24
- rasa/validator.py +149 -16
- rasa/version.py +1 -1
- rasa_pro-3.14.0.dist-info/METADATA +212 -0
- {rasa_pro-3.13.11.dist-info → rasa_pro-3.14.0.dist-info}/RECORD +583 -271
- rasa/core/channels/inspector/dist/assets/channel-51d02e9e.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-cc738fa6.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-0c716443.js +0 -1
- rasa/core/channels/inspector/dist/assets/index-c804b295.js +0 -1335
- rasa_pro-3.13.11.dist-info/METADATA +0 -192
- {rasa_pro-3.13.11.dist-info → rasa_pro-3.14.0.dist-info}/NOTICE +0 -0
- {rasa_pro-3.13.11.dist-info → rasa_pro-3.14.0.dist-info}/WHEEL +0 -0
- {rasa_pro-3.13.11.dist-info → rasa_pro-3.14.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import asyncio
|
|
2
4
|
import audioop
|
|
3
5
|
import base64
|
|
@@ -14,6 +16,7 @@ from typing import (
|
|
|
14
16
|
Optional,
|
|
15
17
|
Text,
|
|
16
18
|
Tuple,
|
|
19
|
+
Union,
|
|
17
20
|
)
|
|
18
21
|
|
|
19
22
|
import structlog
|
|
@@ -43,14 +46,13 @@ if TYPE_CHECKING:
|
|
|
43
46
|
from sanic import Sanic, Websocket # type: ignore[attr-defined]
|
|
44
47
|
from socketio import AsyncServer
|
|
45
48
|
|
|
46
|
-
from rasa.core.channels.channel import InputChannel, UserMessage
|
|
47
49
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
48
50
|
|
|
49
51
|
|
|
50
52
|
structlogger = structlog.get_logger()
|
|
51
53
|
|
|
52
54
|
|
|
53
|
-
def tracker_as_dump(tracker: "DialogueStateTracker") -> str:
|
|
55
|
+
def tracker_as_dump(tracker: "DialogueStateTracker") -> Dict[str, Any]:
|
|
54
56
|
"""Create a dump of the tracker state."""
|
|
55
57
|
from rasa.shared.core.trackers import get_trackers_for_conversation_sessions
|
|
56
58
|
|
|
@@ -62,7 +64,7 @@ def tracker_as_dump(tracker: "DialogueStateTracker") -> str:
|
|
|
62
64
|
last_tracker = multiple_tracker_sessions[-1]
|
|
63
65
|
|
|
64
66
|
state = last_tracker.current_state(EventVerbosity.AFTER_RESTART)
|
|
65
|
-
return
|
|
67
|
+
return state
|
|
66
68
|
|
|
67
69
|
|
|
68
70
|
def does_need_action_prediction(tracker: "DialogueStateTracker") -> bool:
|
|
@@ -91,12 +93,12 @@ class StudioTrackerUpdatePlugin:
|
|
|
91
93
|
"""Remove tasks that have already completed."""
|
|
92
94
|
self.tasks = [task for task in self.tasks if not task.done()]
|
|
93
95
|
|
|
94
|
-
@hookimpl
|
|
96
|
+
@hookimpl
|
|
95
97
|
def after_new_user_message(self, tracker: "DialogueStateTracker") -> None:
|
|
96
98
|
"""Triggers a tracker update notification after a new user message."""
|
|
97
99
|
self.handle_tracker_update(tracker)
|
|
98
100
|
|
|
99
|
-
@hookimpl
|
|
101
|
+
@hookimpl
|
|
100
102
|
def after_action_executed(self, tracker: "DialogueStateTracker") -> None:
|
|
101
103
|
"""Triggers a tracker update notification after an action is executed."""
|
|
102
104
|
self.handle_tracker_update(tracker)
|
|
@@ -116,7 +118,7 @@ class StudioTrackerUpdatePlugin:
|
|
|
116
118
|
self.tasks.append(task)
|
|
117
119
|
self._cleanup_tasks()
|
|
118
120
|
|
|
119
|
-
@hookimpl
|
|
121
|
+
@hookimpl
|
|
120
122
|
def after_server_stop(self) -> None:
|
|
121
123
|
"""Cancels all remaining tasks when the server stops."""
|
|
122
124
|
self._cancel_tasks()
|
|
@@ -144,6 +146,7 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
|
|
|
144
146
|
jwt_key: Optional[Text] = None,
|
|
145
147
|
jwt_method: Optional[Text] = "HS256",
|
|
146
148
|
metadata_key: Optional[Text] = "metadata",
|
|
149
|
+
enable_silence_timeout: bool = False,
|
|
147
150
|
) -> None:
|
|
148
151
|
"""Creates a `StudioChatInput` object."""
|
|
149
152
|
from rasa.core.agent import Agent
|
|
@@ -161,6 +164,7 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
|
|
|
161
164
|
jwt_key=jwt_key,
|
|
162
165
|
jwt_method=jwt_method,
|
|
163
166
|
metadata_key=metadata_key,
|
|
167
|
+
enable_silence_timeout=enable_silence_timeout,
|
|
164
168
|
)
|
|
165
169
|
|
|
166
170
|
# Initialize the Voice Input Channel
|
|
@@ -176,11 +180,14 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
|
|
|
176
180
|
# `background_tasks` holds the asyncio tasks for voice streaming
|
|
177
181
|
self.active_connections: Dict[str, SocketIOVoiceWebsocketAdapter] = {}
|
|
178
182
|
self.background_tasks: Dict[str, asyncio.Task] = {}
|
|
183
|
+
self._turn_start_times: Dict[Text, float] = {}
|
|
179
184
|
|
|
180
185
|
self._register_tracker_update_hook()
|
|
181
186
|
|
|
182
187
|
@classmethod
|
|
183
|
-
def from_credentials(
|
|
188
|
+
def from_credentials(
|
|
189
|
+
cls, credentials: Optional[Dict[Text, Any]]
|
|
190
|
+
) -> "StudioChatInput":
|
|
184
191
|
"""Creates a StudioChatInput channel from credentials."""
|
|
185
192
|
credentials = credentials or {}
|
|
186
193
|
|
|
@@ -198,14 +205,15 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
|
|
|
198
205
|
jwt_key=credentials.get("jwt_key"),
|
|
199
206
|
jwt_method=credentials.get("jwt_method", "HS256"),
|
|
200
207
|
metadata_key=credentials.get("metadata_key", "metadata"),
|
|
208
|
+
enable_silence_timeout=credentials.get("enable_silence_timeout", False),
|
|
201
209
|
)
|
|
202
210
|
|
|
203
|
-
async def emit(self, event: str, data: Dict, room: str) -> None:
|
|
211
|
+
async def emit(self, event: str, data: Union[Dict, str], room: str) -> None:
|
|
204
212
|
"""Emits an event to the websocket."""
|
|
205
|
-
if not self.
|
|
213
|
+
if not self.sio_server:
|
|
206
214
|
structlogger.error("studio_chat.emit.sio_not_initialized")
|
|
207
215
|
return
|
|
208
|
-
await self.
|
|
216
|
+
await self.sio_server.emit(event, data, room=room)
|
|
209
217
|
|
|
210
218
|
def _register_tracker_update_hook(self) -> None:
|
|
211
219
|
plugin_manager().register(StudioTrackerUpdatePlugin(self))
|
|
@@ -214,20 +222,29 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
|
|
|
214
222
|
"""Triggers a tracker update notification after a change to the tracker."""
|
|
215
223
|
await self.publish_tracker_update(tracker.sender_id, tracker_as_dump(tracker))
|
|
216
224
|
|
|
217
|
-
async def publish_tracker_update(
|
|
225
|
+
async def publish_tracker_update(
|
|
226
|
+
self, sender_id: str, tracker_dump: Dict[str, Any]
|
|
227
|
+
) -> None:
|
|
218
228
|
"""Publishes a tracker update notification to the websocket."""
|
|
219
229
|
await self.emit("tracker", tracker_dump, room=sender_id)
|
|
220
230
|
|
|
221
231
|
async def on_message_proxy(
|
|
222
232
|
self,
|
|
223
|
-
on_new_message: Callable[[
|
|
224
|
-
message:
|
|
233
|
+
on_new_message: Callable[[UserMessage], Awaitable[Any]],
|
|
234
|
+
message: UserMessage,
|
|
225
235
|
) -> None:
|
|
226
236
|
"""Proxies the on_new_message call to the underlying channel.
|
|
227
237
|
|
|
228
238
|
Triggers a tracker update notification after processing the message.
|
|
229
239
|
"""
|
|
230
|
-
|
|
240
|
+
try:
|
|
241
|
+
await on_new_message(message)
|
|
242
|
+
except Exception as e:
|
|
243
|
+
structlogger.exception(
|
|
244
|
+
"studio_chat.on_new_message.error",
|
|
245
|
+
error=str(e),
|
|
246
|
+
sender_id=message.sender_id,
|
|
247
|
+
)
|
|
231
248
|
|
|
232
249
|
if not self.agent or not self.agent.is_ready():
|
|
233
250
|
structlogger.error("studio_chat.on_message_proxy.agent_not_initialized")
|
|
@@ -335,26 +352,33 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
|
|
|
335
352
|
elif "marker" in message:
|
|
336
353
|
if message["marker"] == call_state.latest_bot_audio_id:
|
|
337
354
|
# Just finished streaming last audio bytes
|
|
338
|
-
call_state.is_bot_speaking = False
|
|
355
|
+
call_state.is_bot_speaking = False
|
|
339
356
|
if call_state.should_hangup:
|
|
340
357
|
structlogger.debug(
|
|
341
358
|
"studio_chat.hangup", marker=call_state.latest_bot_audio_id
|
|
342
359
|
)
|
|
343
360
|
return EndConversationAction()
|
|
344
361
|
else:
|
|
345
|
-
call_state.is_bot_speaking = True
|
|
362
|
+
call_state.is_bot_speaking = True
|
|
346
363
|
return ContinueConversationAction()
|
|
347
364
|
|
|
348
365
|
def create_output_channel(
|
|
349
366
|
self, voice_websocket: "Websocket", tts_engine: TTSEngine
|
|
350
367
|
) -> VoiceOutputChannel:
|
|
351
|
-
"""Create a voice output channel."""
|
|
368
|
+
"""Create a voice output channel. This is used by VoiceInputChannel."""
|
|
352
369
|
return StudioVoiceOutputChannel(
|
|
353
370
|
voice_websocket,
|
|
354
371
|
tts_engine,
|
|
355
372
|
self.tts_cache,
|
|
356
373
|
)
|
|
357
374
|
|
|
375
|
+
async def interrupt_playback(
|
|
376
|
+
self, ws: Websocket, call_parameters: CallParameters
|
|
377
|
+
) -> None:
|
|
378
|
+
"""Interrupt the current playback of audio."""
|
|
379
|
+
structlogger.debug("studio_chat.interrupt_playback")
|
|
380
|
+
await ws.send(json.dumps({"interruptPlayback": True}))
|
|
381
|
+
|
|
358
382
|
def _start_voice_session(
|
|
359
383
|
self,
|
|
360
384
|
session_id: str,
|
|
@@ -375,7 +399,7 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
|
|
|
375
399
|
|
|
376
400
|
# Create a websocket adapter for this connection
|
|
377
401
|
ws_adapter = SocketIOVoiceWebsocketAdapter(
|
|
378
|
-
|
|
402
|
+
sio_server=self.sio_server,
|
|
379
403
|
session_id=session_id,
|
|
380
404
|
sid=sid,
|
|
381
405
|
bot_message_evt=self.bot_message_evt,
|
|
@@ -414,7 +438,7 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
|
|
|
414
438
|
if sid in self.active_connections:
|
|
415
439
|
del self.active_connections[sid]
|
|
416
440
|
|
|
417
|
-
@hookimpl
|
|
441
|
+
@hookimpl
|
|
418
442
|
def after_server_stop(self) -> None:
|
|
419
443
|
"""Cleanup background tasks and active connections when the server stops."""
|
|
420
444
|
structlogger.info("studio_chat.after_server_stop.cleanup")
|
|
@@ -423,13 +447,13 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
|
|
|
423
447
|
task.cancel()
|
|
424
448
|
|
|
425
449
|
def blueprint(
|
|
426
|
-
self, on_new_message: Callable[[
|
|
450
|
+
self, on_new_message: Callable[[UserMessage], Awaitable[Any]]
|
|
427
451
|
) -> SocketBlueprint:
|
|
428
452
|
socket_blueprint = super().blueprint(
|
|
429
453
|
partial(self.on_message_proxy, on_new_message)
|
|
430
454
|
)
|
|
431
455
|
|
|
432
|
-
if not self.
|
|
456
|
+
if not self.sio_server:
|
|
433
457
|
structlogger.error("studio_chat.blueprint.sio_not_initialized")
|
|
434
458
|
return socket_blueprint
|
|
435
459
|
|
|
@@ -437,14 +461,15 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
|
|
|
437
461
|
async def after_server_start(
|
|
438
462
|
app: "Sanic", _: asyncio.AbstractEventLoop
|
|
439
463
|
) -> None:
|
|
440
|
-
|
|
464
|
+
if hasattr(app.ctx, "agent"):
|
|
465
|
+
self.agent = app.ctx.agent
|
|
441
466
|
|
|
442
|
-
@self.
|
|
467
|
+
@self.sio_server.on("disconnect", namespace=self.namespace)
|
|
443
468
|
async def disconnect(sid: Text) -> None:
|
|
444
469
|
structlogger.debug("studio_chat.sio.disconnect", sid=sid)
|
|
445
470
|
self._cleanup_tasks_for_sid(sid)
|
|
446
471
|
|
|
447
|
-
@self.
|
|
472
|
+
@self.sio_server.on("session_request", namespace=self.namespace)
|
|
448
473
|
async def session_request(sid: Text, data: Optional[Dict]) -> None:
|
|
449
474
|
"""Overrides the base SocketIOInput session_request handler.
|
|
450
475
|
|
|
@@ -464,7 +489,7 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
|
|
|
464
489
|
if data and data.get("is_voice", False):
|
|
465
490
|
self._start_voice_session(data["session_id"], sid, on_new_message)
|
|
466
491
|
|
|
467
|
-
@self.
|
|
492
|
+
@self.sio_server.on(self.user_message_evt, namespace=self.namespace)
|
|
468
493
|
async def handle_message(sid: Text, data: Dict) -> None:
|
|
469
494
|
"""Overrides the base SocketIOInput handle_message handler."""
|
|
470
495
|
# Handle voice messages
|
|
@@ -475,10 +500,18 @@ class StudioChatInput(SocketIOInput, VoiceInputChannel):
|
|
|
475
500
|
ws.put_message(data)
|
|
476
501
|
return
|
|
477
502
|
|
|
478
|
-
|
|
479
|
-
|
|
503
|
+
try:
|
|
504
|
+
# Handle text messages
|
|
505
|
+
await self.handle_user_message(sid, data, on_new_message)
|
|
506
|
+
except Exception as e:
|
|
507
|
+
structlogger.exception(
|
|
508
|
+
"studio_chat.sio.handle_message.error",
|
|
509
|
+
error=str(e),
|
|
510
|
+
sid=sid,
|
|
511
|
+
)
|
|
512
|
+
await self.emit("error", str(e), room=sid)
|
|
480
513
|
|
|
481
|
-
@self.
|
|
514
|
+
@self.sio_server.on("update_tracker", namespace=self.namespace)
|
|
482
515
|
async def on_update_tracker(sid: Text, data: Dict) -> None:
|
|
483
516
|
await self.handle_tracker_update(sid, data)
|
|
484
517
|
|
|
@@ -500,16 +533,33 @@ class StudioVoiceOutputChannel(VoiceOutputChannel):
|
|
|
500
533
|
|
|
501
534
|
def create_marker_message(self, recipient_id: str) -> Tuple[str, str]:
|
|
502
535
|
message_id = uuid.uuid4().hex
|
|
503
|
-
|
|
536
|
+
marker_data: Dict[str, Any] = {"marker": message_id}
|
|
537
|
+
|
|
538
|
+
# Include comprehensive latency information if available
|
|
539
|
+
latency_data = {
|
|
540
|
+
"asr_latency_ms": call_state.asr_latency_ms,
|
|
541
|
+
"rasa_processing_latency_ms": call_state.rasa_processing_latency_ms,
|
|
542
|
+
"tts_first_byte_latency_ms": call_state.tts_first_byte_latency_ms,
|
|
543
|
+
"tts_complete_latency_ms": call_state.tts_complete_latency_ms,
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
# Filter out None values from latency data
|
|
547
|
+
latency_data = {k: v for k, v in latency_data.items() if v is not None}
|
|
548
|
+
|
|
549
|
+
# Add latency data to marker if any metrics are available
|
|
550
|
+
if latency_data:
|
|
551
|
+
marker_data["latency"] = latency_data
|
|
552
|
+
|
|
553
|
+
return json.dumps(marker_data), message_id
|
|
504
554
|
|
|
505
555
|
|
|
506
556
|
class SocketIOVoiceWebsocketAdapter:
|
|
507
557
|
"""Adapter to make Socket.IO work like a Sanic WebSocket for voice channels."""
|
|
508
558
|
|
|
509
559
|
def __init__(
|
|
510
|
-
self,
|
|
560
|
+
self, sio_server: "AsyncServer", session_id: str, sid: str, bot_message_evt: str
|
|
511
561
|
) -> None:
|
|
512
|
-
self.
|
|
562
|
+
self.sio_server = sio_server
|
|
513
563
|
self.bot_message_evt = bot_message_evt
|
|
514
564
|
self._closed = False
|
|
515
565
|
self._receive_queue: asyncio.Queue[Any] = asyncio.Queue()
|
|
@@ -528,7 +578,7 @@ class SocketIOVoiceWebsocketAdapter:
|
|
|
528
578
|
async def send(self, data: Any) -> None:
|
|
529
579
|
"""Send data to the client."""
|
|
530
580
|
if not self.closed:
|
|
531
|
-
await self.
|
|
581
|
+
await self.sio_server.emit(self.bot_message_evt, data, room=self.sid)
|
|
532
582
|
|
|
533
583
|
async def recv(self) -> Any:
|
|
534
584
|
"""Receive data from the client."""
|
rasa/core/channels/telegram.py
CHANGED
|
@@ -4,6 +4,9 @@ import typing
|
|
|
4
4
|
from copy import deepcopy
|
|
5
5
|
from typing import Any, Awaitable, Callable, Dict, List, Optional, Text
|
|
6
6
|
|
|
7
|
+
# Import aiogram at module level to raise error if not installed
|
|
8
|
+
from aiogram import Bot
|
|
9
|
+
from aiogram.types import Message, Update
|
|
7
10
|
from sanic import Blueprint, response
|
|
8
11
|
from sanic.request import Request
|
|
9
12
|
from sanic.response import HTTPResponse
|
|
@@ -28,15 +31,7 @@ class TelegramOutput(OutputChannel):
|
|
|
28
31
|
return "telegram"
|
|
29
32
|
|
|
30
33
|
def __init__(self, access_token: Optional[Text]) -> None:
|
|
31
|
-
|
|
32
|
-
from aiogram import Bot
|
|
33
|
-
|
|
34
|
-
self.bot = Bot(access_token)
|
|
35
|
-
except ImportError:
|
|
36
|
-
raise ImportError(
|
|
37
|
-
"To use the Telegram channel, please install the aiogram package "
|
|
38
|
-
"with 'pip install aiogram'"
|
|
39
|
-
)
|
|
34
|
+
self.bot = Bot(access_token)
|
|
40
35
|
|
|
41
36
|
async def send_text_message(
|
|
42
37
|
self, recipient_id: Text, text: Text, **kwargs: Any
|
|
@@ -30,7 +30,7 @@ TWILIO_VOICE_PATH = "webhooks/twilio_voice/webhook"
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def map_call_params(form: RequestParameters) -> CallParameters:
|
|
33
|
-
"""Map the
|
|
33
|
+
"""Map the Twilio Voice parameters to the CallParameters dataclass."""
|
|
34
34
|
return CallParameters(
|
|
35
35
|
call_id=form.get("CallSid"),
|
|
36
36
|
user_phone=form.get("Caller"),
|
|
@@ -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:
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import asyncio
|
|
2
4
|
import base64
|
|
3
5
|
import hmac
|
|
@@ -21,6 +23,7 @@ from rasa.core.channels.voice_stream.call_state import (
|
|
|
21
23
|
call_state,
|
|
22
24
|
)
|
|
23
25
|
from rasa.core.channels.voice_stream.tts.tts_engine import TTSEngine
|
|
26
|
+
from rasa.core.channels.voice_stream.util import repack_voice_credentials
|
|
24
27
|
from rasa.core.channels.voice_stream.voice_channel import (
|
|
25
28
|
ContinueConversationAction,
|
|
26
29
|
EndConversationAction,
|
|
@@ -85,7 +88,7 @@ class AudiocodesVoiceOutputChannel(VoiceOutputChannel):
|
|
|
85
88
|
# however, Audiocodes does not have an event to indicate that.
|
|
86
89
|
# This is an approximation, as the bot will be sent the audio chunks next
|
|
87
90
|
# which are played to the user immediately.
|
|
88
|
-
call_state.is_bot_speaking = True
|
|
91
|
+
call_state.is_bot_speaking = True
|
|
89
92
|
VoiceInputChannel._cancel_silence_timeout_watcher()
|
|
90
93
|
|
|
91
94
|
async def send_intermediate_marker(self, recipient_id: str) -> None:
|
|
@@ -114,6 +117,7 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
|
|
|
114
117
|
server_url: str,
|
|
115
118
|
asr_config: Dict,
|
|
116
119
|
tts_config: Dict,
|
|
120
|
+
interruptions: Optional[Dict[str, int]] = None,
|
|
117
121
|
token: Optional[Text] = None,
|
|
118
122
|
):
|
|
119
123
|
mark_as_beta_feature("Audiocodes (audiocodes_stream) Channel")
|
|
@@ -121,6 +125,7 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
|
|
|
121
125
|
server_url=server_url,
|
|
122
126
|
asr_config=asr_config,
|
|
123
127
|
tts_config=tts_config,
|
|
128
|
+
interruptions=interruptions,
|
|
124
129
|
)
|
|
125
130
|
self.token = token
|
|
126
131
|
|
|
@@ -128,10 +133,10 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
|
|
|
128
133
|
def from_credentials(
|
|
129
134
|
cls,
|
|
130
135
|
credentials: Optional[Dict[str, Any]],
|
|
131
|
-
) ->
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return
|
|
136
|
+
) -> AudiocodesVoiceInputChannel:
|
|
137
|
+
cls.validate_basic_credentials(credentials)
|
|
138
|
+
new_creds = repack_voice_credentials(credentials)
|
|
139
|
+
return cls(**new_creds)
|
|
135
140
|
|
|
136
141
|
def channel_bytes_to_rasa_audio_bytes(self, input_bytes: bytes) -> RasaAudioBytes:
|
|
137
142
|
return RasaAudioBytes(base64.b64decode(input_bytes))
|
|
@@ -185,7 +190,7 @@ class AudiocodesVoiceInputChannel(VoiceInputChannel):
|
|
|
185
190
|
pass
|
|
186
191
|
elif activity["name"] == "playFinished":
|
|
187
192
|
logger.debug("audiocodes_stream.playFinished", data=activity)
|
|
188
|
-
call_state.is_bot_speaking = False
|
|
193
|
+
call_state.is_bot_speaking = False
|
|
189
194
|
if call_state.should_hangup:
|
|
190
195
|
logger.info("audiocodes_stream.hangup")
|
|
191
196
|
self._send_hangup(ws, data)
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import audioop
|
|
2
4
|
import base64
|
|
3
5
|
import json
|
|
6
|
+
import os
|
|
4
7
|
import uuid
|
|
5
|
-
|
|
8
|
+
import wave
|
|
9
|
+
from typing import Any, Awaitable, Callable, Dict, Optional, Tuple
|
|
6
10
|
|
|
7
11
|
import structlog
|
|
8
12
|
from sanic import ( # type: ignore[attr-defined]
|
|
@@ -18,6 +22,7 @@ from rasa.core.channels.voice_ready.utils import CallParameters
|
|
|
18
22
|
from rasa.core.channels.voice_stream.audio_bytes import RasaAudioBytes
|
|
19
23
|
from rasa.core.channels.voice_stream.call_state import call_state
|
|
20
24
|
from rasa.core.channels.voice_stream.tts.tts_engine import TTSEngine
|
|
25
|
+
from rasa.core.channels.voice_stream.util import repack_voice_credentials
|
|
21
26
|
from rasa.core.channels.voice_stream.voice_channel import (
|
|
22
27
|
ContinueConversationAction,
|
|
23
28
|
EndConversationAction,
|
|
@@ -45,10 +50,70 @@ class BrowserAudioOutputChannel(VoiceOutputChannel):
|
|
|
45
50
|
|
|
46
51
|
def create_marker_message(self, recipient_id: str) -> Tuple[str, str]:
|
|
47
52
|
message_id = uuid.uuid4().hex
|
|
48
|
-
|
|
53
|
+
marker_data = {"marker": message_id}
|
|
54
|
+
|
|
55
|
+
# Include comprehensive latency information if available
|
|
56
|
+
latency_data = {
|
|
57
|
+
"asr_latency_ms": call_state.asr_latency_ms,
|
|
58
|
+
"rasa_processing_latency_ms": call_state.rasa_processing_latency_ms,
|
|
59
|
+
"tts_first_byte_latency_ms": call_state.tts_first_byte_latency_ms,
|
|
60
|
+
"tts_complete_latency_ms": call_state.tts_complete_latency_ms,
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# Filter out None values from latency data
|
|
64
|
+
latency_data = {k: v for k, v in latency_data.items() if v is not None}
|
|
65
|
+
|
|
66
|
+
# Add latency data to marker if any metrics are available
|
|
67
|
+
if latency_data:
|
|
68
|
+
marker_data["latency"] = latency_data # type: ignore[assignment]
|
|
69
|
+
|
|
70
|
+
return json.dumps(marker_data), message_id
|
|
49
71
|
|
|
50
72
|
|
|
51
73
|
class BrowserAudioInputChannel(VoiceInputChannel):
|
|
74
|
+
requires_voice_license = False
|
|
75
|
+
|
|
76
|
+
def __init__(
|
|
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,
|
|
83
|
+
) -> None:
|
|
84
|
+
"""Initializes the browser audio input channel."""
|
|
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")
|
|
116
|
+
|
|
52
117
|
@classmethod
|
|
53
118
|
def name(cls) -> str:
|
|
54
119
|
return "browser_audio"
|
|
@@ -62,6 +127,15 @@ class BrowserAudioInputChannel(VoiceInputChannel):
|
|
|
62
127
|
call_id = f"inspect-{uuid.uuid4()}"
|
|
63
128
|
return CallParameters(call_id, "local", "local", stream_id=call_id)
|
|
64
129
|
|
|
130
|
+
@classmethod
|
|
131
|
+
def from_credentials(
|
|
132
|
+
cls,
|
|
133
|
+
credentials: Optional[Dict[str, Any]],
|
|
134
|
+
) -> BrowserAudioInputChannel:
|
|
135
|
+
cls.validate_basic_credentials(credentials)
|
|
136
|
+
new_creds = repack_voice_credentials(credentials or {})
|
|
137
|
+
return cls(**new_creds)
|
|
138
|
+
|
|
65
139
|
def map_input_message(
|
|
66
140
|
self,
|
|
67
141
|
message: Any,
|
|
@@ -70,21 +144,29 @@ class BrowserAudioInputChannel(VoiceInputChannel):
|
|
|
70
144
|
data = json.loads(message)
|
|
71
145
|
if "audio" in data:
|
|
72
146
|
channel_bytes = base64.b64decode(data["audio"])
|
|
147
|
+
self._append_audio_to_recording(channel_bytes)
|
|
73
148
|
audio_bytes = self.channel_bytes_to_rasa_audio_bytes(channel_bytes)
|
|
74
149
|
return NewAudioAction(audio_bytes)
|
|
75
150
|
elif "marker" in data:
|
|
76
151
|
if data["marker"] == call_state.latest_bot_audio_id:
|
|
77
152
|
# Just finished streaming last audio bytes
|
|
78
|
-
call_state.is_bot_speaking = False
|
|
153
|
+
call_state.is_bot_speaking = False
|
|
79
154
|
if call_state.should_hangup:
|
|
80
155
|
logger.debug(
|
|
81
156
|
"browser_audio.hangup", marker=call_state.latest_bot_audio_id
|
|
82
157
|
)
|
|
83
158
|
return EndConversationAction()
|
|
84
159
|
else:
|
|
85
|
-
call_state.is_bot_speaking = True
|
|
160
|
+
call_state.is_bot_speaking = True
|
|
86
161
|
return ContinueConversationAction()
|
|
87
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
|
+
|
|
88
170
|
def create_output_channel(
|
|
89
171
|
self, voice_websocket: Websocket, tts_engine: TTSEngine
|
|
90
172
|
) -> VoiceOutputChannel:
|
|
@@ -107,8 +189,13 @@ class BrowserAudioInputChannel(VoiceInputChannel):
|
|
|
107
189
|
@blueprint.websocket("/websocket") # type: ignore
|
|
108
190
|
async def handle_message(request: Request, ws: Websocket) -> None:
|
|
109
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")
|
|
110
195
|
await self.run_audio_streaming(on_new_message, ws)
|
|
111
196
|
except Exception as e:
|
|
112
197
|
logger.error("browser_audio.handle_message.error", error=e)
|
|
198
|
+
finally:
|
|
199
|
+
self._stop_recording()
|
|
113
200
|
|
|
114
201
|
return blueprint
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from contextvars import ContextVar
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
|
-
from typing import Any, Dict, Optional
|
|
4
|
+
from typing import Any, Dict, Optional, cast
|
|
5
5
|
|
|
6
6
|
from werkzeug.local import LocalProxy
|
|
7
7
|
|
|
@@ -19,9 +19,20 @@ class CallState:
|
|
|
19
19
|
should_hangup: bool = False
|
|
20
20
|
connection_failed: bool = False
|
|
21
21
|
|
|
22
|
+
# Latency tracking - start times only
|
|
23
|
+
user_speech_start_time: Optional[float] = None
|
|
24
|
+
rasa_processing_start_time: Optional[float] = None
|
|
25
|
+
tts_start_time: Optional[float] = None
|
|
26
|
+
|
|
27
|
+
# Calculated latencies (used by channels like browser_audio)
|
|
28
|
+
asr_latency_ms: Optional[float] = None
|
|
29
|
+
rasa_processing_latency_ms: Optional[float] = None
|
|
30
|
+
tts_first_byte_latency_ms: Optional[float] = None
|
|
31
|
+
tts_complete_latency_ms: Optional[float] = None
|
|
32
|
+
|
|
22
33
|
# Generic field for channel-specific state data
|
|
23
34
|
channel_data: Dict[str, Any] = field(default_factory=dict)
|
|
24
35
|
|
|
25
36
|
|
|
26
37
|
_call_state: ContextVar[CallState] = ContextVar("call_state")
|
|
27
|
-
call_state = LocalProxy(_call_state)
|
|
38
|
+
call_state: CallState = cast(CallState, LocalProxy(_call_state))
|