// 步骤⑧: 逐镜 HLDP 提示词生成 (doubao-seed-2-1-pro) const https = require('https'); const fs = require('fs'); const path = require('path'); const ENV_PATH = path.join(__dirname, '..', '..', '.env'); const ARK_KEY = fs.readFileSync(ENV_PATH, 'utf-8').match(/ARK_API_KEY=(.+)/)[1].trim(); // 10镜合并方案 const SHOTS = [ { id: 'M01', duration: 8, scene: '漆黑画面,警报滴滴声持续。林昊主观视角缓缓睁眼,天花板灯泡忽明忽暗。昏暗灯光下,破旧船员宿舍:两张三层钢架床铺凌乱,空无一人。宿舍唯一的舱门——厚重水密钢门,布满铁锈,上方嵌有矩形铆钉框观察窗。', refs: 'ENV-001-crew-quarters.png (作为场景底板)', camera: 'POV 主观视角,缓慢呼吸感起伏', style: '深海科幻恐怖,3D写实,冷蓝工业光,忽明忽暗' }, { id: 'M02', duration: 8, scene: '林昊抬起双手至脸前,布满老茧,指甲缝嵌满黑色机油污渍。神色迷茫。突然轰隆巨响!船舱猛烈震颤!林昊从下铺猛地坐起,死死抓住床头铁杆固定身体。特写铁杆上镌刻的"秦山号"标记。', refs: 'CHAR-001-林昊, ENV-001-crew-quarters.png', camera: '近景手部→中景全身→推近至铁杆标记特写', style: '同上,镜头随撞击晃动' }, { id: 'M03', duration: 8, scene: '舱外传来极速沉重的脚步声。林昊猛地转头盯向锈迹斑斑的舱门。透过矩形观察窗,一道形状诡异、速度不似人类的黑影飞速闪过。震动渐停,灰尘震落。林昊跳下床,因船体倾斜险些摔倒,扶住床沿。', refs: 'CHAR-001-林昊, ENV-002-hatch-window.png', camera: '中景→快速甩镜至舱门→短暂 POV 透过观察窗', style: '同上,甩镜制造紧张感' }, { id: 'M04', duration: 10, scene: '林昊稳住身形,捂头皱眉,踉跄走向舱门。走到门前,伸手擦拭矩形观察窗内侧玻璃——四层钢化玻璃,内侧擦净,外侧仍被厚重灰尘糊住。拧动舱门把手,伴随刺耳吱呀声,把手纹丝不动。他看向掌心沾满的铁锈。', refs: 'CHAR-001-林昊, ENV-002-hatch-window.png', camera: '中景跟拍走向门→近景擦窗→近景手部+把手', style: '同上,倾斜构图强调船体倾斜' }, { id: 'M05', duration: 6, scene: '林昊瞥见舱门缝下渗出黑色液压油,皱眉面露不耐。转身看见下铺旁悬桌上放着一个硕大黑色破旧工具包。快步走过去,一把拉开拉链。', refs: 'CHAR-001-林昊, ENV-002-hatch-window.png, PROP-001-tool-bag.png', camera: '近景液压油→转身中景→近景拉开拉链', style: '同上' }, { id: 'M06', duration: 6, scene: '工具包内物品:便携式手电筒、备用电源、急救绷带、半米长管钳、军绿水壶,以及一个破旧工牌。推至工牌特写:塑料壳泛黄开裂,编号000768,姓名林昊,岗位模糊不清。照片的人脸部位被利器故意划烂,仅余年轻帅气的下颌轮廓。', refs: 'PROP-001-tool-bag.png, PROP-002-id-badge.png, PROP-003-pipe-wrench.png, PROP-004-flashlight.png', camera: '特写包内物品慢摇→推至工牌极致特写', style: '同上' }, { id: 'M07', duration: 9, scene: '林昊猛抬头看向舱门矩形观察窗——又是一道黑影一闪而逝,更近更快。警报声变急促。林昊面露惧色,压低声音自语,呼吸急促。迅速收起工具包背在身上,抄起半米管钳紧握手中,大步走到舱门前。', refs: 'CHAR-001-林昊, ENV-002-hatch-window.png, PROP-001-tool-bag.png, PROP-003-pipe-wrench.png', camera: '中景抬头→快速甩镜至窗→回林昊恐惧面部→中景武装动作', style: '同上,紧张节奏加快' }, { id: 'M08', duration: 8, scene: '管钳卡住门把手,林昊咬紧牙关猛地用力——把手纹丝不动,铁锈碎屑飘落。盯着门缝下渗出的液压油渍,目光一凛,举管钳高高扬起,冲门把手下方液压凸起狠狠砸下!撞击瞬间:金属变形,白色泄压蒸汽猛然喷出。呲——林昊嘴角微扬,再次用管钳撬动把手,伴随刺耳吱呀声,把手终于缓缓转动。', refs: 'PROP-003-pipe-wrench.png, ENV-002-hatch-window.png', camera: '近景把手+管钳→中景举管钳→撞击晃动→定格雷泄压蒸汽→近景把手转动', style: '同上,动作戏节奏紧凑' }, { id: 'M09', duration: 7, scene: '砰!!一声巨响——一道不似人形的黑影重重砸在舱门外矩形观察窗上。一只手:指甲全部脱落,指尖露出白骨,血肉模糊,顺着玻璃缓缓滑下,留下五道暗红色血痕。然后一张脸贴上玻璃——半人半孢子。右半边:四十岁男人脸,苍白,眼泪滑落,嘴唇无声翕动。左半边:皮肤透明隆起,颗粒蠕动,左眼黑色菌膜覆盖,嘴角撕裂至耳根呈蜂窝状孔洞,黑色孢子在每个孔洞中脉动。每次呼吸,黑色孢子雾从孔洞喷出,蒙上玻璃。', refs: 'ENV-002-hatch-window.png, CHAR-002-半孢感染者', camera: '中景→撞击晃动→慢推至窗外→极致特写半孢脸→推至孢子雾', style: '同上,恐怖高潮,冷蓝光让血呈现近乎黑色' }, { id: 'M10', duration: 5, scene: '林昊僵在原地,瞳孔剧烈收缩,手中紧握的管钳不停发抖。画面骤然全黑。急促警报声拉至最大音量,持续不断。', refs: 'CHAR-001-林昊', camera: '近景林昊面部恐惧→瞳孔特写→渐隐至全黑', style: '同上,尾声渐暗' } ]; function callDoubao(prompt, system) { return new Promise((resolve, reject) => { var payload = JSON.stringify({ model: 'doubao-seed-2-1-pro-260628', messages: [ { role: 'system', content: system }, { role: 'user', content: prompt } ], temperature: 0.3, max_tokens: 512 }); var options = { hostname: 'ark.cn-beijing.volces.com', path: '/api/v3/chat/completions', method: 'POST', headers: { 'Authorization': 'Bearer ' + ARK_KEY, 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload, 'utf-8') } }; var req = https.request(options, function(res) { var body = ''; res.on('data', function(c) { body += c; }); res.on('end', function() { try { var d = JSON.parse(body); if (d.error) { reject(d.error); return; } resolve(d.choices[0].message.content.trim()); } catch(e) { reject(e); } }); }); req.on('error', reject); req.setTimeout(120000, function() { req.destroy(); reject(new Error('timeout')); }); req.write(payload); req.end(); }); } async function main() { var projPath = path.join(__dirname, '..', 'projects', 'deep-sea-voyage'); var outputLines = []; outputLines.push('# 深海迷航 · EP01 · PROMPTS-EP01'); outputLines.push('# 引擎: doubao-seed-2-1-pro-260628'); outputLines.push('# 10镜 · Seedance 2.0 · 720p'); outputLines.push(''); var totalCost = 0; for (var i = 0; i < SHOTS.length; i++) { var s = SHOTS[i]; console.log('--- ' + s.id + ' (' + s.duration + 's) ---'); var cost = (0.5 * s.duration).toFixed(1); totalCost += parseFloat(cost); outputLines.push('## ' + s.id + ' · ' + s.duration + 's'); outputLines.push('△ ' + s.scene); outputLines.push('相机: ' + s.camera); outputLines.push('参考图: ' + s.refs); outputLines.push(''); // AI 生成英文 Seedance prompt var sysPrompt = '你是一个专业的 AI 视频生成提示词工程师。将中文场景描述转化为 Seedance 2.0 英文视频生成提示词。不超过 200 词。包含景别、动作、灯光、风格。不要加引号。'; var userPrompt = '场景: ' + s.scene + '\n相机运动: ' + s.camera + '\n风格: ' + s.style; console.log(' 调用AI生成英文提示词...'); try { var seedancePrompt = await callDoubao(userPrompt, sysPrompt); outputLines.push('Seedance prompt:'); outputLines.push(seedancePrompt); outputLines.push(''); console.log(' ✅ ' + s.id + ' (' + seedancePrompt.length + ' chars)'); } catch(e) { outputLines.push('Seedance prompt: [生成失败: ' + (e.message || e) + ']'); outputLines.push(''); console.log(' ❌ ' + s.id + ': ' + (e.message || e)); } } outputLines.push('---'); outputLines.push('## 成本预估'); outputLines.push(''); outputLines.push('| M# | 时长 | 单价 | 费用 |'); outputLines.push('|:--:|:--:|:--:|:--:|'); for (var j = 0; j < SHOTS.length; j++) { var s2 = SHOTS[j]; var c = (0.5 * s2.duration).toFixed(1); outputLines.push('| ' + s2.id + ' | ' + s2.duration + 's | ¥0.5/s | ¥' + c + ' |'); } outputLines.push('| **合计** | **75s** | — | **¥' + totalCost.toFixed(1) + '** |'); var outPath = path.join(projPath, 'PROMPTS-EP01.hdlp'); fs.writeFileSync(outPath, outputLines.join('\n'), 'utf-8'); console.log('\n🎬 SAVED: ' + outPath); console.log('总计 10镜 75s 预估 ¥' + totalCost.toFixed(1)); } main().catch(function(e) { console.error('FATAL:', e.message || e); });