rasa-pro 3.13.0.dev7__py3-none-any.whl → 3.13.0.dev9__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 +1 -1
- rasa/cli/dialogue_understanding_test.py +1 -1
- rasa/cli/e2e_test.py +1 -1
- rasa/cli/evaluate.py +1 -1
- rasa/cli/export.py +1 -1
- 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 +1 -1
- rasa/cli/utils.py +1 -1
- rasa/cli/x.py +1 -1
- rasa/constants.py +2 -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 +16 -1
- rasa/core/available_endpoints.py +146 -0
- rasa/core/brokers/pika.py +1 -2
- rasa/core/channels/botframework.py +2 -2
- rasa/core/channels/channel.py +2 -2
- rasa/core/channels/development_inspector.py +1 -1
- rasa/core/channels/facebook.py +1 -4
- rasa/core/channels/hangouts.py +8 -5
- rasa/core/channels/inspector/README.md +3 -3
- rasa/core/channels/inspector/dist/assets/{arc-c4b064fc.js → arc-02053cc1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-215b5026.js → blockDiagram-38ab4fdb-008b6289.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-2b54a0a3.js → c4Diagram-3d4e48cf-fb2597be.js} +1 -1
- rasa/core/channels/inspector/dist/assets/channel-078dada8.js +1 -0
- rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-daacea5f.js → classDiagram-70f12bd4-7f847e00.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-930d4dc2.js → classDiagram-v2-f2320105-ba1d689b.js} +1 -1
- rasa/core/channels/inspector/dist/assets/clone-5b4516de.js +1 -0
- rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-83c206ba.js → createText-2e5e7dd3-dd8e67c4.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-b0eb01d0.js → edges-e0da2a9e-10784939.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-17586500.js → erDiagram-9861fffd-24947ae6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-be2a1776.js → flowDb-956e92f1-a9ced505.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-c2120ebd.js → flowDiagram-66a62f08-afda9c7c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-f9613071.js +1 -0
- rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-a6ab5c48.js → flowchart-elk-definition-4a651766-6ef530b8.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-ef613457.js → ganttDiagram-c361ad54-0c7dd39a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-d59185b3.js → gitGraphDiagram-72cf32ee-b57239d6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{graph-0f155405.js → graph-9ed57cec.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-3862675e-d5f1d1b7.js → index-3862675e-233090de.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{index-47737d3a.js → index-72184470.js} +3 -3
- rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-b07d141f.js → infoDiagram-f8f76790-aa116649.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-1936d429.js → journeyDiagram-49397b02-e51877cc.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{layout-dde8d0f3.js → layout-3ca3798c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{line-0c2c7ee0.js → line-26ee10d3.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{linear-35dd89a4.js → linear-aedded32.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-56192851.js → mindmap-definition-fc14e90a-d8957261.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-fc21ed78.js → pieDiagram-8a3498a8-d771f885.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-25e98518.js → quadrantDiagram-120e2f19-09fdf50c.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-546ff1f5.js → requirementDiagram-deff3bca-9f0af02e.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-02d8b82d.js → sankeyDiagram-04a897e0-84415b37.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-3ca5a92e.js → sequenceDiagram-704730f1-8dec4055.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-128ea07c.js → stateDiagram-587899a1-c5431d07.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-95f290af.js → stateDiagram-v2-d93cdb3a-274e77d9.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-4984898a.js → styles-6aaf32cf-e364a1d7.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-9a916d00-1bf266ba.js → styles-9a916d00-0dae36f6.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{styles-c10674c1-60521c63.js → styles-c10674c1-c4641675.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-a25b6e12.js → svgDrawCommon-08f97a94-831fe9a1.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-0fc086bf.js → timeline-definition-85554ec2-c3304b3a.js} +1 -1
- rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-44ee592e.js → xychartDiagram-e933f94c-da799369.js} +1 -1
- rasa/core/channels/inspector/dist/index.html +1 -1
- rasa/core/channels/inspector/src/components/RecruitmentPanel.tsx +1 -1
- 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/socketio.py +56 -41
- rasa/core/channels/studio_chat.py +314 -10
- rasa/core/channels/vier_cvg.py +1 -2
- rasa/core/channels/voice_ready/audiocodes.py +2 -9
- rasa/core/channels/voice_stream/audiocodes.py +8 -5
- rasa/core/channels/voice_stream/browser_audio.py +1 -1
- rasa/core/channels/voice_stream/genesys.py +2 -2
- rasa/core/channels/voice_stream/tts/__init__.py +8 -0
- rasa/core/channels/voice_stream/twilio_media_streams.py +10 -5
- rasa/core/channels/voice_stream/voice_channel.py +39 -23
- rasa/core/http_interpreter.py +3 -7
- rasa/core/information_retrieval/faiss.py +18 -11
- rasa/core/information_retrieval/ingestion/__init__.py +0 -0
- rasa/core/information_retrieval/ingestion/faq_parser.py +158 -0
- rasa/core/jobs.py +2 -1
- rasa/core/nlg/contextual_response_rephraser.py +44 -10
- rasa/core/nlg/generator.py +0 -1
- rasa/core/nlg/interpolator.py +2 -3
- rasa/core/nlg/summarize.py +39 -5
- rasa/core/policies/enterprise_search_policy.py +262 -62
- 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 +56 -17
- rasa/core/processor.py +104 -51
- rasa/core/run.py +33 -11
- rasa/core/tracker_stores/tracker_store.py +1 -1
- rasa/core/training/interactive.py +1 -1
- rasa/core/utils.py +24 -97
- rasa/dialogue_understanding/coexistence/intent_based_router.py +2 -1
- rasa/dialogue_understanding/coexistence/llm_based_router.py +9 -6
- rasa/dialogue_understanding/commands/can_not_handle_command.py +2 -0
- rasa/dialogue_understanding/commands/cancel_flow_command.py +5 -1
- rasa/dialogue_understanding/commands/chit_chat_answer_command.py +2 -0
- rasa/dialogue_understanding/commands/clarify_command.py +5 -1
- rasa/dialogue_understanding/commands/command_syntax_manager.py +1 -0
- rasa/dialogue_understanding/commands/correct_slots_command.py +1 -3
- rasa/dialogue_understanding/commands/human_handoff_command.py +2 -0
- rasa/dialogue_understanding/commands/knowledge_answer_command.py +4 -2
- 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/nlu_command_adapter.py +2 -2
- rasa/dialogue_understanding/generator/prompt_templates/command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +12 -33
- 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 +26 -461
- 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 +11 -64
- rasa/dialogue_understanding/patterns/cancel.py +1 -2
- rasa/dialogue_understanding/patterns/clarify.py +1 -1
- rasa/dialogue_understanding/patterns/correction.py +2 -2
- 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 +6 -7
- rasa/dialogue_understanding/processor/command_processor_component.py +3 -3
- rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +17 -4
- rasa/dialogue_understanding/stack/utils.py +3 -1
- 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/graph.py +2 -2
- rasa/engine/recipes/default_recipe.py +26 -2
- rasa/engine/validation.py +3 -2
- rasa/hooks.py +0 -28
- 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 +1 -5
- 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/model_api.py +88 -0
- rasa/model_manager/trainer_service.py +4 -4
- rasa/plugin.py +1 -11
- 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 +23 -2
- rasa/shared/constants.py +14 -0
- rasa/shared/core/command_payload_reader.py +1 -5
- rasa/shared/core/constants.py +4 -3
- rasa/shared/core/domain.py +7 -0
- rasa/shared/core/events.py +38 -10
- 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/flows/validation.py +16 -3
- rasa/shared/core/slots.py +28 -0
- rasa/shared/core/training_data/story_reader/yaml_story_reader.py +1 -4
- rasa/shared/exceptions.py +4 -0
- rasa/shared/utils/common.py +1 -1
- rasa/shared/utils/llm.py +191 -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 +82 -25
- rasa/tracing/config.py +3 -4
- rasa/tracing/constants.py +19 -1
- rasa/tracing/instrumentation/attribute_extractors.py +10 -2
- rasa/tracing/instrumentation/instrumentation.py +53 -2
- rasa/tracing/instrumentation/metrics.py +98 -15
- rasa/tracing/metric_instrument_provider.py +75 -3
- rasa/utils/common.py +1 -27
- rasa/utils/log_utils.py +1 -45
- rasa/validator.py +2 -8
- rasa/version.py +1 -1
- {rasa_pro-3.13.0.dev7.dist-info → rasa_pro-3.13.0.dev9.dist-info}/METADATA +7 -8
- {rasa_pro-3.13.0.dev7.dist-info → rasa_pro-3.13.0.dev9.dist-info}/RECORD +205 -189
- 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-3730f5fd.js +0 -1
- rasa/core/channels/inspector/dist/assets/clone-e847561e.js +0 -1
- rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-efbbfe00.js +0 -1
- {rasa_pro-3.13.0.dev7.dist-info → rasa_pro-3.13.0.dev9.dist-info}/NOTICE +0 -0
- {rasa_pro-3.13.0.dev7.dist-info → rasa_pro-3.13.0.dev9.dist-info}/WHEEL +0 -0
- {rasa_pro-3.13.0.dev7.dist-info → rasa_pro-3.13.0.dev9.dist-info}/entry_points.txt +0 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from contextlib import contextmanager
|
|
2
2
|
from typing import Any, Dict, Generator, List, Optional, Text
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
import structlog
|
|
5
|
+
|
|
6
|
+
from rasa.dialogue_understanding.commands import Command, NoopCommand, SetSlotCommand
|
|
5
7
|
from rasa.dialogue_understanding.constants import (
|
|
6
8
|
RASA_RECORD_COMMANDS_AND_PROMPTS_ENV_VAR_NAME,
|
|
7
9
|
)
|
|
@@ -16,7 +18,6 @@ from rasa.shared.nlu.constants import (
|
|
|
16
18
|
KEY_USER_PROMPT,
|
|
17
19
|
PREDICTED_COMMANDS,
|
|
18
20
|
PROMPTS,
|
|
19
|
-
SET_SLOT_COMMAND,
|
|
20
21
|
)
|
|
21
22
|
from rasa.shared.nlu.training_data.message import Message
|
|
22
23
|
from rasa.shared.providers.llm.llm_response import LLMResponse
|
|
@@ -26,6 +27,8 @@ record_commands_and_prompts = get_bool_env_variable(
|
|
|
26
27
|
RASA_RECORD_COMMANDS_AND_PROMPTS_ENV_VAR_NAME, False
|
|
27
28
|
)
|
|
28
29
|
|
|
30
|
+
structlogger = structlog.get_logger()
|
|
31
|
+
|
|
29
32
|
|
|
30
33
|
@contextmanager
|
|
31
34
|
def set_record_commands_and_prompts() -> Generator:
|
|
@@ -144,21 +147,74 @@ def _handle_via_nlu_in_coexistence(
|
|
|
144
147
|
if not tracker:
|
|
145
148
|
return False
|
|
146
149
|
|
|
150
|
+
commands = message.get(COMMANDS, [])
|
|
151
|
+
|
|
152
|
+
# If coexistence routing slot is not active, this setup doesn't
|
|
153
|
+
# support dual routing -> default to CALM
|
|
147
154
|
if not tracker.has_coexistence_routing_slot:
|
|
155
|
+
structlogger.debug(
|
|
156
|
+
"utils.handle_via_nlu_in_coexistence"
|
|
157
|
+
".tracker_missing_route_session_to_calm_slot",
|
|
158
|
+
event_info=(
|
|
159
|
+
f"Tracker doesn't have the '{ROUTE_TO_CALM_SLOT}' slot."
|
|
160
|
+
f"Routing to CALM."
|
|
161
|
+
),
|
|
162
|
+
route_session_to_calm=commands,
|
|
163
|
+
)
|
|
148
164
|
return False
|
|
149
165
|
|
|
166
|
+
# Check if the routing decision is stored in the tracker slot
|
|
167
|
+
# If slot is true -> route to CALM
|
|
168
|
+
# If slot is false -> route to DM1
|
|
150
169
|
value = tracker.get_slot(ROUTE_TO_CALM_SLOT)
|
|
151
170
|
if value is not None:
|
|
171
|
+
structlogger.debug(
|
|
172
|
+
"utils.handle_via_nlu_in_coexistence"
|
|
173
|
+
".tracker_route_session_to_calm_slot_value",
|
|
174
|
+
event_info=(
|
|
175
|
+
f"Tracker slot '{ROUTE_TO_CALM_SLOT}' set to '{value}'. "
|
|
176
|
+
f"Routing to "
|
|
177
|
+
f"{'CALM' if value else 'NLU system'}."
|
|
178
|
+
),
|
|
179
|
+
route_session_to_calm_value_in_tracker=value,
|
|
180
|
+
)
|
|
152
181
|
return not value
|
|
153
182
|
|
|
154
|
-
# routing
|
|
155
|
-
#
|
|
156
|
-
if
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
183
|
+
# Non-sticky routing to DM1 is only allowed if NoopCommand is the sole predicted
|
|
184
|
+
# command. In that case, route to DM1
|
|
185
|
+
if len(commands) == 1 and commands[0].get("command") == NoopCommand.command():
|
|
186
|
+
structlogger.debug(
|
|
187
|
+
"utils.handle_via_nlu_in_coexistence.noop_command_detected",
|
|
188
|
+
event_info="NoopCommand found. Routing to NLU system non-sticky.",
|
|
189
|
+
commands=commands,
|
|
190
|
+
)
|
|
191
|
+
return True
|
|
192
|
+
|
|
193
|
+
# If the slot was reset (e.g. new session), try to infer routing from
|
|
194
|
+
# attached commands. Look for a SetSlotCommand targeting the ROUTE_TO_CALM_SLOT
|
|
195
|
+
for command in message.get(COMMANDS, []):
|
|
196
|
+
# If slot is true -> route to CALM
|
|
197
|
+
# If slot is false -> route to DM1
|
|
198
|
+
if (
|
|
199
|
+
command.get("command") == SetSlotCommand.command()
|
|
200
|
+
and command.get("name") == ROUTE_TO_CALM_SLOT
|
|
201
|
+
):
|
|
202
|
+
structlogger.debug(
|
|
203
|
+
"utils.handle_via_nlu_in_coexistence.set_slot_command_detected",
|
|
204
|
+
event_info=(
|
|
205
|
+
f"SetSlotCommand setting the '{ROUTE_TO_CALM_SLOT}' to "
|
|
206
|
+
f"'{command.get('value')}'. "
|
|
207
|
+
f"Routing to "
|
|
208
|
+
f"{'CALM' if command.get('value') else 'NLU system'}."
|
|
209
|
+
),
|
|
210
|
+
commands=commands,
|
|
211
|
+
)
|
|
212
|
+
return not command.get("value")
|
|
213
|
+
|
|
214
|
+
# If no routing info is available -> default to CALM
|
|
215
|
+
structlogger.debug(
|
|
216
|
+
"utils.handle_via_nlu_in_coexistence.no_routing_info_available",
|
|
217
|
+
event_info="No routing info available. Routing to CALM.",
|
|
218
|
+
commands=commands,
|
|
219
|
+
)
|
|
164
220
|
return False
|
|
@@ -3,9 +3,9 @@ from typing import Any, Dict, Iterator, List, Optional, Tuple
|
|
|
3
3
|
|
|
4
4
|
from pydantic import BaseModel, Field
|
|
5
5
|
|
|
6
|
-
from rasa.core import IntentlessPolicy
|
|
7
6
|
from rasa.core.nlg.contextual_response_rephraser import ContextualResponseRephraser
|
|
8
7
|
from rasa.core.policies.enterprise_search_policy import EnterpriseSearchPolicy
|
|
8
|
+
from rasa.core.policies.intentless_policy import IntentlessPolicy
|
|
9
9
|
from rasa.dialogue_understanding.commands.prompt_command import PromptCommand
|
|
10
10
|
from rasa.dialogue_understanding.generator.command_parser import parse_commands
|
|
11
11
|
from rasa.dialogue_understanding_test.command_comparison import are_command_lists_equal
|
|
@@ -5,10 +5,10 @@ from typing import Any, Dict, List, Optional, Text
|
|
|
5
5
|
import structlog
|
|
6
6
|
from tqdm import tqdm
|
|
7
7
|
|
|
8
|
+
from rasa.core.available_endpoints import AvailableEndpoints
|
|
8
9
|
from rasa.core.channels import CollectingOutputChannel, UserMessage
|
|
9
10
|
from rasa.core.exceptions import AgentNotReady
|
|
10
11
|
from rasa.core.persistor import StorageType
|
|
11
|
-
from rasa.core.utils import AvailableEndpoints
|
|
12
12
|
from rasa.dialogue_understanding.commands import Command
|
|
13
13
|
from rasa.dialogue_understanding.utils import set_record_commands_and_prompts
|
|
14
14
|
from rasa.dialogue_understanding_test.du_test_case import (
|
|
@@ -34,6 +34,7 @@ from rasa.e2e_test.e2e_test_runner import E2ETestRunner
|
|
|
34
34
|
from rasa.shared.core.events import UserUttered
|
|
35
35
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
36
36
|
from rasa.shared.nlu.constants import PREDICTED_COMMANDS, PROMPTS
|
|
37
|
+
from rasa.shared.utils.llm import create_tracker_for_user_step
|
|
37
38
|
from rasa.utils.endpoints import EndpointConfig
|
|
38
39
|
|
|
39
40
|
structlogger = structlog.get_logger()
|
|
@@ -179,8 +180,9 @@ class DialogueUnderstandingTestRunner:
|
|
|
179
180
|
# create and save the tracker at the time just
|
|
180
181
|
# before the user message was sent
|
|
181
182
|
step_sender_id = f"{sender_id}_{user_step_index}"
|
|
182
|
-
await
|
|
183
|
+
await create_tracker_for_user_step(
|
|
183
184
|
step_sender_id,
|
|
185
|
+
self.agent,
|
|
184
186
|
test_case_tracker,
|
|
185
187
|
user_uttered_event_indices[user_step_index],
|
|
186
188
|
)
|
|
@@ -289,26 +291,6 @@ class DialogueUnderstandingTestRunner:
|
|
|
289
291
|
|
|
290
292
|
return user_uttered_event
|
|
291
293
|
|
|
292
|
-
async def _create_tracker_for_user_step(
|
|
293
|
-
self,
|
|
294
|
-
step_sender_id: str,
|
|
295
|
-
test_case_tracker: DialogueStateTracker,
|
|
296
|
-
index_user_uttered_event: int,
|
|
297
|
-
) -> None:
|
|
298
|
-
"""Creates a tracker for the user step."""
|
|
299
|
-
tracker = test_case_tracker.copy()
|
|
300
|
-
# modify the sender id so that the test case tracker is not overwritten
|
|
301
|
-
tracker.sender_id = step_sender_id
|
|
302
|
-
|
|
303
|
-
if tracker.events:
|
|
304
|
-
# get timestamp of the event just before the user uttered event
|
|
305
|
-
timestamp = tracker.events[index_user_uttered_event - 1].timestamp
|
|
306
|
-
# revert the tracker to the event just before the user uttered event
|
|
307
|
-
tracker = tracker.travel_back_in_time(timestamp)
|
|
308
|
-
|
|
309
|
-
# store the tracker with the unique sender id
|
|
310
|
-
await self.agent.tracker_store.save(tracker)
|
|
311
|
-
|
|
312
294
|
async def _send_user_message(
|
|
313
295
|
self,
|
|
314
296
|
sender_id: str,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
1
|
from typing import List, Optional
|
|
3
2
|
|
|
4
3
|
import structlog
|
|
@@ -24,6 +23,7 @@ from rasa.shared.core.constants import SlotMappingType
|
|
|
24
23
|
from rasa.shared.core.events import BotUttered, SlotSet, UserUttered
|
|
25
24
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
26
25
|
from rasa.shared.nlu.constants import COMMANDS, ENTITIES, INTENT
|
|
26
|
+
from rasa.shared.utils.llm import generate_sender_id
|
|
27
27
|
|
|
28
28
|
structlogger = structlog.get_logger()
|
|
29
29
|
|
|
@@ -52,7 +52,7 @@ class TestCaseTrackerSimulator:
|
|
|
52
52
|
self.test_case = test_case
|
|
53
53
|
self.output_channel = output_channel or CollectingOutputChannel()
|
|
54
54
|
|
|
55
|
-
self.sender_id = self.
|
|
55
|
+
self.sender_id = generate_sender_id(self.test_case.name)
|
|
56
56
|
|
|
57
57
|
async def simulate_test_case(
|
|
58
58
|
self,
|
|
@@ -150,10 +150,6 @@ class TestCaseTrackerSimulator:
|
|
|
150
150
|
user_uttered_event_indices=user_uttered_event_indices,
|
|
151
151
|
)
|
|
152
152
|
|
|
153
|
-
def _generate_sender_id(self) -> str:
|
|
154
|
-
# add timestamp suffix to ensure sender_id is unique
|
|
155
|
-
return f"{self.test_case.name}_{datetime.now()}"
|
|
156
|
-
|
|
157
153
|
@staticmethod
|
|
158
154
|
async def _get_latest_user_uttered_event_index(
|
|
159
155
|
tracker: DialogueStateTracker, user_uttered_event_indices: List[int]
|
rasa/e2e_test/e2e_test_runner.py
CHANGED
|
@@ -13,11 +13,11 @@ import structlog
|
|
|
13
13
|
from tqdm import tqdm
|
|
14
14
|
|
|
15
15
|
import rasa.shared.utils.io
|
|
16
|
+
from rasa.core.available_endpoints import AvailableEndpoints
|
|
16
17
|
from rasa.core.channels import CollectingOutputChannel, UserMessage
|
|
17
18
|
from rasa.core.constants import ACTIVE_FLOW_METADATA_KEY, STEP_ID_METADATA_KEY
|
|
18
19
|
from rasa.core.exceptions import AgentNotReady
|
|
19
20
|
from rasa.core.persistor import StorageType
|
|
20
|
-
from rasa.core.utils import AvailableEndpoints
|
|
21
21
|
from rasa.dialogue_understanding_test.du_test_case import DialogueUnderstandingTestCase
|
|
22
22
|
from rasa.e2e_test.constants import TEST_CASE_NAME, TEST_FILE_NAME
|
|
23
23
|
from rasa.e2e_test.e2e_config import create_llm_judge_config
|
rasa/engine/constants.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import List, Optional
|
|
2
2
|
|
|
3
|
+
from rasa.core.available_endpoints import AvailableEndpoints
|
|
3
4
|
from rasa.core.channels import UserMessage
|
|
4
|
-
from rasa.core.utils import AvailableEndpoints
|
|
5
5
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
6
6
|
from rasa.shared.importers.importer import TrainingDataImporter
|
|
7
7
|
|
rasa/engine/graph.py
CHANGED
|
@@ -500,9 +500,9 @@ class GraphNode:
|
|
|
500
500
|
structlogger.warning(
|
|
501
501
|
"graph.node.input_not_resolved",
|
|
502
502
|
node_name=self._node_name,
|
|
503
|
-
input_name=i,
|
|
503
|
+
input_name=i, # no PII
|
|
504
504
|
event_info=(
|
|
505
|
-
"Node input was not resolved, there is no
|
|
505
|
+
"Node input was not resolved, there is no output. "
|
|
506
506
|
"Another component should have provided this as an output."
|
|
507
507
|
),
|
|
508
508
|
)
|
|
@@ -396,7 +396,9 @@ class DefaultV1Recipe(Recipe):
|
|
|
396
396
|
return preprocessors
|
|
397
397
|
|
|
398
398
|
def _get_needs_from_args(
|
|
399
|
-
self,
|
|
399
|
+
self,
|
|
400
|
+
component: Type[GraphComponent],
|
|
401
|
+
fn_name: str,
|
|
400
402
|
) -> Dict[str, str]:
|
|
401
403
|
"""Get the needed arguments from the method on the component.
|
|
402
404
|
|
|
@@ -434,6 +436,7 @@ class DefaultV1Recipe(Recipe):
|
|
|
434
436
|
parameters = {
|
|
435
437
|
name
|
|
436
438
|
for name, param in sig.parameters.items()
|
|
439
|
+
# only consider parameters which are positional or keyword
|
|
437
440
|
if param.kind == param.POSITIONAL_OR_KEYWORD
|
|
438
441
|
}
|
|
439
442
|
|
|
@@ -752,8 +755,28 @@ class DefaultV1Recipe(Recipe):
|
|
|
752
755
|
predict_config, predict_nodes, train_nodes, preprocessors
|
|
753
756
|
)
|
|
754
757
|
|
|
758
|
+
# The `story_graph_provider` is only needed if the intentless policy is used.
|
|
759
|
+
# If it is not used, we can remove it from the nodes as it slows down the
|
|
760
|
+
# loading time if users have a large number of stories.
|
|
761
|
+
if not self._intentless_policy_used(predict_nodes):
|
|
762
|
+
# Removes the `story_graph_provider` from the nodes
|
|
763
|
+
predict_nodes.pop("story_graph_provider", None)
|
|
764
|
+
if "command_processor" in predict_nodes:
|
|
765
|
+
# Removes story_graph from the command processor inputs
|
|
766
|
+
predict_nodes["command_processor"].needs.pop("story_graph", None)
|
|
767
|
+
|
|
755
768
|
return predict_nodes
|
|
756
769
|
|
|
770
|
+
@staticmethod
|
|
771
|
+
def _intentless_policy_used(nodes: Dict[Text, SchemaNode]) -> bool:
|
|
772
|
+
"""Checks if the intentless policy is used in the nodes."""
|
|
773
|
+
from rasa.core.policies.intentless_policy import IntentlessPolicy
|
|
774
|
+
|
|
775
|
+
for schema_node in nodes.values():
|
|
776
|
+
if schema_node.matches_type(IntentlessPolicy):
|
|
777
|
+
return True
|
|
778
|
+
return False
|
|
779
|
+
|
|
757
780
|
def _add_nlu_predict_nodes(
|
|
758
781
|
self,
|
|
759
782
|
last_run_node: Text,
|
|
@@ -924,7 +947,8 @@ class DefaultV1Recipe(Recipe):
|
|
|
924
947
|
predict_nodes["command_processor"] = SchemaNode(
|
|
925
948
|
**DEFAULT_PREDICT_KWARGS,
|
|
926
949
|
needs=self._get_needs_from_args(
|
|
927
|
-
CommandProcessorComponent,
|
|
950
|
+
CommandProcessorComponent,
|
|
951
|
+
"execute_commands",
|
|
928
952
|
),
|
|
929
953
|
uses=CommandProcessorComponent,
|
|
930
954
|
fn="execute_commands",
|
rasa/engine/validation.py
CHANGED
|
@@ -23,9 +23,10 @@ import structlog
|
|
|
23
23
|
import typing_utils
|
|
24
24
|
|
|
25
25
|
import rasa.utils.common
|
|
26
|
-
from rasa.core import
|
|
26
|
+
from rasa.core.available_endpoints import AvailableEndpoints
|
|
27
|
+
from rasa.core.nlg.contextual_response_rephraser import ContextualResponseRephraser
|
|
28
|
+
from rasa.core.policies.intentless_policy import IntentlessPolicy
|
|
27
29
|
from rasa.core.policies.policy import PolicyPrediction
|
|
28
|
-
from rasa.core.utils import AvailableEndpoints
|
|
29
30
|
from rasa.dialogue_understanding.coexistence.constants import (
|
|
30
31
|
CALM_ENTRY,
|
|
31
32
|
NLU_ENTRY,
|
rasa/hooks.py
CHANGED
|
@@ -9,7 +9,6 @@ import pluggy
|
|
|
9
9
|
# across the codebase.
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
|
-
from rasa.anonymization.anonymization_pipeline import AnonymizationPipeline
|
|
13
12
|
from rasa.cli import SubParsersAction
|
|
14
13
|
from rasa.core.brokers.broker import EventBroker
|
|
15
14
|
from rasa.core.tracker_stores.tracker_store import TrackerStore
|
|
@@ -88,30 +87,3 @@ def create_tracker_store(
|
|
|
88
87
|
endpoint_config=endpoint_config, domain=domain, event_broker=event_broker
|
|
89
88
|
)
|
|
90
89
|
return endpoint_config
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@hookimpl # type: ignore[misc]
|
|
94
|
-
def init_anonymization_pipeline(endpoints_file: Optional[Text]) -> None:
|
|
95
|
-
"""Hook implementation for initializing the anonymization pipeline."""
|
|
96
|
-
from rasa.anonymization.anonymization_pipeline import load_anonymization_pipeline
|
|
97
|
-
|
|
98
|
-
load_anonymization_pipeline(endpoints_file)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
@hookimpl # type: ignore[misc]
|
|
102
|
-
def get_anonymization_pipeline() -> Optional["AnonymizationPipeline"]:
|
|
103
|
-
"""Hook implementation for getting the anonymization pipeline."""
|
|
104
|
-
from rasa.anonymization.anonymization_pipeline import AnonymizationPipelineProvider
|
|
105
|
-
|
|
106
|
-
return AnonymizationPipelineProvider().get_anonymization_pipeline()
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
@hookimpl # type: ignore[misc]
|
|
110
|
-
def after_server_stop() -> None:
|
|
111
|
-
"""Hook implementation for stopping the anonymization pipeline."""
|
|
112
|
-
from rasa.anonymization.anonymization_pipeline import AnonymizationPipelineProvider
|
|
113
|
-
|
|
114
|
-
anon_pipeline = AnonymizationPipelineProvider().get_anonymization_pipeline()
|
|
115
|
-
|
|
116
|
-
if anon_pipeline is not None:
|
|
117
|
-
anon_pipeline.stop()
|
|
@@ -10,7 +10,9 @@ from rasa.e2e_test.e2e_test_runner import TEST_TURNS_TYPE, E2ETestRunner
|
|
|
10
10
|
from rasa.llm_fine_tuning.conversations import Conversation, ConversationStep
|
|
11
11
|
from rasa.llm_fine_tuning.storage import StorageContext
|
|
12
12
|
from rasa.shared.core.constants import USER
|
|
13
|
+
from rasa.shared.core.events import UserUttered
|
|
13
14
|
from rasa.shared.core.trackers import DialogueStateTracker
|
|
15
|
+
from rasa.shared.exceptions import FinetuningDataPreparationException
|
|
14
16
|
from rasa.shared.nlu.constants import LLM_COMMANDS, LLM_PROMPT
|
|
15
17
|
from rasa.shared.utils.llm import tracker_as_readable_transcript
|
|
16
18
|
|
|
@@ -37,7 +39,7 @@ def annotate_e2e_tests(
|
|
|
37
39
|
storage_context: StorageContext,
|
|
38
40
|
) -> List[Conversation]:
|
|
39
41
|
with set_preparing_fine_tuning_data():
|
|
40
|
-
|
|
42
|
+
conversations = asyncio.run(
|
|
41
43
|
e2e_test_runner.run_tests_for_fine_tuning(
|
|
42
44
|
test_suite.test_cases,
|
|
43
45
|
test_suite.fixtures,
|
|
@@ -46,10 +48,11 @@ def annotate_e2e_tests(
|
|
|
46
48
|
)
|
|
47
49
|
|
|
48
50
|
storage_context.write_conversations(
|
|
49
|
-
|
|
51
|
+
conversations,
|
|
52
|
+
ANNOTATION_MODULE_STORAGE_LOCATION,
|
|
50
53
|
)
|
|
51
54
|
|
|
52
|
-
return
|
|
55
|
+
return conversations
|
|
53
56
|
|
|
54
57
|
|
|
55
58
|
def _get_previous_actual_step_output(
|
|
@@ -80,25 +83,45 @@ def generate_conversation(
|
|
|
80
83
|
Conversation.
|
|
81
84
|
"""
|
|
82
85
|
steps = []
|
|
86
|
+
tracker_event_indices = [
|
|
87
|
+
i for i, event in enumerate(tracker.events) if isinstance(event, UserUttered)
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
if len(test_case.steps) != len(tracker_event_indices):
|
|
91
|
+
raise FinetuningDataPreparationException(
|
|
92
|
+
"Number of test case steps and tracker events do not match."
|
|
93
|
+
)
|
|
83
94
|
|
|
84
95
|
if assertions_used:
|
|
85
96
|
# we only have user steps, extract the bot response from the bot uttered
|
|
86
97
|
# events of the test turn
|
|
87
|
-
for i, original_step in enumerate(
|
|
98
|
+
for i, (original_step, tracker_event_index) in enumerate(
|
|
99
|
+
zip(test_case.steps, tracker_event_indices)
|
|
100
|
+
):
|
|
88
101
|
previous_turn = _get_previous_actual_step_output(test_turns, i)
|
|
89
102
|
steps.append(
|
|
90
103
|
_convert_to_conversation_step(
|
|
91
|
-
original_step,
|
|
104
|
+
original_step,
|
|
105
|
+
test_turns[i],
|
|
106
|
+
test_case.name,
|
|
107
|
+
previous_turn,
|
|
108
|
+
tracker_event_index,
|
|
92
109
|
)
|
|
93
110
|
)
|
|
94
111
|
steps.extend(_create_bot_test_steps(test_turns[i]))
|
|
95
112
|
else:
|
|
96
|
-
for i, original_step in enumerate(
|
|
113
|
+
for i, (original_step, tracker_event_index) in enumerate(
|
|
114
|
+
zip(test_case.steps, tracker_event_indices)
|
|
115
|
+
):
|
|
97
116
|
if original_step.actor == USER:
|
|
98
117
|
previous_turn = _get_previous_actual_step_output(test_turns, i)
|
|
99
118
|
steps.append(
|
|
100
119
|
_convert_to_conversation_step(
|
|
101
|
-
original_step,
|
|
120
|
+
original_step,
|
|
121
|
+
test_turns[i],
|
|
122
|
+
test_case.name,
|
|
123
|
+
previous_turn,
|
|
124
|
+
tracker_event_index,
|
|
102
125
|
)
|
|
103
126
|
)
|
|
104
127
|
else:
|
|
@@ -120,7 +143,7 @@ def generate_conversation(
|
|
|
120
143
|
|
|
121
144
|
transcript = tracker_as_readable_transcript(tracker, max_turns=None)
|
|
122
145
|
|
|
123
|
-
return Conversation(test_case.name, test_case, steps, transcript)
|
|
146
|
+
return Conversation(test_case.name, test_case, steps, transcript, tracker)
|
|
124
147
|
|
|
125
148
|
|
|
126
149
|
def _create_bot_test_steps(current_turn: ActualStepOutput) -> List[TestStep]:
|
|
@@ -140,6 +163,7 @@ def _convert_to_conversation_step(
|
|
|
140
163
|
current_turn: ActualStepOutput,
|
|
141
164
|
test_case_name: str,
|
|
142
165
|
previous_turn: Optional[ActualStepOutput],
|
|
166
|
+
tracker_event_index: Optional[int] = None,
|
|
143
167
|
) -> Union[TestStep, ConversationStep]:
|
|
144
168
|
if not current_step.text == current_turn.text or not isinstance(
|
|
145
169
|
current_turn, ActualStepOutput
|
|
@@ -169,7 +193,13 @@ def _convert_to_conversation_step(
|
|
|
169
193
|
commands = [Command.command_from_json(data) for data in llm_commands]
|
|
170
194
|
rephrase = _should_be_rephrased(current_turn.text, previous_turn, test_case_name)
|
|
171
195
|
|
|
172
|
-
return ConversationStep(
|
|
196
|
+
return ConversationStep(
|
|
197
|
+
current_step,
|
|
198
|
+
commands,
|
|
199
|
+
llm_prompt,
|
|
200
|
+
rephrase=rephrase,
|
|
201
|
+
tracker_event_index=tracker_event_index,
|
|
202
|
+
)
|
|
173
203
|
|
|
174
204
|
|
|
175
205
|
def _should_be_rephrased(
|
|
@@ -4,6 +4,7 @@ from typing import Any, Dict, Iterator, List, Optional, Union
|
|
|
4
4
|
from rasa.dialogue_understanding.commands.prompt_command import PromptCommand
|
|
5
5
|
from rasa.e2e_test.e2e_test_case import TestCase, TestStep
|
|
6
6
|
from rasa.shared.core.constants import USER
|
|
7
|
+
from rasa.shared.core.trackers import DialogueStateTracker
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
@dataclass
|
|
@@ -14,6 +15,7 @@ class ConversationStep:
|
|
|
14
15
|
failed_rephrasings: List[str] = field(default_factory=list)
|
|
15
16
|
passed_rephrasings: List[str] = field(default_factory=list)
|
|
16
17
|
rephrase: bool = True
|
|
18
|
+
tracker_event_index: Optional[int] = None
|
|
17
19
|
|
|
18
20
|
def as_dict(self) -> Dict[str, Any]:
|
|
19
21
|
data = {
|
|
@@ -40,6 +42,7 @@ class Conversation:
|
|
|
40
42
|
original_e2e_test_case: TestCase
|
|
41
43
|
steps: List[Union[TestStep, ConversationStep]]
|
|
42
44
|
transcript: str
|
|
45
|
+
tracker: Optional[DialogueStateTracker] = None
|
|
43
46
|
|
|
44
47
|
def iterate_over_annotated_user_steps(
|
|
45
48
|
self, rephrase: Optional[bool] = None
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
|
-
from typing import Any, Dict, List, Optional
|
|
2
|
+
from typing import Any, Dict, List, Optional, cast
|
|
3
3
|
|
|
4
4
|
import structlog
|
|
5
5
|
from tqdm import tqdm
|
|
6
6
|
|
|
7
|
+
from rasa.core.agent import Agent
|
|
8
|
+
from rasa.core.channels import UserMessage
|
|
7
9
|
from rasa.dialogue_understanding.commands.prompt_command import PromptCommand
|
|
10
|
+
from rasa.dialogue_understanding.utils import set_record_commands_and_prompts
|
|
8
11
|
from rasa.llm_fine_tuning.conversations import Conversation, ConversationStep
|
|
9
12
|
from rasa.llm_fine_tuning.storage import StorageContext
|
|
10
|
-
from rasa.llm_fine_tuning.utils import
|
|
13
|
+
from rasa.llm_fine_tuning.utils import (
|
|
14
|
+
commands_as_string,
|
|
15
|
+
make_mock_invoke_llm,
|
|
16
|
+
patch_invoke_llm_in_generators,
|
|
17
|
+
)
|
|
18
|
+
from rasa.shared.core.trackers import DialogueStateTracker
|
|
19
|
+
from rasa.shared.nlu.constants import KEY_USER_PROMPT, PROMPTS
|
|
20
|
+
from rasa.shared.utils.llm import generate_sender_id
|
|
11
21
|
|
|
12
22
|
LLM_DATA_PREPARATION_MODULE_STORAGE_LOCATION = "3_llm_finetune_data/llm_ft_data.jsonl"
|
|
13
23
|
|
|
@@ -47,40 +57,8 @@ def _create_data_point(
|
|
|
47
57
|
)
|
|
48
58
|
|
|
49
59
|
|
|
50
|
-
def
|
|
51
|
-
|
|
52
|
-
original_user_steps: List[ConversationStep],
|
|
53
|
-
rephrased_user_steps: List[str],
|
|
54
|
-
) -> Optional[str]:
|
|
55
|
-
if len(original_user_steps) != len(rephrased_user_steps):
|
|
56
|
-
structlogger.debug(
|
|
57
|
-
"llm_fine_tuning.llm_data_preparation_module.failed_to_update_prompt",
|
|
58
|
-
original_user_steps=[
|
|
59
|
-
step.original_test_step.text for step in original_user_steps
|
|
60
|
-
],
|
|
61
|
-
rephrased_user_steps=rephrased_user_steps,
|
|
62
|
-
)
|
|
63
|
-
return None
|
|
64
|
-
|
|
65
|
-
updated_prompt = prompt
|
|
66
|
-
for user_step, rephrased_message in zip(original_user_steps, rephrased_user_steps):
|
|
67
|
-
# replace all occurrences of the original user message with the rephrased user
|
|
68
|
-
# message in the conversation history mentioned in the prompt
|
|
69
|
-
updated_prompt = updated_prompt.replace(
|
|
70
|
-
f"USER: {user_step.original_test_step.text}", f"USER: {rephrased_message}"
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
# replace the latest user message mentioned in the prompt
|
|
74
|
-
updated_prompt = updated_prompt.replace(
|
|
75
|
-
f"'''{original_user_steps[-1].original_test_step.text}'''",
|
|
76
|
-
f"'''{rephrased_user_steps[-1]}'''",
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
return updated_prompt
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def _convert_conversation_into_llm_data(
|
|
83
|
-
conversation: Conversation,
|
|
60
|
+
async def _convert_conversation_into_llm_data(
|
|
61
|
+
conversation: Conversation, agent: Agent
|
|
84
62
|
) -> List[LLMDataExample]:
|
|
85
63
|
data = []
|
|
86
64
|
|
|
@@ -95,18 +73,52 @@ def _convert_conversation_into_llm_data(
|
|
|
95
73
|
# create data point for the original e2e test case
|
|
96
74
|
data.append(_create_data_point(step.llm_prompt, step, conversation))
|
|
97
75
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
76
|
+
test_case_name = conversation.name
|
|
77
|
+
|
|
78
|
+
# create data points using the rephrasings, e.g. 'new_conversations'
|
|
79
|
+
for rephrased_user_steps in new_conversations:
|
|
80
|
+
sender_id = generate_sender_id(test_case_name)
|
|
81
|
+
# create a new tracker to be able to simulate the conversation from start
|
|
82
|
+
await agent.tracker_store.save(DialogueStateTracker(sender_id, slots=[]))
|
|
83
|
+
# simulate the conversation to get the prompts
|
|
84
|
+
for i, step in enumerate(original_user_steps):
|
|
85
|
+
rephrased_user_message = rephrased_user_steps[i]
|
|
86
|
+
user_message = UserMessage(rephrased_user_message, sender_id=sender_id)
|
|
87
|
+
|
|
88
|
+
expected_commands = "\n".join(
|
|
89
|
+
[command.to_dsl() for command in step.llm_commands]
|
|
90
|
+
)
|
|
91
|
+
fake_invoke_function = make_mock_invoke_llm(expected_commands)
|
|
92
|
+
|
|
93
|
+
with (
|
|
94
|
+
set_record_commands_and_prompts(),
|
|
95
|
+
patch_invoke_llm_in_generators(fake_invoke_function),
|
|
96
|
+
):
|
|
97
|
+
await agent.handle_message(user_message)
|
|
98
|
+
|
|
99
|
+
rephrased_tracker = await agent.tracker_store.retrieve(sender_id)
|
|
100
|
+
if rephrased_tracker is None:
|
|
101
|
+
# if tracker doesn't exist, we can't create a data point
|
|
102
|
+
continue
|
|
103
|
+
|
|
104
|
+
latest_message = rephrased_tracker.latest_message
|
|
105
|
+
if latest_message is None:
|
|
106
|
+
# if there is no latest message, we don't create a data point
|
|
107
|
+
continue
|
|
108
|
+
|
|
109
|
+
# tell the type checker what we expect to find under "prompts"
|
|
110
|
+
prompts = cast(
|
|
111
|
+
Optional[List[Dict[str, Any]]], latest_message.parse_data.get(PROMPTS)
|
|
105
112
|
)
|
|
106
|
-
|
|
113
|
+
|
|
114
|
+
if prompts:
|
|
115
|
+
# as we only use single step or compact command generator,
|
|
116
|
+
# there is always exactly one prompt
|
|
117
|
+
prompt = prompts[0]
|
|
118
|
+
user_prompt: Optional[str] = prompt.get(KEY_USER_PROMPT)
|
|
107
119
|
data.append(
|
|
108
120
|
_create_data_point(
|
|
109
|
-
|
|
121
|
+
user_prompt, step, conversation, rephrased_user_message
|
|
110
122
|
)
|
|
111
123
|
)
|
|
112
124
|
|
|
@@ -149,7 +161,7 @@ def _construct_new_conversations(conversation: Conversation) -> List[List[str]]:
|
|
|
149
161
|
current_conversation.append(step.original_test_step.text)
|
|
150
162
|
continue
|
|
151
163
|
|
|
152
|
-
# some user steps might have
|
|
164
|
+
# some user steps might have fewer rephrasings than others
|
|
153
165
|
# loop over the rephrasings
|
|
154
166
|
index = i % len(step.passed_rephrasings)
|
|
155
167
|
current_conversation.append(step.passed_rephrasings[index])
|
|
@@ -165,13 +177,18 @@ def _construct_new_conversations(conversation: Conversation) -> List[List[str]]:
|
|
|
165
177
|
return new_conversations
|
|
166
178
|
|
|
167
179
|
|
|
168
|
-
def convert_to_fine_tuning_data(
|
|
169
|
-
conversations: List[Conversation],
|
|
180
|
+
async def convert_to_fine_tuning_data(
|
|
181
|
+
conversations: List[Conversation],
|
|
182
|
+
storage_context: StorageContext,
|
|
183
|
+
agent: Agent,
|
|
170
184
|
) -> List[LLMDataExample]:
|
|
171
185
|
llm_data = []
|
|
172
186
|
|
|
173
187
|
for i in tqdm(range(len(conversations))):
|
|
174
|
-
|
|
188
|
+
conversation_llm_data = await _convert_conversation_into_llm_data(
|
|
189
|
+
conversations[i], agent
|
|
190
|
+
)
|
|
191
|
+
llm_data.extend(conversation_llm_data)
|
|
175
192
|
|
|
176
193
|
storage_context.write_llm_data(
|
|
177
194
|
llm_data, LLM_DATA_PREPARATION_MODULE_STORAGE_LOCATION
|
|
@@ -22,11 +22,7 @@ from rasa.shared.constants import (
|
|
|
22
22
|
from rasa.shared.exceptions import ProviderClientAPIException
|
|
23
23
|
from rasa.shared.providers.mappings import OPENAI_PROVIDER
|
|
24
24
|
from rasa.shared.utils.constants import LOG_COMPONENT_SOURCE_METHOD_INIT
|
|
25
|
-
from rasa.shared.utils.llm import
|
|
26
|
-
USER,
|
|
27
|
-
get_prompt_template,
|
|
28
|
-
llm_factory,
|
|
29
|
-
)
|
|
25
|
+
from rasa.shared.utils.llm import USER, get_prompt_template, llm_factory
|
|
30
26
|
|
|
31
27
|
SEPARATOR = "\n\n"
|
|
32
28
|
BACKUP_SEPARATOR = "\nUSER:"
|