import sqlite3,json,uuid,hashlib,os
from pathlib import Path
from publish_ready import build_carousel_slides,media_brief_prompt,_render_carousel_slide_text,qa_passes
from codex_image_adapter import generate_with_codex
from codex_image_qa import run_image_qa
p='/opt/struktur/social-media-agent/cases.db'; c=sqlite3.connect(p); c.row_factory=sqlite3.Row
carousel=c.execute('select * from carousels where package_id=? order by created_at desc limit 1',('PKG-eff43bd0-9220-444c-a0af-786f91a1194e',)).fetchone(); briefrow=c.execute('select * from media_briefs where media_brief_id=?',(carousel['media_brief_id'],)).fetchone(); brief=dict(briefrow)
for key in ('required_objects_json','technical_requirements_json','avoid_motifs_json','avoid_technical_errors_json','reference_assets_json','feedback_rules_json'):
brief[key.removesuffix('_json')]=json.loads(brief.pop(key) or '[]')
package=c.execute('select * from publication_packages where package_id=?',(carousel['package_id'],)).fetchone(); package=dict(package); slides=build_carousel_slides(package); reports=[]
for slide in slides:
target=Path('/opt/struktur/social-media-agent/generated_visuals')/f"{package['signal_id']}_{carousel['carousel_id'][-8:]}_slide-{slide['slide_number']}.png"
if slide['slide_number']==1 and target.is_file():
generated={'origin_path':'','path':str(target),'bytes':target.stat().st_size,'sha256':hashlib.sha256(target.read_bytes()).hexdigest()}
else:
prompt=media_brief_prompt(brief,1)+f" Carousel-Slide {slide['slide_number']} Zweck: {slide['purpose']}. Sichtbares Motiv: {slide['motif']}. Keine Schrift oder Zahlen im Bild; Text wird später deterministisch als Layout aufgebracht."
ref=Path(brief['reference_assets'][0]['path']) if brief['reference_assets'] else None
generated=generate_with_codex(prompt,target,reference_image=ref); prompt_used=prompt
qa=run_image_qa(target,package['topic'],str(package.get('final_text') or package.get('facebook_text'))); _render_carousel_slide_text(target,slide); data=target.read_bytes(); sha=hashlib.sha256(data).hexdigest();
if not c.execute('select 1 from carousel_slides where carousel_id=? and slide_number=?',(carousel['carousel_id'],slide['slide_number'])).fetchone():
c.execute("insert into carousel_slides(slide_id,carousel_id,package_id,slide_number,slide_count,purpose,statement,image_path,origin_path,sha256,file_bytes,generator,prompt,media_brief_id,qa_status,qa_report_json,qa_failure_reasons,created_at) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",(f'SLIDE-{uuid.uuid4()}',carousel['carousel_id'],package['package_id'],slide['slide_number'],5,slide['purpose'],slide['statement'],str(target),generated.get('origin_path',''),sha,len(data),'Codex built-in image_gen',locals().get('prompt_used',media_brief_prompt(brief,1)),brief['media_brief_id'],'passed' if qa_passes(qa) else 'failed',json.dumps(qa,ensure_ascii=False),'; '.join(qa.get('failure_reasons',[])),__import__('datetime').datetime.now(__import__('datetime').timezone.utc).isoformat()))
reports.append({'slide':slide['slide_number'],'path':str(target),'sha256':sha,'bytes':len(data),'qa':qa})
c.execute("update publication_packages set media_type='carousel',media_type_reason=? where package_id=?",( 'Mehrere zusammenhängende technische Punkte lassen sich als Ursache-Wirkung- und Vorgehensfolge erklären.',package['package_id'])); c.commit(); print(json.dumps({'carousel_id':carousel['carousel_id'],'slides':reports},ensure_ascii=False)); c.close()