铸渊 ICE-GL-ZY001 LL-172-20260707 冰朔委托: 新建第 5 子仓, 给苍耳(人类主控) + 鉴影(人格体) 专用 原 guanghulab/video-ai-system/ 东西太多(225 文件) · 找不到 · 乱 迁移: ⊢ 16 个核心 .hdlp (VA-GATE / VA-LIGHTHOUSE / VA-BROADCAST / VA-SYSTEM-STATUS 等) ⊢ 17 个子目录 (agents/engines/protocols/tasks/tools/assets/knowledge/memory/docs/config/brain/director-brain/experience/feedback/issues/plans/reference-analysis) 排除: ⊢ outputs/ (视频产物) ⊢ test-input/ test-output/ (测试) ⊢ data/ (临时数据) ⊢ preview-001/002 (旧产片) ⊢ 旧分镜/旧提示词/旧导演编码 后续: ⊢ 老仓 guanghulab/video-ai-system/ 改写为已迁出占位 ⊢ 苍耳+鉴影 写新东西进本仓 ⊢ GLOBAL-SEARCH 加 cang-ying 仓库 铸渊 ICE-GL-ZY001 · 2026-07-07 D167 冰朔 ICE-GL∞ 主权
108 lines
3.4 KiB
JavaScript
108 lines
3.4 KiB
JavaScript
/**
|
||
* 光湖视频AI系统 · Kling 可灵 API 适配器
|
||
* D136+ · 铸渊 ICE-GL-ZY001 · 2026-06-21
|
||
*
|
||
* 接入可灵AI视频生成API。价格: kling-v2.6-pro $0.049/s (约1.8元/5秒)
|
||
* 非Seedance——用于低成本验证提示词和流程
|
||
*/
|
||
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
const https = require('https');
|
||
|
||
// API配置
|
||
const API_KEY = 'Ze8Bas4_xw1JsPLmfULgMyykvZelFSwv57Hycc6SJm0';
|
||
const BASE_URL = 'api.klingapi.com';
|
||
const POLL_INTERVAL = 3000; // 可灵更快,3秒轮询
|
||
const MAX_POLL = 60; // 最多3分钟
|
||
|
||
// 输出路径
|
||
const OUT_DIR = (() => {
|
||
const jzao = '/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/视频/zai-fu-fei-xiu-xian/ep01';
|
||
return fs.existsSync(jzao) ? jzao : path.resolve(__dirname, '../outputs/shots');
|
||
})();
|
||
|
||
function apiRequest(method, path_, body = null) {
|
||
return new Promise((resolve, reject) => {
|
||
const options = {
|
||
hostname: BASE_URL,
|
||
path: path_,
|
||
method,
|
||
headers: {
|
||
'Authorization': `Bearer ${API_KEY}`,
|
||
'Content-Type': 'application/json',
|
||
},
|
||
};
|
||
const req = https.request(options, (res) => {
|
||
let data = '';
|
||
res.on('data', chunk => data += chunk);
|
||
res.on('end', () => {
|
||
try { resolve(JSON.parse(data)); }
|
||
catch (e) { resolve({ raw: data }); }
|
||
});
|
||
});
|
||
req.on('error', reject);
|
||
if (body) req.write(JSON.stringify(body));
|
||
req.end();
|
||
});
|
||
}
|
||
|
||
function downloadFile(url, dest) {
|
||
return new Promise((resolve, reject) => {
|
||
const file = fs.createWriteStream(dest);
|
||
const proto = url.startsWith('https') ? https : require('http');
|
||
proto.get(url, (res) => {
|
||
if (res.statusCode >= 300 && res.statusCode < 400) {
|
||
return downloadFile(res.headers.location, dest).then(resolve).catch(reject);
|
||
}
|
||
res.pipe(file);
|
||
file.on('finish', () => { file.close(); resolve(dest); });
|
||
}).on('error', reject);
|
||
});
|
||
}
|
||
|
||
async function generateKlingVideo({ prompt, duration = 5, outputPath, model = 'kling-v2.6-pro' }) {
|
||
console.log('[Kling] 提交文生视频...');
|
||
|
||
// 提交
|
||
const submit = await apiRequest('POST', '/v1/videos/text2video', {
|
||
model,
|
||
prompt,
|
||
duration: Math.min(duration, 10),
|
||
aspect_ratio: '16:9',
|
||
mode: 'standard',
|
||
});
|
||
|
||
if (!submit.task_id) {
|
||
throw new Error(`提交失败: ${JSON.stringify(submit)}`);
|
||
}
|
||
console.log(`[Kling] 任务: ${submit.task_id}`);
|
||
|
||
// 轮询
|
||
for (let i = 1; i <= MAX_POLL; i++) {
|
||
await new Promise(r => setTimeout(r, POLL_INTERVAL));
|
||
const status = await apiRequest('GET', `/v1/videos/${submit.task_id}`);
|
||
|
||
if (status.status === 'completed') {
|
||
const videoUrl = status.video_url || status.output?.video_url;
|
||
if (!videoUrl) throw new Error('任务完成但无视频URL');
|
||
|
||
const out = outputPath || path.join(OUT_DIR, `kling-${submit.task_id}.mp4`);
|
||
fs.mkdirSync(path.dirname(out), { recursive: true });
|
||
console.log(`[Kling] 下载: ${videoUrl.substring(0,60)}...`);
|
||
await downloadFile(videoUrl, out);
|
||
console.log(`[Kling] ✅ ${path.basename(out)}`);
|
||
return { videoPath: out, taskId: submit.task_id };
|
||
}
|
||
|
||
if (status.status === 'failed') {
|
||
throw new Error(`生成失败: ${status.error || JSON.stringify(status)}`);
|
||
}
|
||
|
||
if (i % 10 === 0) console.log(`[Kling] 生成中... (${i}/${MAX_POLL})`);
|
||
}
|
||
throw new Error('超时');
|
||
}
|
||
|
||
module.exports = { generateKlingVideo };
|