auto-save 2026-05-14 13:21 (~3)

This commit is contained in:
2026-05-14 13:21:46 +08:00
parent 22f8885b97
commit 4e4e5395bc
3 changed files with 101 additions and 27 deletions

View File

@@ -1,19 +1,5 @@
{
"entries": [
{
"files_changed": 1,
"hash": "92794f6",
"message": "auto-save 2026-05-13 07:27 (~1)",
"ts": "2026-05-13T07:27:19+08:00",
"type": "commit"
},
{
"files_changed": 1,
"hash": "ced696f",
"message": "auto-save 2026-05-13 07:33 (~1)",
"ts": "2026-05-13T07:33:13+08:00",
"type": "commit"
},
{
"files_changed": 1,
"hash": "af608ef",
@@ -3280,6 +3266,19 @@
"type": "session-heartbeat",
"message": "Codex 会话活跃 · 最近命令codex · 3 项未提交变更 · 最近提交auto-save 2026-05-14 13:10 (~5)",
"files_changed": 3
},
{
"ts": "2026-05-14T13:16:15+08:00",
"type": "commit",
"message": "auto-save 2026-05-14 13:16 (~3)",
"hash": "22f8885",
"files_changed": 3
},
{
"ts": "2026-05-14T05:18:40Z",
"type": "session-heartbeat",
"message": "Codex 会话活跃 · 最近命令codex · 3 项未提交变更 · 最近提交auto-save 2026-05-14 13:16 (~3)",
"files_changed": 3
}
]
}

View File

@@ -629,7 +629,7 @@ api/main.py
</div>
<div class="flow-row">
<div><strong>你看到的区域</strong><span>关键帧素材审核面板</span></div>
<div><strong>主要源码</strong><span><code>FrameLightbox</code>;按“原图/清洗、主体资产、首尾帧、产品融合、审核”五个页签组织;左侧只放主图/框选画布,但主体资产页左侧改为全部已清洗/已选参考帧网格,首尾帧页左侧显示全部关键帧并可勾选人物/机位参考。主体识别页会显示透明骨架人目标和 Vision 验收分数。清洗页右侧支持一键清洗未处理帧、单张替换清洗版和一键替换全部待应用清洗版;批量替换顺序调用 <code>applyCleanedFrame</code>,不新增后端接口。产品融合页左侧是纵向 6 行镜头工作表:顶部选择 5 个内置透明骨架人角色之一,每行只显示已预填场景/产品使用/享受描述、秒数、生成按钮和对应视频结果;描述词内置 36 条镜头语言模板,按“建立出场、产品入画、佩戴贴合、使用感受、生活延展、收尾记忆”排列,点击“换一组”只刷新 6 行描述词。四张桌面 SKG 产品图和所选角色 7 张参考图作为固定参考,生成时分别通过 <code>copyProductLibraryAsset</code><code>copyCharacterLibraryAssets</code> 自动写入当前 job不再暴露产品角度槽、产品融合辅助栏、产品图库选择器或首尾帧槽。主体资产页只确认一个统一主体后端按参考重绘六张纯背景、占满画面的标准站立透明骨架人资产图首尾帧页保留给旧流程/单独生图,不再是产品融合必填步骤。相关接口包括 <code>cleanupFrame</code><code>applyCleanedFrame</code><code>addElement</code><code>generateSubjectAssets</code><code>generateSceneAsset</code><code>copyProductLibraryAsset</code><code>copyCharacterLibraryAssets</code></span></div>
<div><strong>主要源码</strong><span><code>FrameLightbox</code>;按“原图/清洗、主体资产、首尾帧、产品融合、审核”五个页签组织;左侧只放主图/框选画布,但主体资产页左侧改为全部已清洗/已选参考帧网格,首尾帧页左侧显示全部关键帧并可勾选人物/机位参考。主体识别页会显示透明骨架人目标和 Vision 验收分数。清洗页右侧支持一键清洗未处理帧、单张替换清洗版和一键替换全部待应用清洗版;批量替换顺序调用 <code>applyCleanedFrame</code>,不新增后端接口。产品融合页左侧是纵向 6 行镜头工作表:顶部选择 5 个内置透明骨架人角色之一,每行只显示已预填场景/产品使用/享受描述、秒数、生成按钮和对应视频结果;描述词内置 36 条镜头语言模板,按“建立出场、产品入画、佩戴贴合、使用感受、生活延展、收尾记忆”排列,并且会按角色自动改写场景气质、使用动作和享受状态。每行还内置角色参考图调度:例如正面/半身用于出场,侧面/背部特写用于佩戴贴合,半身/背部特写用于收尾产品记忆点。点击“换一组”只刷新 6 行描述词。四张桌面 SKG 产品图和所选角色 7 张参考图作为固定参考,生成时分别通过 <code>copyProductLibraryAsset</code><code>copyCharacterLibraryAssets</code> 自动写入当前 job不再暴露产品角度槽、产品融合辅助栏、产品图库选择器或首尾帧槽。主体资产页只确认一个统一主体后端按参考重绘六张纯背景、占满画面的标准站立透明骨架人资产图首尾帧页保留给旧流程/单独生图,不再是产品融合必填步骤。相关接口包括 <code>cleanupFrame</code><code>applyCleanedFrame</code><code>addElement</code><code>generateSubjectAssets</code><code>generateSceneAsset</code><code>copyProductLibraryAsset</code><code>copyCharacterLibraryAssets</code></span></div>
<div><strong>适合怎么描述</strong><span>“这一组关键帧如何共同生成一个统一主体包;某张关键帧的水印、去主体场景图、产品融合镜头组和质量风险应该如何审核”。</span></div>
</div>
<div class="flow-row">
@@ -928,7 +928,7 @@ SubjectAsset {
</header>
<div class="body">
<p><strong>问题:</strong>当前产品融合不再需要手动首帧/尾帧,用户要的是从内置透明骨架人角色、场景描述、产品使用方式和享受状态直接生成视频。</p>
<p><strong>改动:</strong>桌面 <code>skg_anatomy_characters_20260514_120852</code> 的 5 个角色、35 张图内置为 <code>api/character_library/skg-characters</code>。产品融合页新增角色下拉和角色预览,每行只保留场景/产品使用/享受描述、秒数、生成按钮和结果视频;生成前自动复制所选角色 7 张参考图和固定 4 张 SKG 产品图到当前 job。</p>
<p><strong>改动:</strong>桌面 <code>skg_anatomy_characters_20260514_120852</code> 的 5 个角色、35 张图内置为 <code>api/character_library/skg-characters</code>。产品融合页新增角色下拉和角色预览,每行只保留场景/产品使用/享受描述、秒数、生成按钮和结果视频;选择不同角色时6 行描述会自动改成对应角色的场景气质、产品使用动作和享受状态,并自主写入“本镜头主要参考哪几张角色图、生成什么场景”。生成前自动复制所选角色 7 张参考图和固定 4 张 SKG 产品图到当前 job。</p>
<p><strong>后端:</strong>新增 <code>GET /character-library/skg</code><code>GET /character-library/skg/images/{filename}</code><code>POST /jobs/{job_id}/assets/character-library</code>。视频提交新增 <code>subject_images</code>,无首帧时主人物图以 <code>reference_image</code> role 传入 Ark/Seedance而不是强制作为 <code>first_frame</code></p>
<p><strong>影响:</strong><code>api/main.py</code><code>api/character_library/skg-characters</code><code>web/lib/api.ts</code><code>web/app/page.tsx</code><code>web/components/lightbox.tsx</code><code>docs/source-analysis.html</code></p>
</div>

View File

@@ -194,39 +194,107 @@ const PRODUCT_FUSION_DESCRIPTION_PRESETS = [
"备用30舒适微表情佩戴稳定后透明骨架人眼神变柔和、嘴角轻扬肩颈线条放松镜头从产品细节回到脸部保持广告级质感。",
]
const CHARACTER_PROMPT_PROFILES: Record<string, { name: string; subject: string; scenes: string; usage: string; enjoyment: string }> = {
const FUSION_STAGE_PLANS = [
{
refs: "正面 + 半身近景",
product: "产品先在桌面、床头或手边出现,人物尚未佩戴,负责建立角色和场景",
result: "角色成立、场景成立、观众看到 SKG 产品即将被使用",
},
{
refs: "正面 + 左45度 + 产品正面/侧面",
product: "手把 SKG 从桌面或包中拿起带入画面,产品沿手部运动靠近后颈",
result: "产品进入画面自然,不悬浮,尺寸开始和人物肩颈建立关系",
},
{
refs: "侧面 + 背部特写 + 产品侧面/背面",
product: "SKG 准确落到脖子、后颈、颈肩交界处,双手扶两端微调贴合",
result: "重点解决佩戴位置、产品尺寸、透视和后颈贴合真实性",
},
{
refs: "半身近景 + 侧面",
product: "产品已经稳定佩戴,人物轻按控制区或保持佩戴状态",
result: "表现闭眼、肩部下沉、呼吸放慢、舒适享受,但不做医疗疗效承诺",
},
{
refs: "正面 + 左45度/右45度",
product: "人物在生活场景中继续佩戴 SKG产品位置稳定不漂移不变形",
result: "展示真实使用中的生活方式,人物、场景和产品统一",
},
{
refs: "半身近景 + 背部特写 + 产品主视角",
product: "收尾停在肩颈和产品清楚可辨的位置,手不遮挡产品关键轮廓",
result: "形成广告记忆点:角色舒适、产品清楚、画面干净高级",
},
]
const CHARACTER_PROMPT_PROFILES: Record<string, { name: string; subject: string; stageScenes: string[]; usage: string; enjoyment: string }> = {
"character-01": {
name: "运动阳光男",
subject: "清爽运动阳光男透明骨架人,身形挺拔、年轻有活力,整体气质健康明亮",
scenes: "晨练后卧室、阳台休息区、明亮健身房休息长椅或运动后居家放松场景",
stageScenes: [
"晨练后的明亮卧室阳光从窗边进入SKG 放在床头或运动包旁",
"健身房休息长椅旁,人物从运动包中拿起 SKG",
"阳台休息区侧面近景,阳光照到后颈和白色骨架",
"运动后客厅或卧室半身近景,背景清爽明亮",
"窗边拉伸区或瑜伽垫旁,人物轻松活动肩颈",
"干净白色广告背景或明亮卧室收尾特写",
],
usage: "运动后双手拿起 SKG准确戴到后颈和颈肩交界处轻按侧边控制区并微调贴合",
enjoyment: "从运动后的颈肩紧绷变成轻松舒展,闭眼深呼吸、肩部下沉、露出阳光放松微笑",
},
"character-02": {
name: "都市型男",
subject: "都市通勤型男透明骨架人,穿搭利落,高层公寓和商务感更强",
scenes: "高层公寓客厅、办公桌、商务休息区、夜晚城市窗边或会议间隙",
stageScenes: [
"高层公寓客厅或落地窗前,桌面上摆着 SKG",
"办公桌前或商务休息区,人物从桌面拿起 SKG",
"办公椅侧面近景,后颈和颈肩区域清楚可见",
"夜晚城市窗边半身近景,灯光克制高级",
"会议间隙的安静休息区,人物靠回椅背继续佩戴",
"高层公寓半身收尾,产品在后颈位置清楚可辨",
],
usage: "久坐办公后从桌面拿起 SKG戴到后颈手指轻按按键让产品稳定贴合颈肩",
enjoyment: "从低头疲惫、揉脖子变为靠回椅背放松,眼神平静、嘴角微扬,呈现高效恢复感",
},
"character-03": {
name: "优雅白领女",
subject: "优雅白领女透明骨架人,姿态端正、干净精致,商业广告感更高级",
scenes: "办公室午休区、极简卧室、化妆镜前、柔和落地窗旁或精致公寓客厅",
stageScenes: [
"精致公寓客厅或柔和落地窗旁SKG 放在小桌上",
"办公室午休区或化妆镜前,人物优雅拿起 SKG",
"镜前或窗边侧面近景,后颈线条和白色骨架清楚",
"极简卧室半身近景,柔和光线突出放松表情",
"办公室休息区继续佩戴,动作克制自然",
"高级广告式半身收尾,产品轮廓和人物微笑都清楚",
],
usage: "工作间隙优雅拿起 SKG轻放到后颈双手细致调整两端贴合动作慢而自然",
enjoyment: "从肩颈紧绷转为安静舒缓,闭眼微笑、呼吸放慢,呈现精致、自洽、舒服的状态",
},
"character-04": {
name: "运动辣妹",
subject: "运动辣妹透明骨架人,线条利落、活力强,适合健身后和生活方式广告",
scenes: "健身房更衣区、瑜伽垫旁、阳光客厅、运动后休息区或浴室镜前",
stageScenes: [
"健身房更衣区或瑜伽垫旁SKG 放在水杯和毛巾旁",
"运动后休息区,人物从健身包或桌面拿起 SKG",
"浴室镜前或瑜伽垫旁侧面近景,后颈和肩线清楚",
"阳光客厅半身近景,人物闭眼放松",
"运动后休息区继续佩戴,轻轻侧头伸展",
"健身生活方式广告收尾,产品贴合后颈且轮廓清晰",
],
usage: "训练后拿起 SKG 戴到后颈,侧头伸展时保持产品稳定贴合,手部不遮挡产品轮廓",
enjoyment: "从训练后的酸胀紧绷变为轻松舒展,闭眼享受、肩颈打开,表情自信舒服",
},
"character-05": {
name: "绅士大叔",
subject: "成熟绅士大叔透明骨架人,气质稳重高级,适合书房、客厅和商务休息场景",
scenes: "木质书房、皮质休闲椅、安静客厅、窗边阅读角或商务酒店房间",
stageScenes: [
"木质书房或皮质休闲椅旁SKG 放在书桌边",
"窗边阅读角,人物从桌边稳稳拿起 SKG",
"书房侧后方近景,后颈、颈椎和背部特写参考清楚",
"安静客厅半身近景,灯光温暖克制",
"商务酒店房间或书房里继续佩戴阅读休息",
"成熟高级的半身收尾,产品清楚、人物从容微笑",
],
usage: "阅读或工作后从桌边拿起 SKG稳稳戴到后颈轻扶两端调整到颈肩正确位置",
enjoyment: "从沉稳疲惫变为从容舒适,缓慢闭眼、肩部放松、轻轻微笑,表达成熟克制的享受",
},
@@ -235,10 +303,15 @@ const CHARACTER_PROMPT_PROFILES: Record<string, { name: string; subject: string;
const fusionDescriptionForCharacter = (characterId: string, presetIndex: number) => {
const base = PRODUCT_FUSION_DESCRIPTION_PRESETS[presetIndex % PRODUCT_FUSION_DESCRIPTION_PRESETS.length]
const profile = CHARACTER_PROMPT_PROFILES[characterId] ?? CHARACTER_PROMPT_PROFILES[DEFAULT_CHARACTER_ID]
const stage = presetIndex % FUSION_SHOT_COUNT
const stagePlan = FUSION_STAGE_PLANS[stage]
const scene = profile.stageScenes[stage] || profile.stageScenes[0]
return [
base,
`角色设定:${profile.subject}`,
`场景倾向:${profile.scenes}`,
`自主图像编排:本镜头主要参考角色图【${stagePlan.refs}】,场景生成【${scene}`,
`产品调度:${stagePlan.product}`,
`镜头目标:${stagePlan.result}`,
`产品使用:${profile.usage};产品只能在脖子、后颈、颈肩交界处使用,尺寸必须符合真实颈部按摩仪比例。`,
`享受状态:${profile.enjoyment};不要医疗治疗承诺,不要恐怖解剖感。`,
].join("\n")
@@ -264,7 +337,7 @@ const createFusionShots = (): ProductFusionShot[] =>
person_image: null,
product_region: null,
scene_image: null,
action_text: PRODUCT_FUSION_DESCRIPTION_PRESETS[i % PRODUCT_FUSION_DESCRIPTION_PRESETS.length],
action_text: fusionDescriptionForCharacter(DEFAULT_CHARACTER_ID, i),
duration: 5,
image_model: "gpt-image-2",
video_model: "seedance",
@@ -544,7 +617,7 @@ export function FrameLightbox({ jobId, frames, generatedVideos = [], activeIndex
const start = (page * FUSION_SHOT_COUNT) % PRODUCT_FUSION_DESCRIPTION_PRESETS.length
const next = fusionShots.map((shot, i) => ({
...shot,
action_text: PRODUCT_FUSION_DESCRIPTION_PRESETS[(start + i) % PRODUCT_FUSION_DESCRIPTION_PRESETS.length] || shot.action_text,
action_text: fusionDescriptionForCharacter(selectedCharacterId, start + i),
}))
setFusionPresetPage(page)
setFusionShots(next)
@@ -554,10 +627,12 @@ export function FrameLightbox({ jobId, frames, generatedVideos = [], activeIndex
const selectFusionCharacter = (characterId: string) => {
const character = characterLibrary.find((item) => item.id === characterId)
const next = fusionShots.map((shot) => ({
const start = (fusionPresetPage * FUSION_SHOT_COUNT) % PRODUCT_FUSION_DESCRIPTION_PRESETS.length
const next = fusionShots.map((shot, i) => ({
...shot,
character_id: characterId,
character_name: character?.name || shot.character_name || DEFAULT_CHARACTER_NAME,
action_text: fusionDescriptionForCharacter(characterId, start + i),
subject_image: null,
subject_images: [],
}))
@@ -1274,7 +1349,7 @@ export function FrameLightbox({ jobId, frames, generatedVideos = [], activeIndex
void persistFusionShots(next)
}}
placeholder="写清场景、产品如何佩戴到脖子/后颈,以及人物舒适享受状态。"
className="h-[92px] w-full resize-none rounded-md border border-white/10 bg-black/35 px-2 py-1.5 text-[10px] leading-relaxed text-white/75 outline-none placeholder:text-white/25 focus:border-amber-300/45"
className="h-[148px] w-full resize-none rounded-md border border-white/10 bg-black/35 px-2 py-1.5 text-[10px] leading-relaxed text-white/75 outline-none placeholder:text-white/25 focus:border-amber-300/45"
/>
</label>