#!/usr/bin/env python3
from pathlib import Path
import os,json,hashlib,requests,datetime
P='gacmai_20260718_091744';R=Path('/data/video-pipeline/GacMaiAudio/project')/P;A=R/'artifacts'
def env(path):
 for line in Path(path).read_text(errors='ignore').splitlines():
  line=line.strip()
  if line and not line.startswith('#') and '=' in line:
   k,v=line.split('=',1);os.environ.setdefault(k.strip(),v.strip().strip('"\''))
def sha(p):return hashlib.sha256(Path(p).read_bytes()).hexdigest()
env('/opt/OpenMontage/.env')
assets={'intro':R/'assets/images/intro_1920x1080.png','left':R/'assets/images/left_600x1080.png','right':R/'assets/images/right_600x1080.png','composite':R/'assets/images/three_panel_layout.png','audio':R/'assets/audio/narration_final.wav'}
for p in assets.values():assert p.exists(),p
shas={k:sha(v) for k,v in assets.items()};audio=json.loads((A/'audio_master_qc.json').read_text());visual=json.loads((A/'visual_campaign_acceptance.json').read_text())
assert audio['status']=='passed' and audio['audio_sha256']==shas['audio'] and audio['full_decode']=='passed'
assert visual['status']=='passed' and visual['render_visuals_authorized'] is True and visual['normalized']['layout']==shas['composite']
now=datetime.datetime.now(datetime.timezone.utc).isoformat();auth={'status':'authorized','project_id':P,'story_sha256':'fd016b65cfd699e9d4e97c5e491894135117a12d56c2b467204ab68efd68be98','audio_qc_sha256':sha(A/'audio_master_qc.json'),'visual_acceptance_sha256':sha(A/'visual_campaign_acceptance.json'),'input_sha256':shas,'output':str(R/'render/final_master.mp4'),'gpu_nvenc_only':True,'authorized_at':now};(A/'render_authorization.json').write_text(json.dumps(auth,ensure_ascii=False,indent=2)+'\n')
for k,p in assets.items():assert sha(p)==auth['input_sha256'][k]
base='http://192.168.1.104:8020';key=next((os.environ.get(k) for k in ('GACMAI_RENDER_API_KEY','GPU_RENDER_API_KEY','RENDER_API_KEY','OPENMONTAGE_RENDER_API_KEY') if os.environ.get(k)),None)
if not key:raise SystemExit('render API key unavailable')
h={'X-API-Key':key};health=requests.get(base+'/health',headers=h,timeout=20);health.raise_for_status();hd=health.json();assert hd.get('status')=='ok' and hd.get('h264_nvenc') is True
body={'frame':str(assets['composite']),'intro_poster':str(assets['intro']),'intro_visual_end':6.5,'audio':str(assets['audio']),'footage_dir':'/data/video-pipeline/GacMaiAudio/footage','output':auth['output'],'seed':20260718091744,'pattern':'gacmai-*.mp4','fps':24}
r=requests.post(base+'/v1/jobs',headers={**h,'Content-Type':'application/json'},json=body,timeout=30);r.raise_for_status();d=r.json();jid=d.get('job_id') or d.get('id');assert jid
rec={'status':'submitted','job_id':jid,'status_url':base+'/v1/jobs/'+jid,'request':body,'authorization_sha256':sha(A/'render_authorization.json'),'health':hd,'expected':{'renderer':'h264_nvenc','source_audio_discarded':True,'horizontal_mirror':'hflip'}};(A/'gpu_render_submission.json').write_text(json.dumps(rec,ensure_ascii=False,indent=2)+'\n');print(json.dumps({'status':'submitted','job_id':jid,'status_url':rec['status_url']}))
