kie-ai-cli 1.0.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.en.md +36 -0
- package/README.md +503 -0
- package/dist/api.js +29 -0
- package/dist/code.js +937 -0
- package/dist/commands/chat.js +552 -0
- package/dist/commands/code-command.js +1025 -0
- package/dist/commands/config.js +61 -0
- package/dist/commands/image.js +102 -0
- package/dist/commands/job.js +25 -0
- package/dist/commands/upload.js +41 -0
- package/dist/editor.js +38 -0
- package/dist/image-assist.js +79 -0
- package/dist/image-models.js +336 -0
- package/dist/image-repl.js +525 -0
- package/dist/image-session.js +75 -0
- package/dist/image-templates.js +76 -0
- package/dist/image.js +233 -0
- package/dist/index.js +135 -0
- package/dist/job.js +121 -0
- package/dist/kie-http.js +182 -0
- package/dist/models.js +223 -0
- package/dist/providers/claude.js +63 -0
- package/dist/providers/codex.js +59 -0
- package/dist/providers/index.js +14 -0
- package/dist/providers/openai.js +64 -0
- package/dist/session.js +235 -0
- package/dist/types.js +1 -0
- package/dist/utils/renderer.js +19 -0
- package/package.json +38 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import select from '@inquirer/select';
|
|
3
|
+
import { CONFIG_KEY_IMAGE_MODEL } from './models.js';
|
|
4
|
+
export const DEFAULT_IMAGE_MODEL = 'gpt-image-2-text-to-image';
|
|
5
|
+
export const IMAGE_MODELS = [
|
|
6
|
+
{
|
|
7
|
+
id: 'gpt-image/1.5-text-to-image',
|
|
8
|
+
label: 'GPT Image 1.5 文生图',
|
|
9
|
+
kind: 'text-to-image',
|
|
10
|
+
description: '官方推荐,支持 1:1 / 2:3 / 3:2 与 medium/high 质量',
|
|
11
|
+
supportsQuality: true,
|
|
12
|
+
aspectRatios: ['1:1', '2:3', '3:2'],
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: 'gpt-image/1.5-image-to-image',
|
|
16
|
+
label: 'GPT Image 1.5 图生图',
|
|
17
|
+
kind: 'image-to-image',
|
|
18
|
+
description: '基于 input_urls 编辑图片(需先上传获得 URL)',
|
|
19
|
+
supportsQuality: true,
|
|
20
|
+
aspectRatios: ['1:1', '2:3', '3:2'],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: 'gpt-image-2-text-to-image',
|
|
24
|
+
label: 'GPT Image 2 文生图',
|
|
25
|
+
kind: 'text-to-image',
|
|
26
|
+
description: 'aspect_ratio 使用 auto',
|
|
27
|
+
supportsQuality: false,
|
|
28
|
+
aspectRatios: ['auto'],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'gpt-image-2-image-to-image',
|
|
32
|
+
label: 'GPT Image 2 图生图',
|
|
33
|
+
kind: 'image-to-image',
|
|
34
|
+
description: '基于 input_urls 编辑图片,aspect_ratio 使用 auto',
|
|
35
|
+
supportsQuality: false,
|
|
36
|
+
aspectRatios: ['auto'],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: 'bytedance/seedream',
|
|
40
|
+
label: 'ByteDance Seedream',
|
|
41
|
+
kind: 'text-to-image',
|
|
42
|
+
description: '字节跳动 Seedream 极速文生图,支持 square_hd / landscape_hd / portrait_hd',
|
|
43
|
+
supportsQuality: false,
|
|
44
|
+
aspectRatios: ['auto', '1:1', '16:9', '9:16', '3:2', '2:3', '4:3', '3:4'],
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'bytedance/seedream-v4-text-to-image',
|
|
48
|
+
label: 'ByteDance Seedream v4',
|
|
49
|
+
kind: 'text-to-image',
|
|
50
|
+
description: '字节跳动 Seedream v4 最新文生图,支持 1K 像素高精度排版,支持 seed 参数',
|
|
51
|
+
supportsQuality: false,
|
|
52
|
+
aspectRatios: ['auto', '1:1', '16:9', '9:16', '3:2', '2:3', '4:3', '3:4'],
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 'bytedance/seedream-v4-edit',
|
|
56
|
+
label: 'ByteDance Seedream v4 编辑',
|
|
57
|
+
kind: 'image-to-image',
|
|
58
|
+
description: '字节跳动 Seedream v4 最新图生图/编辑,支持 1K 像素高精度,支持参考图与 seed',
|
|
59
|
+
supportsQuality: false,
|
|
60
|
+
aspectRatios: ['auto', '1:1', '16:9', '9:16', '3:2', '2:3', '4:3', '3:4'],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: 'seedream/4.5-text-to-image',
|
|
64
|
+
label: 'Seedream 4.5 文生图',
|
|
65
|
+
kind: 'text-to-image',
|
|
66
|
+
description: 'Seedream 4.5 最新版本文生图,支持 aspect_ratio 比例与 quality 质量参数',
|
|
67
|
+
supportsQuality: true,
|
|
68
|
+
aspectRatios: ['1:1', '16:9', '9:16', '3:2', '2:3', '4:3', '3:4'],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: 'seedream/4.5-edit',
|
|
72
|
+
label: 'Seedream 4.5 编辑',
|
|
73
|
+
kind: 'image-to-image',
|
|
74
|
+
description: 'Seedream 4.5 最新版本图生图/编辑,支持 aspect_ratio 比例与 quality 质量参数',
|
|
75
|
+
supportsQuality: true,
|
|
76
|
+
aspectRatios: ['1:1', '16:9', '9:16', '3:2', '2:3', '4:3', '3:4'],
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 'seedream/5-lite-text-to-image',
|
|
80
|
+
label: 'Seedream 5 Lite 文生图',
|
|
81
|
+
kind: 'text-to-image',
|
|
82
|
+
description: 'Seedream 5 Lite 最新极速轻量级文生图,支持 aspect_ratio 比例与 quality 质量参数',
|
|
83
|
+
supportsQuality: true,
|
|
84
|
+
aspectRatios: ['1:1', '16:9', '9:16', '3:2', '2:3', '4:3', '3:4'],
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
export function findImageModel(modelId) {
|
|
88
|
+
return IMAGE_MODELS.find((m) => m.id === modelId);
|
|
89
|
+
}
|
|
90
|
+
export function getImageModel(config) {
|
|
91
|
+
return config.get(CONFIG_KEY_IMAGE_MODEL) || DEFAULT_IMAGE_MODEL;
|
|
92
|
+
}
|
|
93
|
+
export function setImageModel(config, modelId) {
|
|
94
|
+
config.set(CONFIG_KEY_IMAGE_MODEL, modelId.trim());
|
|
95
|
+
}
|
|
96
|
+
export function resolveImageModel(config, cliModel) {
|
|
97
|
+
return cliModel?.trim() || getImageModel(config);
|
|
98
|
+
}
|
|
99
|
+
export function formatImageModelLabel(modelId) {
|
|
100
|
+
const known = findImageModel(modelId);
|
|
101
|
+
if (!known)
|
|
102
|
+
return modelId;
|
|
103
|
+
const kind = known.kind === 'text-to-image' ? '文生图' : '图生图';
|
|
104
|
+
return `${known.label} (${modelId}) [${kind}]`;
|
|
105
|
+
}
|
|
106
|
+
/** 按模型构造 createTask 的 input 对象 */
|
|
107
|
+
export function buildImageTaskInput(modelId, options) {
|
|
108
|
+
const known = findImageModel(modelId);
|
|
109
|
+
const prompt = options.prompt.trim();
|
|
110
|
+
if (!prompt) {
|
|
111
|
+
throw new Error('提示词不能为空');
|
|
112
|
+
}
|
|
113
|
+
if (modelId === 'seedream/4.5-edit') {
|
|
114
|
+
const urls = options.imageUrls?.filter(Boolean) ?? [];
|
|
115
|
+
if (urls.length === 0) {
|
|
116
|
+
throw new Error(`模型 ${modelId} 需要参考图,请使用 --image-url <url>(支持本地图片自动上传)`);
|
|
117
|
+
}
|
|
118
|
+
const aspectRatio = normalizeAspectRatio(options.aspectRatio, ['1:1', '16:9', '9:16', '3:2', '2:3', '4:3', '3:4'], '1:1');
|
|
119
|
+
return {
|
|
120
|
+
prompt,
|
|
121
|
+
image_urls: urls,
|
|
122
|
+
aspect_ratio: aspectRatio,
|
|
123
|
+
quality: options.quality ?? 'basic',
|
|
124
|
+
nsfw_checker: true,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
if (modelId === 'seedream/5-lite-text-to-image' || modelId === 'seedream/4.5-text-to-image') {
|
|
128
|
+
const aspectRatio = normalizeAspectRatio(options.aspectRatio, ['1:1', '16:9', '9:16', '3:2', '2:3', '4:3', '3:4'], '1:1');
|
|
129
|
+
return {
|
|
130
|
+
prompt,
|
|
131
|
+
aspect_ratio: aspectRatio,
|
|
132
|
+
quality: options.quality ?? 'basic',
|
|
133
|
+
nsfw_checker: false,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (modelId === 'bytedance/seedream-v4-edit') {
|
|
137
|
+
const urls = options.imageUrls?.filter(Boolean) ?? [];
|
|
138
|
+
if (urls.length === 0) {
|
|
139
|
+
throw new Error(`模型 ${modelId} 需要参考图,请使用 --image-url <url>(支持本地图片自动上传)`);
|
|
140
|
+
}
|
|
141
|
+
let image_size = 'square_hd';
|
|
142
|
+
const ratio = options.aspectRatio?.trim();
|
|
143
|
+
if (ratio) {
|
|
144
|
+
if (ratio === '1:1') {
|
|
145
|
+
image_size = 'square_hd';
|
|
146
|
+
}
|
|
147
|
+
else if (ratio === '16:9' || ratio === '3:2' || ratio === '4:3' || ratio === 'landscape') {
|
|
148
|
+
image_size = 'landscape_hd';
|
|
149
|
+
}
|
|
150
|
+
else if (ratio === '9:16' || ratio === '2:3' || ratio === '3:4' || ratio === 'portrait') {
|
|
151
|
+
image_size = 'portrait_hd';
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
image_size = ratio;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const input = {
|
|
158
|
+
prompt,
|
|
159
|
+
image_urls: urls,
|
|
160
|
+
image_size,
|
|
161
|
+
image_resolution: '1K',
|
|
162
|
+
max_images: 1,
|
|
163
|
+
nsfw_checker: false,
|
|
164
|
+
};
|
|
165
|
+
if (options.seed !== undefined && !Number.isNaN(options.seed)) {
|
|
166
|
+
input.seed = options.seed;
|
|
167
|
+
}
|
|
168
|
+
return input;
|
|
169
|
+
}
|
|
170
|
+
if (modelId === 'bytedance/seedream-v4-text-to-image') {
|
|
171
|
+
let image_size = 'square_hd';
|
|
172
|
+
const ratio = options.aspectRatio?.trim();
|
|
173
|
+
if (ratio) {
|
|
174
|
+
if (ratio === '1:1') {
|
|
175
|
+
image_size = 'square_hd';
|
|
176
|
+
}
|
|
177
|
+
else if (ratio === '16:9' || ratio === '3:2' || ratio === '4:3' || ratio === 'landscape') {
|
|
178
|
+
image_size = 'landscape_hd';
|
|
179
|
+
}
|
|
180
|
+
else if (ratio === '9:16' || ratio === '2:3' || ratio === '3:4' || ratio === 'portrait') {
|
|
181
|
+
image_size = 'portrait_hd';
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
image_size = ratio;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const input = {
|
|
188
|
+
prompt,
|
|
189
|
+
image_size,
|
|
190
|
+
image_resolution: '1K',
|
|
191
|
+
max_images: 1,
|
|
192
|
+
nsfw_checker: false,
|
|
193
|
+
};
|
|
194
|
+
if (options.seed !== undefined && !Number.isNaN(options.seed)) {
|
|
195
|
+
input.seed = options.seed;
|
|
196
|
+
}
|
|
197
|
+
return input;
|
|
198
|
+
}
|
|
199
|
+
if (modelId === 'bytedance/seedream') {
|
|
200
|
+
let image_size = 'square_hd';
|
|
201
|
+
const ratio = options.aspectRatio?.trim();
|
|
202
|
+
if (ratio) {
|
|
203
|
+
if (ratio === '1:1') {
|
|
204
|
+
image_size = 'square_hd';
|
|
205
|
+
}
|
|
206
|
+
else if (ratio === '16:9' || ratio === '3:2' || ratio === '4:3' || ratio === 'landscape') {
|
|
207
|
+
image_size = 'landscape_hd';
|
|
208
|
+
}
|
|
209
|
+
else if (ratio === '9:16' || ratio === '2:3' || ratio === '3:4' || ratio === 'portrait') {
|
|
210
|
+
image_size = 'portrait_hd';
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
image_size = ratio;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
prompt,
|
|
218
|
+
image_size,
|
|
219
|
+
guidance_scale: 2.5,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
if (known?.id === 'gpt-image-2-image-to-image') {
|
|
223
|
+
const urls = options.imageUrls?.filter(Boolean) ?? [];
|
|
224
|
+
if (urls.length === 0) {
|
|
225
|
+
throw new Error(`模型 ${modelId} 需要参考图,请使用 --image-url <url>(可多次指定)`);
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
prompt,
|
|
229
|
+
input_urls: urls,
|
|
230
|
+
aspect_ratio: options.aspectRatio ?? 'auto',
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
if (known?.kind === 'image-to-image') {
|
|
234
|
+
const urls = options.imageUrls?.filter(Boolean) ?? [];
|
|
235
|
+
if (urls.length === 0) {
|
|
236
|
+
throw new Error(`模型 ${modelId} 需要参考图,请使用 --image-url <url>(可多次指定)`);
|
|
237
|
+
}
|
|
238
|
+
const aspectRatio = normalizeAspectRatio(options.aspectRatio, known.aspectRatios, '3:2');
|
|
239
|
+
const input = {
|
|
240
|
+
input_urls: urls,
|
|
241
|
+
prompt,
|
|
242
|
+
aspect_ratio: aspectRatio,
|
|
243
|
+
};
|
|
244
|
+
if (known.supportsQuality) {
|
|
245
|
+
input.quality = options.quality ?? 'medium';
|
|
246
|
+
}
|
|
247
|
+
return input;
|
|
248
|
+
}
|
|
249
|
+
if (known?.id === 'gpt-image-2-text-to-image') {
|
|
250
|
+
return {
|
|
251
|
+
prompt,
|
|
252
|
+
aspect_ratio: options.aspectRatio ?? 'auto',
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
if (known) {
|
|
256
|
+
const aspectRatio = normalizeAspectRatio(options.aspectRatio, known.aspectRatios, '1:1');
|
|
257
|
+
const input = {
|
|
258
|
+
prompt,
|
|
259
|
+
aspect_ratio: aspectRatio,
|
|
260
|
+
};
|
|
261
|
+
if (known.supportsQuality) {
|
|
262
|
+
input.quality = options.quality ?? 'medium';
|
|
263
|
+
}
|
|
264
|
+
return input;
|
|
265
|
+
}
|
|
266
|
+
// 自定义模型:尽量通用
|
|
267
|
+
const input = { prompt };
|
|
268
|
+
if (options.aspectRatio)
|
|
269
|
+
input.aspect_ratio = options.aspectRatio;
|
|
270
|
+
if (options.quality)
|
|
271
|
+
input.quality = options.quality;
|
|
272
|
+
if (options.imageUrls?.length)
|
|
273
|
+
input.input_urls = options.imageUrls;
|
|
274
|
+
return input;
|
|
275
|
+
}
|
|
276
|
+
function normalizeAspectRatio(value, allowed, fallback) {
|
|
277
|
+
if (!value)
|
|
278
|
+
return fallback;
|
|
279
|
+
if (allowed.includes(value))
|
|
280
|
+
return value;
|
|
281
|
+
if (allowed.includes('auto'))
|
|
282
|
+
return 'auto';
|
|
283
|
+
throw new Error(`宽高比 ${value} 不支持,可选: ${allowed.join(', ')}`);
|
|
284
|
+
}
|
|
285
|
+
export function printImageModels(currentModelId) {
|
|
286
|
+
console.log(chalk.yellow('\n可用图片模型 (Image,用于 kie image):\n'));
|
|
287
|
+
for (const m of IMAGE_MODELS) {
|
|
288
|
+
const current = m.id === currentModelId;
|
|
289
|
+
const marker = current ? chalk.green('● ') : chalk.gray(' ');
|
|
290
|
+
const kind = m.kind === 'text-to-image' ? chalk.cyan('文生图') : chalk.magenta('图生图');
|
|
291
|
+
console.log(`${marker}${chalk.bold(m.id.padEnd(32))} ${m.label.padEnd(20)} ${kind} ${chalk.dim(m.description)}`);
|
|
292
|
+
}
|
|
293
|
+
if (!findImageModel(currentModelId)) {
|
|
294
|
+
console.log(chalk.gray(`\n当前使用自定义模型: ${chalk.cyan(currentModelId)}`));
|
|
295
|
+
}
|
|
296
|
+
console.log(chalk.gray('\n切换: kie image-models --set | kie config --set-image-model <id>\n'));
|
|
297
|
+
}
|
|
298
|
+
export function printImageModelPickerMenu(currentModelId) {
|
|
299
|
+
console.log(chalk.yellow('\n选择图片生成模型 — 输入序号或模型 ID,0 取消:\n'));
|
|
300
|
+
IMAGE_MODELS.forEach((m, i) => {
|
|
301
|
+
const current = m.id === currentModelId ? chalk.green(' ← 当前') : '';
|
|
302
|
+
const kind = m.kind === 'text-to-image' ? '文生图' : '图生图';
|
|
303
|
+
console.log(` ${chalk.cyan(String(i + 1).padStart(2))}. [${kind}] ${chalk.bold(m.id)} — ${m.label}${current}`);
|
|
304
|
+
});
|
|
305
|
+
console.log(chalk.gray('\n 0. 取消\n'));
|
|
306
|
+
}
|
|
307
|
+
export function resolveImageModelPick(input) {
|
|
308
|
+
const trimmed = input.trim();
|
|
309
|
+
if (!trimmed || trimmed === '0')
|
|
310
|
+
return null;
|
|
311
|
+
const n = parseInt(trimmed, 10);
|
|
312
|
+
if (!Number.isNaN(n) && n >= 1 && n <= IMAGE_MODELS.length) {
|
|
313
|
+
return IMAGE_MODELS[n - 1].id;
|
|
314
|
+
}
|
|
315
|
+
return trimmed;
|
|
316
|
+
}
|
|
317
|
+
export async function promptSelectImageModel(currentModelId) {
|
|
318
|
+
const choices = IMAGE_MODELS.map((m) => ({
|
|
319
|
+
name: `${m.label} (${m.id}) — ${m.kind === 'text-to-image' ? '文生图' : '图生图'}`,
|
|
320
|
+
value: m.id,
|
|
321
|
+
description: m.description,
|
|
322
|
+
}));
|
|
323
|
+
if (!findImageModel(currentModelId)) {
|
|
324
|
+
choices.unshift({
|
|
325
|
+
name: `当前自定义: ${currentModelId}`,
|
|
326
|
+
value: currentModelId,
|
|
327
|
+
description: '当前正在使用',
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
return select({
|
|
331
|
+
message: '选择图片模型 (↑↓ 移动,Enter 确认)',
|
|
332
|
+
choices,
|
|
333
|
+
default: currentModelId,
|
|
334
|
+
pageSize: Math.min(choices.length, 10),
|
|
335
|
+
});
|
|
336
|
+
}
|