api-key-manager 2.1.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.
Files changed (91) hide show
  1. api_key_manager-2.1.0/PKG-INFO +709 -0
  2. api_key_manager-2.1.0/README.md +676 -0
  3. api_key_manager-2.1.0/api_key_manager.egg-info/PKG-INFO +709 -0
  4. api_key_manager-2.1.0/api_key_manager.egg-info/SOURCES.txt +89 -0
  5. api_key_manager-2.1.0/api_key_manager.egg-info/dependency_links.txt +1 -0
  6. api_key_manager-2.1.0/api_key_manager.egg-info/entry_points.txt +2 -0
  7. api_key_manager-2.1.0/api_key_manager.egg-info/requires.txt +13 -0
  8. api_key_manager-2.1.0/api_key_manager.egg-info/top_level.txt +1 -0
  9. api_key_manager-2.1.0/key_manager/__init__.py +16 -0
  10. api_key_manager-2.1.0/key_manager/__main__.py +5 -0
  11. api_key_manager-2.1.0/key_manager/api_models.py +358 -0
  12. api_key_manager-2.1.0/key_manager/checker.py +51 -0
  13. api_key_manager-2.1.0/key_manager/cli.py +270 -0
  14. api_key_manager-2.1.0/key_manager/config.py +61 -0
  15. api_key_manager-2.1.0/key_manager/core.py +205 -0
  16. api_key_manager-2.1.0/key_manager/detector.py +335 -0
  17. api_key_manager-2.1.0/key_manager/errors.py +179 -0
  18. api_key_manager-2.1.0/key_manager/i18n.py +142 -0
  19. api_key_manager-2.1.0/key_manager/logger.py +207 -0
  20. api_key_manager-2.1.0/key_manager/model_capabilities.py +412 -0
  21. api_key_manager-2.1.0/key_manager/parser.py +153 -0
  22. api_key_manager-2.1.0/key_manager/providers/__init__.py +283 -0
  23. api_key_manager-2.1.0/key_manager/providers/ai302.py +109 -0
  24. api_key_manager-2.1.0/key_manager/providers/anthropic.py +109 -0
  25. api_key_manager-2.1.0/key_manager/providers/baichuan.py +97 -0
  26. api_key_manager-2.1.0/key_manager/providers/base.py +312 -0
  27. api_key_manager-2.1.0/key_manager/providers/cerebras.py +109 -0
  28. api_key_manager-2.1.0/key_manager/providers/cohere.py +90 -0
  29. api_key_manager-2.1.0/key_manager/providers/cstcloud.py +122 -0
  30. api_key_manager-2.1.0/key_manager/providers/dashscope.py +120 -0
  31. api_key_manager-2.1.0/key_manager/providers/dashscope_coding.py +122 -0
  32. api_key_manager-2.1.0/key_manager/providers/deepseek.py +166 -0
  33. api_key_manager-2.1.0/key_manager/providers/dmxapi.py +109 -0
  34. api_key_manager-2.1.0/key_manager/providers/doubao.py +109 -0
  35. api_key_manager-2.1.0/key_manager/providers/fireworks.py +109 -0
  36. api_key_manager-2.1.0/key_manager/providers/google.py +99 -0
  37. api_key_manager-2.1.0/key_manager/providers/grok.py +109 -0
  38. api_key_manager-2.1.0/key_manager/providers/groq.py +109 -0
  39. api_key_manager-2.1.0/key_manager/providers/huggingface.py +54 -0
  40. api_key_manager-2.1.0/key_manager/providers/hyperbolic.py +109 -0
  41. api_key_manager-2.1.0/key_manager/providers/infini.py +135 -0
  42. api_key_manager-2.1.0/key_manager/providers/infini_coding.py +124 -0
  43. api_key_manager-2.1.0/key_manager/providers/kimi.py +121 -0
  44. api_key_manager-2.1.0/key_manager/providers/kimi_coding.py +124 -0
  45. api_key_manager-2.1.0/key_manager/providers/longcat.py +123 -0
  46. api_key_manager-2.1.0/key_manager/providers/mimo.py +109 -0
  47. api_key_manager-2.1.0/key_manager/providers/mimo_plan.py +140 -0
  48. api_key_manager-2.1.0/key_manager/providers/minimax.py +97 -0
  49. api_key_manager-2.1.0/key_manager/providers/minimax_plan.py +122 -0
  50. api_key_manager-2.1.0/key_manager/providers/mistral.py +109 -0
  51. api_key_manager-2.1.0/key_manager/providers/models_registry.py +2901 -0
  52. api_key_manager-2.1.0/key_manager/providers/modelscope.py +134 -0
  53. api_key_manager-2.1.0/key_manager/providers/nvidia.py +109 -0
  54. api_key_manager-2.1.0/key_manager/providers/ocoolai.py +109 -0
  55. api_key_manager-2.1.0/key_manager/providers/openai.py +140 -0
  56. api_key_manager-2.1.0/key_manager/providers/openrouter.py +119 -0
  57. api_key_manager-2.1.0/key_manager/providers/perplexity.py +109 -0
  58. api_key_manager-2.1.0/key_manager/providers/poe.py +109 -0
  59. api_key_manager-2.1.0/key_manager/providers/ppio.py +109 -0
  60. api_key_manager-2.1.0/key_manager/providers/replicate.py +54 -0
  61. api_key_manager-2.1.0/key_manager/providers/siliconflow.py +121 -0
  62. api_key_manager-2.1.0/key_manager/providers/stepfun.py +132 -0
  63. api_key_manager-2.1.0/key_manager/providers/tencent_hunyuan.py +122 -0
  64. api_key_manager-2.1.0/key_manager/providers/together.py +134 -0
  65. api_key_manager-2.1.0/key_manager/providers/yi.py +97 -0
  66. api_key_manager-2.1.0/key_manager/providers/zai.py +109 -0
  67. api_key_manager-2.1.0/key_manager/providers/zhipu.py +127 -0
  68. api_key_manager-2.1.0/key_manager/providers/zhipu_coding.py +124 -0
  69. api_key_manager-2.1.0/key_manager/proxy.py +70 -0
  70. api_key_manager-2.1.0/key_manager/ssrf.py +68 -0
  71. api_key_manager-2.1.0/key_manager/storage.py +134 -0
  72. api_key_manager-2.1.0/key_manager/tester.py +137 -0
  73. api_key_manager-2.1.0/key_manager/url_override.py +5 -0
  74. api_key_manager-2.1.0/key_manager/validator.py +185 -0
  75. api_key_manager-2.1.0/key_manager/web.py +1512 -0
  76. api_key_manager-2.1.0/key_manager/webhook.py +257 -0
  77. api_key_manager-2.1.0/pyproject.toml +102 -0
  78. api_key_manager-2.1.0/setup.cfg +4 -0
  79. api_key_manager-2.1.0/tests/test_checker.py +137 -0
  80. api_key_manager-2.1.0/tests/test_detector.py +246 -0
  81. api_key_manager-2.1.0/tests/test_e2e.py +271 -0
  82. api_key_manager-2.1.0/tests/test_errors.py +185 -0
  83. api_key_manager-2.1.0/tests/test_i18n.py +158 -0
  84. api_key_manager-2.1.0/tests/test_openapi.py +237 -0
  85. api_key_manager-2.1.0/tests/test_parser.py +149 -0
  86. api_key_manager-2.1.0/tests/test_provider_detection.py +439 -0
  87. api_key_manager-2.1.0/tests/test_providers.py +55 -0
  88. api_key_manager-2.1.0/tests/test_security.py +124 -0
  89. api_key_manager-2.1.0/tests/test_storage.py +279 -0
  90. api_key_manager-2.1.0/tests/test_validator.py +318 -0
  91. api_key_manager-2.1.0/tests/test_webhook.py +380 -0
@@ -0,0 +1,709 @@
1
+ Metadata-Version: 2.4
2
+ Name: api-key-manager
3
+ Version: 2.1.0
4
+ Summary: Batch manage API keys for 44+ AI providers with CLI and Web interfaces
5
+ Author: Townrain
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Townrain/API-Key-Manager
8
+ Project-URL: Documentation, https://github.com/Townrain/API-Key-Manager#readme
9
+ Project-URL: Repository, https://github.com/Townrain/API-Key-Manager
10
+ Keywords: api-key,ai,openai,anthropic,google,deepseek
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: httpx>=0.27.2
22
+ Requires-Dist: pyyaml>=6.0.2
23
+ Requires-Dist: rich>=13.9.0
24
+ Requires-Dist: fastapi>=0.115.0
25
+ Requires-Dist: uvicorn>=0.32.0
26
+ Requires-Dist: python-multipart>=0.0.9
27
+ Requires-Dist: cryptography>=42.0.0
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
30
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
31
+ Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
32
+ Requires-Dist: ruff>=0.4.0; extra == "dev"
33
+
34
+ # API Key Manager
35
+
36
+ 批量管理 45+ AI 服务商 API 密钥的 Python 工具,支持 CLI 和 Web 两种界面。
37
+
38
+ ## 功能特性
39
+
40
+ - **批量导入** - 从 JSON 文件导入 API 密钥,自动去重
41
+ - **密钥验证** - 并发验证密钥有效性,支持 45+ AI 服务商
42
+ - **能力测试** - 测试 Token 上限和并发能力
43
+ - **模型筛选** - 按类型筛选模型(推理/视觉/联网/免费/嵌入/重排/工具)
44
+ - **智能检测** - 前缀匹配 + 模式匹配 + 错误签名匹配,三级提供商自动识别
45
+ - **Web 界面** - 赛博朋克风格的管理界面
46
+ - **代理支持** - 支持 HTTP/SOCKS 代理
47
+ - **加密存储** - AES-256-GCM 加密存储 API 密钥,随机盐值
48
+ - **安全防护** - 路径遍历防护、SSRF 防护、时序安全认证
49
+ - **API 文档** - Swagger UI 和 Redoc 自动文档
50
+ - **国际化** - 支持中英文错误信息
51
+ - **SDK 支持** - Python 和 TypeScript 客户端库
52
+ - **Webhook 通知** - 事件驱动的 Webhook 通知系统
53
+
54
+ ## 支持的 AI 服务商
55
+
56
+ ### 国际
57
+
58
+ | 服务商 | 前缀 |
59
+ |--------|------|
60
+ | OpenAI | `sk-proj-` |
61
+ | Anthropic | `sk-ant-api03-` |
62
+ | Google Gemini | `AIza` |
63
+ | DeepSeek | `sk-` |
64
+ | Groq | `gsk_` |
65
+ | Mistral | `sk-` |
66
+ | Cohere | `sk-` |
67
+ | Perplexity | `pplx-` |
68
+ | Together AI | `sk-` |
69
+ | Replicate | `r8_` |
70
+ | Hugging Face | `hf_` |
71
+ | Fireworks | `fw_` |
72
+ | OpenRouter | `sk-or-v1-` |
73
+ | Grok (xAI) | `xai-` |
74
+ | Cerebras | `sk-` |
75
+ | NVIDIA | `sk-` |
76
+ | Hyperbolic | `sk-` |
77
+ | Poe | `sk-` |
78
+
79
+ ### 中国
80
+
81
+ | 服务商 | 前缀 | 显示名 |
82
+ |--------|------|--------|
83
+ | DashScope | `sk-sp-` | 阿里百炼 |
84
+ | ModelScope | `ms-` | 魔搭 |
85
+ | Zhipu GLM | `sk-` | 智谱 |
86
+ | Kimi | `sk-` | 月之暗面 |
87
+ | MiniMax | `sk-` | MiniMax |
88
+ | SiliconFlow | `sk-` | 硅基流动 |
89
+ | Baichuan | `sk-` | 百川 |
90
+ | Yi | `sk-` | 零一万物 |
91
+ | StepFun | `sk-` | 阶跃星辰 |
92
+ | Doubao | `sk-` | 豆包 |
93
+ | Infini | `sk-` | 无问芯穹 |
94
+ | MiMo | `sk-` | 小米 |
95
+ | Tencent Hunyuan | `sk-` | 腾讯混元 |
96
+ | CSTCloud | `sk-` | 中算云 |
97
+
98
+ ### 新增服务商
99
+
100
+ | 服务商 | 说明 |
101
+ |--------|------|
102
+ | LongCat | 新增 |
103
+ | AI302 | 新增 |
104
+ | PPIO | 新增 |
105
+ | DMXAPI | 新增 |
106
+ | OCoolAI | 新增 |
107
+ | ZAI | 新增 |
108
+ | MiMo Plan | 计划版 |
109
+ | MiniMax Plan | 计划版 |
110
+ | DashScope Coding | 编程版 |
111
+ | Zhipu Coding | 编程版 |
112
+ | Kimi Coding | 编程版 |
113
+ | Infini Coding | 编程版 |
114
+
115
+ ## 快速开始
116
+
117
+ ### 安装
118
+
119
+ ```bash
120
+ # 克隆项目
121
+ git clone https://github.com/Townrain/API-Key-Manager.git
122
+ cd key
123
+
124
+ # 安装依赖
125
+ pip install -r requirements.txt
126
+
127
+ # 安装开发依赖(含测试工具)
128
+ pip install -e ".[dev]"
129
+ ```
130
+
131
+ ### CLI 使用
132
+
133
+ ```bash
134
+ # 导入密钥
135
+ python main.py import --file data/input/example.json
136
+ python main.py import --dir ./data/input
137
+
138
+ # 验证密钥
139
+ python main.py check
140
+ python main.py check --provider openai
141
+ python main.py check --key sk-xxx
142
+
143
+ # 测试密钥
144
+ python main.py test
145
+ python main.py test --skip-token
146
+ python main.py test --skip-concurrency
147
+
148
+ # 列出密钥
149
+ python main.py list --provider anthropic --status valid
150
+ python main.py list --status invalid
151
+
152
+ # 生成报告
153
+ python main.py report --days 7
154
+ ```
155
+
156
+ ### Web 界面
157
+
158
+ ```bash
159
+ # 启动 Web 服务器
160
+ python web.py
161
+
162
+ # 访问以下地址:
163
+ # 主界面:http://localhost:18001
164
+ # API 文档:http://localhost:18001/docs
165
+ # Redoc:http://localhost:18001/redoc
166
+ ```
167
+
168
+ ## 安全特性
169
+
170
+ ### 加密存储
171
+
172
+ API 密钥默认使用 AES-256-GCM 加密存储,每次加密使用随机盐值:
173
+
174
+ ```bash
175
+ # 设置加密密钥(环境变量)
176
+ set KEY_MANAGER_SECRET=your-secret-key
177
+
178
+ # 启动服务
179
+ python web.py
180
+ ```
181
+
182
+ 加密后的 `keys.json` 格式:
183
+ ```json
184
+ {
185
+ "encrypted": true,
186
+ "salt": "base64-encoded-random-salt",
187
+ "nonce": "base64-encoded-nonce",
188
+ "data": "base64-encoded-ciphertext"
189
+ }
190
+ ```
191
+
192
+ ### 安全防护
193
+
194
+ - **路径遍历防护** - 导入端点验证路径在允许目录内
195
+ - **SSRF 防护** - `custom_base_url` 验证域名白名单,阻止私有 IP
196
+ - **时序安全认证** - 使用 `hmac.compare_digest()` 防止时序攻击
197
+ - **认证警告** - 未配置 API Key 时启动警告
198
+ - **密钥掩码** - API 响应中只返回 `key_masked`,不暴露完整密钥
199
+
200
+ ### API 认证
201
+
202
+ ```bash
203
+ # 设置 API Key(环境变量)
204
+ set KEY_MANAGER_API_KEY=your-api-key
205
+
206
+ # 或在 config.yaml 中配置
207
+ # auth:
208
+ # api_key: "your-api-key"
209
+ ```
210
+
211
+ ## 提供商智能检测
212
+
213
+ ### 检测策略
214
+
215
+ 系统采用**全并发探测**策略,自动识别 45+ 个 AI 服务商的 API 密钥。
216
+
217
+ #### 检测流程
218
+
219
+ ```
220
+ 1. 模式匹配 - 检查唯一前缀(如 sk-proj- → OpenAI,AIza → Google)
221
+ 2. 格式匹配 - 检查特殊格式(如智谱的 {id}.{secret} 格式)
222
+ 3. 全并发探测 - 同时向所有服务商发送请求(40+ 服务商 × 5 模型 = 200+ 请求)
223
+ 4. 签名匹配 - 如果无200响应,通过错误响应体签名识别服务商
224
+ ```
225
+
226
+ #### 全并发探测逻辑
227
+
228
+ 当密钥无法通过前缀或格式识别时,系统会:
229
+
230
+ 1. 从 Cherry Studio 同步的模型列表中获取每个服务商的前5个模型
231
+ 2. 并发向所有服务商发送请求(每个服务商尝试5个模型)
232
+ 3. 第一个返回200的服务商立即胜出
233
+ 4. 如果所有请求都失败,通过签名匹配识别
234
+
235
+ ```python
236
+ # 检测流程示例
237
+ async def detect_provider(client, key):
238
+ # Step 1: 模式匹配
239
+ pattern_match = detect_by_pattern(key) # 如 sk-proj- → OpenAI
240
+ if pattern_match:
241
+ return pattern_match
242
+
243
+ # Step 2: 格式匹配
244
+ format_candidates = detect_by_format(key) # 如 {id}.{secret} → 智谱/Z.AI
245
+ if format_candidates:
246
+ return format_candidates[0]
247
+
248
+ # Step 3: 全并发探测
249
+ tasks = []
250
+ for name, provider in PROVIDERS.items():
251
+ models = PROVIDER_MODELS.get(name, [])[:5]
252
+ for model in models:
253
+ tasks.append(try_model(name, model))
254
+
255
+ # 第一个返回200的胜出
256
+ for coro in asyncio.as_completed(tasks):
257
+ name, valid, body = await coro
258
+ if valid:
259
+ return name
260
+
261
+ # Step 4: 签名匹配
262
+ return match_by_signature(error_bodies)
263
+ ```
264
+
265
+ ### 特殊密钥格式支持
266
+
267
+ #### 智谱/Z.AI 密钥格式
268
+
269
+ 智谱和 Z.AI 使用 `{id}.{secret}` 格式的密钥(非 `sk-` 开头):
270
+
271
+ ```python
272
+ # 示例密钥格式
273
+ 50bcde33b8774aa8a2cc1bd6d39444ae.ifriyNWRLStzpLEs
274
+
275
+ # 正则表达式匹配
276
+ ZHIPU_KEY_PATTERN = re.compile(r'^[a-zA-Z0-9]{20,50}\.[a-zA-Z0-9]{10,50}$')
277
+ ```
278
+
279
+ 这种格式的密钥会被自动识别为智谱或 Z.AI(两者共享相同的 GLM 模型)。
280
+
281
+ ### 错误签名匹配
282
+
283
+ 当所有并发请求都失败时,系统通过错误响应体中的关键词识别服务商:
284
+
285
+ ```python
286
+ UNIQUE_SIGNATURES = {
287
+ # 国内服务商
288
+ "dashscope": ["model-studio", "modelstudio", "apikey-error"],
289
+ "tencent-hunyuan": ["hunyuan", "console.cloud.tencent.com"],
290
+ "baichuan": ["baichuan-ai.com", "platform.baichuan-ai.com"],
291
+ "minimax": ["authorized_error", "login fail"],
292
+ "yi": ["illegal apikey"],
293
+ "kimi": ["invalid_authentication_error"],
294
+ "siliconflow": ["api key is invalid"],
295
+ "stepfun": ["incorrect api key provided", "invalid_api_key"],
296
+ "doubao": ["authenticationerror"],
297
+ "infini": ["请使用正确的api key进行请求"],
298
+ "zhipu": ["令牌已过期或验证不正确"],
299
+ "mimo": ["invalid api key", "please provide valid api key"],
300
+ # 国外服务商
301
+ "deepseek": ["authentication fails"],
302
+ "anthropic": ["request not allowed", "anthropic", "x-api-key"],
303
+ "openrouter": ["missing authentication header"],
304
+ "mistral": ["mistral", "la plateforme"],
305
+ "replicate": ["unauthenticated", "you did not pass a valid authentication token"],
306
+ "huggingface": ["huggingface", "hf_"],
307
+ "fireworks": ["fireworks", "accounts/fireworks"],
308
+ "perplexity": ["perplexity"],
309
+ "grok": ["console.x.ai"],
310
+ "openai": ["platform.openai.com"],
311
+ "google": ["generativelanguage"],
312
+ "groq": ["groq"],
313
+ }
314
+ ```
315
+
316
+ #### 签名匹配算法
317
+
318
+ ```python
319
+ def score_provider(provider_name, error_body, status_code):
320
+ body = error_body.lower()
321
+ score = 0
322
+ weight = 100 # 每个匹配的签名加100分
323
+
324
+ for sig in UNIQUE_SIGNATURES.get(provider_name, []):
325
+ if sig.lower() in body:
326
+ score += weight
327
+
328
+ return score
329
+
330
+ # 匹配阈值:至少2个签名匹配(200分)才返回结果
331
+ if best_score >= 200:
332
+ return best_name
333
+ ```
334
+
335
+ ### 检测优先级
336
+
337
+ | 优先级 | 方法 | 说明 |
338
+ ||------||------|
339
+ | 1 | 模式匹配 | 唯一前缀,如 `sk-proj-` → OpenAI |
340
+ | 2 | 格式匹配 | 特殊格式,如 `{id}.{secret}` → 智谱 |
341
+ | 3 | 全并发探测 | 第一个返回200的服务商胜出 |
342
+ | 4 | 签名匹配 | 通过错误响应体识别,需至少2个签名匹配 |
343
+
344
+
345
+ ## 错误信息简化
346
+
347
+ 系统会自动将服务商返回的原始错误信息简化为用户友好的提示:
348
+
349
+ | 原始错误信息 | 简化后 |
350
+ |-------------|--------|
351
+ | `Access denied, please make sure your account is in good standing...` | 余额不足 |
352
+ | `Invalid API Key` | Key 无效 |
353
+ | `Authentication fails` | 认证失败 |
354
+ | `Token expired` | Key 已过期 |
355
+ | `Rate limit exceeded` | 请求过于频繁 |
356
+ | `Account suspended` | 账号被封禁 |
357
+ | `Access denied` | 无权限访问 |
358
+ | `Model does not exist` | 模型不存在 |
359
+
360
+ 错误信息简化在 `base.py` 的 `simplify_error()` 函数中实现,支持:
361
+
362
+ - 基于状态码的简化(401 → Key 无效,402 → 余额不足,429 → 请求过于频繁)
363
+ - 基于关键词的模式匹配(authentication、expired、rate limit 等)
364
+ - 长错误信息截断(超过100字符时截断并添加省略号)
365
+
366
+ ## 项目结构
367
+
368
+
369
+ ## 模型检测
370
+
371
+ ### 模型列表来源
372
+
373
+ 系统从 Cherry Studio 同步模型数据,生成 `models_registry.py` 文件,包含每个服务商的静态模型列表:
374
+
375
+ ```python
376
+ PROVIDER_MODELS = {
377
+ "openai": ["gpt-4o", "gpt-4o-mini", "gpt-3.5-turbo", ...],
378
+ "anthropic": ["claude-3-opus", "claude-3-sonnet", ...],
379
+ "dashscope": ["qwen-turbo", "qwen-plus", "qwen-max", ...],
380
+ "siliconflow": ["Qwen/Qwen2.5-7B-Instruct", ...],
381
+ # ... 45+ 服务商
382
+ }
383
+ ```
384
+
385
+ ### 模型检测流程
386
+
387
+ 当用户点击「检测可用模型」时:
388
+
389
+ 1. 获取服务商的模型列表(优先使用 API 返回,回退到静态列表)
390
+ 2. 并发检测每个模型的可用性(batch_size 动态调整)
391
+ 3. 每个模型发送一个最小请求(`POST /chat/completions`,`max_tokens: 5`)
392
+ 4. 返回200的模型标记为可用,其他标记为失败
393
+ 5. 失败的模型会串行重试(最多2次)
394
+
395
+ ```python
396
+ # 模型检测逻辑
397
+ async def check_model(http, model):
398
+ resp = await client.post(
399
+ f"{provider.get_base_url()}/chat/completions",
400
+ json={"model": model, "messages": [...], "max_tokens": 5}
401
+ )
402
+ return model, 200 if resp.status_code == 200 else resp.status_code
403
+
404
+ # 动态并发控制
405
+ batch_size = 5 # 初始并发数
406
+ for i in range(0, len(models), batch_size):
407
+ batch = models[i:i+batch_size]
408
+ results = await asyncio.gather(*[check_model(http, m) for m in batch])
409
+
410
+ # 全部成功 → 并发数 +1
411
+ if all_success:
412
+ batch_size += 1
413
+ # 有失败 → 保持当前并发数
414
+
415
+ # 失败模型串行重试
416
+ for model in failed_models:
417
+ _, code = await check_model(http, model)
418
+ if code == 200:
419
+ # 重试成功
420
+ ```
421
+
422
+ ### 模型能力检测
423
+
424
+ 系统支持按类型筛选模型:
425
+
426
+ | 类型 | 说明 | 筛选方法 |
427
+ |------|------|----------|
428
+ | 视觉模型 | 支持图像输入 | `is_vision_model()` |
429
+ | 工具模型 | 支持函数调用 | `is_tool_model()` |
430
+ | 推理模型 | 支持思维链 | `is_reasoning_model()` |
431
+ | 联网模型 | 支持网络搜索 | `is_websearch_model()` |
432
+ | 免费模型 | 免费额度 | `is_free_model()` |
433
+ | 嵌入模型 | 文本嵌入 | `is_embedding_model()` |
434
+ | 重排模型 | 搜索重排 | `is_rerank_model()` |
435
+
436
+ 能力数据从 Cherry Studio 同步,存储在 `data/model_capabilities.json` 中。
437
+
438
+ ## 项目结构
439
+ ```
440
+ key/
441
+ ├── key_manager/ # 核心包
442
+ │ ├── __init__.py # 包导出
443
+ │ ├── cli.py # CLI 入口
444
+ │ ├── web.py # FastAPI 应用
445
+ │ ├── config.py # 配置加载
446
+ │ ├── storage.py # AES-256-GCM 加密存储
447
+ │ ├── errors.py # 结构化错误码
448
+ │ ├── api_models.py # Pydantic 模型
449
+ │ ├── parser.py # JSON 导入 + 路径验证
450
+ │ ├── detector.py # 智能提供商检测
451
+ │ ├── validator.py # 并发验证引擎
452
+ │ ├── checker.py # 重试包装器
453
+ │ ├── tester.py # 能力测试
454
+ │ ├── ssrf.py # SSRF 防护
455
+ │ ├── logger.py # 日志系统
456
+ │ ├── proxy.py # 代理检测
457
+ │ ├── webhook.py # Webhook 通知
458
+ │ ├── i18n.py # 国际化
459
+ │ ├── model_capabilities.py # 模型能力检测
460
+ │ └── providers/ # 45+ 提供商实现
461
+ │ ├── __init__.py # 注册表
462
+ │ ├── base.py # ABC 接口
463
+ │ ├── openai.py # OpenAI
464
+ │ ├── anthropic.py # Anthropic
465
+ │ └── ... # 更多提供商
466
+ ├── tests/ # 测试套件
467
+ │ ├── test_detector.py # 提供商检测测试
468
+ │ ├── test_parser.py # 解析器测试
469
+ │ ├── test_validator.py # 验证器测试
470
+ │ ├── test_checker.py # 检查器测试
471
+ │ ├── test_providers.py # 提供商合约测试
472
+ │ ├── test_security.py # 安全回归测试
473
+ │ ├── test_storage.py # 加密存储测试
474
+ │ ├── test_errors.py # 错误系统测试
475
+ │ ├── test_i18n.py # 国际化测试
476
+ │ ├── test_e2e.py # 端到端测试
477
+ │ └── test_webhook.py # Webhook 测试
478
+ ├── sdk/ # SDK
479
+ │ ├── python/ # Python SDK
480
+ │ └── typescript/ # TypeScript SDK
481
+ ├── config.yaml # 配置文件
482
+ ├── pyproject.toml # 项目配置
483
+ ├── main.py # CLI 入口
484
+ └── web.py # Web 入口
485
+ ```
486
+
487
+ ## 配置说明
488
+
489
+ 编辑 `config.yaml`:
490
+
491
+ ```yaml
492
+ # 代理设置
493
+ proxy: "http://127.0.0.1:7890" # 或 socks5://127.0.0.1:7890
494
+
495
+ # 验证设置
496
+ check:
497
+ concurrency: 100 # 并发数
498
+ timeout_seconds: 30 # 超时时间
499
+ retry_failed: true # 失败重试
500
+ retry_count: 2 # 重试次数
501
+
502
+ # 测试设置
503
+ test:
504
+ token_steps:
505
+ - 1024
506
+ - 4096
507
+ - 16384
508
+ - 65536
509
+ concurrency_steps:
510
+ - 1
511
+ - 5
512
+ - 10
513
+ - 20
514
+
515
+ # 认证设置
516
+ auth:
517
+ api_key: "your-secret-api-key" # API 认证
518
+
519
+ # 速率限制
520
+ rate_limit:
521
+ requests_per_minute: 60
522
+ ```
523
+
524
+ ## API 端点
525
+
526
+ | 方法 | 端点 | 说明 |
527
+ |------|------|------|
528
+ | GET | `/api/keys` | 获取密钥列表 |
529
+ | GET | `/api/keys/export` | 导出有效密钥 |
530
+ | POST | `/api/import` | 导入密钥 |
531
+ | POST | `/api/import/upload` | 上传 JSON 文件导入 |
532
+ | POST | `/api/check/single` | 验证单个密钥 |
533
+ | POST | `/api/check/batch` | 批量验证 |
534
+ | POST | `/api/test/single` | 测试单个密钥 |
535
+ | POST | `/api/test/token` | 测试 Token 上限 |
536
+ | POST | `/api/test/concurrency` | 测试并发能力 |
537
+ | GET | `/api/models` | 获取模型列表 |
538
+ | POST | `/api/models/check` | 检测可用模型(SSE 流) |
539
+ | GET | `/api/providers` | 获取服务商列表 |
540
+ | GET | `/api/stats` | 获取统计信息 |
541
+ | GET | `/api/logs` | 获取日志 |
542
+ | POST | `/api/webhooks` | 创建 Webhook |
543
+ | GET | `/docs` | Swagger UI 文档 |
544
+ | GET | `/redoc` | Redoc 文档 |
545
+
546
+ ## Webhook 使用
547
+
548
+ ### 支持的事件类型
549
+
550
+ | 事件 | 说明 |
551
+ |------|------|
552
+ | `key.imported` | 密钥导入完成 |
553
+ | `key.checked` | 密钥验证完成 |
554
+ | `key.tested` | 密钥测试完成 |
555
+ | `key.deleted` | 密钥删除 |
556
+ | `batch.check.completed` | 批量验证完成 |
557
+ | `batch.test.completed` | 批量测试完成 |
558
+ | `error.occurred` | 发生错误 |
559
+
560
+ ### 配置 Webhook
561
+
562
+ ```yaml
563
+ webhooks:
564
+ - url: "https://example.com/webhook"
565
+ events:
566
+ - "key.imported"
567
+ - "key.checked"
568
+ secret: "your-webhook-secret" # HMAC-SHA256 签名
569
+ active: true
570
+ max_retries: 3
571
+ ```
572
+
573
+ ### 签名验证
574
+
575
+ ```python
576
+ import hmac
577
+ import hashlib
578
+ import json
579
+
580
+ def verify_signature(payload, secret, signature):
581
+ body = json.dumps(payload, separators=(",", ":"), sort_keys=True)
582
+ expected = hmac.new(
583
+ secret.encode("utf-8"),
584
+ body.encode("utf-8"),
585
+ hashlib.sha256,
586
+ ).hexdigest()
587
+ return signature == f"sha256={expected}"
588
+ ```
589
+
590
+ ## 测试
591
+
592
+ ```bash
593
+ # 运行所有测试
594
+ python -m pytest tests/ -v
595
+
596
+ # 运行特定测试
597
+ python -m pytest tests/test_security.py -v
598
+ python -m pytest tests/test_detector.py -v
599
+
600
+ # 运行测试并查看覆盖率
601
+ python -m pytest tests/ --cov=key_manager --cov-report=term-missing
602
+ ```
603
+
604
+ ### 测试覆盖
605
+
606
+ | 模块 | 测试文件 | 测试数 |
607
+ |------|---------|--------|
608
+ | 提供商检测 | `test_detector.py` | 54 |
609
+ | 密钥解析 | `test_parser.py` | 12 |
610
+ | 验证器 | `test_validator.py` | 5 |
611
+ | 检查器 | `test_checker.py` | 4 |
612
+ | 提供商合约 | `test_providers.py` | 30 |
613
+ | 安全回归 | `test_security.py` | 12 |
614
+ | 加密存储 | `test_storage.py` | 26 |
615
+ | 错误系统 | `test_errors.py` | 28 |
616
+ | 国际化 | `test_i18n.py` | 37 |
617
+ | 端到端 | `test_e2e.py` | 17 |
618
+ | Webhook | `test_webhook.py` | 35 |
619
+ | OpenAPI | `test_openapi.py` | 26 |
620
+
621
+ ## SDK 使用
622
+
623
+ ### Python SDK
624
+
625
+ ```bash
626
+ cd sdk/python
627
+ pip install -e .
628
+ ```
629
+
630
+ ```python
631
+ from key_manager_sdk import KeyManagerClient
632
+
633
+ client = KeyManagerClient(base_url="http://localhost:18001")
634
+
635
+ # 获取密钥列表
636
+ keys = client.get_keys()
637
+
638
+ # 验证单个密钥
639
+ result = client.check_single_key(key="sk-xxx", provider="openai")
640
+ ```
641
+
642
+ ### TypeScript SDK
643
+
644
+ ```bash
645
+ cd sdk/typescript
646
+ npm install
647
+ ```
648
+
649
+ ```typescript
650
+ npm install @api-key-manager/sdk
651
+
652
+ const client = new KeyManagerClient({ baseUrl: 'http://localhost:18001' });
653
+
654
+ // 获取密钥列表
655
+ const keys = await client.getKeys();
656
+
657
+ // 验证单个密钥
658
+ const result = await client.checkSingleKey({ key: 'sk-xxx', provider: 'openai' });
659
+ ```
660
+
661
+ ## 依赖
662
+
663
+ - Python 3.10+
664
+ - httpx - 异步 HTTP 客户端
665
+ - FastAPI - Web 框架
666
+ - uvicorn - ASGI 服务器
667
+ - PyYAML - 配置解析
668
+ - Rich - 终端美化
669
+ - cryptography - 加密存储
670
+ - pydantic - 数据验证
671
+
672
+ ## 已知问题和限制
673
+
674
+ ### 1. 中转站服务商误识别
675
+
676
+ 由于某些中转站服务商(如 Z.AI、DMXAPI、OCoolAI 等)使用与原厂相同的 API 端点和模型,当密钥无效时,错误响应可能包含原厂的签名关键词,导致误识别。
677
+
678
+ 例如:一个硅基流动的密钥,如果被发送到阿里百炼的端点,阿里百炼会返回包含 "model-studio" 和 "apikey-error" 的错误响应,这可能导致系统误认为该密钥是阿里百炼的。
679
+
680
+ **解决方案**:系统要求至少2个签名匹配(200分)才返回识别结果,以减少误报。
681
+
682
+ ### 2. 签名匹配的局限性
683
+
684
+ 签名匹配依赖于服务商返回的错误响应体中的关键词。如果服务商更改了错误消息格式,签名可能失效。
685
+
686
+ **建议**:定期运行 `verify_signatures.py` 脚本验证签名的有效性。
687
+
688
+ ### 3. 并发检测的超时问题
689
+
690
+ 全并发探测时,某些服务商可能响应较慢(超过10秒超时)。这可能导致有效的服务商被跳过。
691
+
692
+ **解决方案**:系统会对失败的模型进行串行重试(最多2次)。
693
+
694
+ ### 4. 智谱/Z.AI 密钥的双重检测
695
+
696
+ 智谱和 Z.AI 使用相同的 GLM 模型和 API 格式,但使用不同的 Base URL:
697
+
698
+ - 智谱:`https://open.bigmodel.cn/api/paas/v4`
699
+ - Z.AI:`https://api.z.ai/api/paas/v4`
700
+
701
+ 同一个密钥可能在两个平台都能工作,系统会返回第一个响应200的服务商。
702
+
703
+ ### 5. 模型列表的时效性
704
+
705
+ 模型列表从 Cherry Studio 同步,每日更新一次。新发布的模型可能需要等待同步后才能被检测到。
706
+
707
+ ## 许可证
708
+
709
+ MIT License