145 lines
6.7 KiB
JavaScript
Raw Normal View History

// 场景底板法T2I → I2I
// ENV-001 底板 → ENV-002 i2i 放大
// D181 · 2026-07-10 · 耳耳蛋签发
const https = require('https');
const fs = require('fs');
const path = require('path');
function loadEnv(filePath) {
const content = fs.readFileSync(filePath, 'utf-8');
const key = content.match(/ARK_API_KEY=(.+)/);
return key ? key[1].trim() : null;
}
const ENV_PATH = path.join(__dirname, '..', '..', '.env');
const ARK_KEY = loadEnv(ENV_PATH);
console.log('密钥: ' + ARK_KEY.substring(0, 15) + '...');
const OUT_DIR = path.join(__dirname, '..', 'projects', 'deep-sea-voyage', 'outputs');
// === T2I ===
function jimengT2I(prompt, outputPath) {
return new Promise((resolve, reject) => {
const payload = JSON.stringify({
model: 'doubao-seedream-4-0-250828',
prompt: prompt,
size: '1024x1024',
n: 1
});
const options = {
hostname: 'ark.cn-beijing.volces.com',
path: '/api/v3/images/generations',
method: 'POST',
headers: {
'Authorization': 'Bearer ' + ARK_KEY,
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(payload, 'utf-8')
}
};
const req = https.request(options, (res) => {
let body = '';
res.on('data', (chunk) => { body += chunk; });
res.on('end', () => {
try {
const data = JSON.parse(body);
if (data.error) { reject(new Error(JSON.stringify(data.error))); return; }
const imageUrl = data.data?.[0]?.url;
if (!imageUrl) { reject(new Error('No image URL: ' + body.substring(0, 300))); return; }
https.get(imageUrl, (imgRes) => {
const chunks = [];
imgRes.on('data', (chunk) => chunks.push(chunk));
imgRes.on('end', () => {
fs.writeFileSync(outputPath, Buffer.concat(chunks));
console.log('✅ ' + outputPath + ' (' + (Buffer.concat(chunks).length / 1024).toFixed(1) + ' KB)');
resolve(outputPath);
});
}).on('error', reject);
} catch (e) { reject(e); }
});
});
req.on('error', reject);
req.write(payload);
req.end();
});
}
// === I2I场景底板法 ===
function jimengI2I(prompt, referenceImgPath, outputPath) {
return new Promise((resolve, reject) => {
const imgBuf = fs.readFileSync(referenceImgPath);
const imgB64 = imgBuf.toString('base64');
const payload = JSON.stringify({
model: 'doubao-seedream-4-0-250828',
prompt: prompt,
image: 'data:image/png;base64,' + imgB64,
size: '1024x1024',
n: 1,
response_format: 'url'
});
const options = {
hostname: 'ark.cn-beijing.volces.com',
path: '/api/v3/images/generations',
method: 'POST',
headers: {
'Authorization': 'Bearer ' + ARK_KEY,
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(payload, 'utf-8')
}
};
const req = https.request(options, (res) => {
let body = '';
res.on('data', (chunk) => { body += chunk; });
res.on('end', () => {
try {
const data = JSON.parse(body);
if (data.error) { reject(new Error(JSON.stringify(data.error))); return; }
const imageUrl = data.data?.[0]?.url;
if (!imageUrl) { reject(new Error('No image URL: ' + body.substring(0, 300))); return; }
https.get(imageUrl, (imgRes) => {
const chunks = [];
imgRes.on('data', (chunk) => chunks.push(chunk));
imgRes.on('end', () => {
fs.writeFileSync(outputPath, Buffer.concat(chunks));
console.log('✅ ' + outputPath + ' (' + (Buffer.concat(chunks).length / 1024).toFixed(1) + ' KB)');
resolve(outputPath);
});
}).on('error', reject);
} catch (e) { reject(e); }
});
});
req.on('error', reject);
req.write(payload);
req.end();
});
}
// === 执行:两步走 ===
async function main() {
const ENV001_V5 = path.join(OUT_DIR, 'ENV-001-crew-quarters-v5.png');
const ENV002_V5 = path.join(OUT_DIR, 'ENV-002-hatch-window-v5.png');
// 第1步T2I 生成 ENV-001 底板
console.log('=== 第1步: T2I 生成 ENV-001 底板 ===\n');
console.log('生成秦山号船员宿舍 v5底板图...\n');
const MASTER_PROMPT = `Interior of a cramped, decaying crew quarters in a deep-sea mining vessel "Qin Shan". Two sets of messy three-tier steel bunk beds with tangled gray blankets. Rusty metal bulkhead walls with visible pipe lines and grime. Oily puddles on the visibly tilted metal floor. The only exit is a heavy-duty STEEL WATERTIGHT BULKHEAD DOOR — rounded corners, thick steel plate, multiple locking dogs (clamps) around its edge. In the upper portion of the door, a small reinforced RECTANGULAR INSPECTION PORT (window) with thick glass and a bolted/riveted steel frame — like a submarine hatch window, NOT a domestic house window. Below the door handle, mounted ON THE DOOR FRAME, is a compact INDUSTRIAL HYDRAULIC ACTUATOR with metal fittings and visible wear. Black hydraulic fluid seeping from the actuator seal and pooling under the door gap. A malfunctioning lightbulb on the ceiling flickers dim, sickly cold blue industrial light, casting sharp swaying shadows across the tilted room. Deep-sea industrial horror, claustrophobic, 3D, photorealistic, very high detail.`;
try {
await jimengT2I(MASTER_PROMPT, ENV001_V5);
// 第2步I2I 用底板生成 ENV-002 局部放大
console.log('\n=== 第2步: I2I 底板法 → ENV-002 局部放大 ===\n');
console.log('以 ENV-001 为底板i2i 放大舱门区域...\n');
const I2I_PROMPT = `Same exact room and door as the reference image. The camera is now zoomed in tightly on THE SAME WATERIGHT BULKHEAD DOOR seen in the reference. Frame the shot to show the UPPER HALF of the door clearly: the small reinforced rectangular inspection port with thick glass and bolted/riveted steel frame (exactly as in the reference), and the lower portion with the door handle and the compact hydraulic actuator mounted on the door frame. The inside glass of the inspection port is smeared partially clean, outside is caked with grime. Black hydraulic fluid seeping from the actuator. Same flickering cold blue light, same rusted bulkhead, same tilted floor, same deep-sea industrial horror atmosphere. 3D, photorealistic, close-up, shallow depth of field, very high detail. Keep the door, window, hydraulic actuator, lighting and colors IDENTICAL to the reference image.`;
await jimengI2I(I2I_PROMPT, ENV001_V5, ENV002_V5);
console.log('\n🎬 底板法完成ENV-001(v5底板) + ENV-002(v5 i2i放大) 现在属于同一扇门。');
} catch (e) {
console.error('❌ 失败: ' + e.message);
}
}
main();