feat(video-from-script): 将可灵生图切换为多图参考风格接口
将 Kling 图像生成器从单图生图 API 升级为多图参考生图端点,支持风格参考图片功能,并更新降级链顺序
This commit is contained in:
@@ -140,7 +140,7 @@ Step 3: 生图 → 审查
|
||||
|
||||
生图模型
|
||||
- 支持模型:gemini / mj / kling
|
||||
- 降级链:gemini → kling → mj → gemini(循环)
|
||||
- 降级链:gemini → mj → kling → gemini(循环)
|
||||
- 触发:连续失败→ Agent 换下一个模型重跑失败项
|
||||
- 操作:`pipeline.js run --manifest <path> --phase images --retry-failed --image-model <新模型>`
|
||||
|
||||
|
||||
@@ -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 <dir> 输出目录 (默认: ./output)
|
||||
-r, --ref <url> 参考图 URL
|
||||
-r, --ref <url> 风格参考图 URL
|
||||
-a, --ar <ratio> 画幅比例 (如 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++
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user