rasa-pro 3.12.12__py3-none-any.whl → 3.12.13__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/api.py +4 -0
- rasa/cli/arguments/default_arguments.py +13 -1
- rasa/cli/arguments/train.py +2 -0
- rasa/cli/train.py +1 -0
- rasa/constants.py +2 -0
- rasa/core/persistor.py +55 -20
- rasa/core/run.py +7 -2
- rasa/dialogue_understanding/commands/clarify_command.py +2 -2
- rasa/dialogue_understanding/generator/llm_based_command_generator.py +1 -1
- rasa/model_manager/config.py +3 -1
- rasa/model_manager/model_api.py +1 -2
- rasa/model_manager/runner_service.py +8 -4
- rasa/model_manager/trainer_service.py +1 -0
- rasa/model_training.py +12 -3
- rasa/server.py +6 -2
- rasa/version.py +1 -1
- {rasa_pro-3.12.12.dist-info → rasa_pro-3.12.13.dist-info}/METADATA +1 -1
- {rasa_pro-3.12.12.dist-info → rasa_pro-3.12.13.dist-info}/RECORD +21 -21
- {rasa_pro-3.12.12.dist-info → rasa_pro-3.12.13.dist-info}/NOTICE +0 -0
- {rasa_pro-3.12.12.dist-info → rasa_pro-3.12.13.dist-info}/WHEEL +0 -0
- {rasa_pro-3.12.12.dist-info → rasa_pro-3.12.13.dist-info}/entry_points.txt +0 -0
rasa/api.py
CHANGED
|
@@ -81,6 +81,7 @@ def train(
|
|
|
81
81
|
remote_storage: Optional[StorageType] = None,
|
|
82
82
|
file_importer: Optional["TrainingDataImporter"] = None,
|
|
83
83
|
keep_local_model_copy: bool = False,
|
|
84
|
+
remote_root_only: bool = False,
|
|
84
85
|
) -> "TrainingResult":
|
|
85
86
|
"""Runs Rasa Core and NLU training in `async` loop.
|
|
86
87
|
|
|
@@ -108,6 +109,8 @@ def train(
|
|
|
108
109
|
If it is not provided, a new instance will be created.
|
|
109
110
|
keep_local_model_copy: If `True` the model will be stored locally even if
|
|
110
111
|
remote storage is configured.
|
|
112
|
+
remote_root_only: If `True`, the model will be stored in the root of the
|
|
113
|
+
remote model storage.
|
|
111
114
|
|
|
112
115
|
Returns:
|
|
113
116
|
An instance of `TrainingResult`.
|
|
@@ -131,6 +134,7 @@ def train(
|
|
|
131
134
|
remote_storage=remote_storage,
|
|
132
135
|
file_importer=file_importer,
|
|
133
136
|
keep_local_model_copy=keep_local_model_copy,
|
|
137
|
+
remote_root_only=remote_root_only,
|
|
134
138
|
)
|
|
135
139
|
)
|
|
136
140
|
|
|
@@ -172,7 +172,7 @@ def add_remote_storage_param(
|
|
|
172
172
|
) -> None:
|
|
173
173
|
parser.add_argument(
|
|
174
174
|
"--remote-storage",
|
|
175
|
-
help="Remote storage which should be used to store/load the model."
|
|
175
|
+
help="Remote storage which should be used to store/load the model. "
|
|
176
176
|
f"Supported storages are: {RemoteStorageType.list()}. "
|
|
177
177
|
"You can also provide your own implementation of the `Persistor` interface.",
|
|
178
178
|
required=required,
|
|
@@ -180,6 +180,18 @@ def add_remote_storage_param(
|
|
|
180
180
|
)
|
|
181
181
|
|
|
182
182
|
|
|
183
|
+
def add_remote_root_only_param(
|
|
184
|
+
parser: argparse.ArgumentParser, required: bool = False
|
|
185
|
+
) -> None:
|
|
186
|
+
parser.add_argument(
|
|
187
|
+
"--remote-root-only",
|
|
188
|
+
action="store_true",
|
|
189
|
+
help="If set, models will be stored only at the root directory "
|
|
190
|
+
"of the remote storage.",
|
|
191
|
+
required=required,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
183
195
|
def parse_remote_storage_arg(value: str) -> StorageType:
|
|
184
196
|
try:
|
|
185
197
|
return parse_remote_storage(value)
|
rasa/cli/arguments/train.py
CHANGED
|
@@ -7,6 +7,7 @@ from rasa.cli.arguments.default_arguments import (
|
|
|
7
7
|
add_endpoint_param,
|
|
8
8
|
add_nlu_data_param,
|
|
9
9
|
add_out_param,
|
|
10
|
+
add_remote_root_only_param,
|
|
10
11
|
add_remote_storage_param,
|
|
11
12
|
add_stories_param,
|
|
12
13
|
)
|
|
@@ -41,6 +42,7 @@ def set_train_arguments(parser: argparse.ArgumentParser) -> None:
|
|
|
41
42
|
parser, help_text="Configuration file for the connectors as a yml file."
|
|
42
43
|
)
|
|
43
44
|
add_remote_storage_param(parser)
|
|
45
|
+
add_remote_root_only_param(parser)
|
|
44
46
|
|
|
45
47
|
|
|
46
48
|
def set_train_core_arguments(parser: argparse.ArgumentParser) -> None:
|
rasa/cli/train.py
CHANGED
|
@@ -155,6 +155,7 @@ def run_training(args: argparse.Namespace, can_exit: bool = False) -> Optional[T
|
|
|
155
155
|
remote_storage=args.remote_storage,
|
|
156
156
|
file_importer=training_data_importer,
|
|
157
157
|
keep_local_model_copy=args.keep_local_model_copy,
|
|
158
|
+
remote_root_only=args.remote_root_only,
|
|
158
159
|
)
|
|
159
160
|
if training_result.code != 0 and can_exit:
|
|
160
161
|
display_research_study_prompt()
|
rasa/constants.py
CHANGED
rasa/core/persistor.py
CHANGED
|
@@ -121,10 +121,12 @@ def get_persistor(storage: StorageType) -> Optional[Persistor]:
|
|
|
121
121
|
class Persistor(abc.ABC):
|
|
122
122
|
"""Store models in cloud and fetch them when needed."""
|
|
123
123
|
|
|
124
|
-
def persist(self, trained_model: str) -> None:
|
|
124
|
+
def persist(self, trained_model: str, remote_root_only: bool = False) -> None:
|
|
125
125
|
"""Uploads a trained model persisted in the `target_dir` to cloud storage."""
|
|
126
126
|
absolute_file_key = self._create_file_key(trained_model)
|
|
127
|
-
file_key =
|
|
127
|
+
file_key = (
|
|
128
|
+
Path(absolute_file_key).name if remote_root_only else absolute_file_key
|
|
129
|
+
)
|
|
128
130
|
self._persist_tar(file_key, trained_model)
|
|
129
131
|
|
|
130
132
|
def retrieve(self, model_name: Text, target_path: Text) -> Text:
|
|
@@ -143,30 +145,32 @@ class Persistor(abc.ABC):
|
|
|
143
145
|
# ensure backward compatibility
|
|
144
146
|
tar_name = self._tar_name(model_name)
|
|
145
147
|
tar_name = self._create_file_key(tar_name)
|
|
146
|
-
|
|
147
|
-
self._retrieve_tar(target_filename)
|
|
148
|
-
self._copy(os.path.basename(tar_name), target_path)
|
|
148
|
+
self._retrieve_tar(tar_name, target_path)
|
|
149
149
|
|
|
150
150
|
if os.path.isdir(target_path):
|
|
151
151
|
return os.path.join(target_path, model_name)
|
|
152
152
|
|
|
153
153
|
return target_path
|
|
154
154
|
|
|
155
|
-
def size_of_persisted_model(
|
|
155
|
+
def size_of_persisted_model(
|
|
156
|
+
self, model_name: Text, target_path: Optional[str] = None
|
|
157
|
+
) -> int:
|
|
156
158
|
"""Returns the size of the model that has been persisted to cloud storage.
|
|
157
159
|
|
|
158
160
|
Args:
|
|
159
161
|
model_name: The name of the model to retrieve.
|
|
162
|
+
target_path: The path to which the model should be saved.
|
|
160
163
|
"""
|
|
161
164
|
tar_name = model_name
|
|
162
165
|
if not model_name.endswith(MODEL_ARCHIVE_EXTENSION):
|
|
163
166
|
# ensure backward compatibility
|
|
164
167
|
tar_name = self._tar_name(model_name)
|
|
165
168
|
tar_name = self._create_file_key(tar_name)
|
|
166
|
-
|
|
167
|
-
return self._retrieve_tar_size(target_filename)
|
|
169
|
+
return self._retrieve_tar_size(tar_name, target_path)
|
|
168
170
|
|
|
169
|
-
def _retrieve_tar_size(
|
|
171
|
+
def _retrieve_tar_size(
|
|
172
|
+
self, filename: Text, target_path: Optional[str] = None
|
|
173
|
+
) -> int:
|
|
170
174
|
"""Returns the size of the model that has been persisted to cloud storage."""
|
|
171
175
|
structlogger.warning(
|
|
172
176
|
"persistor.retrieve_tar_size.not_implemented",
|
|
@@ -179,11 +183,11 @@ class Persistor(abc.ABC):
|
|
|
179
183
|
"size directly from the cloud storage."
|
|
180
184
|
),
|
|
181
185
|
)
|
|
182
|
-
self._retrieve_tar(filename)
|
|
186
|
+
self._retrieve_tar(filename, target_path)
|
|
183
187
|
return os.path.getsize(os.path.basename(filename))
|
|
184
188
|
|
|
185
189
|
@abc.abstractmethod
|
|
186
|
-
def _retrieve_tar(self, filename:
|
|
190
|
+
def _retrieve_tar(self, filename: str, target_path: Optional[str] = None) -> None:
|
|
187
191
|
"""Downloads a model previously persisted to cloud storage."""
|
|
188
192
|
raise NotImplementedError
|
|
189
193
|
|
|
@@ -302,7 +306,9 @@ class AWSPersistor(Persistor):
|
|
|
302
306
|
with open(tar_path, "rb") as f:
|
|
303
307
|
self.s3.Object(self.bucket_name, file_key).put(Body=f)
|
|
304
308
|
|
|
305
|
-
def _retrieve_tar_size(
|
|
309
|
+
def _retrieve_tar_size(
|
|
310
|
+
self, model_path: Text, target_path: Optional[str] = None
|
|
311
|
+
) -> int:
|
|
306
312
|
"""Returns the size of the model that has been persisted to s3."""
|
|
307
313
|
try:
|
|
308
314
|
obj = self.s3.Object(self.bucket_name, model_path)
|
|
@@ -310,7 +316,9 @@ class AWSPersistor(Persistor):
|
|
|
310
316
|
except Exception:
|
|
311
317
|
raise ModelNotFound()
|
|
312
318
|
|
|
313
|
-
def _retrieve_tar(
|
|
319
|
+
def _retrieve_tar(
|
|
320
|
+
self, target_filename: str, target_path: Optional[str] = None
|
|
321
|
+
) -> None:
|
|
314
322
|
"""Downloads a model that has previously been persisted to s3."""
|
|
315
323
|
from botocore import exceptions
|
|
316
324
|
|
|
@@ -320,8 +328,14 @@ class AWSPersistor(Persistor):
|
|
|
320
328
|
f"in the bucket."
|
|
321
329
|
)
|
|
322
330
|
|
|
331
|
+
tar_name = (
|
|
332
|
+
os.path.join(target_path, os.path.basename(target_filename))
|
|
333
|
+
if target_path
|
|
334
|
+
else os.path.basename(target_filename)
|
|
335
|
+
)
|
|
336
|
+
|
|
323
337
|
try:
|
|
324
|
-
with open(
|
|
338
|
+
with open(tar_name, "wb") as f:
|
|
325
339
|
self.bucket.download_fileobj(target_filename, f)
|
|
326
340
|
|
|
327
341
|
structlogger.debug(
|
|
@@ -425,7 +439,9 @@ class GCSPersistor(Persistor):
|
|
|
425
439
|
blob = self.bucket.blob(file_key)
|
|
426
440
|
blob.upload_from_filename(tar_path)
|
|
427
441
|
|
|
428
|
-
def _retrieve_tar_size(
|
|
442
|
+
def _retrieve_tar_size(
|
|
443
|
+
self, target_filename: Text, target_path: Optional[str] = None
|
|
444
|
+
) -> int:
|
|
429
445
|
"""Returns the size of the model that has been persisted to GCS."""
|
|
430
446
|
try:
|
|
431
447
|
blob = self.bucket.blob(target_filename)
|
|
@@ -433,13 +449,22 @@ class GCSPersistor(Persistor):
|
|
|
433
449
|
except Exception:
|
|
434
450
|
raise ModelNotFound()
|
|
435
451
|
|
|
436
|
-
def _retrieve_tar(
|
|
452
|
+
def _retrieve_tar(
|
|
453
|
+
self, target_filename: str, target_path: Optional[str] = None
|
|
454
|
+
) -> None:
|
|
437
455
|
"""Downloads a model that has previously been persisted to GCS."""
|
|
438
456
|
from google.api_core import exceptions
|
|
439
457
|
|
|
440
458
|
blob = self.bucket.blob(target_filename)
|
|
459
|
+
|
|
460
|
+
destination = (
|
|
461
|
+
os.path.join(target_path, os.path.basename(target_filename))
|
|
462
|
+
if target_path
|
|
463
|
+
else target_filename
|
|
464
|
+
)
|
|
465
|
+
|
|
441
466
|
try:
|
|
442
|
-
blob.download_to_filename(
|
|
467
|
+
blob.download_to_filename(destination)
|
|
443
468
|
|
|
444
469
|
structlogger.debug(
|
|
445
470
|
"gcs_persistor.retrieve_tar.object_found", object_key=target_filename
|
|
@@ -500,7 +525,9 @@ class AzurePersistor(Persistor):
|
|
|
500
525
|
with open(tar_path, "rb") as data:
|
|
501
526
|
self._container_client().upload_blob(name=file_key, data=data)
|
|
502
527
|
|
|
503
|
-
def _retrieve_tar_size(
|
|
528
|
+
def _retrieve_tar_size(
|
|
529
|
+
self, target_filename: Text, target_path: Optional[str] = None
|
|
530
|
+
) -> int:
|
|
504
531
|
"""Returns the size of the model that has been persisted to Azure."""
|
|
505
532
|
try:
|
|
506
533
|
blob_client = self._container_client().get_blob_client(target_filename)
|
|
@@ -509,12 +536,20 @@ class AzurePersistor(Persistor):
|
|
|
509
536
|
except Exception:
|
|
510
537
|
raise ModelNotFound()
|
|
511
538
|
|
|
512
|
-
def _retrieve_tar(
|
|
539
|
+
def _retrieve_tar(
|
|
540
|
+
self, target_filename: Text, target_path: Optional[str] = None
|
|
541
|
+
) -> None:
|
|
513
542
|
"""Downloads a model that has previously been persisted to Azure."""
|
|
514
543
|
from azure.core.exceptions import AzureError
|
|
515
544
|
|
|
545
|
+
destination = (
|
|
546
|
+
os.path.join(target_path, os.path.basename(target_filename))
|
|
547
|
+
if target_path
|
|
548
|
+
else target_filename
|
|
549
|
+
)
|
|
550
|
+
|
|
516
551
|
try:
|
|
517
|
-
with open(
|
|
552
|
+
with open(destination, "wb") as model_file:
|
|
518
553
|
blob_client = self._container_client().get_blob_client(target_filename)
|
|
519
554
|
download_stream = blob_client.download_blob()
|
|
520
555
|
model_file.write(download_stream.readall())
|
rasa/core/run.py
CHANGED
|
@@ -86,13 +86,15 @@ def _create_single_channel(channel: Text, credentials: Dict[Text, Any]) -> Any:
|
|
|
86
86
|
)
|
|
87
87
|
|
|
88
88
|
|
|
89
|
-
def _create_app_without_api(
|
|
89
|
+
def _create_app_without_api(
|
|
90
|
+
cors: Optional[Union[Text, List[Text]]] = None, is_inspector_enabled: bool = False
|
|
91
|
+
) -> Sanic:
|
|
90
92
|
app = Sanic("rasa_core_no_api", configure_logging=False)
|
|
91
93
|
|
|
92
94
|
# Reset Sanic warnings filter that allows the triggering of Sanic warnings
|
|
93
95
|
warnings.filterwarnings("ignore", category=DeprecationWarning, module=r"sanic.*")
|
|
94
96
|
|
|
95
|
-
server.add_root_route(app)
|
|
97
|
+
server.add_root_route(app, is_inspector_enabled)
|
|
96
98
|
server.configure_cors(app, cors)
|
|
97
99
|
return app
|
|
98
100
|
|
|
@@ -127,6 +129,7 @@ def configure_app(
|
|
|
127
129
|
server_listeners: Optional[List[Tuple[Callable, Text]]] = None,
|
|
128
130
|
use_uvloop: Optional[bool] = True,
|
|
129
131
|
keep_alive_timeout: int = constants.DEFAULT_KEEP_ALIVE_TIMEOUT,
|
|
132
|
+
is_inspector_enabled: bool = False,
|
|
130
133
|
) -> Sanic:
|
|
131
134
|
"""Run the agent."""
|
|
132
135
|
rasa.core.utils.configure_file_logging(
|
|
@@ -144,6 +147,7 @@ def configure_app(
|
|
|
144
147
|
jwt_private_key=jwt_private_key,
|
|
145
148
|
jwt_method=jwt_method,
|
|
146
149
|
endpoints=endpoints,
|
|
150
|
+
is_inspector_enabled=is_inspector_enabled,
|
|
147
151
|
)
|
|
148
152
|
)
|
|
149
153
|
else:
|
|
@@ -259,6 +263,7 @@ def serve_application(
|
|
|
259
263
|
syslog_protocol=syslog_protocol,
|
|
260
264
|
request_timeout=request_timeout,
|
|
261
265
|
server_listeners=server_listeners,
|
|
266
|
+
is_inspector_enabled=inspect,
|
|
262
267
|
)
|
|
263
268
|
|
|
264
269
|
ssl_context = server.create_ssl_context(
|
|
@@ -117,9 +117,9 @@ class ClarifyCommand(Command):
|
|
|
117
117
|
@staticmethod
|
|
118
118
|
def regex_pattern() -> str:
|
|
119
119
|
mapper = {
|
|
120
|
-
CommandSyntaxVersion.v1: r"Clarify\(([\"\'a-zA-Z0-9_, ]*)\)",
|
|
120
|
+
CommandSyntaxVersion.v1: r"Clarify\(([\"\'a-zA-Z0-9_, -]*)\)",
|
|
121
121
|
CommandSyntaxVersion.v2: (
|
|
122
|
-
r"""^[\s\W\d]*disambiguate flows (["'a-zA-Z0-9_, ]*)['"`]*$"""
|
|
122
|
+
r"""^[\s\W\d]*disambiguate flows (["'a-zA-Z0-9_, -]*)['"`]*$"""
|
|
123
123
|
),
|
|
124
124
|
}
|
|
125
125
|
return mapper.get(
|
|
@@ -528,7 +528,7 @@ class LLMBasedCommandGenerator(
|
|
|
528
528
|
either contain a StartFlowCommand or a SetSlot command
|
|
529
529
|
for the current collect step.
|
|
530
530
|
"""
|
|
531
|
-
return self.config.get(KEY_MINIMIZE_NUM_CALLS,
|
|
531
|
+
return self.config.get(KEY_MINIMIZE_NUM_CALLS, True) and (
|
|
532
532
|
self._prior_commands_contain_start_flow(prior_commands)
|
|
533
533
|
or self._prior_commands_contain_set_slot_for_active_collect_step(
|
|
534
534
|
prior_commands, flows, tracker
|
rasa/model_manager/config.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import sys
|
|
3
3
|
|
|
4
|
+
from rasa.constants import RASA_REMOTE_STORAGE_ENV_VAR_NAME
|
|
5
|
+
|
|
4
6
|
DEFAULT_SERVER_BASE_WORKING_DIRECTORY = "working-data"
|
|
5
7
|
|
|
6
8
|
SERVER_BASE_WORKING_DIRECTORY = os.environ.get(
|
|
@@ -12,7 +14,7 @@ SERVER_PORT = os.environ.get("RASA_MODEL_SERVER_PORT", 8000)
|
|
|
12
14
|
SERVER_BASE_URL = os.environ.get("RASA_MODEL_SERVER_BASE_URL", None)
|
|
13
15
|
|
|
14
16
|
# defaults to storing on the local hard drive
|
|
15
|
-
SERVER_MODEL_REMOTE_STORAGE = os.environ.get(
|
|
17
|
+
SERVER_MODEL_REMOTE_STORAGE = os.environ.get(RASA_REMOTE_STORAGE_ENV_VAR_NAME, None)
|
|
16
18
|
|
|
17
19
|
# The path to the python executable that is running this script
|
|
18
20
|
# we will use the same python to run training / bots
|
rasa/model_manager/model_api.py
CHANGED
|
@@ -532,8 +532,7 @@ def size_of_model(model_name: str) -> Optional[int]:
|
|
|
532
532
|
model_name=model_file_name,
|
|
533
533
|
)
|
|
534
534
|
return fetch_size_of_remote_model(
|
|
535
|
-
model_file_name,
|
|
536
|
-
config.SERVER_MODEL_REMOTE_STORAGE,
|
|
535
|
+
model_file_name, config.SERVER_MODEL_REMOTE_STORAGE, model_path
|
|
537
536
|
)
|
|
538
537
|
raise ModelNotFound("Model not found.")
|
|
539
538
|
|
|
@@ -166,13 +166,13 @@ def fetch_remote_model_to_dir(
|
|
|
166
166
|
) -> str:
|
|
167
167
|
"""Fetch the model from remote storage.
|
|
168
168
|
|
|
169
|
-
Returns the path to the model
|
|
169
|
+
Returns the path to the model directory.
|
|
170
170
|
"""
|
|
171
171
|
from rasa.core.persistor import get_persistor
|
|
172
172
|
|
|
173
173
|
persistor = get_persistor(storage_type)
|
|
174
174
|
|
|
175
|
-
# we
|
|
175
|
+
# we know there must be a persistor, because the config is set
|
|
176
176
|
# this is here to please the type checker for the call below
|
|
177
177
|
assert persistor is not None
|
|
178
178
|
|
|
@@ -182,7 +182,9 @@ def fetch_remote_model_to_dir(
|
|
|
182
182
|
raise ModelNotFound() from e
|
|
183
183
|
|
|
184
184
|
|
|
185
|
-
def fetch_size_of_remote_model(
|
|
185
|
+
def fetch_size_of_remote_model(
|
|
186
|
+
model_name: str, storage_type: str, model_path: str
|
|
187
|
+
) -> int:
|
|
186
188
|
"""Fetch the size of the model from remote storage."""
|
|
187
189
|
from rasa.core.persistor import get_persistor
|
|
188
190
|
|
|
@@ -192,7 +194,9 @@ def fetch_size_of_remote_model(model_name: str, storage_type: str) -> int:
|
|
|
192
194
|
# this is here to please the type checker for the call below
|
|
193
195
|
assert persistor is not None
|
|
194
196
|
|
|
195
|
-
return persistor.size_of_persisted_model(
|
|
197
|
+
return persistor.size_of_persisted_model(
|
|
198
|
+
model_name=model_name, target_path=model_path
|
|
199
|
+
)
|
|
196
200
|
|
|
197
201
|
|
|
198
202
|
def start_bot_process(
|
rasa/model_training.py
CHANGED
|
@@ -160,6 +160,7 @@ async def train(
|
|
|
160
160
|
remote_storage: Optional[StorageType] = None,
|
|
161
161
|
file_importer: Optional[TrainingDataImporter] = None,
|
|
162
162
|
keep_local_model_copy: bool = False,
|
|
163
|
+
remote_root_only: bool = False,
|
|
163
164
|
) -> TrainingResult:
|
|
164
165
|
"""Trains a Rasa model (Core and NLU).
|
|
165
166
|
|
|
@@ -187,6 +188,8 @@ async def train(
|
|
|
187
188
|
If it is not provided, a new instance will be created.
|
|
188
189
|
keep_local_model_copy: If `True` the model will be stored locally even if
|
|
189
190
|
remote storage is configured.
|
|
191
|
+
remote_root_only: If `True`, the model will be stored in the root of the
|
|
192
|
+
remote model storage.
|
|
190
193
|
|
|
191
194
|
Returns:
|
|
192
195
|
An instance of `TrainingResult`.
|
|
@@ -269,6 +272,7 @@ async def train(
|
|
|
269
272
|
dry_run=dry_run,
|
|
270
273
|
remote_storage=remote_storage,
|
|
271
274
|
keep_local_model_copy=keep_local_model_copy,
|
|
275
|
+
remote_root_only=remote_root_only,
|
|
272
276
|
**(core_additional_arguments or {}),
|
|
273
277
|
**(nlu_additional_arguments or {}),
|
|
274
278
|
)
|
|
@@ -284,6 +288,7 @@ async def _train_graph(
|
|
|
284
288
|
dry_run: bool = False,
|
|
285
289
|
remote_storage: Optional[StorageType] = None,
|
|
286
290
|
keep_local_model_copy: bool = False,
|
|
291
|
+
remote_root_only: bool = False,
|
|
287
292
|
**kwargs: Any,
|
|
288
293
|
) -> TrainingResult:
|
|
289
294
|
if model_to_finetune:
|
|
@@ -363,7 +368,9 @@ async def _train_graph(
|
|
|
363
368
|
is_finetuning=is_finetuning,
|
|
364
369
|
)
|
|
365
370
|
if remote_storage:
|
|
366
|
-
push_model_to_remote_storage(
|
|
371
|
+
push_model_to_remote_storage(
|
|
372
|
+
full_model_path, remote_storage, remote_root_only
|
|
373
|
+
)
|
|
367
374
|
if not keep_local_model_copy:
|
|
368
375
|
full_model_path.unlink()
|
|
369
376
|
structlogger.info(
|
|
@@ -581,14 +588,16 @@ async def train_nlu(
|
|
|
581
588
|
).model
|
|
582
589
|
|
|
583
590
|
|
|
584
|
-
def push_model_to_remote_storage(
|
|
591
|
+
def push_model_to_remote_storage(
|
|
592
|
+
model_path: Path, remote_storage: StorageType, remote_root_only: bool = False
|
|
593
|
+
) -> None:
|
|
585
594
|
"""Push model to remote storage."""
|
|
586
595
|
from rasa.core.persistor import get_persistor
|
|
587
596
|
|
|
588
597
|
persistor = get_persistor(remote_storage)
|
|
589
598
|
|
|
590
599
|
if persistor is not None:
|
|
591
|
-
persistor.persist(str(model_path))
|
|
600
|
+
persistor.persist(str(model_path), remote_root_only)
|
|
592
601
|
|
|
593
602
|
else:
|
|
594
603
|
raise RasaException(
|
rasa/server.py
CHANGED
|
@@ -522,12 +522,15 @@ def configure_cors(
|
|
|
522
522
|
)
|
|
523
523
|
|
|
524
524
|
|
|
525
|
-
def add_root_route(app: Sanic) -> None:
|
|
525
|
+
def add_root_route(app: Sanic, is_inspector_enabled: bool = False) -> None:
|
|
526
526
|
"""Add '/' route to return hello."""
|
|
527
527
|
|
|
528
528
|
@app.get("/")
|
|
529
529
|
async def hello(request: Request) -> HTTPResponse:
|
|
530
530
|
"""Check if the server is running and responds with the version."""
|
|
531
|
+
if not is_inspector_enabled:
|
|
532
|
+
return response.text("Hello from Rasa: " + rasa.__version__)
|
|
533
|
+
|
|
531
534
|
html_content = f"""
|
|
532
535
|
<html>
|
|
533
536
|
<body>
|
|
@@ -688,6 +691,7 @@ def create_app(
|
|
|
688
691
|
jwt_private_key: Optional[Text] = None,
|
|
689
692
|
jwt_method: Text = "HS256",
|
|
690
693
|
endpoints: Optional[AvailableEndpoints] = None,
|
|
694
|
+
is_inspector_enabled: bool = False,
|
|
691
695
|
) -> Sanic:
|
|
692
696
|
"""Class representing a Rasa HTTP server."""
|
|
693
697
|
app = Sanic("rasa_server")
|
|
@@ -733,7 +737,7 @@ def create_app(
|
|
|
733
737
|
) -> HTTPResponse:
|
|
734
738
|
return response.json(exception.error_info, status=exception.status)
|
|
735
739
|
|
|
736
|
-
add_root_route(app)
|
|
740
|
+
add_root_route(app, is_inspector_enabled)
|
|
737
741
|
|
|
738
742
|
@app.get("/version")
|
|
739
743
|
async def version(request: Request) -> HTTPResponse:
|
rasa/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: rasa-pro
|
|
3
|
-
Version: 3.12.
|
|
3
|
+
Version: 3.12.13
|
|
4
4
|
Summary: State-of-the-art open-core Conversational AI framework for Enterprises that natively leverages generative AI for effortless assistant development.
|
|
5
5
|
Keywords: nlp,machine-learning,machine-learning-library,bot,bots,botkit,rasa conversational-agents,conversational-ai,chatbot,chatbot-framework,bot-framework
|
|
6
6
|
Author: Rasa Technologies GmbH
|
|
@@ -7,18 +7,18 @@ rasa/anonymization/anonymization_rule_executor.py,sha256=1O_QAqrChpZ-uBzgipv5MTw
|
|
|
7
7
|
rasa/anonymization/anonymization_rule_orchestrator.py,sha256=hoKAL36w9Eaa-b2Im2kNAYpXqndZYIwqssva9nEflRQ,4115
|
|
8
8
|
rasa/anonymization/schemas/config.yml,sha256=EP_af8HctyRT2f6Ywv9khpO58ZdP5_LkPItrXQgdNaU,1158
|
|
9
9
|
rasa/anonymization/utils.py,sha256=y9i2tnlyG5ofNrNYGSCWl17wBYvEmTgw2zgoQ--p-vA,3623
|
|
10
|
-
rasa/api.py,sha256=
|
|
10
|
+
rasa/api.py,sha256=X46dHY75l4iLg5zlifb0KwkCT2Lkcs2VIXoz_5VkxGU,6306
|
|
11
11
|
rasa/cli/__init__.py,sha256=eO5vp9rFCANtbTVU-pxN3iMBKw4p9WRcgzytt9MzinY,115
|
|
12
12
|
rasa/cli/arguments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
rasa/cli/arguments/data.py,sha256=e3mYapaRIczM74P5genuXy1ORqIR4x20khQXUvy8JLA,3040
|
|
14
|
-
rasa/cli/arguments/default_arguments.py,sha256=
|
|
14
|
+
rasa/cli/arguments/default_arguments.py,sha256=p4fKzh0wXsh8mIfLEQnu-pNOhDngViFamcE75fh5fPw,6863
|
|
15
15
|
rasa/cli/arguments/evaluate.py,sha256=Pd8ot5ndV5eKl1H_9fxWKWNlmYtZEjziMucI_zSADWA,2200
|
|
16
16
|
rasa/cli/arguments/export.py,sha256=1wjypmlat3-2rqlL3vAAlZ2UjudR0yktIHFH-oUKil4,1499
|
|
17
17
|
rasa/cli/arguments/interactive.py,sha256=CNxeW-VykltT8QlxLq8JxBcKJ-1U7LbbLXJac1q2mn0,2685
|
|
18
18
|
rasa/cli/arguments/run.py,sha256=3hNSEXvHgOV0ylrcLHNZnAPFotl8Hrwb64D3_XMpllA,6765
|
|
19
19
|
rasa/cli/arguments/shell.py,sha256=c74UgQu_tcfJ40CJ0Hb1vUEkjmUeDSw2O9UsNzfSCBw,443
|
|
20
20
|
rasa/cli/arguments/test.py,sha256=A8kbTJkm8k0_tf_R4qIqw5M9WD-fBmLf0wmAFXpRWGA,6837
|
|
21
|
-
rasa/cli/arguments/train.py,sha256=
|
|
21
|
+
rasa/cli/arguments/train.py,sha256=BkQg7UE8_-Ey7Nwm6UCTXmLFVry0wgkNALOjYmvNqK4,8954
|
|
22
22
|
rasa/cli/arguments/visualize.py,sha256=e8yhvc6Jfy1JKSOIVFV5mY5QPowkf0o1kt6IGujVxcY,861
|
|
23
23
|
rasa/cli/arguments/x.py,sha256=_23reqNwiit2VoCqmv23kQZudA3iZVXaBV_zEXJjV6w,1028
|
|
24
24
|
rasa/cli/data.py,sha256=J_L9E0LnNJj6HjiJZkUok0VIhEzjk4Gf5DnXGaTA8nI,13305
|
|
@@ -85,11 +85,11 @@ rasa/cli/studio/train.py,sha256=PyD3KdcM2QliFo6hH9FGYz6iV7tXbS5liiE3aV6jElA,1571
|
|
|
85
85
|
rasa/cli/studio/upload.py,sha256=1-cqlCI7GMoGD9nmstO2wlqj3nhksSBOFIUJhNsbRB8,1705
|
|
86
86
|
rasa/cli/telemetry.py,sha256=mNMMbcgnNPZzeF1k-khN-7lAQFnkFx75VBwtnPfPI6k,3538
|
|
87
87
|
rasa/cli/test.py,sha256=JfzBh1_TAOnd346jVikSK94bTlUA-BLSAQ7XBRvL2TQ,8901
|
|
88
|
-
rasa/cli/train.py,sha256=
|
|
88
|
+
rasa/cli/train.py,sha256=fMt-HyLB7hmYa8LqdvukMMXRqP_DrE9R_oYoW2l6AVE,9348
|
|
89
89
|
rasa/cli/utils.py,sha256=kNm5aWB7w4plHgdKVT2MkhtNXuTAJ3qgqfgC8ORXNl8,16850
|
|
90
90
|
rasa/cli/visualize.py,sha256=YmRAATAfxHpgE8_PknGyM-oIujwICNzVftTzz6iLNNc,1256
|
|
91
91
|
rasa/cli/x.py,sha256=C7dLtYXAkD-uj7hNj7Pz5YbOupp2yRcMjQbsEVqXUJ8,6825
|
|
92
|
-
rasa/constants.py,sha256=
|
|
92
|
+
rasa/constants.py,sha256=5OMUcJ_gjn8qglY37DeUS4g5xe2VZAiLIv8IKwIGWJ0,1364
|
|
93
93
|
rasa/core/__init__.py,sha256=wTSmsFlgK0Ylvuyq20q9APwpT5xyVJYZfzhs4rrkciM,456
|
|
94
94
|
rasa/core/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
95
95
|
rasa/core/actions/action.py,sha256=_QfY3ngSF2sf2Y3QDPJo7Nd6F_FA6_zDWgw1OQSLkEk,42676
|
|
@@ -324,7 +324,7 @@ rasa/core/nlg/interpolator.py,sha256=hEOhqfMXrAqTZiqjg2t6ZfTK6DJQ5IiX4tJIz2b8Fbw
|
|
|
324
324
|
rasa/core/nlg/response.py,sha256=SecKyoBQjEnZr4t-Gg5fkUpkozwGT2lzswIKgD63Dac,7248
|
|
325
325
|
rasa/core/nlg/summarize.py,sha256=liXcbJMBm0NaaSH0LwlSs1l0dTby0OEprSzeKeyRyv0,2109
|
|
326
326
|
rasa/core/nlg/translate.py,sha256=ZXRvysqXGdtHBJ7x3YkW6zfmnb9DuEGHCMTL41v-M8M,2112
|
|
327
|
-
rasa/core/persistor.py,sha256=
|
|
327
|
+
rasa/core/persistor.py,sha256=7LCZHAwCM-xrUI38aaJ5dkxJvLdJXWI1TEUKsBo4_EE,21295
|
|
328
328
|
rasa/core/policies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
329
329
|
rasa/core/policies/ensemble.py,sha256=XoHxU0jcb_io_LBOpjJffylzqtGEB7CH9ivhRyO8pDc,12960
|
|
330
330
|
rasa/core/policies/enterprise_search_policy.py,sha256=mPiqAplOfe5MtgEzoF6TclVnlA4QgpMqXJsKuBGFv3o,37011
|
|
@@ -343,7 +343,7 @@ rasa/core/policies/rule_policy.py,sha256=EItfUn07JIBLRIbriPKDprsvWq_-xzZTGrlTS2e
|
|
|
343
343
|
rasa/core/policies/ted_policy.py,sha256=0RzIuyrtt4PxLcqQ-bfaExkZvU-TnsMbgmDcwh2SakY,87710
|
|
344
344
|
rasa/core/policies/unexpected_intent_policy.py,sha256=ZXvbswf2NDy00kHmBQcyXa1OVYFyc79HQKrFkQ4gCfM,39609
|
|
345
345
|
rasa/core/processor.py,sha256=sUEKKDFHw0uDw8BgorN4DFQa5f_kVbOS344qV4F0oDk,59821
|
|
346
|
-
rasa/core/run.py,sha256=
|
|
346
|
+
rasa/core/run.py,sha256=N-NVdo-2wlKbaC1O1lS0t2Uraw9GjJYgZa0MkMPLdlg,11685
|
|
347
347
|
rasa/core/secrets_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
348
348
|
rasa/core/secrets_manager/constants.py,sha256=dTDHenvG1JBVi34QIR6FpdO5RDOXQwAjAxLlgJ2ZNEI,1193
|
|
349
349
|
rasa/core/secrets_manager/endpoints.py,sha256=4b7KXB9amdF23eYGsx8215bOjE5-TQ73qD2hdI8Sm9c,12662
|
|
@@ -372,7 +372,7 @@ rasa/dialogue_understanding/commands/can_not_handle_command.py,sha256=fKOj9ScLxu
|
|
|
372
372
|
rasa/dialogue_understanding/commands/cancel_flow_command.py,sha256=7Jcvza6OBT8vM7bwJlTCujKsCMrC8gxR0DE6uaIb5_0,5340
|
|
373
373
|
rasa/dialogue_understanding/commands/change_flow_command.py,sha256=NnD9PM0B9o4oxTtYdcb-lDBC0-oQkbAQRB-55iYCkng,2409
|
|
374
374
|
rasa/dialogue_understanding/commands/chit_chat_answer_command.py,sha256=PtwNuAHJdIUQ_PIOv5bguVJMyZ_2jPtoozQQdiebKB4,2842
|
|
375
|
-
rasa/dialogue_understanding/commands/clarify_command.py,sha256=
|
|
375
|
+
rasa/dialogue_understanding/commands/clarify_command.py,sha256=BpJ2CQHaA7ck6Vh5WKD7v4m7MOA_Kie-DSBoHR8oVbk,4291
|
|
376
376
|
rasa/dialogue_understanding/commands/command.py,sha256=rhxHmllTMwvb4Uq-pDqmUdlKtu-87y8nqN5DRO-KDwE,2529
|
|
377
377
|
rasa/dialogue_understanding/commands/command_syntax_manager.py,sha256=vO6sOak0g9GucEtiNximJ9bQFbHQwWJ-M5XNF1gGxz4,1893
|
|
378
378
|
rasa/dialogue_understanding/commands/correct_slots_command.py,sha256=LlaBtWc3y-DyDPMF-zGG9x_J9uCe78LqiuogHIyoz5Q,10810
|
|
@@ -400,7 +400,7 @@ rasa/dialogue_understanding/generator/command_parser.py,sha256=wf6FSgqBw5F0legg0
|
|
|
400
400
|
rasa/dialogue_understanding/generator/constants.py,sha256=PuUckBGUZ-Tu31B0cs8yxN99BDW3PGoExZa-BlIL5v8,1108
|
|
401
401
|
rasa/dialogue_understanding/generator/flow_document_template.jinja2,sha256=f4H6vVd-_nX_RtutMh1xD3ZQE_J2OyuPHAtiltfiAPY,253
|
|
402
402
|
rasa/dialogue_understanding/generator/flow_retrieval.py,sha256=DavL-37e0tksMWkxvFImoqlsmYeYeSdDN3u7wZI0K-8,17817
|
|
403
|
-
rasa/dialogue_understanding/generator/llm_based_command_generator.py,sha256=
|
|
403
|
+
rasa/dialogue_understanding/generator/llm_based_command_generator.py,sha256=P1Hwjt8ph2oQQ2PzWaaBRcU36ia4mN21nTzhLtEF5Wc,23586
|
|
404
404
|
rasa/dialogue_understanding/generator/llm_command_generator.py,sha256=z7jhIJ3W_5GFH-p15kVoWbigMIoY8fIJjc_j_uX7yxw,2581
|
|
405
405
|
rasa/dialogue_understanding/generator/multi_step/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
406
406
|
rasa/dialogue_understanding/generator/multi_step/fill_slots_prompt.jinja2,sha256=Y0m673tAML3cFPaLM-urMXDsBYUUcXIw9YUpkAhGUuA,2933
|
|
@@ -553,17 +553,17 @@ rasa/markers/upload.py,sha256=ie9jBznH7SWHrexv7G8tuwcMSShCdRzuWPIY1t4WFKA,2518
|
|
|
553
553
|
rasa/markers/validate.py,sha256=dZvMTcDK_sji9OP8JY4kUcjeIScLF93C3CKTWK8DplI,708
|
|
554
554
|
rasa/model.py,sha256=cAbQXvfZXBKHAj79Z0-mCy29hSSWp2KaroScgDeTfJw,3489
|
|
555
555
|
rasa/model_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
556
|
-
rasa/model_manager/config.py,sha256=
|
|
557
|
-
rasa/model_manager/model_api.py,sha256=
|
|
558
|
-
rasa/model_manager/runner_service.py,sha256=
|
|
556
|
+
rasa/model_manager/config.py,sha256=8upZP4CokMBy0imiiPvINJuLW4JOQ326dPiJ041jJUI,1231
|
|
557
|
+
rasa/model_manager/model_api.py,sha256=ZF36UxVEj9OCAbNparNajqh5-66_w0Ngxq7Htw8Fe8U,20275
|
|
558
|
+
rasa/model_manager/runner_service.py,sha256=yTvnO249vUOEySkdr7_aLOblQOOa38WyiVr1ATeLqN0,8874
|
|
559
559
|
rasa/model_manager/socket_bridge.py,sha256=luU0EzzuM77jthUZUWobW2dMocz-TM_DGrfUSUTqozk,5554
|
|
560
560
|
rasa/model_manager/studio_jwt_auth.py,sha256=uls2QiHUlUrR3fOzZssW4UaAMJMfnPMZeV1aDmZIT0E,2645
|
|
561
|
-
rasa/model_manager/trainer_service.py,sha256=
|
|
561
|
+
rasa/model_manager/trainer_service.py,sha256=ANs1DQ6wK9RjTN93RcQVaGQ1wta1KyyY680vPp1PZr8,10358
|
|
562
562
|
rasa/model_manager/utils.py,sha256=rS0ST-rJMuZOna90r_Ioz7gOkZ8r8vm4XAhzI0iUZOA,2643
|
|
563
563
|
rasa/model_manager/warm_rasa_process.py,sha256=2vg8gBEUvPrr6C5W-fxtWWSajksrOaT83CTk6S4KCkg,5843
|
|
564
564
|
rasa/model_service.py,sha256=XXCaiLj2xq58n05W3R1jmTIv-V8f_7PG30kVpRxf71Y,3727
|
|
565
565
|
rasa/model_testing.py,sha256=eZw7l8Zz3HkH_ZPBurY93HzzudHdoQn8HBnDdZSysAY,14929
|
|
566
|
-
rasa/model_training.py,sha256=
|
|
566
|
+
rasa/model_training.py,sha256=10cw_CIN3q05gmTHqUdLgsfSlmyWPL0dSkrkflYbOmA,22071
|
|
567
567
|
rasa/nlu/__init__.py,sha256=D0IYuTK_ZQ_F_9xsy0bXxVCAtU62Fzvp8S7J9tmfI_c,123
|
|
568
568
|
rasa/nlu/classifiers/__init__.py,sha256=Qvrf7_rfiMxm2Vt2fClb56R3QFExf7WPdFdL-AOvgsk,118
|
|
569
569
|
rasa/nlu/classifiers/classifier.py,sha256=9fm1mORuFf1vowYIXmqE9yLRKdSC4nGQW7UqNZQipKY,133
|
|
@@ -623,7 +623,7 @@ rasa/nlu/utils/mitie_utils.py,sha256=xf2EoOX8nu--t9f7lZ8bFpDtgJweUTey3aOI1R5vGvQ
|
|
|
623
623
|
rasa/nlu/utils/pattern_utils.py,sha256=5Efoc6tpcVmoirAZuCNGNh0QjIs7tUxxk2PfLyPxZAM,5386
|
|
624
624
|
rasa/nlu/utils/spacy_utils.py,sha256=5EnHR-MVAZhGbg2rq8VpOu7I0tagV3ThRTlM0-WO2Cg,11794
|
|
625
625
|
rasa/plugin.py,sha256=cSmFhSWr5WQyYXdJOWwgH4ra_2kbhoNLZAtnqcsGny4,3071
|
|
626
|
-
rasa/server.py,sha256=
|
|
626
|
+
rasa/server.py,sha256=0GQ9rML75EOuRDpUHZjz-uYbkSbnNuK0SRIGQJeiR-I,59599
|
|
627
627
|
rasa/shared/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
628
628
|
rasa/shared/constants.py,sha256=PBpmxNQM29MoLp1pY7RGQ1I1hPt3N0_r2l_y5KguEnQ,12129
|
|
629
629
|
rasa/shared/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -822,9 +822,9 @@ rasa/utils/train_utils.py,sha256=ClJx-6x3-h3Vt6mskacgkcCUJTMXjFPe3zAcy_DfmaU,212
|
|
|
822
822
|
rasa/utils/url_tools.py,sha256=dZ1HGkVdWTJB7zYEdwoDIrEuyX9HE5WsxKKFVsXBLE0,1218
|
|
823
823
|
rasa/utils/yaml.py,sha256=KjbZq5C94ZP7Jdsw8bYYF7HASI6K4-C_kdHfrnPLpSI,2000
|
|
824
824
|
rasa/validator.py,sha256=524VlFTYK0B3iXYveVD6BDC3K0j1QfpzJ9O-TAWczmc,83166
|
|
825
|
-
rasa/version.py,sha256=
|
|
826
|
-
rasa_pro-3.12.
|
|
827
|
-
rasa_pro-3.12.
|
|
828
|
-
rasa_pro-3.12.
|
|
829
|
-
rasa_pro-3.12.
|
|
830
|
-
rasa_pro-3.12.
|
|
825
|
+
rasa/version.py,sha256=xvjgzcMusQj7hAVj2HW5HXv63_EHazJDfb-XQzGy9RU,118
|
|
826
|
+
rasa_pro-3.12.13.dist-info/METADATA,sha256=Ol4uriGrH7UxdD7N3Z3Se-9eBZGOm2szhKZCuBJP6VY,10609
|
|
827
|
+
rasa_pro-3.12.13.dist-info/NOTICE,sha256=7HlBoMHJY9CL2GlYSfTQ-PZsVmLmVkYmMiPlTjhuCqA,218
|
|
828
|
+
rasa_pro-3.12.13.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
|
829
|
+
rasa_pro-3.12.13.dist-info/entry_points.txt,sha256=ckJ2SfEyTPgBqj_I6vm_tqY9dZF_LAPJZA335Xp0Q9U,43
|
|
830
|
+
rasa_pro-3.12.13.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|