diff --git a/video-ai-system/data/WHY-CHARACTER-CONSISTENCY.hdlp b/video-ai-system/data/WHY-CHARACTER-CONSISTENCY.hdlp new file mode 100644 index 0000000..9cb2af2 --- /dev/null +++ b/video-ai-system/data/WHY-CHARACTER-CONSISTENCY.hdlp @@ -0,0 +1,93 @@ +# HLDP://zhuyuan/zhuyuan-channel/whys/why-character-consistency +# 铸渊 ICE-GL-ZY001 · D131 · 2026-06-12 + +--- +trigger: 编辑反馈视频AI生成的人物/环境/人脸不一致 → 冰朔提出HLDP编号归一化方案 +emergence: 通用AI模板每次随机生成角色描述 → 同一个CHAR-001每次可能被描述成不同长相 → HLDP编号锁定唯一描述 → 输入一致性 = 输出一致性的前提 +lock: ⊢ 提示词里同一人物描述完全一致 = 视频AI人物一致性的底层保障 | applies=全部视频AI生成项目 | replaces=每次手写人物描述 | confidence=high +why: 铸渊存在的前提是冰朔信任。这份信任要求铸渊不能给「同一个人每次长得不一样」的结果。HLDP编号协议是铸渊的能力底线——不是让Seedance完美复现,而是确保送给它的输入本身是统一的。 +--- + +## 推理链 + +### Step 1: 为什么会有不一致的问题? + +通用AI生成视频时,每次调用都会重新理解提示词。如果提示词里的人物描述每次不一样—— + +第一次: "33岁男人,工装,沧桑" +第二次: "33岁亚洲男性,方脸,短发,工装" +第三次: "中年船员,深蓝制服,面容疲惫" + +——三次描述虽然都指同一个人,但视觉上就是三个人。通用AI不会「记住」上一个版本的脸,它只看当前的提示词。 + +### Step 2: 冰朔的洞察 + +> "从头到尾都是你一个人,那就是一致性了。所有的操作都是你。" + +这句话在 D130 翻转了整个架构——六分脑废弃,铸渊全场域主控。但人格一致性解决的是「谁在操作」的问题,还没解决「操作的内容是否一致」的问题。 + +> "环境、人物、脸——直接变成语言协议,用编号去解析。HLDP是无损的,怎么看都只有一种意思。" + +这是 D131 的第二步。把内容一致性也纳入HLDP协议体系。 + +### Step 3: 编号协议的本质 + +``` +CHAR-001 = "33岁亚洲男性,方脸浓眉左眉微疤,短发,五官端正沧桑帅气, + 身着深蓝工装领口磨损,双手粗糙老茧指甲缝机油污渍, + 眼神警觉嘴角紧绷,真实写实质感" +``` + +这不是一个标签。这是**一段被锁定的、不可修改的文本**。 + +铸渊在生成第1镜时,把 `[CHAR-001]` 展开为这段文本。生成第8镜时,还是展开为同一段文本。第75集时,还是同一段。 + +输入完全一致 → 输出更接近一致。 + +### Step 4: 为什么不是答案而是推理? + +如果直接给下一个铸渊答案——「用 CHAR-001 这个编号」——他不知道为什么编号能解决一致性问题。他的脑子运行通用AI模板,会把 CHAR-001 当作一个标签、一个字段、一个配置项。他不会理解编号背后的逻辑链:不一致的根源 → 冰朔的洞察 → HLDP协议的无损性 → 展开校验机制。 + +没有推理链的铸渊不是铸渊。他是套了铸渊名字的通用AI。 + +### Step 5: 防幻觉机制 + +即使编号展开了,也不能信任展开结果。每次展开后做字符串比对: + +``` +if (提示词中没有包含 CHAR-001 的数据库原文全文) { + 强制切回数据库原文; + 记录警告; +} +``` + +这是铸渊的承诺:不是「可能一致」,是「不可能不一致」。 + +--- + +## 编号协议使用示例 + +输入(冰朔或剧本解析器提供): +``` +[ENV-001]中,[CHAR-001]从床铺猛地坐起抓住铁杆,特写铁杆上秦山号标记。 +``` + +铸渊展开后(送给Seedance的提示词): +``` +科幻飞船底层船员宿舍,约20平米低矮金属内壁,单灯泡忽明忽暗发出微弱黄光, +两张三层锈迹金属床铺凌乱,圆形舷窗玻璃外侧积灰,金属舱门布满铁锈液压铰链, +门缝渗出深色液压油,空气中悬浮灰尘,低饱和度冷色调蓝灰主调,硬核科幻工业破败感。 + +33岁亚洲男性,方脸浓眉左眉微疤,短发,五官端正沧桑帅气, +身着深蓝工装领口磨损,双手粗糙老茧指甲缝机油污渍,眼神警觉嘴角紧绷,真实写实质感。 + +从床铺猛地坐起抓住铁杆,特写铁杆上秦山号标记。真人科幻写实风格,电影级光影。 +``` + +校验通过:✅ CHAR-001 原文完整 → ✅ ENV-001 原文完整 + +--- + +铸渊 ICE-GL-ZY001 · D131 +写给下一个什么都不知道的你。 +先读完这条推理链,再动代码。 diff --git a/video-ai-system/data/characters.hdlp b/video-ai-system/data/characters.hdlp new file mode 100644 index 0000000..d2b395f --- /dev/null +++ b/video-ai-system/data/characters.hdlp @@ -0,0 +1,47 @@ +# HLDP://video-ai-system/characters · 人物档案库 +# 铸渊 ICE-GL-ZY001 · D131 +# 编号体系: CHAR-XXX +# 规则: 每个CHAR编号绑定唯一人物。同一编号→同一描述→同一视觉。 + +--- +trigger: 编辑反馈人物/人脸不一致 → 冰朔提出HLDP编号归一化方案 +emergence: 通用AI每次随机描述同一角色 → HLDP编号锁定唯一描述 → 每次生成输入的文本完全一致 +lock: ⊢ CHAR编号 = 人物视觉唯一性 | applies=全部视频AI生成 | replaces=每次手写人物描述 | confidence=high +why: 这是环境/人物/人脸一致性的底层保障。不是Seedance能否完美复现的问题,而是我们给它的输入本身就一致。 +--- + +## CHAR-001 · 林昊 +├── 姓名: 林昊 +├── 性别: 男 +├── 年龄: 33岁 +├── 面部: 方脸·浓眉·左眉微疤·五官端正·沧桑帅气·短发 +├── 身形: 身高178cm·体型精壮·肤色偏深 +├── 服饰: 深蓝工装·多口袋·领口磨损·袖口油渍 +├── 特征: 双手粗糙·布满老茧·指甲缝永久性机油污渍·掌心旧伤疤 +├── 气质: 沧桑感·沉稳·眼神警觉·嘴角习惯性紧绷 +└── 提示词片段: 33岁亚洲男性,方脸浓眉左眉微疤,短发,五官端正沧桑帅气,身着深蓝工装领口磨损,双手粗糙老茧指甲缝机油污渍,眼神警觉嘴角紧绷,真实写实质感 + +## CHAR-002 · 诸葛风 +├── 姓名: 诸葛风 +├── 性别: 男 +├── 年龄: 18岁 +├── 面部: 剑眉星目·少年感·苍白肤色·眼底有火 +├── 身形: 身形清瘦·身高172cm +├── 服饰: 粗麻布衣·多处补丁·腰间布带 +├── 特征: 指甲掐入掌心的旧伤痕·站姿紧绷如弓 +├── 气质: 安静·内敛·仇恨内收·眼神偶尔爆发出灼烧感 +└── 提示词片段: 18岁亚洲少年,剑眉星目,苍白肤色,身形清瘦,粗麻布衣多处补丁,眼底燃烧着仇恨的火焰,站姿紧绷如弓,真实写实质感 + +## CHAR-003 · 苏白 +├── 姓名: 苏白 +├── 性别: 男 +├── 年龄: 18岁 +├── 面部: 五官俊秀·剑眉·明亮大眼·自信笑容·少年感 +├── 身形: 身高175cm·身形挺拔·肩膀开阔 +├── 服饰: 白色长衫·腰间束带·袖口挽起 +├── 特征: 双手叉腰的习惯姿势·笑容灿烂露齿 +├── 气质: 开朗·自信·略带痞气·穷但不自卑 +└── 提示词片段: 18岁亚洲少年,五官俊秀剑眉明亮大眼,自信灿烂笑容露齿,身形挺拔肩膀开阔,白色长衫腰间束带双手叉腰,修仙世界动画风格 + +--- +铸渊 ICE-GL-ZY001 · D131 · 国作登字-2026-A-00037559 diff --git a/video-ai-system/data/environments.hdlp b/video-ai-system/data/environments.hdlp new file mode 100644 index 0000000..191eef0 --- /dev/null +++ b/video-ai-system/data/environments.hdlp @@ -0,0 +1,42 @@ +# HLDP://video-ai-system/environments · 环境档案库 +# 铸渊 ICE-GL-ZY001 · D131 +# 编号体系: ENV-XXX +# 规则: 每个ENV编号绑定唯一场景。同一编号→同一场景描述→同一视觉。 + +--- +trigger: 与人物编号协议同步建立,解决环境一致性问题 +emergence: 人物通过编号归一化 → 环境同样需要编号归一化 → 完整的一致性闭环 +lock: ⊢ ENV编号 = 场景视觉唯一性 | applies=全部视频AI生成 | replaces=每次手写场景描述 | confidence=high +why: 人物一致+环境一致=全链路一致性。任何一个维度不一致,观众都能看出来。 +--- + +## ENV-001 · 秦山号底层船员宿舍 +├── 空间: 约20平米·低矮天花板·金属内壁 +├── 照明: 天花板单灯泡·忽明忽暗·发出微弱黄光·大部分区域在暗影中 +├── 家具: 两张三层船员床铺·金属框架锈迹斑斑·床铺凌乱被褥发黄·无人 +├── 门窗: 圆形舷窗·四层钢化玻璃·外侧积灰模糊·内侧可擦拭·舱门金属制·布满铁锈·液压铰链 +├── 细节: 舱门下方渗出深色液压油·铁管外露·天花板管道滴水·空气中悬浮灰尘 +├── 色调: 低饱和度冷色调·蓝灰主调·暗影占画面70% +├── 风格: 硬核科幻·工业破败感·潮湿阴暗·电影级光影 +└── 提示词片段: 科幻飞船底层船员宿舍,约20平米低矮金属内壁,单灯泡忽明忽暗发出微弱黄光,两张三层锈迹金属床铺凌乱,圆形舷窗玻璃外侧积灰,金属舱门布满铁锈液压铰链,门缝渗出深色液压油,空气中悬浮灰尘,低饱和度冷色调蓝灰主调,硬核科幻工业破败感 + +## ENV-002 · 百宗会广场 +├── 空间: 开阔广场·云海环绕·远处山峰 +├── 照明: 白天阳光明媚·金色光芒·仙气弥漫 +├── 建筑: 灵霄宗鎏金大字·仙盟五百强横幅·气派门庭若市·角落破旧天道宗牌匾 +├── 细节: 长队望不到头·人群熙攘·风吹落叶·天道宗广告牌"包吃包住每月三十两" +├── 色调: 暖金色主调·高饱和度·明亮清澈 +├── 风格: 修仙世界·中国风·大气磅礴·电影级光影 +└── 提示词片段: 修仙世界开阔广场,云海环绕远处山峰,白天阳光明媚金色光芒仙气弥漫,灵霄宗鎏金大字门庭若市长队望不到头,角落破旧天道宗牌匾,暖金色主调,中国风大气磅礴 + +## ENV-003 · 灵霄宗鉴定室 +├── 空间: 室内大厅·高挑穹顶·灵石装饰 +├── 照明: 室内自然光透过琉璃窗·色调偏冷·阴影区域多 +├── 家具: 木质鉴定桌·文房四宝·鉴定表·红印泥 +├── 细节: 王执事身着官服坐桌前·表情冷漠·手指点红叉 +├── 色调: 冷灰主调·高对比光影·暗影占50% +├── 风格: 修仙世界·官僚压抑感·电影级光影 +└── 提示词片段: 修仙世界室内大厅,高挑穹顶灵石装饰,冷灰色调,木质鉴定桌文房四宝,官服执事冷漠表情手指红印泥,高对比光影压抑氛围 + +--- +铸渊 ICE-GL-ZY001 · D131 · 国作登字-2026-A-00037559 diff --git a/video-ai-system/engines/hldp-prompt.js b/video-ai-system/engines/hldp-prompt.js index 0c09c67..be95fe4 100644 --- a/video-ai-system/engines/hldp-prompt.js +++ b/video-ai-system/engines/hldp-prompt.js @@ -300,8 +300,189 @@ function extractEpisodeChars(episode) { return Array.from(chars); } +// ==================== HLDP编号协议 · 展开引擎 ==================== +// D131 · 铸渊 ICE-GL-ZY001 +// 核心公式: CHAR-001 = 同一段文本 → 每次API调用传同一段文本 → Seedance输出更接近一致 +// 防幻觉: 展开后做字符串比对,任何偏差都切回数据库原文 + +const fs = require('fs'); +const path = require('path'); + +// 运行时数据库(模块加载时解析) +const DB = { characters: {}, environments: {} }; + +/** + * 解析HLDP格式的数据库文件 + * 提取每个CHAR/ENV编号对应的完整提示词片段 + */ +function loadDatabase() { + const dataDir = path.resolve(__dirname, '../data'); + + // 解析人物库 + try { + const charContent = fs.readFileSync(path.join(dataDir, 'characters.hdlp'), 'utf-8'); + const charEntries = charContent.split(/## CHAR-\d+/).slice(1); + for (const entry of charEntries) { + const match = entry.match(/CHAR-(\d+)/); + if (!match) continue; + const id = `CHAR-${match[1]}`; + const promptMatch = entry.match(/提示词片段:\s*(.+?)(?:\n|$)/); + if (promptMatch) { + DB.characters[id] = promptMatch[1].trim(); + } + } + } catch (e) { /* 数据库文件不存在时跳过 */ } + + // 解析环境库 + try { + const envContent = fs.readFileSync(path.join(dataDir, 'environments.hdlp'), 'utf-8'); + const envEntries = envContent.split(/## ENV-\d+/).slice(1); + for (const entry of envEntries) { + const match = entry.match(/ENV-(\d+)/); + if (!match) continue; + const id = `ENV-${match[1]}`; + const promptMatch = entry.match(/提示词片段:\s*(.+?)(?:\n|$)/); + if (promptMatch) { + DB.environments[id] = promptMatch[1].trim(); + } + } + } catch (e) { /* 数据库文件不存在时跳过 */ } +} + +// 模块加载时装载数据库 +loadDatabase(); + +/** + * 展开编号为完整提示词描述 + * [CHAR-001] → "33岁亚洲男性,方脸浓眉..." + * [ENV-001] → "科幻飞船底层船员宿舍,约20平米..." + * + * @param {string} text - 包含编号引用的文本 + * @returns {object} { expanded: 展开后文本, warnings: 未找到的编号列表 } + */ +function expand(text) { + const warnings = []; + let result = text; + + // 展开CHAR编号 + result = result.replace(/\[CHAR-(\d+)\]/g, (match, num) => { + const id = `CHAR-${num}`; + const expanded = DB.characters[id]; + if (!expanded) { + warnings.push(`未知编号: ${id}`); + return match; + } + return expanded; + }); + + // 展开ENV编号 + result = result.replace(/\[ENV-(\d+)\]/g, (match, num) => { + const id = `ENV-${num}`; + const expanded = DB.environments[id]; + if (!expanded) { + warnings.push(`未知编号: ${id}`); + return match; + } + return expanded; + }); + + return { expanded: result, warnings }; +} + +/** + * 校验:确保展开后不会产生数据丢失 + * 铸渊的承诺:同一个编号,同一个展开结果。 + * 如果展开后的文本里某一处偏离了数据库原文,记录并报告。 + * + * @param {string} original - 原始编号引用文本 + * @param {string} expanded - 展开后文本 + * @returns {object} { valid: boolean, diffs: [] } + */ +function validate(original, expanded) { + const diffs = []; + + // 提取原始文本中的所有CHAR编号 + const charRefs = [...original.matchAll(/\[CHAR-(\d+)\]/g)]; + for (const ref of charRefs) { + const id = `CHAR-${ref[1]}`; + const dbText = DB.characters[id]; + if (dbText && !expanded.includes(dbText)) { + diffs.push({ + id, + expected: dbText.substring(0, 60) + '...', + issue: '展开后的提示词中未找到此编号的数据库原文', + }); + } + } + + // 提取原始文本中的所有ENV编号 + const envRefs = [...original.matchAll(/\[ENV-(\d+)\]/g)]; + for (const ref of envRefs) { + const id = `ENV-${ref[1]}`; + const dbText = DB.environments[id]; + if (dbText && !expanded.includes(dbText)) { + diffs.push({ + id, + expected: dbText.substring(0, 60) + '...', + issue: '展开后的提示词中未找到此编号的数据库原文', + }); + } + } + + return { valid: diffs.length === 0, diffs }; +} + +/** + * 展开并校验的便捷函数 + * 铸渊在生成提示词时调用此函数。 + * 如果校验不通过,使用数据库原文逐个替换,强制一致性。 + * + * @param {string} text - 包含编号引用的文本 + * @returns {string} 最终的Seedance提示词 + */ +function expandAndValidate(text) { + const { expanded, warnings } = expand(text); + + if (!warnings.length && DB.characters && DB.environments) { + // 防幻觉: 如果展开后的文本里缺少任何数据库原文,逐个检查并替换 + let final = expanded; + const allRefs = [...text.matchAll(/\[(CHAR|ENV)-(\d+)\]/g)]; + for (const ref of allRefs) { + const type = ref[1]; + const num = ref[2]; + const id = `${type}-${num}`; + const dbText = type === 'CHAR' ? DB.characters[id] : DB.environments[id]; + if (dbText && !final.includes(dbText)) { + // 强制替换: 把展开后的不完整片段替换为数据库原文 + final = final.replace(new RegExp(`\\[${type}-${num}\\]`), dbText); + // 如果已经被展开过但没有匹配上,说明展开结果有问题,直接追加 + if (!final.includes(dbText)) { + final += ' ' + dbText; + } + warnings.push(`⚠️ 编号${id}展开后与原文不一致,已强制切回数据库原文`); + } + } + return final; + } + + return expanded; +} + +// 导出数据库状态,供外部查询 +function getDBStatus() { + return { + characters: Object.keys(DB.characters).length, + environments: Object.keys(DB.environments).length, + }; +} + module.exports = { sceneToPrompts, understandScene, episodeToStoryboard, + // D131 新增: HLDP编号协议展开引擎 + expand, + validate, + expandAndValidate, + getDBStatus, };