Files
the-silent-gods-hearthfire/tools/build-live-review.py
T

43 lines
5.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""生成本地双版本导航与真人素材审看页,不依赖网络。"""
import csv
import html
import io
import json
from pathlib import Path
ROOT=Path(__file__).resolve().parent.parent
LIVE=ROOT/'08_真人AI短剧'
assets=json.loads((LIVE/'02_资产/全部资产任务.json').read_text(encoding='utf8'))
receipts={}
notes_path=LIVE/'05_检查与交付/图像审看提示.json'
notes=json.loads(notes_path.read_text(encoding='utf8')) if notes_path.exists() else {}
for p in (LIVE/'02_资产/生成回执').glob('*.json'):
r=json.loads(p.read_text(encoding='utf8'));receipts[r['id']]=r
cards=[];rows=[]
for a in assets:
r=receipts.get(a['id']);exists=bool(r and (LIVE/r['path']).is_file())
status='REVIEW' if exists else '待生成'
kind='角色' if a['kind']=='character' else '场景'
picpath=r['path'] if exists else ''
note=notes.get(a['id'],'')
row={'资产ID':a['id'],'名称':a['name'],'类别':kind,'状态':status,'图片':picpath, '提示词':'04_生成与后期/逐项出图提示词/'+a['id']+'.txt','原生尺寸':'×'.join(map(str,r['size'])) if exists and r.get('size') else '', '身份':a.get('identity',''),'审看提示':note,'角色批准':'未批准','动作验证':'未测试'}
rows.append(row)
title=html.escape(a['name']);aid=html.escape(a['id'])
picture=f'<a href="{html.escape(picpath)}"><img loading="lazy" src="{html.escape(picpath)}" alt="{title}"></a>' if exists else '<div class="pending">待生成</div>'
note_html=f'<p class="note">{html.escape(note)}</p>' if note else ''
identity_html=f'<p>{html.escape(a.get("identity",""))}</p>' if a.get('identity') else ''
cards.append(f'<article data-kind="{kind}" data-status="{status}" data-search="{html.escape(a["name"]+" "+a["id"]+" "+a.get("identity",""))}">{picture}<h2>{title}</h2><p>{aid}</p>{identity_html}<p>{kind} · {status}</p>{note_html}<a href="{html.escape(row["提示词"])}">查看完整提示词</a></article>')
done=sum(r['状态']=='REVIEW' for r in rows)
page='''<!doctype html><html lang="zh-CN"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>真人AI短剧素材审看</title><style>
body{margin:0;background:#11151a;color:#f0ede5;font:16px/1.6 system-ui,"Microsoft YaHei",sans-serif}header{padding:38px max(5vw,22px);background:linear-gradient(110deg,#233d3e,#161c29)}h1{font-size:30px;margin:0 0 8px}a{color:#bde7d7}nav{display:flex;flex-wrap:wrap;gap:18px}section{padding:24px max(5vw,22px)}.controls{display:flex;gap:12px;flex-wrap:wrap}input,select{font:inherit;padding:9px 12px;background:#242b33;border:1px solid #50636b;color:#fff;border-radius:6px}.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:22px}article{background:#20272e;border:1px solid #354148;padding:12px;border-radius:10px}img,.pending{width:100%;height:300px;object-fit:contain;background:#13181d}.pending{display:grid;place-items:center;color:#9ba6ac}h2{font-size:18px;margin:12px 0 5px}article p{font-size:12px;color:#c6ced1;word-break:break-all;margin:5px 0}[hidden]{display:none!important}</style>
<header><h1>真人AI奇幻短剧素材审看</h1><p>COUNT · 每项可查看原图与实际出图提示词。REVIEW表示已出候选,尚未作者批准或动作验证。</p><nav><a href="README.md">真人制作入口</a><a href="01_剧本/第一季12集_真人阅读合订本.md">12集完整剧本</a><a href="../影像制作总览.md">双版本总览</a><a href="../06_AI动漫制作/README.md">动漫制作入口</a></nav></header>
<section class="controls"><input id="q" placeholder="搜索角色 场景 名称或编号"><select id="kind"><option value="">全部类别</option><option>角色</option><option>场景</option></select><select id="status"><option value="">全部状态</option><option>REVIEW</option><option>待生成</option></select><span id="visible"></span></section><section class="grid">CARDS</section><script>
const q=document.querySelector('#q'),kind=document.querySelector('#kind'),status=document.querySelector('#status'),items=[...document.querySelectorAll('article')];function filter(){let n=0;for(const x of items){const ok=x.dataset.search.toLowerCase().includes(q.value.toLowerCase())&&(!kind.value||x.dataset.kind===kind.value)&&(!status.value||x.dataset.status===status.value);x.hidden=!ok;if(ok)n++}document.querySelector('#visible').textContent='显示 '+n+' 项'}for(const x of [q,kind,status])x.addEventListener('input',filter);filter();</script></html>'''
page=page.replace('COUNT',f'已生成 {done} / {len(assets)} 项').replace('CARDS','\n'.join(cards))
(LIVE/'素材审看.html').write_text(page,encoding='utf8')
out=io.StringIO(newline='');w=csv.DictWriter(out,list(rows[0]),delimiter='\t',lineterminator='\n');w.writeheader();w.writerows(rows)
(LIVE/'02_资产/资产制作总表.tsv').write_text(out.getvalue(),encoding='utf8')
report={'total':len(assets),'generated':done,'remaining':len(assets)-done,'characters':sum(a['kind']=='character' for a in assets),'environments':sum(a['kind']=='environment' for a in assets),'missing':[a['id'] for a in assets if not (receipts.get(a['id']) and (LIVE/receipts[a['id']]['path']).is_file())]}
(LIVE/'05_检查与交付/图像生成进度.json').write_text(json.dumps(report,ensure_ascii=False,indent=2)+'\n',encoding='utf8')
print(json.dumps({k:v for k,v in report.items() if k!='missing'},ensure_ascii=False))