uapi-sdk-python 0.1.13__tar.gz → 0.1.14__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uapi-sdk-python
3
- Version: 0.1.13
3
+ Version: 0.1.14
4
4
  Summary: Idiomatic UAPI SDK for Python
5
5
  Author-email: UAPI <dev@uapis.cn>
6
6
  Requires-Python: >=3.9
@@ -32,11 +32,13 @@ pip install uapi-sdk-python
32
32
  ```python
33
33
  from uapi import UapiClient
34
34
 
35
- client = UapiClient("https://uapis.cn/api/v1")
36
- result = client.social.get_social_qq_userinfo(qq="10001")
35
+ client = UapiClient("https://uapis.cn", "YOUR_API_KEY")
36
+ result = client.misc.get_misc_hotboard(type="weibo")
37
37
  print(result)
38
38
  ```
39
39
 
40
+ 这个接口默认只要传 `type` 就可以拿当前热榜。`time`、`keyword`、`time_start`、`time_end`、`limit`、`sources` 都是按场景再传的可选参数。
41
+
40
42
  > [!TIP]
41
43
  > 请使用与运行脚本相同的 Python 解释器安装依赖,例如执行 `python -m pip install uapi-sdk-python` 后再运行 `python main.py`。在 VS Code / Pyright 中若提示 “Import uapi could not be resolved”,将解释器切换到当前虚拟环境即可恢复补全。
42
44
 
@@ -54,6 +56,60 @@ print(result)
54
56
 
55
57
  如果你需要查看字段细节或内部逻辑,仓库中的 `./internal` 目录同步保留了由 `openapi-generator` 生成的完整结构体,随时可供参考。
56
58
 
59
+ ## 响应元信息
60
+
61
+ 每次请求完成后,SDK 会自动把响应 Header 解析成结构化的 `ResponseMeta`,你不用自己拆原始字符串。
62
+
63
+ 成功时可以通过 `client.last_response_meta` 读取,失败时可以通过 `err.meta` 读取,两条路径拿到的是同一套字段。
64
+
65
+ ```python
66
+ from uapi import UapiClient, UapiError
67
+
68
+ client = UapiClient("https://uapis.cn", "YOUR_API_KEY")
69
+
70
+ # 成功路径
71
+ client.social.get_social_qq_userinfo(qq="10001")
72
+ meta = client.last_response_meta
73
+ if meta:
74
+ print("这次请求原价:", meta.credits_requested or 0, "积分")
75
+ print("这次实际扣费:", meta.credits_charged or 0, "积分")
76
+ print("特殊计价:", meta.credits_pricing or "原价")
77
+ print("余额剩余:", meta.balance_remaining_cents or 0, "分")
78
+ print("资源包剩余:", meta.quota_remaining_credits or 0, "积分")
79
+ print("当前有效额度桶:", meta.active_quota_buckets or 0)
80
+ print("额度用空即停:", meta.stop_on_empty)
81
+ print("Key QPS:", meta.billing_key_rate_remaining or 0, "/", meta.billing_key_rate_limit or 0, meta.billing_key_rate_unit or "req")
82
+ print("Request ID:", meta.request_id)
83
+
84
+ # 失败路径
85
+ try:
86
+ client.social.get_social_qq_userinfo(qq="10001")
87
+ except UapiError as err:
88
+ if err.meta:
89
+ print("Retry-After 秒数:", err.meta.retry_after_seconds)
90
+ print("Retry-After 原始值:", err.meta.retry_after_raw)
91
+ print("访客 QPS:", err.meta.visitor_rate_remaining or 0, "/", err.meta.visitor_rate_limit or 0)
92
+ print("Request ID:", err.meta.request_id)
93
+ ```
94
+
95
+ 常用字段一览:
96
+
97
+ | 字段 | 说明 |
98
+ |------|------|
99
+ | `credits_requested` | 这次请求原本要扣多少积分,也就是请求价 |
100
+ | `credits_charged` | 这次请求实际扣了多少积分 |
101
+ | `credits_pricing` | 特殊计价原因,例如缓存半价 `cache-hit-half-price` |
102
+ | `balance_remaining_cents` | 账户余额剩余(分) |
103
+ | `quota_remaining_credits` | 资源包剩余积分 |
104
+ | `active_quota_buckets` | 当前还有多少个有效额度桶参与计费 |
105
+ | `stop_on_empty` | 额度耗尽后是否直接停止服务 |
106
+ | `retry_after_seconds` / `retry_after_raw` | 限流后的等待时长;当服务端返回 HTTP 时间字符串时看 `retry_after_raw` |
107
+ | `request_id` | 请求唯一 ID,排障时使用 |
108
+ | `billing_key_rate_limit` / `billing_key_rate_remaining` | Billing Key 当前 QPS 规则的上限与剩余 |
109
+ | `billing_ip_rate_limit` / `billing_ip_rate_remaining` | Billing Key 单 IP 当前 QPS 规则的上限与剩余 |
110
+ | `visitor_rate_limit` / `visitor_rate_remaining` | 访客当前 QPS 规则的上限与剩余 |
111
+ | `rate_limit_policies` / `rate_limits` | 完整结构化限流策略数据 |
112
+
57
113
  ## 进阶实践
58
114
 
59
115
  ### 缓存与幂等
@@ -62,7 +118,7 @@ print(result)
62
118
  from functools import lru_cache
63
119
  from uapi import UapiClient
64
120
 
65
- client = UapiClient("https://uapis.cn/api/v1", token="<TOKEN>")
121
+ client = UapiClient("https://uapis.cn", token="YOUR_API_KEY")
66
122
 
67
123
  @lru_cache(maxsize=128)
68
124
  def cached_lookup(qq: str):
@@ -73,34 +129,19 @@ user = cached_lookup("10001")
73
129
 
74
130
  也可以在 FastAPI / Django 项目里配合 Redis,将 SDK 的响应序列化后写入缓存,命中即直接返回。
75
131
 
76
- ### 注入自定义 httpx.Client
132
+ ### 调整超时与环境
77
133
 
78
134
  ```python
79
- import httpx
80
- from httpx import Auth
81
135
  from uapi import UapiClient
82
136
 
83
- class StaticToken(Auth):
84
- def __init__(self, token: str):
85
- self.token = token
86
- def auth_flow(self, request):
87
- request.headers["Authorization"] = f"Bearer {self.token}"
88
- yield request
89
-
90
- http_client = httpx.Client(
91
- timeout=5,
92
- transport=httpx.HTTPTransport(retries=3),
93
- event_hooks={"request": [lambda request: print("->", request.url)]},
94
- )
95
-
96
137
  client = UapiClient(
97
- "https://uapis.cn/api/v1",
98
- client=http_client,
99
- auth=StaticToken("<TOKEN>"),
138
+ "https://uapis.cn",
139
+ token="YOUR_API_KEY",
140
+ timeout=5.0,
100
141
  )
101
142
  ```
102
143
 
103
- 通过自定义 `client` / `transport` / `auth`,可以无缝植入代理、重试策略或 APM 埋点。
144
+ 如果你需要切换到别的环境,直接改 `base_url` 就可以;如果你只想缩短等待时间,传 `timeout` 就够了。
104
145
 
105
146
  ## 错误模型概览
106
147
 
@@ -18,11 +18,13 @@ pip install uapi-sdk-python
18
18
  ```python
19
19
  from uapi import UapiClient
20
20
 
21
- client = UapiClient("https://uapis.cn/api/v1")
22
- result = client.social.get_social_qq_userinfo(qq="10001")
21
+ client = UapiClient("https://uapis.cn", "YOUR_API_KEY")
22
+ result = client.misc.get_misc_hotboard(type="weibo")
23
23
  print(result)
24
24
  ```
25
25
 
26
+ 这个接口默认只要传 `type` 就可以拿当前热榜。`time`、`keyword`、`time_start`、`time_end`、`limit`、`sources` 都是按场景再传的可选参数。
27
+
26
28
  > [!TIP]
27
29
  > 请使用与运行脚本相同的 Python 解释器安装依赖,例如执行 `python -m pip install uapi-sdk-python` 后再运行 `python main.py`。在 VS Code / Pyright 中若提示 “Import uapi could not be resolved”,将解释器切换到当前虚拟环境即可恢复补全。
28
30
 
@@ -40,6 +42,60 @@ print(result)
40
42
 
41
43
  如果你需要查看字段细节或内部逻辑,仓库中的 `./internal` 目录同步保留了由 `openapi-generator` 生成的完整结构体,随时可供参考。
42
44
 
45
+ ## 响应元信息
46
+
47
+ 每次请求完成后,SDK 会自动把响应 Header 解析成结构化的 `ResponseMeta`,你不用自己拆原始字符串。
48
+
49
+ 成功时可以通过 `client.last_response_meta` 读取,失败时可以通过 `err.meta` 读取,两条路径拿到的是同一套字段。
50
+
51
+ ```python
52
+ from uapi import UapiClient, UapiError
53
+
54
+ client = UapiClient("https://uapis.cn", "YOUR_API_KEY")
55
+
56
+ # 成功路径
57
+ client.social.get_social_qq_userinfo(qq="10001")
58
+ meta = client.last_response_meta
59
+ if meta:
60
+ print("这次请求原价:", meta.credits_requested or 0, "积分")
61
+ print("这次实际扣费:", meta.credits_charged or 0, "积分")
62
+ print("特殊计价:", meta.credits_pricing or "原价")
63
+ print("余额剩余:", meta.balance_remaining_cents or 0, "分")
64
+ print("资源包剩余:", meta.quota_remaining_credits or 0, "积分")
65
+ print("当前有效额度桶:", meta.active_quota_buckets or 0)
66
+ print("额度用空即停:", meta.stop_on_empty)
67
+ print("Key QPS:", meta.billing_key_rate_remaining or 0, "/", meta.billing_key_rate_limit or 0, meta.billing_key_rate_unit or "req")
68
+ print("Request ID:", meta.request_id)
69
+
70
+ # 失败路径
71
+ try:
72
+ client.social.get_social_qq_userinfo(qq="10001")
73
+ except UapiError as err:
74
+ if err.meta:
75
+ print("Retry-After 秒数:", err.meta.retry_after_seconds)
76
+ print("Retry-After 原始值:", err.meta.retry_after_raw)
77
+ print("访客 QPS:", err.meta.visitor_rate_remaining or 0, "/", err.meta.visitor_rate_limit or 0)
78
+ print("Request ID:", err.meta.request_id)
79
+ ```
80
+
81
+ 常用字段一览:
82
+
83
+ | 字段 | 说明 |
84
+ |------|------|
85
+ | `credits_requested` | 这次请求原本要扣多少积分,也就是请求价 |
86
+ | `credits_charged` | 这次请求实际扣了多少积分 |
87
+ | `credits_pricing` | 特殊计价原因,例如缓存半价 `cache-hit-half-price` |
88
+ | `balance_remaining_cents` | 账户余额剩余(分) |
89
+ | `quota_remaining_credits` | 资源包剩余积分 |
90
+ | `active_quota_buckets` | 当前还有多少个有效额度桶参与计费 |
91
+ | `stop_on_empty` | 额度耗尽后是否直接停止服务 |
92
+ | `retry_after_seconds` / `retry_after_raw` | 限流后的等待时长;当服务端返回 HTTP 时间字符串时看 `retry_after_raw` |
93
+ | `request_id` | 请求唯一 ID,排障时使用 |
94
+ | `billing_key_rate_limit` / `billing_key_rate_remaining` | Billing Key 当前 QPS 规则的上限与剩余 |
95
+ | `billing_ip_rate_limit` / `billing_ip_rate_remaining` | Billing Key 单 IP 当前 QPS 规则的上限与剩余 |
96
+ | `visitor_rate_limit` / `visitor_rate_remaining` | 访客当前 QPS 规则的上限与剩余 |
97
+ | `rate_limit_policies` / `rate_limits` | 完整结构化限流策略数据 |
98
+
43
99
  ## 进阶实践
44
100
 
45
101
  ### 缓存与幂等
@@ -48,7 +104,7 @@ print(result)
48
104
  from functools import lru_cache
49
105
  from uapi import UapiClient
50
106
 
51
- client = UapiClient("https://uapis.cn/api/v1", token="<TOKEN>")
107
+ client = UapiClient("https://uapis.cn", token="YOUR_API_KEY")
52
108
 
53
109
  @lru_cache(maxsize=128)
54
110
  def cached_lookup(qq: str):
@@ -59,34 +115,19 @@ user = cached_lookup("10001")
59
115
 
60
116
  也可以在 FastAPI / Django 项目里配合 Redis,将 SDK 的响应序列化后写入缓存,命中即直接返回。
61
117
 
62
- ### 注入自定义 httpx.Client
118
+ ### 调整超时与环境
63
119
 
64
120
  ```python
65
- import httpx
66
- from httpx import Auth
67
121
  from uapi import UapiClient
68
122
 
69
- class StaticToken(Auth):
70
- def __init__(self, token: str):
71
- self.token = token
72
- def auth_flow(self, request):
73
- request.headers["Authorization"] = f"Bearer {self.token}"
74
- yield request
75
-
76
- http_client = httpx.Client(
77
- timeout=5,
78
- transport=httpx.HTTPTransport(retries=3),
79
- event_hooks={"request": [lambda request: print("->", request.url)]},
80
- )
81
-
82
123
  client = UapiClient(
83
- "https://uapis.cn/api/v1",
84
- client=http_client,
85
- auth=StaticToken("<TOKEN>"),
124
+ "https://uapis.cn",
125
+ token="YOUR_API_KEY",
126
+ timeout=5.0,
86
127
  )
87
128
  ```
88
129
 
89
- 通过自定义 `client` / `transport` / `auth`,可以无缝植入代理、重试策略或 APM 埋点。
130
+ 如果你需要切换到别的环境,直接改 `base_url` 就可以;如果你只想缩短等待时间,传 `timeout` 就够了。
90
131
 
91
132
  ## 错误模型概览
92
133
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "uapi-sdk-python"
7
- version = "0.1.13"
7
+ version = "0.1.14"
8
8
  description = "Idiomatic UAPI SDK for Python"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -12,6 +12,13 @@ class _Config:
12
12
  token: Optional[str] = None
13
13
  timeout: float = 15.0
14
14
 
15
+
16
+ def _normalize_base_url(base_url: str) -> str:
17
+ normalized = base_url.rstrip("/")
18
+ if normalized.endswith("/api/v1"):
19
+ normalized = normalized[: -len("/api/v1")]
20
+ return normalized
21
+
15
22
  class _HTTP:
16
23
  def __init__(self, cfg: _Config):
17
24
  self._cfg = cfg
@@ -43,7 +50,7 @@ class UapiClient:
43
50
  """
44
51
 
45
52
  def __init__(self, base_url: str, token: str | None = None, timeout: float = 15.0):
46
- self._http = _HTTP(_Config(base_url, token, timeout))
53
+ self._http = _HTTP(_Config(_normalize_base_url(base_url), token, timeout))
47
54
  # 动态挂载每个 Tag 的 API 门面
48
55
  _clipzy_zai_xian_jian_tie_ban = _ClipzyZaiXianJianTieBanApi(self._http)
49
56
  self.clipzy_zai_xian_jian_tie_ban = _clipzy_zai_xian_jian_tie_ban
@@ -2608,4 +2615,3 @@ UAPI Pro Search 是一个智能搜索引擎,采用机器学习算法对搜索
2608
2615
 
2609
2616
  return self._http.request("POST", path, params=params, json=body if body else None)
2610
2617
 
2611
-
@@ -20,6 +20,7 @@ class RateLimitStateEntry:
20
20
  @dataclass
21
21
  class ResponseMeta:
22
22
  request_id: Optional[str] = None
23
+ retry_after_raw: Optional[str] = None
23
24
  retry_after_seconds: Optional[int] = None
24
25
  debit_status: Optional[str] = None
25
26
  credits_requested: Optional[int] = None
@@ -37,6 +38,21 @@ class ResponseMeta:
37
38
  quota_remaining_credits: Optional[int] = None
38
39
  visitor_quota_limit_credits: Optional[int] = None
39
40
  visitor_quota_remaining_credits: Optional[int] = None
41
+ billing_key_rate_limit: Optional[int] = None
42
+ billing_key_rate_remaining: Optional[int] = None
43
+ billing_key_rate_unit: Optional[str] = None
44
+ billing_key_rate_window_seconds: Optional[int] = None
45
+ billing_key_rate_reset_after_seconds: Optional[int] = None
46
+ billing_ip_rate_limit: Optional[int] = None
47
+ billing_ip_rate_remaining: Optional[int] = None
48
+ billing_ip_rate_unit: Optional[str] = None
49
+ billing_ip_rate_window_seconds: Optional[int] = None
50
+ billing_ip_rate_reset_after_seconds: Optional[int] = None
51
+ visitor_rate_limit: Optional[int] = None
52
+ visitor_rate_remaining: Optional[int] = None
53
+ visitor_rate_unit: Optional[str] = None
54
+ visitor_rate_window_seconds: Optional[int] = None
55
+ visitor_rate_reset_after_seconds: Optional[int] = None
40
56
  raw_headers: Dict[str, str] = field(default_factory=dict)
41
57
 
42
58
  class UapiError(Exception):
@@ -230,8 +246,16 @@ def extract_meta(headers: Mapping[str, str]) -> ResponseMeta:
230
246
  reset_after_seconds=_parse_int(params.get("t")),
231
247
  )
232
248
 
249
+ billing_key_rate_policy = rate_limit_policies.get("billing-key-rate")
250
+ billing_key_rate_state = rate_limits.get("billing-key-rate")
251
+ billing_ip_rate_policy = rate_limit_policies.get("billing-ip-rate")
252
+ billing_ip_rate_state = rate_limits.get("billing-ip-rate")
253
+ visitor_rate_policy = rate_limit_policies.get("visitor-rate")
254
+ visitor_rate_state = rate_limits.get("visitor-rate")
255
+
233
256
  return ResponseMeta(
234
257
  request_id=raw_headers.get("x-request-id"),
258
+ retry_after_raw=raw_headers.get("retry-after"),
235
259
  retry_after_seconds=_parse_int(raw_headers.get("retry-after")),
236
260
  debit_status=raw_headers.get("uapi-debit-status"),
237
261
  credits_requested=_parse_int(raw_headers.get("uapi-credits-requested")),
@@ -249,6 +273,21 @@ def extract_meta(headers: Mapping[str, str]) -> ResponseMeta:
249
273
  quota_remaining_credits=rate_limits.get("billing-quota").remaining if "billing-quota" in rate_limits else None,
250
274
  visitor_quota_limit_credits=rate_limit_policies.get("visitor-quota").quota if "visitor-quota" in rate_limit_policies else None,
251
275
  visitor_quota_remaining_credits=rate_limits.get("visitor-quota").remaining if "visitor-quota" in rate_limits else None,
276
+ billing_key_rate_limit=billing_key_rate_policy.quota if billing_key_rate_policy else None,
277
+ billing_key_rate_remaining=billing_key_rate_state.remaining if billing_key_rate_state else None,
278
+ billing_key_rate_unit=billing_key_rate_policy.unit if billing_key_rate_policy and billing_key_rate_policy.unit is not None else (billing_key_rate_state.unit if billing_key_rate_state else None),
279
+ billing_key_rate_window_seconds=billing_key_rate_policy.window_seconds if billing_key_rate_policy else None,
280
+ billing_key_rate_reset_after_seconds=billing_key_rate_state.reset_after_seconds if billing_key_rate_state else None,
281
+ billing_ip_rate_limit=billing_ip_rate_policy.quota if billing_ip_rate_policy else None,
282
+ billing_ip_rate_remaining=billing_ip_rate_state.remaining if billing_ip_rate_state else None,
283
+ billing_ip_rate_unit=billing_ip_rate_policy.unit if billing_ip_rate_policy and billing_ip_rate_policy.unit is not None else (billing_ip_rate_state.unit if billing_ip_rate_state else None),
284
+ billing_ip_rate_window_seconds=billing_ip_rate_policy.window_seconds if billing_ip_rate_policy else None,
285
+ billing_ip_rate_reset_after_seconds=billing_ip_rate_state.reset_after_seconds if billing_ip_rate_state else None,
286
+ visitor_rate_limit=visitor_rate_policy.quota if visitor_rate_policy else None,
287
+ visitor_rate_remaining=visitor_rate_state.remaining if visitor_rate_state else None,
288
+ visitor_rate_unit=visitor_rate_policy.unit if visitor_rate_policy and visitor_rate_policy.unit is not None else (visitor_rate_state.unit if visitor_rate_state else None),
289
+ visitor_rate_window_seconds=visitor_rate_policy.window_seconds if visitor_rate_policy else None,
290
+ visitor_rate_reset_after_seconds=visitor_rate_state.reset_after_seconds if visitor_rate_state else None,
252
291
  raw_headers=raw_headers,
253
292
  )
254
293
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uapi-sdk-python
3
- Version: 0.1.13
3
+ Version: 0.1.14
4
4
  Summary: Idiomatic UAPI SDK for Python
5
5
  Author-email: UAPI <dev@uapis.cn>
6
6
  Requires-Python: >=3.9
@@ -32,11 +32,13 @@ pip install uapi-sdk-python
32
32
  ```python
33
33
  from uapi import UapiClient
34
34
 
35
- client = UapiClient("https://uapis.cn/api/v1")
36
- result = client.social.get_social_qq_userinfo(qq="10001")
35
+ client = UapiClient("https://uapis.cn", "YOUR_API_KEY")
36
+ result = client.misc.get_misc_hotboard(type="weibo")
37
37
  print(result)
38
38
  ```
39
39
 
40
+ 这个接口默认只要传 `type` 就可以拿当前热榜。`time`、`keyword`、`time_start`、`time_end`、`limit`、`sources` 都是按场景再传的可选参数。
41
+
40
42
  > [!TIP]
41
43
  > 请使用与运行脚本相同的 Python 解释器安装依赖,例如执行 `python -m pip install uapi-sdk-python` 后再运行 `python main.py`。在 VS Code / Pyright 中若提示 “Import uapi could not be resolved”,将解释器切换到当前虚拟环境即可恢复补全。
42
44
 
@@ -54,6 +56,60 @@ print(result)
54
56
 
55
57
  如果你需要查看字段细节或内部逻辑,仓库中的 `./internal` 目录同步保留了由 `openapi-generator` 生成的完整结构体,随时可供参考。
56
58
 
59
+ ## 响应元信息
60
+
61
+ 每次请求完成后,SDK 会自动把响应 Header 解析成结构化的 `ResponseMeta`,你不用自己拆原始字符串。
62
+
63
+ 成功时可以通过 `client.last_response_meta` 读取,失败时可以通过 `err.meta` 读取,两条路径拿到的是同一套字段。
64
+
65
+ ```python
66
+ from uapi import UapiClient, UapiError
67
+
68
+ client = UapiClient("https://uapis.cn", "YOUR_API_KEY")
69
+
70
+ # 成功路径
71
+ client.social.get_social_qq_userinfo(qq="10001")
72
+ meta = client.last_response_meta
73
+ if meta:
74
+ print("这次请求原价:", meta.credits_requested or 0, "积分")
75
+ print("这次实际扣费:", meta.credits_charged or 0, "积分")
76
+ print("特殊计价:", meta.credits_pricing or "原价")
77
+ print("余额剩余:", meta.balance_remaining_cents or 0, "分")
78
+ print("资源包剩余:", meta.quota_remaining_credits or 0, "积分")
79
+ print("当前有效额度桶:", meta.active_quota_buckets or 0)
80
+ print("额度用空即停:", meta.stop_on_empty)
81
+ print("Key QPS:", meta.billing_key_rate_remaining or 0, "/", meta.billing_key_rate_limit or 0, meta.billing_key_rate_unit or "req")
82
+ print("Request ID:", meta.request_id)
83
+
84
+ # 失败路径
85
+ try:
86
+ client.social.get_social_qq_userinfo(qq="10001")
87
+ except UapiError as err:
88
+ if err.meta:
89
+ print("Retry-After 秒数:", err.meta.retry_after_seconds)
90
+ print("Retry-After 原始值:", err.meta.retry_after_raw)
91
+ print("访客 QPS:", err.meta.visitor_rate_remaining or 0, "/", err.meta.visitor_rate_limit or 0)
92
+ print("Request ID:", err.meta.request_id)
93
+ ```
94
+
95
+ 常用字段一览:
96
+
97
+ | 字段 | 说明 |
98
+ |------|------|
99
+ | `credits_requested` | 这次请求原本要扣多少积分,也就是请求价 |
100
+ | `credits_charged` | 这次请求实际扣了多少积分 |
101
+ | `credits_pricing` | 特殊计价原因,例如缓存半价 `cache-hit-half-price` |
102
+ | `balance_remaining_cents` | 账户余额剩余(分) |
103
+ | `quota_remaining_credits` | 资源包剩余积分 |
104
+ | `active_quota_buckets` | 当前还有多少个有效额度桶参与计费 |
105
+ | `stop_on_empty` | 额度耗尽后是否直接停止服务 |
106
+ | `retry_after_seconds` / `retry_after_raw` | 限流后的等待时长;当服务端返回 HTTP 时间字符串时看 `retry_after_raw` |
107
+ | `request_id` | 请求唯一 ID,排障时使用 |
108
+ | `billing_key_rate_limit` / `billing_key_rate_remaining` | Billing Key 当前 QPS 规则的上限与剩余 |
109
+ | `billing_ip_rate_limit` / `billing_ip_rate_remaining` | Billing Key 单 IP 当前 QPS 规则的上限与剩余 |
110
+ | `visitor_rate_limit` / `visitor_rate_remaining` | 访客当前 QPS 规则的上限与剩余 |
111
+ | `rate_limit_policies` / `rate_limits` | 完整结构化限流策略数据 |
112
+
57
113
  ## 进阶实践
58
114
 
59
115
  ### 缓存与幂等
@@ -62,7 +118,7 @@ print(result)
62
118
  from functools import lru_cache
63
119
  from uapi import UapiClient
64
120
 
65
- client = UapiClient("https://uapis.cn/api/v1", token="<TOKEN>")
121
+ client = UapiClient("https://uapis.cn", token="YOUR_API_KEY")
66
122
 
67
123
  @lru_cache(maxsize=128)
68
124
  def cached_lookup(qq: str):
@@ -73,34 +129,19 @@ user = cached_lookup("10001")
73
129
 
74
130
  也可以在 FastAPI / Django 项目里配合 Redis,将 SDK 的响应序列化后写入缓存,命中即直接返回。
75
131
 
76
- ### 注入自定义 httpx.Client
132
+ ### 调整超时与环境
77
133
 
78
134
  ```python
79
- import httpx
80
- from httpx import Auth
81
135
  from uapi import UapiClient
82
136
 
83
- class StaticToken(Auth):
84
- def __init__(self, token: str):
85
- self.token = token
86
- def auth_flow(self, request):
87
- request.headers["Authorization"] = f"Bearer {self.token}"
88
- yield request
89
-
90
- http_client = httpx.Client(
91
- timeout=5,
92
- transport=httpx.HTTPTransport(retries=3),
93
- event_hooks={"request": [lambda request: print("->", request.url)]},
94
- )
95
-
96
137
  client = UapiClient(
97
- "https://uapis.cn/api/v1",
98
- client=http_client,
99
- auth=StaticToken("<TOKEN>"),
138
+ "https://uapis.cn",
139
+ token="YOUR_API_KEY",
140
+ timeout=5.0,
100
141
  )
101
142
  ```
102
143
 
103
- 通过自定义 `client` / `transport` / `auth`,可以无缝植入代理、重试策略或 APM 埋点。
144
+ 如果你需要切换到别的环境,直接改 `base_url` 就可以;如果你只想缩短等待时间,传 `timeout` 就够了。
104
145
 
105
146
  ## 错误模型概览
106
147