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
|
@@ -14,7 +14,7 @@ from sanic import ( # type: ignore[attr-defined]
|
|
|
14
14
|
response,
|
|
15
15
|
)
|
|
16
16
|
|
|
17
|
-
from rasa.core.channels import
|
|
17
|
+
from rasa.core.channels import UserMessage
|
|
18
18
|
from rasa.core.channels.channel import (
|
|
19
19
|
create_auth_requested_response_provider,
|
|
20
20
|
requires_basic_auth,
|
|
@@ -102,16 +102,22 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
102
102
|
server_url: str,
|
|
103
103
|
asr_config: Dict,
|
|
104
104
|
tts_config: Dict,
|
|
105
|
-
monitor_silence: bool = False,
|
|
106
105
|
username: Optional[Text] = None,
|
|
107
106
|
password: Optional[Text] = None,
|
|
108
107
|
):
|
|
109
|
-
super().__init__(
|
|
108
|
+
super().__init__(
|
|
109
|
+
server_url=server_url,
|
|
110
|
+
asr_config=asr_config,
|
|
111
|
+
tts_config=tts_config,
|
|
112
|
+
)
|
|
110
113
|
self.username = username
|
|
111
114
|
self.password = password
|
|
112
115
|
|
|
113
116
|
@classmethod
|
|
114
|
-
def from_credentials(
|
|
117
|
+
def from_credentials(
|
|
118
|
+
cls,
|
|
119
|
+
credentials: Optional[Dict[str, Any]],
|
|
120
|
+
) -> VoiceInputChannel:
|
|
115
121
|
credentials = credentials or {}
|
|
116
122
|
|
|
117
123
|
username = credentials.get("username")
|
|
@@ -126,7 +132,6 @@ class TwilioMediaStreamsInputChannel(VoiceInputChannel):
|
|
|
126
132
|
credentials["server_url"],
|
|
127
133
|
credentials["asr"],
|
|
128
134
|
credentials["tts"],
|
|
129
|
-
credentials.get("monitor_silence", False),
|
|
130
135
|
username=username,
|
|
131
136
|
password=password,
|
|
132
137
|
)
|
|
@@ -31,8 +31,10 @@ from rasa.core.channels.voice_stream.tts.azure import AzureTTS
|
|
|
31
31
|
from rasa.core.channels.voice_stream.tts.cartesia import CartesiaTTS
|
|
32
32
|
from rasa.core.channels.voice_stream.tts.tts_cache import TTSCache
|
|
33
33
|
from rasa.core.channels.voice_stream.tts.tts_engine import TTSEngine, TTSError
|
|
34
|
-
from rasa.core.channels.voice_stream.util import
|
|
35
|
-
|
|
34
|
+
from rasa.core.channels.voice_stream.util import (
|
|
35
|
+
generate_silence,
|
|
36
|
+
)
|
|
37
|
+
from rasa.shared.core.constants import SILENCE_TIMEOUT_SLOT
|
|
36
38
|
from rasa.shared.utils.cli import print_error_and_exit
|
|
37
39
|
from rasa.shared.utils.common import (
|
|
38
40
|
class_from_module_path,
|
|
@@ -171,8 +173,12 @@ class VoiceOutputChannel(OutputChannel):
|
|
|
171
173
|
def update_silence_timeout(self) -> None:
|
|
172
174
|
"""Updates the silence timeout for the session."""
|
|
173
175
|
if self.tracker_state:
|
|
174
|
-
call_state.silence_timeout =
|
|
175
|
-
|
|
176
|
+
call_state.silence_timeout = self.tracker_state["slots"][ # type: ignore[attr-defined]
|
|
177
|
+
SILENCE_TIMEOUT_SLOT
|
|
178
|
+
]
|
|
179
|
+
logger.debug(
|
|
180
|
+
"voice_channel.silence_timeout_updated",
|
|
181
|
+
silence_timeout=call_state.silence_timeout,
|
|
176
182
|
)
|
|
177
183
|
|
|
178
184
|
async def send_text_with_buttons(
|
|
@@ -280,26 +286,34 @@ class VoiceOutputChannel(OutputChannel):
|
|
|
280
286
|
|
|
281
287
|
|
|
282
288
|
class VoiceInputChannel(InputChannel):
|
|
289
|
+
# All children of this class require a voice license to be used.
|
|
290
|
+
requires_voice_license = True
|
|
291
|
+
|
|
283
292
|
def __init__(
|
|
284
293
|
self,
|
|
285
294
|
server_url: str,
|
|
286
295
|
asr_config: Dict,
|
|
287
296
|
tts_config: Dict,
|
|
288
|
-
monitor_silence: bool = False,
|
|
289
297
|
):
|
|
290
|
-
|
|
298
|
+
if self.requires_voice_license:
|
|
299
|
+
validate_voice_license_scope()
|
|
300
|
+
|
|
291
301
|
self.server_url = server_url
|
|
292
302
|
self.asr_config = asr_config
|
|
293
303
|
self.tts_config = tts_config
|
|
294
|
-
self.monitor_silence = monitor_silence
|
|
295
304
|
self.tts_cache = TTSCache(tts_config.get("cache_size", 1000))
|
|
296
305
|
|
|
306
|
+
logger.info(
|
|
307
|
+
"voice_channel.initialized",
|
|
308
|
+
server_url=self.server_url,
|
|
309
|
+
asr_config=self.asr_config,
|
|
310
|
+
tts_config=self.tts_config,
|
|
311
|
+
)
|
|
312
|
+
|
|
297
313
|
async def monitor_silence_timeout(self, asr_event_queue: asyncio.Queue) -> None:
|
|
298
314
|
timeout = call_state.silence_timeout
|
|
299
315
|
if not timeout:
|
|
300
316
|
return
|
|
301
|
-
if not self.monitor_silence:
|
|
302
|
-
return
|
|
303
317
|
logger.debug("voice_channel.silence_timeout_watch_started", timeout=timeout)
|
|
304
318
|
await asyncio.sleep(timeout)
|
|
305
319
|
await asr_event_queue.put(UserSilence())
|
|
@@ -314,13 +328,15 @@ class VoiceInputChannel(InputChannel):
|
|
|
314
328
|
call_state.silence_timeout_watcher = None # type: ignore[attr-defined]
|
|
315
329
|
|
|
316
330
|
@classmethod
|
|
317
|
-
def from_credentials(
|
|
331
|
+
def from_credentials(
|
|
332
|
+
cls,
|
|
333
|
+
credentials: Optional[Dict[str, Any]],
|
|
334
|
+
) -> InputChannel:
|
|
318
335
|
credentials = credentials or {}
|
|
319
336
|
return cls(
|
|
320
337
|
credentials["server_url"],
|
|
321
338
|
credentials["asr"],
|
|
322
339
|
credentials["tts"],
|
|
323
|
-
credentials.get("monitor_silence", False),
|
|
324
340
|
)
|
|
325
341
|
|
|
326
342
|
def channel_bytes_to_rasa_audio_bytes(self, input_bytes: bytes) -> RasaAudioBytes:
|
|
@@ -340,9 +356,9 @@ class VoiceInputChannel(InputChannel):
|
|
|
340
356
|
) -> None:
|
|
341
357
|
output_channel = self.create_output_channel(channel_websocket, tts_engine)
|
|
342
358
|
message = UserMessage(
|
|
343
|
-
USER_CONVERSATION_SESSION_START,
|
|
344
|
-
output_channel,
|
|
345
|
-
call_parameters.stream_id,
|
|
359
|
+
text=USER_CONVERSATION_SESSION_START,
|
|
360
|
+
output_channel=output_channel,
|
|
361
|
+
sender_id=call_parameters.stream_id,
|
|
346
362
|
input_channel=self.name(),
|
|
347
363
|
metadata=asdict(call_parameters),
|
|
348
364
|
)
|
|
@@ -377,17 +393,17 @@ class VoiceInputChannel(InputChannel):
|
|
|
377
393
|
|
|
378
394
|
async def consume_audio_bytes() -> None:
|
|
379
395
|
async for message in channel_websocket:
|
|
380
|
-
|
|
396
|
+
was_bot_speaking_before = call_state.is_bot_speaking
|
|
381
397
|
channel_action = self.map_input_message(message, channel_websocket)
|
|
382
398
|
is_bot_speaking_after = call_state.is_bot_speaking
|
|
383
399
|
|
|
384
|
-
if not
|
|
400
|
+
if not was_bot_speaking_before and is_bot_speaking_after:
|
|
385
401
|
logger.debug("voice_channel.bot_started_speaking")
|
|
386
402
|
# relevant when the bot speaks multiple messages in one turn
|
|
387
403
|
self._cancel_silence_timeout_watcher()
|
|
388
404
|
|
|
389
405
|
# we just stopped speaking, starting a watcher for silence timeout
|
|
390
|
-
if
|
|
406
|
+
if was_bot_speaking_before and not is_bot_speaking_after:
|
|
391
407
|
logger.debug("voice_channel.bot_stopped_speaking")
|
|
392
408
|
self._cancel_silence_timeout_watcher()
|
|
393
409
|
call_state.silence_timeout_watcher = ( # type: ignore[attr-defined]
|
|
@@ -458,9 +474,9 @@ class VoiceInputChannel(InputChannel):
|
|
|
458
474
|
call_state.is_user_speaking = False # type: ignore[attr-defined]
|
|
459
475
|
output_channel = self.create_output_channel(voice_websocket, tts_engine)
|
|
460
476
|
message = UserMessage(
|
|
461
|
-
e.text,
|
|
462
|
-
output_channel,
|
|
463
|
-
call_parameters.stream_id,
|
|
477
|
+
text=e.text,
|
|
478
|
+
output_channel=output_channel,
|
|
479
|
+
sender_id=call_parameters.stream_id,
|
|
464
480
|
input_channel=self.name(),
|
|
465
481
|
metadata=asdict(call_parameters),
|
|
466
482
|
)
|
|
@@ -471,9 +487,9 @@ class VoiceInputChannel(InputChannel):
|
|
|
471
487
|
elif isinstance(e, UserSilence):
|
|
472
488
|
output_channel = self.create_output_channel(voice_websocket, tts_engine)
|
|
473
489
|
message = UserMessage(
|
|
474
|
-
USER_CONVERSATION_SILENCE_TIMEOUT,
|
|
475
|
-
output_channel,
|
|
476
|
-
call_parameters.stream_id,
|
|
490
|
+
text=USER_CONVERSATION_SILENCE_TIMEOUT,
|
|
491
|
+
output_channel=output_channel,
|
|
492
|
+
sender_id=call_parameters.stream_id,
|
|
477
493
|
input_channel=self.name(),
|
|
478
494
|
metadata=asdict(call_parameters),
|
|
479
495
|
)
|
rasa/core/http_interpreter.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import copy
|
|
2
1
|
import logging
|
|
3
2
|
from typing import Any, Dict, Optional, Text
|
|
4
3
|
|
|
@@ -49,7 +48,6 @@ class RasaNLUHttpInterpreter:
|
|
|
49
48
|
if not self.endpoint_config or self.endpoint_config.url is None:
|
|
50
49
|
structlogger.error(
|
|
51
50
|
"http.parse.text",
|
|
52
|
-
text=copy.deepcopy(text),
|
|
53
51
|
event_info="No rasa NLU server specified!",
|
|
54
52
|
)
|
|
55
53
|
return None
|
|
@@ -71,18 +69,16 @@ class RasaNLUHttpInterpreter:
|
|
|
71
69
|
if resp.status == 200:
|
|
72
70
|
return await resp.json()
|
|
73
71
|
else:
|
|
74
|
-
response_text = await resp.text()
|
|
75
72
|
structlogger.error(
|
|
76
73
|
"http.parse.text.failure",
|
|
77
|
-
|
|
78
|
-
response_text=copy.deepcopy(response_text),
|
|
74
|
+
event_info="Failed to parse text",
|
|
79
75
|
)
|
|
80
76
|
return None
|
|
81
|
-
except Exception: # skipcq: PYL-W0703
|
|
77
|
+
except Exception as e: # skipcq: PYL-W0703
|
|
82
78
|
# need to catch all possible exceptions when doing http requests
|
|
83
79
|
# (timeouts, value errors, parser errors, ...)
|
|
84
80
|
structlogger.exception(
|
|
85
81
|
"http.parse.text.exception",
|
|
86
|
-
text
|
|
82
|
+
event_info=f"Exception occurred while parsing text. Error: {e}",
|
|
87
83
|
)
|
|
88
84
|
return None
|
|
@@ -12,6 +12,7 @@ from rasa.core.information_retrieval import (
|
|
|
12
12
|
InformationRetrievalException,
|
|
13
13
|
SearchResultList,
|
|
14
14
|
)
|
|
15
|
+
from rasa.core.information_retrieval.ingestion.faq_parser import _format_faq_documents
|
|
15
16
|
from rasa.utils.endpoints import EndpointConfig
|
|
16
17
|
from rasa.utils.ml_utils import persist_faiss_vector_store
|
|
17
18
|
|
|
@@ -31,10 +32,12 @@ class FAISS_Store(InformationRetrieval):
|
|
|
31
32
|
index_path: str,
|
|
32
33
|
docs_folder: Optional[str],
|
|
33
34
|
create_index: Optional[bool] = False,
|
|
35
|
+
parse_as_faq_pairs: Optional[bool] = False,
|
|
34
36
|
):
|
|
35
37
|
"""Initializes the FAISS Store."""
|
|
36
38
|
self.chunk_size = 1000
|
|
37
39
|
self.chunk_overlap = 20
|
|
40
|
+
self.parse_as_faq_pairs = parse_as_faq_pairs
|
|
38
41
|
|
|
39
42
|
path = Path(index_path) / "documents_faiss"
|
|
40
43
|
if create_index:
|
|
@@ -86,21 +89,25 @@ class FAISS_Store(InformationRetrieval):
|
|
|
86
89
|
if not docs_folder:
|
|
87
90
|
raise ValueError("parameter `docs_folder` needs to be specified")
|
|
88
91
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
documents = self.load_documents(docs_folder)
|
|
93
|
+
|
|
94
|
+
if not self.parse_as_faq_pairs:
|
|
95
|
+
splitter = RecursiveCharacterTextSplitter(
|
|
96
|
+
chunk_size=self.chunk_size,
|
|
97
|
+
chunk_overlap=self.chunk_overlap,
|
|
98
|
+
length_function=len,
|
|
99
|
+
)
|
|
100
|
+
parsed_documents = splitter.split_documents(documents)
|
|
101
|
+
else:
|
|
102
|
+
parsed_documents = _format_faq_documents(documents)
|
|
96
103
|
|
|
97
104
|
logger.info(
|
|
98
105
|
"information_retrieval.faiss_store._create_document_index",
|
|
99
|
-
len_chunks=len(
|
|
106
|
+
len_chunks=len(parsed_documents),
|
|
100
107
|
)
|
|
101
|
-
if
|
|
102
|
-
texts = [
|
|
103
|
-
metadatas = [
|
|
108
|
+
if parsed_documents:
|
|
109
|
+
texts = [document.page_content for document in parsed_documents]
|
|
110
|
+
metadatas = [document.metadata for document in parsed_documents]
|
|
104
111
|
return FAISS.from_texts(texts, embedding, metadatas=metadatas, ids=None)
|
|
105
112
|
else:
|
|
106
113
|
raise ValueError(f"No documents found at '{docs_folder}'.")
|
|
File without changes
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""Utilities for parsing FAQ-style documents (Q/A pairs) used in extractive search."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from collections import defaultdict
|
|
5
|
+
from typing import TYPE_CHECKING, List
|
|
6
|
+
|
|
7
|
+
import structlog
|
|
8
|
+
|
|
9
|
+
from rasa.shared.constants import (
|
|
10
|
+
DOCUMENT_TYPE_FAQ,
|
|
11
|
+
FAQ_DOCUMENT_ENTRY_SEPARATOR,
|
|
12
|
+
FAQ_DOCUMENT_LINE_SEPARATOR,
|
|
13
|
+
FAQ_DOCUMENT_METADATA_ANSWER,
|
|
14
|
+
FAQ_DOCUMENT_METADATA_TITLE,
|
|
15
|
+
FAQ_DOCUMENT_METADATA_TYPE,
|
|
16
|
+
FAQ_INPUT_DATA_ANSWER_LINE_PREFIX,
|
|
17
|
+
FAQ_INPUT_DATA_QUESTION_LINE_PREFIX,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from langchain.schema import Document
|
|
22
|
+
|
|
23
|
+
_FAQ_PAIR_PATTERN = re.compile(
|
|
24
|
+
rf"{re.escape(FAQ_INPUT_DATA_QUESTION_LINE_PREFIX)}\s*"
|
|
25
|
+
rf"(?P<question>.*?)\s*{FAQ_DOCUMENT_LINE_SEPARATOR}\s*"
|
|
26
|
+
rf"{re.escape(FAQ_INPUT_DATA_ANSWER_LINE_PREFIX)}\s*"
|
|
27
|
+
rf"(?P<answer>.*)",
|
|
28
|
+
re.DOTALL,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
structlogger = structlog.get_logger()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _format_faq_documents(documents: List["Document"]) -> List["Document"]:
|
|
36
|
+
"""Splits each loaded file into individual FAQs.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
documents: Documents representing whole files containing FAQs.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
List of Document objects, each containing a separate FAQ.
|
|
43
|
+
|
|
44
|
+
Examples:
|
|
45
|
+
An example of a file containing FAQs:
|
|
46
|
+
|
|
47
|
+
Q: Who is Finley?
|
|
48
|
+
A: Finley is your smart assistant for the FinX App. You can add him to your
|
|
49
|
+
favorite messenger and tell him what you need help with.
|
|
50
|
+
|
|
51
|
+
Q: How does Finley work?
|
|
52
|
+
A: Finley is powered by the latest chatbot technology leveraging a unique
|
|
53
|
+
interplay of large language models and secure logic.
|
|
54
|
+
|
|
55
|
+
More details in documentation: https://rasa.com/docs/reference/config/policies/extractive-search/
|
|
56
|
+
"""
|
|
57
|
+
structured_faqs = []
|
|
58
|
+
from langchain.schema import Document
|
|
59
|
+
|
|
60
|
+
for document in documents:
|
|
61
|
+
chunks = document.page_content.strip().split(FAQ_DOCUMENT_ENTRY_SEPARATOR)
|
|
62
|
+
|
|
63
|
+
for chunk in chunks:
|
|
64
|
+
match = _FAQ_PAIR_PATTERN.match(chunk.strip())
|
|
65
|
+
|
|
66
|
+
if not match:
|
|
67
|
+
structlogger.warning(
|
|
68
|
+
"faq_parser.format_faq_documents.invalid_chunk_skipped",
|
|
69
|
+
event_info=(
|
|
70
|
+
"Chunk does not match expected QA format. "
|
|
71
|
+
"Please refer to the documentation: "
|
|
72
|
+
"https://rasa.com/docs/reference/config/"
|
|
73
|
+
"policies/extractive-search/"
|
|
74
|
+
),
|
|
75
|
+
chunk_preview=chunk[:100],
|
|
76
|
+
)
|
|
77
|
+
continue
|
|
78
|
+
|
|
79
|
+
question = match.group("question").strip()
|
|
80
|
+
answer = match.group("answer").strip()
|
|
81
|
+
title = _sanitize_title(question)
|
|
82
|
+
|
|
83
|
+
formatted_document = Document(
|
|
84
|
+
page_content=question,
|
|
85
|
+
metadata={
|
|
86
|
+
FAQ_DOCUMENT_METADATA_TITLE: title,
|
|
87
|
+
FAQ_DOCUMENT_METADATA_TYPE: DOCUMENT_TYPE_FAQ,
|
|
88
|
+
FAQ_DOCUMENT_METADATA_ANSWER: answer,
|
|
89
|
+
},
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
structured_faqs.append(formatted_document)
|
|
93
|
+
|
|
94
|
+
structlogger.debug(
|
|
95
|
+
"faq_parser.format_faq_documents.parsed_chunk",
|
|
96
|
+
event_info="Parsed chunk.",
|
|
97
|
+
title=title,
|
|
98
|
+
question=question,
|
|
99
|
+
answer=answer,
|
|
100
|
+
parsed_chunk_preview=chunk[:100],
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
structlogger.debug(
|
|
104
|
+
"faq_parser.format_faq_documents.parsed_chunks",
|
|
105
|
+
event_info=(
|
|
106
|
+
f"Retrieved {len(structured_faqs)} FAQ pair(s)"
|
|
107
|
+
f"from {len(documents)} document(s)."
|
|
108
|
+
),
|
|
109
|
+
num_structured_faqs=len(structured_faqs),
|
|
110
|
+
num_documents=len(documents),
|
|
111
|
+
)
|
|
112
|
+
_check_and_parsed_faq_documents_for_duplicates(structured_faqs)
|
|
113
|
+
return structured_faqs
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _sanitize_title(title: str) -> str:
|
|
117
|
+
title = title.lower()
|
|
118
|
+
# Remove all whitespaces with "_"
|
|
119
|
+
title = re.sub(r"\s+", "_", title)
|
|
120
|
+
# Remove all non alpha-numeric characters
|
|
121
|
+
title = re.sub(r"[^\w]", "", title)
|
|
122
|
+
# Collapse multiple "_"
|
|
123
|
+
title = re.sub(r"_+", "_", title)
|
|
124
|
+
# Clean up edges
|
|
125
|
+
return title.strip("_")
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _check_and_parsed_faq_documents_for_duplicates(documents: List["Document"]) -> None:
|
|
129
|
+
seen_qa_pairs = set()
|
|
130
|
+
seen_questions: defaultdict = defaultdict(list)
|
|
131
|
+
|
|
132
|
+
for doc in documents:
|
|
133
|
+
question = doc.page_content.strip()
|
|
134
|
+
answer = doc.metadata.get(FAQ_DOCUMENT_METADATA_ANSWER, "").strip()
|
|
135
|
+
|
|
136
|
+
if not question or not answer:
|
|
137
|
+
continue
|
|
138
|
+
|
|
139
|
+
if (question, answer) in seen_qa_pairs:
|
|
140
|
+
structlogger.warning(
|
|
141
|
+
"faq_parser.duplicate_qa_pair_found",
|
|
142
|
+
event_info="Duplicate QA pair found.",
|
|
143
|
+
question=question,
|
|
144
|
+
answer_preview=answer,
|
|
145
|
+
)
|
|
146
|
+
continue
|
|
147
|
+
|
|
148
|
+
if question in seen_questions and seen_questions[question] != answer:
|
|
149
|
+
structlogger.warning(
|
|
150
|
+
"faq_parser.inconsistent_answer",
|
|
151
|
+
event_info="Duplicate question with different answer found.",
|
|
152
|
+
question=question,
|
|
153
|
+
previous_answers=seen_questions[question],
|
|
154
|
+
new_answer=answer,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
seen_qa_pairs.add((question, answer))
|
|
158
|
+
seen_questions[question].append(answer)
|
rasa/core/jobs.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import logging
|
|
3
|
+
from typing import Optional
|
|
3
4
|
|
|
4
5
|
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
|
5
6
|
from pytz import UnknownTimeZoneError, utc
|
|
6
7
|
|
|
7
8
|
import rasa.shared.utils.io
|
|
8
9
|
|
|
9
|
-
__scheduler = None
|
|
10
|
+
__scheduler: Optional[AsyncIOScheduler] = None
|
|
10
11
|
|
|
11
12
|
logger = logging.getLogger(__name__)
|
|
12
13
|
|
|
@@ -5,7 +5,10 @@ from jinja2 import Template
|
|
|
5
5
|
|
|
6
6
|
from rasa import telemetry
|
|
7
7
|
from rasa.core.nlg.response import TemplatedNaturalLanguageGenerator
|
|
8
|
-
from rasa.core.nlg.summarize import
|
|
8
|
+
from rasa.core.nlg.summarize import (
|
|
9
|
+
_count_multiple_utterances_as_single_turn,
|
|
10
|
+
summarize_conversation,
|
|
11
|
+
)
|
|
9
12
|
from rasa.shared.constants import (
|
|
10
13
|
LLM_CONFIG_KEY,
|
|
11
14
|
MAX_COMPLETION_TOKENS_CONFIG_KEY,
|
|
@@ -14,6 +17,7 @@ from rasa.shared.constants import (
|
|
|
14
17
|
MODEL_NAME_CONFIG_KEY,
|
|
15
18
|
OPENAI_PROVIDER,
|
|
16
19
|
PROMPT_CONFIG_KEY,
|
|
20
|
+
PROMPT_TEMPLATE_CONFIG_KEY,
|
|
17
21
|
PROVIDER_CONFIG_KEY,
|
|
18
22
|
TEMPERATURE_CONFIG_KEY,
|
|
19
23
|
TIMEOUT_CONFIG_KEY,
|
|
@@ -35,6 +39,7 @@ from rasa.shared.utils.llm import (
|
|
|
35
39
|
DEFAULT_OPENAI_GENERATE_MODEL_NAME,
|
|
36
40
|
DEFAULT_OPENAI_MAX_GENERATED_TOKENS,
|
|
37
41
|
USER,
|
|
42
|
+
check_prompt_config_keys_and_warn_if_deprecated,
|
|
38
43
|
combine_custom_and_default_config,
|
|
39
44
|
get_prompt_template,
|
|
40
45
|
llm_factory,
|
|
@@ -55,6 +60,7 @@ RESPONSE_SUMMARISE_CONVERSATION_KEY = "summarize_conversation"
|
|
|
55
60
|
DEFAULT_REPHRASE_ALL = False
|
|
56
61
|
DEFAULT_SUMMARIZE_HISTORY = True
|
|
57
62
|
DEFAULT_MAX_HISTORICAL_TURNS = 5
|
|
63
|
+
DEFAULT_COUNT_MULTIPLE_UTTERANCES_AS_SINGLE_TURN = True
|
|
58
64
|
|
|
59
65
|
DEFAULT_LLM_CONFIG = {
|
|
60
66
|
PROVIDER_CONFIG_KEY: OPENAI_PROVIDER,
|
|
@@ -72,6 +78,7 @@ its meaning. Use simple {{language}}.
|
|
|
72
78
|
Context / previous conversation with the user:
|
|
73
79
|
{{history}}
|
|
74
80
|
|
|
81
|
+
Last user message:
|
|
75
82
|
{{current_input}}
|
|
76
83
|
|
|
77
84
|
Suggested AI Response: {{suggested_response}}
|
|
@@ -105,8 +112,15 @@ class ContextualResponseRephraser(
|
|
|
105
112
|
super().__init__(domain.responses)
|
|
106
113
|
|
|
107
114
|
self.nlg_endpoint = endpoint_config
|
|
115
|
+
|
|
116
|
+
# Warn if the prompt config key is used to set the prompt template
|
|
117
|
+
check_prompt_config_keys_and_warn_if_deprecated(
|
|
118
|
+
self.nlg_endpoint.kwargs, "contextual_response_rephraser"
|
|
119
|
+
)
|
|
120
|
+
|
|
108
121
|
self.prompt_template = get_prompt_template(
|
|
109
|
-
self.nlg_endpoint.kwargs.get(
|
|
122
|
+
self.nlg_endpoint.kwargs.get(PROMPT_TEMPLATE_CONFIG_KEY)
|
|
123
|
+
or self.nlg_endpoint.kwargs.get(PROMPT_CONFIG_KEY),
|
|
110
124
|
DEFAULT_RESPONSE_VARIATION_PROMPT_TEMPLATE,
|
|
111
125
|
log_source_component=ContextualResponseRephraser.__name__,
|
|
112
126
|
log_source_method=LOG_COMPONENT_SOURCE_METHOD_INIT,
|
|
@@ -124,6 +138,11 @@ class ContextualResponseRephraser(
|
|
|
124
138
|
"max_historical_turns", DEFAULT_MAX_HISTORICAL_TURNS
|
|
125
139
|
)
|
|
126
140
|
|
|
141
|
+
self.count_multiple_utterances_as_single_turn = self.nlg_endpoint.kwargs.get(
|
|
142
|
+
"count_multiple_utterances_as_single_turn",
|
|
143
|
+
DEFAULT_COUNT_MULTIPLE_UTTERANCES_AS_SINGLE_TURN,
|
|
144
|
+
)
|
|
145
|
+
|
|
127
146
|
self.llm_config = resolve_model_client_config(
|
|
128
147
|
self.nlg_endpoint.kwargs.get(LLM_CONFIG_KEY),
|
|
129
148
|
ContextualResponseRephraser.__name__,
|
|
@@ -260,8 +279,16 @@ class ContextualResponseRephraser(
|
|
|
260
279
|
Returns:
|
|
261
280
|
The history for the prompt.
|
|
262
281
|
"""
|
|
282
|
+
# Count multiple utterances by bot/user as single turn in conversation history
|
|
283
|
+
turns_wrapper = (
|
|
284
|
+
_count_multiple_utterances_as_single_turn
|
|
285
|
+
if self.count_multiple_utterances_as_single_turn
|
|
286
|
+
else None
|
|
287
|
+
)
|
|
263
288
|
llm = llm_factory(self.llm_config, DEFAULT_LLM_CONFIG)
|
|
264
|
-
return await summarize_conversation(
|
|
289
|
+
return await summarize_conversation(
|
|
290
|
+
tracker, llm, max_turns=5, turns_wrapper=turns_wrapper
|
|
291
|
+
)
|
|
265
292
|
|
|
266
293
|
async def rephrase(
|
|
267
294
|
self,
|
|
@@ -283,19 +310,26 @@ class ContextualResponseRephraser(
|
|
|
283
310
|
|
|
284
311
|
prompt_template_text = self._template_for_response_rephrasing(response)
|
|
285
312
|
|
|
286
|
-
#
|
|
287
|
-
|
|
288
|
-
current_input =
|
|
313
|
+
# Last user message (=current input) should always be in prompt if available
|
|
314
|
+
last_message_by_user = getattr(tracker.latest_message, "text", "")
|
|
315
|
+
current_input = (
|
|
316
|
+
f"{USER}: {last_message_by_user}" if last_message_by_user else ""
|
|
317
|
+
)
|
|
289
318
|
|
|
290
319
|
# Only summarise conversation history if flagged
|
|
291
320
|
if self.summarize_history:
|
|
292
321
|
history = await self._create_history(tracker)
|
|
293
322
|
else:
|
|
294
|
-
#
|
|
323
|
+
# Count multiple utterances by bot/user as single turn
|
|
324
|
+
turns_wrapper = (
|
|
325
|
+
_count_multiple_utterances_as_single_turn
|
|
326
|
+
if self.count_multiple_utterances_as_single_turn
|
|
327
|
+
else None
|
|
328
|
+
)
|
|
295
329
|
max_turns = max(self.max_historical_turns, 1)
|
|
296
|
-
history = tracker_as_readable_transcript(
|
|
297
|
-
|
|
298
|
-
|
|
330
|
+
history = tracker_as_readable_transcript(
|
|
331
|
+
tracker, max_turns=max_turns, turns_wrapper=turns_wrapper
|
|
332
|
+
)
|
|
299
333
|
|
|
300
334
|
prompt = Template(prompt_template_text).render(
|
|
301
335
|
history=history,
|
rasa/core/nlg/generator.py
CHANGED
|
@@ -292,7 +292,6 @@ def _evaluate_predicate(constraint: str, filled_slots: Dict[Text, Any]) -> bool:
|
|
|
292
292
|
structlogger.error(
|
|
293
293
|
"rasa.core.nlg.generator.evaluate_conditional_response_predicate.error",
|
|
294
294
|
predicate=constraint,
|
|
295
|
-
document=document,
|
|
296
295
|
error=str(e),
|
|
297
296
|
)
|
|
298
297
|
return False
|
rasa/core/nlg/interpolator.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import copy
|
|
2
1
|
import logging
|
|
3
2
|
import re
|
|
4
3
|
from typing import Any, Dict, List, Text, Union
|
|
@@ -70,9 +69,9 @@ def interpolate_format_template(response: Text, values: Dict[Text, Text]) -> Tex
|
|
|
70
69
|
)
|
|
71
70
|
structlogger.exception(
|
|
72
71
|
"interpolator.interpolate.text",
|
|
73
|
-
response=copy.deepcopy(response),
|
|
74
72
|
placeholder_key=e.args[0],
|
|
75
73
|
event_info=event_info,
|
|
74
|
+
error=str(e),
|
|
76
75
|
)
|
|
77
76
|
return response
|
|
78
77
|
|
|
@@ -98,9 +97,9 @@ def interpolate_jinja_template(response: Text, values: Dict[Text, Any]) -> Text:
|
|
|
98
97
|
)
|
|
99
98
|
structlogger.exception(
|
|
100
99
|
"interpolator.interpolate.text",
|
|
101
|
-
response=copy.deepcopy(response),
|
|
102
100
|
placeholder_key=e.args[0],
|
|
103
101
|
event_info=event_info,
|
|
102
|
+
error=str(e),
|
|
104
103
|
)
|
|
105
104
|
return response
|
|
106
105
|
|