fiuai-sdk-python 0.8.1__tar.gz → 0.8.3__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.
Files changed (43) hide show
  1. fiuai_sdk_python-0.8.3/PKG-INFO +768 -0
  2. fiuai_sdk_python-0.8.3/README.md +734 -0
  3. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/pyproject.toml +1 -1
  4. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/auth/context_mgr.py +8 -0
  5. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/auth/header.py +3 -0
  6. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/auth/helper.py +11 -0
  7. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/auth/type.py +9 -2
  8. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/client.py +5 -0
  9. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/context.py +12 -4
  10. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/http/client.py +4 -1
  11. fiuai_sdk_python-0.8.1/PKG-INFO +0 -36
  12. fiuai_sdk_python-0.8.1/README.md +0 -2
  13. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/.gitignore +0 -0
  14. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/CHANGELOG.md +0 -0
  15. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/LICENSE +0 -0
  16. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/__init__.py +0 -0
  17. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/auth/__init__.py +0 -0
  18. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/bank.py +0 -0
  19. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/company.py +0 -0
  20. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/config.py +0 -0
  21. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/const.py +0 -0
  22. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/datatype.py +0 -0
  23. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/doctype.py +0 -0
  24. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/error.py +0 -0
  25. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/examples/fastapi_integration.py +0 -0
  26. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/http/__init__.py +0 -0
  27. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/item.py +0 -0
  28. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/perm.py +0 -0
  29. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/pkg/cache/__init__.py +0 -0
  30. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/pkg/cache/cache_client.py +0 -0
  31. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/pkg/cache/circuit_breaker.py +0 -0
  32. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/pkg/cache/decorator.py +0 -0
  33. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/pkg/cache/redis_manager.py +0 -0
  34. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/pkg/cache/types.py +0 -0
  35. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/profile.py +0 -0
  36. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/resp.py +0 -0
  37. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/setup.py +0 -0
  38. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/type.py +0 -0
  39. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/util.py +0 -0
  40. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/utils/__init__.py +0 -0
  41. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/utils/ids.py +0 -0
  42. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/utils/logger.py +0 -0
  43. {fiuai_sdk_python-0.8.1 → fiuai_sdk_python-0.8.3}/src/fiuai_sdk_python/utils/text.py +0 -0
@@ -0,0 +1,768 @@
1
+ Metadata-Version: 2.4
2
+ Name: fiuai_sdk_python
3
+ Version: 0.8.3
4
+ Summary: FiuAI Python SDK - 企业级AI服务集成开发工具包
5
+ Project-URL: Homepage, https://github.com/fiuai/fiuai-sdk-python
6
+ Project-URL: Documentation, https://github.com/fiuai/fiuai-sdk-python#readme
7
+ Project-URL: Repository, https://github.com/fiuai/fiuai-sdk-python.git
8
+ Project-URL: Issues, https://github.com/fiuai/fiuai-sdk-python/issues
9
+ Project-URL: Changelog, https://github.com/fiuai/fiuai-sdk-python/blob/main/CHANGELOG.md
10
+ Author-email: liming <lmlala@aliyun.com>
11
+ Maintainer-email: liming <lmlala@aliyun.com>
12
+ License: MIT
13
+ License-File: LICENSE
14
+ Keywords: ai,enterprise,fiuai,python,sdk
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Requires-Python: >=3.12
25
+ Requires-Dist: fastapi>=0.118.2
26
+ Requires-Dist: httpx>=0.28.1
27
+ Requires-Dist: langgraph-checkpoint-redis>=0.3.1
28
+ Requires-Dist: pydantic>=2.11.7
29
+ Requires-Dist: pytest>=8.4.1
30
+ Requires-Dist: redis>=7.1.0
31
+ Requires-Dist: snowflake-id>=1.0.2
32
+ Requires-Dist: tenacity>=9.1.2
33
+ Description-Content-Type: text/markdown
34
+
35
+ # fiuai-sdk-python
36
+
37
+ FiuAI Python SDK — 企业级 AI 服务集成开发工具包。
38
+
39
+ 提供统一的 FiuAI 平台接入能力, 包括: 认证上下文管理、Frappe API 客户端、HTTP 客户端工厂、Redis 缓存 (含熔断降级)、雪花 ID 生成、日志初始化等。
40
+
41
+ ## 安装
42
+
43
+ ```bash
44
+ # uv (推荐)
45
+ uv add fiuai-sdk-python
46
+
47
+ # pip
48
+ pip install fiuai-sdk-python
49
+ ```
50
+
51
+ > 要求 Python >= 3.12
52
+
53
+ ---
54
+
55
+ ## 目录
56
+
57
+ - [快速开始](#快速开始)
58
+ - [SDK 初始化](#sdk-初始化)
59
+ - [Frappe API 客户端](#frappe-api-客户端)
60
+ - [认证与上下文](#认证与上下文)
61
+ - [HTTP 客户端](#http-客户端)
62
+ - [Redis 连接池管理](#redis-连接池管理)
63
+ - [缓存客户端](#缓存客户端)
64
+ - [缓存装饰器](#缓存装饰器)
65
+ - [熔断器](#熔断器)
66
+ - [日志系统](#日志系统)
67
+ - [雪花 ID 生成](#雪花-id-生成)
68
+ - [工具函数](#工具函数)
69
+ - [FastAPI 集成](#fastapi-集成)
70
+ - [API 参考索引](#api-参考索引)
71
+
72
+ ---
73
+
74
+ ## 快速开始
75
+
76
+ ```python
77
+ from fiuai_sdk_python import init_fiuai, get_client
78
+
79
+ # 1. 初始化 SDK (全局一次)
80
+ init_fiuai(url="https://your-frappe-instance.com")
81
+
82
+ # 2. 获取客户端
83
+ client = get_client(
84
+ username="user@example.com",
85
+ auth_tenant_id="tenant-001",
86
+ current_company="company-001",
87
+ )
88
+
89
+ # 3. 调用 API
90
+ response = client.get_user_profile_info()
91
+ if response.is_success():
92
+ print(response.data)
93
+ ```
94
+
95
+ ---
96
+
97
+ ## SDK 初始化
98
+
99
+ ```python
100
+ from fiuai_sdk_python import init_fiuai
101
+
102
+ init_fiuai(
103
+ url="https://your-frappe-instance.com",
104
+ max_api_retry=3, # API 重试次数
105
+ timeout=5, # 请求超时 (秒)
106
+ verify=False, # SSL 证书校验
107
+ )
108
+ ```
109
+
110
+ `init_fiuai` 是全局单例, 只需在应用启动时调用一次。后续通过 `get_client()` 获取客户端时, 会自动读取此配置。
111
+
112
+ ---
113
+
114
+ ## Frappe API 客户端
115
+
116
+ ### 获取客户端
117
+
118
+ ```python
119
+ from fiuai_sdk_python import get_client, FiuaiSDK
120
+
121
+ # 方式 1: 工厂函数 (推荐, 自动读取 init_fiuai 配置)
122
+ client = get_client(
123
+ username="user@example.com",
124
+ auth_tenant_id="tenant-001",
125
+ current_company="company-001",
126
+ company_unique_no="UNQ-001",
127
+ )
128
+
129
+ # 方式 2: 直接实例化
130
+ client = FiuaiSDK(
131
+ url="https://your-frappe-instance.com",
132
+ username="user@example.com",
133
+ auth_tenant_id="tenant-001",
134
+ current_company="company-001",
135
+ )
136
+ ```
137
+
138
+ ### CRUD 操作
139
+
140
+ ```python
141
+ # 创建文档
142
+ resp = client.internal_create(data={
143
+ "doctype": "Sales Invoice",
144
+ "customer": "CUST-001",
145
+ "items": [{"item_code": "ITEM-001", "qty": 10}],
146
+ })
147
+
148
+ # 查询单条
149
+ resp = client.internal_get("Sales Invoice", "SI-00001")
150
+
151
+ # 查询列表
152
+ resp = client.internal_get_list(
153
+ doctype="Sales Invoice",
154
+ filters={"customer": "CUST-001"},
155
+ fields=["name", "grand_total"],
156
+ limit_page_length=50,
157
+ order_by="creation desc",
158
+ )
159
+
160
+ # 更新
161
+ resp = client.internal_update(data={
162
+ "doctype": "Sales Invoice",
163
+ "name": "SI-00001",
164
+ "custom_field": "new_value",
165
+ })
166
+
167
+ # 删除
168
+ resp = client.internal_delete("Sales Invoice", "SI-00001")
169
+
170
+ # 提交 / 取消
171
+ resp = client.internal_submit("Sales Invoice", "SI-00001")
172
+ resp = client.internal_cancel("Sales Invoice", "SI-00001")
173
+ ```
174
+
175
+ ### 通用请求
176
+
177
+ ```python
178
+ # POST
179
+ resp = client.internal_post_req("/api/method/custom_method", postdata={"key": "value"})
180
+
181
+ # GET
182
+ resp = client.internal_get_req("/api/method/custom_method", params={"key": "value"})
183
+ ```
184
+
185
+ ### 临时头覆盖
186
+
187
+ 跨租户/跨公司调用时, 可临时切换身份:
188
+
189
+ ```python
190
+ client.set_temp_header(
191
+ auth_tenant_id="other-tenant",
192
+ auth_company_id="other-company",
193
+ user_id="other-user@example.com",
194
+ )
195
+
196
+ resp = client.internal_get_list("Customer", limit_page_length=10)
197
+ client.clear_temp_headers()
198
+ ```
199
+
200
+ ### 响应处理
201
+
202
+ 所有 API 调用返回 `ApiResponse`:
203
+
204
+ ```python
205
+ resp = client.internal_get("Sales Invoice", "SI-00001")
206
+
207
+ resp.http_success # HTTP 状态码 2xx
208
+ resp.api_success # 业务层成功
209
+ resp.is_success() # http_success and api_success
210
+ resp.status_code # HTTP 状态码
211
+ resp.data # 响应数据
212
+ resp.error_code # 错误码
213
+ resp.error_message # 错误信息
214
+ ```
215
+
216
+ ---
217
+
218
+ ## 认证与上下文
219
+
220
+ ### 数据模型
221
+
222
+ ```python
223
+ from fiuai_sdk_python.auth import AuthData, AuthHeader
224
+
225
+ # AuthData: 解析后的认证数据
226
+ # 字段: user_id, auth_tenant_id, current_company, impersonation,
227
+ # company_unique_no, trace_id, client, channel, lang, accept_language
228
+
229
+ # AuthHeader: HTTP 头映射
230
+ # 字段: x_fiuai_user, x_fiuai_auth_tenant_id, x_fiuai_current_company, ...
231
+ ```
232
+
233
+ ### 从请求解析认证
234
+
235
+ ```python
236
+ from fiuai_sdk_python.auth import parse_auth_headers, extract_auth_from_request
237
+
238
+ # 从字典解析
239
+ auth = parse_auth_headers({"X-Fiuai-User": "user@example.com", ...})
240
+
241
+ # 从 FastAPI Request 解析
242
+ auth = extract_auth_from_request(request, engine="fastapi")
243
+ ```
244
+
245
+ ### 便捷函数
246
+
247
+ ```python
248
+ from fiuai_sdk_python.auth import (
249
+ get_auth_data,
250
+ get_current_user_id,
251
+ get_current_tenant_id,
252
+ get_current_company,
253
+ get_company_unique_no,
254
+ is_impersonating,
255
+ )
256
+
257
+ user_id = get_current_user_id(request)
258
+ tenant_id = get_current_tenant_id(request)
259
+ company_id = get_current_company(request)
260
+ ```
261
+
262
+ ### 上下文管理
263
+
264
+ ```python
265
+ from fiuai_sdk_python.auth import init_context, get_auth_data_from_context, ContextManager
266
+
267
+ # 初始化上下文 (通常在中间件中)
268
+ ctx = init_context(
269
+ auth_data=auth_data,
270
+ event_id="evt-001",
271
+ task_id="task-001",
272
+ )
273
+
274
+ # 在业务代码中读取
275
+ auth = get_auth_data_from_context()
276
+ ```
277
+
278
+ ### RequestContext (基于 contextvars)
279
+
280
+ ```python
281
+ from fiuai_sdk_python import RequestContext, get_current_headers, get_trace_id
282
+
283
+ # 注入上下文
284
+ with RequestContext.from_fastapi_request(request):
285
+ headers = get_current_headers()
286
+ trace_id = get_trace_id()
287
+ ```
288
+
289
+ ---
290
+
291
+ ## HTTP 客户端
292
+
293
+ 提供基于 `httpx` 的 HTTP 客户端工厂, 支持自动注入认证头和重试。
294
+
295
+ ```python
296
+ from fiuai_sdk_python.http import (
297
+ create_http_client, # 创建异步客户端
298
+ create_sync_http_client, # 创建同步客户端
299
+ get_async_http_client, # 全局单例异步客户端
300
+ get_sync_http_client, # 全局单例同步客户端
301
+ close_global_clients, # 关闭全局客户端
302
+ )
303
+
304
+ # 异步客户端 (自动注入 auth headers)
305
+ async_client = create_http_client(
306
+ base_url="https://api.example.com",
307
+ timeout=30,
308
+ retry_count=3,
309
+ retry_interval=1,
310
+ )
311
+
312
+ async with async_client as client:
313
+ resp = await client.get("/api/resource")
314
+
315
+ # 同步客户端
316
+ sync_client = create_sync_http_client(base_url="https://api.example.com")
317
+ resp = sync_client.get("/api/resource")
318
+ ```
319
+
320
+ ### 认证头拦截器
321
+
322
+ HTTP 客户端会自动从当前 `RequestContext` 中提取认证头并注入请求:
323
+
324
+ ```python
325
+ from fiuai_sdk_python.http import extract_auth_headers, AUTH_HEADER_KEYS
326
+
327
+ headers = extract_auth_headers() # 从当前上下文提取
328
+ ```
329
+
330
+ ---
331
+
332
+ ## Redis 连接池管理
333
+
334
+ `redis_manager` 是全局单例, 管理多个 Redis 连接池。
335
+
336
+ ### 初始化
337
+
338
+ ```python
339
+ from fiuai_sdk_python.pkg.cache import redis_manager, RedisDBConfig
340
+
341
+ await redis_manager.initialize(
342
+ async_dbs=[
343
+ RedisDBConfig(
344
+ name="default",
345
+ host="127.0.0.1",
346
+ port=6379,
347
+ password="your-password",
348
+ db=0,
349
+ pool_size=20,
350
+ ),
351
+ RedisDBConfig(
352
+ name="cache",
353
+ host="127.0.0.1",
354
+ port=6379,
355
+ password="your-password",
356
+ db=1,
357
+ pool_size=10,
358
+ ),
359
+ ],
360
+ sync_dbs=[
361
+ RedisDBConfig(
362
+ name="default",
363
+ host="127.0.0.1",
364
+ port=6379,
365
+ password="your-password",
366
+ db=0,
367
+ pool_size=5,
368
+ ),
369
+ ],
370
+ )
371
+ ```
372
+
373
+ > 支持增量注册: 多次调用 `initialize()` 不会重复创建已存在的连接池。
374
+ > async 和 sync 连接池独立追踪, 同名 db 可分别注册为 async 和 sync。
375
+
376
+ ### 获取客户端
377
+
378
+ ```python
379
+ # 异步
380
+ async_client = redis_manager.get_async_client("default")
381
+ value = await async_client.get("key")
382
+
383
+ # 同步
384
+ sync_client = redis_manager.get_sync_client("default")
385
+ value = sync_client.get("key")
386
+ ```
387
+
388
+ ### LangGraph Checkpoint (Agent 场景)
389
+
390
+ ```python
391
+ # 仅 Agent 项目需要, lazy import langgraph-checkpoint-redis
392
+ redis_manager.setup_langgraph_checkpoint("default")
393
+
394
+ # 异步版
395
+ await redis_manager.setup_langgraph_checkpoint_async("default")
396
+ ```
397
+
398
+ ### 关闭
399
+
400
+ ```python
401
+ await redis_manager.close_all()
402
+ ```
403
+
404
+ ---
405
+
406
+ ## 缓存客户端
407
+
408
+ `CacheClient` 在 Redis 客户端之上提供: key 前缀管理、TTL、Hash 操作、cache-aside 模式、熔断降级。
409
+
410
+ ### 创建
411
+
412
+ ```python
413
+ from fiuai_sdk_python.pkg.cache import CacheClient, CacheConfig, CircuitBreakerConfig
414
+
415
+ client = CacheClient(CacheConfig(
416
+ redis_db_name="cache", # redis_manager 中注册的连接池名
417
+ default_ttl=300, # 默认 TTL (秒), None 不过期
418
+ key_prefix="myapp", # key 前缀, 实际 key 为 "myapp:{key}"
419
+ circuit_breaker=CircuitBreakerConfig(
420
+ failure_threshold=5, # 连续失败 5 次后熔断
421
+ recovery_timeout=30.0, # 熔断 30 秒后进入半开
422
+ half_open_max_calls=1, # 半开状态允许 1 次探测
423
+ ),
424
+ ))
425
+ ```
426
+
427
+ ### KV 操作
428
+
429
+ ```python
430
+ # 异步
431
+ await client.set("user:123", '{"name": "test"}', ttl=60)
432
+ value = await client.get("user:123") # -> Optional[str]
433
+ exists = await client.exists("user:123") # -> bool
434
+ await client.delete("user:123")
435
+
436
+ # 同步
437
+ client.set_sync("user:123", '{"name": "test"}', ttl=60)
438
+ value = client.get_sync("user:123")
439
+ ```
440
+
441
+ ### Hash 操作
442
+
443
+ ```python
444
+ await client.hset("config", "theme", "dark")
445
+ theme = await client.hget("config", "theme") # -> "dark"
446
+ all_config = await client.hgetall("config") # -> {"theme": "dark", ...}
447
+ ```
448
+
449
+ ### Cache-Aside (核心)
450
+
451
+ `get_or_load` 是最常用的模式: 命中缓存直接返回, miss 时调用 loader 加载并写回缓存。
452
+
453
+ ```python
454
+ # 异步
455
+ async def load_user_config(user_id: str) -> dict:
456
+ return await db.query("SELECT * FROM config WHERE user_id = ?", user_id)
457
+
458
+ config = await client.get_or_load(
459
+ key=f"config:{user_id}",
460
+ loader=lambda: load_user_config(user_id),
461
+ ttl=120,
462
+ # serializer/deserializer 默认 json.dumps/json.loads
463
+ )
464
+
465
+ # 同步
466
+ config = client.get_or_load_sync(
467
+ key=f"config:{user_id}",
468
+ loader=lambda: db.query_sync(...),
469
+ ttl=120,
470
+ )
471
+ ```
472
+
473
+ ### 熔断降级
474
+
475
+ Redis 不可用时, `CacheClient` 自动降级:
476
+ - `get` / `get_sync` → 返回 `None`
477
+ - `set` / `set_sync` → 返回 `False`
478
+ - `get_or_load` / `get_or_load_sync` → 直接调 loader, 业务不中断
479
+
480
+ 无需业务代码感知 Redis 故障。
481
+
482
+ ---
483
+
484
+ ## 缓存装饰器
485
+
486
+ `@cached` 装饰器将 cache-aside 模式封装为函数级注解。
487
+
488
+ ### 初始化默认客户端
489
+
490
+ ```python
491
+ from fiuai_sdk_python.pkg.cache import init_cache, CacheConfig
492
+
493
+ # 应用启动时调用一次 (在 redis_manager.initialize 之后)
494
+ init_cache(CacheConfig(
495
+ redis_db_name="cache",
496
+ default_ttl=120,
497
+ key_prefix="myapp",
498
+ ))
499
+ ```
500
+
501
+ ### 使用装饰器
502
+
503
+ ```python
504
+ from fiuai_sdk_python.pkg.cache import cached
505
+
506
+ # 固定 key
507
+ @cached(key="global_settings", ttl=300)
508
+ async def get_settings() -> dict:
509
+ return await fetch_settings_from_db()
510
+
511
+ # 动态 key (根据函数参数生成)
512
+ @cached(
513
+ key=lambda company_id, side: f"config:{company_id}:{side}",
514
+ ttl=120,
515
+ )
516
+ def get_company_config(company_id: str, side: str) -> dict:
517
+ return query_config(company_id, side)
518
+
519
+ # 带 prefix
520
+ @cached(
521
+ key=lambda user_id: f"profile:{user_id}",
522
+ ttl=60,
523
+ prefix="finnexus", # 最终 key: "finnexus:profile:{user_id}"
524
+ )
525
+ async def get_user_profile(user_id: str) -> dict:
526
+ ...
527
+
528
+ # 指定自定义 CacheClient
529
+ @cached(key="custom", client=my_cache_client)
530
+ def get_data() -> dict:
531
+ ...
532
+ ```
533
+
534
+ 装饰器自动识别 sync/async 函数, 无需区分。
535
+
536
+ > 如果 `init_cache` 未调用 (即默认客户端为 None), 装饰器退化为直接调用原函数, 不会报错。
537
+
538
+ ---
539
+
540
+ ## 熔断器
541
+
542
+ `CircuitBreaker` 实现三态熔断 (CLOSED → OPEN → HALF_OPEN → CLOSED), 通常由 `CacheClient` 内部使用, 也可独立使用。
543
+
544
+ ```
545
+ 正常 (CLOSED) ──连续失败达阈值──→ 熔断 (OPEN)
546
+ ↑ │
547
+ │ 冷却期过后
548
+ │ ↓
549
+ └───── 探测成功 ───── 半开 (HALF_OPEN)
550
+
551
+ 探测失败 ──→ 回到 OPEN
552
+ ```
553
+
554
+ ### 独立使用
555
+
556
+ ```python
557
+ from fiuai_sdk_python.pkg.cache import CircuitBreaker, CircuitBreakerConfig
558
+
559
+ breaker = CircuitBreaker(CircuitBreakerConfig(
560
+ failure_threshold=3,
561
+ recovery_timeout=10.0,
562
+ half_open_max_calls=1,
563
+ ))
564
+
565
+ if breaker.allow_request:
566
+ try:
567
+ result = call_external_service()
568
+ breaker.record_success()
569
+ except Exception:
570
+ breaker.record_failure()
571
+ else:
572
+ result = fallback_value()
573
+
574
+ # 查看状态
575
+ print(breaker.state) # CircuitState.CLOSED / OPEN / HALF_OPEN
576
+ ```
577
+
578
+ ---
579
+
580
+ ## 日志系统
581
+
582
+ ```python
583
+ from fiuai_sdk_python.utils.logger import init_logger, get_logger
584
+
585
+ # 初始化 (应用启动时调用一次)
586
+ init_logger(
587
+ log_path="logs/",
588
+ log_level="INFO",
589
+ context_injector=lambda: {"trace_id": get_current_trace_id()},
590
+ )
591
+
592
+ # 在各模块中使用
593
+ logger = get_logger(__name__)
594
+ logger.info("processing request")
595
+ logger.error("something went wrong", exc_info=True)
596
+ ```
597
+
598
+ 日志格式: `%(asctime)s - %(name)s - %(levelname)s - [trace_id:%(trace_id)s] - %(message)s`
599
+
600
+ `context_injector` 可注入自定义上下文字段 (如 trace_id) 到每条日志。
601
+
602
+ ---
603
+
604
+ ## 雪花 ID 生成
605
+
606
+ ```python
607
+ from fiuai_sdk_python.utils.ids import gen_id, get_instance_info
608
+
609
+ # 生成唯一 ID
610
+ unique_id = gen_id() # -> "7345892348923489234" (字符串)
611
+
612
+ # 查看实例信息
613
+ info = get_instance_info()
614
+ # -> {"instance_id": 42, "process_id": 12345, "start_time": ...}
615
+
616
+ # 自定义实例 ID (分布式部署时)
617
+ from fiuai_sdk_python.utils.ids import set_custom_instance_id
618
+ set_custom_instance_id(42)
619
+ ```
620
+
621
+ ---
622
+
623
+ ## 工具函数
624
+
625
+ ### 文本处理
626
+
627
+ ```python
628
+ from fiuai_sdk_python.utils.text import safe_string_name, safe_str, safe_json_str
629
+
630
+ # 全角符号转半角
631
+ safe_string_name("北京(朝阳)公司") # -> "北京(朝阳)公司"
632
+
633
+ # URL 安全编码 (用于 Redis 密码等含特殊字符的场景)
634
+ safe_str("p@ss#word!") # -> "p%40ss%23word%21"
635
+
636
+ # JSON 安全处理 (转义控制字符)
637
+ safe_json_str("line1\nline2") # -> "line1\\nline2"
638
+ ```
639
+
640
+ ---
641
+
642
+ ## FastAPI 集成
643
+
644
+ ### 中间件注入上下文
645
+
646
+ ```python
647
+ from fastapi import FastAPI
648
+ from fiuai_sdk_python import init_fiuai
649
+ from fiuai_sdk_python.examples.fastapi_integration import setup_fiuai_context
650
+
651
+ app = FastAPI()
652
+
653
+ # 初始化 SDK
654
+ init_fiuai(url="https://your-frappe-instance.com")
655
+
656
+ # 注册上下文中间件 (自动将请求头注入 RequestContext)
657
+ setup_fiuai_context(app)
658
+ ```
659
+
660
+ ### 完整启动示例
661
+
662
+ ```python
663
+ from contextlib import asynccontextmanager
664
+ from fastapi import FastAPI
665
+ from fiuai_sdk_python import init_fiuai
666
+ from fiuai_sdk_python.utils.logger import init_logger
667
+ from fiuai_sdk_python.pkg.cache import redis_manager, RedisDBConfig, init_cache, CacheConfig
668
+ from fiuai_sdk_python.examples.fastapi_integration import setup_fiuai_context
669
+
670
+
671
+ @asynccontextmanager
672
+ async def lifespan(app: FastAPI):
673
+ # 启动
674
+ init_logger(log_path="logs/", log_level="INFO")
675
+ init_fiuai(url="https://your-frappe-instance.com")
676
+
677
+ await redis_manager.initialize(async_dbs=[
678
+ RedisDBConfig(name="default", host="127.0.0.1", port=6379, password="", db=0),
679
+ ])
680
+ init_cache(CacheConfig(redis_db_name="default", default_ttl=120, key_prefix="myapp"))
681
+
682
+ yield
683
+
684
+ # 关闭
685
+ await redis_manager.close_all()
686
+
687
+
688
+ app = FastAPI(lifespan=lifespan)
689
+ setup_fiuai_context(app)
690
+ ```
691
+
692
+ ---
693
+
694
+ ## API 参考索引
695
+
696
+ ### 顶层导出 (`fiuai_sdk_python`)
697
+
698
+ | 名称 | 类型 | 说明 |
699
+ |------|------|------|
700
+ | `init_fiuai` | function | 初始化 SDK 全局配置 |
701
+ | `FiuaiSDK` | class | Frappe API 客户端 |
702
+ | `get_client` | function | 客户端工厂 |
703
+ | `UserProfileInfo` | class | 用户信息模型 |
704
+ | `UserProfile` | class | 用户基本模型 |
705
+ | `RequestContext` | class | 请求上下文 (contextvars) |
706
+ | `get_current_headers` | function | 获取当前上下文 headers |
707
+ | `get_trace_id` | function | 获取当前 trace_id |
708
+
709
+ ### 认证模块 (`fiuai_sdk_python.auth`)
710
+
711
+ | 名称 | 类型 | 说明 |
712
+ |------|------|------|
713
+ | `AuthData` | class | 解析后的认证数据 |
714
+ | `AuthHeader` | class | HTTP 认证头映射 |
715
+ | `parse_auth_headers` | function | 从 dict 解析认证 |
716
+ | `extract_auth_from_request` | function | 从 Request 解析认证 |
717
+ | `init_context` | function | 初始化上下文管理器 |
718
+ | `get_auth_data_from_context` | function | 从上下文获取 AuthData |
719
+ | `ContextManager` | class | 上下文管理器 |
720
+ | `WorldData` | class | World 事件/任务上下文 |
721
+
722
+ ### HTTP 模块 (`fiuai_sdk_python.http`)
723
+
724
+ | 名称 | 类型 | 说明 |
725
+ |------|------|------|
726
+ | `create_http_client` | function | 创建异步 HTTP 客户端 |
727
+ | `create_sync_http_client` | function | 创建同步 HTTP 客户端 |
728
+ | `get_async_http_client` | function | 全局异步客户端单例 |
729
+ | `get_sync_http_client` | function | 全局同步客户端单例 |
730
+ | `close_global_clients` | function | 关闭全局客户端 |
731
+ | `extract_auth_headers` | function | 从上下文提取认证头 |
732
+
733
+ ### 缓存模块 (`fiuai_sdk_python.pkg.cache`)
734
+
735
+ | 名称 | 类型 | 说明 |
736
+ |------|------|------|
737
+ | `redis_manager` | RedisManager | Redis 连接池管理器 (单例) |
738
+ | `RedisDBConfig` | class | Redis 连接配置 |
739
+ | `CacheClient` | class | 通用缓存客户端 |
740
+ | `CacheConfig` | class | 缓存客户端配置 |
741
+ | `init_cache` | function | 初始化默认 CacheClient |
742
+ | `get_default_client` | function | 获取默认 CacheClient |
743
+ | `cached` | decorator | 函数级缓存装饰器 |
744
+ | `CircuitBreaker` | class | 三态熔断器 |
745
+ | `CircuitBreakerConfig` | class | 熔断器配置 |
746
+ | `CircuitState` | enum | 熔断状态枚举 |
747
+
748
+ ### 工具模块 (`fiuai_sdk_python.utils`)
749
+
750
+ | 名称 | 模块 | 说明 |
751
+ |------|------|------|
752
+ | `init_logger` | logger | 初始化日志系统 |
753
+ | `get_logger` | logger | 获取 logger 实例 |
754
+ | `safe_string_name` | text | 全角转半角 |
755
+ | `safe_str` | text | URL 安全编码 |
756
+ | `safe_json_str` | text | JSON 安全处理 |
757
+ | `gen_id` | ids | 生成雪花 ID |
758
+ | `set_custom_instance_id` | ids | 设置自定义实例 ID |
759
+
760
+ ---
761
+
762
+ ## 版本
763
+
764
+ 当前版本: **0.8.1**
765
+
766
+ ## License
767
+
768
+ MIT License - Copyright (c) 2025 FiuAI