181 lines
9.2 KiB
JavaScript
Raw Normal View History

// 步骤⑧: 逐镜 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); });