import json, os, subprocess, time, concurrent.futures, datetime, glob, traceback
P='/data/video-pipeline/Youtube-Video-Maker/Project/24052026-001-Ly-Thuong-Kiet'
SCRIPT='/home/onepiece/.openclaw/workspace/skills/gen-img-gpt/scripts/gen_img_gpt.py'
STYLE='/data/video-pipeline/Youtube-Video-Maker/data/ref-img/template1/ref1.png'
OUT=P+'/images/scenes'; LOGD=P+'/logs'; TMP=P+'/tmp/image_prompts_retry'
os.makedirs(TMP,exist_ok=True)
scenes=json.load(open(P+'/script/scenes.json'))
missing=[s for s in scenes if not (os.path.exists(f'{OUT}/scene_{s["scene_id"]:03d}.png') and os.path.getsize(f'{OUT}/scene_{s["scene_id"]:03d}.png')>10000)]
progress_path=LOGD+'/image_generation_progress.json'
def now(): return datetime.datetime.utcnow().isoformat()+'Z'
def save(extra=None):
 done=len(glob.glob(OUT+'/scene_*.png'))
 data={'updated_utc':now(),'project_id':'24052026-001-Ly-Thuong-Kiet','total':len(scenes),'done':done,'remaining':len(scenes)-done,'max_workers':3,'status':'retry_running','retry_missing_start':len(missing)}
 if extra: data.update(extra)
 open(progress_path,'w').write(json.dumps(data,ensure_ascii=False,indent=2))
def one(s):
 sid=s['scene_id']; out=f'{OUT}/scene_{sid:03d}.png'
 if os.path.exists(out) and os.path.getsize(out)>10000: return {'scene_id':sid,'status':'exists'}
 prompt=s['visual_prompt']+' Production scene image for approved story video. Keep exact locked mực loang kể chuyện layout: 16:9 horizontal, warm antique cream paper, central irregular ink-wash window about 65 percent canvas, no pure white, no full bleed, no text, no watermark. Historically grounded Đại Việt Lý dynasty 11th century.'
 last=''
 for attempt in range(1,6):
  try:
   r=subprocess.run(['python3',SCRIPT,'--prompt',prompt,'--input-ref',STYLE,'--output',out,'--size','auto','--quality','auto','--background','auto','--image-detail','high','--output-format','png'],stdout=subprocess.PIPE,stderr=subprocess.PIPE,text=True,timeout=600)
   last=(r.stdout+'\n'+r.stderr)[-2000:]
   if r.returncode==0 and os.path.exists(out) and os.path.getsize(out)>10000:
    open(f'{LOGD}/scene_{sid:03d}_image.retry.log','w').write(last)
    return {'scene_id':sid,'status':'ok','attempt':attempt}
  except Exception:
   last=traceback.format_exc()[-2000:]
  time.sleep(20*attempt)
 open(f'{LOGD}/scene_{sid:03d}_image.RETRY_ERROR.log','w').write(last)
 return {'scene_id':sid,'status':'failed','error':last[-400:]}
save({'note':'retry started'})
failed=[]
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as ex:
 for fut in concurrent.futures.as_completed([ex.submit(one,s) for s in missing]):
  res=fut.result()
  if res['status']=='failed': failed.append(res)
  save({'last_result':res,'failed_count':len(failed)})
save({'status':'completed' if not failed else 'retry_completed_with_failures','failed_count':len(failed),'failed':failed[:20]})
