tcaicc 1.4.0__tar.gz
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.
- tcaicc-1.4.0/.gitignore +30 -0
- tcaicc-1.4.0/PKG-INFO +27 -0
- tcaicc-1.4.0/README.md +5 -0
- tcaicc-1.4.0/THIRD_PARTY_NOTICES +26 -0
- tcaicc-1.4.0/doc/demo.py +50 -0
- tcaicc-1.4.0/doc/demo_endpoint.py +53 -0
- tcaicc-1.4.0/doc/demo_endpoint_stream.py +67 -0
- tcaicc-1.4.0/doc/demo_stream.py +64 -0
- tcaicc-1.4.0/pyproject.toml +98 -0
- tcaicc-1.4.0/src/tcaicc/__init__.py +121 -0
- tcaicc-1.4.0/src/tcaicc/common/__init__.py +1 -0
- tcaicc-1.4.0/src/tcaicc/common/cipherx/__init__.py +151 -0
- tcaicc-1.4.0/src/tcaicc/common/cipherx/_aead.py +43 -0
- tcaicc-1.4.0/src/tcaicc/common/cipherx/_binding.py +208 -0
- tcaicc-1.4.0/src/tcaicc/common/cipherx/_constants.py +17 -0
- tcaicc-1.4.0/src/tcaicc/common/cipherx/_decrypt.py +109 -0
- tcaicc-1.4.0/src/tcaicc/common/cipherx/_encrypt.py +127 -0
- tcaicc-1.4.0/src/tcaicc/common/cipherx/_envelope.py +264 -0
- tcaicc-1.4.0/src/tcaicc/common/cipherx/_errors.py +67 -0
- tcaicc-1.4.0/src/tcaicc/common/cipherx/_hash.py +14 -0
- tcaicc-1.4.0/src/tcaicc/common/cipherx/_kat.py +82 -0
- tcaicc-1.4.0/src/tcaicc/common/cipherx/_metadata.py +141 -0
- tcaicc-1.4.0/src/tcaicc/common/cipherx/_padding.py +68 -0
- tcaicc-1.4.0/src/tcaicc/common/cipherx/_prefix.py +11 -0
- tcaicc-1.4.0/src/tcaicc/common/cipherx/_requestid.py +26 -0
- tcaicc-1.4.0/src/tcaicc/common/cipherx/_stream.py +189 -0
- tcaicc-1.4.0/src/tcaicc/common/cryptox/__init__.py +54 -0
- tcaicc-1.4.0/src/tcaicc/common/cryptox/_aead.py +43 -0
- tcaicc-1.4.0/src/tcaicc/common/cryptox/_dek.py +36 -0
- tcaicc-1.4.0/src/tcaicc/common/cryptox/_errors.py +22 -0
- tcaicc-1.4.0/src/tcaicc/common/cryptox/_kdf.py +36 -0
- tcaicc-1.4.0/src/tcaicc/common/cryptox/_kex.py +73 -0
- tcaicc-1.4.0/src/tcaicc/common/cryptox/_lp.py +17 -0
- tcaicc-1.4.0/src/tcaicc/common/cryptox/_mac.py +13 -0
- tcaicc-1.4.0/src/tcaicc/common/cryptox/_nonce.py +7 -0
- tcaicc-1.4.0/src/tcaicc/common/cryptox/_subtle.py +10 -0
- tcaicc-1.4.0/src/tcaicc/common/security/__init__.py +185 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_body.py +242 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_client.py +1122 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_config.py +26 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_crypto_errors.py +58 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_derive.py +59 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_detect.py +33 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_endpoint_pool.py +149 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_endpoints.py +29 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_errors.py +53 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_field_path_aliases.py +86 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_flags.py +12 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_http.py +310 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_keysched.py +95 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_log.py +166 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_model_pool.py +355 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_policy.py +179 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_pool.py +319 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_proto.py +74 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_request.py +221 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_sev.py +254 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_stream.py +93 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_tls.py +213 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_transcript.py +116 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_transport.py +80 -0
- tcaicc-1.4.0/src/tcaicc/common/security/_trust_anchors.py +127 -0
- tcaicc-1.4.0/src/tcaicc/common/security/trust_anchors/bergamo_ark.pem +37 -0
- tcaicc-1.4.0/src/tcaicc/common/security/trust_anchors/bergamo_ask.pem +37 -0
- tcaicc-1.4.0/src/tcaicc/common/security/trust_anchors/genoa_ark.pem +37 -0
- tcaicc-1.4.0/src/tcaicc/common/security/trust_anchors/genoa_ask.pem +37 -0
- tcaicc-1.4.0/src/tcaicc/common/security/trust_anchors/milan_ark.pem +37 -0
- tcaicc-1.4.0/src/tcaicc/common/security/trust_anchors/milan_ask.pem +37 -0
- tcaicc-1.4.0/src/tcaicc/common/security/trust_anchors/siena_ark.pem +37 -0
- tcaicc-1.4.0/src/tcaicc/common/security/trust_anchors/siena_ask.pem +37 -0
- tcaicc-1.4.0/src/tcaicc/common/security/trust_anchors/turin_ark.pem +37 -0
- tcaicc-1.4.0/src/tcaicc/common/security/trust_anchors/turin_ask.pem +37 -0
tcaicc-1.4.0/.gitignore
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Byte-compiled / optimized
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Packaging
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
.eggs/
|
|
11
|
+
|
|
12
|
+
# Virtual environments
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
|
|
16
|
+
# Test / coverage caches
|
|
17
|
+
.pytest_cache/
|
|
18
|
+
.coverage
|
|
19
|
+
.coverage.*
|
|
20
|
+
htmlcov/
|
|
21
|
+
|
|
22
|
+
# Editors / OS
|
|
23
|
+
.idea/
|
|
24
|
+
.vscode/
|
|
25
|
+
.DS_Store
|
|
26
|
+
|
|
27
|
+
# 明文默认 mTLS 证书源材料(由 hardcode.sh 加密进 _default_certs.py;密文可提交,明文不提交)
|
|
28
|
+
cert/
|
|
29
|
+
|
|
30
|
+
# doc/ 下 demo*.py 是权威文档示例,随仓库提交;doc.html 不在本仓库,维护于 ../aicc-sdk-doc/。
|
tcaicc-1.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: tcaicc
|
|
3
|
+
Version: 1.4.0
|
|
4
|
+
Summary: Tencent AICC confidential-model SDK for Python
|
|
5
|
+
Author: Tencent
|
|
6
|
+
License-Expression: LicenseRef-Proprietary
|
|
7
|
+
License-File: THIRD_PARTY_NOTICES
|
|
8
|
+
Keywords: aicc,confidential-computing,encryption,ml-kem,remote-attestation,sev-snp,tencent
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Security :: Cryptography
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: cryptography>=48
|
|
20
|
+
Requires-Dist: httpx>=0.27
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# TCAICC
|
|
24
|
+
|
|
25
|
+
版本:1.4.0
|
|
26
|
+
|
|
27
|
+
许可:专有软件,仅限腾讯云 AICC 服务客户使用;第三方组件见 [THIRD_PARTY_NOTICES](THIRD_PARTY_NOTICES)。
|
tcaicc-1.4.0/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
TCAICC SDK 第三方组件声明 / Third-Party Notices
|
|
2
|
+
|
|
3
|
+
本软件未内置第三方源代码。下列开源组件为运行时依赖,由用户在安装时从 PyPI
|
|
4
|
+
另行获取,适用其各自的许可证,不受本软件 LICENSE 约束。版本为本版本构建时锁定的版本,
|
|
5
|
+
实际安装版本以 pip 解析结果为准。
|
|
6
|
+
|
|
7
|
+
| 组件 | 版本 | 许可证 | 项目地址 |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| cryptography | 49.0.0 | Apache-2.0 OR BSD-3-Clause | https://github.com/pyca/cryptography |
|
|
10
|
+
| cffi | 2.1.0 | MIT-0 | https://github.com/python-cffi/cffi |
|
|
11
|
+
| pycparser | 3.0 | BSD-3-Clause | https://github.com/eliben/pycparser |
|
|
12
|
+
| httpx | 0.28.1 | BSD-3-Clause | https://github.com/encode/httpx |
|
|
13
|
+
| httpcore | 1.0.9 | BSD-3-Clause | https://github.com/encode/httpcore |
|
|
14
|
+
| h11 | 0.16.0 | MIT | https://github.com/python-hyper/h11 |
|
|
15
|
+
| anyio | 4.14.2 | MIT | https://github.com/agronholm/anyio |
|
|
16
|
+
| idna | 3.18 | BSD-3-Clause | https://github.com/kjd/idna |
|
|
17
|
+
| certifi | 2026.7.22 | MPL-2.0 | https://github.com/certifi/python-certifi |
|
|
18
|
+
| exceptiongroup | 1.3.1 | MIT | https://github.com/agronholm/exceptiongroup |
|
|
19
|
+
| typing-extensions | 4.16.0 | PSF-2.0 | https://github.com/python/typing_extensions |
|
|
20
|
+
|
|
21
|
+
说明:
|
|
22
|
+
- cryptography、httpx 为直接依赖,其余为传递依赖;exceptiongroup 仅 Python < 3.11、
|
|
23
|
+
typing-extensions 仅 Python < 3.13、cffi/pycparser 仅 CPython 时安装。
|
|
24
|
+
- 本软件随包分发的 AMD SEV-SNP 根证书(ARK/ASK,位于 tcaicc/common/security/trust_anchors/)
|
|
25
|
+
为 AMD 公开发布的证书,版权归 Advanced Micro Devices, Inc. 所有。
|
|
26
|
+
- 各组件许可证全文见其项目地址或安装后的 *.dist-info/ 目录。
|
tcaicc-1.4.0/doc/demo.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# demo.py —— 非流式示例(ModelPool 按 model 发现端点):安全会话握手 → 加密请求 → 解密回文,只打印明文。
|
|
2
|
+
#
|
|
3
|
+
# 环境变量(均必填,无内置默认):AICC_BASE_URL(安全会话入口)、AICC_GATEWAY_URL(LLM 网关)、AICC_API_KEY、AICC_MODEL_NAME
|
|
4
|
+
#
|
|
5
|
+
# python doc/demo.py
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
import httpx
|
|
10
|
+
|
|
11
|
+
from tcaicc import ModelPool, Protocol, SessionFactory, SessionPool, default_policy
|
|
12
|
+
|
|
13
|
+
base_url = os.getenv("AICC_BASE_URL")
|
|
14
|
+
gateway_url = os.getenv("AICC_GATEWAY_URL")
|
|
15
|
+
api_key = os.getenv("AICC_API_KEY")
|
|
16
|
+
model_name = os.getenv("AICC_MODEL_NAME")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def run():
|
|
20
|
+
# ① 模型池:按 model 发现集群端点并握手,托管会话。
|
|
21
|
+
# tls_verify=True(默认):校验 https 证书;网关用自签证书时改 False(直接不校验,构造时告警一次)。
|
|
22
|
+
config = {"tls_verify": True}
|
|
23
|
+
|
|
24
|
+
def build(endpoint):
|
|
25
|
+
return SessionPool(SessionFactory(base_url, api_key, ttl=60 * 60 * 8).set_config(config), 1)
|
|
26
|
+
|
|
27
|
+
with ModelPool(base_url, api_key, 60 * 60 * 8, build).set_config(config) as models:
|
|
28
|
+
# ② 每轮 HTTP 请求新建一个 Request(携带本次会话的集群端点)。
|
|
29
|
+
with models.new_request(model_name) as req:
|
|
30
|
+
# ③ 加密请求体后发给网关。
|
|
31
|
+
policy = default_policy(Protocol.OPENAI)
|
|
32
|
+
body = {"model": model_name, "messages": [{"role": "user", "content": "你好"}]}
|
|
33
|
+
enc_body = req.encrypt_request(json.dumps(body).encode(), policy)
|
|
34
|
+
headers = {
|
|
35
|
+
"Content-Type": "application/json",
|
|
36
|
+
"X-AICC-Mode": "1",
|
|
37
|
+
"Authorization": f"Bearer {api_key}",
|
|
38
|
+
"X-AICC-Endpoint": req.endpoint, # 带上握手时的集群端点,网关据此路由
|
|
39
|
+
}
|
|
40
|
+
r = httpx.post(gateway_url, content=enc_body, headers=headers, timeout=600)
|
|
41
|
+
if r.status_code != 200:
|
|
42
|
+
raise RuntimeError(f"gateway {r.status_code}: {r.text}")
|
|
43
|
+
|
|
44
|
+
# ④ 解密回文,打印明文回答。
|
|
45
|
+
plain = req.decrypt_response(r.content, policy)
|
|
46
|
+
print(json.loads(plain)["choices"][0]["message"]["content"])
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if __name__ == "__main__":
|
|
50
|
+
run()
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# demo_endpoint.py —— 非流式示例(固定端点):安全会话握手 → 加密请求 → 解密回文,只打印明文。
|
|
2
|
+
#
|
|
3
|
+
# 环境变量(均必填,无内置默认):AICC_BASE_URL(安全会话入口)、AICC_GATEWAY_URL(LLM 网关)、AICC_API_KEY、AICC_MODEL_NAME、
|
|
4
|
+
# AICC_ENDPOINT(集群端点;不经 DescribeEndpoints 发现,直接用于握手与数据面路由)
|
|
5
|
+
#
|
|
6
|
+
# python doc/demo_endpoint.py
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
import httpx
|
|
11
|
+
|
|
12
|
+
from tcaicc import Protocol, SessionFactory, SessionPool, default_policy
|
|
13
|
+
|
|
14
|
+
base_url = os.getenv("AICC_BASE_URL")
|
|
15
|
+
gateway_url = os.getenv("AICC_GATEWAY_URL")
|
|
16
|
+
api_key = os.getenv("AICC_API_KEY")
|
|
17
|
+
model_name = os.getenv("AICC_MODEL_NAME")
|
|
18
|
+
endpoint = os.getenv("AICC_ENDPOINT")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def run():
|
|
22
|
+
# ① 会话池:工厂固定集群端点,握手时带 X-AICC-Endpoint 头,托管会话。
|
|
23
|
+
# tls_verify=True(默认):校验 https 证书;网关用自签证书时改 False(直接不校验,构造时告警一次)。
|
|
24
|
+
factory = (
|
|
25
|
+
SessionFactory(base_url, api_key, ttl=60 * 60 * 8)
|
|
26
|
+
.set_config({"tls_verify": True})
|
|
27
|
+
.set_endpoint(endpoint)
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
with SessionPool(factory, 1) as sessions:
|
|
31
|
+
# ② 每轮 HTTP 请求新建一个 Request(携带本次会话的集群端点)。
|
|
32
|
+
with sessions.new_request() as req:
|
|
33
|
+
# ③ 加密请求体后发给网关。
|
|
34
|
+
policy = default_policy(Protocol.OPENAI)
|
|
35
|
+
body = {"model": model_name, "messages": [{"role": "user", "content": "你好"}]}
|
|
36
|
+
enc_body = req.encrypt_request(json.dumps(body).encode(), policy)
|
|
37
|
+
headers = {
|
|
38
|
+
"Content-Type": "application/json",
|
|
39
|
+
"X-AICC-Mode": "1",
|
|
40
|
+
"Authorization": f"Bearer {api_key}",
|
|
41
|
+
"X-AICC-Endpoint": req.endpoint, # 带上握手时的集群端点,网关据此路由
|
|
42
|
+
}
|
|
43
|
+
r = httpx.post(gateway_url, content=enc_body, headers=headers, timeout=600)
|
|
44
|
+
if r.status_code != 200:
|
|
45
|
+
raise RuntimeError(f"gateway {r.status_code}: {r.text}")
|
|
46
|
+
|
|
47
|
+
# ④ 解密回文,打印明文回答。
|
|
48
|
+
plain = req.decrypt_response(r.content, policy)
|
|
49
|
+
print(json.loads(plain)["choices"][0]["message"]["content"])
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__":
|
|
53
|
+
run()
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# demo_endpoint_stream.py —— 流式示例(固定端点):安全会话握手 → 加密请求 → 逐 SSE 事件解密,只打印明文。
|
|
2
|
+
#
|
|
3
|
+
# 环境变量(均必填,无内置默认):AICC_BASE_URL(安全会话入口)、AICC_GATEWAY_URL(LLM 网关)、AICC_API_KEY、AICC_MODEL_NAME、
|
|
4
|
+
# AICC_ENDPOINT(集群端点;不经 DescribeEndpoints 发现,直接用于握手与数据面路由)
|
|
5
|
+
#
|
|
6
|
+
# python doc/demo_endpoint_stream.py
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
import httpx
|
|
11
|
+
|
|
12
|
+
from tcaicc import Protocol, SessionFactory, SessionPool, default_policy
|
|
13
|
+
|
|
14
|
+
base_url = os.getenv("AICC_BASE_URL")
|
|
15
|
+
gateway_url = os.getenv("AICC_GATEWAY_URL")
|
|
16
|
+
api_key = os.getenv("AICC_API_KEY")
|
|
17
|
+
model_name = os.getenv("AICC_MODEL_NAME")
|
|
18
|
+
endpoint = os.getenv("AICC_ENDPOINT")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def run():
|
|
22
|
+
# ① 会话池:工厂固定集群端点,握手时带 X-AICC-Endpoint 头,托管会话。
|
|
23
|
+
# tls_verify=True(默认):校验 https 证书;网关用自签证书时改 False(直接不校验,构造时告警一次)。
|
|
24
|
+
factory = (
|
|
25
|
+
SessionFactory(base_url, api_key, ttl=60 * 60 * 8)
|
|
26
|
+
.set_config({"tls_verify": True})
|
|
27
|
+
.set_endpoint(endpoint)
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
with SessionPool(factory, 1) as sessions:
|
|
31
|
+
# ② 每轮 HTTP 请求新建一个 Request(携带本次会话的集群端点)。
|
|
32
|
+
with sessions.new_request() as req:
|
|
33
|
+
# ③ 加密请求体(stream=true)后发给网关。
|
|
34
|
+
policy = default_policy(Protocol.OPENAI)
|
|
35
|
+
body = {"model": model_name, "messages": [{"role": "user", "content": "你好"}], "stream": True}
|
|
36
|
+
enc_body = req.encrypt_request(json.dumps(body).encode(), policy)
|
|
37
|
+
headers = {
|
|
38
|
+
"Content-Type": "application/json",
|
|
39
|
+
"Accept": "text/event-stream",
|
|
40
|
+
"X-AICC-Mode": "1",
|
|
41
|
+
"Authorization": f"Bearer {api_key}",
|
|
42
|
+
"X-AICC-Endpoint": req.endpoint, # 带上握手时的集群端点,网关据此路由
|
|
43
|
+
}
|
|
44
|
+
timeout = httpx.Timeout(600, read=None)
|
|
45
|
+
with httpx.stream("POST", gateway_url, content=enc_body, headers=headers, timeout=timeout) as r:
|
|
46
|
+
if r.status_code != 200:
|
|
47
|
+
raise RuntimeError(f"gateway {r.status_code}: {r.read().decode()}")
|
|
48
|
+
|
|
49
|
+
# ④ 逐个 SSE 事件解密,打印增量明文。
|
|
50
|
+
sd = req.new_stream_decryptor()
|
|
51
|
+
for line in r.iter_lines():
|
|
52
|
+
if not line.startswith("data: "):
|
|
53
|
+
continue
|
|
54
|
+
data = line[len("data: "):]
|
|
55
|
+
if data == "[DONE]":
|
|
56
|
+
break
|
|
57
|
+
plain, is_last = sd.decrypt_event(data.encode(), policy)
|
|
58
|
+
choices = json.loads(plain).get("choices") if plain else None
|
|
59
|
+
if choices:
|
|
60
|
+
print(choices[0].get("delta", {}).get("content") or "", end="", flush=True)
|
|
61
|
+
if is_last:
|
|
62
|
+
break
|
|
63
|
+
print()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
if __name__ == "__main__":
|
|
67
|
+
run()
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# demo_stream.py —— 流式示例(ModelPool 按 model 发现端点):安全会话握手 → 加密请求 → 逐 SSE 事件解密,只打印明文。
|
|
2
|
+
#
|
|
3
|
+
# 环境变量(均必填,无内置默认):AICC_BASE_URL(安全会话入口)、AICC_GATEWAY_URL(LLM 网关)、AICC_API_KEY、AICC_MODEL_NAME
|
|
4
|
+
#
|
|
5
|
+
# python doc/demo_stream.py
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
import httpx
|
|
10
|
+
|
|
11
|
+
from tcaicc import ModelPool, Protocol, SessionFactory, SessionPool, default_policy
|
|
12
|
+
|
|
13
|
+
base_url = os.getenv("AICC_BASE_URL")
|
|
14
|
+
gateway_url = os.getenv("AICC_GATEWAY_URL")
|
|
15
|
+
api_key = os.getenv("AICC_API_KEY")
|
|
16
|
+
model_name = os.getenv("AICC_MODEL_NAME")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def run():
|
|
20
|
+
# ① 模型池:按 model 发现集群端点并握手,托管会话。
|
|
21
|
+
# tls_verify=True(默认):校验 https 证书;网关用自签证书时改 False(直接不校验,构造时告警一次)。
|
|
22
|
+
config = {"tls_verify": True}
|
|
23
|
+
|
|
24
|
+
def build(endpoint):
|
|
25
|
+
return SessionPool(SessionFactory(base_url, api_key, ttl=60 * 60 * 8).set_config(config), 1)
|
|
26
|
+
|
|
27
|
+
with ModelPool(base_url, api_key, 60 * 60 * 8, build).set_config(config) as models:
|
|
28
|
+
# ② 每轮 HTTP 请求新建一个 Request(携带本次会话的集群端点)。
|
|
29
|
+
with models.new_request(model_name) as req:
|
|
30
|
+
# ③ 加密请求体(stream=true)后发给网关。
|
|
31
|
+
policy = default_policy(Protocol.OPENAI)
|
|
32
|
+
body = {"model": model_name, "messages": [{"role": "user", "content": "你好"}], "stream": True}
|
|
33
|
+
enc_body = req.encrypt_request(json.dumps(body).encode(), policy)
|
|
34
|
+
headers = {
|
|
35
|
+
"Content-Type": "application/json",
|
|
36
|
+
"Accept": "text/event-stream",
|
|
37
|
+
"X-AICC-Mode": "1",
|
|
38
|
+
"Authorization": f"Bearer {api_key}",
|
|
39
|
+
"X-AICC-Endpoint": req.endpoint, # 带上握手时的集群端点,网关据此路由
|
|
40
|
+
}
|
|
41
|
+
timeout = httpx.Timeout(600, read=None)
|
|
42
|
+
with httpx.stream("POST", gateway_url, content=enc_body, headers=headers, timeout=timeout) as r:
|
|
43
|
+
if r.status_code != 200:
|
|
44
|
+
raise RuntimeError(f"gateway {r.status_code}: {r.read().decode()}")
|
|
45
|
+
|
|
46
|
+
# ④ 逐个 SSE 事件解密,打印增量明文。
|
|
47
|
+
sd = req.new_stream_decryptor()
|
|
48
|
+
for line in r.iter_lines():
|
|
49
|
+
if not line.startswith("data: "):
|
|
50
|
+
continue
|
|
51
|
+
data = line[len("data: "):]
|
|
52
|
+
if data == "[DONE]":
|
|
53
|
+
break
|
|
54
|
+
plain, is_last = sd.decrypt_event(data.encode(), policy)
|
|
55
|
+
choices = json.loads(plain).get("choices") if plain else None
|
|
56
|
+
if choices:
|
|
57
|
+
print(choices[0].get("delta", {}).get("content") or "", end="", flush=True)
|
|
58
|
+
if is_last:
|
|
59
|
+
break
|
|
60
|
+
print()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
if __name__ == "__main__":
|
|
64
|
+
run()
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "tcaicc"
|
|
7
|
+
version = "1.4.0"
|
|
8
|
+
description = "Tencent AICC confidential-model SDK for Python"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "LicenseRef-Proprietary"
|
|
11
|
+
license-files = ["THIRD_PARTY_NOTICES"]
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
authors = [{ name = "Tencent" }]
|
|
14
|
+
keywords = [
|
|
15
|
+
"aicc",
|
|
16
|
+
"confidential-computing",
|
|
17
|
+
"remote-attestation",
|
|
18
|
+
"sev-snp",
|
|
19
|
+
"ml-kem",
|
|
20
|
+
"encryption",
|
|
21
|
+
"tencent",
|
|
22
|
+
]
|
|
23
|
+
classifiers = [
|
|
24
|
+
"Development Status :: 5 - Production/Stable",
|
|
25
|
+
"Intended Audience :: Developers",
|
|
26
|
+
"Programming Language :: Python :: 3",
|
|
27
|
+
"Programming Language :: Python :: 3.10",
|
|
28
|
+
"Programming Language :: Python :: 3.11",
|
|
29
|
+
"Programming Language :: Python :: 3.12",
|
|
30
|
+
"Programming Language :: Python :: 3.13",
|
|
31
|
+
"Operating System :: OS Independent",
|
|
32
|
+
"Topic :: Security :: Cryptography",
|
|
33
|
+
]
|
|
34
|
+
dependencies = [
|
|
35
|
+
"cryptography>=48",
|
|
36
|
+
"httpx>=0.27",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[dependency-groups]
|
|
40
|
+
dev = ["pytest>=8", "ruff>=0.16"]
|
|
41
|
+
|
|
42
|
+
[tool.hatch.build.targets.wheel]
|
|
43
|
+
packages = ["src/tcaicc"]
|
|
44
|
+
|
|
45
|
+
# sdist 用白名单:只收源码、权威 demo 与元数据,工作树里的 tests/release/脚本/html 一律不进。
|
|
46
|
+
# doc/*.html 是网页文档(另行发布),不进发行包。
|
|
47
|
+
[tool.hatch.build.targets.sdist]
|
|
48
|
+
only-include = [
|
|
49
|
+
"/src/tcaicc",
|
|
50
|
+
"/doc/demo.py",
|
|
51
|
+
"/doc/demo_stream.py",
|
|
52
|
+
"/doc/demo_endpoint.py",
|
|
53
|
+
"/doc/demo_endpoint_stream.py",
|
|
54
|
+
"/README.md",
|
|
55
|
+
"/THIRD_PARTY_NOTICES",
|
|
56
|
+
"/pyproject.toml",
|
|
57
|
+
]
|
|
58
|
+
exclude = ["__pycache__", "*.py[cod]"]
|
|
59
|
+
|
|
60
|
+
[tool.ruff]
|
|
61
|
+
line-length = 100
|
|
62
|
+
target-version = "py310"
|
|
63
|
+
src = ["src", "tests", "scripts"]
|
|
64
|
+
extend-exclude = ["doc/examples", ".venv"]
|
|
65
|
+
|
|
66
|
+
[tool.ruff.lint]
|
|
67
|
+
# 选用对 SDK 友好的规则集:
|
|
68
|
+
# E/W pycodestyle(基础风格)
|
|
69
|
+
# F pyflakes(未用导入/变量等真实缺陷)
|
|
70
|
+
# I isort(导入排序)
|
|
71
|
+
# UP pyupgrade(现代语法;future-annotations 下移除多余引号)
|
|
72
|
+
# B bugbear(常见 bug,含 BLE001 盲 except)
|
|
73
|
+
# SIM simplify
|
|
74
|
+
# C4 comprehensions
|
|
75
|
+
# RUF ruff 专有(__all__/__slots__ 排序等)
|
|
76
|
+
# PIE 杂项清理
|
|
77
|
+
# ISC 隐式字符串拼接
|
|
78
|
+
select = ["E", "W", "F", "I", "UP", "B", "SIM", "C4", "RUF", "PIE", "ISC"]
|
|
79
|
+
ignore = [
|
|
80
|
+
"E501", # 不强制行长;超长多为长字符串/URL/对齐注释,手动折行取舍
|
|
81
|
+
"B008", # 函数默认值里调用函数(测试 fixture 常见)
|
|
82
|
+
"SIM117", # 嵌套 try/with 合并有时降低可读性
|
|
83
|
+
# 代码注释/文档大量使用中文全角标点(,。×– 等),RUF001/002/003 会误报为歧义字符。
|
|
84
|
+
"RUF001", "RUF002", "RUF003",
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
[tool.ruff.lint.per-file-ignores]
|
|
88
|
+
# 测试中 broad except 配 pytest.fail 是惯用法。
|
|
89
|
+
"tests/*" = ["BLE001"]
|
|
90
|
+
# 包 __init__.py 的 __all__ 按模块分组(带注释),刻意不按字母序。
|
|
91
|
+
"src/tcaicc/**/__init__.py" = ["RUF022"]
|
|
92
|
+
|
|
93
|
+
[tool.ruff.lint.isort]
|
|
94
|
+
known-first-party = ["tcaicc"]
|
|
95
|
+
combine-as-imports = true
|
|
96
|
+
|
|
97
|
+
# 本项目只启用 ruff lint,不启用 ruff format(保留手工列对齐等刻意风格)。
|
|
98
|
+
# 不要对 src/tests/scripts 运行 `ruff format`,会重排 35+ 文件并破坏对齐注释。
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
__version__ = "1.4.0"
|
|
2
|
+
|
|
3
|
+
from .common.cipherx import (
|
|
4
|
+
ChunkDecryptor,
|
|
5
|
+
ChunkEncryptor,
|
|
6
|
+
CipherType,
|
|
7
|
+
CipherTypeError,
|
|
8
|
+
CipherxError,
|
|
9
|
+
DecryptError,
|
|
10
|
+
Envelope,
|
|
11
|
+
FormatError,
|
|
12
|
+
HashMismatchError,
|
|
13
|
+
KeySizeError,
|
|
14
|
+
Metadata,
|
|
15
|
+
StreamClosedError,
|
|
16
|
+
StreamVerifyError,
|
|
17
|
+
TooLargeError,
|
|
18
|
+
compute_prefix,
|
|
19
|
+
encrypt_prompt,
|
|
20
|
+
encrypt_response,
|
|
21
|
+
parse,
|
|
22
|
+
)
|
|
23
|
+
from .common.cryptox import (
|
|
24
|
+
CryptoxError,
|
|
25
|
+
DecryptError as CryptoxDecryptError,
|
|
26
|
+
HybridEphemeral,
|
|
27
|
+
HybridShare,
|
|
28
|
+
constant_time_equal,
|
|
29
|
+
derive_dek,
|
|
30
|
+
encode_lp,
|
|
31
|
+
hkdf_expand,
|
|
32
|
+
hkdf_extract,
|
|
33
|
+
hmac_sha256,
|
|
34
|
+
open_,
|
|
35
|
+
open_base64,
|
|
36
|
+
random_nonce,
|
|
37
|
+
respond_hybrid_exchange,
|
|
38
|
+
seal,
|
|
39
|
+
seal_base64,
|
|
40
|
+
zero,
|
|
41
|
+
)
|
|
42
|
+
from .common.security import (
|
|
43
|
+
ENDPOINT_NOT_FOUND,
|
|
44
|
+
FLAG_PROMPT_LONG,
|
|
45
|
+
FLAG_PROMPT_SHORT,
|
|
46
|
+
NO_ENDPOINT,
|
|
47
|
+
TLS_INSECURE,
|
|
48
|
+
TLS_NONE,
|
|
49
|
+
TLS_TLS,
|
|
50
|
+
ClosedError,
|
|
51
|
+
CreateResult,
|
|
52
|
+
CryptoError,
|
|
53
|
+
DeriveResult,
|
|
54
|
+
EncodingError,
|
|
55
|
+
EndpointNotFoundError,
|
|
56
|
+
EndpointPool,
|
|
57
|
+
HttpClient,
|
|
58
|
+
HttpTransportResponse,
|
|
59
|
+
ImportResult,
|
|
60
|
+
InsecureTLSWarning,
|
|
61
|
+
KeyGeneratorError,
|
|
62
|
+
KeySizeError as CryptoKeySizeError,
|
|
63
|
+
Logger,
|
|
64
|
+
LogLevel,
|
|
65
|
+
ModelPool,
|
|
66
|
+
NoEndpointError,
|
|
67
|
+
Policy,
|
|
68
|
+
Protocol,
|
|
69
|
+
Request,
|
|
70
|
+
SecuritySession,
|
|
71
|
+
SecuritySessionError,
|
|
72
|
+
SessionFactory,
|
|
73
|
+
SessionIDError,
|
|
74
|
+
SessionPool,
|
|
75
|
+
StreamDecryptor,
|
|
76
|
+
TimeoutException,
|
|
77
|
+
TlsMode,
|
|
78
|
+
Transport,
|
|
79
|
+
TransportError,
|
|
80
|
+
TransportRequest,
|
|
81
|
+
TransportResponse,
|
|
82
|
+
binding_key,
|
|
83
|
+
build_ssl_context,
|
|
84
|
+
default_policy,
|
|
85
|
+
describe_endpoints,
|
|
86
|
+
detect_envelope,
|
|
87
|
+
set_log_level,
|
|
88
|
+
set_logger,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
__all__ = [
|
|
92
|
+
"__version__",
|
|
93
|
+
# cryptox(低层原语)
|
|
94
|
+
"CryptoxError", "CryptoxDecryptError", "HybridEphemeral", "HybridShare",
|
|
95
|
+
"constant_time_equal", "derive_dek", "encode_lp", "hkdf_expand", "hkdf_extract",
|
|
96
|
+
"hmac_sha256", "open_", "open_base64", "random_nonce",
|
|
97
|
+
"respond_hybrid_exchange", "seal", "seal_base64", "zero",
|
|
98
|
+
# cipherx(信封格式)
|
|
99
|
+
"CipherxError", "KeySizeError", "FormatError", "TooLargeError", "DecryptError",
|
|
100
|
+
"HashMismatchError", "CipherTypeError", "StreamClosedError", "StreamVerifyError",
|
|
101
|
+
"encrypt_prompt", "encrypt_response", "parse",
|
|
102
|
+
"ChunkEncryptor", "ChunkDecryptor", "Envelope", "Metadata", "CipherType",
|
|
103
|
+
"compute_prefix",
|
|
104
|
+
# 数据面加解密客户端
|
|
105
|
+
"CryptoError", "CryptoKeySizeError", "SessionIDError", "ClosedError", "EncodingError",
|
|
106
|
+
"Request", "StreamDecryptor", "detect_envelope",
|
|
107
|
+
"Policy", "Protocol", "default_policy",
|
|
108
|
+
# 传输(TLS 形态由 base_url scheme 决定,无 mTLS)
|
|
109
|
+
"HttpClient", "TransportResponse", "TransportRequest", "Transport",
|
|
110
|
+
"HttpTransportResponse", "InsecureTLSWarning", "build_ssl_context", "TlsMode",
|
|
111
|
+
"TLS_TLS", "TLS_INSECURE", "TLS_NONE",
|
|
112
|
+
# 安全会话
|
|
113
|
+
"SessionFactory", "SessionPool", "SecuritySession",
|
|
114
|
+
"EndpointPool", "ModelPool", "describe_endpoints", "binding_key",
|
|
115
|
+
"FLAG_PROMPT_SHORT", "FLAG_PROMPT_LONG",
|
|
116
|
+
"EndpointNotFoundError", "NoEndpointError", "ENDPOINT_NOT_FOUND", "NO_ENDPOINT",
|
|
117
|
+
"CreateResult", "ImportResult", "DeriveResult",
|
|
118
|
+
"SecuritySessionError", "TransportError", "TimeoutException", "KeyGeneratorError",
|
|
119
|
+
# 进程级日志(四级阈值,默认 error 即零输出)
|
|
120
|
+
"set_logger", "set_log_level", "LogLevel", "Logger",
|
|
121
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""common 共享子包。"""
|