/** * 光湖视频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 };