Admin-Plattform für die Tenants von Onyscribe: Editor mit Live-Vorschau (echter Core in Sandbox), Versionen, KI-Agent (Cortecs), OIDC-Abgleich über die Login-Developer-API, Deploy-Engine (Mittwald, gesperrt ohne DEPLOY_LIVE, Freigabe pro Tenant), Core-Vertrag (Schema/Manifest), Core-Releases mit Kompatibilitätsprüfung, Canary-Rollout und Rollback, Zustandsabgleich. Runbook: docs/RUNBOOK_PARALLELTEST.md Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
66 lines
2.6 KiB
Python
66 lines
2.6 KiB
Python
"""Läuft in einem isolierten Verzeichnis mit Kopie des Cores + materialisiertem Tenant.
|
||
|
||
Aufruf: python preview_worker.py <index|pdf|validate> <ausgabedatei> (JSON-Eingabe auf stdin)
|
||
Führt den ECHTEN Core aus (auch overrides.py) – deshalb nur als Subprozess ohne Secrets/Netz-Keys.
|
||
"""
|
||
import json
|
||
import os
|
||
import sys
|
||
import traceback
|
||
|
||
sys.path.insert(0, os.getcwd())
|
||
|
||
kind, out = sys.argv[1], sys.argv[2]
|
||
args = json.loads(sys.stdin.read() or "{}")
|
||
|
||
|
||
def main() -> None:
|
||
from core import app as appmod
|
||
from core.config import CFG
|
||
|
||
if kind == "index":
|
||
page = appmod._render_index()
|
||
open(out, "w", encoding="utf-8").write(page)
|
||
elif kind == "pdf":
|
||
pdf = appmod.build_pdf(args.get("title") or "Vorschau", args["summary"], "SPRECHER_0: Beispiel.")
|
||
open(out, "wb").write(pdf)
|
||
elif kind == "prompt":
|
||
base = appmod._summary_prompt()
|
||
ctx = {"title": args.get("title", ""), "insurance_type": args.get("terminart", ""),
|
||
"customer_2": args.get("projekt", ""), "customer_name": args.get("kunde", ""), "customer_address": ""}
|
||
final = appmod.HOOKS.build_prompt(base, ctx)
|
||
json.dump({"prompt": final, "chars": len(final)}, open(out, "w"))
|
||
elif kind == "validate":
|
||
errors, warnings = [], []
|
||
page = appmod._render_index()
|
||
if "@@" in page:
|
||
errors.append("Web-UI: nicht ersetzte @@PLATZHALTER@@ im Template")
|
||
if not CFG.logo_path:
|
||
warnings.append("Kein Logo (logo.svg/logo.png) hinterlegt")
|
||
if not CFG.favicon_path:
|
||
warnings.append("Kein favicon.svg – es wird ein generisches Favicon verwendet")
|
||
try:
|
||
pdf = appmod.build_pdf("Validierung", args["summary"], "SPRECHER_0: Beispiel.")
|
||
if pdf[:5] != b"%PDF-":
|
||
errors.append("PDF-Rendering lieferte kein PDF")
|
||
except Exception as exc: # noqa: BLE001
|
||
errors.append(f"PDF-Rendering fehlgeschlagen: {exc}")
|
||
prompt = CFG.prompt_path.read_text(encoding="utf-8")
|
||
if len(prompt.strip()) < 200:
|
||
warnings.append("Prompt ist sehr kurz")
|
||
json.dump({"ok": not errors, "errors": errors, "warnings": warnings,
|
||
"tenant": CFG.id, "prompt_chars": len(prompt)}, open(out, "w"))
|
||
|
||
|
||
try:
|
||
main()
|
||
except SystemExit:
|
||
raise
|
||
except BaseException: # noqa: BLE001
|
||
tb = traceback.format_exc()
|
||
if kind == "validate":
|
||
json.dump({"ok": False, "errors": ["Tenant lässt sich nicht laden:\n" + tb[-1500:]], "warnings": []}, open(out, "w"))
|
||
else:
|
||
sys.stderr.write(tb)
|
||
sys.exit(2)
|