from pathlib import Path
p=Path('/opt/struktur/social-media-agent/publish_ready.py')
s=p.read_text()
s=s.replace('from urllib.parse import urlparse\n', 'from urllib.parse import urlparse\nfrom openai_image_adapter import OpenAIImageError, generate_with_openai_image\n')
start=s.index('def fach_image_prompt(package: dict) -> str:\n')
end=s.index('\n\ndef image_relevance_gate', start)
new='''def fach_image_prompt(package: dict) -> str:\n """Build a professional, topic-specific prompt; Mallorca is secondary context."""\n pillar = _text(package.get("content_pillar") or package.get("topic_category"))\n topic = _text(package.get("topic")) or "Hohe Luftfeuchte Mallorca"\n statement = _text(package.get("relevance") or package.get("evidence_summary"))\n low = f"{pillar} {topic} {statement}".casefold()\n if "luftqualität" in low or "luftqualitaet" in low or "co2" in low or "voc" in low:\n motif = "professionelles CO2-Messgerät, VOC-/Luftqualitätssensor und Hygrometer"\n action = "Fachperson führt eine Luftqualitätsmessung durch und prüft die Messwerte"\n elif "lüft" in low or "lueft" in low:\n motif = "reales dezentrales Lüftungsgerät mit Innenblende und Wanddurchführung"\n action = "Fachperson misst direkt am Lüftungsgerät und prüft die technische Montage"\n elif "monitor" in low or "homeprotect" in low or "sensor" in low:\n motif = "realer Raumklimasensor mit Smartphone oder Tablet zur Messdatendarstellung"\n action = "Fachperson kontrolliert Feuchte-, Temperatur- und Luftqualitätsdaten"\n elif "objekt" in low or "bestands" in low or "prüfung" in low:\n motif = "Grundriss, professionelles Messgerät, Fenster, Wand und Raumdetails"\n action = "Fachperson führt eine technische Bestandsaufnahme von Raum und Gebäudehülle durch"\n else:\n motif = "professionelles digitales Feuchtemessgerät an einer Innenwand, dezente sichtbare Feuchtespur und Kondensation"\n action = "Fachperson prüft die Innenwand sachlich mit dem Feuchtemessgerät"\n return (f"Content-Pillar: {pillar}. Konkrete Aussage des Posts: {topic}. {statement}. "\n f"Sichtbares fachliches Hauptmotiv: {motif}. Technische Handlung: {action}. "\n "Realistischer Innenraum einer mediterranen Wohnimmobilie auf Mallorca als dezenter Gebäudekontext, "\n "professionelle technische Gebäudediagnostik, glaubwürdige Proportionen, natürliche sachliche Fotografie, "\n "scharfer Fokus auf dem Messgerät oder Sensor. Keine erfundenen Marken, Logos, Produktnamen, lesbaren Fantasiewerte "\n "oder technisch unmöglichen Einbausituationen. Ausschließen: Strand, Meer, Küstenpanorama, touristische Straße, "\n "Sehenswürdigkeiten, Palmen als Hauptmotiv, Luxusvilla ohne Technikbezug, Reise-/Postkartenästhetik, primitive Infografik, "\n "Comicstil, Icons, Diagramm-Fallback, Text im Bild, Fantasieschrift.")\n'''
s=s[:start]+new+s[end:]
start=s.index('def generate_package_image(package_id: str, *, force: bool = False) -> dict:\n')
end=s.index('\n\ndef _direct_url', start)
new='''def generate_package_image(package_id: str, *, force: bool = False) -> dict:\n """Generate exactly one OpenAI image from an explicit cockpit action."""\n con = sqlite3.connect(CASES_DB); con.row_factory = sqlite3.Row\n row = con.execute("SELECT * FROM publication_packages WHERE package_id=?", (package_id,)).fetchone()\n if not row:\n con.close(); raise ValueError("publication package not found")\n package = dict(row)\n old_path = valid_package_image_path(package)\n old_version = int(package.get("image_version") or 0)\n prompt = fach_image_prompt(package)\n prompt_ok, prompt_reason = image_relevance_gate(package, prompt)\n if not prompt_ok:\n con.execute("UPDATE publication_packages SET image_status='error',image_error=?,updated_at=? WHERE package_id=?", (prompt_reason, _now(), package_id)); con.commit(); con.close()\n return {"ok": False, "status": "Bild fachlich unpassend", "error": prompt_reason}\n target = (BASE_DIR / "generated_visuals" / f"{package['signal_id']}_gpt-image-2.png").resolve()\n try:\n if old_path and force:\n archive = (BASE_DIR / "generated_visuals" / "archive").resolve(); archive.mkdir(parents=True, exist_ok=True)\n shutil.copy2(old_path, archive / f"{package_id}-v{old_version or 1}.png")\n result = generate_with_openai_image(prompt, target, size="1024x1024", quality="high")\n now = _now(); version = old_version + 1\n 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_asset_id='',media_source_type='KI',media_source_ref='OpenAI Images API',media_rights_status='OpenAI-Generierung; Social-Nutzung prüfen',media_quality='nicht visuell freigegeben — Carlo prüfen',media_use_count=0,image_usage_json=?,updated_at=? WHERE package_id=?", (str(target), now, "OpenAI gpt-image-2", version, prompt, prompt, json.dumps(result.get("usage", {}), ensure_ascii=False), now, package_id))\n con.commit(); con.close()\n return {"ok": True, "status": "Bild vorhanden — visuelle Abnahme offen", "path": str(target), "version": version, "generator": "OpenAI gpt-image-2", "api": result}\n except (OpenAIImageError, OSError, ValueError) as exc:\n now = _now()\n con.execute("UPDATE publication_packages SET image_status='error',image_error=?,image_generator='OpenAI gpt-image-2',image_prompt_used=?,updated_at=? WHERE package_id=?", (str(exc)[:500], prompt, now, package_id)); con.commit(); con.close()\n return {"ok": False, "status": "KI-Bild konnte nicht erzeugt werden", "error": str(exc), "generator": "OpenAI gpt-image-2"}\n'''
s=s[:start]+new+s[end:]
s=s.replace('"media_asset_id": "TEXT NOT NULL DEFAULT \'\'", "media_source_type"', '"image_usage_json": "TEXT NOT NULL DEFAULT \'{}\'",\n "media_asset_id": "TEXT NOT NULL DEFAULT \'\'", "media_source_type"')
s=s.replace('"image_generator", "image_version", "image_error", "image_prompt_used"):', '"image_generator", "image_version", "image_error", "image_prompt_used", "image_usage_json"):' )
p.write_text(s)