thestage 0.6.7__py3-none-any.whl → 0.6.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.
Files changed (194) hide show
  1. thestage/__init__.py +1 -1
  2. thestage/cli_command_helper.py +2 -2
  3. thestage/config/__init__.py +1 -1
  4. thestage/{services → config/business}/app_config_service.py +3 -4
  5. thestage/{services/config_provider → config/business}/config_provider.py +6 -5
  6. thestage/config/{config_storage.py → business/config_storage.py} +1 -1
  7. thestage/{services → config/business}/validation_service.py +9 -10
  8. thestage/{controllers/config_controller.py → config/communication/config_command.py} +7 -7
  9. thestage/{services/connect → connect/business}/connect_service.py +22 -19
  10. thestage/{services → connect/business}/remote_server_service.py +4 -5
  11. thestage/connect/communication/connect_api_client.py +84 -0
  12. thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_key_to_user_response.py +0 -1
  13. thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_public_key_to_instance_response.py +1 -4
  14. thestage/{services/clients/thestage_api/dtos/base_controller → connect/dto}/connect_resolve_response.py +0 -1
  15. thestage/controllers/base_controller.py +2 -2
  16. thestage/debug_main.dist.py +16 -14
  17. thestage/{services/container → docker_container/business}/container_service.py +27 -22
  18. thestage/{services/container → docker_container/business}/mapper/container_mapper.py +3 -3
  19. thestage/docker_container/communication/__init__.py +0 -0
  20. thestage/{controllers/container_controller.py → docker_container/communication/docker_command.py} +17 -23
  21. thestage/docker_container/communication/docker_container_api_client.py +99 -0
  22. thestage/docker_container/dto/__init__.py +0 -0
  23. thestage/docker_container/dto/container_action_request.py +11 -0
  24. thestage/{services/clients/thestage_api/dtos → docker_container/dto}/container_response.py +4 -4
  25. thestage/{services/clients/thestage_api/dtos/docker_container_controller → docker_container/dto}/docker_container_list_response.py +3 -5
  26. thestage/docker_container/dto/enum/__init__.py +0 -0
  27. thestage/git/__init__.py +0 -0
  28. thestage/git/business/__init__.py +0 -0
  29. thestage/git/communication/__init__.py +0 -0
  30. thestage/{services/clients/git → git/communication}/git_client.py +4 -4
  31. thestage/global_dto/__init__.py +0 -0
  32. thestage/global_dto/enums/__init__.py +0 -0
  33. thestage/helpers/error_handler.py +3 -3
  34. thestage/helpers/logger/app_logger.py +1 -3
  35. thestage/i18n/en_GB/messages.po +14 -14
  36. thestage/inference_model/__init__.py +0 -0
  37. thestage/inference_model/business/__init__.py +0 -0
  38. thestage/inference_model/business/inference_model_service.py +281 -0
  39. thestage/inference_model/business/mapper/__init__.py +0 -0
  40. thestage/{services/project/mapper/project_inference_simulator_model_mapper.py → inference_model/business/mapper/inference_model_mapper.py} +5 -5
  41. thestage/inference_model/communication/__init__.py +0 -0
  42. thestage/inference_model/communication/inference_model_api_client.py +139 -0
  43. thestage/inference_model/communication/inference_model_command.py +246 -0
  44. thestage/inference_model/dto/__init__.py +0 -0
  45. thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_instance_response.py +0 -1
  46. thestage/inference_model/dto/enum/__init__.py +0 -0
  47. thestage/{services/project/dto/inference_simulator_model_dto.py → inference_model/dto/inference_model.py} +1 -1
  48. thestage/{entities/project_inference_simulator_model.py → inference_model/dto/inference_model_entity.py} +1 -1
  49. thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/inference_simulator_model_list_for_project_response.py +2 -3
  50. 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
  51. 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
  52. thestage/inference_simulator/__init__.py +0 -0
  53. thestage/inference_simulator/business/__init__.py +0 -0
  54. thestage/inference_simulator/business/inference_simulator_service.py +338 -0
  55. thestage/inference_simulator/business/mapper/__init__.py +0 -0
  56. thestage/{services/project/mapper/project_inference_simulator_mapper.py → inference_simulator/business/mapper/inference_simulator_mapper.py} +5 -5
  57. thestage/inference_simulator/communication/__init__.py +0 -0
  58. thestage/inference_simulator/communication/inference_simulator_api_client.py +114 -0
  59. thestage/inference_simulator/communication/inference_simulator_command.py +347 -0
  60. thestage/inference_simulator/dto/__init__.py +0 -0
  61. thestage/inference_simulator/dto/enum/__init__.py +0 -0
  62. thestage/inference_simulator/dto/get_inference_simulator_response.py +12 -0
  63. thestage/{services/project/dto/inference_simulator_dto.py → inference_simulator/dto/inference_simulator.py} +1 -1
  64. thestage/{entities/project_inference_simulator.py → inference_simulator/dto/inference_simulator_entity.py} +1 -1
  65. thestage/{services/clients/thestage_api/dtos/inference_controller → inference_simulator/dto}/inference_simulator_list_response.py +2 -2
  66. thestage/{services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_request.py → inference_simulator/dto/start_inference_simulator_request.py} +1 -1
  67. thestage/inference_simulator/dto/start_inference_simulator_response.py +10 -0
  68. thestage/instance/__init__.py +0 -0
  69. thestage/instance/business/__init__.py +0 -0
  70. thestage/{services/instance → instance/business}/instance_service.py +26 -27
  71. thestage/instance/business/mapper/__init__.py +0 -0
  72. thestage/{services/instance/mapper/instance_mapper.py → instance/business/mapper/rented_instance_mapper.py} +3 -3
  73. thestage/{services/instance/mapper/selfhosted_mapper.py → instance/business/mapper/selfhosted_instance_mapper.py} +5 -7
  74. thestage/instance/communication/__init__.py +0 -0
  75. thestage/instance/communication/instance_api_client.py +150 -0
  76. thestage/{controllers/instance_controller.py → instance/communication/instance_command.py} +5 -5
  77. thestage/instance/dto/__init__.py +0 -0
  78. thestage/instance/dto/enum/__init__.py +0 -0
  79. thestage/{services/clients/thestage_api/dtos → instance/dto}/instance_detected_gpus.py +1 -2
  80. thestage/{services/clients/thestage_api/dtos → instance/dto}/instance_rented_response.py +2 -2
  81. thestage/{services/clients/thestage_api/dtos → instance/dto}/selfhosted_instance_response.py +2 -3
  82. thestage/logging/__init__.py +0 -0
  83. thestage/logging/business/__init__.py +0 -0
  84. thestage/{services/logging → logging/business}/logging_service.py +40 -28
  85. thestage/logging/communication/__init__.py +0 -0
  86. thestage/logging/communication/logging_api_client.py +63 -0
  87. thestage/logging/dto/__init__.py +0 -0
  88. thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/log_polling_response.py +2 -2
  89. thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/user_logs_query_response.py +2 -2
  90. thestage/main.py +47 -8
  91. thestage/project/__init__.py +0 -0
  92. thestage/project/business/__init__.py +0 -0
  93. thestage/project/business/project_service.py +480 -0
  94. thestage/project/communication/__init__.py +0 -0
  95. thestage/project/communication/project_api_client.py +46 -0
  96. thestage/project/communication/project_command.py +284 -0
  97. thestage/project/dto/__init__.py +0 -0
  98. thestage/services/clients/thestage_api/core/api_client_core.py +1 -1
  99. thestage/services/clients/thestage_api/dtos/entity_filter_request.py +1 -1
  100. thestage/services/clients/thestage_api/dtos/sftp_path_helper.py +1 -1
  101. thestage/services/filesystem_service.py +2 -2
  102. thestage/services/service_factory.py +130 -43
  103. thestage/task/__init__.py +0 -0
  104. thestage/task/business/__init__.py +0 -0
  105. thestage/task/business/mapper/__init__.py +0 -0
  106. thestage/{services/project/mapper/project_task_mapper.py → task/business/mapper/task_mapper.py} +5 -5
  107. thestage/task/business/task_service.py +304 -0
  108. thestage/task/communication/__init__.py +0 -0
  109. thestage/task/communication/task_api_client.py +122 -0
  110. thestage/task/communication/task_command.py +212 -0
  111. thestage/task/dto/__init__.py +0 -0
  112. thestage/task/dto/enum/__init__.py +0 -0
  113. thestage/{services/clients/thestage_api/dtos/task_controller/task_list_for_project_response.py → task/dto/list_for_project_response.py} +2 -2
  114. thestage/{services/clients/thestage_api/dtos/project_controller/project_run_task_request.py → task/dto/run_task_request.py} +1 -1
  115. thestage/task/dto/run_task_response.py +13 -0
  116. thestage/{services/task/dto/task_dto.py → task/dto/task.py} +1 -4
  117. thestage/{entities/project_task.py → task/dto/task_entity.py} +1 -1
  118. thestage/{services/clients/thestage_api/dtos/task_controller/task_view_response.py → task/dto/view_response.py} +2 -2
  119. {thestage-0.6.7.dist-info → thestage-0.6.8.dist-info}/METADATA +1 -1
  120. thestage-0.6.8.dist-info/RECORD +219 -0
  121. {thestage-0.6.7.dist-info → thestage-0.6.8.dist-info}/WHEEL +1 -1
  122. thestage/controllers/project_controller.py +0 -1056
  123. thestage/services/clients/thestage_api/api_client.py +0 -751
  124. thestage/services/clients/thestage_api/dtos/container_param_request.py +0 -11
  125. thestage/services/clients/thestage_api/dtos/inference_controller/get_inference_simulator_response.py +0 -13
  126. thestage/services/clients/thestage_api/dtos/project_controller/project_run_task_response.py +0 -13
  127. thestage/services/clients/thestage_api/dtos/project_controller/project_start_inference_simulator_response.py +0 -10
  128. thestage/services/clients/thestage_api/dtos/user_controller/user_profile.py +0 -12
  129. thestage/services/project/project_service.py +0 -1287
  130. thestage-0.6.7.dist-info/RECORD +0 -167
  131. /thestage/{entities → color_scheme}/__init__.py +0 -0
  132. /thestage/{entities/enums → config/business}/__init__.py +0 -0
  133. /thestage/{services/clients/git → config/communication}/__init__.py +0 -0
  134. /thestage/{services/clients/thestage_api/dtos/enums → config/dto}/__init__.py +0 -0
  135. /thestage/{services/core_files → config/dto}/config_entity.py +0 -0
  136. /thestage/{services/connect → config}/dto/remote_server_config.py +0 -0
  137. /thestage/{services/config_provider → connect}/__init__.py +0 -0
  138. /thestage/{services/container → connect/business}/__init__.py +0 -0
  139. /thestage/{services/container/mapper → connect/communication}/__init__.py +0 -0
  140. /thestage/{services/instance → connect/dto}/__init__.py +0 -0
  141. /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_key_to_user_request.py +0 -0
  142. /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/add_ssh_public_key_to_instance_request.py +0 -0
  143. /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/is_user_has_public_ssh_key_request.py +0 -0
  144. /thestage/{services/clients/thestage_api/dtos/ssh_key_controller → connect/dto}/is_user_has_public_ssh_key_response.py +0 -0
  145. /thestage/{services/instance/mapper → docker_container}/__init__.py +0 -0
  146. /thestage/{services/project → docker_container/business}/__init__.py +0 -0
  147. /thestage/{services/project → docker_container/business}/mapper/__init__.py +0 -0
  148. /thestage/{entities/container.py → docker_container/dto/container_entity.py} +0 -0
  149. /thestage/{services/clients/thestage_api/dtos/docker_container_controller → docker_container/dto}/docker_container_list_request.py +0 -0
  150. /thestage/{services/clients/thestage_api/dtos → docker_container/dto}/docker_container_mapping.py +0 -0
  151. /thestage/{services/clients/thestage_api/dtos/enums → docker_container/dto/enum}/container_pending_action.py +0 -0
  152. /thestage/{services/clients/thestage_api/dtos/enums → docker_container/dto/enum}/container_status.py +0 -0
  153. /thestage/{services/logging/exception → exceptions}/log_polling_exception.py +0 -0
  154. /thestage/git/{ProgressPrinter.py → business/ProgressPrinter.py} +0 -0
  155. /thestage/{entities → global_dto}/enums/order_direction_type.py +0 -0
  156. /thestage/{entities → global_dto}/enums/shell_type.py +0 -0
  157. /thestage/{entities → global_dto}/enums/tail_output_type.py +0 -0
  158. /thestage/{entities → global_dto}/enums/yes_no_response.py +0 -0
  159. /thestage/{entities → global_dto}/file_item.py +0 -0
  160. /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_instance_request.py +0 -0
  161. /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_sagemaker_request.py +0 -0
  162. /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/deploy_inference_model_to_sagemaker_response.py +0 -0
  163. /thestage/{services/clients/thestage_api/dtos/enums → inference_model/dto/enum}/inference_model_status.py +0 -0
  164. /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_model/dto}/inference_simulator_model_list_for_project_request.py +0 -0
  165. /thestage/{services/clients/thestage_api/dtos → inference_model/dto}/inference_simulator_model_response.py +0 -0
  166. /thestage/{services/clients/thestage_api/dtos/enums → inference_simulator/dto/enum}/inference_simulator_status.py +0 -0
  167. /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_simulator/dto}/get_inference_simulator_request.py +0 -0
  168. /thestage/{services/clients/thestage_api/dtos/inference_controller → inference_simulator/dto}/inference_simulator_list_request.py +0 -0
  169. /thestage/{services/clients/thestage_api/dtos → inference_simulator/dto}/inference_simulator_response.py +0 -0
  170. /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/cpu_type.py +0 -0
  171. /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/gpu_name.py +0 -0
  172. /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/instance_rented_status.py +0 -0
  173. /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/provider_name.py +0 -0
  174. /thestage/{services/clients/thestage_api/dtos/enums → instance/dto/enum}/selfhosted_status.py +0 -0
  175. /thestage/{entities → instance/dto}/rented_instance.py +0 -0
  176. /thestage/{entities → instance/dto}/self_hosted_instance.py +0 -0
  177. /thestage/{services/logging → logging}/byte_print_style.py +0 -0
  178. /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/docker_container_log_stream_request.py +0 -0
  179. /thestage/{services/logging → logging}/dto/log_message.py +0 -0
  180. /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/log_polling_request.py +0 -0
  181. /thestage/{services/logging → logging}/dto/log_type.py +0 -0
  182. /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/task_log_stream_request.py +0 -0
  183. /thestage/{services/clients/thestage_api/dtos/logging_controller → logging/dto}/user_logs_query_request.py +0 -0
  184. /thestage/{services/logging → logging}/logging_constants.py +0 -0
  185. /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
  186. /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
  187. /thestage/{services/project → project}/dto/project_config.py +0 -0
  188. /thestage/{services/clients/thestage_api/dtos → project/dto}/project_response.py +0 -0
  189. /thestage/{services/clients/thestage_api/dtos/enums → task/dto/enum}/task_execution_status.py +0 -0
  190. /thestage/{services/clients/thestage_api/dtos/enums → task/dto/enum}/task_status.py +0 -0
  191. /thestage/{services/clients/thestage_api/dtos/task_controller/task_list_for_project_request.py → task/dto/list_for_project_request.py} +0 -0
  192. /thestage/{services/clients/thestage_api/dtos/task_controller/task_status_localized_map_response.py → task/dto/status_localized_map_response.py} +0 -0
  193. {thestage-0.6.7.dist-info → thestage-0.6.8.dist-info}/entry_points.txt +0 -0
  194. {thestage-0.6.7.dist-info → thestage-0.6.8.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%. Please 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("Please 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("Please 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%. Please 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%. Please 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 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.entities.project_inference_simulator_model import ProjectInferenceSimulatorModelEntity
3
+ from thestage.inference_model.dto.inference_model_entity import InferenceModelEntity
4
4
  from thestage.services.abstract_mapper import AbstractMapper
5
- from thestage.services.project.dto.inference_simulator_model_dto import InferenceSimulatorModelDto
5
+ from thestage.inference_model.dto.inference_model import InferenceModel
6
6
 
7
7
 
8
- class ProjectInferenceSimulatorModelMapper(AbstractMapper):
9
- def build_entity(self, item: InferenceSimulatorModelDto) -> Optional[ProjectInferenceSimulatorModelEntity]:
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 ProjectInferenceSimulatorModelEntity(
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