From bdbfc1ff7d2a9072b65fa02b2a04d4e83427b2d6 Mon Sep 17 00:00:00 2001 From: Dotty Dotter Date: Wed, 6 May 2026 23:47:42 +0200 Subject: [PATCH] feat(Phase 18): PM-Prompt verschaerft + Auto-Re-Generate bei zu kurzem Output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SYSTEM_PROMPT mit explizitem 'Mindestens 320 Worte, < 280 ist Verstoss' + Hinweis 'wenn Substanz ausgeht: Lebenslage vertiefen statt abbrechen'. - Output-Format-Beispiel mit MINDESTENS-Hinweis. - generate_draft prüft nach LLM-Call die Wortzahl. Bei <280 Worten: ein einzelner Re-Prompt mit höherer Temperatur (0.5) und Hint zur ersten zu-kurzen Wortzahl. Wenn der zweite Versuch laenger ist, wird er übernommen — sonst bleibt der erste. - max_retries=1 fuer den zweiten Call (nicht endlos). Audit-Hauptbefund war 15/19 PMs unter Soll 320–380 Worten. Co-Authored-By: Claude Opus 4.7 (1M context) --- app/presse_generator.py | 42 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/app/presse_generator.py b/app/presse_generator.py index 240f3b0..2a930b8 100644 --- a/app/presse_generator.py +++ b/app/presse_generator.py @@ -95,7 +95,10 @@ Drücke das aus über: ## Stil -- 320–380 Worte (länger als bisher — konkrete Beispiele brauchen Platz) +- **Mindestens 320 Worte, höchstens 400.** Outputs unter 280 Worten + sind Verstoß gegen die Vorgabe — wenn dir die Substanz ausgeht, + vertiefe eine der drei Lebenslagen mit konkreten Zahlen statt + einfach abzubrechen. - Aktive Verben, kurze Sätze (max 22 Worte) - Drucksachen-Nummer einmal im Lead nennen ("Drucksache 21/4757") - Bezug zur News-Lage in 1 Satz, ohne den Medienanbieter zu nennen @@ -159,7 +162,7 @@ Niemals ganze Sätze fett, niemals Zwischenüberschriften. Antworte NUR mit gültigem JSON: { "titel": "", - "body": "<320–380 Worte. Mindestens 3 Lebenslagen mit konkretem Effekt. Keine GWÖ-Werte-Aufzählung. Kein Score.>" + "body": "" }""" @@ -444,6 +447,41 @@ async def generate_draft( if needs_split: body = _split_into_thread_posts(body) + # PM-Wortzahl-Re-Generate: wenn deutlich unter Mindestwortzahl, + # ein Re-Prompt mit höherer Temperatur. Nur ein Versuch — sonst + # endlose LLM-Calls bei zähen Anträgen. + if style == "pm": + word_count = len(body.split()) + if word_count < 280: + logger.info( + "PM-Wortzahl %s zu niedrig (Soll ≥320), re-generate mit Hint", + word_count, + ) + req2 = LlmRequest( + system_prompt=system_prompt_active, + user_prompt=user_prompt + ( + f"\n\nWICHTIG: Der erste Versuch hatte nur {word_count} Worte " + "und ist zu kurz. Liefere jetzt mindestens 320 Worte mit " + "konkreten Zahlen/Personen/Beträgen pro Lebenslage." + ), + model=model, + base_temperature=0.5, + max_tokens=1800, + max_retries=1, + json_object_mode=True, + ) + try: + result2 = await bewerter.bewerte(req2) + titel2 = (result2.get("titel") or "").strip()[:200] + body2 = (result2.get("body") or "").strip() + body2 = body2.replace("\\n", "\n").replace("\\r", "\r").replace("\\t", "\t") + body2 = _re.sub(r'([.!?])"([A-ZÄÖÜ])', r'\1\n\n\2', body2) + if len(body2.split()) > word_count and titel2 and body2: + titel = titel2 + body = body2 + except Exception: + logger.exception("PM-Wortzahl-Re-Generate fehlgeschlagen") + if not titel or not body: raise ValueError("LLM-Response unvollständig (titel oder body leer)")