rasa-pro 3.12.0.dev1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rasa-pro might be problematic. Click here for more details.
- README.md +41 -0
- rasa/__init__.py +9 -0
- rasa/__main__.py +177 -0
- rasa/anonymization/__init__.py +2 -0
- rasa/anonymization/anonymisation_rule_yaml_reader.py +91 -0
- rasa/anonymization/anonymization_pipeline.py +286 -0
- rasa/anonymization/anonymization_rule_executor.py +260 -0
- rasa/anonymization/anonymization_rule_orchestrator.py +120 -0
- rasa/anonymization/schemas/config.yml +47 -0
- rasa/anonymization/utils.py +118 -0
- rasa/api.py +160 -0
- rasa/cli/__init__.py +5 -0
- rasa/cli/arguments/__init__.py +0 -0
- rasa/cli/arguments/data.py +106 -0
- rasa/cli/arguments/default_arguments.py +207 -0
- rasa/cli/arguments/evaluate.py +65 -0
- rasa/cli/arguments/export.py +51 -0
- rasa/cli/arguments/interactive.py +74 -0
- rasa/cli/arguments/run.py +219 -0
- rasa/cli/arguments/shell.py +17 -0
- rasa/cli/arguments/test.py +211 -0
- rasa/cli/arguments/train.py +279 -0
- rasa/cli/arguments/visualize.py +34 -0
- rasa/cli/arguments/x.py +30 -0
- rasa/cli/data.py +354 -0
- rasa/cli/dialogue_understanding_test.py +251 -0
- rasa/cli/e2e_test.py +259 -0
- rasa/cli/evaluate.py +222 -0
- rasa/cli/export.py +250 -0
- rasa/cli/inspect.py +75 -0
- rasa/cli/interactive.py +166 -0
- rasa/cli/license.py +65 -0
- rasa/cli/llm_fine_tuning.py +403 -0
- rasa/cli/markers.py +78 -0
- rasa/cli/project_templates/__init__.py +0 -0
- rasa/cli/project_templates/calm/actions/__init__.py +0 -0
- rasa/cli/project_templates/calm/actions/action_template.py +27 -0
- rasa/cli/project_templates/calm/actions/add_contact.py +30 -0
- rasa/cli/project_templates/calm/actions/db.py +57 -0
- rasa/cli/project_templates/calm/actions/list_contacts.py +22 -0
- rasa/cli/project_templates/calm/actions/remove_contact.py +35 -0
- rasa/cli/project_templates/calm/config.yml +10 -0
- rasa/cli/project_templates/calm/credentials.yml +33 -0
- rasa/cli/project_templates/calm/data/flows/add_contact.yml +31 -0
- rasa/cli/project_templates/calm/data/flows/list_contacts.yml +14 -0
- rasa/cli/project_templates/calm/data/flows/remove_contact.yml +29 -0
- rasa/cli/project_templates/calm/db/contacts.json +10 -0
- rasa/cli/project_templates/calm/domain/add_contact.yml +39 -0
- rasa/cli/project_templates/calm/domain/list_contacts.yml +17 -0
- rasa/cli/project_templates/calm/domain/remove_contact.yml +38 -0
- rasa/cli/project_templates/calm/domain/shared.yml +10 -0
- rasa/cli/project_templates/calm/e2e_tests/cancelations/user_cancels_during_a_correction.yml +16 -0
- rasa/cli/project_templates/calm/e2e_tests/cancelations/user_changes_mind_on_a_whim.yml +7 -0
- rasa/cli/project_templates/calm/e2e_tests/corrections/user_corrects_contact_handle.yml +20 -0
- rasa/cli/project_templates/calm/e2e_tests/corrections/user_corrects_contact_name.yml +19 -0
- rasa/cli/project_templates/calm/e2e_tests/happy_paths/user_adds_contact_to_their_list.yml +15 -0
- rasa/cli/project_templates/calm/e2e_tests/happy_paths/user_lists_contacts.yml +5 -0
- rasa/cli/project_templates/calm/e2e_tests/happy_paths/user_removes_contact.yml +11 -0
- rasa/cli/project_templates/calm/e2e_tests/happy_paths/user_removes_contact_from_list.yml +12 -0
- rasa/cli/project_templates/calm/endpoints.yml +58 -0
- rasa/cli/project_templates/default/actions/__init__.py +0 -0
- rasa/cli/project_templates/default/actions/actions.py +27 -0
- rasa/cli/project_templates/default/config.yml +44 -0
- rasa/cli/project_templates/default/credentials.yml +33 -0
- rasa/cli/project_templates/default/data/nlu.yml +91 -0
- rasa/cli/project_templates/default/data/rules.yml +13 -0
- rasa/cli/project_templates/default/data/stories.yml +30 -0
- rasa/cli/project_templates/default/domain.yml +34 -0
- rasa/cli/project_templates/default/endpoints.yml +42 -0
- rasa/cli/project_templates/default/tests/test_stories.yml +91 -0
- rasa/cli/project_templates/tutorial/actions/__init__.py +0 -0
- rasa/cli/project_templates/tutorial/actions/actions.py +22 -0
- rasa/cli/project_templates/tutorial/config.yml +12 -0
- rasa/cli/project_templates/tutorial/credentials.yml +33 -0
- rasa/cli/project_templates/tutorial/data/flows.yml +8 -0
- rasa/cli/project_templates/tutorial/data/patterns.yml +11 -0
- rasa/cli/project_templates/tutorial/domain.yml +35 -0
- rasa/cli/project_templates/tutorial/endpoints.yml +55 -0
- rasa/cli/run.py +143 -0
- rasa/cli/scaffold.py +273 -0
- rasa/cli/shell.py +141 -0
- rasa/cli/studio/__init__.py +0 -0
- rasa/cli/studio/download.py +62 -0
- rasa/cli/studio/studio.py +296 -0
- rasa/cli/studio/train.py +59 -0
- rasa/cli/studio/upload.py +62 -0
- rasa/cli/telemetry.py +102 -0
- rasa/cli/test.py +280 -0
- rasa/cli/train.py +278 -0
- rasa/cli/utils.py +484 -0
- rasa/cli/visualize.py +40 -0
- rasa/cli/x.py +206 -0
- rasa/constants.py +45 -0
- rasa/core/__init__.py +17 -0
- rasa/core/actions/__init__.py +0 -0
- rasa/core/actions/action.py +1318 -0
- rasa/core/actions/action_clean_stack.py +59 -0
- rasa/core/actions/action_exceptions.py +24 -0
- rasa/core/actions/action_hangup.py +29 -0
- rasa/core/actions/action_repeat_bot_messages.py +89 -0
- rasa/core/actions/action_run_slot_rejections.py +210 -0
- rasa/core/actions/action_trigger_chitchat.py +31 -0
- rasa/core/actions/action_trigger_flow.py +109 -0
- rasa/core/actions/action_trigger_search.py +31 -0
- rasa/core/actions/constants.py +5 -0
- rasa/core/actions/custom_action_executor.py +191 -0
- rasa/core/actions/direct_custom_actions_executor.py +109 -0
- rasa/core/actions/e2e_stub_custom_action_executor.py +72 -0
- rasa/core/actions/forms.py +741 -0
- rasa/core/actions/grpc_custom_action_executor.py +251 -0
- rasa/core/actions/http_custom_action_executor.py +145 -0
- rasa/core/actions/loops.py +114 -0
- rasa/core/actions/two_stage_fallback.py +186 -0
- rasa/core/agent.py +559 -0
- rasa/core/auth_retry_tracker_store.py +122 -0
- rasa/core/brokers/__init__.py +0 -0
- rasa/core/brokers/broker.py +126 -0
- rasa/core/brokers/file.py +58 -0
- rasa/core/brokers/kafka.py +324 -0
- rasa/core/brokers/pika.py +388 -0
- rasa/core/brokers/sql.py +86 -0
- rasa/core/channels/__init__.py +61 -0
- rasa/core/channels/botframework.py +338 -0
- rasa/core/channels/callback.py +84 -0
- rasa/core/channels/channel.py +456 -0
- rasa/core/channels/console.py +241 -0
- rasa/core/channels/development_inspector.py +197 -0
- rasa/core/channels/facebook.py +419 -0
- rasa/core/channels/hangouts.py +329 -0
- rasa/core/channels/inspector/.eslintrc.cjs +25 -0
- rasa/core/channels/inspector/.gitignore +23 -0
- rasa/core/channels/inspector/README.md +54 -0
- rasa/core/channels/inspector/assets/favicon.ico +0 -0
- rasa/core/channels/inspector/assets/rasa-chat.js +2 -0
- rasa/core/channels/inspector/custom.d.ts +3 -0
- rasa/core/channels/inspector/dist/assets/arc-861ddd57.js +1 -0
- rasa/core/channels/inspector/dist/assets/array-9f3ba611.js +1 -0
- rasa/core/channels/inspector/dist/assets/c4Diagram-d0fbc5ce-921f02db.js +10 -0
- rasa/core/channels/inspector/dist/assets/classDiagram-936ed81e-b436c4f8.js +2 -0
- rasa/core/channels/inspector/dist/assets/classDiagram-v2-c3cb15f1-511a23cb.js +2 -0
- rasa/core/channels/inspector/dist/assets/createText-62fc7601-ef476ecd.js +7 -0
- rasa/core/channels/inspector/dist/assets/edges-f2ad444c-f1878e0a.js +4 -0
- rasa/core/channels/inspector/dist/assets/erDiagram-9d236eb7-fac75185.js +51 -0
- rasa/core/channels/inspector/dist/assets/flowDb-1972c806-201c5bbc.js +6 -0
- rasa/core/channels/inspector/dist/assets/flowDiagram-7ea5b25a-f904ae41.js +4 -0
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-855bc5b3-b080d6f2.js +1 -0
- rasa/core/channels/inspector/dist/assets/flowchart-elk-definition-abe16c3d-1813da66.js +139 -0
- rasa/core/channels/inspector/dist/assets/ganttDiagram-9b5ea136-872af172.js +266 -0
- rasa/core/channels/inspector/dist/assets/gitGraphDiagram-99d0ae7c-34a0af5a.js +70 -0
- rasa/core/channels/inspector/dist/assets/ibm-plex-mono-v4-latin-regular-128cfa44.ttf +0 -0
- rasa/core/channels/inspector/dist/assets/ibm-plex-mono-v4-latin-regular-21dbcb97.woff +0 -0
- rasa/core/channels/inspector/dist/assets/ibm-plex-mono-v4-latin-regular-222b5e26.svg +329 -0
- rasa/core/channels/inspector/dist/assets/ibm-plex-mono-v4-latin-regular-9ad89b2a.woff2 +0 -0
- rasa/core/channels/inspector/dist/assets/index-2c4b9a3b-42ba3e3d.js +1 -0
- rasa/core/channels/inspector/dist/assets/index-37817b51.js +1317 -0
- rasa/core/channels/inspector/dist/assets/index-3ee28881.css +1 -0
- rasa/core/channels/inspector/dist/assets/infoDiagram-736b4530-6b731386.js +7 -0
- rasa/core/channels/inspector/dist/assets/init-77b53fdd.js +1 -0
- rasa/core/channels/inspector/dist/assets/journeyDiagram-df861f2b-e8579ac6.js +139 -0
- rasa/core/channels/inspector/dist/assets/lato-v14-latin-700-60c05ee4.woff +0 -0
- rasa/core/channels/inspector/dist/assets/lato-v14-latin-700-8335d9b8.svg +438 -0
- rasa/core/channels/inspector/dist/assets/lato-v14-latin-700-9cc39c75.ttf +0 -0
- rasa/core/channels/inspector/dist/assets/lato-v14-latin-700-ead13ccf.woff2 +0 -0
- rasa/core/channels/inspector/dist/assets/lato-v14-latin-regular-16705655.woff2 +0 -0
- rasa/core/channels/inspector/dist/assets/lato-v14-latin-regular-5aeb07f9.woff +0 -0
- rasa/core/channels/inspector/dist/assets/lato-v14-latin-regular-9c459044.ttf +0 -0
- rasa/core/channels/inspector/dist/assets/lato-v14-latin-regular-9e2898a4.svg +435 -0
- rasa/core/channels/inspector/dist/assets/layout-89e6403a.js +1 -0
- rasa/core/channels/inspector/dist/assets/line-dc73d3fc.js +1 -0
- rasa/core/channels/inspector/dist/assets/linear-f5b1d2bc.js +1 -0
- rasa/core/channels/inspector/dist/assets/mindmap-definition-beec6740-82cb74fa.js +109 -0
- rasa/core/channels/inspector/dist/assets/ordinal-ba9b4969.js +1 -0
- rasa/core/channels/inspector/dist/assets/path-53f90ab3.js +1 -0
- rasa/core/channels/inspector/dist/assets/pieDiagram-dbbf0591-bdf5f29b.js +35 -0
- rasa/core/channels/inspector/dist/assets/quadrantDiagram-4d7f4fd6-c7a0cbe4.js +7 -0
- rasa/core/channels/inspector/dist/assets/requirementDiagram-6fc4c22a-7ec5410f.js +52 -0
- rasa/core/channels/inspector/dist/assets/sankeyDiagram-8f13d901-caee5554.js +8 -0
- rasa/core/channels/inspector/dist/assets/sequenceDiagram-b655622a-2935f8db.js +122 -0
- rasa/core/channels/inspector/dist/assets/stateDiagram-59f0c015-8f5d9693.js +1 -0
- rasa/core/channels/inspector/dist/assets/stateDiagram-v2-2b26beab-d565d1de.js +1 -0
- rasa/core/channels/inspector/dist/assets/styles-080da4f6-75ad421d.js +110 -0
- rasa/core/channels/inspector/dist/assets/styles-3dcbcfbf-7e764226.js +159 -0
- rasa/core/channels/inspector/dist/assets/styles-9c745c82-7a4e0e61.js +207 -0
- rasa/core/channels/inspector/dist/assets/svgDrawCommon-4835440b-4019d1bf.js +1 -0
- rasa/core/channels/inspector/dist/assets/timeline-definition-5b62e21b-01ea12df.js +61 -0
- rasa/core/channels/inspector/dist/assets/xychartDiagram-2b33534f-89407137.js +7 -0
- rasa/core/channels/inspector/dist/index.html +42 -0
- rasa/core/channels/inspector/index.html +40 -0
- rasa/core/channels/inspector/jest.config.ts +13 -0
- rasa/core/channels/inspector/package.json +52 -0
- rasa/core/channels/inspector/setupTests.ts +2 -0
- rasa/core/channels/inspector/src/App.tsx +220 -0
- rasa/core/channels/inspector/src/components/Chat.tsx +95 -0
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +108 -0
- rasa/core/channels/inspector/src/components/DialogueInformation.tsx +187 -0
- rasa/core/channels/inspector/src/components/DialogueStack.tsx +136 -0
- rasa/core/channels/inspector/src/components/ExpandIcon.tsx +16 -0
- rasa/core/channels/inspector/src/components/FullscreenButton.tsx +45 -0
- rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +22 -0
- rasa/core/channels/inspector/src/components/NoActiveFlow.tsx +21 -0
- rasa/core/channels/inspector/src/components/RasaLogo.tsx +32 -0
- rasa/core/channels/inspector/src/components/SaraDiagrams.tsx +39 -0
- rasa/core/channels/inspector/src/components/Slots.tsx +91 -0
- rasa/core/channels/inspector/src/components/Welcome.tsx +54 -0
- rasa/core/channels/inspector/src/helpers/audiostream.ts +191 -0
- rasa/core/channels/inspector/src/helpers/formatters.test.ts +392 -0
- rasa/core/channels/inspector/src/helpers/formatters.ts +306 -0
- rasa/core/channels/inspector/src/helpers/utils.ts +127 -0
- rasa/core/channels/inspector/src/main.tsx +13 -0
- rasa/core/channels/inspector/src/theme/Button/Button.ts +29 -0
- rasa/core/channels/inspector/src/theme/Heading/Heading.ts +31 -0
- rasa/core/channels/inspector/src/theme/Input/Input.ts +27 -0
- rasa/core/channels/inspector/src/theme/Link/Link.ts +10 -0
- rasa/core/channels/inspector/src/theme/Modal/Modal.ts +47 -0
- rasa/core/channels/inspector/src/theme/Table/Table.tsx +38 -0
- rasa/core/channels/inspector/src/theme/Tooltip/Tooltip.ts +12 -0
- rasa/core/channels/inspector/src/theme/base/breakpoints.ts +8 -0
- rasa/core/channels/inspector/src/theme/base/colors.ts +88 -0
- rasa/core/channels/inspector/src/theme/base/fonts/fontFaces.css +29 -0
- rasa/core/channels/inspector/src/theme/base/fonts/ibm-plex-mono-v4-latin/ibm-plex-mono-v4-latin-regular.eot +0 -0
- rasa/core/channels/inspector/src/theme/base/fonts/ibm-plex-mono-v4-latin/ibm-plex-mono-v4-latin-regular.svg +329 -0
- rasa/core/channels/inspector/src/theme/base/fonts/ibm-plex-mono-v4-latin/ibm-plex-mono-v4-latin-regular.ttf +0 -0
- rasa/core/channels/inspector/src/theme/base/fonts/ibm-plex-mono-v4-latin/ibm-plex-mono-v4-latin-regular.woff +0 -0
- rasa/core/channels/inspector/src/theme/base/fonts/ibm-plex-mono-v4-latin/ibm-plex-mono-v4-latin-regular.woff2 +0 -0
- rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-700.eot +0 -0
- rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-700.svg +438 -0
- rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-700.ttf +0 -0
- rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-700.woff +0 -0
- rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-700.woff2 +0 -0
- rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-regular.eot +0 -0
- rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-regular.svg +435 -0
- rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-regular.ttf +0 -0
- rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-regular.woff +0 -0
- rasa/core/channels/inspector/src/theme/base/fonts/lato-v14-latin/lato-v14-latin-regular.woff2 +0 -0
- rasa/core/channels/inspector/src/theme/base/radii.ts +9 -0
- rasa/core/channels/inspector/src/theme/base/shadows.ts +7 -0
- rasa/core/channels/inspector/src/theme/base/sizes.ts +7 -0
- rasa/core/channels/inspector/src/theme/base/space.ts +15 -0
- rasa/core/channels/inspector/src/theme/base/styles.ts +13 -0
- rasa/core/channels/inspector/src/theme/base/typography.ts +24 -0
- rasa/core/channels/inspector/src/theme/base/zIndices.ts +19 -0
- rasa/core/channels/inspector/src/theme/index.ts +101 -0
- rasa/core/channels/inspector/src/types.ts +84 -0
- rasa/core/channels/inspector/src/vite-env.d.ts +1 -0
- rasa/core/channels/inspector/tests/__mocks__/fileMock.ts +1 -0
- rasa/core/channels/inspector/tests/__mocks__/matchMedia.ts +16 -0
- rasa/core/channels/inspector/tests/__mocks__/styleMock.ts +1 -0
- rasa/core/channels/inspector/tests/renderWithProviders.tsx +14 -0
- rasa/core/channels/inspector/tsconfig.json +26 -0
- rasa/core/channels/inspector/tsconfig.node.json +10 -0
- rasa/core/channels/inspector/vite.config.ts +8 -0
- rasa/core/channels/inspector/yarn.lock +6249 -0
- rasa/core/channels/mattermost.py +229 -0
- rasa/core/channels/rasa_chat.py +126 -0
- rasa/core/channels/rest.py +230 -0
- rasa/core/channels/rocketchat.py +174 -0
- rasa/core/channels/slack.py +620 -0
- rasa/core/channels/socketio.py +302 -0
- rasa/core/channels/telegram.py +298 -0
- rasa/core/channels/twilio.py +169 -0
- rasa/core/channels/vier_cvg.py +374 -0
- rasa/core/channels/voice_ready/__init__.py +0 -0
- rasa/core/channels/voice_ready/audiocodes.py +501 -0
- rasa/core/channels/voice_ready/jambonz.py +121 -0
- rasa/core/channels/voice_ready/jambonz_protocol.py +396 -0
- rasa/core/channels/voice_ready/twilio_voice.py +403 -0
- rasa/core/channels/voice_ready/utils.py +37 -0
- rasa/core/channels/voice_stream/__init__.py +0 -0
- rasa/core/channels/voice_stream/asr/__init__.py +0 -0
- rasa/core/channels/voice_stream/asr/asr_engine.py +89 -0
- rasa/core/channels/voice_stream/asr/asr_event.py +18 -0
- rasa/core/channels/voice_stream/asr/azure.py +130 -0
- rasa/core/channels/voice_stream/asr/deepgram.py +90 -0
- rasa/core/channels/voice_stream/audio_bytes.py +8 -0
- rasa/core/channels/voice_stream/browser_audio.py +107 -0
- rasa/core/channels/voice_stream/call_state.py +23 -0
- rasa/core/channels/voice_stream/tts/__init__.py +0 -0
- rasa/core/channels/voice_stream/tts/azure.py +106 -0
- rasa/core/channels/voice_stream/tts/cartesia.py +118 -0
- rasa/core/channels/voice_stream/tts/tts_cache.py +27 -0
- rasa/core/channels/voice_stream/tts/tts_engine.py +58 -0
- rasa/core/channels/voice_stream/twilio_media_streams.py +173 -0
- rasa/core/channels/voice_stream/util.py +57 -0
- rasa/core/channels/voice_stream/voice_channel.py +427 -0
- rasa/core/channels/webexteams.py +134 -0
- rasa/core/concurrent_lock_store.py +210 -0
- rasa/core/constants.py +112 -0
- rasa/core/evaluation/__init__.py +0 -0
- rasa/core/evaluation/marker.py +267 -0
- rasa/core/evaluation/marker_base.py +923 -0
- rasa/core/evaluation/marker_stats.py +293 -0
- rasa/core/evaluation/marker_tracker_loader.py +103 -0
- rasa/core/exceptions.py +29 -0
- rasa/core/exporter.py +284 -0
- rasa/core/featurizers/__init__.py +0 -0
- rasa/core/featurizers/precomputation.py +410 -0
- rasa/core/featurizers/single_state_featurizer.py +421 -0
- rasa/core/featurizers/tracker_featurizers.py +1262 -0
- rasa/core/http_interpreter.py +89 -0
- rasa/core/information_retrieval/__init__.py +7 -0
- rasa/core/information_retrieval/faiss.py +124 -0
- rasa/core/information_retrieval/information_retrieval.py +137 -0
- rasa/core/information_retrieval/milvus.py +59 -0
- rasa/core/information_retrieval/qdrant.py +96 -0
- rasa/core/jobs.py +63 -0
- rasa/core/lock.py +139 -0
- rasa/core/lock_store.py +343 -0
- rasa/core/migrate.py +403 -0
- rasa/core/nlg/__init__.py +3 -0
- rasa/core/nlg/callback.py +146 -0
- rasa/core/nlg/contextual_response_rephraser.py +320 -0
- rasa/core/nlg/generator.py +230 -0
- rasa/core/nlg/interpolator.py +143 -0
- rasa/core/nlg/response.py +155 -0
- rasa/core/nlg/summarize.py +70 -0
- rasa/core/persistor.py +538 -0
- rasa/core/policies/__init__.py +0 -0
- rasa/core/policies/ensemble.py +329 -0
- rasa/core/policies/enterprise_search_policy.py +905 -0
- rasa/core/policies/enterprise_search_prompt_template.jinja2 +25 -0
- rasa/core/policies/enterprise_search_prompt_with_citation_template.jinja2 +60 -0
- rasa/core/policies/flow_policy.py +205 -0
- rasa/core/policies/flows/__init__.py +0 -0
- rasa/core/policies/flows/flow_exceptions.py +44 -0
- rasa/core/policies/flows/flow_executor.py +754 -0
- rasa/core/policies/flows/flow_step_result.py +43 -0
- rasa/core/policies/intentless_policy.py +1031 -0
- rasa/core/policies/intentless_prompt_template.jinja2 +22 -0
- rasa/core/policies/memoization.py +538 -0
- rasa/core/policies/policy.py +725 -0
- rasa/core/policies/rule_policy.py +1273 -0
- rasa/core/policies/ted_policy.py +2169 -0
- rasa/core/policies/unexpected_intent_policy.py +1022 -0
- rasa/core/processor.py +1465 -0
- rasa/core/run.py +342 -0
- rasa/core/secrets_manager/__init__.py +0 -0
- rasa/core/secrets_manager/constants.py +36 -0
- rasa/core/secrets_manager/endpoints.py +391 -0
- rasa/core/secrets_manager/factory.py +241 -0
- rasa/core/secrets_manager/secret_manager.py +262 -0
- rasa/core/secrets_manager/vault.py +584 -0
- rasa/core/test.py +1335 -0
- rasa/core/tracker_store.py +1703 -0
- rasa/core/train.py +105 -0
- rasa/core/training/__init__.py +89 -0
- rasa/core/training/converters/__init__.py +0 -0
- rasa/core/training/converters/responses_prefix_converter.py +119 -0
- rasa/core/training/interactive.py +1744 -0
- rasa/core/training/story_conflict.py +381 -0
- rasa/core/training/training.py +93 -0
- rasa/core/utils.py +366 -0
- rasa/core/visualize.py +70 -0
- rasa/dialogue_understanding/__init__.py +0 -0
- rasa/dialogue_understanding/coexistence/__init__.py +0 -0
- rasa/dialogue_understanding/coexistence/constants.py +4 -0
- rasa/dialogue_understanding/coexistence/intent_based_router.py +196 -0
- rasa/dialogue_understanding/coexistence/llm_based_router.py +327 -0
- rasa/dialogue_understanding/coexistence/router_template.jinja2 +12 -0
- rasa/dialogue_understanding/commands/__init__.py +61 -0
- rasa/dialogue_understanding/commands/can_not_handle_command.py +70 -0
- rasa/dialogue_understanding/commands/cancel_flow_command.py +125 -0
- rasa/dialogue_understanding/commands/change_flow_command.py +44 -0
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +57 -0
- rasa/dialogue_understanding/commands/clarify_command.py +86 -0
- rasa/dialogue_understanding/commands/command.py +85 -0
- rasa/dialogue_understanding/commands/correct_slots_command.py +297 -0
- rasa/dialogue_understanding/commands/error_command.py +79 -0
- rasa/dialogue_understanding/commands/free_form_answer_command.py +9 -0
- rasa/dialogue_understanding/commands/handle_code_change_command.py +73 -0
- rasa/dialogue_understanding/commands/human_handoff_command.py +66 -0
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +57 -0
- rasa/dialogue_understanding/commands/noop_command.py +54 -0
- rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +60 -0
- rasa/dialogue_understanding/commands/restart_command.py +58 -0
- rasa/dialogue_understanding/commands/session_end_command.py +61 -0
- rasa/dialogue_understanding/commands/session_start_command.py +59 -0
- rasa/dialogue_understanding/commands/set_slot_command.py +160 -0
- rasa/dialogue_understanding/commands/skip_question_command.py +75 -0
- rasa/dialogue_understanding/commands/start_flow_command.py +107 -0
- rasa/dialogue_understanding/commands/user_silence_command.py +59 -0
- rasa/dialogue_understanding/commands/utils.py +45 -0
- rasa/dialogue_understanding/generator/__init__.py +21 -0
- rasa/dialogue_understanding/generator/command_generator.py +464 -0
- rasa/dialogue_understanding/generator/constants.py +27 -0
- rasa/dialogue_understanding/generator/flow_document_template.jinja2 +4 -0
- rasa/dialogue_understanding/generator/flow_retrieval.py +466 -0
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +500 -0
- rasa/dialogue_understanding/generator/llm_command_generator.py +67 -0
- rasa/dialogue_understanding/generator/multi_step/__init__.py +0 -0
- rasa/dialogue_understanding/generator/multi_step/fill_slots_prompt.jinja2 +62 -0
- rasa/dialogue_understanding/generator/multi_step/handle_flows_prompt.jinja2 +38 -0
- rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +920 -0
- rasa/dialogue_understanding/generator/nlu_command_adapter.py +261 -0
- rasa/dialogue_understanding/generator/single_step/__init__.py +0 -0
- rasa/dialogue_understanding/generator/single_step/command_prompt_template.jinja2 +60 -0
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +486 -0
- rasa/dialogue_understanding/patterns/__init__.py +0 -0
- rasa/dialogue_understanding/patterns/cancel.py +111 -0
- rasa/dialogue_understanding/patterns/cannot_handle.py +43 -0
- rasa/dialogue_understanding/patterns/chitchat.py +37 -0
- rasa/dialogue_understanding/patterns/clarify.py +97 -0
- rasa/dialogue_understanding/patterns/code_change.py +41 -0
- rasa/dialogue_understanding/patterns/collect_information.py +90 -0
- rasa/dialogue_understanding/patterns/completed.py +40 -0
- rasa/dialogue_understanding/patterns/continue_interrupted.py +42 -0
- rasa/dialogue_understanding/patterns/correction.py +278 -0
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +301 -0
- rasa/dialogue_understanding/patterns/human_handoff.py +37 -0
- rasa/dialogue_understanding/patterns/internal_error.py +47 -0
- rasa/dialogue_understanding/patterns/repeat.py +37 -0
- rasa/dialogue_understanding/patterns/restart.py +37 -0
- rasa/dialogue_understanding/patterns/search.py +37 -0
- rasa/dialogue_understanding/patterns/session_start.py +37 -0
- rasa/dialogue_understanding/patterns/skip_question.py +38 -0
- rasa/dialogue_understanding/patterns/user_silence.py +37 -0
- rasa/dialogue_understanding/processor/__init__.py +0 -0
- rasa/dialogue_understanding/processor/command_processor.py +720 -0
- rasa/dialogue_understanding/processor/command_processor_component.py +43 -0
- rasa/dialogue_understanding/stack/__init__.py +0 -0
- rasa/dialogue_understanding/stack/dialogue_stack.py +178 -0
- rasa/dialogue_understanding/stack/frames/__init__.py +19 -0
- rasa/dialogue_understanding/stack/frames/chit_chat_frame.py +27 -0
- rasa/dialogue_understanding/stack/frames/dialogue_stack_frame.py +137 -0
- rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +157 -0
- rasa/dialogue_understanding/stack/frames/pattern_frame.py +10 -0
- rasa/dialogue_understanding/stack/frames/search_frame.py +27 -0
- rasa/dialogue_understanding/stack/utils.py +211 -0
- rasa/dialogue_understanding/utils.py +14 -0
- rasa/dialogue_understanding_test/__init__.py +0 -0
- rasa/dialogue_understanding_test/command_metric_calculation.py +12 -0
- rasa/dialogue_understanding_test/constants.py +17 -0
- rasa/dialogue_understanding_test/du_test_case.py +118 -0
- rasa/dialogue_understanding_test/du_test_result.py +11 -0
- rasa/dialogue_understanding_test/du_test_runner.py +93 -0
- rasa/dialogue_understanding_test/io.py +54 -0
- rasa/dialogue_understanding_test/validation.py +22 -0
- rasa/e2e_test/__init__.py +0 -0
- rasa/e2e_test/aggregate_test_stats_calculator.py +134 -0
- rasa/e2e_test/assertions.py +1345 -0
- rasa/e2e_test/assertions_schema.yml +129 -0
- rasa/e2e_test/constants.py +31 -0
- rasa/e2e_test/e2e_config.py +220 -0
- rasa/e2e_test/e2e_config_schema.yml +26 -0
- rasa/e2e_test/e2e_test_case.py +569 -0
- rasa/e2e_test/e2e_test_converter.py +363 -0
- rasa/e2e_test/e2e_test_converter_prompt.jinja2 +70 -0
- rasa/e2e_test/e2e_test_coverage_report.py +364 -0
- rasa/e2e_test/e2e_test_result.py +54 -0
- rasa/e2e_test/e2e_test_runner.py +1192 -0
- rasa/e2e_test/e2e_test_schema.yml +181 -0
- rasa/e2e_test/pykwalify_extensions.py +39 -0
- rasa/e2e_test/stub_custom_action.py +70 -0
- rasa/e2e_test/utils/__init__.py +0 -0
- rasa/e2e_test/utils/e2e_yaml_utils.py +55 -0
- rasa/e2e_test/utils/io.py +598 -0
- rasa/e2e_test/utils/validation.py +178 -0
- rasa/engine/__init__.py +0 -0
- rasa/engine/caching.py +463 -0
- rasa/engine/constants.py +17 -0
- rasa/engine/exceptions.py +14 -0
- rasa/engine/graph.py +642 -0
- rasa/engine/loader.py +48 -0
- rasa/engine/recipes/__init__.py +0 -0
- rasa/engine/recipes/config_files/default_config.yml +41 -0
- rasa/engine/recipes/default_components.py +97 -0
- rasa/engine/recipes/default_recipe.py +1272 -0
- rasa/engine/recipes/graph_recipe.py +79 -0
- rasa/engine/recipes/recipe.py +93 -0
- rasa/engine/runner/__init__.py +0 -0
- rasa/engine/runner/dask.py +250 -0
- rasa/engine/runner/interface.py +49 -0
- rasa/engine/storage/__init__.py +0 -0
- rasa/engine/storage/local_model_storage.py +244 -0
- rasa/engine/storage/resource.py +110 -0
- rasa/engine/storage/storage.py +199 -0
- rasa/engine/training/__init__.py +0 -0
- rasa/engine/training/components.py +176 -0
- rasa/engine/training/fingerprinting.py +64 -0
- rasa/engine/training/graph_trainer.py +256 -0
- rasa/engine/training/hooks.py +164 -0
- rasa/engine/validation.py +1451 -0
- rasa/env.py +14 -0
- rasa/exceptions.py +69 -0
- rasa/graph_components/__init__.py +0 -0
- rasa/graph_components/converters/__init__.py +0 -0
- rasa/graph_components/converters/nlu_message_converter.py +48 -0
- rasa/graph_components/providers/__init__.py +0 -0
- rasa/graph_components/providers/domain_for_core_training_provider.py +87 -0
- rasa/graph_components/providers/domain_provider.py +71 -0
- rasa/graph_components/providers/flows_provider.py +74 -0
- rasa/graph_components/providers/forms_provider.py +44 -0
- rasa/graph_components/providers/nlu_training_data_provider.py +56 -0
- rasa/graph_components/providers/responses_provider.py +44 -0
- rasa/graph_components/providers/rule_only_provider.py +49 -0
- rasa/graph_components/providers/story_graph_provider.py +96 -0
- rasa/graph_components/providers/training_tracker_provider.py +55 -0
- rasa/graph_components/validators/__init__.py +0 -0
- rasa/graph_components/validators/default_recipe_validator.py +550 -0
- rasa/graph_components/validators/finetuning_validator.py +302 -0
- rasa/hooks.py +111 -0
- rasa/jupyter.py +63 -0
- rasa/llm_fine_tuning/__init__.py +0 -0
- rasa/llm_fine_tuning/annotation_module.py +241 -0
- rasa/llm_fine_tuning/conversations.py +144 -0
- rasa/llm_fine_tuning/llm_data_preparation_module.py +178 -0
- rasa/llm_fine_tuning/paraphrasing/__init__.py +0 -0
- rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +281 -0
- rasa/llm_fine_tuning/paraphrasing/default_rephrase_prompt_template.jina2 +44 -0
- rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +121 -0
- rasa/llm_fine_tuning/paraphrasing/rephrased_user_message.py +10 -0
- rasa/llm_fine_tuning/paraphrasing_module.py +128 -0
- rasa/llm_fine_tuning/storage.py +174 -0
- rasa/llm_fine_tuning/train_test_split_module.py +441 -0
- rasa/markers/__init__.py +0 -0
- rasa/markers/marker.py +269 -0
- rasa/markers/marker_base.py +828 -0
- rasa/markers/upload.py +74 -0
- rasa/markers/validate.py +21 -0
- rasa/model.py +118 -0
- rasa/model_manager/__init__.py +0 -0
- rasa/model_manager/config.py +40 -0
- rasa/model_manager/model_api.py +559 -0
- rasa/model_manager/runner_service.py +286 -0
- rasa/model_manager/socket_bridge.py +146 -0
- rasa/model_manager/studio_jwt_auth.py +86 -0
- rasa/model_manager/trainer_service.py +325 -0
- rasa/model_manager/utils.py +87 -0
- rasa/model_manager/warm_rasa_process.py +187 -0
- rasa/model_service.py +112 -0
- rasa/model_testing.py +457 -0
- rasa/model_training.py +596 -0
- rasa/nlu/__init__.py +7 -0
- rasa/nlu/classifiers/__init__.py +3 -0
- rasa/nlu/classifiers/classifier.py +5 -0
- rasa/nlu/classifiers/diet_classifier.py +1881 -0
- rasa/nlu/classifiers/fallback_classifier.py +192 -0
- rasa/nlu/classifiers/keyword_intent_classifier.py +188 -0
- rasa/nlu/classifiers/logistic_regression_classifier.py +253 -0
- rasa/nlu/classifiers/mitie_intent_classifier.py +156 -0
- rasa/nlu/classifiers/regex_message_handler.py +56 -0
- rasa/nlu/classifiers/sklearn_intent_classifier.py +330 -0
- rasa/nlu/constants.py +77 -0
- rasa/nlu/convert.py +40 -0
- rasa/nlu/emulators/__init__.py +0 -0
- rasa/nlu/emulators/dialogflow.py +55 -0
- rasa/nlu/emulators/emulator.py +49 -0
- rasa/nlu/emulators/luis.py +86 -0
- rasa/nlu/emulators/no_emulator.py +10 -0
- rasa/nlu/emulators/wit.py +56 -0
- rasa/nlu/extractors/__init__.py +0 -0
- rasa/nlu/extractors/crf_entity_extractor.py +715 -0
- rasa/nlu/extractors/duckling_entity_extractor.py +206 -0
- rasa/nlu/extractors/entity_synonyms.py +178 -0
- rasa/nlu/extractors/extractor.py +470 -0
- rasa/nlu/extractors/mitie_entity_extractor.py +293 -0
- rasa/nlu/extractors/regex_entity_extractor.py +220 -0
- rasa/nlu/extractors/spacy_entity_extractor.py +95 -0
- rasa/nlu/featurizers/__init__.py +0 -0
- rasa/nlu/featurizers/dense_featurizer/__init__.py +0 -0
- rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +445 -0
- rasa/nlu/featurizers/dense_featurizer/dense_featurizer.py +57 -0
- rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +768 -0
- rasa/nlu/featurizers/dense_featurizer/mitie_featurizer.py +170 -0
- rasa/nlu/featurizers/dense_featurizer/spacy_featurizer.py +132 -0
- rasa/nlu/featurizers/featurizer.py +89 -0
- rasa/nlu/featurizers/sparse_featurizer/__init__.py +0 -0
- rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +867 -0
- rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +571 -0
- rasa/nlu/featurizers/sparse_featurizer/regex_featurizer.py +271 -0
- rasa/nlu/featurizers/sparse_featurizer/sparse_featurizer.py +9 -0
- rasa/nlu/model.py +24 -0
- rasa/nlu/run.py +27 -0
- rasa/nlu/selectors/__init__.py +0 -0
- rasa/nlu/selectors/response_selector.py +987 -0
- rasa/nlu/test.py +1940 -0
- rasa/nlu/tokenizers/__init__.py +0 -0
- rasa/nlu/tokenizers/jieba_tokenizer.py +148 -0
- rasa/nlu/tokenizers/mitie_tokenizer.py +75 -0
- rasa/nlu/tokenizers/spacy_tokenizer.py +72 -0
- rasa/nlu/tokenizers/tokenizer.py +239 -0
- rasa/nlu/tokenizers/whitespace_tokenizer.py +95 -0
- rasa/nlu/utils/__init__.py +35 -0
- rasa/nlu/utils/bilou_utils.py +462 -0
- rasa/nlu/utils/hugging_face/__init__.py +0 -0
- rasa/nlu/utils/hugging_face/registry.py +108 -0
- rasa/nlu/utils/hugging_face/transformers_pre_post_processors.py +311 -0
- rasa/nlu/utils/mitie_utils.py +113 -0
- rasa/nlu/utils/pattern_utils.py +168 -0
- rasa/nlu/utils/spacy_utils.py +310 -0
- rasa/plugin.py +90 -0
- rasa/server.py +1588 -0
- rasa/shared/__init__.py +0 -0
- rasa/shared/constants.py +311 -0
- rasa/shared/core/__init__.py +0 -0
- rasa/shared/core/command_payload_reader.py +109 -0
- rasa/shared/core/constants.py +180 -0
- rasa/shared/core/conversation.py +46 -0
- rasa/shared/core/domain.py +2172 -0
- rasa/shared/core/events.py +2559 -0
- rasa/shared/core/flows/__init__.py +7 -0
- rasa/shared/core/flows/flow.py +562 -0
- rasa/shared/core/flows/flow_path.py +84 -0
- rasa/shared/core/flows/flow_step.py +146 -0
- rasa/shared/core/flows/flow_step_links.py +319 -0
- rasa/shared/core/flows/flow_step_sequence.py +70 -0
- rasa/shared/core/flows/flows_list.py +258 -0
- rasa/shared/core/flows/flows_yaml_schema.json +303 -0
- rasa/shared/core/flows/nlu_trigger.py +117 -0
- rasa/shared/core/flows/steps/__init__.py +24 -0
- rasa/shared/core/flows/steps/action.py +56 -0
- rasa/shared/core/flows/steps/call.py +64 -0
- rasa/shared/core/flows/steps/collect.py +112 -0
- rasa/shared/core/flows/steps/constants.py +5 -0
- rasa/shared/core/flows/steps/continuation.py +36 -0
- rasa/shared/core/flows/steps/end.py +22 -0
- rasa/shared/core/flows/steps/internal.py +44 -0
- rasa/shared/core/flows/steps/link.py +51 -0
- rasa/shared/core/flows/steps/no_operation.py +48 -0
- rasa/shared/core/flows/steps/set_slots.py +50 -0
- rasa/shared/core/flows/steps/start.py +30 -0
- rasa/shared/core/flows/utils.py +39 -0
- rasa/shared/core/flows/validation.py +735 -0
- rasa/shared/core/flows/yaml_flows_io.py +405 -0
- rasa/shared/core/generator.py +908 -0
- rasa/shared/core/slot_mappings.py +526 -0
- rasa/shared/core/slots.py +654 -0
- rasa/shared/core/trackers.py +1183 -0
- rasa/shared/core/training_data/__init__.py +0 -0
- rasa/shared/core/training_data/loading.py +89 -0
- rasa/shared/core/training_data/story_reader/__init__.py +0 -0
- rasa/shared/core/training_data/story_reader/story_reader.py +129 -0
- rasa/shared/core/training_data/story_reader/story_step_builder.py +168 -0
- rasa/shared/core/training_data/story_reader/yaml_story_reader.py +888 -0
- rasa/shared/core/training_data/story_writer/__init__.py +0 -0
- rasa/shared/core/training_data/story_writer/story_writer.py +76 -0
- rasa/shared/core/training_data/story_writer/yaml_story_writer.py +444 -0
- rasa/shared/core/training_data/structures.py +858 -0
- rasa/shared/core/training_data/visualization.html +146 -0
- rasa/shared/core/training_data/visualization.py +603 -0
- rasa/shared/data.py +249 -0
- rasa/shared/engine/__init__.py +0 -0
- rasa/shared/engine/caching.py +26 -0
- rasa/shared/exceptions.py +167 -0
- rasa/shared/importers/__init__.py +0 -0
- rasa/shared/importers/importer.py +770 -0
- rasa/shared/importers/multi_project.py +215 -0
- rasa/shared/importers/rasa.py +108 -0
- rasa/shared/importers/remote_importer.py +196 -0
- rasa/shared/importers/utils.py +36 -0
- rasa/shared/nlu/__init__.py +0 -0
- rasa/shared/nlu/constants.py +53 -0
- rasa/shared/nlu/interpreter.py +10 -0
- rasa/shared/nlu/training_data/__init__.py +0 -0
- rasa/shared/nlu/training_data/entities_parser.py +208 -0
- rasa/shared/nlu/training_data/features.py +492 -0
- rasa/shared/nlu/training_data/formats/__init__.py +10 -0
- rasa/shared/nlu/training_data/formats/dialogflow.py +163 -0
- rasa/shared/nlu/training_data/formats/luis.py +87 -0
- rasa/shared/nlu/training_data/formats/rasa.py +135 -0
- rasa/shared/nlu/training_data/formats/rasa_yaml.py +618 -0
- rasa/shared/nlu/training_data/formats/readerwriter.py +244 -0
- rasa/shared/nlu/training_data/formats/wit.py +52 -0
- rasa/shared/nlu/training_data/loading.py +137 -0
- rasa/shared/nlu/training_data/lookup_tables_parser.py +30 -0
- rasa/shared/nlu/training_data/message.py +490 -0
- rasa/shared/nlu/training_data/schemas/__init__.py +0 -0
- rasa/shared/nlu/training_data/schemas/data_schema.py +85 -0
- rasa/shared/nlu/training_data/schemas/nlu.yml +53 -0
- rasa/shared/nlu/training_data/schemas/responses.yml +70 -0
- rasa/shared/nlu/training_data/synonyms_parser.py +42 -0
- rasa/shared/nlu/training_data/training_data.py +729 -0
- rasa/shared/nlu/training_data/util.py +223 -0
- rasa/shared/providers/__init__.py +0 -0
- rasa/shared/providers/_configs/__init__.py +0 -0
- rasa/shared/providers/_configs/azure_openai_client_config.py +677 -0
- rasa/shared/providers/_configs/client_config.py +59 -0
- rasa/shared/providers/_configs/default_litellm_client_config.py +132 -0
- rasa/shared/providers/_configs/huggingface_local_embedding_client_config.py +236 -0
- rasa/shared/providers/_configs/litellm_router_client_config.py +222 -0
- rasa/shared/providers/_configs/model_group_config.py +173 -0
- rasa/shared/providers/_configs/openai_client_config.py +177 -0
- rasa/shared/providers/_configs/rasa_llm_client_config.py +75 -0
- rasa/shared/providers/_configs/self_hosted_llm_client_config.py +178 -0
- rasa/shared/providers/_configs/utils.py +117 -0
- rasa/shared/providers/_ssl_verification_utils.py +124 -0
- rasa/shared/providers/_utils.py +79 -0
- rasa/shared/providers/constants.py +7 -0
- rasa/shared/providers/embedding/__init__.py +0 -0
- rasa/shared/providers/embedding/_base_litellm_embedding_client.py +243 -0
- rasa/shared/providers/embedding/_langchain_embedding_client_adapter.py +74 -0
- rasa/shared/providers/embedding/azure_openai_embedding_client.py +335 -0
- rasa/shared/providers/embedding/default_litellm_embedding_client.py +126 -0
- rasa/shared/providers/embedding/embedding_client.py +90 -0
- rasa/shared/providers/embedding/embedding_response.py +41 -0
- rasa/shared/providers/embedding/huggingface_local_embedding_client.py +191 -0
- rasa/shared/providers/embedding/litellm_router_embedding_client.py +138 -0
- rasa/shared/providers/embedding/openai_embedding_client.py +172 -0
- rasa/shared/providers/llm/__init__.py +0 -0
- rasa/shared/providers/llm/_base_litellm_client.py +265 -0
- rasa/shared/providers/llm/azure_openai_llm_client.py +415 -0
- rasa/shared/providers/llm/default_litellm_llm_client.py +110 -0
- rasa/shared/providers/llm/litellm_router_llm_client.py +202 -0
- rasa/shared/providers/llm/llm_client.py +78 -0
- rasa/shared/providers/llm/llm_response.py +50 -0
- rasa/shared/providers/llm/openai_llm_client.py +161 -0
- rasa/shared/providers/llm/rasa_llm_client.py +120 -0
- rasa/shared/providers/llm/self_hosted_llm_client.py +276 -0
- rasa/shared/providers/mappings.py +94 -0
- rasa/shared/providers/router/__init__.py +0 -0
- rasa/shared/providers/router/_base_litellm_router_client.py +185 -0
- rasa/shared/providers/router/router_client.py +75 -0
- rasa/shared/utils/__init__.py +0 -0
- rasa/shared/utils/cli.py +102 -0
- rasa/shared/utils/common.py +324 -0
- rasa/shared/utils/constants.py +4 -0
- rasa/shared/utils/health_check/__init__.py +0 -0
- rasa/shared/utils/health_check/embeddings_health_check_mixin.py +31 -0
- rasa/shared/utils/health_check/health_check.py +258 -0
- rasa/shared/utils/health_check/llm_health_check_mixin.py +31 -0
- rasa/shared/utils/io.py +499 -0
- rasa/shared/utils/llm.py +764 -0
- rasa/shared/utils/pykwalify_extensions.py +27 -0
- rasa/shared/utils/schemas/__init__.py +0 -0
- rasa/shared/utils/schemas/config.yml +2 -0
- rasa/shared/utils/schemas/domain.yml +145 -0
- rasa/shared/utils/schemas/events.py +214 -0
- rasa/shared/utils/schemas/model_config.yml +36 -0
- rasa/shared/utils/schemas/stories.yml +173 -0
- rasa/shared/utils/yaml.py +1068 -0
- rasa/studio/__init__.py +0 -0
- rasa/studio/auth.py +270 -0
- rasa/studio/config.py +136 -0
- rasa/studio/constants.py +19 -0
- rasa/studio/data_handler.py +368 -0
- rasa/studio/download.py +489 -0
- rasa/studio/results_logger.py +137 -0
- rasa/studio/train.py +134 -0
- rasa/studio/upload.py +563 -0
- rasa/telemetry.py +1876 -0
- rasa/tracing/__init__.py +0 -0
- rasa/tracing/config.py +355 -0
- rasa/tracing/constants.py +62 -0
- rasa/tracing/instrumentation/__init__.py +0 -0
- rasa/tracing/instrumentation/attribute_extractors.py +765 -0
- rasa/tracing/instrumentation/instrumentation.py +1306 -0
- rasa/tracing/instrumentation/intentless_policy_instrumentation.py +144 -0
- rasa/tracing/instrumentation/metrics.py +294 -0
- rasa/tracing/metric_instrument_provider.py +205 -0
- rasa/utils/__init__.py +0 -0
- rasa/utils/beta.py +83 -0
- rasa/utils/cli.py +28 -0
- rasa/utils/common.py +639 -0
- rasa/utils/converter.py +53 -0
- rasa/utils/endpoints.py +331 -0
- rasa/utils/io.py +252 -0
- rasa/utils/json_utils.py +60 -0
- rasa/utils/licensing.py +542 -0
- rasa/utils/log_utils.py +181 -0
- rasa/utils/mapper.py +210 -0
- rasa/utils/ml_utils.py +147 -0
- rasa/utils/plotting.py +362 -0
- rasa/utils/sanic_error_handler.py +32 -0
- rasa/utils/singleton.py +23 -0
- rasa/utils/tensorflow/__init__.py +0 -0
- rasa/utils/tensorflow/callback.py +112 -0
- rasa/utils/tensorflow/constants.py +116 -0
- rasa/utils/tensorflow/crf.py +492 -0
- rasa/utils/tensorflow/data_generator.py +440 -0
- rasa/utils/tensorflow/environment.py +161 -0
- rasa/utils/tensorflow/exceptions.py +5 -0
- rasa/utils/tensorflow/feature_array.py +366 -0
- rasa/utils/tensorflow/layers.py +1565 -0
- rasa/utils/tensorflow/layers_utils.py +113 -0
- rasa/utils/tensorflow/metrics.py +281 -0
- rasa/utils/tensorflow/model_data.py +798 -0
- rasa/utils/tensorflow/model_data_utils.py +499 -0
- rasa/utils/tensorflow/models.py +935 -0
- rasa/utils/tensorflow/rasa_layers.py +1094 -0
- rasa/utils/tensorflow/transformer.py +640 -0
- rasa/utils/tensorflow/types.py +6 -0
- rasa/utils/train_utils.py +572 -0
- rasa/utils/url_tools.py +53 -0
- rasa/utils/yaml.py +54 -0
- rasa/validator.py +1644 -0
- rasa/version.py +3 -0
- rasa_pro-3.12.0.dev1.dist-info/METADATA +199 -0
- rasa_pro-3.12.0.dev1.dist-info/NOTICE +5 -0
- rasa_pro-3.12.0.dev1.dist-info/RECORD +790 -0
- rasa_pro-3.12.0.dev1.dist-info/WHEEL +4 -0
- rasa_pro-3.12.0.dev1.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,2559 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import copy
|
|
3
|
+
import json
|
|
4
|
+
import logging
|
|
5
|
+
import structlog
|
|
6
|
+
import re
|
|
7
|
+
from abc import ABC
|
|
8
|
+
|
|
9
|
+
import jsonpickle
|
|
10
|
+
import time
|
|
11
|
+
import uuid
|
|
12
|
+
from dateutil import parser
|
|
13
|
+
from datetime import datetime
|
|
14
|
+
from typing import (
|
|
15
|
+
List,
|
|
16
|
+
Dict,
|
|
17
|
+
Text,
|
|
18
|
+
Any,
|
|
19
|
+
Type,
|
|
20
|
+
Optional,
|
|
21
|
+
TYPE_CHECKING,
|
|
22
|
+
Iterable,
|
|
23
|
+
cast,
|
|
24
|
+
Tuple,
|
|
25
|
+
TypeVar,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
import rasa.shared.utils.common
|
|
29
|
+
import rasa.shared.utils.io
|
|
30
|
+
from typing import Union
|
|
31
|
+
|
|
32
|
+
from rasa.shared.constants import DOCS_URL_TRAINING_DATA
|
|
33
|
+
from rasa.shared.core.constants import (
|
|
34
|
+
LOOP_NAME,
|
|
35
|
+
EXTERNAL_MESSAGE_PREFIX,
|
|
36
|
+
ACTION_NAME_SENDER_ID_CONNECTOR_STR,
|
|
37
|
+
IS_EXTERNAL,
|
|
38
|
+
USE_TEXT_FOR_FEATURIZATION,
|
|
39
|
+
LOOP_INTERRUPTED,
|
|
40
|
+
ENTITY_LABEL_SEPARATOR,
|
|
41
|
+
ACTION_SESSION_START_NAME,
|
|
42
|
+
ACTION_LISTEN_NAME,
|
|
43
|
+
)
|
|
44
|
+
from rasa.shared.exceptions import UnsupportedFeatureException
|
|
45
|
+
from rasa.shared.nlu.constants import (
|
|
46
|
+
ENTITY_ATTRIBUTE_TYPE,
|
|
47
|
+
INTENT,
|
|
48
|
+
TEXT,
|
|
49
|
+
ENTITIES,
|
|
50
|
+
COMMANDS,
|
|
51
|
+
ENTITY_ATTRIBUTE_VALUE,
|
|
52
|
+
ACTION_TEXT,
|
|
53
|
+
ACTION_NAME,
|
|
54
|
+
INTENT_NAME_KEY,
|
|
55
|
+
ENTITY_ATTRIBUTE_ROLE,
|
|
56
|
+
ENTITY_ATTRIBUTE_GROUP,
|
|
57
|
+
PREDICTED_CONFIDENCE_KEY,
|
|
58
|
+
INTENT_RANKING_KEY,
|
|
59
|
+
ENTITY_ATTRIBUTE_TEXT,
|
|
60
|
+
ENTITY_ATTRIBUTE_START,
|
|
61
|
+
ENTITY_ATTRIBUTE_CONFIDENCE,
|
|
62
|
+
ENTITY_ATTRIBUTE_END,
|
|
63
|
+
FULL_RETRIEVAL_INTENT_NAME_KEY,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
if TYPE_CHECKING:
|
|
68
|
+
from typing_extensions import TypedDict
|
|
69
|
+
|
|
70
|
+
from rasa.shared.core.trackers import DialogueStateTracker
|
|
71
|
+
|
|
72
|
+
EntityPrediction = TypedDict(
|
|
73
|
+
"EntityPrediction",
|
|
74
|
+
{
|
|
75
|
+
ENTITY_ATTRIBUTE_TEXT: Text, # type: ignore[misc]
|
|
76
|
+
ENTITY_ATTRIBUTE_START: Optional[float],
|
|
77
|
+
ENTITY_ATTRIBUTE_END: Optional[float],
|
|
78
|
+
ENTITY_ATTRIBUTE_VALUE: Text,
|
|
79
|
+
ENTITY_ATTRIBUTE_CONFIDENCE: float,
|
|
80
|
+
ENTITY_ATTRIBUTE_TYPE: Text,
|
|
81
|
+
ENTITY_ATTRIBUTE_GROUP: Optional[Text],
|
|
82
|
+
ENTITY_ATTRIBUTE_ROLE: Optional[Text],
|
|
83
|
+
"additional_info": Any,
|
|
84
|
+
},
|
|
85
|
+
total=False,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
IntentPrediction = TypedDict(
|
|
89
|
+
"IntentPrediction",
|
|
90
|
+
{INTENT_NAME_KEY: Text, PREDICTED_CONFIDENCE_KEY: float}, # type: ignore[misc]
|
|
91
|
+
)
|
|
92
|
+
NLUPredictionData = TypedDict(
|
|
93
|
+
"NLUPredictionData",
|
|
94
|
+
{
|
|
95
|
+
TEXT: Text, # type: ignore[misc]
|
|
96
|
+
INTENT: IntentPrediction,
|
|
97
|
+
INTENT_RANKING_KEY: List[IntentPrediction],
|
|
98
|
+
ENTITIES: List[EntityPrediction],
|
|
99
|
+
"message_id": Optional[Text],
|
|
100
|
+
"metadata": Dict,
|
|
101
|
+
},
|
|
102
|
+
total=False,
|
|
103
|
+
)
|
|
104
|
+
logger = logging.getLogger(__name__)
|
|
105
|
+
structlogger = structlog.get_logger()
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def deserialise_events(serialized_events: List[Dict[Text, Any]]) -> List["Event"]:
|
|
109
|
+
"""Convert a list of dictionaries to a list of corresponding events.
|
|
110
|
+
|
|
111
|
+
Example format:
|
|
112
|
+
[{"event": "slot", "value": 5, "name": "my_slot"}]
|
|
113
|
+
"""
|
|
114
|
+
deserialised = []
|
|
115
|
+
|
|
116
|
+
for e in serialized_events:
|
|
117
|
+
if "event" in e:
|
|
118
|
+
event = Event.from_parameters(e)
|
|
119
|
+
if event:
|
|
120
|
+
deserialised.append(event)
|
|
121
|
+
else:
|
|
122
|
+
structlogger.warning(
|
|
123
|
+
"event.deserialization.failed", rasa_event=copy.deepcopy(event)
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
return deserialised
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def deserialise_entities(entities: Union[Text, List[Any]]) -> List[Dict[Text, Any]]:
|
|
130
|
+
if isinstance(entities, str):
|
|
131
|
+
entities = json.loads(entities)
|
|
132
|
+
|
|
133
|
+
return [e for e in entities if isinstance(e, dict)]
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def format_message(
|
|
137
|
+
text: Text, intent: Optional[Text], entities: Union[Text, List[Any]]
|
|
138
|
+
) -> Text:
|
|
139
|
+
"""Uses NLU parser information to generate a message with inline entity annotations.
|
|
140
|
+
|
|
141
|
+
Arguments:
|
|
142
|
+
text: text of the message
|
|
143
|
+
intent: intent of the message
|
|
144
|
+
entities: entities of the message
|
|
145
|
+
|
|
146
|
+
Return:
|
|
147
|
+
Message with entities annotated inline, e.g.
|
|
148
|
+
`I am from [Berlin]{`"`entity`"`: `"`city`"`}`.
|
|
149
|
+
"""
|
|
150
|
+
from rasa.shared.nlu.training_data.formats.readerwriter import TrainingDataWriter
|
|
151
|
+
from rasa.shared.nlu.training_data import entities_parser
|
|
152
|
+
|
|
153
|
+
message_from_md = entities_parser.parse_training_example(text, intent)
|
|
154
|
+
deserialised_entities = deserialise_entities(entities)
|
|
155
|
+
return TrainingDataWriter.generate_message(
|
|
156
|
+
{"text": message_from_md.get(TEXT), "entities": deserialised_entities}
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def split_events(
|
|
161
|
+
events: Iterable["Event"],
|
|
162
|
+
event_type_to_split_on: Type["Event"],
|
|
163
|
+
additional_splitting_conditions: Optional[Dict[Text, Any]] = None,
|
|
164
|
+
include_splitting_event: bool = True,
|
|
165
|
+
) -> List[List["Event"]]:
|
|
166
|
+
"""Splits events according to an event type and condition.
|
|
167
|
+
|
|
168
|
+
Examples:
|
|
169
|
+
Splitting events according to the event type `ActionExecuted` and the
|
|
170
|
+
`action_name` 'action_session_start' would look as follows:
|
|
171
|
+
|
|
172
|
+
>> _events = split_events(
|
|
173
|
+
events,
|
|
174
|
+
ActionExecuted,
|
|
175
|
+
{"action_name": "action_session_start"},
|
|
176
|
+
True
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
events: Events to split.
|
|
181
|
+
event_type_to_split_on: The event type to split on.
|
|
182
|
+
additional_splitting_conditions: Additional event attributes to split on.
|
|
183
|
+
include_splitting_event: Whether the events of the type on which the split
|
|
184
|
+
is based should be included in the returned events.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
The split events.
|
|
188
|
+
"""
|
|
189
|
+
sub_events = []
|
|
190
|
+
current: List["Event"] = []
|
|
191
|
+
|
|
192
|
+
def event_fulfills_splitting_condition(evt: "Event") -> bool:
|
|
193
|
+
# event does not have the correct type
|
|
194
|
+
if not isinstance(evt, event_type_to_split_on):
|
|
195
|
+
return False
|
|
196
|
+
|
|
197
|
+
# the type is correct and there are no further conditions
|
|
198
|
+
if not additional_splitting_conditions:
|
|
199
|
+
return True
|
|
200
|
+
|
|
201
|
+
# there are further conditions - check those
|
|
202
|
+
return all(
|
|
203
|
+
getattr(evt, k, None) == v
|
|
204
|
+
for k, v in additional_splitting_conditions.items()
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
for event in events:
|
|
208
|
+
if event_fulfills_splitting_condition(event):
|
|
209
|
+
if current:
|
|
210
|
+
sub_events.append(current)
|
|
211
|
+
|
|
212
|
+
current = []
|
|
213
|
+
if include_splitting_event:
|
|
214
|
+
current.append(event)
|
|
215
|
+
else:
|
|
216
|
+
current.append(event)
|
|
217
|
+
|
|
218
|
+
if current:
|
|
219
|
+
sub_events.append(current)
|
|
220
|
+
|
|
221
|
+
return sub_events
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def do_events_begin_with_session_start(events: List["Event"]) -> bool:
|
|
225
|
+
"""Determines whether `events` begins with a session start sequence.
|
|
226
|
+
|
|
227
|
+
A session start sequence is a sequence of two events: an executed
|
|
228
|
+
`action_session_start` as well as a logged `session_started`.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
events: The events to inspect.
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
Whether `events` begins with a session start sequence.
|
|
235
|
+
"""
|
|
236
|
+
if len(events) < 2:
|
|
237
|
+
return False
|
|
238
|
+
|
|
239
|
+
first = events[0]
|
|
240
|
+
second = events[1]
|
|
241
|
+
|
|
242
|
+
# We are not interested in specific metadata or timestamps. Action name and event
|
|
243
|
+
# type are sufficient for this check
|
|
244
|
+
return (
|
|
245
|
+
isinstance(first, ActionExecuted)
|
|
246
|
+
and first.action_name == ACTION_SESSION_START_NAME
|
|
247
|
+
and isinstance(second, SessionStarted)
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def remove_parse_data(event: Dict[Text, Any]) -> Dict[Text, Any]:
|
|
252
|
+
"""Reduce event details to the minimum necessary to be structlogged.
|
|
253
|
+
|
|
254
|
+
Deletes the parse_data key from the event if it exists.
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
event: The event to be reduced.
|
|
258
|
+
|
|
259
|
+
Returns:
|
|
260
|
+
A reduced copy of the event.
|
|
261
|
+
"""
|
|
262
|
+
reduced_event = copy.deepcopy(event)
|
|
263
|
+
if "parse_data" in reduced_event:
|
|
264
|
+
del reduced_event["parse_data"]
|
|
265
|
+
return reduced_event
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
E = TypeVar("E", bound="Event")
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class Event(ABC):
|
|
272
|
+
"""Describes events in conversation and how the affect the conversation state.
|
|
273
|
+
|
|
274
|
+
Immutable representation of everything which happened during a conversation of the
|
|
275
|
+
user with the assistant. Tells the `rasa.shared.core.trackers.DialogueStateTracker`
|
|
276
|
+
how to update its state as the events occur.
|
|
277
|
+
"""
|
|
278
|
+
|
|
279
|
+
type_name = "event"
|
|
280
|
+
|
|
281
|
+
def __init__(
|
|
282
|
+
self,
|
|
283
|
+
timestamp: Optional[float] = None,
|
|
284
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
285
|
+
) -> None:
|
|
286
|
+
self.timestamp = timestamp or time.time()
|
|
287
|
+
self.metadata = metadata or {}
|
|
288
|
+
|
|
289
|
+
def __ne__(self, other: Any) -> bool:
|
|
290
|
+
# Not strictly necessary, but to avoid having both x==y and x!=y
|
|
291
|
+
# True at the same time
|
|
292
|
+
return not (self == other)
|
|
293
|
+
|
|
294
|
+
@abc.abstractmethod
|
|
295
|
+
def as_story_string(self) -> Optional[Text]:
|
|
296
|
+
"""Returns the event as story string.
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
textual representation of the event or None.
|
|
300
|
+
"""
|
|
301
|
+
# Every class should implement this
|
|
302
|
+
raise NotImplementedError
|
|
303
|
+
|
|
304
|
+
@staticmethod
|
|
305
|
+
def from_story_string(
|
|
306
|
+
event_name: Text,
|
|
307
|
+
parameters: Dict[Text, Any],
|
|
308
|
+
default: Optional[Type["Event"]] = None,
|
|
309
|
+
) -> Optional[List["Event"]]:
|
|
310
|
+
event_class = Event.resolve_by_type(event_name, default)
|
|
311
|
+
|
|
312
|
+
if not event_class:
|
|
313
|
+
return None
|
|
314
|
+
|
|
315
|
+
return event_class._from_story_string(parameters)
|
|
316
|
+
|
|
317
|
+
@staticmethod
|
|
318
|
+
def from_parameters(
|
|
319
|
+
parameters: Dict[Text, Any], default: Optional[Type["Event"]] = None
|
|
320
|
+
) -> Optional["Event"]:
|
|
321
|
+
event_name = parameters.get("event")
|
|
322
|
+
if event_name is None:
|
|
323
|
+
return None
|
|
324
|
+
|
|
325
|
+
event_class: Optional[Type[Event]] = Event.resolve_by_type(event_name, default)
|
|
326
|
+
if not event_class:
|
|
327
|
+
return None
|
|
328
|
+
|
|
329
|
+
return event_class._from_parameters(parameters)
|
|
330
|
+
|
|
331
|
+
@classmethod
|
|
332
|
+
def _from_story_string(
|
|
333
|
+
cls: Type[E], parameters: Dict[Text, Any]
|
|
334
|
+
) -> Optional[List[E]]:
|
|
335
|
+
"""Called to convert a parsed story line into an event."""
|
|
336
|
+
return [cls(parameters.get("timestamp"), parameters.get("metadata"))]
|
|
337
|
+
|
|
338
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
339
|
+
d = {"event": self.type_name, "timestamp": self.timestamp}
|
|
340
|
+
|
|
341
|
+
if self.metadata:
|
|
342
|
+
d["metadata"] = self.metadata
|
|
343
|
+
|
|
344
|
+
return d
|
|
345
|
+
|
|
346
|
+
def fingerprint(self) -> Text:
|
|
347
|
+
"""Returns a unique hash for the event which is stable across python runs.
|
|
348
|
+
|
|
349
|
+
Returns:
|
|
350
|
+
fingerprint of the event
|
|
351
|
+
"""
|
|
352
|
+
data = self.as_dict()
|
|
353
|
+
del data["timestamp"]
|
|
354
|
+
return rasa.shared.utils.io.get_dictionary_fingerprint(data)
|
|
355
|
+
|
|
356
|
+
@classmethod
|
|
357
|
+
def _from_parameters(cls, parameters: Dict[Text, Any]) -> Optional["Event"]:
|
|
358
|
+
"""Called to convert a dictionary of parameters to a single event.
|
|
359
|
+
|
|
360
|
+
By default uses the same implementation as the story line
|
|
361
|
+
conversation ``_from_story_string``. But the subclass might
|
|
362
|
+
decide to handle parameters differently if the parsed parameters
|
|
363
|
+
don't origin from a story file.
|
|
364
|
+
"""
|
|
365
|
+
result = cls._from_story_string(parameters)
|
|
366
|
+
if len(result) > 1:
|
|
367
|
+
logger.warning(
|
|
368
|
+
f"Event from parameters called with parameters "
|
|
369
|
+
f"for multiple events. This is not supported, "
|
|
370
|
+
f"only the first event will be returned. "
|
|
371
|
+
f"Parameters: {parameters}"
|
|
372
|
+
)
|
|
373
|
+
return result[0] if result else None
|
|
374
|
+
|
|
375
|
+
@staticmethod
|
|
376
|
+
def resolve_by_type(
|
|
377
|
+
type_name: Text, default: Optional[Type["Event"]] = None
|
|
378
|
+
) -> Optional[Type["Event"]]:
|
|
379
|
+
"""Returns a slots class by its type name."""
|
|
380
|
+
for cls in rasa.shared.utils.common.all_subclasses(Event):
|
|
381
|
+
if cls.type_name == type_name:
|
|
382
|
+
return cls
|
|
383
|
+
if type_name == "topic":
|
|
384
|
+
return None # backwards compatibility to support old TopicSet evts
|
|
385
|
+
elif default is not None:
|
|
386
|
+
return default
|
|
387
|
+
else:
|
|
388
|
+
raise ValueError(f"Unknown event name '{type_name}'.")
|
|
389
|
+
|
|
390
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
391
|
+
"""Applies event to current conversation state.
|
|
392
|
+
|
|
393
|
+
Args:
|
|
394
|
+
tracker: The current conversation state.
|
|
395
|
+
"""
|
|
396
|
+
pass
|
|
397
|
+
|
|
398
|
+
@abc.abstractmethod
|
|
399
|
+
def __eq__(self, other: Any) -> bool:
|
|
400
|
+
"""Compares object with other object."""
|
|
401
|
+
# Every class should implement this
|
|
402
|
+
raise NotImplementedError()
|
|
403
|
+
|
|
404
|
+
def __str__(self) -> Text:
|
|
405
|
+
"""Returns text representation of event."""
|
|
406
|
+
return f"{self.__class__.__name__}()"
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
class AlwaysEqualEventMixin(Event, ABC):
|
|
410
|
+
"""Class to deduplicate common behavior for events without additional attributes."""
|
|
411
|
+
|
|
412
|
+
def __eq__(self, other: Any) -> bool:
|
|
413
|
+
"""Compares object with other object."""
|
|
414
|
+
if not isinstance(other, self.__class__):
|
|
415
|
+
return NotImplemented
|
|
416
|
+
|
|
417
|
+
return True
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
class SkipEventInMDStoryMixin(Event, ABC):
|
|
421
|
+
"""Skips the visualization of an event in Markdown stories."""
|
|
422
|
+
|
|
423
|
+
def as_story_string(self) -> None:
|
|
424
|
+
"""Returns the event as story string.
|
|
425
|
+
|
|
426
|
+
Returns:
|
|
427
|
+
None, as this event should not appear inside the story.
|
|
428
|
+
"""
|
|
429
|
+
return
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
class UserUttered(Event):
|
|
433
|
+
"""The user has said something to the bot.
|
|
434
|
+
|
|
435
|
+
As a side effect a new `Turn` will be created in the `Tracker`.
|
|
436
|
+
"""
|
|
437
|
+
|
|
438
|
+
type_name = "user"
|
|
439
|
+
|
|
440
|
+
def __init__(
|
|
441
|
+
self,
|
|
442
|
+
text: Optional[Text] = None,
|
|
443
|
+
intent: Optional[Dict] = None,
|
|
444
|
+
entities: Optional[List[Dict]] = None,
|
|
445
|
+
parse_data: Optional["NLUPredictionData"] = None,
|
|
446
|
+
timestamp: Optional[float] = None,
|
|
447
|
+
input_channel: Optional[Text] = None,
|
|
448
|
+
message_id: Optional[Text] = None,
|
|
449
|
+
metadata: Optional[Dict] = None,
|
|
450
|
+
use_text_for_featurization: Optional[bool] = None,
|
|
451
|
+
) -> None:
|
|
452
|
+
"""Creates event for incoming user message.
|
|
453
|
+
|
|
454
|
+
Args:
|
|
455
|
+
text: Text of user message.
|
|
456
|
+
intent: Intent prediction of user message.
|
|
457
|
+
entities: Extracted entities.
|
|
458
|
+
parse_data: Detailed NLU parsing result for message.
|
|
459
|
+
timestamp: When the event was created.
|
|
460
|
+
metadata: Additional event metadata.
|
|
461
|
+
input_channel: Which channel the user used to send message.
|
|
462
|
+
message_id: Unique ID for message.
|
|
463
|
+
use_text_for_featurization: `True` if the message's text was used to predict
|
|
464
|
+
next action. `False` if the message's intent was used.
|
|
465
|
+
|
|
466
|
+
"""
|
|
467
|
+
self.text = text
|
|
468
|
+
self.intent = intent if intent else {}
|
|
469
|
+
self.entities = entities if entities else []
|
|
470
|
+
self.input_channel = input_channel
|
|
471
|
+
self.message_id = message_id
|
|
472
|
+
|
|
473
|
+
super().__init__(timestamp, metadata)
|
|
474
|
+
|
|
475
|
+
# The featurization is set by the policies during prediction time using a
|
|
476
|
+
# `DefinePrevUserUtteredFeaturization` event.
|
|
477
|
+
self.use_text_for_featurization = use_text_for_featurization
|
|
478
|
+
# define how this user utterance should be featurized
|
|
479
|
+
if self.text and not self.intent_name:
|
|
480
|
+
# happens during training
|
|
481
|
+
self.use_text_for_featurization = True
|
|
482
|
+
elif self.intent_name and not self.text:
|
|
483
|
+
# happens during training
|
|
484
|
+
self.use_text_for_featurization = False
|
|
485
|
+
|
|
486
|
+
self.parse_data: "NLUPredictionData" = {
|
|
487
|
+
INTENT: self.intent, # type: ignore[misc]
|
|
488
|
+
# Copy entities so that changes to `self.entities` don't affect
|
|
489
|
+
# `self.parse_data` and hence don't get persisted
|
|
490
|
+
ENTITIES: self.entities.copy(),
|
|
491
|
+
TEXT: self.text,
|
|
492
|
+
"message_id": self.message_id,
|
|
493
|
+
"metadata": self.metadata,
|
|
494
|
+
}
|
|
495
|
+
if parse_data:
|
|
496
|
+
self.parse_data.update(**parse_data)
|
|
497
|
+
|
|
498
|
+
@staticmethod
|
|
499
|
+
def _from_parse_data(
|
|
500
|
+
text: Text,
|
|
501
|
+
parse_data: "NLUPredictionData",
|
|
502
|
+
timestamp: Optional[float] = None,
|
|
503
|
+
input_channel: Optional[Text] = None,
|
|
504
|
+
message_id: Optional[Text] = None,
|
|
505
|
+
metadata: Optional[Dict] = None,
|
|
506
|
+
) -> "UserUttered":
|
|
507
|
+
return UserUttered(
|
|
508
|
+
text,
|
|
509
|
+
parse_data.get(INTENT),
|
|
510
|
+
parse_data.get(ENTITIES, []),
|
|
511
|
+
parse_data,
|
|
512
|
+
timestamp,
|
|
513
|
+
input_channel,
|
|
514
|
+
message_id,
|
|
515
|
+
metadata,
|
|
516
|
+
)
|
|
517
|
+
|
|
518
|
+
def __hash__(self) -> int:
|
|
519
|
+
"""Returns unique hash of object."""
|
|
520
|
+
return hash(json.dumps(self.as_sub_state()))
|
|
521
|
+
|
|
522
|
+
@property
|
|
523
|
+
def has_triggered_error(self) -> bool:
|
|
524
|
+
return len(self.error_commands) > 0
|
|
525
|
+
|
|
526
|
+
@property
|
|
527
|
+
def error_commands(self) -> List[Dict[Text, Any]]:
|
|
528
|
+
from rasa.dialogue_understanding.commands import ErrorCommand
|
|
529
|
+
|
|
530
|
+
return [c for c in self.commands if c["command"] == ErrorCommand.command()]
|
|
531
|
+
|
|
532
|
+
@property
|
|
533
|
+
def commands(self) -> List[Dict[str, Any]]:
|
|
534
|
+
"""Returns commands included in the message."""
|
|
535
|
+
if COMMANDS in self.parse_data and isinstance(
|
|
536
|
+
self.parse_data[COMMANDS], # type: ignore[literal-required]
|
|
537
|
+
list,
|
|
538
|
+
):
|
|
539
|
+
return self.parse_data[COMMANDS] # type: ignore[literal-required]
|
|
540
|
+
return []
|
|
541
|
+
|
|
542
|
+
@property
|
|
543
|
+
def intent_name(self) -> Optional[Text]:
|
|
544
|
+
"""Returns intent name or `None` if no intent."""
|
|
545
|
+
return self.intent.get(INTENT_NAME_KEY)
|
|
546
|
+
|
|
547
|
+
@property
|
|
548
|
+
def full_retrieval_intent_name(self) -> Optional[Text]:
|
|
549
|
+
"""Returns full retrieval intent name or `None` if no retrieval intent."""
|
|
550
|
+
return self.intent.get(FULL_RETRIEVAL_INTENT_NAME_KEY)
|
|
551
|
+
|
|
552
|
+
# Note that this means two UserUttered events with the same text, intent
|
|
553
|
+
# and entities but _different_ timestamps will be considered equal.
|
|
554
|
+
def __eq__(self, other: Any) -> bool:
|
|
555
|
+
"""Compares object with other object."""
|
|
556
|
+
if not isinstance(other, UserUttered):
|
|
557
|
+
return NotImplemented
|
|
558
|
+
|
|
559
|
+
return (
|
|
560
|
+
self.text,
|
|
561
|
+
self.intent_name,
|
|
562
|
+
[
|
|
563
|
+
jsonpickle.encode(sorted(ent)) for ent in self.entities
|
|
564
|
+
], # TODO: test? Or fix in regex_message_handler?
|
|
565
|
+
) == (
|
|
566
|
+
other.text,
|
|
567
|
+
other.intent_name,
|
|
568
|
+
[jsonpickle.encode(sorted(ent)) for ent in other.entities],
|
|
569
|
+
)
|
|
570
|
+
|
|
571
|
+
def __str__(self) -> Text:
|
|
572
|
+
"""Returns text representation of event."""
|
|
573
|
+
entities = ""
|
|
574
|
+
if self.entities:
|
|
575
|
+
entities_list = [
|
|
576
|
+
f"{entity[ENTITY_ATTRIBUTE_VALUE]} "
|
|
577
|
+
f"(Type: {entity[ENTITY_ATTRIBUTE_TYPE]}, "
|
|
578
|
+
f"Role: {entity.get(ENTITY_ATTRIBUTE_ROLE)}, "
|
|
579
|
+
f"Group: {entity.get(ENTITY_ATTRIBUTE_GROUP)})"
|
|
580
|
+
for entity in self.entities
|
|
581
|
+
]
|
|
582
|
+
entities = f", entities: {', '.join(entities_list)}"
|
|
583
|
+
|
|
584
|
+
return (
|
|
585
|
+
f"UserUttered(text: {self.text}, intent: {self.intent_name}"
|
|
586
|
+
f"{entities}"
|
|
587
|
+
f", use_text_for_featurization: {self.use_text_for_featurization})"
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
def __repr__(self) -> Text:
|
|
591
|
+
"""Returns text representation of event for debugging."""
|
|
592
|
+
return (
|
|
593
|
+
f"UserUttered('{self.text}', "
|
|
594
|
+
f"'{self.intent_name}', "
|
|
595
|
+
f"{json.dumps(self.entities)})"
|
|
596
|
+
)
|
|
597
|
+
|
|
598
|
+
@staticmethod
|
|
599
|
+
def empty() -> "UserUttered":
|
|
600
|
+
return UserUttered(None)
|
|
601
|
+
|
|
602
|
+
def is_empty(self) -> bool:
|
|
603
|
+
return not self.text and not self.intent_name and not self.entities
|
|
604
|
+
|
|
605
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
606
|
+
_dict = super().as_dict()
|
|
607
|
+
_dict.update(
|
|
608
|
+
{
|
|
609
|
+
"text": self.text,
|
|
610
|
+
"parse_data": self.parse_data,
|
|
611
|
+
"input_channel": getattr(self, "input_channel", None),
|
|
612
|
+
"message_id": getattr(self, "message_id", None),
|
|
613
|
+
"metadata": self.metadata,
|
|
614
|
+
}
|
|
615
|
+
)
|
|
616
|
+
return _dict
|
|
617
|
+
|
|
618
|
+
def as_sub_state(self) -> Dict[Text, Union[None, Text, List[Optional[Text]]]]:
|
|
619
|
+
"""Turns a UserUttered event into features.
|
|
620
|
+
|
|
621
|
+
The substate contains information about entities, intent and text of the
|
|
622
|
+
`UserUttered` event.
|
|
623
|
+
|
|
624
|
+
Returns:
|
|
625
|
+
a dictionary with intent name, text and entities
|
|
626
|
+
"""
|
|
627
|
+
entities = [entity.get(ENTITY_ATTRIBUTE_TYPE) for entity in self.entities]
|
|
628
|
+
entities.extend(
|
|
629
|
+
(
|
|
630
|
+
f"{entity.get(ENTITY_ATTRIBUTE_TYPE)}{ENTITY_LABEL_SEPARATOR}"
|
|
631
|
+
f"{entity.get(ENTITY_ATTRIBUTE_ROLE)}"
|
|
632
|
+
)
|
|
633
|
+
for entity in self.entities
|
|
634
|
+
if ENTITY_ATTRIBUTE_ROLE in entity
|
|
635
|
+
)
|
|
636
|
+
entities.extend(
|
|
637
|
+
(
|
|
638
|
+
f"{entity.get(ENTITY_ATTRIBUTE_TYPE)}{ENTITY_LABEL_SEPARATOR}"
|
|
639
|
+
f"{entity.get(ENTITY_ATTRIBUTE_GROUP)}"
|
|
640
|
+
)
|
|
641
|
+
for entity in self.entities
|
|
642
|
+
if ENTITY_ATTRIBUTE_GROUP in entity
|
|
643
|
+
)
|
|
644
|
+
|
|
645
|
+
out: Dict[Text, Union[None, Text, List[Optional[Text]]]] = {}
|
|
646
|
+
# During training we expect either intent_name or text to be set.
|
|
647
|
+
# During prediction both will be set.
|
|
648
|
+
if self.text and (
|
|
649
|
+
self.use_text_for_featurization or self.use_text_for_featurization is None
|
|
650
|
+
):
|
|
651
|
+
out[TEXT] = self.text
|
|
652
|
+
if self.intent_name and not self.use_text_for_featurization:
|
|
653
|
+
out[INTENT] = self.intent_name
|
|
654
|
+
# don't add entities for e2e utterances
|
|
655
|
+
if entities and not self.use_text_for_featurization:
|
|
656
|
+
out[ENTITIES] = entities
|
|
657
|
+
|
|
658
|
+
return out
|
|
659
|
+
|
|
660
|
+
@classmethod
|
|
661
|
+
def _from_story_string(
|
|
662
|
+
cls, parameters: Dict[Text, Any]
|
|
663
|
+
) -> Optional[List["UserUttered"]]:
|
|
664
|
+
try:
|
|
665
|
+
return [
|
|
666
|
+
cls._from_parse_data(
|
|
667
|
+
parameters.get("text"),
|
|
668
|
+
parameters.get("parse_data"),
|
|
669
|
+
parameters.get("timestamp"),
|
|
670
|
+
parameters.get("input_channel"),
|
|
671
|
+
parameters.get("message_id"),
|
|
672
|
+
parameters.get("metadata"),
|
|
673
|
+
)
|
|
674
|
+
]
|
|
675
|
+
except KeyError as e:
|
|
676
|
+
raise ValueError(f"Failed to parse bot uttered event. {e}")
|
|
677
|
+
|
|
678
|
+
def _entity_string(self) -> Text:
|
|
679
|
+
if self.entities:
|
|
680
|
+
return json.dumps(
|
|
681
|
+
{
|
|
682
|
+
entity[ENTITY_ATTRIBUTE_TYPE]: entity[ENTITY_ATTRIBUTE_VALUE]
|
|
683
|
+
for entity in self.entities
|
|
684
|
+
},
|
|
685
|
+
ensure_ascii=False,
|
|
686
|
+
)
|
|
687
|
+
return ""
|
|
688
|
+
|
|
689
|
+
def as_story_string(self, e2e: bool = False) -> Text:
|
|
690
|
+
"""Return event as string for Markdown training format.
|
|
691
|
+
|
|
692
|
+
Args:
|
|
693
|
+
e2e: `True` if the the event should be printed in the format for
|
|
694
|
+
end-to-end conversation tests.
|
|
695
|
+
|
|
696
|
+
Returns:
|
|
697
|
+
Event as string.
|
|
698
|
+
"""
|
|
699
|
+
if self.use_text_for_featurization and not e2e:
|
|
700
|
+
raise UnsupportedFeatureException(
|
|
701
|
+
f"Printing end-to-end user utterances is not supported in the "
|
|
702
|
+
f"Markdown training format. Please use the YAML training data format "
|
|
703
|
+
f"instead. Please see {DOCS_URL_TRAINING_DATA} for more information."
|
|
704
|
+
)
|
|
705
|
+
|
|
706
|
+
if e2e:
|
|
707
|
+
text_with_entities = format_message(
|
|
708
|
+
self.text or "", self.intent_name, self.entities
|
|
709
|
+
)
|
|
710
|
+
|
|
711
|
+
intent_prefix = f"{self.intent_name}: " if self.intent_name else ""
|
|
712
|
+
return f"{intent_prefix}{text_with_entities}"
|
|
713
|
+
|
|
714
|
+
return f"{self.intent_name or ''}{self._entity_string()}"
|
|
715
|
+
|
|
716
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
717
|
+
"""Applies event to tracker. See docstring of `Event`."""
|
|
718
|
+
tracker.latest_message = self
|
|
719
|
+
tracker.clear_followup_action()
|
|
720
|
+
|
|
721
|
+
@staticmethod
|
|
722
|
+
def create_external(
|
|
723
|
+
intent_name: Text,
|
|
724
|
+
entity_list: Optional[List[Dict[Text, Any]]] = None,
|
|
725
|
+
input_channel: Optional[Text] = None,
|
|
726
|
+
) -> "UserUttered":
|
|
727
|
+
return UserUttered(
|
|
728
|
+
text=f"{EXTERNAL_MESSAGE_PREFIX}{intent_name}",
|
|
729
|
+
intent={INTENT_NAME_KEY: intent_name},
|
|
730
|
+
metadata={IS_EXTERNAL: True},
|
|
731
|
+
entities=entity_list or [],
|
|
732
|
+
input_channel=input_channel,
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
class DefinePrevUserUtteredFeaturization(SkipEventInMDStoryMixin):
|
|
737
|
+
"""Stores information whether action was predicted based on text or intent."""
|
|
738
|
+
|
|
739
|
+
type_name = "user_featurization"
|
|
740
|
+
|
|
741
|
+
def __init__(
|
|
742
|
+
self,
|
|
743
|
+
use_text_for_featurization: bool,
|
|
744
|
+
timestamp: Optional[float] = None,
|
|
745
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
746
|
+
) -> None:
|
|
747
|
+
"""Creates event.
|
|
748
|
+
|
|
749
|
+
Args:
|
|
750
|
+
use_text_for_featurization: `True` if message text was used to predict
|
|
751
|
+
action. `False` if intent was used.
|
|
752
|
+
timestamp: When the event was created.
|
|
753
|
+
metadata: Additional event metadata.
|
|
754
|
+
"""
|
|
755
|
+
super().__init__(timestamp, metadata)
|
|
756
|
+
self.use_text_for_featurization = use_text_for_featurization
|
|
757
|
+
|
|
758
|
+
def __str__(self) -> Text:
|
|
759
|
+
"""Returns text representation of event."""
|
|
760
|
+
return f"DefinePrevUserUtteredFeaturization({self.use_text_for_featurization})"
|
|
761
|
+
|
|
762
|
+
def __hash__(self) -> int:
|
|
763
|
+
"""Returns unique hash for event."""
|
|
764
|
+
return hash(self.use_text_for_featurization)
|
|
765
|
+
|
|
766
|
+
@classmethod
|
|
767
|
+
def _from_parameters(
|
|
768
|
+
cls, parameters: Dict[Text, Any]
|
|
769
|
+
) -> "DefinePrevUserUtteredFeaturization":
|
|
770
|
+
return DefinePrevUserUtteredFeaturization(
|
|
771
|
+
parameters.get(USE_TEXT_FOR_FEATURIZATION),
|
|
772
|
+
parameters.get("timestamp"),
|
|
773
|
+
parameters.get("metadata"),
|
|
774
|
+
)
|
|
775
|
+
|
|
776
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
777
|
+
"""Returns serialized event."""
|
|
778
|
+
d = super().as_dict()
|
|
779
|
+
d.update({USE_TEXT_FOR_FEATURIZATION: self.use_text_for_featurization})
|
|
780
|
+
return d
|
|
781
|
+
|
|
782
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
783
|
+
"""Applies event to current conversation state.
|
|
784
|
+
|
|
785
|
+
Args:
|
|
786
|
+
tracker: The current conversation state.
|
|
787
|
+
"""
|
|
788
|
+
if tracker.latest_action_name != ACTION_LISTEN_NAME:
|
|
789
|
+
# featurization belong only to the last user message
|
|
790
|
+
# a user message is always followed by action listen
|
|
791
|
+
return
|
|
792
|
+
|
|
793
|
+
if not tracker.latest_message:
|
|
794
|
+
return
|
|
795
|
+
|
|
796
|
+
# update previous user message's featurization based on this event
|
|
797
|
+
tracker.latest_message.use_text_for_featurization = (
|
|
798
|
+
self.use_text_for_featurization
|
|
799
|
+
)
|
|
800
|
+
|
|
801
|
+
def __eq__(self, other: Any) -> bool:
|
|
802
|
+
"""Compares object with other object."""
|
|
803
|
+
if not isinstance(other, DefinePrevUserUtteredFeaturization):
|
|
804
|
+
return NotImplemented
|
|
805
|
+
|
|
806
|
+
return self.use_text_for_featurization == other.use_text_for_featurization
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
class EntitiesAdded(SkipEventInMDStoryMixin):
|
|
810
|
+
"""Event that is used to add extracted entities to the tracker state."""
|
|
811
|
+
|
|
812
|
+
type_name = "entities"
|
|
813
|
+
|
|
814
|
+
def __init__(
|
|
815
|
+
self,
|
|
816
|
+
entities: List[Dict[Text, Any]],
|
|
817
|
+
timestamp: Optional[float] = None,
|
|
818
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
819
|
+
) -> None:
|
|
820
|
+
"""Initializes event.
|
|
821
|
+
|
|
822
|
+
Args:
|
|
823
|
+
entities: Entities extracted from previous user message. This can either
|
|
824
|
+
be done by NLU components or end-to-end policy predictions.
|
|
825
|
+
timestamp: the timestamp
|
|
826
|
+
metadata: some optional metadata
|
|
827
|
+
"""
|
|
828
|
+
super().__init__(timestamp, metadata)
|
|
829
|
+
self.entities = entities
|
|
830
|
+
|
|
831
|
+
def __str__(self) -> Text:
|
|
832
|
+
"""Returns the string representation of the event."""
|
|
833
|
+
entity_str = [e[ENTITY_ATTRIBUTE_TYPE] for e in self.entities]
|
|
834
|
+
return f"{self.__class__.__name__}({entity_str})"
|
|
835
|
+
|
|
836
|
+
def __hash__(self) -> int:
|
|
837
|
+
"""Returns the hash value of the event."""
|
|
838
|
+
return hash(json.dumps(self.entities))
|
|
839
|
+
|
|
840
|
+
def __eq__(self, other: Any) -> bool:
|
|
841
|
+
"""Compares this event with another event."""
|
|
842
|
+
if not isinstance(other, EntitiesAdded):
|
|
843
|
+
return NotImplemented
|
|
844
|
+
|
|
845
|
+
return self.entities == other.entities
|
|
846
|
+
|
|
847
|
+
@classmethod
|
|
848
|
+
def _from_parameters(cls, parameters: Dict[Text, Any]) -> "EntitiesAdded":
|
|
849
|
+
return EntitiesAdded(
|
|
850
|
+
parameters.get(ENTITIES),
|
|
851
|
+
parameters.get("timestamp"),
|
|
852
|
+
parameters.get("metadata"),
|
|
853
|
+
)
|
|
854
|
+
|
|
855
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
856
|
+
"""Converts the event into a dict.
|
|
857
|
+
|
|
858
|
+
Returns:
|
|
859
|
+
A dict that represents this event.
|
|
860
|
+
"""
|
|
861
|
+
d = super().as_dict()
|
|
862
|
+
d.update({ENTITIES: self.entities})
|
|
863
|
+
return d
|
|
864
|
+
|
|
865
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
866
|
+
"""Applies event to current conversation state.
|
|
867
|
+
|
|
868
|
+
Args:
|
|
869
|
+
tracker: The current conversation state.
|
|
870
|
+
"""
|
|
871
|
+
if tracker.latest_action_name != ACTION_LISTEN_NAME:
|
|
872
|
+
# entities belong only to the last user message
|
|
873
|
+
# a user message always comes after action listen
|
|
874
|
+
return
|
|
875
|
+
|
|
876
|
+
if not tracker.latest_message:
|
|
877
|
+
return
|
|
878
|
+
|
|
879
|
+
for entity in self.entities:
|
|
880
|
+
if entity not in tracker.latest_message.entities:
|
|
881
|
+
tracker.latest_message.entities.append(entity)
|
|
882
|
+
|
|
883
|
+
|
|
884
|
+
class BotUttered(SkipEventInMDStoryMixin):
|
|
885
|
+
"""The bot has said something to the user.
|
|
886
|
+
|
|
887
|
+
This class is not used in the story training as it is contained in the
|
|
888
|
+
|
|
889
|
+
``ActionExecuted`` class. An entry is made in the ``Tracker``.
|
|
890
|
+
"""
|
|
891
|
+
|
|
892
|
+
type_name = "bot"
|
|
893
|
+
|
|
894
|
+
def __init__(
|
|
895
|
+
self,
|
|
896
|
+
text: Optional[Text] = None,
|
|
897
|
+
data: Optional[Dict] = None,
|
|
898
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
899
|
+
timestamp: Optional[float] = None,
|
|
900
|
+
) -> None:
|
|
901
|
+
"""Creates event for a bot response.
|
|
902
|
+
|
|
903
|
+
Args:
|
|
904
|
+
text: Plain text which bot responded with.
|
|
905
|
+
data: Additional data for more complex utterances (e.g. buttons).
|
|
906
|
+
timestamp: When the event was created.
|
|
907
|
+
metadata: Additional event metadata.
|
|
908
|
+
"""
|
|
909
|
+
self.text = text
|
|
910
|
+
self.data = data or {}
|
|
911
|
+
super().__init__(timestamp, metadata)
|
|
912
|
+
|
|
913
|
+
def __members(self) -> Tuple[Optional[Text], Text, Text]:
|
|
914
|
+
data_no_nones = {k: v for k, v in self.data.items() if v is not None}
|
|
915
|
+
meta_no_nones = {k: v for k, v in self.metadata.items() if v is not None}
|
|
916
|
+
return (
|
|
917
|
+
self.text,
|
|
918
|
+
jsonpickle.encode(data_no_nones),
|
|
919
|
+
jsonpickle.encode(meta_no_nones),
|
|
920
|
+
)
|
|
921
|
+
|
|
922
|
+
def __hash__(self) -> int:
|
|
923
|
+
"""Returns unique hash for event."""
|
|
924
|
+
return hash(self.__members())
|
|
925
|
+
|
|
926
|
+
def __eq__(self, other: Any) -> bool:
|
|
927
|
+
"""Compares object with other object."""
|
|
928
|
+
if not isinstance(other, BotUttered):
|
|
929
|
+
return NotImplemented
|
|
930
|
+
|
|
931
|
+
return self.__members() == other.__members()
|
|
932
|
+
|
|
933
|
+
def _clean_up_metadata(self) -> Dict[str, Any]:
|
|
934
|
+
"""Removes search_results metadata key from the metadata.
|
|
935
|
+
|
|
936
|
+
This is intended to prevent increasing the string representation
|
|
937
|
+
character length of the bot event.
|
|
938
|
+
"""
|
|
939
|
+
from rasa.core.policies.enterprise_search_policy import (
|
|
940
|
+
SEARCH_RESULTS_METADATA_KEY,
|
|
941
|
+
)
|
|
942
|
+
|
|
943
|
+
metadata = copy.deepcopy(self.metadata)
|
|
944
|
+
|
|
945
|
+
if SEARCH_RESULTS_METADATA_KEY in self.metadata:
|
|
946
|
+
metadata.pop(SEARCH_RESULTS_METADATA_KEY)
|
|
947
|
+
structlogger.debug(
|
|
948
|
+
"search_results.metadata.removed",
|
|
949
|
+
event_info="Removed search_results metadata key only "
|
|
950
|
+
"from the string representation of the bot event.",
|
|
951
|
+
)
|
|
952
|
+
|
|
953
|
+
return metadata
|
|
954
|
+
|
|
955
|
+
def __str__(self) -> Text:
|
|
956
|
+
"""Returns text representation of event."""
|
|
957
|
+
metadata = self._clean_up_metadata()
|
|
958
|
+
|
|
959
|
+
return "BotUttered(text: {}, data: {}, metadata: {})".format(
|
|
960
|
+
self.text, json.dumps(self.data), json.dumps(metadata)
|
|
961
|
+
)
|
|
962
|
+
|
|
963
|
+
def __repr__(self) -> Text:
|
|
964
|
+
"""Returns text representation of event for debugging."""
|
|
965
|
+
metadata = self._clean_up_metadata()
|
|
966
|
+
|
|
967
|
+
return "BotUttered('{}', {}, {}, {})".format(
|
|
968
|
+
self.text, json.dumps(self.data), json.dumps(metadata), self.timestamp
|
|
969
|
+
)
|
|
970
|
+
|
|
971
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
972
|
+
"""Applies event to current conversation state."""
|
|
973
|
+
tracker.latest_bot_utterance = self
|
|
974
|
+
|
|
975
|
+
def message(self) -> Dict[Text, Any]:
|
|
976
|
+
"""Return the complete message as a dictionary."""
|
|
977
|
+
m = self.data.copy()
|
|
978
|
+
m["text"] = self.text
|
|
979
|
+
m["timestamp"] = self.timestamp
|
|
980
|
+
m.update(self.metadata)
|
|
981
|
+
|
|
982
|
+
if m.get("image") == m.get("attachment"):
|
|
983
|
+
# we need this as there is an oddity we introduced a while ago where
|
|
984
|
+
# we automatically set the attachment to the image. to not break
|
|
985
|
+
# any persisted events we kept that, but we need to make sure that
|
|
986
|
+
# the message contains the image only once
|
|
987
|
+
m["attachment"] = None
|
|
988
|
+
|
|
989
|
+
return m
|
|
990
|
+
|
|
991
|
+
@staticmethod
|
|
992
|
+
def empty() -> "BotUttered":
|
|
993
|
+
"""Creates an empty bot utterance."""
|
|
994
|
+
return BotUttered()
|
|
995
|
+
|
|
996
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
997
|
+
"""Returns serialized event."""
|
|
998
|
+
d = super().as_dict()
|
|
999
|
+
d.update({"text": self.text, "data": self.data, "metadata": self.metadata})
|
|
1000
|
+
return d
|
|
1001
|
+
|
|
1002
|
+
@classmethod
|
|
1003
|
+
def _from_parameters(cls, parameters: Dict[Text, Any]) -> "BotUttered":
|
|
1004
|
+
try:
|
|
1005
|
+
return BotUttered(
|
|
1006
|
+
parameters.get("text"),
|
|
1007
|
+
parameters.get("data"),
|
|
1008
|
+
parameters.get("metadata"),
|
|
1009
|
+
parameters.get("timestamp"),
|
|
1010
|
+
)
|
|
1011
|
+
except KeyError as e:
|
|
1012
|
+
raise ValueError(f"Failed to parse bot uttered event. {e}")
|
|
1013
|
+
|
|
1014
|
+
|
|
1015
|
+
class SlotSet(Event):
|
|
1016
|
+
"""The user has specified their preference for the value of a `slot`.
|
|
1017
|
+
|
|
1018
|
+
Every slot has a name and a value. This event can be used to set a
|
|
1019
|
+
value for a slot on a conversation.
|
|
1020
|
+
|
|
1021
|
+
As a side effect the `Tracker`'s slots will be updated so
|
|
1022
|
+
that `tracker.slots[key]=value`.
|
|
1023
|
+
"""
|
|
1024
|
+
|
|
1025
|
+
type_name = "slot"
|
|
1026
|
+
|
|
1027
|
+
def __init__(
|
|
1028
|
+
self,
|
|
1029
|
+
key: Text,
|
|
1030
|
+
value: Optional[Any] = None,
|
|
1031
|
+
timestamp: Optional[float] = None,
|
|
1032
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
1033
|
+
) -> None:
|
|
1034
|
+
"""Creates event to set slot.
|
|
1035
|
+
|
|
1036
|
+
Args:
|
|
1037
|
+
key: Name of the slot which is set.
|
|
1038
|
+
value: Value to which slot is set.
|
|
1039
|
+
timestamp: When the event was created.
|
|
1040
|
+
metadata: Additional event metadata.
|
|
1041
|
+
"""
|
|
1042
|
+
self.key = key
|
|
1043
|
+
self.value = value
|
|
1044
|
+
super().__init__(timestamp, metadata)
|
|
1045
|
+
|
|
1046
|
+
def __repr__(self) -> Text:
|
|
1047
|
+
"""Returns text representation of event."""
|
|
1048
|
+
return f"SlotSet(key: {self.key}, value: {self.value})"
|
|
1049
|
+
|
|
1050
|
+
def __hash__(self) -> int:
|
|
1051
|
+
"""Returns unique hash for event."""
|
|
1052
|
+
return hash((self.key, jsonpickle.encode(self.value)))
|
|
1053
|
+
|
|
1054
|
+
def __eq__(self, other: Any) -> bool:
|
|
1055
|
+
"""Compares object with other object."""
|
|
1056
|
+
if not isinstance(other, SlotSet):
|
|
1057
|
+
return NotImplemented
|
|
1058
|
+
|
|
1059
|
+
return (self.key, self.value) == (other.key, other.value)
|
|
1060
|
+
|
|
1061
|
+
def as_story_string(self) -> Text:
|
|
1062
|
+
"""Returns text representation of event."""
|
|
1063
|
+
props = json.dumps({self.key: self.value}, ensure_ascii=False)
|
|
1064
|
+
return f"{self.type_name}{props}"
|
|
1065
|
+
|
|
1066
|
+
@classmethod
|
|
1067
|
+
def _from_story_string(
|
|
1068
|
+
cls, parameters: Dict[Text, Any]
|
|
1069
|
+
) -> Optional[List["SlotSet"]]:
|
|
1070
|
+
slots = []
|
|
1071
|
+
for slot_key, slot_val in parameters.items():
|
|
1072
|
+
slots.append(SlotSet(slot_key, slot_val))
|
|
1073
|
+
|
|
1074
|
+
if slots:
|
|
1075
|
+
return slots
|
|
1076
|
+
else:
|
|
1077
|
+
return None
|
|
1078
|
+
|
|
1079
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
1080
|
+
"""Returns serialized event."""
|
|
1081
|
+
d = super().as_dict()
|
|
1082
|
+
d.update({"name": self.key, "value": self.value})
|
|
1083
|
+
return d
|
|
1084
|
+
|
|
1085
|
+
@classmethod
|
|
1086
|
+
def _from_parameters(cls, parameters: Dict[Text, Any]) -> "SlotSet":
|
|
1087
|
+
try:
|
|
1088
|
+
return SlotSet(
|
|
1089
|
+
parameters.get("name"),
|
|
1090
|
+
parameters.get("value"),
|
|
1091
|
+
parameters.get("timestamp"),
|
|
1092
|
+
parameters.get("metadata"),
|
|
1093
|
+
)
|
|
1094
|
+
except KeyError as e:
|
|
1095
|
+
raise ValueError(f"Failed to parse set slot event. {e}")
|
|
1096
|
+
|
|
1097
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
1098
|
+
"""Applies event to current conversation state."""
|
|
1099
|
+
tracker._set_slot(self.key, self.value)
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
class Restarted(AlwaysEqualEventMixin):
|
|
1103
|
+
"""Conversation should start over & history wiped.
|
|
1104
|
+
|
|
1105
|
+
Instead of deleting all events, this event can be used to reset the
|
|
1106
|
+
trackers state (e.g. ignoring any past user messages & resetting all
|
|
1107
|
+
the slots).
|
|
1108
|
+
"""
|
|
1109
|
+
|
|
1110
|
+
type_name = "restart"
|
|
1111
|
+
|
|
1112
|
+
def __hash__(self) -> int:
|
|
1113
|
+
"""Returns unique hash for event."""
|
|
1114
|
+
return hash(32143124312)
|
|
1115
|
+
|
|
1116
|
+
def as_story_string(self) -> Text:
|
|
1117
|
+
"""Returns text representation of event."""
|
|
1118
|
+
return self.type_name
|
|
1119
|
+
|
|
1120
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
1121
|
+
"""Resets the tracker and triggers a followup `ActionSessionStart`."""
|
|
1122
|
+
tracker._reset()
|
|
1123
|
+
tracker.trigger_followup_action(ACTION_SESSION_START_NAME)
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
class UserUtteranceReverted(AlwaysEqualEventMixin):
|
|
1127
|
+
"""Bot reverts everything until before the most recent user message.
|
|
1128
|
+
|
|
1129
|
+
The bot will revert all events after the latest `UserUttered`, this
|
|
1130
|
+
also means that the last event on the tracker is usually `action_listen`
|
|
1131
|
+
and the bot is waiting for a new user message.
|
|
1132
|
+
"""
|
|
1133
|
+
|
|
1134
|
+
type_name = "rewind"
|
|
1135
|
+
|
|
1136
|
+
def __hash__(self) -> int:
|
|
1137
|
+
"""Returns unique hash for event."""
|
|
1138
|
+
return hash(32143124315)
|
|
1139
|
+
|
|
1140
|
+
def as_story_string(self) -> Text:
|
|
1141
|
+
"""Returns text representation of event."""
|
|
1142
|
+
return self.type_name
|
|
1143
|
+
|
|
1144
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
1145
|
+
"""Applies event to current conversation state."""
|
|
1146
|
+
tracker._reset()
|
|
1147
|
+
tracker.replay_events()
|
|
1148
|
+
|
|
1149
|
+
|
|
1150
|
+
class AllSlotsReset(AlwaysEqualEventMixin):
|
|
1151
|
+
"""All Slots are reset to their initial values.
|
|
1152
|
+
|
|
1153
|
+
If you want to keep the dialogue history and only want to reset the
|
|
1154
|
+
slots, you can use this event to set all the slots to their initial
|
|
1155
|
+
values.
|
|
1156
|
+
"""
|
|
1157
|
+
|
|
1158
|
+
type_name = "reset_slots"
|
|
1159
|
+
|
|
1160
|
+
def __hash__(self) -> int:
|
|
1161
|
+
"""Returns unique hash for event."""
|
|
1162
|
+
return hash(32143124316)
|
|
1163
|
+
|
|
1164
|
+
def as_story_string(self) -> Text:
|
|
1165
|
+
"""Returns text representation of event."""
|
|
1166
|
+
return self.type_name
|
|
1167
|
+
|
|
1168
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
1169
|
+
"""Applies event to current conversation state."""
|
|
1170
|
+
tracker._reset_slots()
|
|
1171
|
+
|
|
1172
|
+
|
|
1173
|
+
class DialogueStackUpdated(Event):
|
|
1174
|
+
"""Update the stack of a conversation."""
|
|
1175
|
+
|
|
1176
|
+
type_name = "stack"
|
|
1177
|
+
|
|
1178
|
+
def __init__(
|
|
1179
|
+
self,
|
|
1180
|
+
update: str,
|
|
1181
|
+
timestamp: Optional[float] = None,
|
|
1182
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
1183
|
+
) -> None:
|
|
1184
|
+
"""Creates an event which updates the stack on a tracker.
|
|
1185
|
+
|
|
1186
|
+
Args:
|
|
1187
|
+
update: The update to the stack.
|
|
1188
|
+
timestamp: When the event was created.
|
|
1189
|
+
metadata: Additional event metadata.
|
|
1190
|
+
"""
|
|
1191
|
+
self.update = update
|
|
1192
|
+
super().__init__(timestamp, metadata)
|
|
1193
|
+
|
|
1194
|
+
def __hash__(self) -> int:
|
|
1195
|
+
"""Returns unique hash for event."""
|
|
1196
|
+
return hash(self.update)
|
|
1197
|
+
|
|
1198
|
+
def __eq__(self, other: Any) -> bool:
|
|
1199
|
+
"""Compares object with other object."""
|
|
1200
|
+
if not isinstance(other, DialogueStackUpdated):
|
|
1201
|
+
return NotImplemented
|
|
1202
|
+
|
|
1203
|
+
return self.update == other.update
|
|
1204
|
+
|
|
1205
|
+
def __str__(self) -> Text:
|
|
1206
|
+
"""Returns text representation of event."""
|
|
1207
|
+
return f"DialogueStackUpdate(update: {self.update})"
|
|
1208
|
+
|
|
1209
|
+
def __repr__(self) -> Text:
|
|
1210
|
+
"""Returns text representation of event for debugging."""
|
|
1211
|
+
return f'DialogueStackUpdate("""{self.update}""")'
|
|
1212
|
+
|
|
1213
|
+
def as_story_string(self) -> Text:
|
|
1214
|
+
"""Returns text representation of event."""
|
|
1215
|
+
props = json.dumps({"update": self.update})
|
|
1216
|
+
return f"{self.type_name}{props}"
|
|
1217
|
+
|
|
1218
|
+
@classmethod
|
|
1219
|
+
def _from_story_string(
|
|
1220
|
+
cls, parameters: Dict[Text, Any]
|
|
1221
|
+
) -> Optional[List["DialogueStackUpdated"]]:
|
|
1222
|
+
return [
|
|
1223
|
+
DialogueStackUpdated(
|
|
1224
|
+
parameters.get("update"),
|
|
1225
|
+
parameters.get("timestamp"),
|
|
1226
|
+
parameters.get("metadata"),
|
|
1227
|
+
)
|
|
1228
|
+
]
|
|
1229
|
+
|
|
1230
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
1231
|
+
"""Returns serialized event."""
|
|
1232
|
+
d = super().as_dict()
|
|
1233
|
+
d.update({"update": self.update})
|
|
1234
|
+
return d
|
|
1235
|
+
|
|
1236
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
1237
|
+
"""Applies event to current conversation state."""
|
|
1238
|
+
tracker.apply_stack_update(self.update)
|
|
1239
|
+
|
|
1240
|
+
def update_as_json(self) -> List[Dict[Text, Any]]:
|
|
1241
|
+
"""Return the update as a JsonPatch object."""
|
|
1242
|
+
return json.loads(self.update)
|
|
1243
|
+
|
|
1244
|
+
|
|
1245
|
+
class ReminderScheduled(Event):
|
|
1246
|
+
"""Schedules the asynchronous triggering of a user intent at a given time.
|
|
1247
|
+
|
|
1248
|
+
The triggered intent can include entities if needed.
|
|
1249
|
+
"""
|
|
1250
|
+
|
|
1251
|
+
type_name = "reminder"
|
|
1252
|
+
|
|
1253
|
+
def __init__(
|
|
1254
|
+
self,
|
|
1255
|
+
intent: Text,
|
|
1256
|
+
trigger_date_time: datetime,
|
|
1257
|
+
entities: Optional[List[Dict]] = None,
|
|
1258
|
+
name: Optional[Text] = None,
|
|
1259
|
+
kill_on_user_message: bool = True,
|
|
1260
|
+
timestamp: Optional[float] = None,
|
|
1261
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
1262
|
+
) -> None:
|
|
1263
|
+
"""Creates the reminder.
|
|
1264
|
+
|
|
1265
|
+
Args:
|
|
1266
|
+
intent: Name of the intent to be triggered.
|
|
1267
|
+
trigger_date_time: Date at which the execution of the action
|
|
1268
|
+
should be triggered (either utc or with tz).
|
|
1269
|
+
name: ID of the reminder. If there are multiple reminders with
|
|
1270
|
+
the same id only the last will be run.
|
|
1271
|
+
entities: Entities that should be supplied together with the
|
|
1272
|
+
triggered intent.
|
|
1273
|
+
kill_on_user_message: ``True`` means a user message before the
|
|
1274
|
+
trigger date will abort the reminder.
|
|
1275
|
+
timestamp: Creation date of the event.
|
|
1276
|
+
metadata: Optional event metadata.
|
|
1277
|
+
"""
|
|
1278
|
+
self.intent = intent
|
|
1279
|
+
self.entities = entities
|
|
1280
|
+
self.trigger_date_time = trigger_date_time
|
|
1281
|
+
self.kill_on_user_message = kill_on_user_message
|
|
1282
|
+
self.name = name if name is not None else str(uuid.uuid1())
|
|
1283
|
+
super().__init__(timestamp, metadata)
|
|
1284
|
+
|
|
1285
|
+
def __hash__(self) -> int:
|
|
1286
|
+
"""Returns unique hash for event."""
|
|
1287
|
+
return hash(
|
|
1288
|
+
(
|
|
1289
|
+
self.intent,
|
|
1290
|
+
self.entities,
|
|
1291
|
+
self.trigger_date_time.isoformat(),
|
|
1292
|
+
self.kill_on_user_message,
|
|
1293
|
+
self.name,
|
|
1294
|
+
)
|
|
1295
|
+
)
|
|
1296
|
+
|
|
1297
|
+
def __eq__(self, other: Any) -> bool:
|
|
1298
|
+
"""Compares object with other object."""
|
|
1299
|
+
if not isinstance(other, ReminderScheduled):
|
|
1300
|
+
return NotImplemented
|
|
1301
|
+
|
|
1302
|
+
return self.name == other.name
|
|
1303
|
+
|
|
1304
|
+
def __str__(self) -> Text:
|
|
1305
|
+
"""Returns text representation of event."""
|
|
1306
|
+
return (
|
|
1307
|
+
f"ReminderScheduled(intent: {self.intent}, "
|
|
1308
|
+
f"trigger_date: {self.trigger_date_time}, "
|
|
1309
|
+
f"entities: {self.entities}, name: {self.name})"
|
|
1310
|
+
)
|
|
1311
|
+
|
|
1312
|
+
def scheduled_job_name(self, sender_id: Text) -> Text:
|
|
1313
|
+
return (
|
|
1314
|
+
f"[{hash(self.name)},{hash(self.intent)},{hash(str(self.entities))}]"
|
|
1315
|
+
f"{ACTION_NAME_SENDER_ID_CONNECTOR_STR}"
|
|
1316
|
+
f"{sender_id}"
|
|
1317
|
+
)
|
|
1318
|
+
|
|
1319
|
+
def _properties(self) -> Dict[Text, Any]:
|
|
1320
|
+
return {
|
|
1321
|
+
"intent": self.intent,
|
|
1322
|
+
"date_time": self.trigger_date_time.isoformat(),
|
|
1323
|
+
"entities": self.entities,
|
|
1324
|
+
"name": self.name,
|
|
1325
|
+
"kill_on_user_msg": self.kill_on_user_message,
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
def as_story_string(self) -> Text:
|
|
1329
|
+
"""Returns text representation of event."""
|
|
1330
|
+
props = json.dumps(self._properties())
|
|
1331
|
+
return f"{self.type_name}{props}"
|
|
1332
|
+
|
|
1333
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
1334
|
+
"""Returns serialized event."""
|
|
1335
|
+
d = super().as_dict()
|
|
1336
|
+
d.update(self._properties())
|
|
1337
|
+
return d
|
|
1338
|
+
|
|
1339
|
+
@classmethod
|
|
1340
|
+
def _from_story_string(
|
|
1341
|
+
cls, parameters: Dict[Text, Any]
|
|
1342
|
+
) -> Optional[List["ReminderScheduled"]]:
|
|
1343
|
+
trigger_date_time = parser.parse(parameters.get("date_time"))
|
|
1344
|
+
|
|
1345
|
+
return [
|
|
1346
|
+
ReminderScheduled(
|
|
1347
|
+
parameters.get("intent"),
|
|
1348
|
+
trigger_date_time,
|
|
1349
|
+
parameters.get("entities"),
|
|
1350
|
+
name=parameters.get("name"),
|
|
1351
|
+
kill_on_user_message=parameters.get("kill_on_user_msg", True),
|
|
1352
|
+
timestamp=parameters.get("timestamp"),
|
|
1353
|
+
metadata=parameters.get("metadata"),
|
|
1354
|
+
)
|
|
1355
|
+
]
|
|
1356
|
+
|
|
1357
|
+
|
|
1358
|
+
class ReminderCancelled(Event):
|
|
1359
|
+
"""Cancel certain jobs."""
|
|
1360
|
+
|
|
1361
|
+
type_name = "cancel_reminder"
|
|
1362
|
+
|
|
1363
|
+
def __init__(
|
|
1364
|
+
self,
|
|
1365
|
+
name: Optional[Text] = None,
|
|
1366
|
+
intent: Optional[Text] = None,
|
|
1367
|
+
entities: Optional[List[Dict]] = None,
|
|
1368
|
+
timestamp: Optional[float] = None,
|
|
1369
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
1370
|
+
) -> None:
|
|
1371
|
+
"""Creates a ReminderCancelled event.
|
|
1372
|
+
|
|
1373
|
+
If all arguments are `None`, this will cancel all reminders.
|
|
1374
|
+
are to be cancelled. If no arguments are supplied, this will cancel all
|
|
1375
|
+
reminders.
|
|
1376
|
+
|
|
1377
|
+
Args:
|
|
1378
|
+
name: Name of the reminder to be cancelled.
|
|
1379
|
+
intent: Intent name that is to be used to identify the reminders to be
|
|
1380
|
+
cancelled.
|
|
1381
|
+
entities: Entities that are to be used to identify the reminders to be
|
|
1382
|
+
cancelled.
|
|
1383
|
+
timestamp: Optional timestamp.
|
|
1384
|
+
metadata: Optional event metadata.
|
|
1385
|
+
"""
|
|
1386
|
+
self.name = name
|
|
1387
|
+
self.intent = intent
|
|
1388
|
+
self.entities = entities
|
|
1389
|
+
super().__init__(timestamp, metadata)
|
|
1390
|
+
|
|
1391
|
+
def __hash__(self) -> int:
|
|
1392
|
+
"""Returns unique hash for event."""
|
|
1393
|
+
return hash((self.name, self.intent, str(self.entities)))
|
|
1394
|
+
|
|
1395
|
+
def __eq__(self, other: Any) -> bool:
|
|
1396
|
+
"""Compares object with other object."""
|
|
1397
|
+
if not isinstance(other, ReminderCancelled):
|
|
1398
|
+
return NotImplemented
|
|
1399
|
+
|
|
1400
|
+
return hash(self) == hash(other)
|
|
1401
|
+
|
|
1402
|
+
def __str__(self) -> Text:
|
|
1403
|
+
"""Returns text representation of event."""
|
|
1404
|
+
return (
|
|
1405
|
+
f"ReminderCancelled(name: {self.name}, intent: {self.intent}, "
|
|
1406
|
+
f"entities: {self.entities})"
|
|
1407
|
+
)
|
|
1408
|
+
|
|
1409
|
+
def cancels_job_with_name(self, job_name: Text, sender_id: Text) -> bool:
|
|
1410
|
+
"""Determines if this event should cancel the job with the given name.
|
|
1411
|
+
|
|
1412
|
+
Args:
|
|
1413
|
+
job_name: Name of the job to be tested.
|
|
1414
|
+
sender_id: The `sender_id` of the tracker.
|
|
1415
|
+
|
|
1416
|
+
Returns:
|
|
1417
|
+
`True`, if this `ReminderCancelled` event should cancel the job with the
|
|
1418
|
+
given name, and `False` otherwise.
|
|
1419
|
+
"""
|
|
1420
|
+
match = re.match(
|
|
1421
|
+
rf"^\[([\d\-]*),([\d\-]*),([\d\-]*)\]"
|
|
1422
|
+
rf"({re.escape(ACTION_NAME_SENDER_ID_CONNECTOR_STR)}"
|
|
1423
|
+
rf"{re.escape(sender_id)})",
|
|
1424
|
+
job_name,
|
|
1425
|
+
)
|
|
1426
|
+
if not match:
|
|
1427
|
+
return False
|
|
1428
|
+
name_hash, intent_hash, entities_hash = match.group(1, 2, 3)
|
|
1429
|
+
|
|
1430
|
+
# Cancel everything unless names/intents/entities are given to
|
|
1431
|
+
# narrow it down.
|
|
1432
|
+
return (
|
|
1433
|
+
((not self.name) or self._matches_name_hash(name_hash))
|
|
1434
|
+
and ((not self.intent) or self._matches_intent_hash(intent_hash))
|
|
1435
|
+
and ((not self.entities) or self._matches_entities_hash(entities_hash))
|
|
1436
|
+
)
|
|
1437
|
+
|
|
1438
|
+
def _matches_name_hash(self, name_hash: Text) -> bool:
|
|
1439
|
+
return str(hash(self.name)) == name_hash
|
|
1440
|
+
|
|
1441
|
+
def _matches_intent_hash(self, intent_hash: Text) -> bool:
|
|
1442
|
+
return str(hash(self.intent)) == intent_hash
|
|
1443
|
+
|
|
1444
|
+
def _matches_entities_hash(self, entities_hash: Text) -> bool:
|
|
1445
|
+
return str(hash(str(self.entities))) == entities_hash
|
|
1446
|
+
|
|
1447
|
+
def as_story_string(self) -> Text:
|
|
1448
|
+
"""Returns text representation of event."""
|
|
1449
|
+
props = json.dumps(
|
|
1450
|
+
{"name": self.name, "intent": self.intent, "entities": self.entities}
|
|
1451
|
+
)
|
|
1452
|
+
return f"{self.type_name}{props}"
|
|
1453
|
+
|
|
1454
|
+
@classmethod
|
|
1455
|
+
def _from_story_string(
|
|
1456
|
+
cls, parameters: Dict[Text, Any]
|
|
1457
|
+
) -> Optional[List["ReminderCancelled"]]:
|
|
1458
|
+
return [
|
|
1459
|
+
ReminderCancelled(
|
|
1460
|
+
parameters.get("name"),
|
|
1461
|
+
parameters.get("intent"),
|
|
1462
|
+
parameters.get("entities"),
|
|
1463
|
+
timestamp=parameters.get("timestamp"),
|
|
1464
|
+
metadata=parameters.get("metadata"),
|
|
1465
|
+
)
|
|
1466
|
+
]
|
|
1467
|
+
|
|
1468
|
+
|
|
1469
|
+
class ActionReverted(AlwaysEqualEventMixin):
|
|
1470
|
+
"""Bot undoes its last action.
|
|
1471
|
+
|
|
1472
|
+
The bot reverts everything until before the most recent action.
|
|
1473
|
+
This includes the action itself, as well as any events that
|
|
1474
|
+
action created, like set slot events - the bot will now
|
|
1475
|
+
predict a new action using the state before the most recent
|
|
1476
|
+
action.
|
|
1477
|
+
"""
|
|
1478
|
+
|
|
1479
|
+
type_name = "undo"
|
|
1480
|
+
|
|
1481
|
+
def __hash__(self) -> int:
|
|
1482
|
+
"""Returns unique hash for event."""
|
|
1483
|
+
return hash(32143124318)
|
|
1484
|
+
|
|
1485
|
+
def as_story_string(self) -> Text:
|
|
1486
|
+
"""Returns text representation of event."""
|
|
1487
|
+
return self.type_name
|
|
1488
|
+
|
|
1489
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
1490
|
+
"""Applies event to current conversation state."""
|
|
1491
|
+
tracker._reset()
|
|
1492
|
+
tracker.replay_events()
|
|
1493
|
+
|
|
1494
|
+
|
|
1495
|
+
class StoryExported(Event):
|
|
1496
|
+
"""Story should get dumped to a file."""
|
|
1497
|
+
|
|
1498
|
+
type_name = "export"
|
|
1499
|
+
|
|
1500
|
+
def __init__(
|
|
1501
|
+
self,
|
|
1502
|
+
path: Optional[Text] = None,
|
|
1503
|
+
timestamp: Optional[float] = None,
|
|
1504
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
1505
|
+
) -> None:
|
|
1506
|
+
"""Creates event about story exporting.
|
|
1507
|
+
|
|
1508
|
+
Args:
|
|
1509
|
+
path: Path to which story was exported to.
|
|
1510
|
+
timestamp: When the event was created.
|
|
1511
|
+
metadata: Additional event metadata.
|
|
1512
|
+
"""
|
|
1513
|
+
self.path = path
|
|
1514
|
+
super().__init__(timestamp, metadata)
|
|
1515
|
+
|
|
1516
|
+
def __hash__(self) -> int:
|
|
1517
|
+
"""Returns unique hash for event."""
|
|
1518
|
+
return hash(32143124319)
|
|
1519
|
+
|
|
1520
|
+
@classmethod
|
|
1521
|
+
def _from_story_string(
|
|
1522
|
+
cls, parameters: Dict[Text, Any]
|
|
1523
|
+
) -> Optional[List["StoryExported"]]:
|
|
1524
|
+
return [
|
|
1525
|
+
StoryExported(
|
|
1526
|
+
parameters.get("path"),
|
|
1527
|
+
parameters.get("timestamp"),
|
|
1528
|
+
parameters.get("metadata"),
|
|
1529
|
+
)
|
|
1530
|
+
]
|
|
1531
|
+
|
|
1532
|
+
def as_story_string(self) -> Text:
|
|
1533
|
+
"""Returns text representation of event."""
|
|
1534
|
+
return self.type_name
|
|
1535
|
+
|
|
1536
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
1537
|
+
"""Applies event to current conversation state."""
|
|
1538
|
+
if self.path:
|
|
1539
|
+
tracker.export_stories_to_file(self.path)
|
|
1540
|
+
|
|
1541
|
+
def __eq__(self, other: Any) -> bool:
|
|
1542
|
+
"""Compares object with other object."""
|
|
1543
|
+
if not isinstance(other, StoryExported):
|
|
1544
|
+
return NotImplemented
|
|
1545
|
+
|
|
1546
|
+
return self.path == other.path
|
|
1547
|
+
|
|
1548
|
+
|
|
1549
|
+
class FollowupAction(Event):
|
|
1550
|
+
"""Enqueue a followup action."""
|
|
1551
|
+
|
|
1552
|
+
type_name = "followup"
|
|
1553
|
+
|
|
1554
|
+
def __init__(
|
|
1555
|
+
self,
|
|
1556
|
+
name: Text,
|
|
1557
|
+
timestamp: Optional[float] = None,
|
|
1558
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
1559
|
+
) -> None:
|
|
1560
|
+
"""Creates an event which forces the model to run a certain action next.
|
|
1561
|
+
|
|
1562
|
+
Args:
|
|
1563
|
+
name: Name of the action to run.
|
|
1564
|
+
timestamp: When the event was created.
|
|
1565
|
+
metadata: Additional event metadata.
|
|
1566
|
+
"""
|
|
1567
|
+
self.action_name = name
|
|
1568
|
+
super().__init__(timestamp, metadata)
|
|
1569
|
+
|
|
1570
|
+
def __hash__(self) -> int:
|
|
1571
|
+
"""Returns unique hash for event."""
|
|
1572
|
+
return hash(self.action_name)
|
|
1573
|
+
|
|
1574
|
+
def __eq__(self, other: Any) -> bool:
|
|
1575
|
+
"""Compares object with other object."""
|
|
1576
|
+
if not isinstance(other, FollowupAction):
|
|
1577
|
+
return NotImplemented
|
|
1578
|
+
|
|
1579
|
+
return self.action_name == other.action_name
|
|
1580
|
+
|
|
1581
|
+
def __str__(self) -> Text:
|
|
1582
|
+
"""Returns text representation of event."""
|
|
1583
|
+
return f"FollowupAction(action: {self.action_name})"
|
|
1584
|
+
|
|
1585
|
+
def as_story_string(self) -> Text:
|
|
1586
|
+
"""Returns text representation of event."""
|
|
1587
|
+
props = json.dumps({"name": self.action_name})
|
|
1588
|
+
return f"{self.type_name}{props}"
|
|
1589
|
+
|
|
1590
|
+
@classmethod
|
|
1591
|
+
def _from_story_string(
|
|
1592
|
+
cls, parameters: Dict[Text, Any]
|
|
1593
|
+
) -> Optional[List["FollowupAction"]]:
|
|
1594
|
+
return [
|
|
1595
|
+
FollowupAction(
|
|
1596
|
+
parameters.get("name"),
|
|
1597
|
+
parameters.get("timestamp"),
|
|
1598
|
+
parameters.get("metadata"),
|
|
1599
|
+
)
|
|
1600
|
+
]
|
|
1601
|
+
|
|
1602
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
1603
|
+
"""Returns serialized event."""
|
|
1604
|
+
d = super().as_dict()
|
|
1605
|
+
d.update({"name": self.action_name})
|
|
1606
|
+
return d
|
|
1607
|
+
|
|
1608
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
1609
|
+
"""Applies event to current conversation state."""
|
|
1610
|
+
tracker.trigger_followup_action(self.action_name)
|
|
1611
|
+
|
|
1612
|
+
|
|
1613
|
+
class ConversationPaused(AlwaysEqualEventMixin):
|
|
1614
|
+
"""Ignore messages from the user to let a human take over.
|
|
1615
|
+
|
|
1616
|
+
As a side effect the `Tracker`'s `paused` attribute will
|
|
1617
|
+
be set to `True`.
|
|
1618
|
+
"""
|
|
1619
|
+
|
|
1620
|
+
type_name = "pause"
|
|
1621
|
+
|
|
1622
|
+
def __hash__(self) -> int:
|
|
1623
|
+
"""Returns unique hash for event."""
|
|
1624
|
+
return hash(32143124313)
|
|
1625
|
+
|
|
1626
|
+
def as_story_string(self) -> Text:
|
|
1627
|
+
"""Returns text representation of event."""
|
|
1628
|
+
return str(self)
|
|
1629
|
+
|
|
1630
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
1631
|
+
"""Applies event to current conversation state."""
|
|
1632
|
+
tracker._paused = True
|
|
1633
|
+
|
|
1634
|
+
|
|
1635
|
+
class ConversationResumed(AlwaysEqualEventMixin):
|
|
1636
|
+
"""Bot takes over conversation.
|
|
1637
|
+
|
|
1638
|
+
Inverse of `PauseConversation`. As a side effect the `Tracker`'s
|
|
1639
|
+
`paused` attribute will be set to `False`.
|
|
1640
|
+
"""
|
|
1641
|
+
|
|
1642
|
+
type_name = "resume"
|
|
1643
|
+
|
|
1644
|
+
def __hash__(self) -> int:
|
|
1645
|
+
"""Returns unique hash for event."""
|
|
1646
|
+
return hash(32143124314)
|
|
1647
|
+
|
|
1648
|
+
def as_story_string(self) -> Text:
|
|
1649
|
+
"""Returns text representation of event."""
|
|
1650
|
+
return self.type_name
|
|
1651
|
+
|
|
1652
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
1653
|
+
"""Applies event to current conversation state."""
|
|
1654
|
+
tracker._paused = False
|
|
1655
|
+
|
|
1656
|
+
|
|
1657
|
+
class ActionExecuted(Event):
|
|
1658
|
+
"""An operation describes an action taken + its result.
|
|
1659
|
+
|
|
1660
|
+
It comprises an action and a list of events. operations will be appended
|
|
1661
|
+
to the latest `Turn`` in `Tracker.turns`.
|
|
1662
|
+
"""
|
|
1663
|
+
|
|
1664
|
+
type_name = "action"
|
|
1665
|
+
|
|
1666
|
+
def __init__(
|
|
1667
|
+
self,
|
|
1668
|
+
action_name: Optional[Text] = None,
|
|
1669
|
+
policy: Optional[Text] = None,
|
|
1670
|
+
confidence: Optional[float] = None,
|
|
1671
|
+
timestamp: Optional[float] = None,
|
|
1672
|
+
metadata: Optional[Dict] = None,
|
|
1673
|
+
action_text: Optional[Text] = None,
|
|
1674
|
+
hide_rule_turn: bool = False,
|
|
1675
|
+
) -> None:
|
|
1676
|
+
"""Creates event for a successful event execution.
|
|
1677
|
+
|
|
1678
|
+
Args:
|
|
1679
|
+
action_name: Name of the action which was executed. `None` if it was an
|
|
1680
|
+
end-to-end prediction.
|
|
1681
|
+
policy: Policy which predicted action.
|
|
1682
|
+
confidence: Confidence with which policy predicted action.
|
|
1683
|
+
timestamp: When the event was created.
|
|
1684
|
+
metadata: Additional event metadata.
|
|
1685
|
+
action_text: In case it's an end-to-end action prediction, the text which
|
|
1686
|
+
was predicted.
|
|
1687
|
+
hide_rule_turn: If `True`, this action should be hidden in the dialogue
|
|
1688
|
+
history created for ML-based policies.
|
|
1689
|
+
"""
|
|
1690
|
+
self.action_name = action_name
|
|
1691
|
+
self.policy = policy
|
|
1692
|
+
self.confidence = confidence
|
|
1693
|
+
self.unpredictable = False
|
|
1694
|
+
self.action_text = action_text
|
|
1695
|
+
self.hide_rule_turn = hide_rule_turn
|
|
1696
|
+
|
|
1697
|
+
if self.action_name is None and self.action_text is None:
|
|
1698
|
+
raise ValueError(
|
|
1699
|
+
"Both the name of the action and the end-to-end "
|
|
1700
|
+
"predicted text are missing. "
|
|
1701
|
+
"The `ActionExecuted` event cannot be initialised."
|
|
1702
|
+
)
|
|
1703
|
+
|
|
1704
|
+
super().__init__(timestamp, metadata)
|
|
1705
|
+
|
|
1706
|
+
def __members__(self) -> Tuple[Optional[Text], Optional[Text], Text]:
|
|
1707
|
+
meta_no_nones = {k: v for k, v in self.metadata.items() if v is not None}
|
|
1708
|
+
return (self.action_name, self.action_text, jsonpickle.encode(meta_no_nones))
|
|
1709
|
+
|
|
1710
|
+
def __repr__(self) -> Text:
|
|
1711
|
+
"""Returns event as string for debugging."""
|
|
1712
|
+
return "ActionExecuted(action: {}, policy: {}, confidence: {})".format(
|
|
1713
|
+
self.action_name, self.policy, self.confidence
|
|
1714
|
+
)
|
|
1715
|
+
|
|
1716
|
+
def __str__(self) -> Text:
|
|
1717
|
+
"""Returns event as human readable string."""
|
|
1718
|
+
return str(self.action_name) or str(self.action_text)
|
|
1719
|
+
|
|
1720
|
+
def __hash__(self) -> int:
|
|
1721
|
+
"""Returns unique hash for event."""
|
|
1722
|
+
return hash(self.__members__())
|
|
1723
|
+
|
|
1724
|
+
def __eq__(self, other: Any) -> bool:
|
|
1725
|
+
"""Compares object with other object."""
|
|
1726
|
+
if not isinstance(other, ActionExecuted):
|
|
1727
|
+
return NotImplemented
|
|
1728
|
+
|
|
1729
|
+
return self.__members__() == other.__members__()
|
|
1730
|
+
|
|
1731
|
+
def as_story_string(self) -> Optional[Text]:
|
|
1732
|
+
"""Returns event in Markdown format."""
|
|
1733
|
+
if self.action_text:
|
|
1734
|
+
raise UnsupportedFeatureException(
|
|
1735
|
+
f"Printing end-to-end bot utterances is not supported in the "
|
|
1736
|
+
f"Markdown training format. Please use the YAML training data format "
|
|
1737
|
+
f"instead. Please see {DOCS_URL_TRAINING_DATA} for more information."
|
|
1738
|
+
)
|
|
1739
|
+
|
|
1740
|
+
return self.action_name
|
|
1741
|
+
|
|
1742
|
+
@classmethod
|
|
1743
|
+
def _from_story_string(
|
|
1744
|
+
cls, parameters: Dict[Text, Any]
|
|
1745
|
+
) -> Optional[List["ActionExecuted"]]:
|
|
1746
|
+
return [
|
|
1747
|
+
ActionExecuted(
|
|
1748
|
+
parameters.get("name"),
|
|
1749
|
+
parameters.get("policy"),
|
|
1750
|
+
parameters.get("confidence"),
|
|
1751
|
+
parameters.get("timestamp"),
|
|
1752
|
+
parameters.get("metadata"),
|
|
1753
|
+
parameters.get("action_text"),
|
|
1754
|
+
parameters.get("hide_rule_turn", False),
|
|
1755
|
+
)
|
|
1756
|
+
]
|
|
1757
|
+
|
|
1758
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
1759
|
+
"""Returns serialized event."""
|
|
1760
|
+
d = super().as_dict()
|
|
1761
|
+
d.update(
|
|
1762
|
+
{
|
|
1763
|
+
"name": self.action_name,
|
|
1764
|
+
"policy": self.policy,
|
|
1765
|
+
"confidence": self.confidence,
|
|
1766
|
+
"action_text": self.action_text,
|
|
1767
|
+
"hide_rule_turn": self.hide_rule_turn,
|
|
1768
|
+
}
|
|
1769
|
+
)
|
|
1770
|
+
return d
|
|
1771
|
+
|
|
1772
|
+
def as_sub_state(self) -> Dict[Text, Text]:
|
|
1773
|
+
"""Turns ActionExecuted into a dictionary containing action name or action text.
|
|
1774
|
+
|
|
1775
|
+
One action cannot have both set at the same time
|
|
1776
|
+
|
|
1777
|
+
Returns:
|
|
1778
|
+
a dictionary containing action name or action text with the corresponding
|
|
1779
|
+
key.
|
|
1780
|
+
"""
|
|
1781
|
+
if self.action_name:
|
|
1782
|
+
return {ACTION_NAME: self.action_name}
|
|
1783
|
+
else:
|
|
1784
|
+
# FIXME: we should define the type better here, and require either
|
|
1785
|
+
# `action_name` or `action_text`
|
|
1786
|
+
return {ACTION_TEXT: cast(Text, self.action_text)}
|
|
1787
|
+
|
|
1788
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
1789
|
+
"""Applies event to current conversation state."""
|
|
1790
|
+
tracker.set_latest_action(self.as_sub_state())
|
|
1791
|
+
tracker.clear_followup_action()
|
|
1792
|
+
|
|
1793
|
+
|
|
1794
|
+
class AgentUttered(SkipEventInMDStoryMixin):
|
|
1795
|
+
"""The agent has said something to the user.
|
|
1796
|
+
|
|
1797
|
+
This class is not used in the story training as it is contained in the
|
|
1798
|
+
``ActionExecuted`` class. An entry is made in the ``Tracker``.
|
|
1799
|
+
"""
|
|
1800
|
+
|
|
1801
|
+
type_name = "agent"
|
|
1802
|
+
|
|
1803
|
+
def __init__(
|
|
1804
|
+
self,
|
|
1805
|
+
text: Optional[Text] = None,
|
|
1806
|
+
data: Optional[Any] = None,
|
|
1807
|
+
timestamp: Optional[float] = None,
|
|
1808
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
1809
|
+
) -> None:
|
|
1810
|
+
"""See docstring of `BotUttered`."""
|
|
1811
|
+
self.text = text
|
|
1812
|
+
self.data = data
|
|
1813
|
+
super().__init__(timestamp, metadata)
|
|
1814
|
+
|
|
1815
|
+
def __hash__(self) -> int:
|
|
1816
|
+
"""Returns unique hash for event."""
|
|
1817
|
+
return hash((self.text, jsonpickle.encode(self.data)))
|
|
1818
|
+
|
|
1819
|
+
def __eq__(self, other: Any) -> bool:
|
|
1820
|
+
"""Compares object with other object."""
|
|
1821
|
+
if not isinstance(other, AgentUttered):
|
|
1822
|
+
return NotImplemented
|
|
1823
|
+
|
|
1824
|
+
return (self.text, jsonpickle.encode(self.data)) == (
|
|
1825
|
+
other.text,
|
|
1826
|
+
jsonpickle.encode(other.data),
|
|
1827
|
+
)
|
|
1828
|
+
|
|
1829
|
+
def __str__(self) -> Text:
|
|
1830
|
+
"""Returns text representation of event."""
|
|
1831
|
+
return "AgentUttered(text: {}, data: {})".format(
|
|
1832
|
+
self.text, json.dumps(self.data)
|
|
1833
|
+
)
|
|
1834
|
+
|
|
1835
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
1836
|
+
"""Returns serialized event."""
|
|
1837
|
+
d = super().as_dict()
|
|
1838
|
+
d.update({"text": self.text, "data": self.data})
|
|
1839
|
+
return d
|
|
1840
|
+
|
|
1841
|
+
@classmethod
|
|
1842
|
+
def _from_parameters(cls, parameters: Dict[Text, Any]) -> "AgentUttered":
|
|
1843
|
+
try:
|
|
1844
|
+
return AgentUttered(
|
|
1845
|
+
parameters.get("text"),
|
|
1846
|
+
parameters.get("data"),
|
|
1847
|
+
parameters.get("timestamp"),
|
|
1848
|
+
parameters.get("metadata"),
|
|
1849
|
+
)
|
|
1850
|
+
except KeyError as e:
|
|
1851
|
+
raise ValueError(f"Failed to parse agent uttered event. {e}")
|
|
1852
|
+
|
|
1853
|
+
|
|
1854
|
+
class ActiveLoop(Event):
|
|
1855
|
+
"""If `name` is given: activates a loop with `name` else deactivates active loop."""
|
|
1856
|
+
|
|
1857
|
+
type_name = "active_loop"
|
|
1858
|
+
|
|
1859
|
+
def __init__(
|
|
1860
|
+
self,
|
|
1861
|
+
name: Optional[Text],
|
|
1862
|
+
timestamp: Optional[float] = None,
|
|
1863
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
1864
|
+
) -> None:
|
|
1865
|
+
"""Creates event for active loop.
|
|
1866
|
+
|
|
1867
|
+
Args:
|
|
1868
|
+
name: Name of activated loop or `None` if current loop is deactivated.
|
|
1869
|
+
timestamp: When the event was created.
|
|
1870
|
+
metadata: Additional event metadata.
|
|
1871
|
+
"""
|
|
1872
|
+
self.name = name
|
|
1873
|
+
super().__init__(timestamp, metadata)
|
|
1874
|
+
|
|
1875
|
+
def __str__(self) -> Text:
|
|
1876
|
+
"""Returns text representation of event."""
|
|
1877
|
+
return f"Loop({self.name})"
|
|
1878
|
+
|
|
1879
|
+
def __repr__(self) -> Text:
|
|
1880
|
+
"""Returns event as string for debugging."""
|
|
1881
|
+
return f"ActiveLoop({self.name}, {self.timestamp}, {self.metadata})"
|
|
1882
|
+
|
|
1883
|
+
def __hash__(self) -> int:
|
|
1884
|
+
"""Returns unique hash for event."""
|
|
1885
|
+
return hash(self.name)
|
|
1886
|
+
|
|
1887
|
+
def __eq__(self, other: Any) -> bool:
|
|
1888
|
+
"""Compares object with other object."""
|
|
1889
|
+
if not isinstance(other, ActiveLoop):
|
|
1890
|
+
return NotImplemented
|
|
1891
|
+
|
|
1892
|
+
return self.name == other.name
|
|
1893
|
+
|
|
1894
|
+
def as_story_string(self) -> Text:
|
|
1895
|
+
"""Returns text representation of event."""
|
|
1896
|
+
props = json.dumps({LOOP_NAME: self.name})
|
|
1897
|
+
return f"{ActiveLoop.type_name}{props}"
|
|
1898
|
+
|
|
1899
|
+
@classmethod
|
|
1900
|
+
def _from_story_string(cls, parameters: Dict[Text, Any]) -> List["ActiveLoop"]:
|
|
1901
|
+
"""Called to convert a parsed story line into an event."""
|
|
1902
|
+
return [
|
|
1903
|
+
ActiveLoop(
|
|
1904
|
+
parameters.get(LOOP_NAME),
|
|
1905
|
+
parameters.get("timestamp"),
|
|
1906
|
+
parameters.get("metadata"),
|
|
1907
|
+
)
|
|
1908
|
+
]
|
|
1909
|
+
|
|
1910
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
1911
|
+
"""Returns serialized event."""
|
|
1912
|
+
d = super().as_dict()
|
|
1913
|
+
d.update({LOOP_NAME: self.name})
|
|
1914
|
+
return d
|
|
1915
|
+
|
|
1916
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
1917
|
+
"""Applies event to current conversation state."""
|
|
1918
|
+
tracker.change_loop_to(self.name)
|
|
1919
|
+
|
|
1920
|
+
|
|
1921
|
+
class LegacyForm(ActiveLoop):
|
|
1922
|
+
"""Legacy handler of old `Form` events.
|
|
1923
|
+
|
|
1924
|
+
The `ActiveLoop` event used to be called `Form`. This class is there to handle old
|
|
1925
|
+
legacy events which were stored with the old type name `form`.
|
|
1926
|
+
"""
|
|
1927
|
+
|
|
1928
|
+
type_name = "form"
|
|
1929
|
+
|
|
1930
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
1931
|
+
"""Returns serialized event."""
|
|
1932
|
+
d = super().as_dict()
|
|
1933
|
+
# Dump old `Form` events as `ActiveLoop` events instead of keeping the old
|
|
1934
|
+
# event type.
|
|
1935
|
+
d["event"] = ActiveLoop.type_name
|
|
1936
|
+
return d
|
|
1937
|
+
|
|
1938
|
+
def fingerprint(self) -> Text:
|
|
1939
|
+
"""Returns the hash of the event."""
|
|
1940
|
+
d = self.as_dict()
|
|
1941
|
+
# Revert event name to legacy subclass name to avoid different event types
|
|
1942
|
+
# having the same fingerprint.
|
|
1943
|
+
d["event"] = self.type_name
|
|
1944
|
+
del d["timestamp"]
|
|
1945
|
+
return rasa.shared.utils.io.get_dictionary_fingerprint(d)
|
|
1946
|
+
|
|
1947
|
+
|
|
1948
|
+
class LoopInterrupted(SkipEventInMDStoryMixin):
|
|
1949
|
+
"""Event added by FormPolicy and RulePolicy.
|
|
1950
|
+
|
|
1951
|
+
Notifies form action whether or not to validate the user input.
|
|
1952
|
+
"""
|
|
1953
|
+
|
|
1954
|
+
type_name = "loop_interrupted"
|
|
1955
|
+
|
|
1956
|
+
def __init__(
|
|
1957
|
+
self,
|
|
1958
|
+
is_interrupted: bool,
|
|
1959
|
+
timestamp: Optional[float] = None,
|
|
1960
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
1961
|
+
) -> None:
|
|
1962
|
+
"""Event to notify that loop was interrupted.
|
|
1963
|
+
|
|
1964
|
+
This e.g. happens when a user is within a form, and is de-railing the
|
|
1965
|
+
form-filling by asking FAQs.
|
|
1966
|
+
|
|
1967
|
+
Args:
|
|
1968
|
+
is_interrupted: `True` if the loop execution was interrupted, and ML
|
|
1969
|
+
policies had to take over the last prediction.
|
|
1970
|
+
timestamp: When the event was created.
|
|
1971
|
+
metadata: Additional event metadata.
|
|
1972
|
+
"""
|
|
1973
|
+
super().__init__(timestamp, metadata)
|
|
1974
|
+
self.is_interrupted = is_interrupted
|
|
1975
|
+
|
|
1976
|
+
def __str__(self) -> Text:
|
|
1977
|
+
"""Returns text representation of event."""
|
|
1978
|
+
return f"{LoopInterrupted.__name__}({self.is_interrupted})"
|
|
1979
|
+
|
|
1980
|
+
def __hash__(self) -> int:
|
|
1981
|
+
"""Returns unique hash for event."""
|
|
1982
|
+
return hash(self.is_interrupted)
|
|
1983
|
+
|
|
1984
|
+
def __eq__(self, other: Any) -> bool:
|
|
1985
|
+
"""Compares object with other object."""
|
|
1986
|
+
if not isinstance(other, LoopInterrupted):
|
|
1987
|
+
return NotImplemented
|
|
1988
|
+
|
|
1989
|
+
return self.is_interrupted == other.is_interrupted
|
|
1990
|
+
|
|
1991
|
+
@classmethod
|
|
1992
|
+
def _from_parameters(cls, parameters: Dict[Text, Any]) -> "LoopInterrupted":
|
|
1993
|
+
return LoopInterrupted(
|
|
1994
|
+
parameters.get(LOOP_INTERRUPTED, False),
|
|
1995
|
+
parameters.get("timestamp"),
|
|
1996
|
+
parameters.get("metadata"),
|
|
1997
|
+
)
|
|
1998
|
+
|
|
1999
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
2000
|
+
"""Returns serialized event."""
|
|
2001
|
+
d = super().as_dict()
|
|
2002
|
+
d.update({LOOP_INTERRUPTED: self.is_interrupted})
|
|
2003
|
+
return d
|
|
2004
|
+
|
|
2005
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
2006
|
+
"""Applies event to current conversation state."""
|
|
2007
|
+
tracker.interrupt_loop(self.is_interrupted)
|
|
2008
|
+
|
|
2009
|
+
|
|
2010
|
+
class LegacyFormValidation(LoopInterrupted):
|
|
2011
|
+
"""Legacy handler of old `FormValidation` events.
|
|
2012
|
+
|
|
2013
|
+
The `LoopInterrupted` event used to be called `FormValidation`. This class is there
|
|
2014
|
+
to handle old legacy events which were stored with the old type name
|
|
2015
|
+
`form_validation`.
|
|
2016
|
+
"""
|
|
2017
|
+
|
|
2018
|
+
type_name = "form_validation"
|
|
2019
|
+
|
|
2020
|
+
def __init__(
|
|
2021
|
+
self,
|
|
2022
|
+
validate: bool,
|
|
2023
|
+
timestamp: Optional[float] = None,
|
|
2024
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
2025
|
+
) -> None:
|
|
2026
|
+
"""See parent class docstring."""
|
|
2027
|
+
# `validate = True` is the same as `interrupted = False`
|
|
2028
|
+
super().__init__(not validate, timestamp, metadata)
|
|
2029
|
+
|
|
2030
|
+
@classmethod
|
|
2031
|
+
def _from_parameters(cls, parameters: Dict) -> "LoopInterrupted":
|
|
2032
|
+
return LoopInterrupted(
|
|
2033
|
+
# `validate = True` means `is_interrupted = False`
|
|
2034
|
+
not parameters.get("validate", True),
|
|
2035
|
+
parameters.get("timestamp"),
|
|
2036
|
+
parameters.get("metadata"),
|
|
2037
|
+
)
|
|
2038
|
+
|
|
2039
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
2040
|
+
"""Returns serialized event."""
|
|
2041
|
+
d = super().as_dict()
|
|
2042
|
+
# Dump old `Form` events as `ActiveLoop` events instead of keeping the old
|
|
2043
|
+
# event type.
|
|
2044
|
+
d["event"] = LoopInterrupted.type_name
|
|
2045
|
+
return d
|
|
2046
|
+
|
|
2047
|
+
def fingerprint(self) -> Text:
|
|
2048
|
+
"""Returns hash of the event."""
|
|
2049
|
+
d = self.as_dict()
|
|
2050
|
+
# Revert event name to legacy subclass name to avoid different event types
|
|
2051
|
+
# having the same fingerprint.
|
|
2052
|
+
d["event"] = self.type_name
|
|
2053
|
+
del d["timestamp"]
|
|
2054
|
+
return rasa.shared.utils.io.get_dictionary_fingerprint(d)
|
|
2055
|
+
|
|
2056
|
+
|
|
2057
|
+
class ActionExecutionRejected(SkipEventInMDStoryMixin):
|
|
2058
|
+
"""Notify Core that the execution of the action has been rejected."""
|
|
2059
|
+
|
|
2060
|
+
type_name = "action_execution_rejected"
|
|
2061
|
+
|
|
2062
|
+
def __init__(
|
|
2063
|
+
self,
|
|
2064
|
+
action_name: Text,
|
|
2065
|
+
policy: Optional[Text] = None,
|
|
2066
|
+
confidence: Optional[float] = None,
|
|
2067
|
+
timestamp: Optional[float] = None,
|
|
2068
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
2069
|
+
) -> None:
|
|
2070
|
+
"""Creates event.
|
|
2071
|
+
|
|
2072
|
+
Args:
|
|
2073
|
+
action_name: Action which was rejected.
|
|
2074
|
+
policy: Policy which predicted the rejected action.
|
|
2075
|
+
confidence: Confidence with which the reject action was predicted.
|
|
2076
|
+
timestamp: When the event was created.
|
|
2077
|
+
metadata: Additional event metadata.
|
|
2078
|
+
"""
|
|
2079
|
+
self.action_name = action_name
|
|
2080
|
+
self.policy = policy
|
|
2081
|
+
self.confidence = confidence
|
|
2082
|
+
super().__init__(timestamp, metadata)
|
|
2083
|
+
|
|
2084
|
+
def __str__(self) -> Text:
|
|
2085
|
+
"""Returns text representation of event."""
|
|
2086
|
+
return (
|
|
2087
|
+
"ActionExecutionRejected("
|
|
2088
|
+
"action: {}, policy: {}, confidence: {})"
|
|
2089
|
+
"".format(self.action_name, self.policy, self.confidence)
|
|
2090
|
+
)
|
|
2091
|
+
|
|
2092
|
+
def __hash__(self) -> int:
|
|
2093
|
+
"""Returns unique hash for event."""
|
|
2094
|
+
return hash(self.action_name)
|
|
2095
|
+
|
|
2096
|
+
def __eq__(self, other: Any) -> bool:
|
|
2097
|
+
"""Compares object with other object."""
|
|
2098
|
+
if not isinstance(other, ActionExecutionRejected):
|
|
2099
|
+
return NotImplemented
|
|
2100
|
+
|
|
2101
|
+
return self.action_name == other.action_name
|
|
2102
|
+
|
|
2103
|
+
@classmethod
|
|
2104
|
+
def _from_parameters(cls, parameters: Dict[Text, Any]) -> "ActionExecutionRejected":
|
|
2105
|
+
return ActionExecutionRejected(
|
|
2106
|
+
parameters.get("name"),
|
|
2107
|
+
parameters.get("policy"),
|
|
2108
|
+
parameters.get("confidence"),
|
|
2109
|
+
parameters.get("timestamp"),
|
|
2110
|
+
parameters.get("metadata"),
|
|
2111
|
+
)
|
|
2112
|
+
|
|
2113
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
2114
|
+
"""Returns serialized event."""
|
|
2115
|
+
d = super().as_dict()
|
|
2116
|
+
d.update(
|
|
2117
|
+
{
|
|
2118
|
+
"name": self.action_name,
|
|
2119
|
+
"policy": self.policy,
|
|
2120
|
+
"confidence": self.confidence,
|
|
2121
|
+
}
|
|
2122
|
+
)
|
|
2123
|
+
return d
|
|
2124
|
+
|
|
2125
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
2126
|
+
"""Applies event to current conversation state."""
|
|
2127
|
+
tracker.reject_action(self.action_name)
|
|
2128
|
+
|
|
2129
|
+
|
|
2130
|
+
class SessionStarted(AlwaysEqualEventMixin):
|
|
2131
|
+
"""Mark the beginning of a new conversation session."""
|
|
2132
|
+
|
|
2133
|
+
type_name = "session_started"
|
|
2134
|
+
|
|
2135
|
+
def __hash__(self) -> int:
|
|
2136
|
+
"""Returns unique hash for event."""
|
|
2137
|
+
return hash(32143124320)
|
|
2138
|
+
|
|
2139
|
+
def __repr__(self) -> Text:
|
|
2140
|
+
"""Returns event as string for debugging."""
|
|
2141
|
+
return f"SessionStarted(type_name: {self.type_name})"
|
|
2142
|
+
|
|
2143
|
+
def __str__(self) -> Text:
|
|
2144
|
+
"""Returns event as human-readable string."""
|
|
2145
|
+
return f"{self.__class__.__name__}({self.type_name})"
|
|
2146
|
+
|
|
2147
|
+
def as_story_string(self) -> None:
|
|
2148
|
+
"""Skips representing event in stories."""
|
|
2149
|
+
logger.warning(
|
|
2150
|
+
f"'{self.type_name}' events cannot be serialised as story strings."
|
|
2151
|
+
)
|
|
2152
|
+
|
|
2153
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
2154
|
+
"""Applies event to current conversation state."""
|
|
2155
|
+
# noinspection PyProtectedMember
|
|
2156
|
+
tracker._reset()
|
|
2157
|
+
|
|
2158
|
+
|
|
2159
|
+
class RoutingSessionEnded(AlwaysEqualEventMixin):
|
|
2160
|
+
"""Mark the end of a routing session for coexistence."""
|
|
2161
|
+
|
|
2162
|
+
type_name = "routing_session_ended"
|
|
2163
|
+
|
|
2164
|
+
def __hash__(self) -> int:
|
|
2165
|
+
"""Returns unique hash for event."""
|
|
2166
|
+
return hash(32143124434)
|
|
2167
|
+
|
|
2168
|
+
def __repr__(self) -> Text:
|
|
2169
|
+
"""Returns event as string for debugging."""
|
|
2170
|
+
return f"RoutingSessionEnded(type_name: {self.type_name})"
|
|
2171
|
+
|
|
2172
|
+
def __str__(self) -> Text:
|
|
2173
|
+
"""Returns event as human-readable string."""
|
|
2174
|
+
return f"{self.__class__.__name__}({self.type_name})"
|
|
2175
|
+
|
|
2176
|
+
def as_story_string(self) -> None:
|
|
2177
|
+
"""Skips representing event in stories."""
|
|
2178
|
+
logger.warning(
|
|
2179
|
+
f"'{self.type_name}' events cannot be serialised as story strings."
|
|
2180
|
+
)
|
|
2181
|
+
|
|
2182
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
2183
|
+
"""Applies event to current conversation state."""
|
|
2184
|
+
# noinspection PyProtectedMember
|
|
2185
|
+
tracker._reset(is_coexistence_reset=True)
|
|
2186
|
+
|
|
2187
|
+
|
|
2188
|
+
class FlowStarted(SkipEventInMDStoryMixin):
|
|
2189
|
+
"""Mark the beginning of a new flow."""
|
|
2190
|
+
|
|
2191
|
+
type_name = "flow_started"
|
|
2192
|
+
|
|
2193
|
+
def __init__(
|
|
2194
|
+
self,
|
|
2195
|
+
flow_id: Text,
|
|
2196
|
+
timestamp: Optional[float] = None,
|
|
2197
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
2198
|
+
) -> None:
|
|
2199
|
+
"""Creates event to start flow.
|
|
2200
|
+
|
|
2201
|
+
Args:
|
|
2202
|
+
flow_id: ID of the flow to be started.
|
|
2203
|
+
timestamp: When the event was created.
|
|
2204
|
+
metadata: Additional event metadata.
|
|
2205
|
+
"""
|
|
2206
|
+
self.flow_id = flow_id
|
|
2207
|
+
super().__init__(timestamp, metadata)
|
|
2208
|
+
|
|
2209
|
+
def __repr__(self) -> Text:
|
|
2210
|
+
"""Returns event as string for debugging."""
|
|
2211
|
+
return f"FlowStarted(flow: {self.flow_id})"
|
|
2212
|
+
|
|
2213
|
+
def __str__(self) -> Text:
|
|
2214
|
+
"""Returns event as human-readable string."""
|
|
2215
|
+
return f"{self.__class__.__name__}({self.flow_id})"
|
|
2216
|
+
|
|
2217
|
+
def __hash__(self) -> int:
|
|
2218
|
+
"""Returns unique hash for event."""
|
|
2219
|
+
return hash(self.flow_id)
|
|
2220
|
+
|
|
2221
|
+
def __eq__(self, other: Any) -> bool:
|
|
2222
|
+
"""Compares object with other object."""
|
|
2223
|
+
if not isinstance(other, FlowStarted):
|
|
2224
|
+
return NotImplemented
|
|
2225
|
+
|
|
2226
|
+
return self.flow_id == other.flow_id
|
|
2227
|
+
|
|
2228
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
2229
|
+
"""Returns serialized event."""
|
|
2230
|
+
serialized = super().as_dict()
|
|
2231
|
+
serialized.update({"flow_id": self.flow_id})
|
|
2232
|
+
return serialized
|
|
2233
|
+
|
|
2234
|
+
@classmethod
|
|
2235
|
+
def _from_parameters(cls, parameters: Dict[Text, Any]) -> "FlowStarted":
|
|
2236
|
+
try:
|
|
2237
|
+
return FlowStarted(
|
|
2238
|
+
parameters.get("flow_id"),
|
|
2239
|
+
parameters.get("timestamp"),
|
|
2240
|
+
parameters.get("metadata"),
|
|
2241
|
+
)
|
|
2242
|
+
except KeyError as e:
|
|
2243
|
+
raise ValueError(f"Failed to parse flow_started event. {e}")
|
|
2244
|
+
|
|
2245
|
+
|
|
2246
|
+
class FlowInterrupted(SkipEventInMDStoryMixin):
|
|
2247
|
+
"""Mark the interruption of a flow."""
|
|
2248
|
+
|
|
2249
|
+
type_name = "flow_interrupted"
|
|
2250
|
+
|
|
2251
|
+
def __init__(
|
|
2252
|
+
self,
|
|
2253
|
+
flow_id: Text,
|
|
2254
|
+
step_id: Text,
|
|
2255
|
+
timestamp: Optional[float] = None,
|
|
2256
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
2257
|
+
) -> None:
|
|
2258
|
+
"""Creates event to interrupt a flow.
|
|
2259
|
+
|
|
2260
|
+
Args:
|
|
2261
|
+
flow_id: Name of the flow to be interrupted.
|
|
2262
|
+
step_id: ID of the flow step where the flow was interrupted.
|
|
2263
|
+
timestamp: When the event was created.
|
|
2264
|
+
metadata: Additional event metadata.
|
|
2265
|
+
"""
|
|
2266
|
+
self.flow_id = flow_id
|
|
2267
|
+
self.step_id = step_id
|
|
2268
|
+
self.is_interrupted = True
|
|
2269
|
+
super().__init__(timestamp, metadata)
|
|
2270
|
+
|
|
2271
|
+
def __repr__(self) -> Text:
|
|
2272
|
+
"""Returns event as string for debugging."""
|
|
2273
|
+
return f"FlowInterrupted(flow: {self.flow_id}, step_id: {self.step_id})"
|
|
2274
|
+
|
|
2275
|
+
def __str__(self) -> Text:
|
|
2276
|
+
"""Returns event as human-readable string."""
|
|
2277
|
+
return f"{self.__class__.__name__}({self.flow_id}, {self.step_id})"
|
|
2278
|
+
|
|
2279
|
+
def __hash__(self) -> int:
|
|
2280
|
+
"""Returns unique hash for event."""
|
|
2281
|
+
return hash(
|
|
2282
|
+
(
|
|
2283
|
+
self.flow_id,
|
|
2284
|
+
self.step_id,
|
|
2285
|
+
json.dumps({"is_interrupted": self.is_interrupted}),
|
|
2286
|
+
)
|
|
2287
|
+
)
|
|
2288
|
+
|
|
2289
|
+
def __eq__(self, other: Any) -> bool:
|
|
2290
|
+
"""Compares object with other object."""
|
|
2291
|
+
if not isinstance(other, FlowInterrupted):
|
|
2292
|
+
return NotImplemented
|
|
2293
|
+
|
|
2294
|
+
return (self.flow_id, self.step_id) == (other.flow_id, other.step_id)
|
|
2295
|
+
|
|
2296
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
2297
|
+
"""Returns serialized event."""
|
|
2298
|
+
serialized = super().as_dict()
|
|
2299
|
+
serialized.update(
|
|
2300
|
+
{
|
|
2301
|
+
"flow_id": self.flow_id,
|
|
2302
|
+
"step_id": self.step_id,
|
|
2303
|
+
}
|
|
2304
|
+
)
|
|
2305
|
+
return serialized
|
|
2306
|
+
|
|
2307
|
+
@classmethod
|
|
2308
|
+
def _from_parameters(cls, parameters: Dict[Text, Any]) -> "FlowInterrupted":
|
|
2309
|
+
try:
|
|
2310
|
+
return FlowInterrupted(
|
|
2311
|
+
parameters.get("flow_id"),
|
|
2312
|
+
parameters.get("step_id"),
|
|
2313
|
+
parameters.get("timestamp"),
|
|
2314
|
+
parameters.get("metadata"),
|
|
2315
|
+
)
|
|
2316
|
+
except KeyError as e:
|
|
2317
|
+
raise ValueError(f"Failed to parse flow_interrupted event. {e}")
|
|
2318
|
+
|
|
2319
|
+
|
|
2320
|
+
class FlowResumed(SkipEventInMDStoryMixin):
|
|
2321
|
+
"""Mark the resuming of a flow."""
|
|
2322
|
+
|
|
2323
|
+
type_name = "flow_resumed"
|
|
2324
|
+
|
|
2325
|
+
def __init__(
|
|
2326
|
+
self,
|
|
2327
|
+
flow_id: Text,
|
|
2328
|
+
step_id: Text,
|
|
2329
|
+
timestamp: Optional[float] = None,
|
|
2330
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
2331
|
+
) -> None:
|
|
2332
|
+
"""Creates event to resume a flow.
|
|
2333
|
+
|
|
2334
|
+
Args:
|
|
2335
|
+
flow_id: ID of the flow to be resumed.
|
|
2336
|
+
step_id: ID of the flow step where the flow was resumed.
|
|
2337
|
+
timestamp: When the event was created.
|
|
2338
|
+
metadata: Additional event metadata.
|
|
2339
|
+
"""
|
|
2340
|
+
self.flow_id = flow_id
|
|
2341
|
+
self.step_id = step_id
|
|
2342
|
+
self.is_resumed = True
|
|
2343
|
+
super().__init__(timestamp, metadata)
|
|
2344
|
+
|
|
2345
|
+
def __repr__(self) -> Text:
|
|
2346
|
+
"""Returns event as string for debugging."""
|
|
2347
|
+
return f"FlowResumed(flow: {self.flow_id}, step_id: {self.step_id})"
|
|
2348
|
+
|
|
2349
|
+
def __str__(self) -> Text:
|
|
2350
|
+
"""Returns event as human-readable string."""
|
|
2351
|
+
return f"{self.__class__.__name__}({self.flow_id}, {self.step_id})"
|
|
2352
|
+
|
|
2353
|
+
def __hash__(self) -> int:
|
|
2354
|
+
"""Returns unique hash for event."""
|
|
2355
|
+
return hash(
|
|
2356
|
+
(self.flow_id, self.step_id, json.dumps({"is_resumed": self.is_resumed}))
|
|
2357
|
+
)
|
|
2358
|
+
|
|
2359
|
+
def __eq__(self, other: Any) -> bool:
|
|
2360
|
+
"""Compares object with other object."""
|
|
2361
|
+
if not isinstance(other, FlowResumed):
|
|
2362
|
+
return NotImplemented
|
|
2363
|
+
|
|
2364
|
+
return (self.flow_id, self.step_id) == (other.flow_id, other.step_id)
|
|
2365
|
+
|
|
2366
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
2367
|
+
"""Returns serialized event."""
|
|
2368
|
+
serialized = super().as_dict()
|
|
2369
|
+
serialized.update({"flow_id": self.flow_id, "step_id": self.step_id})
|
|
2370
|
+
return serialized
|
|
2371
|
+
|
|
2372
|
+
@classmethod
|
|
2373
|
+
def _from_parameters(cls, parameters: Dict[Text, Any]) -> "FlowResumed":
|
|
2374
|
+
try:
|
|
2375
|
+
return FlowResumed(
|
|
2376
|
+
parameters.get("flow_id"),
|
|
2377
|
+
parameters.get("step_id"),
|
|
2378
|
+
parameters.get("timestamp"),
|
|
2379
|
+
parameters.get("metadata"),
|
|
2380
|
+
)
|
|
2381
|
+
except KeyError as e:
|
|
2382
|
+
raise ValueError(f"Failed to parse flow_resumed event. {e}")
|
|
2383
|
+
|
|
2384
|
+
|
|
2385
|
+
class FlowCompleted(SkipEventInMDStoryMixin):
|
|
2386
|
+
"""Mark the completion of a flow."""
|
|
2387
|
+
|
|
2388
|
+
type_name = "flow_completed"
|
|
2389
|
+
|
|
2390
|
+
def __init__(
|
|
2391
|
+
self,
|
|
2392
|
+
flow_id: Text,
|
|
2393
|
+
step_id: Text,
|
|
2394
|
+
timestamp: Optional[float] = None,
|
|
2395
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
2396
|
+
) -> None:
|
|
2397
|
+
"""Creates event to complete a flow.
|
|
2398
|
+
|
|
2399
|
+
Args:
|
|
2400
|
+
flow_id: ID of the flow to be completed.
|
|
2401
|
+
step_id: ID of the flow step where the flow was completed.
|
|
2402
|
+
timestamp: When the event was created.
|
|
2403
|
+
metadata: Additional event metadata.
|
|
2404
|
+
"""
|
|
2405
|
+
self.flow_id = flow_id
|
|
2406
|
+
self.step_id = step_id
|
|
2407
|
+
self.is_completed = True
|
|
2408
|
+
super().__init__(timestamp, metadata)
|
|
2409
|
+
|
|
2410
|
+
def __repr__(self) -> Text:
|
|
2411
|
+
"""Returns event as string for debugging."""
|
|
2412
|
+
return f"FlowCompleted(flow: {self.flow_id}, step_id: {self.step_id})"
|
|
2413
|
+
|
|
2414
|
+
def __str__(self) -> Text:
|
|
2415
|
+
"""Returns event as human-readable string."""
|
|
2416
|
+
return f"{self.__class__.__name__}({self.flow_id}, {self.step_id})"
|
|
2417
|
+
|
|
2418
|
+
def __hash__(self) -> int:
|
|
2419
|
+
"""Returns unique hash for event."""
|
|
2420
|
+
return hash(
|
|
2421
|
+
(
|
|
2422
|
+
self.flow_id,
|
|
2423
|
+
self.step_id,
|
|
2424
|
+
json.dumps({"is_completed": self.is_completed}),
|
|
2425
|
+
)
|
|
2426
|
+
)
|
|
2427
|
+
|
|
2428
|
+
def __eq__(self, other: Any) -> bool:
|
|
2429
|
+
"""Compares object with other object."""
|
|
2430
|
+
if not isinstance(other, FlowCompleted):
|
|
2431
|
+
return NotImplemented
|
|
2432
|
+
|
|
2433
|
+
return (self.flow_id, self.step_id) == (other.flow_id, other.step_id)
|
|
2434
|
+
|
|
2435
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
2436
|
+
"""Returns serialized event."""
|
|
2437
|
+
serialized = super().as_dict()
|
|
2438
|
+
serialized.update(
|
|
2439
|
+
{
|
|
2440
|
+
"flow_id": self.flow_id,
|
|
2441
|
+
"step_id": self.step_id,
|
|
2442
|
+
}
|
|
2443
|
+
)
|
|
2444
|
+
return serialized
|
|
2445
|
+
|
|
2446
|
+
@classmethod
|
|
2447
|
+
def _from_parameters(cls, parameters: Dict[Text, Any]) -> "FlowCompleted":
|
|
2448
|
+
try:
|
|
2449
|
+
return FlowCompleted(
|
|
2450
|
+
parameters.get("flow_id"),
|
|
2451
|
+
parameters.get("step_id"),
|
|
2452
|
+
parameters.get("timestamp"),
|
|
2453
|
+
parameters.get("metadata"),
|
|
2454
|
+
)
|
|
2455
|
+
except KeyError as e:
|
|
2456
|
+
raise ValueError(f"Failed to parse flow_completed event. {e}")
|
|
2457
|
+
|
|
2458
|
+
|
|
2459
|
+
class FlowCancelled(SkipEventInMDStoryMixin):
|
|
2460
|
+
"""Mark the cancellation of a flow."""
|
|
2461
|
+
|
|
2462
|
+
type_name = "flow_cancelled"
|
|
2463
|
+
|
|
2464
|
+
def __init__(
|
|
2465
|
+
self,
|
|
2466
|
+
flow_id: Text,
|
|
2467
|
+
step_id: Text,
|
|
2468
|
+
timestamp: Optional[float] = None,
|
|
2469
|
+
metadata: Optional[Dict[Text, Any]] = None,
|
|
2470
|
+
) -> None:
|
|
2471
|
+
"""Creates event to cancel a flow.
|
|
2472
|
+
|
|
2473
|
+
Args:
|
|
2474
|
+
flow_id: ID of the flow which was cancelled.
|
|
2475
|
+
step_id: ID of the flow step where the flow was cancelled.
|
|
2476
|
+
timestamp: When the event was created.
|
|
2477
|
+
metadata: Additional event metadata.
|
|
2478
|
+
"""
|
|
2479
|
+
self.flow_id = flow_id
|
|
2480
|
+
self.step_id = step_id
|
|
2481
|
+
self.is_cancelled = True
|
|
2482
|
+
super().__init__(timestamp, metadata)
|
|
2483
|
+
|
|
2484
|
+
def __repr__(self) -> Text:
|
|
2485
|
+
"""Returns event as string for debugging."""
|
|
2486
|
+
return f"FlowCancelled(flow: {self.flow_id}, step_id: {self.step_id})"
|
|
2487
|
+
|
|
2488
|
+
def __str__(self) -> Text:
|
|
2489
|
+
"""Returns event as human-readable string."""
|
|
2490
|
+
return f"{self.__class__.__name__}({self.flow_id}, {self.step_id})"
|
|
2491
|
+
|
|
2492
|
+
def __hash__(self) -> int:
|
|
2493
|
+
"""Returns unique hash for event."""
|
|
2494
|
+
return hash(
|
|
2495
|
+
(
|
|
2496
|
+
self.flow_id,
|
|
2497
|
+
self.step_id,
|
|
2498
|
+
json.dumps({"is_cancelled": self.is_cancelled}),
|
|
2499
|
+
)
|
|
2500
|
+
)
|
|
2501
|
+
|
|
2502
|
+
def __eq__(self, other: Any) -> bool:
|
|
2503
|
+
"""Compares object with other object."""
|
|
2504
|
+
if not isinstance(other, FlowCancelled):
|
|
2505
|
+
return NotImplemented
|
|
2506
|
+
|
|
2507
|
+
return (self.flow_id, self.step_id) == (other.flow_id, other.step_id)
|
|
2508
|
+
|
|
2509
|
+
def as_dict(self) -> Dict[Text, Any]:
|
|
2510
|
+
"""Returns serialized event."""
|
|
2511
|
+
serialized = super().as_dict()
|
|
2512
|
+
serialized.update(
|
|
2513
|
+
{
|
|
2514
|
+
"flow_id": self.flow_id,
|
|
2515
|
+
"step_id": self.step_id,
|
|
2516
|
+
}
|
|
2517
|
+
)
|
|
2518
|
+
return serialized
|
|
2519
|
+
|
|
2520
|
+
@classmethod
|
|
2521
|
+
def _from_parameters(cls, parameters: Dict[Text, Any]) -> "FlowCancelled":
|
|
2522
|
+
try:
|
|
2523
|
+
return FlowCancelled(
|
|
2524
|
+
parameters.get("flow_id"),
|
|
2525
|
+
parameters.get("step_id"),
|
|
2526
|
+
parameters.get("timestamp"),
|
|
2527
|
+
parameters.get("metadata"),
|
|
2528
|
+
)
|
|
2529
|
+
except KeyError as e:
|
|
2530
|
+
raise ValueError(f"Failed to parse flow_cancelled event. {e}")
|
|
2531
|
+
|
|
2532
|
+
|
|
2533
|
+
class SessionEnded(AlwaysEqualEventMixin):
|
|
2534
|
+
"""Mark the end of a conversation session."""
|
|
2535
|
+
|
|
2536
|
+
type_name = "session_ended"
|
|
2537
|
+
|
|
2538
|
+
def __hash__(self) -> int:
|
|
2539
|
+
"""Returns unique hash for event."""
|
|
2540
|
+
return hash(32143124321)
|
|
2541
|
+
|
|
2542
|
+
def __repr__(self) -> Text:
|
|
2543
|
+
"""Returns event as string for debugging."""
|
|
2544
|
+
return f"SessionEnded(type_name: {self.type_name})"
|
|
2545
|
+
|
|
2546
|
+
def __str__(self) -> Text:
|
|
2547
|
+
"""Returns event as human-readable string."""
|
|
2548
|
+
return f"{self.__class__.__name__}({self.type_name})"
|
|
2549
|
+
|
|
2550
|
+
def as_story_string(self) -> None:
|
|
2551
|
+
"""Skips representing event in stories."""
|
|
2552
|
+
logger.warning(
|
|
2553
|
+
f"'{self.type_name}' events cannot be serialised as story strings."
|
|
2554
|
+
)
|
|
2555
|
+
|
|
2556
|
+
def apply_to(self, tracker: "DialogueStateTracker") -> None:
|
|
2557
|
+
"""Applies event to current conversation state."""
|
|
2558
|
+
# noinspection PyProtectedMember
|
|
2559
|
+
tracker._reset()
|