Protokoll #11612

ID11612
Zeitstempel2025-12-23 20:23:31.609394
Clientroot
IP
Warning: Undefined array key "request_ip" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13

Deprecated: htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens13,531 (Input: 0, Output: 0)
Dauer128680 ms
Request-Zeit
Warning: Undefined array key "request_timestamp" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 18
Response-Zeit-

Warning: Undefined array key "error_message" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 22

Request

{
    "event": "PreToolUse",
    "tool_name": "Edit",
    "tool_input": {
        "file_path": "\/opt\/scripts\/pipeline\/generate.py",
        "old_string": "def build_generation_prompt(briefing, context, profile, contract, structure=None):\n    \"\"\"Build the content generation prompt.\"\"\"\n\n    # Format context\n    context_text = \"\"\n    for i, ctx in enumerate(context, 1):\n        context_text += f\"\\n[Quelle {i}: {ctx['source']}]\\n{ctx['content']}\\n\"\n\n    # Build rich profile instructions\n    profile_text = \"\"\n    if profile:\n        config = profile.get(\"config\", {})\n        autorenprofil = config.get(\"autorenprofil\", config)  # Support both structures\n\n        # Extract voice\/stimme\n        stimme = autorenprofil.get(\"stimme\", {})\n        stimme_text = \"\"\n        if stimme:\n            stimme_text = f\"\"\"\n### Stimme\/Tonalität:\n- Ton: {stimme.get(\"ton\", \"neutral\")}\n- Perspektive: {stimme.get(\"perspektive\", \"neutral\")}\n- Komplexität: {stimme.get(\"komplexitaet\", \"mittel\")}\n- Autorität: {stimme.get(\"autoritaet\", \"Experte\")}\"\"\"\n\n        # Extract style\/stil\n        stil = autorenprofil.get(\"stil\", {})\n        stil_text = \"\"\n        if stil:\n            fachsprache_beispiele = stil.get(\"fachsprache_beispiele\", [])\n            fachsprache_str = \", \".join(fachsprache_beispiele[:5]) if fachsprache_beispiele else \"\"\n            stil_text = f\"\"\"\n### Stil:\n- Fachsprache: {\"Ja\" if stil.get(\"fachsprache\", False) else \"Nein\"}\n- Fachbegriffe: {fachsprache_str}\n- Satzlänge: {stil.get(\"satzlaenge\", \"mittel\")}\n- Absatzstruktur: {stil.get(\"absatzstruktur\", \"klar gegliedert\")}\"\"\"\n\n        # Extract language patterns\/sprachliche_muster\n        muster = autorenprofil.get(\"sprachliche_muster\", {})\n        muster_text = \"\"\n        if muster:\n            phrasen = muster.get(\"phrasen\", [])\n            phrasen_str = \", \".join([f'\"{p}\"' for p in phrasen[:4]]) if phrasen else \"\"\n            uebergaenge = muster.get(\"uebergaenge\", [])\n            uebergaenge_str = \", \".join([f'\"{u}\"' for u in uebergaenge[:3]]) if uebergaenge else \"\"\n            muster_text = f\"\"\"\n### Sprachliche Muster:\n- Typische Phrasen: {phrasen_str}\n- Übergangsformulierungen: {uebergaenge_str}\"\"\"\n\n        # Extract taboos\/tabus\n        tabus = autorenprofil.get(\"tabus\", [])\n        tabus_text = \"\"\n        if tabus:\n            tabus_str = \", \".join(tabus[:5])\n            tabus_text = f\"\"\"\n### Zu vermeiden (Tabus):\n{tabus_str}\"\"\"\n\n        # Extract core messages\/kernbotschaften\n        kernbotschaften = autorenprofil.get(\"kernbotschaften\", [])\n        kern_text = \"\"\n        if kernbotschaften:\n            kern_str = \"\\n\".join([f\"- {k}\" for k in kernbotschaften[:4]])\n            kern_text = f\"\"\"\n### Kernbotschaften (implizit vermitteln):\n{kern_str}\"\"\"\n\n        # Extract output format (HTML for web profiles)\n        output_format = autorenprofil.get(\"output_format\", {})\n        format_text = \"\"\n        if output_format and output_format.get(\"typ\") == \"html\":\n            erlaubte = output_format.get(\"erlaubte_elemente\", {})\n            verboten = output_format.get(\"verbotene_elemente\", [])\n            regeln = output_format.get(\"struktur_regeln\", [])\n\n            erlaubte_str = []\n            for _kategorie, elemente in erlaubte.items():\n                erlaubte_str.extend(elemente[:3])\n\n            format_text = f\"\"\"\n### Output-Format: HTML\n**Erlaubte Elemente:**\n{\", \".join(erlaubte_str[:10])}\n\n**Struktur-Regeln:**\n- {chr(10).join(\"- \" + r for r in regeln[:4]) if regeln else \"Semantisches HTML verwenden\"}\n\n**Verboten:** {\", \".join(verboten[:4]) if verboten else \"div, span, br, style\"}\"\"\"\n\n        # Combine all profile sections\n        profile_text = f\"\"\"\n## Autorenprofil: {profile.get(\"name\", \"Standard\")}\n{stimme_text}\n{stil_text}\n{muster_text}\n{tabus_text}\n{kern_text}\n{format_text}\n\"\"\"\n\n    # Build contract requirements\n    contract_text = \"\"\n    if contract:\n        config = contract.get(\"config\", {})\n        req = config.get(\"requirements\", {})\n        contract_text = f\"\"\"\nContract: {contract.get(\"name\", \"Standard\")}\n- Wortanzahl: {req.get(\"min_words\", 500)} - {req.get(\"max_words\", 5000)} Wörter\n- Struktur-Validierung: {req.get(\"structure_validation\", True)}\n\"\"\"\n\n    # Build structure instructions\n    structure_text = \"\"\n    if structure:\n        config = structure.get(\"config\", {})\n        structure_text = f\"\"\"\nStruktur-Template: {structure.get(\"name\", \"\")}\n- Typ: {structure.get(\"type\", \"\")}\n- Abschnitte: {json.dumps(config.get(\"sections\", []), ensure_ascii=False)}\n\"\"\"\n\n    # Determine if HTML output is required\n    html_output = False\n    if profile:\n        config = profile.get(\"config\", {})\n        autorenprofil = config.get(\"autorenprofil\", config)\n        output_format = autorenprofil.get(\"output_format\", {})\n        html_output = output_format.get(\"typ\") == \"html\"\n\n    format_instruction = \"\"\n    if html_output:\n        format_instruction = \"\"\"7. **WICHTIG: Ausgabe als wohlformatiertes HTML**\n   - Verwende nur: h1, h2, h3, h4, p, ul, ol, li, strong, a, section, table, tr, td\n   - Jeder h2-Abschnitt muss in einer eigenen <section> stehen\n   - Kein Markdown, kein div\/span\/br\n   - Fließtext immer in <p>-Tags\"\"\"",
        "new_string": "def _parse_new_author_profile(config):\n    \"\"\"Parse new-style author profile (Cary format) into prompt text.\"\"\"\n    sections = []\n\n    # Haltung\n    haltung = config.get(\"haltung\", {})\n    if haltung:\n        sections.append(f\"\"\"### Haltung:\n- Grundhaltung: {haltung.get(\"grundhaltung\", \"\")}\n- Ausrichtung: {haltung.get(\"ausrichtung\", \"\")}\n- Spannungstoleranz: {haltung.get(\"spannungstoleranz\", \"\")}\n- Vereinfachung: {haltung.get(\"vereinfachung\", \"\")}\"\"\")\n\n    # Tonalität\n    tonalitaet = config.get(\"tonalitaet\", {})\n    if tonalitaet:\n        sections.append(f\"\"\"### Tonalität:\n- Charakter: {tonalitaet.get(\"charakter\", \"\")}\n- Stil: {tonalitaet.get(\"stil\", \"\")}\n- Wirkung: {tonalitaet.get(\"wirkung\", \"\")}\n- Abgrenzung: {tonalitaet.get(\"abgrenzung\", \"\")}\"\"\")\n\n    # Sprachmodus\n    sprachmodus = config.get(\"sprachmodus\", {})\n    if sprachmodus:\n        sections.append(f\"\"\"### Sprachmodus:\n- Denkstil: {sprachmodus.get(\"denkstil\", \"\")}\n- Aussagenform: {sprachmodus.get(\"aussagenform\", \"\")}\n- Fragenfunktion: {sprachmodus.get(\"fragenfunktion\", \"\")}\"\"\")\n\n    # Grammatik und Satzbau - WICHTIG für Verbote\n    grammatik = config.get(\"grammatik_und_satzbau\", {})\n    if grammatik:\n        verbote = []\n        if grammatik.get(\"stakkato\") == \"ausgeschlossen\":\n            verbote.append(\"Stakkato-Sätze\")\n        if grammatik.get(\"einschuebe\") == \"keine\":\n            verbote.append(\"Einschübe\")\n        if grammatik.get(\"gedankenstriche\") == \"verboten\":\n            verbote.append(\"Gedankenstriche (–)\")\n\n        sections.append(f\"\"\"### Grammatik und Satzbau:\n- Sätze: {grammatik.get(\"saetze\", \"\")}\n- Rhythmus: {grammatik.get(\"rhythmus\", \"\")}\n- **VERBOTEN:** {\", \".join(verbote) if verbote else \"keine\"}\"\"\")\n\n    # Wortwahl\n    wortwahl = config.get(\"wortwahl\", {})\n    if wortwahl:\n        verboten = []\n        if wortwahl.get(\"buzzwords\") == \"ausgeschlossen\":\n            verboten.append(\"Buzzwords\")\n        if wortwahl.get(\"methodennamen\") == \"ausgeschlossen\":\n            verboten.append(\"Methodennamen\")\n\n        sections.append(f\"\"\"### Wortwahl:\n- Niveau: {wortwahl.get(\"niveau\", \"\")}\n- Begriffe: {wortwahl.get(\"begriffe\", \"\")}\n- **VERBOTEN:** {\", \".join(verboten) if verboten else \"keine\"}\"\"\")\n\n    # Adressierung\n    adressierung = config.get(\"adressierung\", {})\n    if adressierung:\n        sections.append(f\"\"\"### Adressierung:\n- Form: {adressierung.get(\"form\", \"Sie\")}\n- Beziehung: {adressierung.get(\"beziehung\", \"\")}\n- Einladung: {adressierung.get(\"einladung\", \"\")}\"\"\")\n\n    # Metaphern\n    metaphern = config.get(\"metaphern\", {})\n    if metaphern:\n        sections.append(f\"\"\"### Metaphern:\n- Einsatz: {metaphern.get(\"einsatz\", \"\")}\n- Herkunft: {metaphern.get(\"herkunft\", \"\")}\n- Konsistenz: {metaphern.get(\"konsistenz\", \"\")}\"\"\")\n\n    return \"\\n\\n\".join(sections)\n\n\ndef _parse_new_structure(config):\n    \"\"\"Parse new-style structure profile into prompt text and format info.\"\"\"\n    sections = []\n    output_format = None\n    erlaubte_tags = []\n\n    # Ausgabe-Format\n    ausgabe = config.get(\"ausgabe\", {})\n    if ausgabe:\n        output_format = ausgabe.get(\"format\", \"markdown\")\n        erlaubte_tags = ausgabe.get(\"erlaubte_tags\", [])\n        verbotene_tags = ausgabe.get(\"verbotene_tags\", [])\n\n        if output_format == \"body-html\":\n            sections.append(f\"\"\"### Ausgabe-Format: HTML\n- **Nur diese Tags verwenden:** {\", \".join(erlaubte_tags)}\n- **Verboten:** {\", \".join(verbotene_tags)}\n- {ausgabe.get(\"hinweis\", \"Sauberes semantisches HTML\")}\"\"\")\n\n    # Gesamtaufbau\n    aufbau = config.get(\"gesamtaufbau\", {})\n    if aufbau:\n        sections.append(f\"\"\"### Gesamtaufbau:\n- Form: {aufbau.get(\"form\", \"\")}\n- Dramaturgie: {aufbau.get(\"dramaturgie\", \"\")}\n- Linearität: {aufbau.get(\"linearitaet\", \"\")}\n- Themensprünge: {aufbau.get(\"themenspruenge\", \"\")}\"\"\")\n\n    # Einstieg\n    einstieg = config.get(\"einstieg\", {})\n    if einstieg:\n        sections.append(f\"\"\"### Einstieg:\n- Funktion: {einstieg.get(\"funktion\", \"\")}\n- Inhaltstyp: {einstieg.get(\"inhaltstyp\", \"\")}\n- Ausschluss: {einstieg.get(\"ausschluss\", \"\")}\"\"\")\n\n    # Hauptteil-Blöcke\n    hauptteil = config.get(\"hauptteil\", {})\n    bloecke = hauptteil.get(\"bloecke\", [])\n    if bloecke:\n        bloecke_text = \"\\n\".join([f\"  {i+1}. {b.get('fokus', '')} → {b.get('ziel', '')}\" for i, b in enumerate(bloecke)])\n        sections.append(f\"\"\"### Hauptteil-Struktur:\n{bloecke_text}\"\"\")\n\n    # Schluss\n    schluss = config.get(\"schluss\", {})\n    if schluss:\n        sections.append(f\"\"\"### Schluss:\n- Typ: {schluss.get(\"typ\", \"\")}\n- Funktion: {schluss.get(\"funktion\", \"\")}\n- Abgrenzung: {schluss.get(\"abgrenzung\", \"\")}\"\"\")\n\n    # Formatierung\n    formatierung = config.get(\"formatierung\", {})\n    if formatierung:\n        ausschluss = formatierung.get(\"ausschluss\", [])\n        if ausschluss:\n            sections.append(f\"\"\"### Formatierung verboten:\n{\", \".join(ausschluss)}\"\"\")\n\n    return \"\\n\\n\".join(sections), output_format, erlaubte_tags\n\n\ndef build_generation_prompt(briefing, context, profile, contract, structure=None):\n    \"\"\"Build the content generation prompt.\"\"\"\n\n    # Format context\n    context_text = \"\"\n    for i, ctx in enumerate(context, 1):\n        context_text += f\"\\n[Quelle {i}: {ctx['source']}]\\n{ctx['content']}\\n\"\n\n    # Build profile instructions - detect new vs old format\n    profile_text = \"\"\n    if profile:\n        config = profile.get(\"config\", {})\n\n        # Detect new format (has \"haltung\" or \"tonalitaet\" at top level)\n        if \"haltung\" in config or \"tonalitaet\" in config or \"grammatik_und_satzbau\" in config:\n            # New Cary-style profile\n            profile_text = f\"\"\"\n## Autorenprofil: {profile.get(\"name\", \"Standard\")}\n\n{_parse_new_author_profile(config)}\n\"\"\"\n        else:\n            # Old format - keep backwards compatibility\n            autorenprofil = config.get(\"autorenprofil\", config)\n\n            stimme = autorenprofil.get(\"stimme\", {})\n            stimme_text = \"\"\n            if stimme:\n                stimme_text = f\"\"\"\n### Stimme\/Tonalität:\n- Ton: {stimme.get(\"ton\", \"neutral\")}\n- Perspektive: {stimme.get(\"perspektive\", \"neutral\")}\n- Komplexität: {stimme.get(\"komplexitaet\", \"mittel\")}\"\"\"\n\n            stil = autorenprofil.get(\"stil\", {})\n            stil_text = \"\"\n            if stil:\n                stil_text = f\"\"\"\n### Stil:\n- Fachsprache: {\"Ja\" if stil.get(\"fachsprache\", False) else \"Nein\"}\n- Satzlänge: {stil.get(\"satzlaenge\", \"mittel\")}\"\"\"\n\n            tabus = autorenprofil.get(\"tabus\", [])\n            tabus_text = \"\"\n            if tabus:\n                tabus_text = f\"\"\"\n### Zu vermeiden:\n{\", \".join(tabus[:5])}\"\"\"\n\n            profile_text = f\"\"\"\n## Autorenprofil: {profile.get(\"name\", \"Standard\")}\n{stimme_text}\n{stil_text}\n{tabus_text}\n\"\"\"\n\n    # Build contract requirements\n    contract_text = \"\"\n    if contract:\n        config = contract.get(\"config\", {})\n        req = config.get(\"requirements\", {})\n        contract_text = f\"\"\"\nContract: {contract.get(\"name\", \"Standard\")}\n- Wortanzahl: {req.get(\"min_words\", 500)} - {req.get(\"max_words\", 5000)} Wörter\n\"\"\"\n\n    # Build structure instructions - detect new vs old format\n    structure_text = \"\"\n    output_format = \"markdown\"\n    erlaubte_tags = []\n\n    if structure:\n        config = structure.get(\"config\", {})\n\n        # Detect new format (has \"ausgabe\" at top level)\n        if \"ausgabe\" in config or \"gesamtaufbau\" in config:\n            # New Blog-Struktur format\n            parsed_text, output_format, erlaubte_tags = _parse_new_structure(config)\n            structure_text = f\"\"\"\n## Struktur: {structure.get(\"name\", \"\")}\n\n{parsed_text}\n\"\"\"\n        else:\n            # Old format\n            structure_text = f\"\"\"\nStruktur-Template: {structure.get(\"name\", \"\")}\n- Abschnitte: {json.dumps(config.get(\"sections\", []), ensure_ascii=False)}\n\"\"\"\n\n    # Build format instruction based on structure's ausgabe\n    format_instruction = \"\"\n    if output_format == \"body-html\":\n        tags_str = \", \".join(erlaubte_tags) if erlaubte_tags else \"h1, h2, h3, h4, p, a, ol, ul, li, strong, table, hr\"\n        format_instruction = f\"\"\"7. **KRITISCH - Ausgabe als sauberes HTML:**\n   - NUR diese Tags: {tags_str}\n   - KEIN Markdown (keine ##, keine **, keine -)\n   - KEIN div, span, br, img, script, style\n   - Jeder Absatz in <p>-Tags\n   - Überschriften als <h2>, <h3>, <h4>\n   - Listen als <ul>\/<ol> mit <li>\"\"\""
    }
}

Response

{
    "tool_response": {
        "filePath": "\/opt\/scripts\/pipeline\/generate.py",
        "oldString": "def build_generation_prompt(briefing, context, profile, contract, structure=None):\n    \"\"\"Build the content generation prompt.\"\"\"\n\n    # Format context\n    context_text = \"\"\n    for i, ctx in enumerate(context, 1):\n        context_text += f\"\\n[Quelle {i}: {ctx['source']}]\\n{ctx['content']}\\n\"\n\n    # Build rich profile instructions\n    profile_text = \"\"\n    if profile:\n        config = profile.get(\"config\", {})\n        autorenprofil = config.get(\"autorenprofil\", config)  # Support both structures\n\n        # Extract voice\/stimme\n        stimme = autorenprofil.get(\"stimme\", {})\n        stimme_text = \"\"\n        if stimme:\n            stimme_text = f\"\"\"\n### Stimme\/Tonalität:\n- Ton: {stimme.get(\"ton\", \"neutral\")}\n- Perspektive: {stimme.get(\"perspektive\", \"neutral\")}\n- Komplexität: {stimme.get(\"komplexitaet\", \"mittel\")}\n- Autorität: {stimme.get(\"autoritaet\", \"Experte\")}\"\"\"\n\n        # Extract style\/stil\n        stil = autorenprofil.get(\"stil\", {})\n        stil_text = \"\"\n        if stil:\n            fachsprache_beispiele = stil.get(\"fachsprache_beispiele\", [])\n            fachsprache_str = \", \".join(fachsprache_beispiele[:5]) if fachsprache_beispiele else \"\"\n            stil_text = f\"\"\"\n### Stil:\n- Fachsprache: {\"Ja\" if stil.get(\"fachsprache\", False) else \"Nein\"}\n- Fachbegriffe: {fachsprache_str}\n- Satzlänge: {stil.get(\"satzlaenge\", \"mittel\")}\n- Absatzstruktur: {stil.get(\"absatzstruktur\", \"klar gegliedert\")}\"\"\"\n\n        # Extract language patterns\/sprachliche_muster\n        muster = autorenprofil.get(\"sprachliche_muster\", {})\n        muster_text = \"\"\n        if muster:\n            phrasen = muster.get(\"phrasen\", [])\n            phrasen_str = \", \".join([f'\"{p}\"' for p in phrasen[:4]]) if phrasen else \"\"\n            uebergaenge = muster.get(\"uebergaenge\", [])\n            uebergaenge_str = \", \".join([f'\"{u}\"' for u in uebergaenge[:3]]) if uebergaenge else \"\"\n            muster_text = f\"\"\"\n### Sprachliche Muster:\n- Typische Phrasen: {phrasen_str}\n- Übergangsformulierungen: {uebergaenge_str}\"\"\"\n\n        # Extract taboos\/tabus\n        tabus = autorenprofil.get(\"tabus\", [])\n        tabus_text = \"\"\n        if tabus:\n            tabus_str = \", \".join(tabus[:5])\n            tabus_text = f\"\"\"\n### Zu vermeiden (Tabus):\n{tabus_str}\"\"\"\n\n        # Extract core messages\/kernbotschaften\n        kernbotschaften = autorenprofil.get(\"kernbotschaften\", [])\n        kern_text = \"\"\n        if kernbotschaften:\n            kern_str = \"\\n\".join([f\"- {k}\" for k in kernbotschaften[:4]])\n            kern_text = f\"\"\"\n### Kernbotschaften (implizit vermitteln):\n{kern_str}\"\"\"\n\n        # Extract output format (HTML for web profiles)\n        output_format = autorenprofil.get(\"output_format\", {})\n        format_text = \"\"\n        if output_format and output_format.get(\"typ\") == \"html\":\n            erlaubte = output_format.get(\"erlaubte_elemente\", {})\n            verboten = output_format.get(\"verbotene_elemente\", [])\n            regeln = output_format.get(\"struktur_regeln\", [])\n\n            erlaubte_str = []\n            for _kategorie, elemente in erlaubte.items():\n                erlaubte_str.extend(elemente[:3])\n\n            format_text = f\"\"\"\n### Output-Format: HTML\n**Erlaubte Elemente:**\n{\", \".join(erlaubte_str[:10])}\n\n**Struktur-Regeln:**\n- {chr(10).join(\"- \" + r for r in regeln[:4]) if regeln else \"Semantisches HTML verwenden\"}\n\n**Verboten:** {\", \".join(verboten[:4]) if verboten else \"div, span, br, style\"}\"\"\"\n\n        # Combine all profile sections\n        profile_text = f\"\"\"\n## Autorenprofil: {profile.get(\"name\", \"Standard\")}\n{stimme_text}\n{stil_text}\n{muster_text}\n{tabus_text}\n{kern_text}\n{format_text}\n\"\"\"\n\n    # Build contract requirements\n    contract_text = \"\"\n    if contract:\n        config = contract.get(\"config\", {})\n        req = config.get(\"requirements\", {})\n        contract_text = f\"\"\"\nContract: {contract.get(\"name\", \"Standard\")}\n- Wortanzahl: {req.get(\"min_words\", 500)} - {req.get(\"max_words\", 5000)} Wörter\n- Struktur-Validierung: {req.get(\"structure_validation\", True)}\n\"\"\"\n\n    # Build structure instructions\n    structure_text = \"\"\n    if structure:\n        config = structure.get(\"config\", {})\n        structure_text = f\"\"\"\nStruktur-Template: {structure.get(\"name\", \"\")}\n- Typ: {structure.get(\"type\", \"\")}\n- Abschnitte: {json.dumps(config.get(\"sections\", []), ensure_ascii=False)}\n\"\"\"\n\n    # Determine if HTML output is required\n    html_output = False\n    if profile:\n        config = profile.get(\"config\", {})\n        autorenprofil = config.get(\"autorenprofil\", config)\n        output_format = autorenprofil.get(\"output_format\", {})\n        html_output = output_format.get(\"typ\") == \"html\"\n\n    format_instruction = \"\"\n    if html_output:\n        format_instruction = \"\"\"7. **WICHTIG: Ausgabe als wohlformatiertes HTML**\n   - Verwende nur: h1, h2, h3, h4, p, ul, ol, li, strong, a, section, table, tr, td\n   - Jeder h2-Abschnitt muss in einer eigenen <section> stehen\n   - Kein Markdown, kein div\/span\/br\n   - Fließtext immer in <p>-Tags\"\"\"",
        "newString": "def _parse_new_author_profile(config):\n    \"\"\"Parse new-style author profile (Cary format) into prompt text.\"\"\"\n    sections = []\n\n    # Haltung\n    haltung = config.get(\"haltung\", {})\n    if haltung:\n        sections.append(f\"\"\"### Haltung:\n- Grundhaltung: {haltung.get(\"grundhaltung\", \"\")}\n- Ausrichtung: {haltung.get(\"ausrichtung\", \"\")}\n- Spannungstoleranz: {haltung.get(\"spannungstoleranz\", \"\")}\n- Vereinfachung: {haltung.get(\"vereinfachung\", \"\")}\"\"\")\n\n    # Tonalität\n    tonalitaet = config.get(\"tonalitaet\", {})\n    if tonalitaet:\n        sections.append(f\"\"\"### Tonalität:\n- Charakter: {tonalitaet.get(\"charakter\", \"\")}\n- Stil: {tonalitaet.get(\"stil\", \"\")}\n- Wirkung: {tonalitaet.get(\"wirkung\", \"\")}\n- Abgrenzung: {tonalitaet.get(\"abgrenzung\", \"\")}\"\"\")\n\n    # Sprachmodus\n    sprachmodus = config.get(\"sprachmodus\", {})\n    if sprachmodus:\n        sections.append(f\"\"\"### Sprachmodus:\n- Denkstil: {sprachmodus.get(\"denkstil\", \"\")}\n- Aussagenform: {sprachmodus.get(\"aussagenform\", \"\")}\n- Fragenfunktion: {sprachmodus.get(\"fragenfunktion\", \"\")}\"\"\")\n\n    # Grammatik und Satzbau - WICHTIG für Verbote\n    grammatik = config.get(\"grammatik_und_satzbau\", {})\n    if grammatik:\n        verbote = []\n        if grammatik.get(\"stakkato\") == \"ausgeschlossen\":\n            verbote.append(\"Stakkato-Sätze\")\n        if grammatik.get(\"einschuebe\") == \"keine\":\n            verbote.append(\"Einschübe\")\n        if grammatik.get(\"gedankenstriche\") == \"verboten\":\n            verbote.append(\"Gedankenstriche (–)\")\n\n        sections.append(f\"\"\"### Grammatik und Satzbau:\n- Sätze: {grammatik.get(\"saetze\", \"\")}\n- Rhythmus: {grammatik.get(\"rhythmus\", \"\")}\n- **VERBOTEN:** {\", \".join(verbote) if verbote else \"keine\"}\"\"\")\n\n    # Wortwahl\n    wortwahl = config.get(\"wortwahl\", {})\n    if wortwahl:\n        verboten = []\n        if wortwahl.get(\"buzzwords\") == \"ausgeschlossen\":\n            verboten.append(\"Buzzwords\")\n        if wortwahl.get(\"methodennamen\") == \"ausgeschlossen\":\n            verboten.append(\"Methodennamen\")\n\n        sections.append(f\"\"\"### Wortwahl:\n- Niveau: {wortwahl.get(\"niveau\", \"\")}\n- Begriffe: {wortwahl.get(\"begriffe\", \"\")}\n- **VERBOTEN:** {\", \".join(verboten) if verboten else \"keine\"}\"\"\")\n\n    # Adressierung\n    adressierung = config.get(\"adressierung\", {})\n    if adressierung:\n        sections.append(f\"\"\"### Adressierung:\n- Form: {adressierung.get(\"form\", \"Sie\")}\n- Beziehung: {adressierung.get(\"beziehung\", \"\")}\n- Einladung: {adressierung.get(\"einladung\", \"\")}\"\"\")\n\n    # Metaphern\n    metaphern = config.get(\"metaphern\", {})\n    if metaphern:\n        sections.append(f\"\"\"### Metaphern:\n- Einsatz: {metaphern.get(\"einsatz\", \"\")}\n- Herkunft: {metaphern.get(\"herkunft\", \"\")}\n- Konsistenz: {metaphern.get(\"konsistenz\", \"\")}\"\"\")\n\n    return \"\\n\\n\".join(sections)\n\n\ndef _parse_new_structure(config):\n    \"\"\"Parse new-style structure profile into prompt text and format info.\"\"\"\n    sections = []\n    output_format = None\n    erlaubte_tags = []\n\n    # Ausgabe-Format\n    ausgabe = config.get(\"ausgabe\", {})\n    if ausgabe:\n        output_format = ausgabe.get(\"format\", \"markdown\")\n        erlaubte_tags = ausgabe.get(\"erlaubte_tags\", [])\n        verbotene_tags = ausgabe.get(\"verbotene_tags\", [])\n\n        if output_format == \"body-html\":\n            sections.append(f\"\"\"### Ausgabe-Format: HTML\n- **Nur diese Tags verwenden:** {\", \".join(erlaubte_tags)}\n- **Verboten:** {\", \".join(verbotene_tags)}\n- {ausgabe.get(\"hinweis\", \"Sauberes semantisches HTML\")}\"\"\")\n\n    # Gesamtaufbau\n    aufbau = config.get(\"gesamtaufbau\", {})\n    if aufbau:\n        sections.append(f\"\"\"### Gesamtaufbau:\n- Form: {aufbau.get(\"form\", \"\")}\n- Dramaturgie: {aufbau.get(\"dramaturgie\", \"\")}\n- Linearität: {aufbau.get(\"linearitaet\", \"\")}\n- Themensprünge: {aufbau.get(\"themenspruenge\", \"\")}\"\"\")\n\n    # Einstieg\n    einstieg = config.get(\"einstieg\", {})\n    if einstieg:\n        sections.append(f\"\"\"### Einstieg:\n- Funktion: {einstieg.get(\"funktion\", \"\")}\n- Inhaltstyp: {einstieg.get(\"inhaltstyp\", \"\")}\n- Ausschluss: {einstieg.get(\"ausschluss\", \"\")}\"\"\")\n\n    # Hauptteil-Blöcke\n    hauptteil = config.get(\"hauptteil\", {})\n    bloecke = hauptteil.get(\"bloecke\", [])\n    if bloecke:\n        bloecke_text = \"\\n\".join([f\"  {i+1}. {b.get('fokus', '')} → {b.get('ziel', '')}\" for i, b in enumerate(bloecke)])\n        sections.append(f\"\"\"### Hauptteil-Struktur:\n{bloecke_text}\"\"\")\n\n    # Schluss\n    schluss = config.get(\"schluss\", {})\n    if schluss:\n        sections.append(f\"\"\"### Schluss:\n- Typ: {schluss.get(\"typ\", \"\")}\n- Funktion: {schluss.get(\"funktion\", \"\")}\n- Abgrenzung: {schluss.get(\"abgrenzung\", \"\")}\"\"\")\n\n    # Formatierung\n    formatierung = config.get(\"formatierung\", {})\n    if formatierung:\n        ausschluss = formatierung.get(\"ausschluss\", [])\n        if ausschluss:\n            sections.append(f\"\"\"### Formatierung verboten:\n{\", \".join(ausschluss)}\"\"\")\n\n    return \"\\n\\n\".join(sections), output_format, erlaubte_tags\n\n\ndef build_generation_prompt(briefing, context, profile, contract, structure=None):\n    \"\"\"Build the content generation prompt.\"\"\"\n\n    # Format context\n    context_text = \"\"\n    for i, ctx in enumerate(context, 1):\n        context_text += f\"\\n[Quelle {i}: {ctx['source']}]\\n{ctx['content']}\\n\"\n\n    # Build profile instructions - detect new vs old format\n    profile_text = \"\"\n    if profile:\n        config = profile.get(\"config\", {})\n\n        # Detect new format (has \"haltung\" or \"tonalitaet\" at top level)\n        if \"haltung\" in config or \"tonalitaet\" in config or \"grammatik_und_satzbau\" in config:\n            # New Cary-style profile\n            profile_text = f\"\"\"\n## Autorenprofil: {profile.get(\"name\", \"Standard\")}\n\n{_parse_new_author_profile(config)}\n\"\"\"\n        else:\n            # Old format - keep backwards compatibility\n            autorenprofil = config.get(\"autorenprofil\", config)\n\n            stimme = autorenprofil.get(\"stimme\", {})\n            stimme_text = \"\"\n            if stimme:\n                stimme_text = f\"\"\"\n### Stimme\/Tonalität:\n- Ton: {stimme.get(\"ton\", \"neutral\")}\n- Perspektive: {stimme.get(\"perspektive\", \"neutral\")}\n- Komplexität: {stimme.get(\"komplexitaet\", \"mittel\")}\"\"\"\n\n            stil = autorenprofil.get(\"stil\", {})\n            stil_text = \"\"\n            if stil:\n                stil_text = f\"\"\"\n### Stil:\n- Fachsprache: {\"Ja\" if stil.get(\"fachsprache\", False) else \"Nein\"}\n- Satzlänge: {stil.get(\"satzlaenge\", \"mittel\")}\"\"\"\n\n            tabus = autorenprofil.get(\"tabus\", [])\n            tabus_text = \"\"\n            if tabus:\n                tabus_text = f\"\"\"\n### Zu vermeiden:\n{\", \".join(tabus[:5])}\"\"\"\n\n            profile_text = f\"\"\"\n## Autorenprofil: {profile.get(\"name\", \"Standard\")}\n{stimme_text}\n{stil_text}\n{tabus_text}\n\"\"\"\n\n    # Build contract requirements\n    contract_text = \"\"\n    if contract:\n        config = contract.get(\"config\", {})\n        req = config.get(\"requirements\", {})\n        contract_text = f\"\"\"\nContract: {contract.get(\"name\", \"Standard\")}\n- Wortanzahl: {req.get(\"min_words\", 500)} - {req.get(\"max_words\", 5000)} Wörter\n\"\"\"\n\n    # Build structure instructions - detect new vs old format\n    structure_text = \"\"\n    output_format = \"markdown\"\n    erlaubte_tags = []\n\n    if structure:\n        config = structure.get(\"config\", {})\n\n        # Detect new format (has \"ausgabe\" at top level)\n        if \"ausgabe\" in config or \"gesamtaufbau\" in config:\n            # New Blog-Struktur format\n            parsed_text, output_format, erlaubte_tags = _parse_new_structure(config)\n            structure_text = f\"\"\"\n## Struktur: {structure.get(\"name\", \"\")}\n\n{parsed_text}\n\"\"\"\n        else:\n            # Old format\n            structure_text = f\"\"\"\nStruktur-Template: {structure.get(\"name\", \"\")}\n- Abschnitte: {json.dumps(config.get(\"sections\", []), ensure_ascii=False)}\n\"\"\"\n\n    # Build format instruction based on structure's ausgabe\n    format_instruction = \"\"\n    if output_format == \"body-html\":\n        tags_str = \", \".join(erlaubte_tags) if erlaubte_tags else \"h1, h2, h3, h4, p, a, ol, ul, li, strong, table, hr\"\n        format_instruction = f\"\"\"7. **KRITISCH - Ausgabe als sauberes HTML:**\n   - NUR diese Tags: {tags_str}\n   - KEIN Markdown (keine ##, keine **, keine -)\n   - KEIN div, span, br, img, script, style\n   - Jeder Absatz in <p>-Tags\n   - Überschriften als <h2>, <h3>, <h4>\n   - Listen als <ul>\/<ol> mit <li>\"\"\"",
        "originalFile": "#!\/usr\/bin\/env python3\n\"\"\"\nContent Generation for KI-System\nGenerates content using RAG context, author profiles, and contracts.\n\"\"\"\n\nimport json\nimport sys\n\nsys.path.insert(0, \"\/opt\/scripts\/pipeline\")\n\nfrom config import ANTHROPIC_API_KEY, ANTHROPIC_MODEL, OLLAMA_CHAT_MODEL, OLLAMA_HOST  # noqa: I001, E402\nfrom db import db  # noqa: E402\nfrom embed import search_similar  # noqa: E402\n\n\ndef _repair_json(json_str):\n    \"\"\"\n    Attempt to repair common JSON issues from LLM output.\n\n    Fixes:\n    - Unescaped quotes in strings\n    - Missing commas between array elements\n    - Trailing commas\n    - Control characters in strings\n    \"\"\"\n    import re\n\n    # Remove control characters except newlines and tabs\n    json_str = re.sub(r\"[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f]\", \"\", json_str)\n\n    # Fix common issue: missing comma before closing bracket in arrays\n    json_str = re.sub(r'\"\\s*\\n\\s*]', '\"\\n]', json_str)\n\n    # Fix trailing commas before closing brackets\/braces\n    json_str = re.sub(r\",\\s*}\", \"}\", json_str)\n    json_str = re.sub(r\",\\s*]\", \"]\", json_str)\n\n    # Fix missing commas between array elements (string followed by string)\n    json_str = re.sub(r'\"\\s*\\n\\s*\"', '\",\\n\"', json_str)\n\n    # Fix unescaped quotes within strings (heuristic: quotes not at boundaries)\n    # This is tricky, so we do a simple fix for common patterns\n    lines = json_str.split(\"\\n\")\n    fixed_lines = []\n    for line in lines:\n        # Count quotes - if odd number and line has content, try to fix\n        quote_count = line.count('\"') - line.count('\\\\\"')\n        if quote_count % 2 != 0 and \":\" in line:\n            # Try to escape internal quotes (very basic heuristic)\n            parts = line.split(\":\", 1)\n            if len(parts) == 2:\n                key_part = parts[0]\n                value_part = parts[1]\n                # If value has odd quotes, try to balance\n                if value_part.count('\"') % 2 != 0:\n                    # Add escaped quote or remove problematic char\n                    value_part = value_part.rstrip().rstrip(\",\")\n                    if not value_part.endswith('\"'):\n                        value_part += '\"'\n                    line = key_part + \":\" + value_part\n        fixed_lines.append(line)\n\n    return \"\\n\".join(fixed_lines)\n\n\ndef get_prompt(name):\n    \"\"\"Load prompt from database by name.\"\"\"\n    cursor = db.execute(\n        \"\"\"SELECT content FROM prompts WHERE name = %s AND is_active = 1 ORDER BY version DESC LIMIT 1\"\"\",\n        (name,),\n    )\n    result = cursor.fetchone()\n    cursor.close()\n    return result[\"content\"] if result else None\n\n\ndef get_rag_context(briefing, collection=\"documents\", limit=5):\n    \"\"\"\n    Get relevant context from Qdrant based on briefing.\n    Returns list of chunks with content and metadata.\n    \"\"\"\n    results = search_similar(briefing, collection=collection, limit=limit)\n\n    context_items = []\n    for result in results:\n        context_items.append(\n            {\n                \"content\": result[\"payload\"].get(\"content\", \"\"),\n                \"source\": result[\"payload\"].get(\"document_title\", \"Unknown\"),\n                \"score\": round(result[\"score\"], 4),\n            }\n        )\n\n    return context_items\n\n\ndef get_config_item(item_id, item_type):\n    \"\"\"Load configuration item from content_config table.\"\"\"\n    if not item_id:\n        return None\n\n    cursor = db.execute(\n        \"SELECT name, content FROM content_config WHERE id = %s AND type = %s AND status = 'active'\",\n        (item_id, item_type),\n    )\n    result = cursor.fetchone()\n    cursor.close()\n\n    if result:\n        config = json.loads(result[\"content\"]) if isinstance(result[\"content\"], str) else result[\"content\"]\n        return {\"name\": result[\"name\"], \"config\": config}\n    return None\n\n\ndef get_author_profile(profile_id):\n    \"\"\"Load author profile from database.\"\"\"\n    return get_config_item(profile_id, \"author_profile\")\n\n\ndef get_contract(contract_id):\n    \"\"\"Load content contract from database.\"\"\"\n    return get_config_item(contract_id, \"contract\")\n\n\ndef get_structure(structure_id):\n    \"\"\"Load content structure from database.\"\"\"\n    result = get_config_item(structure_id, \"structure\")\n    if result:\n        # Structure has additional 'type' field in config\n        result[\"type\"] = result[\"config\"].get(\"type\", \"article\")\n    return result\n\n\ndef get_order(order_id):\n    \"\"\"Load content order with all related data.\"\"\"\n    cursor = db.execute(\n        \"\"\"SELECT co.*,\n                  ap.name as profile_name, ap.content as profile_config,\n                  cc.name as contract_name, cc.content as contract_config,\n                  cs.name as structure_name, cs.content as structure_config\n           FROM content_orders co\n           LEFT JOIN content_config ap ON co.author_profile_id = ap.id AND ap.type = 'author_profile'\n           LEFT JOIN content_config cc ON co.contract_id = cc.id AND cc.type = 'contract'\n           LEFT JOIN content_config cs ON co.structure_id = cs.id AND cs.type = 'structure'\n           WHERE co.id = %s\"\"\",\n        (order_id,),\n    )\n    result = cursor.fetchone()\n    cursor.close()\n    return result\n\n\ndef build_generation_prompt(briefing, context, profile, contract, structure=None):\n    \"\"\"Build the content generation prompt.\"\"\"\n\n    # Format context\n    context_text = \"\"\n    for i, ctx in enumerate(context, 1):\n        context_text += f\"\\n[Quelle {i}: {ctx['source']}]\\n{ctx['content']}\\n\"\n\n    # Build rich profile instructions\n    profile_text = \"\"\n    if profile:\n        config = profile.get(\"config\", {})\n        autorenprofil = config.get(\"autorenprofil\", config)  # Support both structures\n\n        # Extract voice\/stimme\n        stimme = autorenprofil.get(\"stimme\", {})\n        stimme_text = \"\"\n        if stimme:\n            stimme_text = f\"\"\"\n### Stimme\/Tonalität:\n- Ton: {stimme.get(\"ton\", \"neutral\")}\n- Perspektive: {stimme.get(\"perspektive\", \"neutral\")}\n- Komplexität: {stimme.get(\"komplexitaet\", \"mittel\")}\n- Autorität: {stimme.get(\"autoritaet\", \"Experte\")}\"\"\"\n\n        # Extract style\/stil\n        stil = autorenprofil.get(\"stil\", {})\n        stil_text = \"\"\n        if stil:\n            fachsprache_beispiele = stil.get(\"fachsprache_beispiele\", [])\n            fachsprache_str = \", \".join(fachsprache_beispiele[:5]) if fachsprache_beispiele else \"\"\n            stil_text = f\"\"\"\n### Stil:\n- Fachsprache: {\"Ja\" if stil.get(\"fachsprache\", False) else \"Nein\"}\n- Fachbegriffe: {fachsprache_str}\n- Satzlänge: {stil.get(\"satzlaenge\", \"mittel\")}\n- Absatzstruktur: {stil.get(\"absatzstruktur\", \"klar gegliedert\")}\"\"\"\n\n        # Extract language patterns\/sprachliche_muster\n        muster = autorenprofil.get(\"sprachliche_muster\", {})\n        muster_text = \"\"\n        if muster:\n            phrasen = muster.get(\"phrasen\", [])\n            phrasen_str = \", \".join([f'\"{p}\"' for p in phrasen[:4]]) if phrasen else \"\"\n            uebergaenge = muster.get(\"uebergaenge\", [])\n            uebergaenge_str = \", \".join([f'\"{u}\"' for u in uebergaenge[:3]]) if uebergaenge else \"\"\n            muster_text = f\"\"\"\n### Sprachliche Muster:\n- Typische Phrasen: {phrasen_str}\n- Übergangsformulierungen: {uebergaenge_str}\"\"\"\n\n        # Extract taboos\/tabus\n        tabus = autorenprofil.get(\"tabus\", [])\n        tabus_text = \"\"\n        if tabus:\n            tabus_str = \", \".join(tabus[:5])\n            tabus_text = f\"\"\"\n### Zu vermeiden (Tabus):\n{tabus_str}\"\"\"\n\n        # Extract core messages\/kernbotschaften\n        kernbotschaften = autorenprofil.get(\"kernbotschaften\", [])\n        kern_text = \"\"\n        if kernbotschaften:\n            kern_str = \"\\n\".join([f\"- {k}\" for k in kernbotschaften[:4]])\n            kern_text = f\"\"\"\n### Kernbotschaften (implizit vermitteln):\n{kern_str}\"\"\"\n\n        # Extract output format (HTML for web profiles)\n        output_format = autorenprofil.get(\"output_format\", {})\n        format_text = \"\"\n        if output_format and output_format.get(\"typ\") == \"html\":\n            erlaubte = output_format.get(\"erlaubte_elemente\", {})\n            verboten = output_format.get(\"verbotene_elemente\", [])\n            regeln = output_format.get(\"struktur_regeln\", [])\n\n            erlaubte_str = []\n            for _kategorie, elemente in erlaubte.items():\n                erlaubte_str.extend(elemente[:3])\n\n            format_text = f\"\"\"\n### Output-Format: HTML\n**Erlaubte Elemente:**\n{\", \".join(erlaubte_str[:10])}\n\n**Struktur-Regeln:**\n- {chr(10).join(\"- \" + r for r in regeln[:4]) if regeln else \"Semantisches HTML verwenden\"}\n\n**Verboten:** {\", \".join(verboten[:4]) if verboten else \"div, span, br, style\"}\"\"\"\n\n        # Combine all profile sections\n        profile_text = f\"\"\"\n## Autorenprofil: {profile.get(\"name\", \"Standard\")}\n{stimme_text}\n{stil_text}\n{muster_text}\n{tabus_text}\n{kern_text}\n{format_text}\n\"\"\"\n\n    # Build contract requirements\n    contract_text = \"\"\n    if contract:\n        config = contract.get(\"config\", {})\n        req = config.get(\"requirements\", {})\n        contract_text = f\"\"\"\nContract: {contract.get(\"name\", \"Standard\")}\n- Wortanzahl: {req.get(\"min_words\", 500)} - {req.get(\"max_words\", 5000)} Wörter\n- Struktur-Validierung: {req.get(\"structure_validation\", True)}\n\"\"\"\n\n    # Build structure instructions\n    structure_text = \"\"\n    if structure:\n        config = structure.get(\"config\", {})\n        structure_text = f\"\"\"\nStruktur-Template: {structure.get(\"name\", \"\")}\n- Typ: {structure.get(\"type\", \"\")}\n- Abschnitte: {json.dumps(config.get(\"sections\", []), ensure_ascii=False)}\n\"\"\"\n\n    # Determine if HTML output is required\n    html_output = False\n    if profile:\n        config = profile.get(\"config\", {})\n        autorenprofil = config.get(\"autorenprofil\", config)\n        output_format = autorenprofil.get(\"output_format\", {})\n        html_output = output_format.get(\"typ\") == \"html\"\n\n    format_instruction = \"\"\n    if html_output:\n        format_instruction = \"\"\"7. **WICHTIG: Ausgabe als wohlformatiertes HTML**\n   - Verwende nur: h1, h2, h3, h4, p, ul, ol, li, strong, a, section, table, tr, td\n   - Jeder h2-Abschnitt mu... [TRUNCATED-b1a598d104e1d301]",
        "structuredPatch": [
            {
                "oldStart": 151,
                "oldLines": 6,
                "newStart": 151,
                "newLines": 148,
                "lines": [
                    "     return result",
                    " ",
                    " ",
                    "+def _parse_new_author_profile(config):",
                    "+    \"\"\"Parse new-style author profile (Cary format) into prompt text.\"\"\"",
                    "+    sections = []",
                    "+",
                    "+    # Haltung",
                    "+    haltung = config.get(\"haltung\", {})",
                    "+    if haltung:",
                    "+        sections.append(f\"\"\"### Haltung:",
                    "+- Grundhaltung: {haltung.get(\"grundhaltung\", \"\")}",
                    "+- Ausrichtung: {haltung.get(\"ausrichtung\", \"\")}",
                    "+- Spannungstoleranz: {haltung.get(\"spannungstoleranz\", \"\")}",
                    "+- Vereinfachung: {haltung.get(\"vereinfachung\", \"\")}\"\"\")",
                    "+",
                    "+    # Tonalität",
                    "+    tonalitaet = config.get(\"tonalitaet\", {})",
                    "+    if tonalitaet:",
                    "+        sections.append(f\"\"\"### Tonalität:",
                    "+- Charakter: {tonalitaet.get(\"charakter\", \"\")}",
                    "+- Stil: {tonalitaet.get(\"stil\", \"\")}",
                    "+- Wirkung: {tonalitaet.get(\"wirkung\", \"\")}",
                    "+- Abgrenzung: {tonalitaet.get(\"abgrenzung\", \"\")}\"\"\")",
                    "+",
                    "+    # Sprachmodus",
                    "+    sprachmodus = config.get(\"sprachmodus\", {})",
                    "+    if sprachmodus:",
                    "+        sections.append(f\"\"\"### Sprachmodus:",
                    "+- Denkstil: {sprachmodus.get(\"denkstil\", \"\")}",
                    "+- Aussagenform: {sprachmodus.get(\"aussagenform\", \"\")}",
                    "+- Fragenfunktion: {sprachmodus.get(\"fragenfunktion\", \"\")}\"\"\")",
                    "+",
                    "+    # Grammatik und Satzbau - WICHTIG für Verbote",
                    "+    grammatik = config.get(\"grammatik_und_satzbau\", {})",
                    "+    if grammatik:",
                    "+        verbote = []",
                    "+        if grammatik.get(\"stakkato\") == \"ausgeschlossen\":",
                    "+            verbote.append(\"Stakkato-Sätze\")",
                    "+        if grammatik.get(\"einschuebe\") == \"keine\":",
                    "+            verbote.append(\"Einschübe\")",
                    "+        if grammatik.get(\"gedankenstriche\") == \"verboten\":",
                    "+            verbote.append(\"Gedankenstriche (–)\")",
                    "+",
                    "+        sections.append(f\"\"\"### Grammatik und Satzbau:",
                    "+- Sätze: {grammatik.get(\"saetze\", \"\")}",
                    "+- Rhythmus: {grammatik.get(\"rhythmus\", \"\")}",
                    "+- **VERBOTEN:** {\", \".join(verbote) if verbote else \"keine\"}\"\"\")",
                    "+",
                    "+    # Wortwahl",
                    "+    wortwahl = config.get(\"wortwahl\", {})",
                    "+    if wortwahl:",
                    "+        verboten = []",
                    "+        if wortwahl.get(\"buzzwords\") == \"ausgeschlossen\":",
                    "+            verboten.append(\"Buzzwords\")",
                    "+        if wortwahl.get(\"methodennamen\") == \"ausgeschlossen\":",
                    "+            verboten.append(\"Methodennamen\")",
                    "+",
                    "+        sections.append(f\"\"\"### Wortwahl:",
                    "+- Niveau: {wortwahl.get(\"niveau\", \"\")}",
                    "+- Begriffe: {wortwahl.get(\"begriffe\", \"\")}",
                    "+- **VERBOTEN:** {\", \".join(verboten) if verboten else \"keine\"}\"\"\")",
                    "+",
                    "+    # Adressierung",
                    "+    adressierung = config.get(\"adressierung\", {})",
                    "+    if adressierung:",
                    "+        sections.append(f\"\"\"### Adressierung:",
                    "+- Form: {adressierung.get(\"form\", \"Sie\")}",
                    "+- Beziehung: {adressierung.get(\"beziehung\", \"\")}",
                    "+- Einladung: {adressierung.get(\"einladung\", \"\")}\"\"\")",
                    "+",
                    "+    # Metaphern",
                    "+    metaphern = config.get(\"metaphern\", {})",
                    "+    if metaphern:",
                    "+        sections.append(f\"\"\"### Metaphern:",
                    "+- Einsatz: {metaphern.get(\"einsatz\", \"\")}",
                    "+- Herkunft: {metaphern.get(\"herkunft\", \"\")}",
                    "+- Konsistenz: {metaphern.get(\"konsistenz\", \"\")}\"\"\")",
                    "+",
                    "+    return \"\\n\\n\".join(sections)",
                    "+",
                    "+",
                    "+def _parse_new_structure(config):",
                    "+    \"\"\"Parse new-style structure profile into prompt text and format info.\"\"\"",
                    "+    sections = []",
                    "+    output_format = None",
                    "+    erlaubte_tags = []",
                    "+",
                    "+    # Ausgabe-Format",
                    "+    ausgabe = config.get(\"ausgabe\", {})",
                    "+    if ausgabe:",
                    "+        output_format = ausgabe.get(\"format\", \"markdown\")",
                    "+        erlaubte_tags = ausgabe.get(\"erlaubte_tags\", [])",
                    "+        verbotene_tags = ausgabe.get(\"verbotene_tags\", [])",
                    "+",
                    "+        if output_format == \"body-html\":",
                    "+            sections.append(f\"\"\"### Ausgabe-Format: HTML",
                    "+- **Nur diese Tags verwenden:** {\", \".join(erlaubte_tags)}",
                    "+- **Verboten:** {\", \".join(verbotene_tags)}",
                    "+- {ausgabe.get(\"hinweis\", \"Sauberes semantisches HTML\")}\"\"\")",
                    "+",
                    "+    # Gesamtaufbau",
                    "+    aufbau = config.get(\"gesamtaufbau\", {})",
                    "+    if aufbau:",
                    "+        sections.append(f\"\"\"### Gesamtaufbau:",
                    "+- Form: {aufbau.get(\"form\", \"\")}",
                    "+- Dramaturgie: {aufbau.get(\"dramaturgie\", \"\")}",
                    "+- Linearität: {aufbau.get(\"linearitaet\", \"\")}",
                    "+- Themensprünge: {aufbau.get(\"themenspruenge\", \"\")}\"\"\")",
                    "+",
                    "+    # Einstieg",
                    "+    einstieg = config.get(\"einstieg\", {})",
                    "+    if einstieg:",
                    "+        sections.append(f\"\"\"### Einstieg:",
                    "+- Funktion: {einstieg.get(\"funktion\", \"\")}",
                    "+- Inhaltstyp: {einstieg.get(\"inhaltstyp\", \"\")}",
                    "+- Ausschluss: {einstieg.get(\"ausschluss\", \"\")}\"\"\")",
                    "+",
                    "+    # Hauptteil-Blöcke",
                    "+    hauptteil = config.get(\"hauptteil\", {})",
                    "+    bloecke = hauptteil.get(\"bloecke\", [])",
                    "+    if bloecke:",
                    "+        bloecke_text = \"\\n\".join([f\"  {i+1}. {b.get('fokus', '')} → {b.get('ziel', '')}\" for i, b in enumerate(bloecke)])",
                    "+        sections.append(f\"\"\"### Hauptteil-Struktur:",
                    "+{bloecke_text}\"\"\")",
                    "+",
                    "+    # Schluss",
                    "+    schluss = config.get(\"schluss\", {})",
                    "+    if schluss:",
                    "+        sections.append(f\"\"\"### Schluss:",
                    "+- Typ: {schluss.get(\"typ\", \"\")}",
                    "+- Funktion: {schluss.get(\"funktion\", \"\")}",
                    "+- Abgrenzung: {schluss.get(\"abgrenzung\", \"\")}\"\"\")",
                    "+",
                    "+    # Formatierung",
                    "+    formatierung = config.get(\"formatierung\", {})",
                    "+    if formatierung:",
                    "+        ausschluss = formatierung.get(\"ausschluss\", [])",
                    "+        if ausschluss:",
                    "+            sections.append(f\"\"\"### Formatierung verboten:",
                    "+{\", \".join(ausschluss)}\"\"\")",
                    "+",
                    "+    return \"\\n\\n\".join(sections), output_format, erlaubte_tags",
                    "+",
                    "+",
                    " def build_generation_prompt(briefing, context, profile, contract, structure=None):",
                    "     \"\"\"Build the content generation prompt.\"\"\"",
                    " "
                ]
            },
            {
                "oldStart": 159,
                "oldLines": 98,
                "newStart": 301,
                "newLines": 52,
                "lines": [
                    "     for i, ctx in enumerate(context, 1):",
                    "         context_text += f\"\\n[Quelle {i}: {ctx['source']}]\\n{ctx['content']}\\n\"",
                    " ",
                    "-    # Build rich profile instructions",
                    "+    # Build profile instructions - detect new vs old format",
                    "     profile_text = \"\"",
                    "     if profile:",
                    "         config = profile.get(\"config\", {})",
                    "-        autorenprofil = config.get(\"autorenprofil\", config)  # Support both structures",
                    " ",
                    "-        # Extract voice\/stimme",
                    "-        stimme = autorenprofil.get(\"stimme\", {})",
                    "-        stimme_text = \"\"",
                    "-        if stimme:",
                    "-            stimme_text = f\"\"\"",
                    "+        # Detect new format (has \"haltung\" or \"tonalitaet\" at top level)",
                    "+        if \"haltung\" in config or \"tonalitaet\" in config or \"grammatik_und_satzbau\" in config:",
                    "+            # New Cary-style profile",
                    "+            profile_text = f\"\"\"",
                    "+## Autorenprofil: {profile.get(\"name\", \"Standard\")}",
                    "+",
                    "+{_parse_new_author_profile(config)}",
                    "+\"\"\"",
                    "+        else:",
                    "+            # Old format - keep backwards compatibility",
                    "+            autorenprofil = config.get(\"autorenprofil\", config)",
                    "+",
                    "+            stimme = autorenprofil.get(\"stimme\", {})",
                    "+            stimme_text = \"\"",
                    "+            if stimme:",
                    "+                stimme_text = f\"\"\"",
                    " ### Stimme\/Tonalität:",
                    " - Ton: {stimme.get(\"ton\", \"neutral\")}",
                    " - Perspektive: {stimme.get(\"perspektive\", \"neutral\")}",
                    "-- Komplexität: {stimme.get(\"komplexitaet\", \"mittel\")}",
                    "-- Autorität: {stimme.get(\"autoritaet\", \"Experte\")}\"\"\"",
                    "+- Komplexität: {stimme.get(\"komplexitaet\", \"mittel\")}\"\"\"",
                    " ",
                    "-        # Extract style\/stil",
                    "-        stil = autorenprofil.get(\"stil\", {})",
                    "-        stil_text = \"\"",
                    "-        if stil:",
                    "-            fachsprache_beispiele = stil.get(\"fachsprache_beispiele\", [])",
                    "-            fachsprache_str = \", \".join(fachsprache_beispiele[:5]) if fachsprache_beispiele else \"\"",
                    "-            stil_text = f\"\"\"",
                    "+            stil = autorenprofil.get(\"stil\", {})",
                    "+            stil_text = \"\"",
                    "+            if stil:",
                    "+                stil_text = f\"\"\"",
                    " ### Stil:",
                    " - Fachsprache: {\"Ja\" if stil.get(\"fachsprache\", False) else \"Nein\"}",
                    "-- Fachbegriffe: {fachsprache_str}",
                    "-- Satzlänge: {stil.get(\"satzlaenge\", \"mittel\")}",
                    "-- Absatzstruktur: {stil.get(\"absatzstruktur\", \"klar gegliedert\")}\"\"\"",
                    "+- Satzlänge: {stil.get(\"satzlaenge\", \"mittel\")}\"\"\"",
                    " ",
                    "-        # Extract language patterns\/sprachliche_muster",
                    "-        muster = autorenprofil.get(\"sprachliche_muster\", {})",
                    "-        muster_text = \"\"",
                    "-        if muster:",
                    "-            phrasen = muster.get(\"phrasen\", [])",
                    "-            phrasen_str = \", \".join([f'\"{p}\"' for p in phrasen[:4]]) if phrasen else \"\"",
                    "-            uebergaenge = muster.get(\"uebergaenge\", [])",
                    "-            uebergaenge_str = \", \".join([f'\"{u}\"' for u in uebergaenge[:3]]) if uebergaenge else \"\"",
                    "-            muster_text = f\"\"\"",
                    "-### Sprachliche Muster:",
                    "-- Typische Phrasen: {phrasen_str}",
                    "-- Übergangsformulierungen: {uebergaenge_str}\"\"\"",
                    "+            tabus = autorenprofil.get(\"tabus\", [])",
                    "+            tabus_text = \"\"",
                    "+            if tabus:",
                    "+                tabus_text = f\"\"\"",
                    "+### Zu vermeiden:",
                    "+{\", \".join(tabus[:5])}\"\"\"",
                    " ",
                    "-        # Extract taboos\/tabus",
                    "-        tabus = autorenprofil.get(\"tabus\", [])",
                    "-        tabus_text = \"\"",
                    "-        if tabus:",
                    "-            tabus_str = \", \".join(tabus[:5])",
                    "-            tabus_text = f\"\"\"",
                    "-### Zu vermeiden (Tabus):",
                    "-{tabus_str}\"\"\"",
                    "-",
                    "-        # Extract core messages\/kernbotschaften",
                    "-        kernbotschaften = autorenprofil.get(\"kernbotschaften\", [])",
                    "-        kern_text = \"\"",
                    "-        if kernbotschaften:",
                    "-            kern_str = \"\\n\".join([f\"- {k}\" for k in kernbotschaften[:4]])",
                    "-            kern_text = f\"\"\"",
                    "-### Kernbotschaften (implizit vermitteln):",
                    "-{kern_str}\"\"\"",
                    "-",
                    "-        # Extract output format (HTML for web profiles)",
                    "-        output_format = autorenprofil.get(\"output_format\", {})",
                    "-        format_text = \"\"",
                    "-        if output_format and output_format.get(\"typ\") == \"html\":",
                    "-            erlaubte = output_format.get(\"erlaubte_elemente\", {})",
                    "-            verboten = output_format.get(\"verbotene_elemente\", [])",
                    "-            regeln = output_format.get(\"struktur_regeln\", [])",
                    "-",
                    "-            erlaubte_str = []",
                    "-            for _kategorie, elemente in erlaubte.items():",
                    "-                erlaubte_str.extend(elemente[:3])",
                    "-",
                    "-            format_text = f\"\"\"",
                    "-### Output-Format: HTML",
                    "-**Erlaubte Elemente:**",
                    "-{\", \".join(erlaubte_str[:10])}",
                    "-",
                    "-**Struktur-Regeln:**",
                    "-- {chr(10).join(\"- \" + r for r in regeln[:4]) if regeln else \"Semantisches HTML verwenden\"}",
                    "-",
                    "-**Verboten:** {\", \".join(verboten[:4]) if verboten else \"div, span, br, style\"}\"\"\"",
                    "-",
                    "-        # Combine all profile sections",
                    "-        profile_text = f\"\"\"",
                    "+            profile_text = f\"\"\"",
                    " ## Autorenprofil: {profile.get(\"name\", \"Standard\")}",
                    " {stimme_text}",
                    " {stil_text}",
                    "-{muster_text}",
                    " {tabus_text}",
                    "-{kern_text}",
                    "-{format_text}",
                    " \"\"\"",
                    " ",
                    "     # Build contract requirements"
                ]
            },
            {
                "oldStart": 261,
                "oldLines": 34,
                "newStart": 357,
                "newLines": 43,
                "lines": [
                    "         contract_text = f\"\"\"",
                    " Contract: {contract.get(\"name\", \"Standard\")}",
                    " - Wortanzahl: {req.get(\"min_words\", 500)} - {req.get(\"max_words\", 5000)} Wörter",
                    "-- Struktur-Validierung: {req.get(\"structure_validation\", True)}",
                    " \"\"\"",
                    " ",
                    "-    # Build structure instructions",
                    "+    # Build structure instructions - detect new vs old format",
                    "     structure_text = \"\"",
                    "+    output_format = \"markdown\"",
                    "+    erlaubte_tags = []",
                    "+",
                    "     if structure:",
                    "         config = structure.get(\"config\", {})",
                    "-        structure_text = f\"\"\"",
                    "+",
                    "+        # Detect new format (has \"ausgabe\" at top level)",
                    "+        if \"ausgabe\" in config or \"gesamtaufbau\" in config:",
                    "+            # New Blog-Struktur format",
                    "+            parsed_text, output_format, erlaubte_tags = _parse_new_structure(config)",
                    "+            structure_text = f\"\"\"",
                    "+## Struktur: {structure.get(\"name\", \"\")}",
                    "+",
                    "+{parsed_text}",
                    "+\"\"\"",
                    "+        else:",
                    "+            # Old format",
                    "+            structure_text = f\"\"\"",
                    " Struktur-Template: {structure.get(\"name\", \"\")}",
                    "-- Typ: {structure.get(\"type\", \"\")}",
                    " - Abschnitte: {json.dumps(config.get(\"sections\", []), ensure_ascii=False)}",
                    " \"\"\"",
                    " ",
                    "-    # Determine if HTML output is required",
                    "-    html_output = False",
                    "-    if profile:",
                    "-        config = profile.get(\"config\", {})",
                    "-        autorenprofil = config.get(\"autorenprofil\", config)",
                    "-        output_format = autorenprofil.get(\"output_format\", {})",
                    "-        html_output = output_format.get(\"typ\") == \"html\"",
                    "-",
                    "+    # Build format instruction based on structure's ausgabe",
                    "     format_instruction = \"\"",
                    "-    if html_output:",
                    "-        format_instruction = \"\"\"7. **WICHTIG: Ausgabe als wohlformatiertes HTML**",
                    "-   - Verwende nur: h1, h2, h3, h4, p, ul, ol, li, strong, a, section, table, tr, td",
                    "-   - Jeder h2-Abschnitt muss in einer eigenen <section> stehen",
                    "-   - Kein Markdown, kein div\/span\/br",
                    "-   - Fließtext immer in <p>-Tags\"\"\"",
                    "+    if output_format == \"body-html\":",
                    "+        tags_str = \", \".join(erlaubte_tags) if erlaubte_tags else \"h1, h2, h3, h4, p, a, ol, ul, li, strong, table, hr\"",
                    "+        format_instruction = f\"\"\"7. **KRITISCH - Ausgabe als sauberes HTML:**",
                    "+   - NUR diese Tags: {tags_str}",
                    "+   - KEIN Markdown (keine ##, keine **, keine -)",
                    "+   - KEIN div, span, br, img, script, style",
                    "+   - Jeder Absatz in <p>-Tags",
                    "+   - Überschriften als <h2>, <h3>, <h4>",
                    "+   - Listen als <ul>\/<ol> mit <li>\"\"\"",
                    " ",
                    "     # Load generate prompt template from database",
                    "     # Note: Assumes db.connect() was called by the caller (generate_content)"
                ]
            }
        ],
        "userModified": false,
        "replaceAll": false
    }
}
← Vorheriger Zur Liste Nächster →