thestage 0.6.7__py3-none-any.whl → 0.7.0__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.
- thestage/__init__.py +1 -1
- thestage/cli_command.py +3 -0
- thestage/cli_command_helper.py +2 -2
- thestage/config/__init__.py +1 -1
- thestage/{services → config/business}/app_config_service.py +3 -4
- thestage/{services/config_provider → config/business}/config_provider.py +6 -5
- thestage/config/{config_storage.py → business/config_storage.py} +1 -1
- thestage/{services → config/business}/validation_service.py +9 -10
- thestage/{controllers/config_controller.py → config/communication/config_command.py} +7 -7
- thestage/{services/connect → connect/business}/connect_service.py +22 -19
- thestage/{services → connect/business}/remote_server_service.py +4 -5
- thestage/connect/communication/connect_api_client.py +84 -0
- thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_key_to_user_response.py +0 -1
- thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_public_key_to_instance_response.py +1 -4
- thestage/{services/clients/thestage_api/dtos/base_controller → connect/dto}/connect_resolve_response.py +0 -1
- thestage/controllers/base_controller.py +2 -2
- thestage/debug_main.dist.py +16 -14
- thestage/{services/container → docker_container/business}/container_service.py +147 -22
- thestage/{services/container → docker_container/business}/mapper/container_mapper.py +3 -3
- thestage/docker_container/business/mapper/image_mapper.py +16 -0
- thestage/docker_container/communication/__init__.py +0 -0
- thestage/{controllers/container_controller.py → docker_container/communication/docker_command.py} +192 -29
- thestage/docker_container/communication/docker_container_api_client.py +139 -0
- thestage/docker_container/communication/image_command.py +40 -0
- thestage/docker_container/dto/__init__.py +0 -0
- thestage/docker_container/dto/container_action_request.py +11 -0
- thestage/{services/clients/thestage_api/dtos → docker_container/dto}/container_response.py +11 -4
- thestage/docker_container/dto/docker_container_create_request.py +28 -0
- thestage/docker_container/dto/docker_container_create_response.py +11 -0
- thestage/{services/clients/thestage_api/dtos/docker_container_controller → docker_container/dto}/docker_container_list_response.py +3 -5
- thestage/docker_container/dto/docker_image_list_request.py +11 -0
- thestage/docker_container/dto/docker_image_list_response.py +13 -0
- thestage/docker_container/dto/enum/__init__.py +0 -0
- thestage/docker_container/dto/image_entity.py +14 -0
- thestage/git/__init__.py +0 -0
- thestage/git/business/__init__.py +0 -0
- thestage/git/communication/__init__.py +0 -0
- thestage/{services/clients/git → git/communication}/git_client.py +4 -4
- thestage/global_dto/__init__.py +0 -0
- thestage/global_dto/enums/__init__.py +0 -0
- thestage/helpers/error_handler.py +4 -4
- thestage/helpers/logger/app_logger.py +1 -3
- thestage/i18n/en_GB/messages.po +14 -14
- thestage/inference_model/__init__.py +0 -0
- thestage/inference_model/business/__init__.py +0 -0
- thestage/inference_model/business/inference_model_service.py +281 -0
- thestage/inference_model/business/mapper/__init__.py +0 -0
- thestage/{services/project/mapper/project_inference_simulator_model_mapper.py → inference_model/business/mapper/inference_model_mapper.py} +5 -5
- thestage/inference_model/communication/__init__.py +0 -0
- thestage/inference_model/communication/inference_model_api_client.py +139 -0
- thestage/inference_model/communication/inference_model_command.py +246 -0
- thestage/inference_model/dto/__init__.py +0 -0
- thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_instance_response.py +0 -1
- thestage/inference_model/dto/enum/__init__.py +0 -0
- thestage/{services/project/dto/inference_simulator_model_dto.py → inference_model/dto/inference_model.py} +1 -1
- thestage/{entities/project_inference_simulator_model.py → inference_model/dto/inference_model_entity.py} +1 -1
- thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/inference_simulator_model_list_for_project_response.py +2 -3
- thestage/{services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_request.py → inference_model/dto/push_inference_simulator_model_request.py} +1 -1
- thestage/{services/clients/thestage_api/dtos/project_controller/project_push_inference_simulator_model_response.py → inference_model/dto/push_inference_simulator_model_response.py} +1 -1
- thestage/inference_simulator/__init__.py +0 -0
- thestage/inference_simulator/business/__init__.py +0 -0
- thestage/inference_simulator/business/inference_simulator_service.py +338 -0
- thestage/inference_simulator/business/mapper/__init__.py +0 -0
- thestage/{services/project/mapper/project_inference_simulator_mapper.py → inference_simulator/business/mapper/inference_simulator_mapper.py} +5 -5
- thestage/inference_simulator/communication/__init__.py +0 -0
- thestage/inference_simulator/communication/inference_simulator_api_client.py +114 -0
- thestage/inference_simulator/communication/inference_simulator_command.py +347 -0
- thestage/inference_simulator/dto/__init__.py +0 -0
- thestage/inference_simulator/dto/enum/__init__.py +0 -0
- thestage/inference_simulator/dto/get_inference_simulator_response.py +12 -0
- thestage/{services/project/dto/inference_simulator_dto.py → inference_simulator/dto/inference_simulator.py} +1 -1
- thestage/{entities/project_inference_simulator.py → inference_simulator/dto/inference_simulator_entity.py} +1 -1
- thestage/{services/clients/thestage_api/dtos/inference_controller → inference_simulator/dto}/inference_simulator_list_response.py +2 -2
- thestage/{services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_request.py → inference_simulator/dto/start_inference_simulator_request.py} +1 -1
- thestage/inference_simulator/dto/start_inference_simulator_response.py +10 -0
- thestage/instance/__init__.py +0 -0
- thestage/instance/business/__init__.py +0 -0
- thestage/{services/instance → instance/business}/instance_service.py +26 -27
- thestage/instance/business/mapper/__init__.py +0 -0
- thestage/{services/instance/mapper/instance_mapper.py → instance/business/mapper/rented_instance_mapper.py} +3 -3
- thestage/{services/instance/mapper/selfhosted_mapper.py → instance/business/mapper/selfhosted_instance_mapper.py} +5 -7
- thestage/instance/communication/__init__.py +0 -0
- thestage/instance/communication/instance_api_client.py +150 -0
- thestage/{controllers/instance_controller.py → instance/communication/instance_command.py} +5 -5
- thestage/instance/dto/__init__.py +0 -0
- thestage/instance/dto/enum/__init__.py +0 -0
- thestage/{services/clients/thestage_api/dtos → instance/dto}/instance_detected_gpus.py +1 -2
- thestage/{services/clients/thestage_api/dtos → instance/dto}/instance_rented_response.py +2 -2
- thestage/{services/clients/thestage_api/dtos → instance/dto}/selfhosted_instance_response.py +2 -3
- thestage/logging/__init__.py +0 -0
- thestage/logging/business/__init__.py +0 -0
- thestage/{services/logging → logging/business}/logging_service.py +40 -28
- thestage/logging/communication/__init__.py +0 -0
- thestage/logging/communication/logging_api_client.py +63 -0
- thestage/logging/dto/__init__.py +0 -0
- thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/log_polling_response.py +2 -2
- thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/user_logs_query_response.py +2 -2
- thestage/main.py +54 -8
- thestage/project/__init__.py +0 -0
- thestage/project/business/__init__.py +0 -0
- thestage/project/business/project_service.py +480 -0
- thestage/project/communication/__init__.py +0 -0
- thestage/project/communication/project_api_client.py +46 -0
- thestage/project/communication/project_command.py +284 -0
- thestage/project/dto/__init__.py +0 -0
- thestage/services/clients/thestage_api/core/api_client_core.py +1 -1
- thestage/services/clients/thestage_api/dtos/entity_filter_request.py +1 -1
- thestage/services/clients/thestage_api/dtos/sftp_path_helper.py +1 -1
- thestage/services/filesystem_service.py +2 -2
- thestage/services/service_factory.py +130 -43
- thestage/task/__init__.py +0 -0
- thestage/task/business/__init__.py +0 -0
- thestage/task/business/mapper/__init__.py +0 -0
- thestage/{services/project/mapper/project_task_mapper.py → task/business/mapper/task_mapper.py} +5 -5
- thestage/task/business/task_service.py +307 -0
- thestage/task/communication/__init__.py +0 -0
- thestage/task/communication/task_api_client.py +122 -0
- thestage/task/communication/task_command.py +212 -0
- thestage/task/dto/__init__.py +0 -0
- thestage/task/dto/enum/__init__.py +0 -0
- thestage/{services/clients/thestage_api/dtos/task_controller/task_list_for_project_response.py → task/dto/list_for_project_response.py} +2 -2
- thestage/{services/clients/thestage_api/dtos/project_controller/project_run_task_request.py → task/dto/run_task_request.py} +1 -1
- thestage/task/dto/run_task_response.py +13 -0
- thestage/{services/task/dto/task_dto.py → task/dto/task.py} +1 -4
- thestage/{entities/project_task.py → task/dto/task_entity.py} +1 -1
- thestage/{services/clients/thestage_api/dtos/task_controller/task_view_response.py → task/dto/view_response.py} +2 -2
- {thestage-0.6.7.dist-info → thestage-0.7.0.dist-info}/METADATA +1 -1
- thestage-0.7.0.dist-info/RECORD +226 -0
- {thestage-0.6.7.dist-info → thestage-0.7.0.dist-info}/WHEEL +1 -1
- thestage/controllers/project_controller.py +0 -1056
- thestage/services/clients/thestage_api/api_client.py +0 -751
- thestage/services/clients/thestage_api/dtos/container_param_request.py +0 -11
- thestage/services/clients/thestage_api/dtos/inference_controller/get_inference_simulator_response.py +0 -13
- thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_response.py +0 -13
- thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_response.py +0 -10
- thestage/services/clients/thestage_api/dtos/user_controller/user_profile.py +0 -12
- thestage/services/project/project_service.py +0 -1287
- thestage-0.6.7.dist-info/RECORD +0 -167
- /thestage/{entities → color_scheme}/__init__.py +0 -0
- /thestage/{entities/enums → config/business}/__init__.py +0 -0
- /thestage/{services/clients/git → config/communication}/__init__.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → config/dto}/__init__.py +0 -0
- /thestage/{services/core_files → config/dto}/config_entity.py +0 -0
- /thestage/{services/connect → config}/dto/remote_server_config.py +0 -0
- /thestage/{services/config_provider → connect}/__init__.py +0 -0
- /thestage/{services/container → connect/business}/__init__.py +0 -0
- /thestage/{services/container/mapper → connect/communication}/__init__.py +0 -0
- /thestage/{services/instance → connect/dto}/__init__.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_key_to_user_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_public_key_to_instance_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/is_user_has_public_ssh_key_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/is_user_has_public_ssh_key_response.py +0 -0
- /thestage/{services/instance/mapper → docker_container}/__init__.py +0 -0
- /thestage/{services/project → docker_container/business}/__init__.py +0 -0
- /thestage/{services/project → docker_container/business}/mapper/__init__.py +0 -0
- /thestage/{entities/container.py → docker_container/dto/container_entity.py} +0 -0
- /thestage/{services/clients/thestage_api/dtos/docker_container_controller → docker_container/dto}/docker_container_list_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos → docker_container/dto}/docker_container_mapping.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → docker_container/dto/enum}/container_pending_action.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → docker_container/dto/enum}/container_status.py +0 -0
- /thestage/{services/logging/exception → exceptions}/log_polling_exception.py +0 -0
- /thestage/git/{ProgressPrinter.py → business/ProgressPrinter.py} +0 -0
- /thestage/{entities → global_dto}/enums/order_direction_type.py +0 -0
- /thestage/{entities → global_dto}/enums/shell_type.py +0 -0
- /thestage/{entities → global_dto}/enums/tail_output_type.py +0 -0
- /thestage/{entities → global_dto}/enums/yes_no_response.py +0 -0
- /thestage/{entities → global_dto}/file_item.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_instance_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_sagemaker_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_sagemaker_response.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → inference_model/dto/enum}/inference_model_status.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/inference_simulator_model_list_for_project_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos → inference_model/dto}/inference_simulator_model_response.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → inference_simulator/dto/enum}/inference_simulator_status.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_simulator/dto}/get_inference_simulator_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_simulator/dto}/inference_simulator_list_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos → inference_simulator/dto}/inference_simulator_response.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/cpu_type.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/gpu_name.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/instance_rented_status.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/provider_name.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/selfhosted_status.py +0 -0
- /thestage/{entities → instance/dto}/rented_instance.py +0 -0
- /thestage/{entities → instance/dto}/self_hosted_instance.py +0 -0
- /thestage/{services/logging → logging}/byte_print_style.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/docker_container_log_stream_request.py +0 -0
- /thestage/{services/logging → logging}/dto/log_message.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/log_polling_request.py +0 -0
- /thestage/{services/logging → logging}/dto/log_type.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/task_log_stream_request.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/user_logs_query_request.py +0 -0
- /thestage/{services/logging → logging}/logging_constants.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_request.py → project/dto/get_deploy_ssh_key_request.py} +0 -0
- /thestage/{services/clients/thestage_api/dtos/project_controller/project_get_deploy_ssh_key_response.py → project/dto/get_deploy_ssh_key_response.py} +0 -0
- /thestage/{services/project → project}/dto/project_config.py +0 -0
- /thestage/{services/clients/thestage_api/dtos → project/dto}/project_response.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → task/dto/enum}/task_execution_status.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/enums → task/dto/enum}/task_status.py +0 -0
- /thestage/{services/clients/thestage_api/dtos/task_controller/task_list_for_project_request.py → task/dto/list_for_project_request.py} +0 -0
- /thestage/{services/clients/thestage_api/dtos/task_controller/task_status_localized_map_response.py → task/dto/status_localized_map_response.py} +0 -0
- {thestage-0.6.7.dist-info → thestage-0.7.0.dist-info}/entry_points.txt +0 -0
- {thestage-0.6.7.dist-info → thestage-0.7.0.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import Optional, List
|
|
4
|
+
|
|
5
|
+
import boto3
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from thestage.config.business.config_provider import ConfigProvider
|
|
9
|
+
from thestage.helpers.error_handler import error_handler
|
|
10
|
+
from thestage.i18n.translation import __
|
|
11
|
+
from thestage.inference_model.business.mapper.inference_model_mapper import InferenceModelMapper
|
|
12
|
+
from thestage.inference_model.communication.inference_model_api_client import InferenceModelApiClient
|
|
13
|
+
from thestage.inference_model.dto.deploy_inference_model_to_instance_response import \
|
|
14
|
+
DeployInferenceModelToInstanceResponse
|
|
15
|
+
from thestage.inference_model.dto.deploy_inference_model_to_sagemaker_response import \
|
|
16
|
+
DeployInferenceModelToSagemakerResponse
|
|
17
|
+
from thestage.inference_model.dto.enum.inference_model_status import InferenceModelStatus
|
|
18
|
+
from thestage.inference_model.dto.inference_model import InferenceModel
|
|
19
|
+
from thestage.inference_model.dto.inference_model_entity import InferenceModelEntity
|
|
20
|
+
from thestage.project.business.project_service import ProjectService
|
|
21
|
+
from thestage.project.dto.project_config import ProjectConfig
|
|
22
|
+
from thestage.services.abstract_service import AbstractService
|
|
23
|
+
from thestage.services.clients.thestage_api.dtos.paginated_entity_list import PaginatedEntityList
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class InferenceModelService(AbstractService):
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
inference_model_api_client: InferenceModelApiClient,
|
|
30
|
+
config_provider: ConfigProvider,
|
|
31
|
+
project_service: ProjectService,
|
|
32
|
+
):
|
|
33
|
+
self.__inference_model_api_client = inference_model_api_client
|
|
34
|
+
self.__config_provider = config_provider
|
|
35
|
+
self.__project_service = project_service
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@error_handler()
|
|
39
|
+
def get_project_inference_simulator_model_list(
|
|
40
|
+
self,
|
|
41
|
+
project_public_id: Optional[str],
|
|
42
|
+
project_slug: Optional[str],
|
|
43
|
+
statuses: List[str],
|
|
44
|
+
row: int = 5,
|
|
45
|
+
page: int = 1,
|
|
46
|
+
) -> PaginatedEntityList[InferenceModel]:
|
|
47
|
+
data: Optional[
|
|
48
|
+
PaginatedEntityList[InferenceModel]] = self.__inference_model_api_client.get_inference_simulator_model_list_for_project(
|
|
49
|
+
statuses=statuses,
|
|
50
|
+
project_public_id=project_public_id,
|
|
51
|
+
project_slug=project_slug,
|
|
52
|
+
page=page,
|
|
53
|
+
limit=row,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
return data
|
|
57
|
+
|
|
58
|
+
@error_handler()
|
|
59
|
+
def project_deploy_inference_simulator_model_to_instance(
|
|
60
|
+
self,
|
|
61
|
+
model_public_id: Optional[str] = None,
|
|
62
|
+
model_slug: Optional[str] = None,
|
|
63
|
+
rented_instance_public_id: Optional[str] = None,
|
|
64
|
+
rented_instance_slug: Optional[str] = None,
|
|
65
|
+
self_hosted_instance_public_id: Optional[str] = None,
|
|
66
|
+
self_hosted_instance_slug: Optional[str] = None,
|
|
67
|
+
) -> str:
|
|
68
|
+
config = self.__config_provider.get_config()
|
|
69
|
+
project_config: ProjectConfig = self.__project_service.get_fixed_project_config()
|
|
70
|
+
if not project_config:
|
|
71
|
+
typer.echo(
|
|
72
|
+
__("No project found at the path: %path%. Initialize or clone a project first. Or provide path to project using --working-directory option.",
|
|
73
|
+
{"path": config.runtime.working_directory}))
|
|
74
|
+
raise typer.Exit(1)
|
|
75
|
+
|
|
76
|
+
instance_args_count = sum(v is not None for v in
|
|
77
|
+
[rented_instance_public_id, rented_instance_slug, self_hosted_instance_public_id,
|
|
78
|
+
self_hosted_instance_slug])
|
|
79
|
+
if instance_args_count != 1:
|
|
80
|
+
typer.echo("Provide a single instance (rented or self-hosted) identifier - name or ID.")
|
|
81
|
+
raise typer.Exit(1)
|
|
82
|
+
|
|
83
|
+
model_args_count = sum(v is not None for v in [model_public_id, model_slug])
|
|
84
|
+
if model_args_count != 1:
|
|
85
|
+
typer.echo("Provide a single model identifier - name or ID.")
|
|
86
|
+
raise typer.Exit(1)
|
|
87
|
+
|
|
88
|
+
typer.echo(f"Creating inference simulator")
|
|
89
|
+
deploy_model_to_instance_response: DeployInferenceModelToInstanceResponse = self.__inference_model_api_client.deploy_inference_model_to_instance(
|
|
90
|
+
model_public_id=model_public_id,
|
|
91
|
+
model_slug=model_slug,
|
|
92
|
+
rented_instance_public_id=rented_instance_public_id,
|
|
93
|
+
rented_instance_slug=rented_instance_slug,
|
|
94
|
+
self_hosted_instance_public_id=self_hosted_instance_public_id,
|
|
95
|
+
self_hosted_instance_slug=self_hosted_instance_slug,
|
|
96
|
+
)
|
|
97
|
+
if deploy_model_to_instance_response:
|
|
98
|
+
if deploy_model_to_instance_response.message:
|
|
99
|
+
typer.echo(deploy_model_to_instance_response.message)
|
|
100
|
+
if deploy_model_to_instance_response.is_success:
|
|
101
|
+
typer.echo("Inference simulator has been scheduled to run successfully.")
|
|
102
|
+
else:
|
|
103
|
+
typer.echo(__(
|
|
104
|
+
'Failed to start inference simulator: %server_massage%',
|
|
105
|
+
{'server_massage': deploy_model_to_instance_response.message or ""}
|
|
106
|
+
))
|
|
107
|
+
raise typer.Exit(1)
|
|
108
|
+
else:
|
|
109
|
+
typer.echo(__("Failed to start inference simulator"))
|
|
110
|
+
raise typer.Exit(1)
|
|
111
|
+
|
|
112
|
+
return deploy_model_to_instance_response.inferenceSimulatorPublicId
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@error_handler()
|
|
116
|
+
def project_deploy_inference_simulator_model_to_sagemaker(
|
|
117
|
+
self,
|
|
118
|
+
model_public_id: Optional[str] = None,
|
|
119
|
+
model_slug: Optional[str] = None,
|
|
120
|
+
arn: Optional[str] = None,
|
|
121
|
+
instance_type: Optional[str] = None,
|
|
122
|
+
initial_variant_weight: Optional[float] = 1.0,
|
|
123
|
+
initial_instance_count: Optional[int] = None,
|
|
124
|
+
) -> None:
|
|
125
|
+
config = self.__config_provider.get_config()
|
|
126
|
+
project_config: ProjectConfig = self.__project_service.get_fixed_project_config()
|
|
127
|
+
if not project_config:
|
|
128
|
+
typer.echo(
|
|
129
|
+
__("No project found at the path: %path%. Initialize or clone a project first. Or provide path to project using --working-directory option.",
|
|
130
|
+
{"path": config.runtime.working_directory}))
|
|
131
|
+
raise typer.Exit(1)
|
|
132
|
+
|
|
133
|
+
if not instance_type:
|
|
134
|
+
typer.echo(__("Error: Instance type is required."))
|
|
135
|
+
raise typer.Exit(1)
|
|
136
|
+
|
|
137
|
+
if not initial_instance_count:
|
|
138
|
+
typer.echo(__("Error: Initial instance count is required."))
|
|
139
|
+
raise typer.Exit(1)
|
|
140
|
+
|
|
141
|
+
if not arn:
|
|
142
|
+
typer.echo(__("Error: ARN is required."))
|
|
143
|
+
raise typer.Exit(1)
|
|
144
|
+
|
|
145
|
+
project_config: ProjectConfig = self.__config_provider.read_project_config()
|
|
146
|
+
if not project_config:
|
|
147
|
+
typer.echo(__("No project found at the path: %path%. Initialize or clone a project first.",
|
|
148
|
+
{"path": config.runtime.working_directory}))
|
|
149
|
+
raise typer.Exit(1)
|
|
150
|
+
|
|
151
|
+
deploy_model_to_sagemaker_response: DeployInferenceModelToSagemakerResponse = self.__inference_model_api_client.deploy_inference_model_to_sagemaker(
|
|
152
|
+
model_public_id=model_public_id,
|
|
153
|
+
model_slug=model_slug,
|
|
154
|
+
arn=arn,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
if not deploy_model_to_sagemaker_response.is_success:
|
|
158
|
+
typer.echo(__(
|
|
159
|
+
'Model deployment preparation failed: %server_massage%',
|
|
160
|
+
{'server_massage': deploy_model_to_sagemaker_response.message or ""}
|
|
161
|
+
))
|
|
162
|
+
raise typer.Exit(1)
|
|
163
|
+
|
|
164
|
+
model_id = deploy_model_to_sagemaker_response.modelId
|
|
165
|
+
image_uri = deploy_model_to_sagemaker_response.ecrImageUrl
|
|
166
|
+
model_uri = deploy_model_to_sagemaker_response.s3ArtifactsUrl
|
|
167
|
+
region = "us-east-1"
|
|
168
|
+
sm_client = boto3.client('sagemaker', region_name=region)
|
|
169
|
+
|
|
170
|
+
try:
|
|
171
|
+
container = {
|
|
172
|
+
"Image": image_uri,
|
|
173
|
+
"ModelDataUrl": model_uri,
|
|
174
|
+
"Environment": {
|
|
175
|
+
"SAGEMAKER_TRITON_DEFAULT_MODEL_NAME": model_id,
|
|
176
|
+
"THESTAGE_API_URL": config.main.thestage_api_url,
|
|
177
|
+
"THESTAGE_AUTH_TOKEN": config.main.thestage_auth_token
|
|
178
|
+
},
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
sm_model_name = f"{model_slug}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
|
|
182
|
+
create_model_response = sm_client.create_model(
|
|
183
|
+
ModelName=sm_model_name,
|
|
184
|
+
ExecutionRoleArn=arn,
|
|
185
|
+
PrimaryContainer=container,
|
|
186
|
+
)
|
|
187
|
+
typer.echo(f"Model created successfully. Model ARN: {create_model_response['ModelArn']}")
|
|
188
|
+
|
|
189
|
+
endpoint_config_name = f"{model_slug}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
|
|
190
|
+
create_endpoint_config_response = sm_client.create_endpoint_config(
|
|
191
|
+
EndpointConfigName=endpoint_config_name,
|
|
192
|
+
ProductionVariants=[
|
|
193
|
+
{
|
|
194
|
+
"InstanceType": instance_type,
|
|
195
|
+
"InitialVariantWeight": initial_variant_weight,
|
|
196
|
+
"InitialInstanceCount": initial_instance_count,
|
|
197
|
+
"ModelName": sm_model_name,
|
|
198
|
+
"VariantName": "AllTraffic",
|
|
199
|
+
}
|
|
200
|
+
],
|
|
201
|
+
)
|
|
202
|
+
typer.echo(
|
|
203
|
+
f"Endpoint configuration created successfully. Endpoint Config ARN: {create_endpoint_config_response['EndpointConfigArn']}")
|
|
204
|
+
|
|
205
|
+
endpoint_name = f"{model_slug}-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
|
|
206
|
+
create_endpoint_response = sm_client.create_endpoint(
|
|
207
|
+
EndpointName=endpoint_name,
|
|
208
|
+
EndpointConfigName=endpoint_config_name,
|
|
209
|
+
)
|
|
210
|
+
typer.echo(f"Endpoint created successfully. Endpoint ARN: {create_endpoint_response['EndpointArn']}")
|
|
211
|
+
|
|
212
|
+
typer.echo("Waiting for the endpoint to become active...")
|
|
213
|
+
while True:
|
|
214
|
+
resp = sm_client.describe_endpoint(EndpointName=endpoint_name)
|
|
215
|
+
status = resp["EndpointStatus"]
|
|
216
|
+
typer.echo(f"Status: {status}")
|
|
217
|
+
if status == "InService":
|
|
218
|
+
break
|
|
219
|
+
elif status == "Failed":
|
|
220
|
+
typer.echo(f"Endpoint creation failed. Reason: {resp.get('FailureReason', 'Unknown')}")
|
|
221
|
+
raise typer.Exit(1)
|
|
222
|
+
time.sleep(60)
|
|
223
|
+
|
|
224
|
+
typer.echo(f"Endpoint is ready. ARN: {resp['EndpointArn']} Status: {status}")
|
|
225
|
+
|
|
226
|
+
except Exception as e:
|
|
227
|
+
typer.echo(__("Failed to deploy the inference simulator model to SageMaker: %error%", {"error": str(e)}))
|
|
228
|
+
raise typer.Exit(1)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
@error_handler()
|
|
232
|
+
def print_inference_simulator_model_list(self, project_public_id, project_slug, statuses, row, page):
|
|
233
|
+
if not project_public_id and not project_slug:
|
|
234
|
+
project_config: ProjectConfig = self.__config_provider.read_project_config()
|
|
235
|
+
if not project_config:
|
|
236
|
+
typer.echo(__("Provide the project unique ID or name, or run this command from within an initialized project directory"))
|
|
237
|
+
raise typer.Exit(1)
|
|
238
|
+
project_public_id = project_config.public_id
|
|
239
|
+
|
|
240
|
+
inference_simulator_model_status_map = self.__inference_model_api_client.get_inference_simulator_model_business_status_map()
|
|
241
|
+
|
|
242
|
+
if not statuses:
|
|
243
|
+
statuses = ({key: inference_simulator_model_status_map[key] for key in [
|
|
244
|
+
InferenceModelStatus.SCHEDULED,
|
|
245
|
+
InferenceModelStatus.PROCESSING,
|
|
246
|
+
InferenceModelStatus.PUSH_SUCCEED,
|
|
247
|
+
]}).values()
|
|
248
|
+
|
|
249
|
+
if "all" in statuses:
|
|
250
|
+
statuses = inference_simulator_model_status_map.values()
|
|
251
|
+
|
|
252
|
+
for input_status_item in statuses:
|
|
253
|
+
if input_status_item not in inference_simulator_model_status_map.values():
|
|
254
|
+
typer.echo(__("'%invalid_status%' is not one of %valid_statuses%", {
|
|
255
|
+
'invalid_status': input_status_item,
|
|
256
|
+
'valid_statuses': str(list(inference_simulator_model_status_map.values()))
|
|
257
|
+
}))
|
|
258
|
+
raise typer.Exit(1)
|
|
259
|
+
|
|
260
|
+
typer.echo(__(
|
|
261
|
+
"Listing inference simulator models with the following statuses: %statuses%, to view all inference simulator models, use --status all",
|
|
262
|
+
placeholders={
|
|
263
|
+
'statuses': ', '.join([status_item for status_item in statuses])
|
|
264
|
+
}))
|
|
265
|
+
|
|
266
|
+
backend_statuses: List[str] = [key for key, value in inference_simulator_model_status_map.items() if value in statuses]
|
|
267
|
+
|
|
268
|
+
self.print(
|
|
269
|
+
func_get_data=self.get_project_inference_simulator_model_list,
|
|
270
|
+
func_special_params={
|
|
271
|
+
'project_public_id': project_public_id,
|
|
272
|
+
'project_slug': project_slug,
|
|
273
|
+
'statuses': backend_statuses,
|
|
274
|
+
},
|
|
275
|
+
mapper=InferenceModelMapper(),
|
|
276
|
+
headers=list(map(lambda x: x.alias, InferenceModelEntity.model_fields.values())),
|
|
277
|
+
row=row,
|
|
278
|
+
page=page,
|
|
279
|
+
max_col_width=[100, 100, 100, 100, 25],
|
|
280
|
+
show_index="never",
|
|
281
|
+
)
|
|
File without changes
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
2
|
|
|
3
|
-
from thestage.
|
|
3
|
+
from thestage.inference_model.dto.inference_model_entity import InferenceModelEntity
|
|
4
4
|
from thestage.services.abstract_mapper import AbstractMapper
|
|
5
|
-
from thestage.
|
|
5
|
+
from thestage.inference_model.dto.inference_model import InferenceModel
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
class
|
|
9
|
-
def build_entity(self, item:
|
|
8
|
+
class InferenceModelMapper(AbstractMapper):
|
|
9
|
+
def build_entity(self, item: InferenceModel) -> Optional[InferenceModelEntity]:
|
|
10
10
|
if not item:
|
|
11
11
|
return None
|
|
12
12
|
|
|
13
|
-
return
|
|
13
|
+
return InferenceModelEntity(
|
|
14
14
|
public_id=item.public_id,
|
|
15
15
|
slug=item.slug,
|
|
16
16
|
status=item.status or '',
|
|
File without changes
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from typing import Optional, List, Dict
|
|
2
|
+
|
|
3
|
+
from thestage.config.business.config_provider import ConfigProvider
|
|
4
|
+
from thestage.global_dto.enums.order_direction_type import OrderDirectionType
|
|
5
|
+
from thestage.helpers.error_handler import error_handler
|
|
6
|
+
from thestage.services.clients.thestage_api.core.api_client_core import TheStageApiClientCore
|
|
7
|
+
from thestage.services.clients.thestage_api.dtos.entity_filter_request import EntityFilterRequest
|
|
8
|
+
from thestage.services.clients.thestage_api.dtos.paginated_entity_list import PaginatedEntityList
|
|
9
|
+
|
|
10
|
+
from thestage.inference_model.dto.inference_model import InferenceModel
|
|
11
|
+
from thestage.inference_model.dto.inference_simulator_model_list_for_project_request import InferenceSimulatorModelListForProjectRequest
|
|
12
|
+
from thestage.inference_model.dto.inference_simulator_model_list_for_project_response import InferenceSimulatorModelListForProjectResponse
|
|
13
|
+
from thestage.inference_model.dto.push_inference_simulator_model_request import PushInferenceSimulatorModelRequest
|
|
14
|
+
from thestage.inference_model.dto.push_inference_simulator_model_response import PushInferenceSimulatorModelResponse
|
|
15
|
+
from thestage.inference_model.dto.inference_simulator_model_response import InferenceSimulatorModelStatusMapperResponse
|
|
16
|
+
from thestage.inference_model.dto.deploy_inference_model_to_instance_request import DeployInferenceModelToInstanceRequest
|
|
17
|
+
from thestage.inference_model.dto.deploy_inference_model_to_instance_response import DeployInferenceModelToInstanceResponse
|
|
18
|
+
from thestage.inference_model.dto.deploy_inference_model_to_sagemaker_request import DeployInferenceModelToSagemakerRequest
|
|
19
|
+
from thestage.inference_model.dto.deploy_inference_model_to_sagemaker_response import DeployInferenceModelToSagemakerResponse
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class InferenceModelApiClient(TheStageApiClientCore):
|
|
23
|
+
def __init__(self, config_provider: ConfigProvider):
|
|
24
|
+
super().__init__(url=config_provider.get_config().main.thestage_api_url)
|
|
25
|
+
self.__config_provider = config_provider
|
|
26
|
+
|
|
27
|
+
def get_inference_simulator_model_list_for_project(
|
|
28
|
+
self,
|
|
29
|
+
project_public_id: Optional[str],
|
|
30
|
+
project_slug: Optional[str],
|
|
31
|
+
statuses: Optional[List[str]] = None,
|
|
32
|
+
page: int = 1,
|
|
33
|
+
limit: int = 10,
|
|
34
|
+
) -> Optional[PaginatedEntityList[InferenceModel]]:
|
|
35
|
+
request = InferenceSimulatorModelListForProjectRequest(
|
|
36
|
+
projectPublicId=project_public_id,
|
|
37
|
+
projectSlug=project_slug,
|
|
38
|
+
statuses=statuses,
|
|
39
|
+
entityFilterRequest=EntityFilterRequest(
|
|
40
|
+
orderByField="createdAt",
|
|
41
|
+
orderByDirection=OrderDirectionType.DESC,
|
|
42
|
+
page=page,
|
|
43
|
+
limit=limit,
|
|
44
|
+
),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
response = self._request(
|
|
48
|
+
method='POST',
|
|
49
|
+
url='/user-api/v2/inference-simulator-model/list',
|
|
50
|
+
data=request.model_dump(),
|
|
51
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
52
|
+
)
|
|
53
|
+
result = InferenceSimulatorModelListForProjectResponse.model_validate(response) if response else None
|
|
54
|
+
return result.inferenceSimulatorModels if result and result.is_success else None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def push_project_inference_simulator_model(
|
|
58
|
+
self,
|
|
59
|
+
public_id: Optional[str],
|
|
60
|
+
slug: Optional[str],
|
|
61
|
+
) -> Optional[PushInferenceSimulatorModelResponse]:
|
|
62
|
+
request = PushInferenceSimulatorModelRequest(
|
|
63
|
+
inferenceSimulatorPublicId=public_id,
|
|
64
|
+
inferenceSimulatorSlug=slug,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
response = self._request(
|
|
68
|
+
method='POST',
|
|
69
|
+
url='/user-api/v2/inference-simulator/push-model',
|
|
70
|
+
data=request.model_dump(),
|
|
71
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
return PushInferenceSimulatorModelResponse.model_validate(response) if response else None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def get_inference_simulator_model_business_status_map(self) -> Optional[Dict[str, str]]:
|
|
78
|
+
response = self._request(
|
|
79
|
+
method='POST',
|
|
80
|
+
url='/user-api/v1/inference-simulator-model/status-localized-mapping',
|
|
81
|
+
data=None,
|
|
82
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
data = InferenceSimulatorModelStatusMapperResponse.model_validate(response) if response else None
|
|
86
|
+
|
|
87
|
+
return data.inference_simulator_model_status_map if data else None
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@error_handler()
|
|
91
|
+
def deploy_inference_model_to_instance(
|
|
92
|
+
self,
|
|
93
|
+
model_public_id: str,
|
|
94
|
+
model_slug: str,
|
|
95
|
+
new_inference_simulator_slug: str,
|
|
96
|
+
rented_instance_public_id: Optional[str] = None,
|
|
97
|
+
rented_instance_slug: Optional[str] = None,
|
|
98
|
+
self_hosted_instance_public_id: Optional[str] = None,
|
|
99
|
+
self_hosted_instance_slug: Optional[str] = None,
|
|
100
|
+
|
|
101
|
+
) -> Optional[DeployInferenceModelToInstanceResponse]:
|
|
102
|
+
request = DeployInferenceModelToInstanceRequest(
|
|
103
|
+
modelPublicId=model_public_id,
|
|
104
|
+
modelSlug=model_slug,
|
|
105
|
+
instanceRentedPublicId=rented_instance_public_id,
|
|
106
|
+
instanceRentedSlug=rented_instance_slug,
|
|
107
|
+
selfhostedInstancePublicId=self_hosted_instance_public_id,
|
|
108
|
+
selfhostedInstanceSlug=self_hosted_instance_slug
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
response = self._request(
|
|
112
|
+
method='POST',
|
|
113
|
+
url='/user-api/v2/inference-simulator-model/deploy/instance',
|
|
114
|
+
data=request.model_dump(),
|
|
115
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
116
|
+
)
|
|
117
|
+
return DeployInferenceModelToInstanceResponse.model_validate(response) if response else None
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@error_handler()
|
|
121
|
+
def deploy_inference_model_to_sagemaker(
|
|
122
|
+
self,
|
|
123
|
+
model_public_id: Optional[str],
|
|
124
|
+
model_slug: Optional[str],
|
|
125
|
+
arn: Optional[str] = None,
|
|
126
|
+
) -> Optional[DeployInferenceModelToSagemakerResponse]:
|
|
127
|
+
request = DeployInferenceModelToSagemakerRequest(
|
|
128
|
+
modelPublicId=model_public_id,
|
|
129
|
+
modelSlug=model_slug,
|
|
130
|
+
arn=arn,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
response = self._request(
|
|
134
|
+
method='POST',
|
|
135
|
+
url='/user-api/v1/inference-simulator-model/grant-user-arn-access',
|
|
136
|
+
data=request.model_dump(),
|
|
137
|
+
token=self.__config_provider.get_config().main.thestage_auth_token,
|
|
138
|
+
)
|
|
139
|
+
return DeployInferenceModelToSagemakerResponse.model_validate(response) if response else None
|