from pathlib import Path
p=Path('/opt/struktur/social-media-agent/publish_ready.py')
s=p.read_text()
old='from codex_image_adapter import CodexImageError, generate_with_codex'
new='from codex_image_adapter import CodexImageError, generate_with_codex\nfrom codex_image_qa import CodexImageQAError, qa_passes, run_image_qa'
assert s.count(old)==1
s=s.replace(old,new)
start=s.index('def generate_package_image(')
end=s.index('\n\ndef _direct_url',start)
replacement='''def generate_package_image(package_id: str, *, force: bool = False) -> dict:
"""Generate Codex images, run technical vision QA, and fail closed."""
con = sqlite3.connect(CASES_DB); con.row_factory = sqlite3.Row
row = con.execute("SELECT * FROM publication_packages WHERE package_id=?", (package_id,)).fetchone()
if not row:
con.close(); raise ValueError("publication package not found")
package = dict(row); old_version = int(package.get("image_version") or 0)
prompt_base = fach_image_prompt(package)
prompt_ok, prompt_reason = image_relevance_gate(package, prompt_base)
if not prompt_ok:
con.execute("UPDATE publication_packages SET image_status='error',image_error=?,qa_status='failed',qa_failure_reasons=?,updated_at=? WHERE package_id=?", (prompt_reason, prompt_reason, _now(), package_id)); con.commit(); con.close()
return {"ok": False, "status": "Bild fachlich unpassend", "error": prompt_reason}
feedback: list[str] = []
last_result: dict[str, Any] = {}
for attempt in range(1, 4):
prompt = prompt_base
if feedback:
prompt += " Korrigiere zwingend diese Fehler des vorherigen Versuchs: " + "; ".join(feedback) + "."
target = (BASE_DIR / "generated_visuals" / f"{package['signal_id']}_codex-image-gen-v{old_version + attempt}.png").resolve()
try:
generated = generate_with_codex(prompt, target)
qa = run_image_qa(target, _text(package.get("topic")), _text(package.get("final_text") or package.get("facebook_text")))
last_result = qa
report_json = json.dumps(qa, ensure_ascii=False)
if qa_passes(qa):
now = _now()
con.execute("UPDATE publication_packages SET image_status='present',image_path=?,image_created_at=?,image_generator=?,image_version=?,image_error='',image_prompt=?,image_prompt_used=?,media_source_type='Codex built-in image_gen',media_source_ref=?,media_quality='technisch geprüft — visuelle Abnahme offen',qa_status='passed',qa_report_json=?,qa_failure_reasons='',qa_checked_at=?,updated_at=? WHERE package_id=?", (str(target), now, "Codex built-in image_gen", old_version + attempt, prompt, prompt, generated["origin_path"], report_json, now, now, package_id))
con.commit(); con.close()
return {"ok": True, "status": "Bild technisch geprüft — visuelle Abnahme offen", "path": str(target), "version": old_version + attempt, "generator": "Codex built-in image_gen", "qa": qa, "attempts": attempt}
feedback = qa.get("failure_reasons", []) or ["Technische Bildprüfung nicht bestanden."]
reason = "; ".join(feedback)
con.execute("UPDATE publication_packages SET image_status='error',image_path=?,image_generator='Codex built-in image_gen',image_version=?,image_error=?,media_source_type='Codex built-in image_gen',media_source_ref=?,media_quality='TECHNISCH ABGELEHNT',qa_status='failed',qa_report_json=?,qa_failure_reasons=?,qa_checked_at=?,updated_at=? WHERE package_id=?", (str(target), old_version + attempt, "Technische Bildprüfung nicht bestanden: " + reason, generated["origin_path"], report_json, reason, _now(), _now(), package_id)); con.commit()
except (CodexImageError, CodexImageQAError, OSError, ValueError) as exc:
feedback = [str(exc)]
con.execute("UPDATE publication_packages SET image_status='error',image_generator='Codex built-in image_gen',image_version=?,image_error=?,media_quality='TECHNISCH ABGELEHNT',qa_status='failed',qa_failure_reasons=?,qa_checked_at=?,updated_at=? WHERE package_id=?", (old_version + attempt, "Technische Bildprüfung nicht bestanden: " + str(exc), str(exc), _now(), package_id)); con.commit()
if attempt < 3:
continue
con.close()
return {"ok": False, "status": "Kein technisch plausibles KI-Bild gefunden", "error": "; ".join(feedback), "qa": last_result, "attempts": attempt}
con.close()
return {"ok": False, "status": "Kein technisch plausibles KI-Bild gefunden", "attempts": 3}
'''
s=s[:start]+replacement+s[end:]
needle=''' "image_usage_json": "TEXT NOT NULL DEFAULT '{}'",'''
insert=''' "image_usage_json": "TEXT NOT NULL DEFAULT '{}'",\n "qa_status": "TEXT NOT NULL DEFAULT 'not_checked'", "qa_report_json": "TEXT NOT NULL DEFAULT '{}'", "qa_failure_reasons": "TEXT NOT NULL DEFAULT ''", "qa_checked_at": "TEXT NOT NULL DEFAULT ''",'''
assert s.count(needle)==1
s=s.replace(needle,insert)
p.write_text(s)
print('patched publish_ready with QA')