rasa-pro 3.13.0.dev5__py3-none-any.whl → 3.13.0.dev8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rasa-pro might be problematic. Click here for more details.
- rasa/__main__.py +0 -3
- rasa/api.py +5 -1
- rasa/cli/arguments/default_arguments.py +13 -1
- rasa/cli/arguments/train.py +2 -0
- rasa/cli/dialogue_understanding_test.py +1 -1
- rasa/cli/e2e_test.py +1 -1
- rasa/cli/evaluate.py +2 -2
- rasa/cli/export.py +3 -3
- rasa/cli/llm_fine_tuning.py +12 -11
- rasa/cli/project_templates/defaults.py +133 -0
- rasa/cli/run.py +1 -1
- rasa/cli/studio/link.py +53 -0
- rasa/cli/studio/pull.py +78 -0
- rasa/cli/studio/push.py +78 -0
- rasa/cli/studio/studio.py +12 -0
- rasa/cli/studio/upload.py +8 -0
- rasa/cli/train.py +2 -1
- rasa/cli/utils.py +1 -1
- rasa/cli/x.py +1 -1
- rasa/constants.py +4 -0
- rasa/core/__init__.py +0 -16
- rasa/core/actions/action.py +5 -1
- rasa/core/actions/action_repeat_bot_messages.py +18 -22
- rasa/core/actions/action_run_slot_rejections.py +0 -1
- rasa/core/agent.py +18 -3
- rasa/core/available_endpoints.py +146 -0
- rasa/core/brokers/kafka.py +4 -0
- rasa/core/brokers/pika.py +5 -2
- rasa/core/brokers/sql.py +1 -1
- rasa/core/channels/botframework.py +2 -2
- rasa/core/channels/channel.py +2 -2
- rasa/core/channels/hangouts.py +8 -5
- rasa/core/channels/inspector/.eslintrc.cjs +12 -6
- rasa/core/channels/inspector/.prettierrc +5 -0
- rasa/core/channels/inspector/README.md +10 -4
- rasa/core/channels/inspector/dist/assets/{arc-9f75cc3b.js → arc-c4b064fc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-7f34db23.js → blockDiagram-38ab4fdb-215b5026.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-948bab2c.js → c4Diagram-3d4e48cf-2b54a0a3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-3730f5fd.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-53b0dd0e.js → classDiagram-70f12bd4-daacea5f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-fdf789e7.js → classDiagram-v2-f2320105-930d4dc2.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-e847561e.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-87c4ece5.js → createText-2e5e7dd3-83c206ba.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-5a8b0749.js → edges-e0da2a9e-b0eb01d0.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-66da90e2.js → erDiagram-9861fffd-17586500.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-10044f05.js → flowDb-956e92f1-be2a1776.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-f338f66a.js → flowDiagram-66a62f08-c2120ebd.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-efbbfe00.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-b13140aa.js → flowchart-elk-definition-4a651766-a6ab5c48.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-f2b4a55a.js → ganttDiagram-c361ad54-ef613457.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-dedc298d.js → gitGraphDiagram-72cf32ee-d59185b3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-4ede11ff.js → graph-0f155405.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-65549d37.js → index-3862675e-d5f1d1b7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3a23e736.js → index-47737d3a.js} +123 -123
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-65439671.js → infoDiagram-f8f76790-b07d141f.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-56d03d98.js → journeyDiagram-49397b02-1936d429.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-dd48f7f4.js → layout-dde8d0f3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-1569ad2c.js → line-0c2c7ee0.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-48bf4935.js → linear-35dd89a4.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-688504c1.js → mindmap-definition-fc14e90a-56192851.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-78b6d7e6.js → pieDiagram-8a3498a8-fc21ed78.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-048b84b3.js → quadrantDiagram-120e2f19-25e98518.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-dd67f107.js → requirementDiagram-deff3bca-546ff1f5.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-8128436e.js → sankeyDiagram-04a897e0-02d8b82d.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-1a0d1461.js → sequenceDiagram-704730f1-3ca5a92e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-46d388ed.js → stateDiagram-587899a1-128ea07c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-ea42951a.js → stateDiagram-v2-d93cdb3a-95f290af.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-7427ed0c.js → styles-6aaf32cf-4984898a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-ff5e5a16.js → styles-9a916d00-1bf266ba.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-7b3680cf.js → styles-c10674c1-60521c63.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-f860f2ad.js → svgDrawCommon-08f97a94-a25b6e12.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-2eebf0c8.js → timeline-definition-85554ec2-0fc086bf.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-5d7f4e96.js → xychartDiagram-e933f94c-44ee592e.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/package.json +3 -1
- rasa/core/channels/inspector/src/App.tsx +91 -90
- rasa/core/channels/inspector/src/components/Chat.tsx +45 -41
- rasa/core/channels/inspector/src/components/DiagramFlow.tsx +40 -40
- rasa/core/channels/inspector/src/components/DialogueInformation.tsx +57 -57
- rasa/core/channels/inspector/src/components/DialogueStack.tsx +36 -27
- rasa/core/channels/inspector/src/components/ExpandIcon.tsx +4 -4
- rasa/core/channels/inspector/src/components/FullscreenButton.tsx +7 -7
- rasa/core/channels/inspector/src/components/LoadingSpinner.tsx +28 -12
- rasa/core/channels/inspector/src/components/NoActiveFlow.tsx +9 -9
- rasa/core/channels/inspector/src/components/RasaLogo.tsx +5 -5
- rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +55 -60
- rasa/core/channels/inspector/src/components/SaraDiagrams.tsx +5 -5
- rasa/core/channels/inspector/src/components/Slots.tsx +22 -22
- rasa/core/channels/inspector/src/components/Welcome.tsx +28 -31
- rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +245 -0
- rasa/core/channels/inspector/src/helpers/audio/microphone-processor.js +12 -0
- rasa/core/channels/inspector/src/helpers/audio/playback-processor.js +36 -0
- rasa/core/channels/inspector/src/helpers/conversation.ts +7 -7
- rasa/core/channels/inspector/src/helpers/formatters.test.ts +181 -181
- rasa/core/channels/inspector/src/helpers/formatters.ts +111 -111
- rasa/core/channels/inspector/src/helpers/utils.ts +78 -61
- rasa/core/channels/inspector/src/main.tsx +8 -8
- rasa/core/channels/inspector/src/theme/Button/Button.ts +8 -8
- rasa/core/channels/inspector/src/theme/Heading/Heading.ts +7 -7
- rasa/core/channels/inspector/src/theme/Input/Input.ts +9 -9
- rasa/core/channels/inspector/src/theme/Link/Link.ts +6 -6
- rasa/core/channels/inspector/src/theme/Modal/Modal.ts +13 -13
- rasa/core/channels/inspector/src/theme/Table/Table.tsx +10 -10
- rasa/core/channels/inspector/src/theme/Tooltip/Tooltip.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/breakpoints.ts +7 -7
- rasa/core/channels/inspector/src/theme/base/colors.ts +64 -64
- rasa/core/channels/inspector/src/theme/base/fonts/fontFaces.css +21 -18
- rasa/core/channels/inspector/src/theme/base/radii.ts +8 -8
- rasa/core/channels/inspector/src/theme/base/shadows.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/sizes.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/space.ts +12 -12
- rasa/core/channels/inspector/src/theme/base/styles.ts +5 -5
- rasa/core/channels/inspector/src/theme/base/typography.ts +12 -12
- rasa/core/channels/inspector/src/theme/base/zIndices.ts +3 -3
- rasa/core/channels/inspector/src/theme/index.ts +38 -38
- rasa/core/channels/inspector/src/types.ts +56 -50
- rasa/core/channels/inspector/yarn.lock +5 -0
- rasa/core/channels/mattermost.py +1 -1
- rasa/core/channels/rasa_chat.py +2 -4
- rasa/core/channels/rest.py +5 -4
- rasa/core/channels/studio_chat.py +3 -2
- rasa/core/channels/vier_cvg.py +1 -2
- rasa/core/channels/voice_ready/audiocodes.py +35 -25
- rasa/core/channels/voice_stream/audiocodes.py +7 -4
- rasa/core/channels/voice_stream/genesys.py +2 -2
- rasa/core/channels/voice_stream/twilio_media_streams.py +10 -5
- rasa/core/channels/voice_stream/voice_channel.py +33 -22
- rasa/core/evaluation/marker_tracker_loader.py +1 -1
- rasa/core/exporter.py +1 -1
- rasa/core/http_interpreter.py +3 -7
- rasa/core/jobs.py +2 -1
- rasa/core/nlg/contextual_response_rephraser.py +38 -11
- rasa/core/nlg/generator.py +0 -1
- rasa/core/nlg/interpolator.py +2 -3
- rasa/core/nlg/summarize.py +40 -6
- rasa/core/persistor.py +55 -20
- rasa/core/policies/enterprise_search_policy.py +290 -66
- rasa/core/policies/enterprise_search_prompt_with_relevancy_check_and_citation_template.jinja2 +63 -0
- rasa/core/policies/flow_policy.py +1 -1
- rasa/core/policies/flows/flow_executor.py +96 -17
- rasa/core/policies/intentless_policy.py +24 -16
- rasa/core/processor.py +106 -53
- rasa/core/run.py +40 -13
- rasa/core/tracker_stores/__init__.py +0 -0
- rasa/core/{auth_retry_tracker_store.py → tracker_stores/auth_retry_tracker_store.py} +5 -1
- rasa/core/tracker_stores/dynamo_tracker_store.py +218 -0
- rasa/core/tracker_stores/mongo_tracker_store.py +206 -0
- rasa/core/tracker_stores/redis_tracker_store.py +219 -0
- rasa/core/tracker_stores/sql_tracker_store.py +555 -0
- rasa/core/tracker_stores/tracker_store.py +805 -0
- rasa/core/training/interactive.py +1 -1
- rasa/core/utils.py +24 -91
- rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -1
- rasa/dialogue_understanding/coexistence/llm_based_router.py +8 -3
- rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -0
- rasa/dialogue_understanding/commands/cancel_flow_command.py +2 -0
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -0
- rasa/dialogue_understanding/commands/clarify_command.py +6 -2
- rasa/dialogue_understanding/commands/command_syntax_manager.py +1 -0
- rasa/dialogue_understanding/commands/human_handoff_command.py +2 -0
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +2 -0
- rasa/dialogue_understanding/commands/repeat_bot_messages_command.py +2 -0
- rasa/dialogue_understanding/commands/set_slot_command.py +11 -1
- rasa/dialogue_understanding/commands/skip_question_command.py +2 -0
- rasa/dialogue_understanding/commands/start_flow_command.py +4 -0
- rasa/dialogue_understanding/commands/utils.py +26 -2
- rasa/dialogue_understanding/generator/__init__.py +7 -1
- rasa/dialogue_understanding/generator/command_generator.py +4 -2
- rasa/dialogue_understanding/generator/command_parser.py +2 -2
- rasa/dialogue_understanding/generator/command_parser_validator.py +63 -0
- rasa/dialogue_understanding/generator/constants.py +2 -2
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +1 -1
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +78 -0
- rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +28 -463
- rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +147 -0
- rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +477 -0
- rasa/dialogue_understanding/generator/single_step/single_step_llm_command_generator.py +8 -58
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +37 -25
- rasa/dialogue_understanding/patterns/domain_for_patterns.py +190 -0
- rasa/dialogue_understanding/processor/command_processor.py +3 -3
- rasa/dialogue_understanding/processor/command_processor_component.py +3 -3
- rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +17 -4
- rasa/dialogue_understanding/utils.py +68 -12
- rasa/dialogue_understanding_test/du_test_case.py +1 -1
- rasa/dialogue_understanding_test/du_test_runner.py +4 -22
- rasa/dialogue_understanding_test/test_case_simulation/test_case_tracker_simulator.py +2 -6
- rasa/e2e_test/e2e_test_runner.py +1 -1
- rasa/engine/constants.py +1 -1
- rasa/engine/recipes/default_recipe.py +26 -2
- rasa/engine/validation.py +3 -2
- rasa/hooks.py +2 -30
- rasa/keys +1 -0
- rasa/llm_fine_tuning/annotation_module.py +39 -9
- rasa/llm_fine_tuning/conversations.py +3 -0
- rasa/llm_fine_tuning/llm_data_preparation_module.py +66 -49
- rasa/llm_fine_tuning/paraphrasing/conversation_rephraser.py +4 -2
- rasa/llm_fine_tuning/paraphrasing/rephrase_validator.py +52 -44
- rasa/llm_fine_tuning/paraphrasing_module.py +10 -12
- rasa/llm_fine_tuning/storage.py +4 -4
- rasa/llm_fine_tuning/utils.py +63 -1
- rasa/model_manager/config.py +3 -1
- rasa/model_manager/model_api.py +89 -2
- rasa/model_manager/runner_service.py +8 -4
- rasa/model_manager/trainer_service.py +5 -4
- rasa/model_training.py +12 -3
- rasa/nlu/extractors/crf_entity_extractor.py +66 -16
- rasa/plugin.py +2 -12
- rasa/privacy/__init__.py +0 -0
- rasa/privacy/constants.py +83 -0
- rasa/privacy/event_broker_utils.py +77 -0
- rasa/privacy/privacy_config.py +281 -0
- rasa/privacy/privacy_config_schema.json +86 -0
- rasa/privacy/privacy_filter.py +340 -0
- rasa/privacy/privacy_manager.py +576 -0
- rasa/server.py +29 -4
- rasa/shared/constants.py +6 -0
- rasa/shared/core/constants.py +4 -3
- rasa/shared/core/domain.py +7 -0
- rasa/shared/core/events.py +99 -3
- rasa/shared/core/flows/flow.py +1 -2
- rasa/shared/core/flows/flows_yaml_schema.json +3 -0
- rasa/shared/core/flows/steps/collect.py +46 -2
- rasa/shared/core/slots.py +28 -0
- rasa/shared/exceptions.py +4 -0
- rasa/shared/providers/_configs/azure_openai_client_config.py +4 -0
- rasa/shared/providers/_configs/openai_client_config.py +4 -0
- rasa/shared/providers/embedding/_base_litellm_embedding_client.py +3 -0
- rasa/shared/providers/llm/_base_litellm_client.py +5 -2
- rasa/shared/utils/llm.py +161 -6
- rasa/shared/utils/yaml.py +32 -0
- rasa/studio/data_handler.py +3 -3
- rasa/studio/download/download.py +37 -60
- rasa/studio/download/flows.py +23 -31
- rasa/studio/link.py +200 -0
- rasa/studio/pull.py +94 -0
- rasa/studio/push.py +131 -0
- rasa/studio/upload.py +117 -67
- rasa/telemetry.py +84 -27
- rasa/tracing/config.py +4 -5
- rasa/tracing/constants.py +19 -1
- rasa/tracing/instrumentation/attribute_extractors.py +11 -3
- rasa/tracing/instrumentation/instrumentation.py +54 -3
- rasa/tracing/instrumentation/metrics.py +98 -15
- rasa/tracing/metric_instrument_provider.py +75 -3
- rasa/utils/common.py +1 -27
- rasa/utils/licensing.py +1 -2
- rasa/utils/log_utils.py +1 -45
- rasa/validator.py +2 -8
- rasa/version.py +1 -1
- {rasa_pro-3.13.0.dev5.dist-info → rasa_pro-3.13.0.dev8.dist-info}/METADATA +8 -9
- {rasa_pro-3.13.0.dev5.dist-info → rasa_pro-3.13.0.dev8.dist-info}/RECORD +254 -231
- rasa/anonymization/__init__.py +0 -2
- rasa/anonymization/anonymisation_rule_yaml_reader.py +0 -91
- rasa/anonymization/anonymization_pipeline.py +0 -286
- rasa/anonymization/anonymization_rule_executor.py +0 -266
- rasa/anonymization/anonymization_rule_orchestrator.py +0 -119
- rasa/anonymization/schemas/config.yml +0 -47
- rasa/anonymization/utils.py +0 -118
- rasa/core/channels/inspector/dist/assets/channel-dfa68278.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-edb7f119.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-65e7c670.js +0 -1
- rasa/core/channels/inspector/src/helpers/audiostream.ts +0 -191
- rasa/core/tracker_store.py +0 -1792
- {rasa_pro-3.13.0.dev5.dist-info → rasa_pro-3.13.0.dev8.dist-info}/NOTICE +0 -0
- {rasa_pro-3.13.0.dev5.dist-info → rasa_pro-3.13.0.dev8.dist-info}/WHEEL +0 -0
- {rasa_pro-3.13.0.dev5.dist-info → rasa_pro-3.13.0.dev8.dist-info}/entry_points.txt +0 -0
rasa/shared/utils/llm.py
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import importlib.resources
|
|
2
4
|
import json
|
|
3
5
|
import logging
|
|
4
6
|
from copy import deepcopy
|
|
7
|
+
from datetime import datetime
|
|
5
8
|
from functools import wraps
|
|
6
9
|
from typing import (
|
|
7
10
|
TYPE_CHECKING,
|
|
8
11
|
Any,
|
|
9
12
|
Callable,
|
|
10
13
|
Dict,
|
|
14
|
+
List,
|
|
11
15
|
Literal,
|
|
12
16
|
Optional,
|
|
13
17
|
Text,
|
|
@@ -18,14 +22,20 @@ from typing import (
|
|
|
18
22
|
)
|
|
19
23
|
|
|
20
24
|
import structlog
|
|
25
|
+
from pydantic import BaseModel, Field
|
|
21
26
|
|
|
22
27
|
import rasa.shared.utils.io
|
|
23
|
-
from rasa.core.
|
|
28
|
+
from rasa.core.available_endpoints import AvailableEndpoints
|
|
24
29
|
from rasa.shared.constants import (
|
|
30
|
+
CONFIG_NAME_KEY,
|
|
31
|
+
CONFIG_PIPELINE_KEY,
|
|
32
|
+
CONFIG_POLICIES_KEY,
|
|
25
33
|
DEFAULT_PROMPT_PACKAGE_NAME,
|
|
34
|
+
LLM_CONFIG_KEY,
|
|
26
35
|
MODEL_CONFIG_KEY,
|
|
27
36
|
MODEL_GROUP_CONFIG_KEY,
|
|
28
37
|
MODEL_GROUP_ID_CONFIG_KEY,
|
|
38
|
+
MODEL_GROUPS_CONFIG_KEY,
|
|
29
39
|
MODELS_CONFIG_KEY,
|
|
30
40
|
PROVIDER_CONFIG_KEY,
|
|
31
41
|
RASA_PATTERN_INTERNAL_ERROR_USER_INPUT_EMPTY,
|
|
@@ -61,9 +71,11 @@ from rasa.shared.providers.mappings import (
|
|
|
61
71
|
get_embedding_client_from_provider,
|
|
62
72
|
get_llm_client_from_provider,
|
|
63
73
|
)
|
|
74
|
+
from rasa.shared.utils.common import all_subclasses
|
|
64
75
|
from rasa.shared.utils.constants import LOG_COMPONENT_SOURCE_METHOD_INIT
|
|
65
76
|
|
|
66
77
|
if TYPE_CHECKING:
|
|
78
|
+
from rasa.core.agent import Agent
|
|
67
79
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
68
80
|
|
|
69
81
|
|
|
@@ -107,6 +119,18 @@ _CombineConfigs_F = TypeVar(
|
|
|
107
119
|
)
|
|
108
120
|
|
|
109
121
|
|
|
122
|
+
class SystemPrompts(BaseModel):
|
|
123
|
+
command_generator: str = Field(
|
|
124
|
+
..., description="Prompt used by the LLM command generator."
|
|
125
|
+
)
|
|
126
|
+
enterprise_search: str = Field(
|
|
127
|
+
..., description="Prompt for standard enterprise search requests."
|
|
128
|
+
)
|
|
129
|
+
contextual_response_rephraser: str = Field(
|
|
130
|
+
..., description="Prompt used for re-phrasing assistant responses."
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
|
|
110
134
|
def _compute_hash_for_cache_from_configs(
|
|
111
135
|
config_x: Dict[str, Any], config_y: Dict[str, Any]
|
|
112
136
|
) -> int:
|
|
@@ -191,6 +215,7 @@ def tracker_as_readable_transcript(
|
|
|
191
215
|
human_prefix: str = USER,
|
|
192
216
|
ai_prefix: str = AI,
|
|
193
217
|
max_turns: Optional[int] = 20,
|
|
218
|
+
turns_wrapper: Optional[Callable[[List[str]], List[str]]] = None,
|
|
194
219
|
) -> str:
|
|
195
220
|
"""Creates a readable dialogue from a tracker.
|
|
196
221
|
|
|
@@ -199,6 +224,7 @@ def tracker_as_readable_transcript(
|
|
|
199
224
|
human_prefix: the prefix to use for human utterances
|
|
200
225
|
ai_prefix: the prefix to use for ai utterances
|
|
201
226
|
max_turns: the maximum number of turns to include in the transcript
|
|
227
|
+
turns_wrapper: optional function to wrap the turns in a custom way
|
|
202
228
|
|
|
203
229
|
Example:
|
|
204
230
|
>>> tracker = Tracker(
|
|
@@ -235,8 +261,11 @@ def tracker_as_readable_transcript(
|
|
|
235
261
|
elif isinstance(event, BotUttered):
|
|
236
262
|
transcript.append(f"{ai_prefix}: {sanitize_message_for_prompt(event.text)}")
|
|
237
263
|
|
|
238
|
-
|
|
239
|
-
|
|
264
|
+
# turns_wrapper to count multiple utterances by bot/user as single turn
|
|
265
|
+
if turns_wrapper:
|
|
266
|
+
transcript = turns_wrapper(transcript)
|
|
267
|
+
# otherwise, just take the last `max_turns` lines of the transcript
|
|
268
|
+
transcript = transcript[-max_turns if max_turns is not None else None :]
|
|
240
269
|
|
|
241
270
|
return "\n".join(transcript)
|
|
242
271
|
|
|
@@ -678,7 +707,6 @@ def get_prompt_template(
|
|
|
678
707
|
Returns:
|
|
679
708
|
The prompt template.
|
|
680
709
|
"""
|
|
681
|
-
|
|
682
710
|
try:
|
|
683
711
|
if jinja_file_path is not None:
|
|
684
712
|
prompt_template = rasa.shared.utils.io.read_file(jinja_file_path)
|
|
@@ -814,7 +842,9 @@ def allowed_values_for_slot(slot: Slot) -> Union[str, None]:
|
|
|
814
842
|
|
|
815
843
|
|
|
816
844
|
def resolve_model_client_config(
|
|
817
|
-
model_config: Optional[Dict[str, Any]],
|
|
845
|
+
model_config: Optional[Dict[str, Any]],
|
|
846
|
+
component_name: Optional[str] = None,
|
|
847
|
+
model_groups: Optional[List[Dict[str, Any]]] = None,
|
|
818
848
|
) -> Optional[Dict[str, Any]]:
|
|
819
849
|
"""Resolve the model group in the model config.
|
|
820
850
|
|
|
@@ -828,6 +858,7 @@ def resolve_model_client_config(
|
|
|
828
858
|
model_config: The model config to be resolved.
|
|
829
859
|
component_name: The name of the component.
|
|
830
860
|
component_name: The method of the component.
|
|
861
|
+
model_groups: Model groups from endpoints.yml.
|
|
831
862
|
|
|
832
863
|
Returns:
|
|
833
864
|
The resolved llm config.
|
|
@@ -854,7 +885,12 @@ def resolve_model_client_config(
|
|
|
854
885
|
|
|
855
886
|
model_group_id = model_config.get(MODEL_GROUP_CONFIG_KEY)
|
|
856
887
|
|
|
857
|
-
|
|
888
|
+
# If `model_groups` is provided, use it to initialise `AvailableEndpoints`,
|
|
889
|
+
# since `get_instance()` reads from the local endpoints file instead.
|
|
890
|
+
if model_groups:
|
|
891
|
+
endpoints = AvailableEndpoints(model_groups=model_groups)
|
|
892
|
+
else:
|
|
893
|
+
endpoints = AvailableEndpoints.get_instance()
|
|
858
894
|
if endpoints.model_groups is None:
|
|
859
895
|
_raise_invalid_config_exception(
|
|
860
896
|
reason=(
|
|
@@ -886,3 +922,122 @@ def resolve_model_client_config(
|
|
|
886
922
|
)
|
|
887
923
|
|
|
888
924
|
return model_group[0]
|
|
925
|
+
|
|
926
|
+
|
|
927
|
+
def generate_sender_id(test_case_name: str) -> str:
|
|
928
|
+
# add timestamp suffix to ensure sender_id is unique
|
|
929
|
+
return f"{test_case_name}_{datetime.now()}"
|
|
930
|
+
|
|
931
|
+
|
|
932
|
+
async def create_tracker_for_user_step(
|
|
933
|
+
step_sender_id: str,
|
|
934
|
+
agent: "Agent",
|
|
935
|
+
test_case_tracker: "DialogueStateTracker",
|
|
936
|
+
index_user_uttered_event: int,
|
|
937
|
+
) -> None:
|
|
938
|
+
"""Creates a tracker for the user step."""
|
|
939
|
+
tracker = test_case_tracker.copy()
|
|
940
|
+
# modify the sender id so that the original tracker is not overwritten
|
|
941
|
+
tracker.sender_id = step_sender_id
|
|
942
|
+
|
|
943
|
+
if tracker.events:
|
|
944
|
+
# get the timestamp of the event just before the user uttered event
|
|
945
|
+
timestamp = tracker.events[index_user_uttered_event - 1].timestamp
|
|
946
|
+
# revert the tracker to the event just before the user uttered event
|
|
947
|
+
tracker = tracker.travel_back_in_time(timestamp)
|
|
948
|
+
|
|
949
|
+
# store the tracker with the unique sender id
|
|
950
|
+
await agent.tracker_store.save(tracker)
|
|
951
|
+
|
|
952
|
+
|
|
953
|
+
def _get_llm_command_generator_config(
|
|
954
|
+
config: Dict[Text, Any],
|
|
955
|
+
) -> Optional[Dict[Text, Any]]:
|
|
956
|
+
"""Get the llm command generator config from config.yml.
|
|
957
|
+
|
|
958
|
+
Args:
|
|
959
|
+
config: The config.yml file data.
|
|
960
|
+
|
|
961
|
+
Returns:
|
|
962
|
+
The llm command generator config.
|
|
963
|
+
"""
|
|
964
|
+
from rasa.dialogue_understanding.generator import LLMBasedCommandGenerator
|
|
965
|
+
|
|
966
|
+
# Collect all LLM based Command Generator class names.
|
|
967
|
+
command_generator_subclasses = all_subclasses(LLMBasedCommandGenerator)
|
|
968
|
+
command_generator_class_names = [
|
|
969
|
+
command_generator.__name__ for command_generator in command_generator_subclasses
|
|
970
|
+
]
|
|
971
|
+
|
|
972
|
+
# Read the LLM config of the Command Generator from the config.yml file.
|
|
973
|
+
pipelines = config.get(CONFIG_PIPELINE_KEY, [])
|
|
974
|
+
for pipeline in pipelines:
|
|
975
|
+
if pipeline.get(CONFIG_NAME_KEY) in command_generator_class_names:
|
|
976
|
+
return pipeline.get(LLM_CONFIG_KEY)
|
|
977
|
+
|
|
978
|
+
return None
|
|
979
|
+
|
|
980
|
+
|
|
981
|
+
def _get_command_generator_prompt(
|
|
982
|
+
config: Dict[Text, Any], endpoints: Dict[Text, Any]
|
|
983
|
+
) -> Text:
|
|
984
|
+
"""Get the command generator prompt based on the config."""
|
|
985
|
+
from rasa.dialogue_understanding.generator.single_step.compact_llm_command_generator import ( # noqa: E501
|
|
986
|
+
DEFAULT_COMMAND_PROMPT_TEMPLATE_FILE_NAME,
|
|
987
|
+
FALLBACK_COMMAND_PROMPT_TEMPLATE_FILE_NAME,
|
|
988
|
+
MODEL_PROMPT_MAPPER,
|
|
989
|
+
)
|
|
990
|
+
|
|
991
|
+
model_config = _get_llm_command_generator_config(config)
|
|
992
|
+
llm_config = resolve_model_client_config(
|
|
993
|
+
model_config=model_config,
|
|
994
|
+
model_groups=endpoints.get(MODEL_GROUPS_CONFIG_KEY),
|
|
995
|
+
)
|
|
996
|
+
return get_default_prompt_template_based_on_model(
|
|
997
|
+
llm_config=llm_config,
|
|
998
|
+
model_prompt_mapping=MODEL_PROMPT_MAPPER,
|
|
999
|
+
default_prompt_path=DEFAULT_COMMAND_PROMPT_TEMPLATE_FILE_NAME,
|
|
1000
|
+
fallback_prompt_path=FALLBACK_COMMAND_PROMPT_TEMPLATE_FILE_NAME,
|
|
1001
|
+
)
|
|
1002
|
+
|
|
1003
|
+
|
|
1004
|
+
def _get_enterprise_search_prompt(config: Dict[Text, Any]) -> Text:
|
|
1005
|
+
"""Get the enterprise search prompt based on the config."""
|
|
1006
|
+
from rasa.core.policies.enterprise_search_policy import EnterpriseSearchPolicy
|
|
1007
|
+
|
|
1008
|
+
def get_enterprise_search_config() -> Dict[Text, Any]:
|
|
1009
|
+
policies = config.get(CONFIG_POLICIES_KEY, [])
|
|
1010
|
+
for policy in policies:
|
|
1011
|
+
if policy.get(CONFIG_NAME_KEY) == EnterpriseSearchPolicy.__name__:
|
|
1012
|
+
return policy
|
|
1013
|
+
|
|
1014
|
+
return {}
|
|
1015
|
+
|
|
1016
|
+
enterprise_search_config = get_enterprise_search_config()
|
|
1017
|
+
return EnterpriseSearchPolicy.get_system_default_prompt_based_on_config(
|
|
1018
|
+
enterprise_search_config
|
|
1019
|
+
)
|
|
1020
|
+
|
|
1021
|
+
|
|
1022
|
+
def get_system_default_prompts(
|
|
1023
|
+
config: Dict[Text, Any], endpoints: Dict[Text, Any]
|
|
1024
|
+
) -> SystemPrompts:
|
|
1025
|
+
"""
|
|
1026
|
+
Returns the system default prompts for the component.
|
|
1027
|
+
|
|
1028
|
+
Args:
|
|
1029
|
+
config: The config.yml file data.
|
|
1030
|
+
endpoints: The endpoints.yml file data.
|
|
1031
|
+
|
|
1032
|
+
Returns:
|
|
1033
|
+
SystemPrompts: A Pydantic model containing all default prompts.
|
|
1034
|
+
"""
|
|
1035
|
+
from rasa.core.nlg.contextual_response_rephraser import (
|
|
1036
|
+
DEFAULT_RESPONSE_VARIATION_PROMPT_TEMPLATE,
|
|
1037
|
+
)
|
|
1038
|
+
|
|
1039
|
+
return SystemPrompts(
|
|
1040
|
+
command_generator=_get_command_generator_prompt(config, endpoints),
|
|
1041
|
+
enterprise_search=_get_enterprise_search_prompt(config),
|
|
1042
|
+
contextual_response_rephraser=DEFAULT_RESPONSE_VARIATION_PROMPT_TEMPLATE,
|
|
1043
|
+
)
|
rasa/shared/utils/yaml.py
CHANGED
|
@@ -21,6 +21,7 @@ from ruamel.yaml import YAML, RoundTripRepresenter, YAMLError
|
|
|
21
21
|
from ruamel.yaml.comments import CommentedMap, CommentedSeq
|
|
22
22
|
from ruamel.yaml.constructor import BaseConstructor, DuplicateKeyError, ScalarNode
|
|
23
23
|
from ruamel.yaml.loader import SafeLoader
|
|
24
|
+
from ruamel.yaml.scalarstring import LiteralScalarString
|
|
24
25
|
|
|
25
26
|
from rasa.shared.constants import (
|
|
26
27
|
ASSERTIONS_SCHEMA_EXTENSIONS_FILE,
|
|
@@ -794,6 +795,25 @@ def write_yaml(
|
|
|
794
795
|
should_preserve_key_order: Whether to force preserve key order in `data`.
|
|
795
796
|
transform: A function to transform the data before writing it to the file.
|
|
796
797
|
"""
|
|
798
|
+
|
|
799
|
+
def multiline_str_representer(self: Any, value: str) -> Any:
|
|
800
|
+
"""Dump multi-line strings as readable YAML block scalars where possible."""
|
|
801
|
+
if "\n" in value:
|
|
802
|
+
# First line after the newline decides: paragraph vs. snippet
|
|
803
|
+
first_line = value.split("\n", 1)[1]
|
|
804
|
+
|
|
805
|
+
# If the first line after the newline is not indented, treat the value
|
|
806
|
+
# as plain text. Indented text is likely pre-formatted YAML/JSON/etc.
|
|
807
|
+
if not first_line.startswith((" ", "\t")):
|
|
808
|
+
return self.represent_scalar(
|
|
809
|
+
"tag:yaml.org,2002:str",
|
|
810
|
+
LiteralScalarString(value),
|
|
811
|
+
style="|",
|
|
812
|
+
)
|
|
813
|
+
|
|
814
|
+
# Fallback: keep default YAML scalar style (plain/quoted)
|
|
815
|
+
return self.represent_scalar("tag:yaml.org,2002:str", value)
|
|
816
|
+
|
|
797
817
|
_enable_ordered_dict_yaml_dumping()
|
|
798
818
|
|
|
799
819
|
if should_preserve_key_order:
|
|
@@ -808,6 +828,7 @@ def write_yaml(
|
|
|
808
828
|
type(None),
|
|
809
829
|
lambda self, _: self.represent_scalar("tag:yaml.org,2002:null", "null"),
|
|
810
830
|
)
|
|
831
|
+
dumper.representer.add_representer(str, multiline_str_representer)
|
|
811
832
|
|
|
812
833
|
if isinstance(target, StringIO):
|
|
813
834
|
dumper.dump(data, target, transform=transform)
|
|
@@ -1025,6 +1046,17 @@ def validate_yaml_with_jsonschema(
|
|
|
1025
1046
|
except (YAMLError, DuplicateKeyError) as e:
|
|
1026
1047
|
raise YamlSyntaxException(underlying_yaml_exception=e)
|
|
1027
1048
|
|
|
1049
|
+
validate_data_with_jsonschema(source_data, schema_content, humanize_error)
|
|
1050
|
+
|
|
1051
|
+
|
|
1052
|
+
def validate_data_with_jsonschema(
|
|
1053
|
+
source_data: Any,
|
|
1054
|
+
schema_content: Any,
|
|
1055
|
+
humanize_error: Callable[
|
|
1056
|
+
[jsonschema.ValidationError], str
|
|
1057
|
+
] = default_error_humanizer,
|
|
1058
|
+
) -> None:
|
|
1059
|
+
"""Validate Python object against the provided jsonschema content."""
|
|
1028
1060
|
try:
|
|
1029
1061
|
jsonschema.validate(source_data, schema_content)
|
|
1030
1062
|
except jsonschema.ValidationError as error:
|
rasa/studio/data_handler.py
CHANGED
|
@@ -320,14 +320,14 @@ def create_new_flows_from_diff(
|
|
|
320
320
|
|
|
321
321
|
|
|
322
322
|
def import_data_from_studio(
|
|
323
|
-
handler: StudioDataHandler, domain_path: Path,
|
|
323
|
+
handler: StudioDataHandler, domain_path: Path, data_path: Path
|
|
324
324
|
) -> Tuple[TrainingDataImporter, TrainingDataImporter]:
|
|
325
325
|
"""Construct TrainingDataImporter from Studio data and original data.
|
|
326
326
|
|
|
327
327
|
Args:
|
|
328
328
|
handler (StudioDataHandler): handler with data from studio
|
|
329
329
|
domain_path (Path): Path to a domain file
|
|
330
|
-
|
|
330
|
+
data_path (List[Path]): List of paths to training data files
|
|
331
331
|
|
|
332
332
|
Returns:
|
|
333
333
|
Tuple[TrainingDataImporter, TrainingDataImporter]:
|
|
@@ -335,7 +335,7 @@ def import_data_from_studio(
|
|
|
335
335
|
"""
|
|
336
336
|
tmp_dir = get_temp_dir_name()
|
|
337
337
|
data_original = TrainingDataImporter.load_from_dict(
|
|
338
|
-
domain_path=domain_path, training_data_paths=
|
|
338
|
+
domain_path=str(domain_path), training_data_paths=[str(data_path)]
|
|
339
339
|
)
|
|
340
340
|
|
|
341
341
|
data_paths = []
|
rasa/studio/download/download.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import argparse
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from typing import Dict,
|
|
3
|
+
from typing import Dict, Optional, Tuple
|
|
4
4
|
|
|
5
5
|
import questionary
|
|
6
6
|
import structlog
|
|
@@ -46,7 +46,7 @@ def handle_download(args: argparse.Namespace) -> None:
|
|
|
46
46
|
)
|
|
47
47
|
handler.request_all_data()
|
|
48
48
|
|
|
49
|
-
domain_path,
|
|
49
|
+
domain_path, data_path = _prepare_data_and_domain_paths(args)
|
|
50
50
|
|
|
51
51
|
# Handle config and endpoints.
|
|
52
52
|
config_path, write_config = _handle_file_overwrite(
|
|
@@ -78,12 +78,12 @@ def handle_download(args: argparse.Namespace) -> None:
|
|
|
78
78
|
structlogger.info("studio.download.config_endpoints", event_info=message)
|
|
79
79
|
|
|
80
80
|
if not args.overwrite:
|
|
81
|
-
_handle_download_no_overwrite(handler, domain_path,
|
|
81
|
+
_handle_download_no_overwrite(handler, domain_path, data_path)
|
|
82
82
|
else:
|
|
83
|
-
_handle_download_with_overwrite(handler, domain_path,
|
|
83
|
+
_handle_download_with_overwrite(handler, domain_path, data_path)
|
|
84
84
|
|
|
85
85
|
|
|
86
|
-
def _prepare_data_and_domain_paths(args: argparse.Namespace) -> Tuple[Path,
|
|
86
|
+
def _prepare_data_and_domain_paths(args: argparse.Namespace) -> Tuple[Path, Path]:
|
|
87
87
|
"""Prepars the domain and data paths based on the provided arguments.
|
|
88
88
|
|
|
89
89
|
Args:
|
|
@@ -115,28 +115,15 @@ def _prepare_data_and_domain_paths(args: argparse.Namespace) -> Tuple[Path, List
|
|
|
115
115
|
domain_path = domain_path / STUDIO_DOMAIN_FILENAME
|
|
116
116
|
domain_path.touch()
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
data_path = rasa.cli.utils.get_validated_path(
|
|
122
|
-
f, "data", DEFAULT_DATA_PATH, none_is_valid=True
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
if data_path is None:
|
|
126
|
-
data_path = Path(f)
|
|
127
|
-
data_path.mkdir(parents=True, exist_ok=True)
|
|
128
|
-
else:
|
|
129
|
-
data_path = Path(data_path)
|
|
118
|
+
data_path = rasa.cli.utils.get_validated_path(
|
|
119
|
+
args.data[0], "data", DEFAULT_DATA_PATH, none_is_valid=True
|
|
120
|
+
)
|
|
130
121
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
data_path.mkdir(parents=True, exist_ok=True)
|
|
135
|
-
data_paths.append(data_path)
|
|
122
|
+
data_path = Path(data_path or args.data[0])
|
|
123
|
+
if not (data_path.is_file() or data_path.is_dir()):
|
|
124
|
+
data_path.mkdir(parents=True, exist_ok=True)
|
|
136
125
|
|
|
137
|
-
|
|
138
|
-
data_paths = list(dict.fromkeys(data_paths))
|
|
139
|
-
return domain_path, data_paths
|
|
126
|
+
return domain_path, data_path
|
|
140
127
|
|
|
141
128
|
|
|
142
129
|
def _handle_file_overwrite(
|
|
@@ -177,7 +164,7 @@ def _handle_file_overwrite(
|
|
|
177
164
|
|
|
178
165
|
|
|
179
166
|
def _handle_download_no_overwrite(
|
|
180
|
-
handler: StudioDataHandler, domain_path: Path,
|
|
167
|
+
handler: StudioDataHandler, domain_path: Path, data_path: Path
|
|
181
168
|
) -> None:
|
|
182
169
|
"""Handles downloading without overwriting existing files.
|
|
183
170
|
|
|
@@ -187,10 +174,10 @@ def _handle_download_no_overwrite(
|
|
|
187
174
|
data_paths: The paths to the data files or directories.
|
|
188
175
|
"""
|
|
189
176
|
data_from_studio, data_local = import_data_from_studio(
|
|
190
|
-
handler, domain_path,
|
|
177
|
+
handler, domain_path, data_path
|
|
191
178
|
)
|
|
192
179
|
_merge_domain_no_overwrite(domain_path, data_from_studio, data_local)
|
|
193
|
-
_merge_data_no_overwrite(
|
|
180
|
+
_merge_data_no_overwrite(data_path, handler, data_from_studio, data_local)
|
|
194
181
|
|
|
195
182
|
|
|
196
183
|
def _merge_domain_no_overwrite(
|
|
@@ -264,7 +251,7 @@ def _merge_file_domain(
|
|
|
264
251
|
|
|
265
252
|
|
|
266
253
|
def _merge_data_no_overwrite(
|
|
267
|
-
|
|
254
|
+
data_path: Path,
|
|
268
255
|
handler: StudioDataHandler,
|
|
269
256
|
data_from_studio: TrainingDataImporter,
|
|
270
257
|
data_local: TrainingDataImporter,
|
|
@@ -272,38 +259,29 @@ def _merge_data_no_overwrite(
|
|
|
272
259
|
"""Merges NLU and flow data without overwriting existing data.
|
|
273
260
|
|
|
274
261
|
Args:
|
|
275
|
-
|
|
262
|
+
data_path: The paths to the data files or directories.
|
|
276
263
|
handler: The StudioDataHandler instance.
|
|
277
264
|
data_from_studio: The Studio data importer.
|
|
278
265
|
data_local: The local data importer.
|
|
279
266
|
"""
|
|
280
|
-
if not
|
|
267
|
+
if not data_path:
|
|
281
268
|
structlogger.warning(
|
|
282
269
|
"studio.download.merge_data_no_overwrite.no_path",
|
|
283
270
|
event_info="No data paths provided. Skipping data merge.",
|
|
284
271
|
)
|
|
285
272
|
return
|
|
286
273
|
|
|
287
|
-
if
|
|
288
|
-
data_path
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
data_path, handler, data_from_studio, data_local
|
|
292
|
-
)
|
|
293
|
-
elif data_path.is_dir():
|
|
294
|
-
_merge_dir_data_no_overwrite(
|
|
295
|
-
data_path, handler, data_from_studio, data_local
|
|
296
|
-
)
|
|
297
|
-
else:
|
|
298
|
-
structlogger.warning(
|
|
299
|
-
"studio.download.merge_data_no_overwrite.invalid_path",
|
|
300
|
-
event_info=(
|
|
301
|
-
f"Provided path '{data_path}' is neither a file nor a directory."
|
|
302
|
-
),
|
|
303
|
-
)
|
|
274
|
+
if data_path.is_file():
|
|
275
|
+
_merge_file_data_no_overwrite(data_path, handler, data_from_studio, data_local)
|
|
276
|
+
elif data_path.is_dir():
|
|
277
|
+
_merge_dir_data_no_overwrite(data_path, handler, data_from_studio, data_local)
|
|
304
278
|
else:
|
|
305
|
-
|
|
306
|
-
|
|
279
|
+
structlogger.warning(
|
|
280
|
+
"studio.download.merge_data_no_overwrite.invalid_path",
|
|
281
|
+
event_info=(
|
|
282
|
+
f"Provided path '{data_path}' is neither a file nor a directory."
|
|
283
|
+
),
|
|
284
|
+
)
|
|
307
285
|
|
|
308
286
|
|
|
309
287
|
def _merge_file_data_no_overwrite(
|
|
@@ -353,25 +331,23 @@ def _merge_dir_data_no_overwrite(
|
|
|
353
331
|
|
|
354
332
|
|
|
355
333
|
def _handle_download_with_overwrite(
|
|
356
|
-
handler: StudioDataHandler, domain_path: Path,
|
|
334
|
+
handler: StudioDataHandler, domain_path: Path, data_path: Path
|
|
357
335
|
) -> None:
|
|
358
336
|
"""Handles downloading and merging data when the user opts for overwrite.
|
|
359
337
|
|
|
360
338
|
Args:
|
|
361
339
|
handler: The StudioDataHandler instance.
|
|
362
340
|
domain_path: The path to the domain file or directory.
|
|
363
|
-
|
|
341
|
+
data_path: The paths to the data files or directories.
|
|
364
342
|
"""
|
|
365
343
|
data_from_studio, data_local = import_data_from_studio(
|
|
366
|
-
handler, domain_path,
|
|
344
|
+
handler, domain_path, data_path
|
|
367
345
|
)
|
|
368
346
|
mapper = RasaPrimitiveStorageMapper(
|
|
369
|
-
domain_path=domain_path, training_data_paths=
|
|
347
|
+
domain_path=domain_path, training_data_paths=[data_path]
|
|
370
348
|
)
|
|
371
349
|
merge_domain_with_overwrite(data_from_studio, data_local, domain_path)
|
|
372
|
-
merge_flows_with_overwrite(
|
|
373
|
-
data_paths, handler, data_from_studio, data_local, mapper
|
|
374
|
-
)
|
|
350
|
+
merge_flows_with_overwrite(data_path, handler, data_from_studio, data_local, mapper)
|
|
375
351
|
|
|
376
352
|
|
|
377
353
|
def _persist_nlu_diff(
|
|
@@ -432,8 +408,9 @@ def pretty_write_nlu_yaml(data: Dict, file: Path) -> None:
|
|
|
432
408
|
file: The file to write to.
|
|
433
409
|
"""
|
|
434
410
|
dumper = yaml.YAML()
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
item
|
|
411
|
+
if nlu_data := data.get("nlu"):
|
|
412
|
+
for item in nlu_data:
|
|
413
|
+
if item.get("examples"):
|
|
414
|
+
item["examples"] = LiteralScalarString(item["examples"])
|
|
438
415
|
with file.open("w", encoding="utf-8") as outfile:
|
|
439
416
|
dumper.dump(data, outfile)
|
rasa/studio/download/flows.py
CHANGED
|
@@ -18,7 +18,7 @@ STUDIO_FLOWS_DIR_NAME = "studio_flows"
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def merge_flows_with_overwrite(
|
|
21
|
-
|
|
21
|
+
data_path: Path,
|
|
22
22
|
handler: Any,
|
|
23
23
|
data_from_studio: TrainingDataImporter,
|
|
24
24
|
data_local: TrainingDataImporter,
|
|
@@ -28,17 +28,12 @@ def merge_flows_with_overwrite(
|
|
|
28
28
|
Merges flows data from a file or directory when overwrite is enabled.
|
|
29
29
|
|
|
30
30
|
Args:
|
|
31
|
-
|
|
31
|
+
data_path: List of paths to the training data.
|
|
32
32
|
handler: The StudioDataHandler instance.
|
|
33
33
|
data_from_studio: The TrainingDataImporter instance for Studio data.
|
|
34
34
|
data_local: The TrainingDataImporter instance for local data.
|
|
35
35
|
mapper: The RasaPrimitiveStorageMapper instance for mapping.
|
|
36
36
|
"""
|
|
37
|
-
if len(data_paths) != 1:
|
|
38
|
-
# TODO: Handle multiple data paths.
|
|
39
|
-
raise NotImplementedError("Multiple data paths are not supported yet.")
|
|
40
|
-
|
|
41
|
-
data_path = data_paths[0]
|
|
42
37
|
if data_path.is_file():
|
|
43
38
|
merge_training_data_file(handler, data_from_studio, data_local, data_path)
|
|
44
39
|
elif data_path.is_dir():
|
|
@@ -132,7 +127,8 @@ def merge_nlu_in_directory(
|
|
|
132
127
|
)
|
|
133
128
|
nlu_data = nlu_data.merge(local_nlu.get_nlu_data())
|
|
134
129
|
|
|
135
|
-
|
|
130
|
+
if nlu_yaml := nlu_data.nlu_as_yaml():
|
|
131
|
+
pretty_write_nlu_yaml(read_yaml(nlu_yaml), nlu_file_path)
|
|
136
132
|
|
|
137
133
|
|
|
138
134
|
def get_nlu_path(
|
|
@@ -211,14 +207,16 @@ def merge_flows_in_directory(
|
|
|
211
207
|
local_flow_paths: Set[Path] = _get_local_flow_paths(local_flows, mapper)
|
|
212
208
|
|
|
213
209
|
# Track updated flows and update local files with Studio flow data.
|
|
214
|
-
|
|
210
|
+
all_updated_flows_ids: List[Text] = []
|
|
215
211
|
for flow_file_path in local_flow_paths:
|
|
216
|
-
|
|
217
|
-
|
|
212
|
+
updated_flows_ids = _update_flow_file(flow_file_path, studio_flow_map)
|
|
213
|
+
all_updated_flows_ids.extend(updated_flows_ids)
|
|
218
214
|
|
|
219
215
|
# Identify new Studio flows and save them as separate files in the directory.
|
|
220
216
|
new_flows = [
|
|
221
|
-
flow
|
|
217
|
+
flow
|
|
218
|
+
for flow_id, flow in studio_flow_map.items()
|
|
219
|
+
if flow_id not in all_updated_flows_ids
|
|
222
220
|
]
|
|
223
221
|
_dump_flows_as_separate_files(new_flows, data_path)
|
|
224
222
|
|
|
@@ -243,7 +241,7 @@ def _get_local_flow_paths(
|
|
|
243
241
|
|
|
244
242
|
def _update_flow_file(
|
|
245
243
|
flow_file_path: Path, studio_flows_map: Dict[Text, Any]
|
|
246
|
-
) -> List[
|
|
244
|
+
) -> List[Text]:
|
|
247
245
|
"""
|
|
248
246
|
Reads a flow file, updates outdated flows, and replaces them with studio versions.
|
|
249
247
|
|
|
@@ -252,31 +250,25 @@ def _update_flow_file(
|
|
|
252
250
|
studio_flows_map: A dictionary mapping flow IDs to their updated versions.
|
|
253
251
|
|
|
254
252
|
Returns:
|
|
255
|
-
A list of
|
|
253
|
+
A list of Flows IDs from the updated flow file.
|
|
256
254
|
"""
|
|
257
255
|
file_flows = YAMLFlowsReader.read_from_file(flow_file_path, False)
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
updated_list.append(flow)
|
|
268
|
-
|
|
269
|
-
if has_changes:
|
|
270
|
-
new_flows_list = FlowsList(underlying_flows=updated_list)
|
|
271
|
-
new_flows_list = strip_default_next_references(new_flows_list)
|
|
256
|
+
|
|
257
|
+
# Build a list of flows, replacing any outdated flow with its studio version
|
|
258
|
+
updated_flows = [
|
|
259
|
+
studio_flows_map.get(flow.id, flow) or flow
|
|
260
|
+
for flow in file_flows.underlying_flows
|
|
261
|
+
]
|
|
262
|
+
|
|
263
|
+
# If the updated flows differ from the original file flows, write them back
|
|
264
|
+
if updated_flows != file_flows.underlying_flows:
|
|
272
265
|
YamlFlowsWriter.dump(
|
|
273
|
-
flows=
|
|
266
|
+
flows=updated_flows,
|
|
274
267
|
filename=flow_file_path,
|
|
275
268
|
should_clean_json=True,
|
|
276
269
|
)
|
|
277
|
-
return new_flows_list.underlying_flows
|
|
278
270
|
|
|
279
|
-
return
|
|
271
|
+
return [flow.id for flow in updated_flows]
|
|
280
272
|
|
|
281
273
|
|
|
282
274
|
def _dump_flows_as_separate_files(flows: List[Any], data_path: Path) -> None:
|