maxframe 2.2.0__cp39-cp39-macosx_10_9_universal2.whl → 2.3.0rc1__cp39-cp39-macosx_10_9_universal2.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 maxframe might be problematic. Click here for more details.

Files changed (114) hide show
  1. maxframe/_utils.cpython-39-darwin.so +0 -0
  2. maxframe/codegen/core.py +3 -2
  3. maxframe/codegen/spe/dataframe/merge.py +4 -0
  4. maxframe/codegen/spe/dataframe/misc.py +2 -0
  5. maxframe/codegen/spe/dataframe/reduction.py +18 -0
  6. maxframe/codegen/spe/dataframe/sort.py +9 -1
  7. maxframe/codegen/spe/dataframe/tests/test_reduction.py +13 -0
  8. maxframe/codegen/spe/dataframe/tseries.py +9 -0
  9. maxframe/codegen/spe/learn/contrib/lightgbm.py +4 -3
  10. maxframe/codegen/spe/tensor/datasource.py +1 -0
  11. maxframe/config/config.py +3 -0
  12. maxframe/conftest.py +10 -0
  13. maxframe/core/base.py +2 -1
  14. maxframe/core/entity/tileables.py +2 -0
  15. maxframe/core/graph/core.cpython-39-darwin.so +0 -0
  16. maxframe/core/graph/entity.py +7 -1
  17. maxframe/core/mode.py +6 -1
  18. maxframe/dataframe/__init__.py +2 -2
  19. maxframe/dataframe/arithmetic/__init__.py +4 -0
  20. maxframe/dataframe/arithmetic/maximum.py +33 -0
  21. maxframe/dataframe/arithmetic/minimum.py +33 -0
  22. maxframe/dataframe/core.py +98 -106
  23. maxframe/dataframe/datasource/core.py +6 -0
  24. maxframe/dataframe/datasource/direct.py +57 -0
  25. maxframe/dataframe/datasource/read_csv.py +19 -11
  26. maxframe/dataframe/datasource/read_odps_query.py +29 -6
  27. maxframe/dataframe/datasource/read_odps_table.py +32 -10
  28. maxframe/dataframe/datasource/read_parquet.py +38 -39
  29. maxframe/dataframe/datastore/__init__.py +6 -0
  30. maxframe/dataframe/datastore/direct.py +268 -0
  31. maxframe/dataframe/datastore/to_odps.py +6 -0
  32. maxframe/dataframe/extensions/flatjson.py +2 -1
  33. maxframe/dataframe/groupby/__init__.py +5 -1
  34. maxframe/dataframe/groupby/aggregation.py +10 -6
  35. maxframe/dataframe/groupby/apply_chunk.py +1 -3
  36. maxframe/dataframe/groupby/core.py +20 -4
  37. maxframe/dataframe/indexing/__init__.py +2 -1
  38. maxframe/dataframe/indexing/insert.py +45 -17
  39. maxframe/dataframe/merge/__init__.py +3 -0
  40. maxframe/dataframe/merge/combine.py +244 -0
  41. maxframe/dataframe/misc/__init__.py +14 -3
  42. maxframe/dataframe/misc/check_unique.py +41 -10
  43. maxframe/dataframe/misc/drop.py +31 -0
  44. maxframe/dataframe/misc/infer_dtypes.py +251 -0
  45. maxframe/dataframe/misc/map.py +31 -18
  46. maxframe/dataframe/misc/repeat.py +159 -0
  47. maxframe/dataframe/misc/tests/test_misc.py +35 -1
  48. maxframe/dataframe/missing/checkna.py +3 -2
  49. maxframe/dataframe/reduction/__init__.py +10 -5
  50. maxframe/dataframe/reduction/aggregation.py +6 -6
  51. maxframe/dataframe/reduction/argmax.py +7 -4
  52. maxframe/dataframe/reduction/argmin.py +7 -4
  53. maxframe/dataframe/reduction/core.py +18 -9
  54. maxframe/dataframe/reduction/mode.py +144 -0
  55. maxframe/dataframe/reduction/nunique.py +10 -3
  56. maxframe/dataframe/reduction/tests/test_reduction.py +12 -0
  57. maxframe/dataframe/sort/__init__.py +9 -2
  58. maxframe/dataframe/sort/argsort.py +7 -1
  59. maxframe/dataframe/sort/core.py +1 -1
  60. maxframe/dataframe/sort/rank.py +147 -0
  61. maxframe/dataframe/tseries/__init__.py +19 -0
  62. maxframe/dataframe/tseries/at_time.py +61 -0
  63. maxframe/dataframe/tseries/between_time.py +122 -0
  64. maxframe/dataframe/utils.py +30 -26
  65. maxframe/learn/contrib/llm/core.py +16 -7
  66. maxframe/learn/contrib/llm/deploy/__init__.py +13 -0
  67. maxframe/learn/contrib/llm/deploy/config.py +221 -0
  68. maxframe/learn/contrib/llm/deploy/core.py +247 -0
  69. maxframe/learn/contrib/llm/deploy/framework.py +35 -0
  70. maxframe/learn/contrib/llm/deploy/loader.py +360 -0
  71. maxframe/learn/contrib/llm/deploy/tests/__init__.py +13 -0
  72. maxframe/learn/contrib/llm/deploy/tests/test_register_models.py +359 -0
  73. maxframe/learn/contrib/llm/models/__init__.py +1 -0
  74. maxframe/learn/contrib/llm/models/dashscope.py +12 -6
  75. maxframe/learn/contrib/llm/models/managed.py +76 -11
  76. maxframe/learn/contrib/llm/models/openai.py +72 -0
  77. maxframe/learn/contrib/llm/tests/__init__.py +13 -0
  78. maxframe/learn/contrib/llm/tests/test_core.py +34 -0
  79. maxframe/learn/contrib/llm/tests/test_openai.py +187 -0
  80. maxframe/learn/contrib/llm/tests/test_text_gen.py +155 -0
  81. maxframe/learn/contrib/llm/text.py +348 -42
  82. maxframe/learn/contrib/models.py +4 -1
  83. maxframe/learn/contrib/xgboost/classifier.py +2 -0
  84. maxframe/learn/contrib/xgboost/core.py +31 -7
  85. maxframe/learn/contrib/xgboost/predict.py +4 -2
  86. maxframe/learn/contrib/xgboost/regressor.py +5 -0
  87. maxframe/learn/contrib/xgboost/train.py +2 -0
  88. maxframe/learn/preprocessing/_data/min_max_scaler.py +34 -23
  89. maxframe/learn/preprocessing/_data/standard_scaler.py +34 -25
  90. maxframe/learn/utils/__init__.py +1 -0
  91. maxframe/learn/utils/extmath.py +42 -9
  92. maxframe/learn/utils/odpsio.py +80 -11
  93. maxframe/lib/filesystem/_oss_lib/common.py +2 -0
  94. maxframe/lib/mmh3.cpython-39-darwin.so +0 -0
  95. maxframe/opcodes.py +9 -1
  96. maxframe/remote/core.py +4 -0
  97. maxframe/serialization/core.cpython-39-darwin.so +0 -0
  98. maxframe/serialization/tests/test_serial.py +2 -2
  99. maxframe/tensor/arithmetic/__init__.py +1 -1
  100. maxframe/tensor/arithmetic/core.py +2 -2
  101. maxframe/tensor/arithmetic/tests/test_arithmetic.py +0 -9
  102. maxframe/tensor/core.py +3 -0
  103. maxframe/tensor/misc/copyto.py +1 -1
  104. maxframe/tests/test_udf.py +61 -0
  105. maxframe/tests/test_utils.py +8 -5
  106. maxframe/udf.py +103 -7
  107. maxframe/utils.py +61 -8
  108. {maxframe-2.2.0.dist-info → maxframe-2.3.0rc1.dist-info}/METADATA +1 -2
  109. {maxframe-2.2.0.dist-info → maxframe-2.3.0rc1.dist-info}/RECORD +113 -90
  110. maxframe_client/session/task.py +8 -1
  111. maxframe_client/tests/test_session.py +24 -0
  112. maxframe/dataframe/arrays.py +0 -864
  113. {maxframe-2.2.0.dist-info → maxframe-2.3.0rc1.dist-info}/WHEEL +0 -0
  114. {maxframe-2.2.0.dist-info → maxframe-2.3.0rc1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,247 @@
1
+ # Copyright 1999-2025 Alibaba Group Holding Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import Any, Dict, List, Optional, Union
16
+
17
+ from odps.models import Resource as ODPSResource
18
+
19
+ from .....serialization.serializables import Serializable, StringField
20
+ from .config import ModelDeploymentConfig
21
+ from .framework import InferenceFrameworkEnum
22
+
23
+ _registered_llm_models = {}
24
+
25
+
26
+ class ResourceNameTemplate(Serializable):
27
+ """
28
+ A template-based resource name builder that supports variable substitution.
29
+ All values in the substitution dict will have their hyphens (-) replaced with underscores (_).
30
+
31
+ Example:
32
+ template = ResourceNameTemplate(
33
+ project="my_project",
34
+ schema="schema_{region_id}",
35
+ name="resource_{env}"
36
+ )
37
+ # Render with variables
38
+ full_name = template.build_full_resource_name({"region_id": "cn-hangzhou", "env": "prod"})
39
+ # Result: resource name with cn_hangzhou and prod substituted
40
+ """
41
+
42
+ project: str = StringField("project", default=None)
43
+ schema: str = StringField("schema", default=None)
44
+ name: str = StringField("name")
45
+
46
+ def build_full_resource_name(self, template_vars: Dict[str, Any]):
47
+ """
48
+ Build full resource name with template variable substitution.
49
+ """
50
+ normalized_vars = {
51
+ key: str(value).replace("-", "_") for key, value in template_vars.items()
52
+ }
53
+
54
+ project, schema, name = self.project, self.schema, self.name
55
+ res_name = ODPSResource.build_full_resource_name(
56
+ name=name, project_name=project, schema_name=schema
57
+ )
58
+ try:
59
+ return res_name.format(**normalized_vars)
60
+ except KeyError:
61
+ # If template variable is missing, return as-is
62
+ return res_name
63
+
64
+ def __eq__(self, other):
65
+ if not isinstance(other, ResourceNameTemplate):
66
+ return False
67
+ return (
68
+ self.project == other.project
69
+ and self.schema == other.schema
70
+ and self.name == other.name
71
+ )
72
+
73
+ def __hash__(self):
74
+ return hash((self.project, self.schema, self.name))
75
+
76
+ def to_json(self) -> dict:
77
+ ret = {"name": self.name}
78
+ if self.project:
79
+ ret["project"] = self.project
80
+ if self.schema:
81
+ ret["schema"] = self.schema
82
+ return ret
83
+
84
+ @classmethod
85
+ def from_json(cls, serialized: dict) -> "ResourceNameTemplate":
86
+ kw = serialized.copy()
87
+ return cls(
88
+ project=kw.get("project"),
89
+ schema=kw.get("schema"),
90
+ name=kw["name"],
91
+ )
92
+
93
+
94
+ def create_model_deployments(
95
+ model_name: str,
96
+ model_file: str,
97
+ inference_frameworks: Union[
98
+ str, InferenceFrameworkEnum, List[InferenceFrameworkEnum]
99
+ ],
100
+ required_resources: List[Union[str, ResourceNameTemplate]] = None,
101
+ default_load_params: Optional[Dict[str, Any]] = None,
102
+ required_cpu: Optional[float] = None,
103
+ required_memory: Optional[int] = None,
104
+ required_gu: Optional[int] = None,
105
+ required_gpu_memory: Optional[int] = None,
106
+ device: str = None,
107
+ properties: Optional[Dict[str, Any]] = None,
108
+ tags: Optional[List[str]] = None,
109
+ ):
110
+ frameworks_to_register = (
111
+ [inference_frameworks]
112
+ if isinstance(inference_frameworks, (str, InferenceFrameworkEnum))
113
+ else inference_frameworks
114
+ )
115
+
116
+ deployment_configs = []
117
+ for inference_framework in frameworks_to_register:
118
+ inference_framework = (
119
+ InferenceFrameworkEnum.from_string(inference_framework)
120
+ if isinstance(inference_framework, str)
121
+ else inference_framework
122
+ )
123
+
124
+ model_config = ModelDeploymentConfig(
125
+ model_name=model_name,
126
+ model_file=model_file,
127
+ inference_framework_type=inference_framework,
128
+ required_resource_files=required_resources,
129
+ load_params=default_load_params,
130
+ required_cpu=required_cpu,
131
+ required_memory=required_memory,
132
+ required_gu=required_gu,
133
+ required_gpu_memory=required_gpu_memory,
134
+ device=device,
135
+ properties=properties,
136
+ tags=tags,
137
+ )
138
+ deployment_configs.append(model_config)
139
+ return deployment_configs
140
+
141
+
142
+ def register_model_deployments(
143
+ model_name: str,
144
+ model_file: str,
145
+ inference_frameworks: Union[
146
+ str, InferenceFrameworkEnum, List[InferenceFrameworkEnum]
147
+ ],
148
+ required_resources: List[Union[str, ResourceNameTemplate]] = None,
149
+ default_load_params: Optional[Dict[str, Any]] = None,
150
+ required_cpu: Optional[float] = None,
151
+ required_memory: Optional[int] = None,
152
+ required_gu: Optional[int] = None,
153
+ required_gpu_memory: Optional[int] = None,
154
+ device: str = None,
155
+ properties: Optional[Dict[str, Any]] = None,
156
+ tags: Optional[List[str]] = None,
157
+ ):
158
+ """
159
+ Register model deployments
160
+
161
+ Notes
162
+ -----
163
+ - Alpha version for model deployments, all fields could be changed in the future.
164
+ """
165
+ model_name = model_name.lower()
166
+ if not isinstance(inference_frameworks, (InferenceFrameworkEnum, List, str)):
167
+ raise TypeError(
168
+ f"inference_framework_type must be type InferenceFrameworkEnum or List[InferenceFrameworkEnum] but {type(inference_frameworks)}"
169
+ )
170
+
171
+ model_deployments = create_model_deployments(
172
+ model_name=model_name,
173
+ model_file=model_file,
174
+ inference_frameworks=inference_frameworks,
175
+ required_resources=required_resources,
176
+ default_load_params=default_load_params,
177
+ required_cpu=required_cpu,
178
+ required_memory=required_memory,
179
+ required_gu=required_gu,
180
+ required_gpu_memory=required_gpu_memory,
181
+ device=device,
182
+ properties=properties,
183
+ tags=tags,
184
+ )
185
+
186
+ for deployment in model_deployments:
187
+ if model_name not in _registered_llm_models:
188
+ _registered_llm_models[model_name] = {}
189
+ if deployment.device not in _registered_llm_models[model_name]:
190
+ _registered_llm_models[model_name][deployment.device] = {}
191
+
192
+ existing = _registered_llm_models[model_name][deployment.device].get(
193
+ deployment.inference_framework_type
194
+ )
195
+
196
+ if existing:
197
+ raise ValueError(
198
+ f"Model {model_name} with {deployment.inference_framework_type} on {deployment.device} already registered"
199
+ )
200
+
201
+ _registered_llm_models[model_name][deployment.device][
202
+ deployment.inference_framework_type
203
+ ] = deployment
204
+
205
+ return model_deployments
206
+
207
+
208
+ def get_registered_model_config(
209
+ model_name: str,
210
+ expected_device: Optional[str] = None,
211
+ expected_inference_framework: Optional[InferenceFrameworkEnum] = None,
212
+ ) -> Optional[ModelDeploymentConfig]:
213
+ model_name = model_name.lower()
214
+
215
+ def _load_model_framework_config(framework_configs, expected_framework):
216
+ if expected_framework is not None:
217
+ return framework_configs[expected_framework]
218
+ else:
219
+ model_config = next(iter(framework_configs.values()))
220
+ return model_config
221
+
222
+ try:
223
+ if expected_device is not None:
224
+ model_framework_configs = _registered_llm_models[model_name][
225
+ expected_device
226
+ ]
227
+ return _load_model_framework_config(
228
+ model_framework_configs, expected_inference_framework
229
+ )
230
+ else:
231
+ model_all_configs = _registered_llm_models[model_name]
232
+ for device, model_framework_configs in model_all_configs.items():
233
+ model_config = _load_model_framework_config(
234
+ model_framework_configs, expected_inference_framework
235
+ )
236
+ if model_config:
237
+ return model_config
238
+ except KeyError:
239
+ pass
240
+ except StopIteration:
241
+ pass
242
+
243
+ return None
244
+
245
+
246
+ def clean_registered_model():
247
+ _registered_llm_models.clear()
@@ -0,0 +1,35 @@
1
+ # Copyright 1999-2025 Alibaba Group Holding Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from enum import Enum
16
+
17
+
18
+ class InferenceFrameworkEnum(Enum):
19
+ LLAMA_CPP_PYTHON_TEXT = "LLAMA_CPP_PYTHON:TEXT"
20
+ LLAMA_CPP_SERVE_TEXT = "LLAMA_CPP_SERVE:TEXT"
21
+ DASH_SCOPE_TEXT = "DASH_SCOPE:TEXT"
22
+ DASH_SCOPE_MULTIMODAL = "DASH_SCOPE:MULTIMODAL"
23
+ VLLM_SERVE_TEXT = "VLLM_SERVE:TEXT"
24
+ OPENAI_REMOTE_TEXT = "OPENAI_REMOTE:TEXT"
25
+ OTHER = "OTHER"
26
+
27
+ @classmethod
28
+ def from_string(cls, label):
29
+ if label is None:
30
+ return None
31
+
32
+ if isinstance(label, cls):
33
+ return label
34
+
35
+ return cls(label)
@@ -0,0 +1,360 @@
1
+ # Copyright 1999-2025 Alibaba Group Holding Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import json
16
+ from typing import Any, Dict, List, Optional
17
+
18
+ from .....protocol import JsonSerializable
19
+ from .....serialization.serializables import (
20
+ DictField,
21
+ FieldTypes,
22
+ Int32Field,
23
+ ListField,
24
+ ReferenceField,
25
+ StringField,
26
+ )
27
+ from .core import ResourceNameTemplate, register_model_deployments
28
+
29
+ _ALLOWED_DEVICES = {"cpu", "gpu", "ppu", "tpu", "cuda"}
30
+
31
+
32
+ class DeploymentConfigResourceRequirement(JsonSerializable):
33
+ cpu: int = Int32Field("cpu", default=1)
34
+ memory: int = Int32Field("memory", default=4)
35
+ gu: int = Int32Field("gu", default=0)
36
+ gpu_memory: int = Int32Field("gpu_memory", default=0)
37
+
38
+ def __init__(self, cpu, memory, **kw):
39
+ gu = kw.get("gu")
40
+ gpu_memory = kw.get("gpu_memory")
41
+ if (
42
+ not isinstance(cpu, int)
43
+ or not isinstance(memory, int)
44
+ or (gu and not isinstance(gu, int))
45
+ or (gpu_memory and not isinstance(gpu_memory, int))
46
+ ):
47
+ raise TypeError("cpu, memory, gpu and gpu_memory must be int")
48
+ super().__init__(cpu=cpu, memory=memory, gu=gu, gpu_memory=gpu_memory)
49
+
50
+ def to_json(self) -> dict:
51
+ ret = {
52
+ "cpu": self.cpu,
53
+ "memory": self.memory,
54
+ "gu": self.gu,
55
+ "gpu_memory": self.gpu_memory,
56
+ }
57
+ return ret
58
+
59
+ @classmethod
60
+ def from_json(cls, serialized: dict) -> "DeploymentConfigResourceRequirement":
61
+ return cls(
62
+ cpu=serialized.get("cpu", 1),
63
+ memory=serialized.get("memory", 4),
64
+ gu=serialized.get("gu", 0),
65
+ gpu_memory=serialized.get("gpu_memory", 0),
66
+ )
67
+
68
+
69
+ class DeploymentConfigBase(JsonSerializable):
70
+ model_file: Optional[str] = StringField("model_file", default=None)
71
+ model_file_resources: List[ResourceNameTemplate] = ListField(
72
+ "model_file_resources", field_type=FieldTypes.reference, default_factory=list
73
+ )
74
+ resource_requirements: Optional[
75
+ DeploymentConfigResourceRequirement
76
+ ] = ReferenceField(
77
+ "resource_requirements", DeploymentConfigResourceRequirement, default=None
78
+ )
79
+ load_params: Optional[Dict[str, Any]] = DictField(
80
+ "load_params",
81
+ key_type=FieldTypes.string,
82
+ value_type=FieldTypes.any,
83
+ default_factory=dict,
84
+ )
85
+ properties: Dict[str, Any] = DictField(
86
+ "properties",
87
+ key_type=FieldTypes.string,
88
+ value_type=FieldTypes.any,
89
+ default_factory=dict,
90
+ )
91
+
92
+ def __init__(
93
+ self,
94
+ model_file=None,
95
+ model_file_resources=None,
96
+ resource_requirements=None,
97
+ load_params=None,
98
+ properties=None,
99
+ **kw,
100
+ ):
101
+ if model_file and not isinstance(model_file, str):
102
+ raise TypeError("model_file must be a string")
103
+ if resource_requirements and not isinstance(
104
+ resource_requirements, DeploymentConfigResourceRequirement
105
+ ):
106
+ raise TypeError(
107
+ "resource_requirements must be a DeploymentConfigResourceRequirement"
108
+ )
109
+ if load_params and not isinstance(load_params, dict):
110
+ raise TypeError("load_params must be a dict")
111
+ if properties and not isinstance(properties, dict):
112
+ raise TypeError("properties must be a dict")
113
+ if model_file_resources:
114
+ if not isinstance(model_file_resources, list):
115
+ raise TypeError("model_file_resources must be a list")
116
+ if not all(
117
+ isinstance(res, ResourceNameTemplate) for res in model_file_resources
118
+ ):
119
+ raise TypeError(
120
+ "model_file_resources must be a list of ResourceNameTemplate"
121
+ )
122
+
123
+ super().__init__(
124
+ model_file=model_file,
125
+ model_file_resources=model_file_resources,
126
+ load_params=load_params,
127
+ resource_requirements=resource_requirements,
128
+ properties=properties,
129
+ **kw,
130
+ )
131
+
132
+ @classmethod
133
+ def from_json(cls, serialized: dict) -> "DeploymentConfigBase":
134
+ kw = serialized.copy()
135
+ resource_requirements_data = kw.get("resource_requirements")
136
+ return cls(
137
+ model_file=kw.get("model_file"),
138
+ model_file_resources=[
139
+ ResourceNameTemplate.from_json(res)
140
+ for res in kw.get("model_file_resources", [])
141
+ ],
142
+ load_params=kw.get("load_params", {}),
143
+ resource_requirements=(
144
+ DeploymentConfigResourceRequirement.from_json(
145
+ resource_requirements_data
146
+ )
147
+ if resource_requirements_data
148
+ else None
149
+ ),
150
+ properties=kw.get("properties", {}),
151
+ )
152
+
153
+ def to_json(self) -> dict:
154
+ return {
155
+ "properties": self.properties,
156
+ "load_params": self.load_params,
157
+ "model_file": self.model_file,
158
+ "model_file_resources": [
159
+ res.to_json() for res in self.model_file_resources
160
+ ],
161
+ "resource_requirements": (
162
+ self.resource_requirements.to_json()
163
+ if self.resource_requirements
164
+ else None
165
+ ),
166
+ }
167
+
168
+
169
+ class FrameworkDeploymentConfig(DeploymentConfigBase):
170
+ framework: str = StringField("framework")
171
+ device: str = StringField("device", default="cpu")
172
+
173
+ def __init__(
174
+ self,
175
+ **kw,
176
+ ):
177
+ framework = kw.get("framework")
178
+ if not framework:
179
+ raise ValueError("framework is required")
180
+
181
+ device = kw.get("device")
182
+ if not device:
183
+ device = "cpu"
184
+ if device not in _ALLOWED_DEVICES:
185
+ raise ValueError(f"device must be one of {_ALLOWED_DEVICES}")
186
+
187
+ super().__init__(**kw)
188
+
189
+ @classmethod
190
+ def from_json(cls, serialized: dict) -> "FrameworkDeploymentConfig":
191
+ kw = serialized.copy()
192
+ resource_requirements_data = kw.get("resource_requirements")
193
+ return cls(
194
+ model_file=kw.get("model_file"),
195
+ model_file_resources=[
196
+ ResourceNameTemplate.from_json(res)
197
+ for res in kw.get("model_file_resources", [])
198
+ ],
199
+ load_params=kw.get("load_params", {}),
200
+ resource_requirements=(
201
+ DeploymentConfigResourceRequirement.from_json(
202
+ resource_requirements_data
203
+ )
204
+ if resource_requirements_data
205
+ else None
206
+ ),
207
+ properties=kw.get("properties", {}),
208
+ framework=kw["framework"],
209
+ device=kw.get("device", "cpu"),
210
+ )
211
+
212
+ def to_json(self):
213
+ ret = super().to_json()
214
+ ret["framework"] = self.framework
215
+ ret["device"] = self.device
216
+ return ret
217
+
218
+
219
+ class ModelDeploymentConfig(JsonSerializable):
220
+ model_name: str = StringField("model_name")
221
+ common_config: DeploymentConfigBase = ReferenceField(
222
+ "common_config", DeploymentConfigBase, default_factory=DeploymentConfigBase
223
+ )
224
+ deployments: List[FrameworkDeploymentConfig] = ListField(
225
+ "deployments", field_type=FieldTypes.reference, default_factory=list
226
+ )
227
+ tags: List[str] = ListField(
228
+ "tags", field_type=FieldTypes.string, default_factory=list
229
+ )
230
+
231
+ def __init__(self, model_name, deployments, **kwargs):
232
+ if not model_name:
233
+ raise ValueError("model_name is required")
234
+ if not deployments:
235
+ raise ValueError("deployments is required")
236
+ else:
237
+ if not isinstance(deployments, list):
238
+ raise TypeError("deployments must be a list")
239
+ if not all(
240
+ isinstance(deployment, FrameworkDeploymentConfig)
241
+ for deployment in deployments
242
+ ):
243
+ raise TypeError(
244
+ "deployments must be a list of FrameworkDeploymentConfig"
245
+ )
246
+ super().__init__(model_name=model_name, deployments=deployments, **kwargs)
247
+
248
+ def to_json(self) -> dict:
249
+ ret = {
250
+ "model_name": self.model_name,
251
+ "tags": self.tags,
252
+ }
253
+ if self.common_config:
254
+ ret["common_config"] = self.common_config.to_json()
255
+ if self.deployments:
256
+ ret["deployments"] = [
257
+ deployment.to_json() for deployment in self.deployments
258
+ ]
259
+ return ret
260
+
261
+ @classmethod
262
+ def from_json(cls, serialized: dict) -> "ModelDeploymentConfig":
263
+ kw = serialized.copy()
264
+ return cls(
265
+ model_name=kw["model_name"],
266
+ common_config=(
267
+ DeploymentConfigBase.from_json(kw.get("common_config", {}))
268
+ if kw.get("common_config")
269
+ else None
270
+ ),
271
+ deployments=[
272
+ FrameworkDeploymentConfig.from_json(deployment)
273
+ for deployment in kw.get("deployments", [])
274
+ ],
275
+ tags=kw.get("tags", []),
276
+ )
277
+
278
+
279
+ def _model_config_from_json(json_content: str) -> List[ModelDeploymentConfig]:
280
+ data_list = json.loads(json_content)
281
+ if not isinstance(data_list, list):
282
+ raise ValueError("JSON root must be a list of model configurations.")
283
+ return [ModelDeploymentConfig.from_json(item_data) for item_data in data_list]
284
+
285
+
286
+ def _model_config_to_json(
287
+ model_configs: List[ModelDeploymentConfig],
288
+ ) -> str:
289
+ data_list = [config.to_json() for config in model_configs]
290
+ return json.dumps(data_list, ensure_ascii=False)
291
+
292
+
293
+ def register_models_from_json_file(config_path):
294
+ """
295
+ Loads model configurations from a JSON file and registers them.
296
+ """
297
+
298
+ with open(config_path, "r") as f:
299
+ model_list = _model_config_from_json(f.read())
300
+
301
+ if not model_list:
302
+ return
303
+
304
+ for model in model_list:
305
+ common_config = model.common_config or DeploymentConfigBase()
306
+ deployments = model.deployments
307
+
308
+ for deployment in deployments:
309
+ model_file = deployment.model_file or common_config.model_file
310
+ model_file_resources = (
311
+ deployment.model_file_resources
312
+ or common_config.model_file_resources
313
+ )
314
+
315
+ properties = deployment.properties or common_config.properties
316
+ load_params = deployment.load_params or common_config.load_params
317
+ calc_resources = (
318
+ deployment.resource_requirements
319
+ or common_config.resource_requirements
320
+ )
321
+ tags = list(set(model.tags or []))
322
+
323
+ register_model_deployments(
324
+ model_name=model.model_name,
325
+ model_file=model_file,
326
+ inference_frameworks=deployment.framework,
327
+ required_resources=[
328
+ ResourceNameTemplate(
329
+ project=resource_item.project,
330
+ schema=resource_item.schema,
331
+ name=resource_item.name,
332
+ )
333
+ for resource_item in model_file_resources
334
+ ],
335
+ default_load_params=load_params,
336
+ required_cpu=calc_resources.cpu,
337
+ required_memory=calc_resources.memory,
338
+ required_gu=calc_resources.gu,
339
+ required_gpu_memory=calc_resources.gpu_memory,
340
+ device=deployment.device,
341
+ properties=properties,
342
+ tags=tags,
343
+ )
344
+
345
+
346
+ def register_models_from_dir(config_dir):
347
+ """
348
+ Loads model configurations from a directory and registers them.
349
+ """
350
+ from pathlib import Path
351
+
352
+ model_json_files = list(Path(config_dir).glob("*_models.json"))
353
+
354
+ for file_path in model_json_files:
355
+ try:
356
+ register_models_from_json_file(file_path)
357
+ except Exception as e:
358
+ raise ValueError(
359
+ f"Failed to load model config from {file_path}, error: {e}"
360
+ )
@@ -0,0 +1,13 @@
1
+ # Copyright 1999-2025 Alibaba Group Holding Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.