volcengine-python-sdk-aicc 0.0.41__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 (60) hide show
  1. bytedance/__init__.py +4 -0
  2. bytedance/jeddak_secure_channel/__init__.py +28 -0
  3. bytedance/jeddak_secure_channel/client.py +305 -0
  4. bytedance/jeddak_secure_channel/config.py +171 -0
  5. bytedance/jeddak_secure_channel/consts.py +5 -0
  6. bytedance/jeddak_secure_channel/crypto/__init__.py +14 -0
  7. bytedance/jeddak_secure_channel/crypto/aes.py +174 -0
  8. bytedance/jeddak_secure_channel/crypto/envelope.py +395 -0
  9. bytedance/jeddak_secure_channel/crypto/rsa.py +164 -0
  10. bytedance/jeddak_secure_channel/error.py +131 -0
  11. bytedance/jeddak_secure_channel/log/__init__.py +23 -0
  12. bytedance/jeddak_secure_channel/log/config.py +31 -0
  13. bytedance/jeddak_secure_channel/log/logger.py +88 -0
  14. bytedance/jeddak_secure_channel/logger_factory.py +134 -0
  15. bytedance/jeddak_secure_channel/ra.py +772 -0
  16. bytedance/jeddak_secure_channel/server.py +745 -0
  17. bytedance/jeddak_secure_channel/service/__init__.py +16 -0
  18. bytedance/jeddak_secure_channel/service/eps.py +133 -0
  19. bytedance/jeddak_secure_channel/service/eps_models.py +47 -0
  20. bytedance/jeddak_secure_channel/service/ras.py +88 -0
  21. bytedance/jeddak_secure_channel/service/tks.py +51 -0
  22. bytedance/jeddak_secure_channel/service/tks_models.py +334 -0
  23. bytedance/jeddak_secure_channel/utils.py +469 -0
  24. bytedance/jeddak_secure_model/model_automation_tool.py +181 -0
  25. bytedance/jeddak_secure_model/model_encryption.py +416 -0
  26. bytedance/jeddak_secure_model/model_hub_admin.py +116 -0
  27. bytedance/jeddak_secure_model/pcc_utils.py +279 -0
  28. bytedance/jeddak_secure_model/rds_utils.py +63 -0
  29. bytedance/tks/attester.py +41 -0
  30. bytedance/tks/client.py +629 -0
  31. bytedance/tks/consts.py +122 -0
  32. bytedance/tks/crypto/aes.py +47 -0
  33. bytedance/tks/crypto/ec.py +39 -0
  34. bytedance/tks/exceptions.py +22 -0
  35. bytedance/volcengine_aicc_sdk/__init__.py +14 -0
  36. bytedance/volcengine_aicc_sdk/aicc_client.py +277 -0
  37. bytedance/volcengine_aicc_sdk/aicc_inference.py +64 -0
  38. bytedance/volcengine_aicc_sdk/ark_inference_client.py +343 -0
  39. bytedance/volcengine_aicc_sdk/asr_inference_client.py +158 -0
  40. bytedance/volcengine_aicc_sdk/asr_websocket_client.py +705 -0
  41. bytedance/volcengine_aicc_sdk/auc_inference_client.py +305 -0
  42. bytedance/volcengine_aicc_sdk/common/__init__.py +0 -0
  43. bytedance/volcengine_aicc_sdk/common/aes.py +136 -0
  44. bytedance/volcengine_aicc_sdk/common/constant.py +4 -0
  45. bytedance/volcengine_aicc_sdk/common/error.py +21 -0
  46. bytedance/volcengine_aicc_sdk/common/log/__init__.py +24 -0
  47. bytedance/volcengine_aicc_sdk/common/log/config.py +31 -0
  48. bytedance/volcengine_aicc_sdk/common/log/logger.py +88 -0
  49. bytedance/volcengine_aicc_sdk/common/tos_utils.py +341 -0
  50. bytedance/volcengine_aicc_sdk/common/utils.py +45 -0
  51. bytedance/volcengine_aicc_sdk/cu_inference_client.py +292 -0
  52. bytedance/volcengine_aicc_sdk/deepseek_inference_client.py +501 -0
  53. bytedance/volcengine_aicc_sdk/secure_http_client.py +406 -0
  54. bytedance/volcengine_aicc_sdk/seedance_inference_client.py +500 -0
  55. bytedance/volcengine_aicc_sdk/seedream_inference_client.py +213 -0
  56. volcengine_python_sdk_aicc-0.0.41.dist-info/METADATA +79 -0
  57. volcengine_python_sdk_aicc-0.0.41.dist-info/RECORD +60 -0
  58. volcengine_python_sdk_aicc-0.0.41.dist-info/WHEEL +5 -0
  59. volcengine_python_sdk_aicc-0.0.41.dist-info/licenses/LICENSE +202 -0
  60. volcengine_python_sdk_aicc-0.0.41.dist-info/top_level.txt +1 -0
@@ -0,0 +1,279 @@
1
+ """
2
+ Copyright (year) Beijing Volcano Engine Technology Ltd.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ """
16
+
17
+ import hashlib
18
+ import hmac
19
+ from urllib.parse import quote
20
+ import json
21
+ import requests
22
+ from datetime import datetime, timezone
23
+
24
+
25
+ # 以下参数视服务不同而不同,一个服务内通常是一致的
26
+ # Service = "pcc_test"
27
+ Version = "2024-12-24"
28
+ Region = "cn-beijing"
29
+ Host = "pcc.volcengineapi.com"
30
+ ContentType = "application/json"
31
+
32
+
33
+ def norm_query(params):
34
+ query = ""
35
+ for key in sorted(params.keys()):
36
+ if isinstance(params[key], list):
37
+ for k in params[key]:
38
+ query = (
39
+ query + quote(key, safe="-_.~") + "=" + quote(k, safe="-_.~") + "&"
40
+ )
41
+ else:
42
+ query = (query + quote(key, safe="-_.~") + "=" + quote(params[key], safe="-_.~") + "&")
43
+ query = query[:-1]
44
+ return query.replace("+", "%20")
45
+
46
+
47
+ # 第一步:准备辅助函数。
48
+ # sha256 非对称加密
49
+ def hmac_sha256(key: bytes, content: str):
50
+ return hmac.new(key, content.encode("utf-8"), hashlib.sha256).digest()
51
+
52
+
53
+ # sha256 hash算法
54
+ def hash_sha256(content: str):
55
+ return hashlib.sha256(content.encode("utf-8")).hexdigest()
56
+
57
+
58
+ def indent_text(text, spaces=4):
59
+ prefix = ' ' * spaces
60
+ return '\n'.join(prefix + line for line in text.splitlines())
61
+
62
+
63
+ # 第二步:签名请求函数
64
+ def request(method, date, query, header, ak, sk, action, body, silent=False, service="pcc"):
65
+ # 第三步:创建身份证明。其中的 Service 和 Region 字段是固定的。ak 和 sk 分别代表
66
+ # AccessKeyID 和 SecretAccessKey。同时需要初始化签名结构体。一些签名计算时需要的属性也在这里处理。
67
+ # 初始化身份证明结构体
68
+ credential = {
69
+ "access_key_id": ak,
70
+ "secret_access_key": sk,
71
+ "service": service,
72
+ "region": Region,
73
+ }
74
+ # 初始化签名结构体
75
+ request_param = {
76
+ "body": body,
77
+ "host": Host,
78
+ "path": "/",
79
+ "method": method,
80
+ "content_type": ContentType,
81
+ "date": date,
82
+ "query": {"Action": action, "Version": Version, **query},
83
+ }
84
+ if body is None:
85
+ request_param["body"] = ""
86
+ # 第四步:接下来开始计算签名。在计算签名前,先准备好用于接收签算结果的 signResult 变量,并设置一些参数。
87
+ # 初始化签名结果的结构体
88
+ x_date = request_param["date"].strftime("%Y%m%dT%H%M%SZ")
89
+ short_x_date = x_date[:8]
90
+ x_content_sha256 = hash_sha256(request_param["body"])
91
+ sign_result = {
92
+ "Host": request_param["host"],
93
+ "X-Content-Sha256": x_content_sha256,
94
+ "X-Date": x_date,
95
+ "Content-Type": request_param["content_type"],
96
+ }
97
+ # 第五步:计算 Signature 签名。
98
+ signed_headers_str = ";".join(
99
+ ["content-type", "host", "x-content-sha256", "x-date"]
100
+ )
101
+ # signed_headers_str = signed_headers_str + ";x-security-token"
102
+ canonical_request_str = "\n".join(
103
+ [request_param["method"].upper(),
104
+ request_param["path"],
105
+ norm_query(request_param["query"]),
106
+ "\n".join(
107
+ [
108
+ "content-type:" + request_param["content_type"],
109
+ "host:" + request_param["host"],
110
+ "x-content-sha256:" + x_content_sha256,
111
+ "x-date:" + x_date,
112
+ ]
113
+ ),
114
+ "",
115
+ signed_headers_str,
116
+ x_content_sha256,
117
+ ]
118
+ )
119
+
120
+ # 打印正规化的请求用于调试比对
121
+ if not silent:
122
+ print(indent_text(canonical_request_str))
123
+ hashed_canonical_request = hash_sha256(canonical_request_str)
124
+
125
+ # 打印hash值用于调试比对
126
+ if not silent:
127
+ print(indent_text(hashed_canonical_request))
128
+ credential_scope = "/".join([short_x_date, credential["region"], credential["service"], "request"])
129
+ string_to_sign = "\n".join(["HMAC-SHA256", x_date, credential_scope, hashed_canonical_request])
130
+
131
+ # 打印最终计算的签名字符串用于调试比对
132
+ if not silent:
133
+ print(indent_text(string_to_sign))
134
+ k_date = hmac_sha256(credential["secret_access_key"].encode("utf-8"), short_x_date)
135
+ k_region = hmac_sha256(k_date, credential["region"])
136
+ k_service = hmac_sha256(k_region, credential["service"])
137
+ k_signing = hmac_sha256(k_service, "request")
138
+ signature = hmac_sha256(k_signing, string_to_sign).hex()
139
+
140
+ sign_result["Authorization"] = "HMAC-SHA256 Credential={}, SignedHeaders={}, Signature={}".format(
141
+ credential["access_key_id"] + "/" + credential_scope,
142
+ signed_headers_str,
143
+ signature,
144
+ )
145
+ formatted_str = json.dumps(sign_result, indent=2) # 字典转为格式化字符串
146
+ indented_str = '\n'.join([' ' + line for line in formatted_str.splitlines()])
147
+ if not silent:
148
+ print(indented_str)
149
+ header = {**header, **sign_result}
150
+ # header = {**header, **{"X-Security-Token": SessionToken}}
151
+ # 第六步:将 Signature 签名写入 HTTP Header 中,并发送 HTTP 请求。
152
+ r = requests.request(method=method,
153
+ url="https://{}{}".format(request_param["host"], request_param["path"]),
154
+ headers=header,
155
+ params=request_param["query"],
156
+ data=request_param["body"],
157
+ )
158
+ return r.json()
159
+
160
+
161
+ def set_tks_policy(AK: str, SK: str, uid: str, key_id: str, policy_id: str, silent: bool = False, service: str = "pcc"):
162
+ now = datetime.utcnow()
163
+ header = {
164
+ "AppID": uid,
165
+ "Token": "",
166
+ "Signature": "",
167
+ "Timestamp": str(int(datetime.now(timezone.utc).timestamp()))
168
+ }
169
+ data = {
170
+ "ID": key_id,
171
+ "Range": "key",
172
+ "Rules": """[[{\"tee\":\"none\",\"platform\":\"*\",\"policyID\":\"{policy_id}\",\"type\":\"RAPolicy\",\"optional\":false,\"inverse\":false}]]""".replace("{policy_id}", policy_id),
173
+ "IssueToken": False,
174
+ "TokenLifetime": 360000,
175
+ "AppID": "jsc_pcc",
176
+ "Signature": "",
177
+ "Token": ""
178
+ }
179
+ response_body = request(
180
+ "POST", now, {}, header, AK, SK, "SetTksPolicy", json.dumps(data), silent, service
181
+ )
182
+ if not silent:
183
+ print(" set_tks_policy succeed with resp =", response_body)
184
+ return response_body
185
+
186
+
187
+ def publish_inference_model(
188
+ AK: str, SK: str,
189
+ model_name: str, model_version: str, model_description: str, model_baseline: str,
190
+ tos_url: str,
191
+ ring_id: str, key_id: str,
192
+ encrypt_flag: bool, silent: bool = False,
193
+ service: str = "pcc"):
194
+ now = datetime.utcnow()
195
+ data = {
196
+ "ModelName": model_name,
197
+ "ModelVersion": model_version,
198
+ "ModelDescription": model_description,
199
+ "ModelBaseline": model_baseline,
200
+ "TosUrl": tos_url,
201
+ "RingID": ring_id,
202
+ "KeyID": key_id,
203
+ "EncryptFlag": encrypt_flag,
204
+ }
205
+ response_body = request(
206
+ "POST", now, {}, {}, AK, SK, "PublishInferenceModel", json.dumps(data), silent, service
207
+ )
208
+ if not silent:
209
+ print(" publish_inference_model succeed with resp =", response_body)
210
+ return response_body
211
+
212
+
213
+ def deploy_inference_model(AK: str, SK: str, model_id: str, cu_type: str, replica_count: int, inference_engine: str, engine_conf: dict, silent: bool = False, service: str = "pcc"):
214
+ assert cu_type in ["Basic", "Advanced", "Enterprise"], "cu_type must be one of Basic, Advanced, Enterprise"
215
+ assert inference_engine in ["vllm", "sglang"], "inference_engine must be one of vllm, sglang"
216
+ assert isinstance(replica_count, int) and replica_count > 0, "replica_count must be a positive integer"
217
+
218
+ if cu_type == "Basic":
219
+ assert inference_engine == "vllm", "Basic cu_type only supports vllm inference_engine"
220
+ elif cu_type == "Enterprise":
221
+ assert inference_engine == "sglang", "Enterprise cu_type only supports sglang inference_engine"
222
+
223
+ now = datetime.utcnow()
224
+ data = {
225
+ "ModelID": model_id,
226
+ "CuType": cu_type,
227
+ "ReplicaCount": replica_count,
228
+ "InferenceEngine": inference_engine,
229
+ "EngineConf": engine_conf,
230
+ "EnableEic": False,
231
+ "EnableHpa": False,
232
+ "EnableAntiDirt": False
233
+ }
234
+ response_body = request(
235
+ "POST", now, {}, {}, AK, SK, "DeployInferenceModel", json.dumps(data), silent, service
236
+ )
237
+ if not silent:
238
+ print(" deploy_inference_model succeed with resp =", response_body)
239
+ return response_body
240
+
241
+
242
+ def get_engine_conf(AK: str, SK: str, cu_type, inference_engine, model_id: str, silent: bool = False, service: str = "pcc"):
243
+ now = datetime.utcnow()
244
+ data = {
245
+ "CuType": cu_type,
246
+ "InferenceEngine": inference_engine,
247
+ "ModelId": model_id
248
+ }
249
+ response_body = request(
250
+ "POST", now, {}, {}, AK, SK, "GetModelEngineConf", json.dumps(data), silent, service
251
+ )
252
+ # print(response_body)
253
+ return response_body
254
+
255
+
256
+ def list_inference_model(AK: str, SK: str, silent: bool = False, service: str = "pcc"):
257
+ now = datetime.utcnow()
258
+ data = {
259
+ "PageNumber": 1,
260
+ "PageSize": 1000
261
+ }
262
+ response_body = request(
263
+ "POST", now, {}, {}, AK, SK, "ListInferenceModel", json.dumps(data), silent, service
264
+ )
265
+ # print(response_body)
266
+ return response_body
267
+
268
+
269
+ def test_inference_model(AK: str, SK: str, model_id: str, silent: bool = False, service: str = "pcc"):
270
+ now = datetime.utcnow()
271
+ data = {
272
+ "ModelID": model_id
273
+ }
274
+ response_body = request(
275
+ "POST", now, {}, {}, AK, SK, "TestInferenceModel", json.dumps(data), silent, service
276
+ )
277
+ if not silent:
278
+ print(" test_inference_model succeed with resp =", response_body)
279
+ return response_body
@@ -0,0 +1,63 @@
1
+ from bytedance.jsutils.db.base_dbo import DBO
2
+ from bytedance.jsutils.db.db_manager import DBManager
3
+ from sqlalchemy.ext.declarative import declarative_base
4
+ from sqlalchemy.orm import Mapped, mapped_column
5
+ from datetime import datetime
6
+ from typing import Any, Dict, List
7
+
8
+
9
+ Base = declarative_base()
10
+
11
+
12
+ class ToDictMixin:
13
+ _default_select_columns: List[str]
14
+
15
+ def to_dict(self) -> Dict[str, Any]:
16
+ d = {}
17
+ for col in self._default_select_columns:
18
+ obj = getattr(self, col)
19
+ if isinstance(obj, datetime):
20
+ obj = obj.isoformat()
21
+ d[col] = obj
22
+ return d
23
+
24
+
25
+ class PCCHostedModel(Base, ToDictMixin):
26
+ __tablename__ = 'pcc_hosted_models'
27
+ _default_select_columns = ["id", "model_name", "tos_url", "baseline", "created_at"]
28
+
29
+ id: Mapped[int] = mapped_column(
30
+ primary_key=True, autoincrement=True, comment="ID")
31
+ model_name: Mapped[str] = mapped_column(comment="模型名称", default="")
32
+ tos_url: Mapped[str] = mapped_column(comment="模型存放的TOS地址", default="")
33
+ baseline: Mapped[str] = mapped_column(comment="模型加密的密钥环ID", default="")
34
+ created_at: Mapped[str] = mapped_column(comment="模型发布时间 YYYY-MM-DD HHmmSS", default="")
35
+
36
+
37
+ class PCCHostedModelDBO(DBO[PCCHostedModel]):
38
+ _table = PCCHostedModel
39
+
40
+
41
+ def register_to_rds(rds_write_url: str = "", model_meta_data: Dict = {}):
42
+ if rds_write_url == "":
43
+ print("rds_write_url is missing, please pass rds_write_url to register_to_rds() function")
44
+ raise Exception("rds_write_url is missing, please pass rds_write_url to register_to_rds() function")
45
+ DBManager.init("mysql", {"PCCHostedModelTable": PCCHostedModelDBO}, rds_write_url)
46
+
47
+ db_manager = DBManager.get_instance()
48
+
49
+ model_name = model_meta_data.get("model_name", "")
50
+ tos_url = model_meta_data.get("tos_url", "")
51
+ baseline = model_meta_data.get("baseline", "")
52
+ assert model_name != "", "model_name is missing"
53
+ assert tos_url != "", "tos_url is missing"
54
+ assert baseline != "", "baseline is missing"
55
+
56
+ db_manager.PCCHostedModelTable.insert(
57
+ model_name=model_name,
58
+ tos_url=tos_url,
59
+ baseline=baseline,
60
+ created_at=str(datetime.now())
61
+ )
62
+ print(f"inserting model_name={model_name}, tos_url={tos_url}, baseline={baseline} succeeded.")
63
+ print("pcc_hosted_models: ", db_manager.PCCHostedModelTable.select(where={}))
@@ -0,0 +1,41 @@
1
+ __all__ = [
2
+ "Attester",
3
+ "EPSAttester",
4
+ ]
5
+
6
+ import os
7
+ from abc import ABC, abstractmethod
8
+
9
+ import requests
10
+
11
+ from . import exceptions as exp
12
+
13
+
14
+ class Attester(ABC):
15
+ @abstractmethod
16
+ def get_evidence(self, report_data: str) -> bytes:
17
+ raise NotImplementedError
18
+
19
+
20
+ class EPSAttester(Attester):
21
+ def __init__(self) -> None:
22
+ pass
23
+
24
+ def get_evidence(self, report_data: str, pod_name: str = "", attest_gpu: bool = True) -> bytes:
25
+ host_ip = os.environ.get("JPCC_HOST_IP", "localhost")
26
+ eps_addr = f"{host_ip}:8006"
27
+ if not pod_name:
28
+ pod_name = os.environ.get("JPCC_POD_NAME")
29
+ if not pod_name:
30
+ pod_name = os.environ.get("HOSTNAME", "")
31
+
32
+ url = "http://{}/aa/evidence?runtime_data={}&pod_name={}&attest_gpu={}&static_report=true".format(
33
+ eps_addr, report_data, pod_name, str(attest_gpu).lower())
34
+
35
+ try:
36
+ resp = requests.get(url=url)
37
+ resp.raise_for_status()
38
+ except requests.RequestException as e:
39
+ raise exp.RAError("Bad connection to EPS '{}': {}".format(url, e)) from e
40
+
41
+ return resp.content