From 0377cf4bd9bdce3d0676dedd3ea4b4ca82119d7f Mon Sep 17 00:00:00 2001 From: Dotty Dotter Date: Wed, 6 May 2026 02:30:58 +0200 Subject: [PATCH] =?UTF-8?q?fix(#170):=20PM-Prompt=20=E2=80=94=20Paragraphe?= =?UTF-8?q?n-Trennung=20mit=20\\n\\n=20erzwingen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User-Beobachtung im Draft #6: qwen-max nutzte einsame Anfuehrungs- zeichen (") als Paragraph-Trenner statt \\n\\n. Optisch wirkte das wie inkorrekte JSON-Escapes mitten im Text. Zwei Mechanismen: **1. Prompt-Erweiterung:** Neuer Abschnitt "Paragraphen-Formatierung" mit explizitem Beispiel: `"body": "Lead.\\n\\nWirkung 1.\\n\\nWirkung 2.\\n\\n..."`. Klar: keine Anfuehrungszeichen oder Sonderzeichen als Trenner. **2. Post-Process-Heuristik:** Regex `([.!?])"([A-ZÄÖÜ])` → `\\1\\n\\n\\2`. Wenn ein " genau zwischen Punkt+Whitespace und Großbuchstabe steht, ist es wahrscheinlich ein Trenn-Klumpen, kein semantischer Anfuehrer. Wird durch echten Paragraph-Break ersetzt. Konservativ: nur dieses spezifische Pattern wird touched. Echte Quotes (z.B. "Es ist Zeit, …", sagt X) bleiben unangetastet, weil sie nicht direkt nach Satzschluss-Punkt stehen. Co-Authored-By: Claude Opus 4.7 (1M context) --- app/presse_generator.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/app/presse_generator.py b/app/presse_generator.py index 30f5d47..e01f388 100644 --- a/app/presse_generator.py +++ b/app/presse_generator.py @@ -111,6 +111,19 @@ Drücke das aus über: 5. **Was fehlt / was wäre besser** (2-3 Sätze): konkreter Vorschlag 6. **Schluss-Satz**: was wir fordern, ohne Floskel +## Paragraphen-Formatierung + +WICHTIG: trenne die 6 Abschnitte mit **doppeltem Newline** (`\\n\\n`) +im JSON-String. NIEMALS Anführungszeichen oder andere Sonderzeichen +als Paragraph-Trenner verwenden. Beispiel: + +```json +{"body": "Lead-Satz.\\n\\nWirkung 1.\\n\\nWirkung 2.\\n\\nWirkung 3.\\n\\nWas fehlt.\\n\\nForderung."} +``` + +Im JSON: `\\n` als Escape-Sequenz (zwei Zeichen: Backslash + n). +NICHT: rohe Newline-Bytes im String, NICHT: `"`-Zeichen als Trenner. + ## BEISPIELE für den Stil **SCHLECHT** (verboten): @@ -314,10 +327,15 @@ async def generate_draft( titel = (result.get("titel") or "").strip()[:200] body = (result.get("body") or "").strip() - # Post-Process: qwen-max liefert manchmal literal-escapte Sequenzen - # ('\\n' als 2 chars statt echtem Newline). UI braucht echte Newlines - # fuer korrekte Paragraphen-Trennung. Konservativ: nur \\n / \\r / \\t. + # Post-Process Step 1: literal-escapte Sequenzen → echte Whitespaces. + # qwen-max liefert manchmal '\\n' als 2 chars statt echtem Newline. body = body.replace("\\n", "\n").replace("\\r", "\r").replace("\\t", "\t") + # Post-Process Step 2: einsame Anführungszeichen mitten im Text als + # Paragraph-Trenner — qwen tut das gelegentlich trotz Prompt-Anweisung. + # Heuristik: ein " zwischen "Punkt-Whitespace" und "Großbuchstabe" ist + # wahrscheinlich ein Trenn-Klumpen, kein semantischer Anfuehrer. + import re as _re + body = _re.sub(r'([.!?])"([A-ZÄÖÜ])', r'\1\n\n\2', body) if not titel or not body: raise ValueError("LLM-Response unvollständig (titel oder body leer)")