#!/usr/bin/env python3
from pathlib import Path
import hashlib,json,subprocess,sys,datetime,os
ROOT=Path('/data/video-pipeline/HaTramAudio/project/026-Ngay-Chung-Ta-Xoa-Ten-Khoi-Giay-Dang-Ky-Ket-Hon');RUN='run-20260722T033406Z-3df8cc80';WORK=ROOT/'work/artwork';GEN=Path.home()/'.hermes/skills/content-creation/tao-anh/scripts/generate_image.py';CANON='a124ee39d569ab043105b755f9a3c10a2c92a1b3edccb2162ec2ab8767fc1f7f';TITLE='Ngày Chúng Ta Xóa Tên Khỏi Giấy Đăng Ký Kết Hôn'
def sha(p):
 h=hashlib.sha256()
 with p.open('rb') as f:
  for b in iter(lambda:f.read(8<<20),b''):h.update(b)
 return h.hexdigest()
def atomic(p,o):
 p.parent.mkdir(parents=True,exist_ok=True);q=p.with_suffix(p.suffix+'.tmp');q.write_text(json.dumps(o,ensure_ascii=False,indent=2)+'\n');os.replace(q,p)
def now():return datetime.datetime.now(datetime.timezone.utc).isoformat()
assert sha(ROOT/'story/canon.txt')==CANON and json.loads((ROOT/'story/story-qa.json').read_text())['verified']
IH=sha(ROOT/'story/identity-registry.json');RH=sha(ROOT/'story/reveal-ledger.json')
shared='''Key art ngôn tình đô thị cưới trước yêu sau tại Hàng Châu hư cấu, digital illustration bán hiện thực điện ảnh cao cấp, mưa nhẹ bên kênh nhà cổ, xanh ngọc xám pha hổ phách ấm, tối giản, một focal point, không collage/card/slide/mockup, không mô phỏng người thật. Tống Dư An 30 tuổi, nữ kiến trúc sư châu Á hư cấu, tóc đen ngang vai, áo khoác kem, bình tĩnh và tự chủ. Lục Cảnh Hành 33 tuổi, nam quản lý quỹ bảo tồn châu Á hư cấu, tóc đen gọn, áo khoác xanh than, điềm tĩnh, đứng cách cô một khoảng tôn trọng. Motif công khai: hai chiếc chìa khóa đồng cũ, hồ sơ đăng ký khép lại, mái ngói Hàng Châu và mưa trên cửa kính. Không lộ email đầy đủ, kết luận kiểm toán, lời tỏ tình sau ly hôn, thủ đoạn của Chính Phong hay kết quả đấu thầu. Mọi giấy, bảng, biển, nhãn, màn hình, đồng hồ và đạo cụ nền phải trơn, không chữ, không số, không pseudo-text, logo hay watermark. Provider render hình và typography hoàn chỉnh cùng raster; không chừa chỗ hậu kỳ.\n'''
prompts={'intro_poster':shared+f'''Tạo poster ngang chính xác 16:9, master 1920x1080. Dư An là focal point trước căn nhà ven kênh, cầm một chìa khóa; Cảnh Hành ở lớp sau dưới mái hiên, giữa họ là hồ sơ khép kín không chữ. Provider tự quyết typography. RENDER CHÍNH XÁC BA KHỐI CHỮ TIẾNG VIỆT, KHÔNG THÊM CHỮ KHÁC:\n“Hạ Trâm Audio”\n“{TITLE}”\n“Truyện được phát độc quyền tại Hạ Trâm Audio, nghiêm cấm sao chép dưới mọi hình thức”\nGiữ nguyên dấu, dễ đọc, không cắt/che.''','right_panel':shared+f'''Tạo key art dọc tỷ lệ chính xác 656:1080, master 1080x1778. Dư An focal point trước cổng nhà gỗ ven kênh, chìa khóa trong tay; Cảnh Hành đứng dưới mưa ở lớp sau, không tiếp xúc. Provider tự quyết typography. RENDER CHÍNH XÁC BA KHỐI CHỮ TIẾNG VIỆT, KHÔNG THÊM CHỮ KHÁC:\n“Hạ Trâm Audio”\n“{TITLE}”\n“Truyện được phát độc quyền tại Hạ Trâm Audio, nghiêm cấm sao chép dưới mọi hình thức”\nGiữ nguyên dấu, dễ đọc, không cắt/che.''','left_panel':'''Tạo branding panel điện ảnh dọc tỷ lệ chính xác 656:1080, master 1080x1778. Góc phòng thu ấm áp nhìn ra kênh Hàng Châu đêm mưa, microphone và tai nghe trơn, ánh hổ phách trên nền xanh ngọc xám; không nhân vật, không tên truyện, không dòng độc quyền, không layout giả. Mọi đạo cụ không chữ/số/logo/watermark. Provider render typography hoàn chỉnh. RENDER CHÍNH XÁC HAI KHỐI CHỮ TIẾNG VIỆT, KHÔNG THÊM CHỮ KHÁC:\n“Hạ Trâm Audio”\n“Like • Chia sẻ • Đăng ký”\nGiữ nguyên dấu, dễ đọc, không cắt/che.'''}
WORK.mkdir(parents=True,exist_ok=True);bundle={'schema_version':1,'project_id':'026','run_id':RUN,'status':'locked','verified':True,'source_canon_sha256':CANON,'identity_registry_sha256':IH,'reveal_ledger_sha256':RH,'provider_skill':'tao-anh','provider_model':'cx/gpt-5.5-image','text_postprocessing_allowed':False,'items':{}}
for role,prompt in prompts.items():
 pp=WORK/f'{role}.prompt.txt';pp.write_text(prompt);bundle['items'][role]={'prompt_path':str(pp.relative_to(ROOT)),'prompt_sha256':sha(pp)}
atomic(ROOT/'script/image-prompts.json',bundle)
for role in ['intro_poster','left_panel','right_panel']:
 out=WORK/f'{role}-provider.png';rec=WORK/f'{role}.generation.json';item=bundle['items'][role];attempt={'schema_version':1,'project_id':'026','run_id':RUN,'role':role,'status':'requesting','verified':False,'source_canon_sha256':CANON,'identity_registry_sha256':IH,'reveal_ledger_sha256':RH,'prompt_sha256':item['prompt_sha256'],'output':str(out.relative_to(ROOT)),'provider_skill':'tao-anh','text_postprocessed':False,'created_at':now()};atomic(rec,attempt)
 r=subprocess.run([sys.executable,str(GEN),'--prompt',(ROOT/item['prompt_path']).read_text(),'--output',str(out),'--n','1','--size','auto','--quality','auto','--background','auto','--detail','high','--format','png','--timeout','600'],stdout=subprocess.PIPE,stderr=subprocess.PIPE,text=True,timeout=720)
 if r.returncode or not out.exists():attempt.update({'status':'failed','error':(r.stderr or r.stdout)[-1000:]});atomic(rec,attempt);raise RuntimeError(role)
 attempt.update({'status':'generated','technical_verified':True,'artifact_sha256':sha(out),'artifact_bytes':out.stat().st_size,'completed_at':now()});atomic(rec,attempt)
print(json.dumps({'status':'generated_awaiting_visual_qa','roles':list(prompts)},ensure_ascii=False))
