@xinizai/pi-image-gen 0.1.0
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.
- package/README.md +337 -0
- package/dist/core/cache.d.ts +11 -0
- package/dist/core/cache.js +42 -0
- package/dist/core/cache.js.map +1 -0
- package/dist/core/capabilities.d.ts +2 -0
- package/dist/core/capabilities.js +65 -0
- package/dist/core/capabilities.js.map +1 -0
- package/dist/core/errors.d.ts +11 -0
- package/dist/core/errors.js +71 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/global-config.d.ts +25 -0
- package/dist/core/global-config.js +172 -0
- package/dist/core/global-config.js.map +1 -0
- package/dist/core/image-service.d.ts +14 -0
- package/dist/core/image-service.js +42 -0
- package/dist/core/image-service.js.map +1 -0
- package/dist/core/model-browser.d.ts +5 -0
- package/dist/core/model-browser.js +76 -0
- package/dist/core/model-browser.js.map +1 -0
- package/dist/core/model-registry.d.ts +10 -0
- package/dist/core/model-registry.js +44 -0
- package/dist/core/model-registry.js.map +1 -0
- package/dist/core/provider.d.ts +2 -0
- package/dist/core/provider.js +8 -0
- package/dist/core/provider.js.map +1 -0
- package/dist/core/types.d.ts +122 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +490 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/openai-compatible.d.ts +16 -0
- package/dist/providers/openai-compatible.js +216 -0
- package/dist/providers/openai-compatible.js.map +1 -0
- package/dist/tools/shared.d.ts +42 -0
- package/dist/tools/shared.js +241 -0
- package/dist/tools/shared.js.map +1 -0
- package/dist/utils/config.d.ts +5 -0
- package/dist/utils/config.js +65 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/download.d.ts +8 -0
- package/dist/utils/download.js +139 -0
- package/dist/utils/download.js.map +1 -0
- package/dist/utils/files.d.ts +18 -0
- package/dist/utils/files.js +83 -0
- package/dist/utils/files.js.map +1 -0
- package/package.json +34 -0
- package/src/core/cache.ts +43 -0
- package/src/core/capabilities.ts +55 -0
- package/src/core/errors.ts +92 -0
- package/src/core/global-config.ts +167 -0
- package/src/core/image-service.ts +40 -0
- package/src/core/model-browser.ts +73 -0
- package/src/core/model-registry.ts +43 -0
- package/src/core/provider.ts +8 -0
- package/src/core/types.ts +135 -0
- package/src/index.ts +394 -0
- package/src/providers/openai-compatible.ts +198 -0
- package/src/tools/shared.ts +235 -0
- package/src/utils/config.ts +61 -0
- package/src/utils/download.ts +103 -0
- package/src/utils/files.ts +78 -0
package/README.md
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# pi-image-gen
|
|
2
|
+
|
|
3
|
+
一个通用 Pi Agent 图片生成扩展。用户只配置 `IMAGE_BASE_URL` 和 `IMAGE_API_KEY`,扩展会尽可能自动探测 OpenAI-compatible API、发现模型、识别模型能力,并向 Pi Agent 注册图片生成/编辑/变体工具。
|
|
4
|
+
|
|
5
|
+
> 第一版重点支持 OpenAI-compatible API:`GET /models`、`POST /images/generations`、`POST /images/edits`、`POST /images/variations`。其它 Provider 通过 Adapter 架构预留。
|
|
6
|
+
|
|
7
|
+
## 功能
|
|
8
|
+
|
|
9
|
+
- 通过唯一用户入口 `/image-config` 管理多个跨项目共享的 Provider(环境变量仍可作为兼容 fallback)
|
|
10
|
+
- 有限、安全地探测 `GET /models`
|
|
11
|
+
- 自动识别模型能力:`image_generation`、`image_edit`、`image_variation`、`vision`、`text`、`unknown`
|
|
12
|
+
- 模型发现缓存,默认 10 分钟
|
|
13
|
+
- 自动选择稳定默认图片模型
|
|
14
|
+
- 支持 base64 和 URL 图片响应,统一保存为本地文件
|
|
15
|
+
- 图片保存目录默认:`~/.pi/agent/generated/`
|
|
16
|
+
- 不把 API Key 返回给 Agent 或写入输出
|
|
17
|
+
- 注册 Pi Tools:`image_generate`、`image_edit`、`image_variation`、`image_models`、`image_config`、`image_providers`
|
|
18
|
+
- 唯一面向用户的 Slash Command:`/image-config`
|
|
19
|
+
|
|
20
|
+
## 安装
|
|
21
|
+
|
|
22
|
+
开发目录中:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install
|
|
26
|
+
npm run build
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
作为 Pi package 安装时,`package.json` 已声明:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"pi": {
|
|
34
|
+
"extensions": ["./dist/index.js"]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
也可以在当前项目直接使用 `.pi/extensions/pi-image-gen.ts` 开发入口,然后在 Pi 中 `/reload`。
|
|
40
|
+
|
|
41
|
+
## 配置
|
|
42
|
+
|
|
43
|
+
## 配置入口
|
|
44
|
+
|
|
45
|
+
在 Pi 中运行:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
/image-config
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
即可添加 Provider、测试 `/models`、选择默认图片模型、设置默认 Provider,以及设置图片响应格式(自动兼容、URL、Base64 JSON)。配置跨项目保存在:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
~/.pi/agent/pi-image-gen/providers.json
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
最小环境变量配置(无全局 Provider 时的兼容 fallback):
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
export IMAGE_BASE_URL=https://example.com/v1
|
|
61
|
+
export IMAGE_API_KEY=sk-xxxx
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Windows PowerShell:
|
|
65
|
+
|
|
66
|
+
```powershell
|
|
67
|
+
$env:IMAGE_BASE_URL="https://example.com/v1"
|
|
68
|
+
$env:IMAGE_API_KEY="sk-xxxx"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
可选配置:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
export IMAGE_MODEL=gpt-image-1 # fallback 或显式默认文生图模型
|
|
75
|
+
export IMAGE_EDIT_MODEL=gpt-image-1 # 默认编辑模型
|
|
76
|
+
export IMAGE_VARIATION_MODEL=dall-e-2 # 默认变体模型
|
|
77
|
+
export IMAGE_TIMEOUT_SECONDS=60
|
|
78
|
+
export IMAGE_CACHE_TTL_SECONDS=600
|
|
79
|
+
export IMAGE_OUTPUT_DIR=/path/to/generated
|
|
80
|
+
export IMAGE_MAX_RESPONSE_BYTES=8000000
|
|
81
|
+
export IMAGE_MAX_DOWNLOAD_BYTES=25000000
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
手动声明模型能力(当 API 无法自动识别时):
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
export IMAGE_MODEL_CAPABILITIES="my-model:image_generation,image_edit;other-model:vision"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## API URL
|
|
91
|
+
|
|
92
|
+
`IMAGE_BASE_URL` 应指向 API 版本根路径,例如:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
https://api.example.com/v1
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
扩展只会针对该 Base URL 进行有限兼容探测:当前仅尝试 `GET /models`。不会扫描端口、不会递归探测大量 URL。
|
|
99
|
+
|
|
100
|
+
## 自动发现模型
|
|
101
|
+
|
|
102
|
+
启动后或首次调用工具时:
|
|
103
|
+
|
|
104
|
+
1. 读取 Base URL 与 API Key
|
|
105
|
+
2. 调用 `GET {IMAGE_BASE_URL}/models`
|
|
106
|
+
3. 解析 `data[]`
|
|
107
|
+
4. 优先使用 API metadata 中的能力字段
|
|
108
|
+
5. 如果没有 metadata,则使用模型 ID 和 metadata 做启发式候选识别
|
|
109
|
+
6. 写入缓存 `~/.pi/agent/image-gen-cache.json`
|
|
110
|
+
|
|
111
|
+
如果 `/models` 不存在:
|
|
112
|
+
|
|
113
|
+
- 若设置了 `IMAGE_MODEL`,会把它作为 fallback 模型;
|
|
114
|
+
- 否则明确报错,并提示配置 `IMAGE_MODEL`。
|
|
115
|
+
|
|
116
|
+
## 模型能力识别
|
|
117
|
+
|
|
118
|
+
能力类型:
|
|
119
|
+
|
|
120
|
+
- `text`
|
|
121
|
+
- `vision`
|
|
122
|
+
- `image_generation`
|
|
123
|
+
- `image_edit`
|
|
124
|
+
- `image_variation`
|
|
125
|
+
- `unknown`
|
|
126
|
+
|
|
127
|
+
识别优先级:
|
|
128
|
+
|
|
129
|
+
1. 用户手动声明:`IMAGE_MODEL_CAPABILITIES`
|
|
130
|
+
2. API 返回 metadata:`capabilities`、`modalities`、`input_modalities`、`output_modalities` 等
|
|
131
|
+
3. 启发式识别:模型名包含 `image`、`img`、`dall-e`、`gpt-image`、`flux`、`stable-diffusion` 等
|
|
132
|
+
4. 无法确认则标记为 `unknown`
|
|
133
|
+
|
|
134
|
+
启发式识别只表示候选,不保证 100% 正确。扩展不会默认发送真实付费生图请求来验证能力。
|
|
135
|
+
|
|
136
|
+
## 查看模型
|
|
137
|
+
|
|
138
|
+
普通用户请在 Pi 中运行 `/image-config` 后进入 Provider 的“选择默认图片模型”。
|
|
139
|
+
|
|
140
|
+
Agent 仍可调用工具:
|
|
141
|
+
|
|
142
|
+
```text
|
|
143
|
+
image_models({ "refresh": true })
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
输出按能力分组:
|
|
147
|
+
|
|
148
|
+
```text
|
|
149
|
+
Image Generation:
|
|
150
|
+
- model-a
|
|
151
|
+
- model-b
|
|
152
|
+
|
|
153
|
+
Vision:
|
|
154
|
+
- model-c
|
|
155
|
+
|
|
156
|
+
Text:
|
|
157
|
+
- model-d
|
|
158
|
+
|
|
159
|
+
Unknown:
|
|
160
|
+
- model-e
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## 文生图
|
|
164
|
+
|
|
165
|
+
用户可以直接说:
|
|
166
|
+
|
|
167
|
+
```text
|
|
168
|
+
生成一张赛博朋克东京街头,16:9。
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Agent 应调用:
|
|
172
|
+
|
|
173
|
+
```text
|
|
174
|
+
image_generate({
|
|
175
|
+
"prompt": "赛博朋克东京街头",
|
|
176
|
+
"aspect_ratio": "16:9"
|
|
177
|
+
})
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
参数:
|
|
181
|
+
|
|
182
|
+
- `prompt` 必填
|
|
183
|
+
- `model` 可选,默认自动选择
|
|
184
|
+
- `size` 可选,例如 `1024x1024`
|
|
185
|
+
- `aspect_ratio` 可选,例如 `16:9`
|
|
186
|
+
- `quality` 可选
|
|
187
|
+
- `output_format` 可选:`png`、`jpeg`、`jpg`、`webp`
|
|
188
|
+
- `n` 可选
|
|
189
|
+
|
|
190
|
+
## 图片编辑
|
|
191
|
+
|
|
192
|
+
工具:`image_edit`
|
|
193
|
+
|
|
194
|
+
参数:
|
|
195
|
+
|
|
196
|
+
- `image`:Windows 本地路径、Linux 本地路径、`file://`、`https://`
|
|
197
|
+
- `prompt`
|
|
198
|
+
- `model?`
|
|
199
|
+
- `size?`
|
|
200
|
+
- `output_format?`
|
|
201
|
+
|
|
202
|
+
支持输入格式:`.png`、`.jpg`、`.jpeg`、`.webp`。
|
|
203
|
+
|
|
204
|
+
如果没有发现支持 `image_edit` 的模型,会明确报错,而不是伪造成功。
|
|
205
|
+
|
|
206
|
+
## 图片变体
|
|
207
|
+
|
|
208
|
+
工具:`image_variation`
|
|
209
|
+
|
|
210
|
+
参数:
|
|
211
|
+
|
|
212
|
+
- `image`
|
|
213
|
+
- `model?`
|
|
214
|
+
- `size?`
|
|
215
|
+
- `n?`
|
|
216
|
+
|
|
217
|
+
需要模型具备 `image_variation` 能力。
|
|
218
|
+
|
|
219
|
+
## 缓存
|
|
220
|
+
|
|
221
|
+
模型发现缓存默认有效期 10 分钟。
|
|
222
|
+
|
|
223
|
+
缓存按 Provider 隔离,位于:
|
|
224
|
+
|
|
225
|
+
```text
|
|
226
|
+
~/.pi/agent/pi-image-gen/cache/providers/{providerId}.json
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
缓存包含 Base URL、Provider type、模型、能力和发现时间;不保存 API Key 明文。缓存 key 使用 Provider ID、Provider type、Base URL 与 API Key 指纹,API Key 或 Base URL 变化会自动失效。
|
|
230
|
+
|
|
231
|
+
刷新模型、浏览模型和管理 Provider 都在:
|
|
232
|
+
|
|
233
|
+
```text
|
|
234
|
+
/image-config
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## 安全策略
|
|
238
|
+
|
|
239
|
+
- 不打印完整 API Key
|
|
240
|
+
- 不返回 Authorization Header
|
|
241
|
+
- 请求有 timeout
|
|
242
|
+
- API 响应大小有限制
|
|
243
|
+
- 图片下载大小有限制
|
|
244
|
+
- 只支持 http/https 图片 URL
|
|
245
|
+
- 不执行图片文件
|
|
246
|
+
- 不使用 eval
|
|
247
|
+
- 不执行用户输入
|
|
248
|
+
- 不进行端口扫描或大范围 API 探测
|
|
249
|
+
|
|
250
|
+
## 添加 Provider
|
|
251
|
+
|
|
252
|
+
核心接口在 `src/core/types.ts`:
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
interface ImageProvider {
|
|
256
|
+
discoverModels(): Promise<ModelInfo[]>;
|
|
257
|
+
generate(...): Promise<ImageOperationResult>;
|
|
258
|
+
edit(...): Promise<ImageOperationResult>;
|
|
259
|
+
variation(...): Promise<ImageOperationResult>;
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
新增 Provider:
|
|
264
|
+
|
|
265
|
+
1. 在 `src/providers/` 新建实现
|
|
266
|
+
2. 实现 `ImageProvider`
|
|
267
|
+
3. 在 `src/core/provider.ts` 中注册 resolver
|
|
268
|
+
4. 添加 mock 测试
|
|
269
|
+
|
|
270
|
+
## 故障排查
|
|
271
|
+
|
|
272
|
+
### 401
|
|
273
|
+
|
|
274
|
+
API Key 错误或过期。检查 `IMAGE_API_KEY`。
|
|
275
|
+
|
|
276
|
+
### 403
|
|
277
|
+
|
|
278
|
+
API Key 无权访问模型或图片接口。
|
|
279
|
+
|
|
280
|
+
### 404 /models
|
|
281
|
+
|
|
282
|
+
Base URL 可能不包含 `/v1`,或服务商不支持 `/models`。可以设置 `IMAGE_MODEL` fallback。
|
|
283
|
+
|
|
284
|
+
### 429
|
|
285
|
+
|
|
286
|
+
限流或额度不足。稍后重试。
|
|
287
|
+
|
|
288
|
+
### unknown 模型
|
|
289
|
+
|
|
290
|
+
扩展无法确认模型能力。使用:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
export IMAGE_MODEL_CAPABILITIES="model-id:image_generation"
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## 开发
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
npm install
|
|
300
|
+
npm run typecheck
|
|
301
|
+
npm run build
|
|
302
|
+
npm test
|
|
303
|
+
npm pack --dry-run
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
测试使用 mock fetch,不会调用真实付费 API。
|
|
307
|
+
|
|
308
|
+
## npm 发布
|
|
309
|
+
|
|
310
|
+
发布前检查:
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
npm pack --dry-run
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
确认包内没有:
|
|
317
|
+
|
|
318
|
+
- `.env`
|
|
319
|
+
- API Key
|
|
320
|
+
- 本地缓存
|
|
321
|
+
- 测试垃圾
|
|
322
|
+
- 大文件
|
|
323
|
+
|
|
324
|
+
发布需手动执行:
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
npm publish
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
本项目不会自动发布。
|
|
331
|
+
|
|
332
|
+
## 已知限制
|
|
333
|
+
|
|
334
|
+
- 第一版仅实现 OpenAI-compatible Provider。
|
|
335
|
+
- 不会默认发送真实图片生成请求来验证能力,避免潜在付费。
|
|
336
|
+
- 不同服务商图片接口参数可能有差异;当前传递 OpenAI 风格常见字段。
|
|
337
|
+
- `image_edit` 使用 multipart/form-data,某些兼容 API 可能要求不同字段名。
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { DiscoveryResult, ImageGenConfig } from "./types.js";
|
|
2
|
+
export declare class ModelDiscoveryCache {
|
|
3
|
+
private readonly cacheDir;
|
|
4
|
+
constructor(cacheDir?: string);
|
|
5
|
+
get(config: ImageGenConfig, now?: number): Promise<DiscoveryResult | undefined>;
|
|
6
|
+
set(config: ImageGenConfig, result: DiscoveryResult): Promise<void>;
|
|
7
|
+
key(config: ImageGenConfig): string;
|
|
8
|
+
apiKeyFingerprint(config: ImageGenConfig): string;
|
|
9
|
+
private fileFor;
|
|
10
|
+
private read;
|
|
11
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, writeFile, rename, chmod } from "node:fs/promises";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { GLOBAL_DIR } from "./global-config.js";
|
|
5
|
+
export class ModelDiscoveryCache {
|
|
6
|
+
cacheDir;
|
|
7
|
+
constructor(cacheDir = resolve(GLOBAL_DIR, "cache", "providers")) {
|
|
8
|
+
this.cacheDir = cacheDir;
|
|
9
|
+
}
|
|
10
|
+
async get(config, now = Date.now()) {
|
|
11
|
+
const entry = await this.read(config.providerId).catch(() => undefined);
|
|
12
|
+
if (!entry)
|
|
13
|
+
return undefined;
|
|
14
|
+
if (entry.key !== this.key(config))
|
|
15
|
+
return undefined;
|
|
16
|
+
const discovered = Date.parse(entry.result.discoveredAt);
|
|
17
|
+
if (!Number.isFinite(discovered) || now - discovered > config.cacheTtlMs)
|
|
18
|
+
return undefined;
|
|
19
|
+
return entry.result;
|
|
20
|
+
}
|
|
21
|
+
async set(config, result) {
|
|
22
|
+
await mkdir(this.cacheDir, { recursive: true });
|
|
23
|
+
const file = this.fileFor(config.providerId);
|
|
24
|
+
const temp = `${file}.${process.pid}.tmp`;
|
|
25
|
+
await writeFile(temp, JSON.stringify({ key: this.key(config), result: { ...result, apiKeyFingerprint: this.apiKeyFingerprint(config) } }, null, 2), { encoding: "utf8", mode: 0o600 });
|
|
26
|
+
await chmod(temp, 0o600).catch(() => undefined);
|
|
27
|
+
await rename(temp, file);
|
|
28
|
+
}
|
|
29
|
+
key(config) {
|
|
30
|
+
return createHash("sha256").update(`${config.providerId}\n${config.providerType}\n${config.baseUrl}\n${config.apiKeyUpdatedAt}\n${this.apiKeyFingerprint(config)}`).digest("hex");
|
|
31
|
+
}
|
|
32
|
+
apiKeyFingerprint(config) {
|
|
33
|
+
return createHash("sha256").update(config.apiKey).digest("hex").slice(0, 12);
|
|
34
|
+
}
|
|
35
|
+
fileFor(providerId) {
|
|
36
|
+
return resolve(this.cacheDir, `${providerId.replace(/[^a-zA-Z0-9._-]/g, "_")}.json`);
|
|
37
|
+
}
|
|
38
|
+
async read(providerId) {
|
|
39
|
+
return JSON.parse(await readFile(this.fileFor(providerId), "utf8"));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/core/cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import type { ModelCapability, ModelInfo } from "./types.js";
|
|
2
|
+
export declare function detectCapabilities(id: string, metadata: Record<string, unknown>, manual?: ModelCapability[]): Pick<ModelInfo, "capabilities" | "capabilitySource" | "inputModalities" | "outputModalities" | "supportsImageInput" | "supportsMultipleImages" | "supportsSize" | "supportsQuality" | "supportsAspectRatio">;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const imageHints = ["image", "img", "dall-e", "dalle", "gpt-image", "flux", "stable-diffusion", "sdxl", "midjourney", "ideogram", "recraft"];
|
|
2
|
+
const visionHints = ["vision", "vl", "visual", "omni", "gpt-4o", "qwen-vl", "llava"];
|
|
3
|
+
const textHints = ["gpt", "claude", "llama", "mistral", "deepseek", "qwen", "kimi", "mimo"];
|
|
4
|
+
export function detectCapabilities(id, metadata, manual) {
|
|
5
|
+
if (manual?.length)
|
|
6
|
+
return base(manual, "manual", metadata);
|
|
7
|
+
const metaCaps = explicitCapabilities(metadata);
|
|
8
|
+
if (metaCaps.length)
|
|
9
|
+
return base(metaCaps, "metadata", metadata);
|
|
10
|
+
const haystack = `${id} ${JSON.stringify(metadata)}`.toLowerCase();
|
|
11
|
+
const caps = new Set();
|
|
12
|
+
if (imageHints.some((h) => haystack.includes(h))) {
|
|
13
|
+
caps.add("image_generation");
|
|
14
|
+
if (haystack.includes("edit") || haystack.includes("gpt-image"))
|
|
15
|
+
caps.add("image_edit");
|
|
16
|
+
if (haystack.includes("variation") || haystack.includes("dall-e"))
|
|
17
|
+
caps.add("image_variation");
|
|
18
|
+
}
|
|
19
|
+
if (visionHints.some((h) => haystack.includes(h)))
|
|
20
|
+
caps.add("vision");
|
|
21
|
+
if (caps.size === 0 && textHints.some((h) => haystack.includes(h)))
|
|
22
|
+
caps.add("text");
|
|
23
|
+
if (caps.size === 0)
|
|
24
|
+
caps.add("unknown");
|
|
25
|
+
return base([...caps], caps.has("unknown") ? "unknown" : "heuristic", metadata);
|
|
26
|
+
}
|
|
27
|
+
function explicitCapabilities(metadata) {
|
|
28
|
+
const values = [];
|
|
29
|
+
for (const key of ["capabilities", "capability", "modalities", "input_modalities", "output_modalities", "supported_generation_methods"]) {
|
|
30
|
+
const value = metadata[key];
|
|
31
|
+
if (Array.isArray(value))
|
|
32
|
+
values.push(...value.filter((v) => typeof v === "string"));
|
|
33
|
+
else if (typeof value === "string")
|
|
34
|
+
values.push(value);
|
|
35
|
+
}
|
|
36
|
+
const text = values.join(" ").toLowerCase();
|
|
37
|
+
const caps = new Set();
|
|
38
|
+
if (/image[_ -]?generation|text-to-image|generate_images|image_out|output:image/.test(text))
|
|
39
|
+
caps.add("image_generation");
|
|
40
|
+
if (/image[_ -]?edit|edit_images|inpaint|input:image/.test(text))
|
|
41
|
+
caps.add("image_edit");
|
|
42
|
+
if (/image[_ -]?variation|variations/.test(text))
|
|
43
|
+
caps.add("image_variation");
|
|
44
|
+
if (/vision|image_input|input:image/.test(text))
|
|
45
|
+
caps.add("vision");
|
|
46
|
+
if (/text|chat|completion/.test(text))
|
|
47
|
+
caps.add("text");
|
|
48
|
+
return [...caps];
|
|
49
|
+
}
|
|
50
|
+
function base(capabilities, source, metadata) {
|
|
51
|
+
const lower = JSON.stringify(metadata).toLowerCase();
|
|
52
|
+
const supportsImageInput = capabilities.includes("image_edit") || capabilities.includes("vision") || lower.includes("input:image") || lower.includes("image_input");
|
|
53
|
+
return {
|
|
54
|
+
capabilities,
|
|
55
|
+
capabilitySource: source,
|
|
56
|
+
inputModalities: supportsImageInput ? ["text", "image"] : ["text"],
|
|
57
|
+
outputModalities: capabilities.includes("image_generation") || capabilities.includes("image_edit") || capabilities.includes("image_variation") ? ["image"] : ["text"],
|
|
58
|
+
supportsImageInput,
|
|
59
|
+
supportsMultipleImages: lower.includes("multiple") || lower.includes("multi_image"),
|
|
60
|
+
supportsSize: true,
|
|
61
|
+
supportsQuality: lower.includes("quality") || capabilities.includes("image_generation"),
|
|
62
|
+
supportsAspectRatio: lower.includes("aspect") || capabilities.includes("image_generation"),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/core/capabilities.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type ImageErrorCode = "missing_config" | "invalid_base_url" | "auth_failed" | "forbidden" | "not_found" | "rate_limited" | "server_error" | "timeout" | "network_error" | "invalid_request" | "invalid_json" | "invalid_image" | "unsupported_format" | "model_unavailable" | "capability_unknown" | "response_too_large" | "request_too_large" | "download_too_large" | "unsupported_provider";
|
|
2
|
+
export declare class ImageGenError extends Error {
|
|
3
|
+
readonly code: ImageErrorCode;
|
|
4
|
+
readonly suggestion: string;
|
|
5
|
+
readonly status?: number | undefined;
|
|
6
|
+
constructor(code: ImageErrorCode, message: string, suggestion: string, status?: number | undefined);
|
|
7
|
+
toUserMessage(): string;
|
|
8
|
+
}
|
|
9
|
+
export declare function sanitizeSecret(text: string, apiKey?: string): string;
|
|
10
|
+
export declare function maskApiKey(key: string): string;
|
|
11
|
+
export declare function errorFromStatus(status: number, action: string, detail?: string): ImageGenError;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export class ImageGenError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
suggestion;
|
|
4
|
+
status;
|
|
5
|
+
constructor(code, message, suggestion, status) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.suggestion = suggestion;
|
|
9
|
+
this.status = status;
|
|
10
|
+
this.name = "ImageGenError";
|
|
11
|
+
}
|
|
12
|
+
toUserMessage() {
|
|
13
|
+
const status = this.status ? `HTTP ${this.status}。` : "";
|
|
14
|
+
return `${this.message}\n原因:${status}${reasonForCode(this.code)}\n解决办法:${this.suggestion}`;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function sanitizeSecret(text, apiKey) {
|
|
18
|
+
let out = text;
|
|
19
|
+
if (apiKey)
|
|
20
|
+
out = out.split(apiKey).join(maskApiKey(apiKey));
|
|
21
|
+
out = out.replace(/Bearer\s+[A-Za-z0-9._\-]+/g, "Bearer ****");
|
|
22
|
+
out = out.replace(/sk-[A-Za-z0-9._\-]{8,}/g, (m) => maskApiKey(m));
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
export function maskApiKey(key) {
|
|
26
|
+
if (!key)
|
|
27
|
+
return "未配置";
|
|
28
|
+
if (key.length <= 8)
|
|
29
|
+
return "****";
|
|
30
|
+
return `${key.slice(0, 3)}-****${key.slice(-4)}`;
|
|
31
|
+
}
|
|
32
|
+
export function errorFromStatus(status, action, detail) {
|
|
33
|
+
switch (status) {
|
|
34
|
+
case 401: return new ImageGenError("auth_failed", `${action}失败:认证失败。`, "检查 IMAGE_API_KEY 是否正确、是否过期。", status);
|
|
35
|
+
case 403: return new ImageGenError("forbidden", `${action}失败:权限不足。`, "确认 API Key 有访问模型和图片接口的权限。", status);
|
|
36
|
+
case 404: return new ImageGenError("not_found", `${action}失败:接口不存在。`, "确认 IMAGE_BASE_URL 是否包含正确版本路径,例如 https://host/v1。", status);
|
|
37
|
+
case 408: return new ImageGenError("timeout", `${action}失败:请求超时。`, "稍后重试,或增大 IMAGE_TIMEOUT_SECONDS。", status);
|
|
38
|
+
case 409: return new ImageGenError("model_unavailable", `${action}失败:请求冲突或模型不可用。`, "尝试换模型,或检查服务商状态。", status);
|
|
39
|
+
case 413: return new ImageGenError("request_too_large", `${action}失败:请求体过大。`, "降低图片尺寸、减少 n,或使用更小的输入图片。", status);
|
|
40
|
+
case 429: return new ImageGenError("rate_limited", `${action}失败:触发限流。`, "稍后重试,或检查额度/并发限制。", status);
|
|
41
|
+
case 500:
|
|
42
|
+
case 502:
|
|
43
|
+
case 503: return new ImageGenError("server_error", `${action}失败:服务端错误。`, "稍后重试;若持续失败请联系 API 服务商。", status);
|
|
44
|
+
default: return new ImageGenError(status >= 500 ? "server_error" : status >= 400 ? "invalid_request" : "network_error", `${action}失败:HTTP ${status}${detail ? `:${detail}` : "。"}`, status >= 400 && status < 500 ? "检查模型名称、图片尺寸、响应格式和服务商文档。" : "检查网络连接和服务商状态。", status);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function reasonForCode(code) {
|
|
48
|
+
const map = {
|
|
49
|
+
missing_config: "缺少必要配置。",
|
|
50
|
+
invalid_base_url: "Base URL 格式不正确或不是 http/https。",
|
|
51
|
+
auth_failed: "API Key 无效或未授权。",
|
|
52
|
+
forbidden: "当前凭证没有访问权限。",
|
|
53
|
+
not_found: "目标 API 路径不存在。",
|
|
54
|
+
rate_limited: "请求过快或额度不足。",
|
|
55
|
+
server_error: "API 服务端返回错误。",
|
|
56
|
+
timeout: "网络请求超过超时时间。",
|
|
57
|
+
network_error: "网络连接失败或响应异常。",
|
|
58
|
+
invalid_request: "请求已到达 API,但参数或模型不符合服务商要求。",
|
|
59
|
+
invalid_json: "API 返回的 JSON 无法解析。",
|
|
60
|
+
invalid_image: "图片内容为空或不是有效图片。",
|
|
61
|
+
unsupported_format: "仅支持 png、jpg、jpeg、webp。",
|
|
62
|
+
model_unavailable: "模型不存在、不可用或不支持该操作。",
|
|
63
|
+
capability_unknown: "无法自动确认模型能力。",
|
|
64
|
+
response_too_large: "响应超过安全大小限制。",
|
|
65
|
+
request_too_large: "请求体超过服务商限制。",
|
|
66
|
+
download_too_large: "下载图片超过大小限制。",
|
|
67
|
+
unsupported_provider: "暂不支持该 Provider 类型。",
|
|
68
|
+
};
|
|
69
|
+
return map[code];
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { GlobalImageGenConfig, ImageGenConfig, StoredProviderConfig } from "./types.js";
|
|
2
|
+
export declare const GLOBAL_DIR: string;
|
|
3
|
+
export declare const PROVIDERS_FILE: string;
|
|
4
|
+
export declare class GlobalConfigStore {
|
|
5
|
+
private readonly filePath;
|
|
6
|
+
constructor(filePath?: string);
|
|
7
|
+
read(): Promise<GlobalImageGenConfig>;
|
|
8
|
+
write(config: GlobalImageGenConfig): Promise<void>;
|
|
9
|
+
addProvider(input: {
|
|
10
|
+
id?: string;
|
|
11
|
+
name: string;
|
|
12
|
+
baseUrl: string;
|
|
13
|
+
apiKey: string;
|
|
14
|
+
defaultModel?: string;
|
|
15
|
+
responseFormat?: "auto" | "url" | "b64_json";
|
|
16
|
+
manualCapabilities?: string;
|
|
17
|
+
}): Promise<StoredProviderConfig>;
|
|
18
|
+
updateProvider(id: string, patch: Partial<Omit<StoredProviderConfig, "id" | "createdAt">>): Promise<StoredProviderConfig>;
|
|
19
|
+
deleteProvider(id: string): Promise<void>;
|
|
20
|
+
setDefaultProvider(id: string): Promise<void>;
|
|
21
|
+
resolveProvider(idOrName?: string): Promise<StoredProviderConfig | undefined>;
|
|
22
|
+
toRuntimeConfig(provider: StoredProviderConfig, env?: NodeJS.ProcessEnv): Promise<ImageGenConfig>;
|
|
23
|
+
}
|
|
24
|
+
export declare function envFallbackProvider(env?: NodeJS.ProcessEnv): StoredProviderConfig | undefined;
|
|
25
|
+
export declare function resolveRuntimeConfig(providerId?: string, env?: NodeJS.ProcessEnv, store?: GlobalConfigStore): Promise<ImageGenConfig>;
|