From 8656f3a58c7de2b59250ae2bcb3f40b3fec7ad42 Mon Sep 17 00:00:00 2001 From: sion123 <450702724@qq.com> Date: Thu, 30 Apr 2026 00:59:02 +0800 Subject: [PATCH] =?UTF-8?q?feat(video-from-script):=20=E5=B0=86=E5=8F=AF?= =?UTF-8?q?=E7=81=B5=E7=94=9F=E5=9B=BE=E5=88=87=E6=8D=A2=E4=B8=BA=E5=A4=9A?= =?UTF-8?q?=E5=9B=BE=E5=8F=82=E8=80=83=E9=A3=8E=E6=A0=BC=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 Kling 图像生成器从单图生图 API 升级为多图参考生图端点,支持风格参考图片功能,并更新降级链顺序 --- .claude/skills/video-from-script/SKILL.md | 2 +- .../scripts/kling-image-generator.js | 39 ++++++++++++------- .../video-from-script/scripts/pipeline.js | 4 +- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/.claude/skills/video-from-script/SKILL.md b/.claude/skills/video-from-script/SKILL.md index d62a10f..64714da 100644 --- a/.claude/skills/video-from-script/SKILL.md +++ b/.claude/skills/video-from-script/SKILL.md @@ -140,7 +140,7 @@ Step 3: 生图 → 审查 生图模型 - 支持模型:gemini / mj / kling - - 降级链:gemini → kling → mj → gemini(循环) + - 降级链:gemini → mj → kling → gemini(循环) - 触发:连续失败→ Agent 换下一个模型重跑失败项 - 操作:`pipeline.js run --manifest --phase images --retry-failed --image-model <新模型>` diff --git a/.claude/skills/video-from-script/scripts/kling-image-generator.js b/.claude/skills/video-from-script/scripts/kling-image-generator.js index f89637c..500b29b 100644 --- a/.claude/skills/video-from-script/scripts/kling-image-generator.js +++ b/.claude/skills/video-from-script/scripts/kling-image-generator.js @@ -1,13 +1,13 @@ #!/usr/bin/env node /** - * Kling Image Generator - 可灵文生图 / 图生图 + * Kling Image Generator - 可灵多图参考生图 (风格参考) * + * 使用 /v1/images/multi-image2image 端点,支持 style_image 风格参考 * 配置来源: config.json 的 kelingApiKey + kelingSecretAccessKey + kelingApiBaseUrl * * 用法: - * node kling-image-generator.js "a cute cat" -o ./output - * node kling-image-generator.js "portrait" -r http://img.com/ref.jpg + * node kling-image-generator.js "a cute cat" -r http://img.com/style.jpg -o ./output */ const fs = require('fs') @@ -75,24 +75,31 @@ async function download(url, outputPath) { } // ============================================================================ -// 可灵图片 API +// 可灵多图参考生图 API (/v1/images/multi-image2image) // ============================================================================ const KlingImageApi = { async submit(prompt, options = {}) { - const { referenceImageUrl = '', aspectRatio = '' } = options + const { styleImageUrl = '', aspectRatio = '' } = options const token = getToken() - const body = { model_name: Config.model, prompt, n: 1 } - if (referenceImageUrl) body.image = referenceImageUrl + const body = { + model_name: Config.model, + prompt, + n: 1, + } + if (styleImageUrl) { + body.subject_image_list = [{ subject_image: styleImageUrl }] + body.style_image = styleImageUrl + } if (aspectRatio) body.aspect_ratio = aspectRatio console.log(`\n📡 提交可灵图片任务`) console.log(` 模型: ${Config.model}`) console.log(` 提示词: ${prompt.substring(0, 80)}...`) - if (referenceImageUrl) console.log(` 参考图: ${referenceImageUrl.substring(0, 60)}...`) + if (styleImageUrl) console.log(` 风格图: ${styleImageUrl.substring(0, 60)}...`) - const res = await fetch(`${Config.apiBase}/v1/images/generations`, { + const res = await fetch(`${Config.apiBase}/v1/images/multi-image2image`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify(body), @@ -116,7 +123,7 @@ const KlingImageApi = { while (Date.now() - startTime < Config.maxPollTime) { const token = getToken() - const res = await fetch(`${Config.apiBase}/v1/images/generations/${taskId}`, { + const res = await fetch(`${Config.apiBase}/v1/images/multi-image2image/${taskId}`, { headers: { 'Authorization': `Bearer ${token}` }, }) @@ -150,11 +157,11 @@ const KlingImageApi = { // ============================================================================ async function generate(prompt, options = {}) { - const { outputDir = './output', referenceImageUrl = '' } = options + const { outputDir = './output', styleImageUrl = '', aspectRatio = '' } = options fs.mkdirSync(outputDir, { recursive: true }) - const taskId = await KlingImageApi.submit(prompt, { referenceImageUrl }) + const taskId = await KlingImageApi.submit(prompt, { styleImageUrl, aspectRatio }) const result = await KlingImageApi.poll(taskId) const timestamp = new Date().toISOString().replace(/[:.]/g, '-') @@ -177,20 +184,22 @@ async function main() { 选项: -o, --output 输出目录 (默认: ./output) - -r, --ref 参考图 URL + -r, --ref 风格参考图 URL + -a, --ar 画幅比例 (如 9:16, 16:9) -h, --help 帮助 `) return } - const options = { outputDir: './output', referenceImageUrl: '' } + const options = { outputDir: './output', styleImageUrl: '', aspectRatio: '' } const params = [] let i = 0 while (i < args.length) { const arg = args[i] if (arg === '-o' || arg === '--output') { options.outputDir = args[++i] } - else if (arg === '-r' || arg === '--ref') { options.referenceImageUrl = args[++i] } + else if (arg === '-r' || arg === '--ref') { options.styleImageUrl = args[++i] } + else if (arg === '-a' || arg === '--ar') { options.aspectRatio = args[++i] } else { params.push(arg) } i++ } diff --git a/.claude/skills/video-from-script/scripts/pipeline.js b/.claude/skills/video-from-script/scripts/pipeline.js index c23efdd..2fb9cf7 100644 --- a/.claude/skills/video-from-script/scripts/pipeline.js +++ b/.claude/skills/video-from-script/scripts/pipeline.js @@ -221,7 +221,7 @@ async function phaseImages(manifest, manifestPath, options) { const { generate: klingGen } = require('./kling-image-generator') const klingOpts = { outputDir: imagesDir, aspectRatio: ratio } if (refs.urls.length > 0) { - klingOpts.referenceImageUrl = refs.urls[0] + klingOpts.styleImageUrl = refs.urls[0] } log('images', `[${idx}/${items.length}] 可灵生图: ${item.imagePrompt.substring(0, 60)}...`) result = await klingGen(item.imagePrompt, klingOpts) @@ -272,7 +272,7 @@ async function phaseImages(manifest, manifestPath, options) { const { generate: klingGen } = require('./kling-image-generator') lastResult = await klingGen(item.lastFramePrompt, { outputDir: imagesDir, - referenceImageUrl: item.url || '', + styleImageUrl: item.url || '', aspectRatio: ratio, }) }