rasa-pro 3.10.7.dev5__py3-none-any.whl → 3.10.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rasa-pro might be problematic. Click here for more details.
- README.md +37 -1
- rasa/api.py +2 -8
- rasa/cli/arguments/default_arguments.py +2 -23
- rasa/cli/arguments/run.py +0 -2
- rasa/cli/e2e_test.py +8 -10
- rasa/cli/inspect.py +2 -5
- rasa/cli/run.py +0 -7
- rasa/cli/studio/studio.py +21 -1
- rasa/cli/train.py +4 -9
- rasa/cli/utils.py +3 -3
- rasa/core/agent.py +2 -2
- rasa/core/brokers/kafka.py +1 -3
- rasa/core/brokers/pika.py +1 -3
- rasa/core/channels/socketio.py +1 -5
- rasa/core/channels/voice_aware/utils.py +5 -6
- rasa/core/nlg/contextual_response_rephraser.py +2 -11
- rasa/core/policies/enterprise_search_policy.py +2 -11
- rasa/core/policies/intentless_policy.py +2 -9
- rasa/core/run.py +1 -2
- rasa/core/secrets_manager/constants.py +0 -4
- rasa/core/secrets_manager/factory.py +0 -8
- rasa/core/secrets_manager/vault.py +1 -11
- rasa/core/utils.py +19 -30
- rasa/dialogue_understanding/coexistence/llm_based_router.py +2 -9
- rasa/dialogue_understanding/commands/__init__.py +2 -0
- rasa/dialogue_understanding/commands/restart_command.py +58 -0
- rasa/dialogue_understanding/commands/set_slot_command.py +5 -1
- rasa/dialogue_understanding/commands/utils.py +3 -1
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +2 -11
- rasa/dialogue_understanding/generator/llm_command_generator.py +1 -1
- rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +15 -15
- rasa/dialogue_understanding/patterns/restart.py +37 -0
- rasa/e2e_test/e2e_test_runner.py +1 -1
- rasa/engine/graph.py +1 -0
- rasa/engine/recipes/config_files/default_config.yml +3 -0
- rasa/engine/recipes/default_recipe.py +1 -0
- rasa/engine/recipes/graph_recipe.py +1 -0
- rasa/engine/storage/local_model_storage.py +1 -0
- rasa/engine/storage/storage.py +5 -1
- rasa/model_training.py +6 -11
- rasa/{core → nlu}/persistor.py +1 -1
- rasa/server.py +1 -1
- rasa/shared/constants.py +3 -2
- rasa/shared/core/domain.py +47 -101
- rasa/shared/core/flows/flows_list.py +6 -19
- rasa/shared/core/flows/validation.py +0 -25
- rasa/shared/core/flows/yaml_flows_io.py +24 -3
- rasa/shared/importers/importer.py +32 -32
- rasa/shared/importers/multi_project.py +11 -23
- rasa/shared/importers/rasa.py +2 -7
- rasa/shared/importers/remote_importer.py +2 -2
- rasa/shared/importers/utils.py +1 -3
- rasa/shared/nlu/training_data/training_data.py +19 -18
- rasa/shared/providers/_configs/azure_openai_client_config.py +5 -3
- rasa/shared/providers/llm/_base_litellm_client.py +26 -10
- rasa/shared/providers/llm/self_hosted_llm_client.py +15 -3
- rasa/shared/utils/common.py +22 -3
- rasa/shared/utils/llm.py +5 -29
- rasa/shared/utils/schemas/model_config.yml +10 -0
- rasa/studio/auth.py +4 -0
- rasa/tracing/instrumentation/attribute_extractors.py +1 -1
- rasa/validator.py +5 -2
- rasa/version.py +1 -1
- {rasa_pro-3.10.7.dev5.dist-info → rasa_pro-3.10.8.dist-info}/METADATA +43 -7
- {rasa_pro-3.10.7.dev5.dist-info → rasa_pro-3.10.8.dist-info}/RECORD +68 -74
- rasa/model_manager/__init__.py +0 -0
- rasa/model_manager/config.py +0 -12
- rasa/model_manager/model_api.py +0 -467
- rasa/model_manager/runner_service.py +0 -185
- rasa/model_manager/socket_bridge.py +0 -44
- rasa/model_manager/trainer_service.py +0 -240
- rasa/model_manager/utils.py +0 -27
- rasa/model_service.py +0 -66
- {rasa_pro-3.10.7.dev5.dist-info → rasa_pro-3.10.8.dist-info}/NOTICE +0 -0
- {rasa_pro-3.10.7.dev5.dist-info → rasa_pro-3.10.8.dist-info}/WHEEL +0 -0
- {rasa_pro-3.10.7.dev5.dist-info → rasa_pro-3.10.8.dist-info}/entry_points.txt +0 -0
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from typing import Any, Dict, Optional
|
|
3
|
-
import shutil
|
|
4
|
-
import base64
|
|
5
|
-
import structlog
|
|
6
|
-
import subprocess
|
|
7
|
-
from dataclasses import dataclass
|
|
8
|
-
|
|
9
|
-
from rasa.model_manager.config import RASA_PYTHON_PATH, SERVER_BASE_WORKING_DIRECTORY
|
|
10
|
-
from rasa.model_manager.utils import logs_path
|
|
11
|
-
|
|
12
|
-
structlogger = structlog.get_logger()
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@dataclass
|
|
16
|
-
class TrainingSession:
|
|
17
|
-
"""Store information about a training session."""
|
|
18
|
-
|
|
19
|
-
training_id: str
|
|
20
|
-
assistant_id: str
|
|
21
|
-
client_id: Optional[str]
|
|
22
|
-
progress: int
|
|
23
|
-
status: str
|
|
24
|
-
process: subprocess.Popen
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def train_path(training_id: str) -> str:
|
|
28
|
-
"""Return the path to the training directory for a given training id."""
|
|
29
|
-
return os.path.abspath(f"{SERVER_BASE_WORKING_DIRECTORY}/trainings/{training_id}")
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def cache_for_assistant_path(assistant_id: str) -> str:
|
|
33
|
-
"""Return the path to the cache directory for a given assistant id."""
|
|
34
|
-
return os.path.abspath(f"{SERVER_BASE_WORKING_DIRECTORY}/caches/{assistant_id}")
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def write_encoded_data_to_file(encoded_data: bytes, file: str) -> None:
|
|
38
|
-
"""Write base64 encoded data to a file."""
|
|
39
|
-
# create the directory if it does not exist of the parent directory
|
|
40
|
-
os.makedirs(os.path.dirname(file), exist_ok=True)
|
|
41
|
-
|
|
42
|
-
with open(file, "w") as f:
|
|
43
|
-
decoded = base64.b64decode(encoded_data)
|
|
44
|
-
text = decoded.decode("utf-8")
|
|
45
|
-
f.write(text)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def terminate_training(training: TrainingSession) -> None:
|
|
49
|
-
if training.status == "running":
|
|
50
|
-
structlogger.info(
|
|
51
|
-
"model_trainer.user_stopping_training", training_id=training.training_id
|
|
52
|
-
)
|
|
53
|
-
try:
|
|
54
|
-
training.process.terminate()
|
|
55
|
-
training.status = "stopped"
|
|
56
|
-
except ProcessLookupError:
|
|
57
|
-
structlogger.debug(
|
|
58
|
-
"model_trainer.training_process_not_found",
|
|
59
|
-
training_id=training.training_id,
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def update_training_status(training: TrainingSession) -> None:
|
|
64
|
-
if training.status != "running":
|
|
65
|
-
# skip if the training is not running
|
|
66
|
-
return
|
|
67
|
-
if training.process.poll() is None:
|
|
68
|
-
# process is still running
|
|
69
|
-
return
|
|
70
|
-
|
|
71
|
-
complete_training(training)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def complete_training(training: TrainingSession) -> None:
|
|
75
|
-
"""Complete a training session.
|
|
76
|
-
|
|
77
|
-
Transitions the status of a training process to "done" if the process has
|
|
78
|
-
finished successfully, and to "error" if the process has finished with an
|
|
79
|
-
error.
|
|
80
|
-
"""
|
|
81
|
-
training.status = "done" if training.process.returncode == 0 else "error"
|
|
82
|
-
training.progress = 100
|
|
83
|
-
|
|
84
|
-
structlogger.info(
|
|
85
|
-
"model_trainer.training_finished",
|
|
86
|
-
training_id=training.training_id,
|
|
87
|
-
status=training.status,
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
# persist the assistant cache to speed up future training runs for this
|
|
91
|
-
# assistant
|
|
92
|
-
persist_rasa_cache(training.assistant_id, train_path(training.training_id))
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
def seed_training_directory_with_rasa_cache(
|
|
96
|
-
training_base_path: str, assistant_id: str
|
|
97
|
-
) -> None:
|
|
98
|
-
"""Populate the training directory with the cache of a previous training."""
|
|
99
|
-
# check if there is a cache for this assistant
|
|
100
|
-
cache_path = cache_for_assistant_path(assistant_id)
|
|
101
|
-
|
|
102
|
-
if os.path.exists(cache_path):
|
|
103
|
-
structlogger.debug(
|
|
104
|
-
"model_trainer.populating_training_dir_with_cache",
|
|
105
|
-
assistant_id=assistant_id,
|
|
106
|
-
training_base_path=training_base_path,
|
|
107
|
-
)
|
|
108
|
-
# copy the cache to the training directory
|
|
109
|
-
shutil.copytree(cache_path, f"{training_base_path}/.rasa")
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def persist_rasa_cache(assistant_id: str, training_base_path: str) -> None:
|
|
113
|
-
"""Persist the cache of a training session to speed up future trainings."""
|
|
114
|
-
# copy the cache from the training directory to the cache directory
|
|
115
|
-
# cache files are stored inside of `/.rasa/` of the training folder
|
|
116
|
-
structlogger.debug(
|
|
117
|
-
"model_trainer.persisting_assistant_cache", assistant_id=assistant_id
|
|
118
|
-
)
|
|
119
|
-
cache_path = cache_for_assistant_path(assistant_id)
|
|
120
|
-
# clean up the cache directory first
|
|
121
|
-
shutil.rmtree(cache_path, ignore_errors=True)
|
|
122
|
-
shutil.copytree(f"{training_base_path}/.rasa", cache_path)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def write_training_data_to_files(
|
|
126
|
-
encoded_training_data: Dict[str, Any], training_base_path: str
|
|
127
|
-
) -> None:
|
|
128
|
-
"""Write the training data to files in the training directory.
|
|
129
|
-
|
|
130
|
-
Incoming data format, all keys being optional:
|
|
131
|
-
````
|
|
132
|
-
{
|
|
133
|
-
"domain": "base64 encoded domain.yml",
|
|
134
|
-
"credentials": "base64 encoded credentials.yml",
|
|
135
|
-
"endpoints": "base64 encoded endpoints.yml",
|
|
136
|
-
"flows": "base64 encoded flows.yml",
|
|
137
|
-
"config": "base64 encoded config.yml",
|
|
138
|
-
"stories": "base64 encoded stories.yml",
|
|
139
|
-
"rules": "base64 encoded rules.yml",
|
|
140
|
-
"nlu": "base64 encoded nlu.yml"
|
|
141
|
-
}
|
|
142
|
-
```
|
|
143
|
-
"""
|
|
144
|
-
data_to_be_written_to_files = {
|
|
145
|
-
"domain": "domain.yml",
|
|
146
|
-
"credentials": "credentials.yml",
|
|
147
|
-
"endpoints": "endpoints.yml",
|
|
148
|
-
"flows": "data/flows.yml",
|
|
149
|
-
"config": "config.yml",
|
|
150
|
-
"stories": "data/stories.yml",
|
|
151
|
-
"rules": "data/rules.yml",
|
|
152
|
-
"nlu": "data/nlu.yml",
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
for key, file in data_to_be_written_to_files.items():
|
|
156
|
-
write_encoded_data_to_file(
|
|
157
|
-
encoded_training_data.get(key, ""),
|
|
158
|
-
f"{training_base_path}/{file}",
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def prepare_training_directory(
|
|
163
|
-
training_base_path: str, assistant_id: str, data: Dict[str, Any]
|
|
164
|
-
) -> None:
|
|
165
|
-
"""Prepare the training directory for a new training session."""
|
|
166
|
-
encoded_training_data = data.get("bot_config", {}).get("data", {})
|
|
167
|
-
|
|
168
|
-
# create a new working directory and store the training data from the
|
|
169
|
-
# request there. the training data in the request is base64 encoded
|
|
170
|
-
os.makedirs(training_base_path, exist_ok=True)
|
|
171
|
-
|
|
172
|
-
seed_training_directory_with_rasa_cache(training_base_path, assistant_id)
|
|
173
|
-
write_training_data_to_files(encoded_training_data, training_base_path)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
def start_training_process(
|
|
177
|
-
training_id: str, assistant_id: str, client_id: str, training_base_path: str
|
|
178
|
-
) -> TrainingSession:
|
|
179
|
-
log_path = logs_path(training_id)
|
|
180
|
-
|
|
181
|
-
# Start the training in a subprocess
|
|
182
|
-
# set the working directory to the training directory
|
|
183
|
-
# run the rasa train command as a subprocess, activating poetry before running
|
|
184
|
-
# pipe the stdout and stderr to the same file
|
|
185
|
-
process = subprocess.Popen(
|
|
186
|
-
[
|
|
187
|
-
RASA_PYTHON_PATH,
|
|
188
|
-
"-m",
|
|
189
|
-
"rasa.__main__",
|
|
190
|
-
"train",
|
|
191
|
-
"--debug",
|
|
192
|
-
"--out",
|
|
193
|
-
f"{training_base_path}/models",
|
|
194
|
-
"--data",
|
|
195
|
-
f"{training_base_path}/data",
|
|
196
|
-
"--config",
|
|
197
|
-
f"{training_base_path}/config.yml",
|
|
198
|
-
"--domain",
|
|
199
|
-
f"{training_base_path}/domain.yml",
|
|
200
|
-
"--endpoints",
|
|
201
|
-
f"{training_base_path}/endpoints.yml",
|
|
202
|
-
],
|
|
203
|
-
cwd=training_base_path,
|
|
204
|
-
stdout=open(log_path, "w"),
|
|
205
|
-
stderr=subprocess.STDOUT,
|
|
206
|
-
env=os.environ.copy(),
|
|
207
|
-
)
|
|
208
|
-
|
|
209
|
-
structlogger.info(
|
|
210
|
-
"model_trainer.training_started",
|
|
211
|
-
training_id=training_id,
|
|
212
|
-
assistant_id=assistant_id,
|
|
213
|
-
client_id=client_id,
|
|
214
|
-
log=log_path,
|
|
215
|
-
pid=process.pid,
|
|
216
|
-
)
|
|
217
|
-
|
|
218
|
-
return TrainingSession(
|
|
219
|
-
training_id=training_id,
|
|
220
|
-
assistant_id=assistant_id,
|
|
221
|
-
client_id=client_id,
|
|
222
|
-
progress=0,
|
|
223
|
-
status="running",
|
|
224
|
-
process=process, # Store the process handle
|
|
225
|
-
)
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
def run_training(
|
|
229
|
-
training_id: str, assistant_id: str, client_id: str, data: Dict
|
|
230
|
-
) -> TrainingSession:
|
|
231
|
-
"""Run a training session."""
|
|
232
|
-
training_base_path = train_path(training_id)
|
|
233
|
-
|
|
234
|
-
prepare_training_directory(training_base_path, assistant_id, data)
|
|
235
|
-
return start_training_process(
|
|
236
|
-
training_id=training_id,
|
|
237
|
-
assistant_id=assistant_id,
|
|
238
|
-
client_id=client_id,
|
|
239
|
-
training_base_path=training_base_path,
|
|
240
|
-
)
|
rasa/model_manager/utils.py
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
|
|
3
|
-
from rasa.model_manager.config import SERVER_BASE_WORKING_DIRECTORY
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def logs_base_path() -> str:
|
|
7
|
-
"""Return the path to the logs directory."""
|
|
8
|
-
return os.path.abspath(f"{SERVER_BASE_WORKING_DIRECTORY}/logs")
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def models_base_path() -> str:
|
|
12
|
-
"""Return the path to the models directory."""
|
|
13
|
-
return os.path.abspath(f"{SERVER_BASE_WORKING_DIRECTORY}/models")
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def logs_path(action_id: str) -> str:
|
|
17
|
-
"""Return the path to the log file for a given action id.
|
|
18
|
-
|
|
19
|
-
Args:
|
|
20
|
-
action_id: can either be a training_id or a deployment_id
|
|
21
|
-
"""
|
|
22
|
-
return os.path.abspath(f"{logs_base_path()}/{action_id}.txt")
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def models_path(training_id: str) -> str:
|
|
26
|
-
"""Return the path to the models directory for a given training id."""
|
|
27
|
-
return os.path.abspath(f"{models_base_path()}/{training_id}")
|
rasa/model_service.py
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import logging
|
|
3
|
-
|
|
4
|
-
from sanic import Sanic
|
|
5
|
-
import structlog
|
|
6
|
-
|
|
7
|
-
from rasa.core.utils import list_routes
|
|
8
|
-
from rasa.model_manager import model_api
|
|
9
|
-
from rasa.model_manager.config import SERVER_BASE_URL
|
|
10
|
-
from rasa.utils.common import configure_logging_and_warnings
|
|
11
|
-
import rasa.utils.licensing
|
|
12
|
-
|
|
13
|
-
structlogger = structlog.get_logger()
|
|
14
|
-
|
|
15
|
-
MODEL_SERVICE_PORT = 8000
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def url_prefix_from_base_url() -> str:
|
|
19
|
-
"""Return the path prefix from the base URL."""
|
|
20
|
-
if SERVER_BASE_URL:
|
|
21
|
-
from urllib.parse import urlparse
|
|
22
|
-
|
|
23
|
-
return urlparse(SERVER_BASE_URL).path
|
|
24
|
-
|
|
25
|
-
return ""
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def main() -> None:
|
|
29
|
-
"""Start the Rasa Model Manager server.
|
|
30
|
-
|
|
31
|
-
The API server can receive requests to train models, run bots, and manage
|
|
32
|
-
the lifecycle of models and bots.
|
|
33
|
-
"""
|
|
34
|
-
model_api.prepare_working_directories()
|
|
35
|
-
|
|
36
|
-
configure_logging_and_warnings(
|
|
37
|
-
log_level=logging.DEBUG,
|
|
38
|
-
logging_config_file=None,
|
|
39
|
-
warn_only_once=True,
|
|
40
|
-
filter_repeated_logs=True,
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
rasa.utils.licensing.validate_license_from_env()
|
|
44
|
-
# assert that an openai api key is set
|
|
45
|
-
assert (
|
|
46
|
-
"OPENAI_API_KEY" in os.environ
|
|
47
|
-
), "Please set the OPENAI_API_KEY environment variable"
|
|
48
|
-
|
|
49
|
-
structlogger.debug("model_training.starting_server", port=MODEL_SERVICE_PORT)
|
|
50
|
-
structlogger.debug("model_running.starting_server", port=MODEL_SERVICE_PORT)
|
|
51
|
-
|
|
52
|
-
url_prefix = url_prefix_from_base_url()
|
|
53
|
-
# configure the sanice application
|
|
54
|
-
app = Sanic("RasaModelService")
|
|
55
|
-
app.add_task(model_api.continuously_update_process_status)
|
|
56
|
-
app.blueprint(model_api.external_blueprint(), url_prefix=url_prefix)
|
|
57
|
-
app.blueprint(model_api.internal_blueprint())
|
|
58
|
-
|
|
59
|
-
# list all routes
|
|
60
|
-
list_routes(app)
|
|
61
|
-
|
|
62
|
-
app.run(host="0.0.0.0", port=MODEL_SERVICE_PORT, legacy=True)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if __name__ == "__main__":
|
|
66
|
-
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|