Zum Inhalt

generation.py


1. Zweck und Rolle der Datei

generation.py ist die serverseitige Integrations- und Orchestrierungsschicht der Dokumentgenerierungsseite. Die Datei enthält nur einen sehr kleinen Teil der sichtbaren Dash-Oberfläche. Die eigentliche Generation-Oberfläche wird als HTML-Anwendung in einem iframe geladen. generation.py stellt für dieses Frontend die benötigten API-Endpunkte bereit und verbindet es mit zentralen Daten-, Konfigurations- und LLM-Diensten.

Die Datei erfüllt fünf zentrale Aufgaben:

  1. Registrierung der Generation-Seite in Dash.
  2. Einbettung des externen Generation-Frontends über ein iframe.
  3. Bereitstellung der Flask-Routen für Konfiguration, Suche, Speicherung und Generierung.
  4. Aufbau des LLM-Prompts aus Kapitelkonfiguration, Produktdaten, Feldern, Phrase Libraries und Beispielen.
  5. Start asynchroner beziehungsweise gestreamter LLM-Aufrufe über den zentralen Runtime-Service.

generation.py ist vor allem ein Backend-Controller für das in flask/generation/generation.html eingebettete Frontend.


2. Position in der Gesamtarchitektur

Browser
  │
  ▼
Dash-Seite /generation
  │
  └── Iframe: flask/generation/generation.html
          │
          ├── lädt Produkte und Konfigurationen
          ├── sucht Referenzdokumente
          ├── lädt und speichert Produktdaten
          ├── startet Generierungen
          └── startet Review-Chats
                  │
                  ▼
          Flask-Blueprint /api
                  │
                  ▼
          setup_routes(router) in generation.py
                  │
          ┌────────┼─────────────────────┐
          ▼       ▼                   ▼
      DATABASE  DATA_LOADER        LLM-Streaming
      Konfig.   Produktdaten       start_stream_oai
          └───────┴──────────┬───────────┘
                            ▼
                  Ergebnis-Stream in STREAMS

3. Modulinitialisierung und Page-Aufbau

3.1 Registrierung

Direkt beim Import registriert sich das Modul als Dash-Page:

dash.register_page(__name__)
this_app = dash.get_app()

Damit wird die Seite Teil der Dash-Pages-Struktur. Ein expliziter Pfad oder Anzeigename wird in der vorliegenden Datei nicht gesetzt. Dash leitet diese Metadaten daher aus dem Modulnamen beziehungsweise der Standardkonfiguration ab.

Die Ausgabe

print("generation.py has been registered under ", __name__)

ist ein einfaches Start-Debugging und kein strukturiertes Logging.

3.2 Layout

Das Layout besteht ausschließlich aus einem iframe:

layout = html.Div([
    html.Iframe(
        id="generationIframe",
        src="flask/generation/generation.html",
        style={"minWidth": "100%", "height": "100vh", "border": "none"},
    ),
])

Konsequenzen

  • Die Dash-Page besitzt keine eigenen Formulare, Dropdowns oder Generierungsbuttons.
  • Komponenten-IDs aus der eigentlichen Generation-Oberfläche befinden sich nicht in dieser Python-Datei.
  • Änderungen an sichtbaren Feldern müssen in generation.html beziehungsweise dessen JavaScript und Styling vorgenommen werden.
  • Änderungen an Datenverarbeitung, Prompt-Erstellung oder Persistenz erfolgen in den hier definierten API-Routen oder in den darunterliegenden Services.

3.3 Iframe-Resizing

Ein clientseitiger Dash-Callback aktiviert iFrameResize bei Änderungen des URL-Pfads:

this_app.clientside_callback(
    """
    function(arg) {
        iFrameResize({ log: false }, '#generationIframe');
        return window.dash_clientside.no_update;
    }
    """,
    Output("generationIframe", "src"),
    Input("url", "pathname"),
    prevent_initial_call=False,
)

Der Callback nutzt den Output generationIframe.src technisch nur, um bei Navigation ausgeführt zu werden. Er gibt no_update zurück und ändert die Quelle nicht.

Voraussetzung: Die JavaScript-Funktion iFrameResize muss global durch die App oder Assets eingebunden sein. Fehlt die Bibliothek, schlägt der clientseitige Callback fehl.


4. Zentrale Laufzeitabhängigkeiten

4.1 DATABASE

DATABASE wird aus share importiert und ist die zentrale Konfigurationsquelle. Die Datei erwartet mindestens folgende Bereiche:

DATABASE
├── instructions
│   ├── generation
│   ├── generationPW
│   ├── generationCP
│   ├── generationDisc
│   ├── ExampleGenerateDraft
│   └── CustomSentenceGenerateDraft
├── documentTypes
├── chapters
├── fields
├── groups
└── phrases

Die konkrete Struktur wird an mehreren Stellen direkt vorausgesetzt. Änderungen am Schema von DATABASE wirken sich deshalb unmittelbar auf die Generation aus.

4.2 DATA_LOADER

DATA_LOADER ist die produktbezogene Datenzugriffsschicht. Verwendete Methoden:

  • search(field, value) sucht Datensätze.
  • updateByProductCode(productCode, values) aktualisiert einen Produktdatensatz.
  • upload(True) persistiert den aktuellen Zustand.
  • delete(productCode) löscht einen Datensatz.

Die API-Routen arbeiten dabei mit DataFrame-basierten Ergebnissen und konvertieren diese über .to_dict('records').

4.3 db_examples

db_examples ist eine Liste von Referenzdokumenten. Erwartete Felder sind unter anderem:

  • Document Number
  • Title oder Bulletin Title
  • Text
  • Product Number
  • Product Title
  • Product Line
  • Document Level

Diese Datenbasis dient sowohl der Suche als auch der Einbettung ausgewählter Dokumenttexte in den Generierungsprompt.

4.4 LLM-Streaming

Die Datei importiert:

STREAMS, stream_oai, start_stream_oai

Tatsächlich verwendet wird in dieser Datei nur start_stream_oai; stream_oai wird nicht direkt aufgerufen. STREAMS wird im Fehlerfall bereinigt.

Das Muster lautet:

  1. Connection-ID erzeugen.
  2. Prompt oder Conversation zusammenstellen.
  3. start_stream_oai(...) aufrufen.
  4. Connection-ID an das Frontend zurückgeben.
  5. Das Frontend ruft den Stream über eine an anderer Stelle implementierte Route ab.

Die Abrufroute für den Stream ist nicht Bestandteil der vorliegenden Datei.


5. End-to-End-Ablauf einer Dokumentgenerierung

Sequenz-Diagramm

5.1 Vorbelegung laden

Das Frontend lädt über GET /api/get_tcs_fields_for_product:

  • vorhandene Produktwerte,
  • gespeicherten Produkt-, Dokument- und Sprachzustand,
  • gespeicherte ausgewählte Beispiele,
  • gespeicherte benutzerdefinierte Sätze,
  • die für den effektiven Dokumenttyp erforderlichen TCS-Felder.

5.2 Beispiele auswählen

Über POST /api/get_examples können Referenzdokumente per Dokumentnummer, Produktnummer, Titel, Produktname, Volltext oder Filter gefunden werden. Ausgewählte Dokumentnummern werden beim Prompt-Aufbau wieder gegen db_examples aufgelöst.

5.3 Prompt erstellen

POST /api/generatev2 ruft intern get_generation_prompt(..., http=False) auf. Diese Funktion erstellt:

  • eine dokumenttypspezifische Systemnachricht,
  • eine Kapiteloperation,
  • ausgewählte TCS-Felder,
  • Bulletpoint-Anforderungen,
  • Strukturvorgaben,
  • Phrase Libraries,
  • ausgewählte Referenzdokumente,
  • verpflichtende benutzerdefinierte Sätze.

5.4 Stream starten

generatev2 erzeugt eine Connection-ID und startet anschließend:

start_stream_oai(
    connectionID,
    prompt,
    systemMessage,
    deployment_name,
)

Die HTTP-Antwort enthält nicht den generierten Text, sondern nur:

{
  "CID": "<connection-id>"
}

Damit ist die Generation entkoppelt: Der Startrequest endet schnell, während die Antwort separat gestreamt wird.


6. Prompt-Aufbau im Detail

Die zentrale Funktion ist:

def get_generation_prompt(message=None, http=True):

Sie hat zwei Betriebsarten:

  • http=True: direkter API-Aufruf, gibt eine JSON-Antwort zurück und zeigt den Prompt nur Administratoren.
  • http=False: interner Aufruf durch generatev2, gibt (prompt, systemMessage, deployment_name) zurück.

6.1 Eingabepayload

Verwendete Felder der Request-Nachricht:

Feld Bedeutung Pflicht
documentType Interner Dokumenttyp Ja
chapter Zu generierendes Kapitel Ja
language Zielsprache Ja
tcsFields Produkt- und fachbezogene Eingabefelder Ja
chosenExamples Liste ausgewählter Dokumentnummern Nein
customSentences Zusätzliche Pflichtsätze mit Kapitelzuordnung Nein
wordCount Überschreibt die Standardwortzahl des Kapitels Nein

tcsFields muss mindestens so strukturiert sein, dass productTitle gelesen werden kann. Weitere Felder werden anhand der Kapitelkonfiguration aufgenommen.

6.2 Auswahl der Systemnachricht

Standardmäßig wird verwendet:

DATABASE["instructions"]["generation"]

Bestimmte Dokumenttypen schalten auf spezialisierte Instruktionen um:

  • Product-Warning-Varianten → generationPW
  • Concise-Page-Varianten → generationCP
  • informationBulletingenerationDisc

Der Vergleich erfolgt aktuell über fest codierte String-Ketten. Für neue Dokumenttypen ist deshalb zu prüfen, ob eine neue Sonderregel erforderlich ist.

6.3 Laden der Kapitel- und Dokumentkonfiguration

Die Funktion liest:

db_chapter = DATABASE.get("chapters").get(req_chapter, {})
db_document_type = DATABASE.get("documentTypes").get(req_document_type, {})
db_settings = db_document_type.get("Settings", {})

Aus dem Kapitel kommen:

  • Operation
  • WordCount
  • RequirementsBulletPoints
  • Structure
  • Fields

Aus den Dokumenttyp-Settings kommen die einzubindenden Libraries.

6.4 Platzhalterersetzung

Folgende Platzhalter werden ersetzt:

  • [WORD_COUNT]
  • [productTitle]
  • [LANGUAGE]

Die Ersetzung ist auf einzelne Konfigurationsbereiche verteilt:

operation = operation.replace(...)
requirements_bulletpoints = requirements_bulletpoints.replace(...)
structure = structure.replace(...)

Neue Platzhalter müssen derzeit explizit im Python-Code ergänzt werden. Eine zentrale Template-Funktion wäre leichter erweiterbar und testbar.

6.5 Aufnahme der TCS-Felder

Für jedes übertragene Feld gilt:

if fieldId in db_chapter["Fields"] and fieldValue.strip():
    fieldName = DATABASE["fields"][fieldId]["Name"]
    prompt += fieldName + ": " + fieldValue + "\n"

Es werden nur Felder aufgenommen, die für das Kapitel konfiguriert sind. Dadurch bestimmt die Kapitelkonfiguration, welche Produktdaten das Modell sieht.

Kritischer Punkt: fieldValue.strip() setzt einen String voraus. Zahlen, Listen, boolesche Werte oder None führen zu Fehlern. Vor einer Erweiterung um neue Feldtypen sollte eine Normalisierungsfunktion eingeführt werden.

6.6 Phrase Libraries

render_phrase_library unterstützt zwei Grundformen:

Liste
└── Phrase

Dictionary
├── Bereich → Liste
└── Bereich → Dictionary → Liste

Fall 2 Beispielausgabe:

### Phrase Library: Safety Phrases

[problem_description]

(short)
- phrase one
- phrase two

Kritischer Implementierungsfehler

Die Funktion erhält den gesamten bisherigen Prompt und gibt diesen erweitert zurück:

def render_phrase_library(prompt, lib_name, lib_content):
    prompt += ...
    return prompt

Der Aufrufer hängt diesen vollständigen Rückgabewert nochmals an den bestehenden Prompt:

prompt += render_phrase_library(prompt, lib_name, lib_content)

Dadurch wird der bisherige Prompt bei jeder Library dupliziert. Korrekt wäre entweder:

prompt = render_phrase_library(prompt, lib_name, lib_content)

oder eine Funktion, die ausschließlich den neuen Library-Block zurückgibt.

Dieser Punkt ist vor weiteren Prompt-Erweiterungen zu korrigieren, weil mehrere Libraries die Promptgröße stark und unbeabsichtigt erhöhen können.

6.7 Ausgewählte Beispiele

Wenn chosenExamples gesetzt ist, wird für jede Dokumentnummer der vollständige Text aus db_examples geladen:

ex = next(
    e for e in db_examples
    if e["Document Number"].strip() == ex_id
)

Der Prompt erhält zunächst ExampleGenerateDraft und anschließend die vollständigen Beispieltexte in ihrer Auswahlreihenfolge.

Zu beachten:

  • Nicht gefundene IDs werden still übersprungen.
  • Es gibt keine Begrenzung für Anzahl oder Textlänge.
  • Die lineare Suche wird für jede ID erneut ausgeführt.
  • Vollständige Dokumente können den Tokenverbrauch stark erhöhen.

Für Skalierung und Vorhersagbarkeit empfiehlt sich ein vorab aufgebauter Index nach Dokumentnummer und ein konfigurierbares Token- oder Zeichenbudget.

6.8 Benutzerdefinierte Pflichtsätze

customSentences wird als Liste von Objekten erwartet:

[
  {
    "text": "Mandatory sentence",
    "chapters": ["Introduction", "Safety"]
  }
]

Die Verarbeitung:

  1. entfernt Einträge ohne Text oder Kapitel,
  2. gruppiert Sätze nach Kapitel,
  3. entfernt Duplikate unter Erhalt der Reihenfolge,
  4. ergänzt CustomSentenceGenerateDraft,
  5. schreibt die Sätze als verpflichtende Sätze in den Prompt.

Wichtig: Die Funktion filtert nicht auf das aktuell generierte req_chapter. Sie fügt alle in der Payload enthaltenen Kapitelgruppen in den Prompt ein. Das kann gewollt sein, sollte aber fachlich geprüft werden. Für kapitelweise Generation wäre eine Filterung auf das aktuelle Kapitel naheliegend.

6.9 Modellwahl

Das Deployment ist fest gesetzt:

deployment_name = "gpt-4o"

Die Kapitel- oder Dokumenttypkonfiguration enthält möglicherweise bereits LLM-bezogene Daten, diese werden hier aber nicht zur Modellwahl verwendet. Ein zukünftiges Feature für unterschiedliche Modelle muss diesen Hardcode ersetzen und gleichzeitig eine sichere Allowlist verwenden.


7. API-Referenz

Alle Routen werden innerhalb setup_routes(router) registriert. Bei einem Blueprint-Prefix /api ergeben sich die folgenden effektiven Pfade.

7.1 POST /api/get_generation_prompt

Zweck: Erstellt den Prompt zur Diagnose oder Vorschau.

Berechtigung: Nur Administratoren erhalten den Prompt. Nicht-Administratoren erhalten HTTP 403.

Erfolg:

{
  "prompt": "<system message>\n<prompt>\nusing gpt-4o"
}

Fehler:

  • 422, wenn Pflichtparameter fehlen.
  • Potenzielle 500-Fehler werden in dieser Route nicht lokal abgefangen.

Sicherheitsrelevanz: Der Endpunkt kann interne Systeminstruktionen, Produktdaten und vollständige Referenztexte offenlegen. Die Admin-Prüfung ist daher wesentlich.

7.2 POST /api/generatev2

Zweck: Startet die eigentliche Dokumentgenerierung.

Ablauf:

  1. SHA-256-basierte Connection-ID aus der aktuellen Zeit erzeugen.
  2. Prompt intern erstellen.
  3. LLM-Stream starten.
  4. CID zurückgeben.

Erfolg: HTTP 200 mit CID.

Fehler: HTTP 500 mit Fehlermeldung und vollständigem Traceback.

Kritische Punkte:

  • Die CID basiert nur auf time.time(). uuid.uuid4() oder secrets.token_urlsafe() wäre semantisch eindeutiger.
  • Der vollständige Traceback wird an den Client zurückgegeben und kann interne Implementierungsdetails offenlegen.
  • Eine explizite Berechtigungsprüfung ist in generatev2 nicht sichtbar.

7.3 POST /api/get_examples

Zweck: Sucht und filtert Referenzdokumente.

Request-Felder:

  • exampleText
  • filterProductLineActive
  • filterProductLineValue
  • filterLevelActive
  • filterLevelValue
  • filterProdDocName

Response:

{
  "examples": [],
  "products": []
}

examples enthält flache Dokumentergebnisse. products gruppiert dieselben Ergebnisse nach Produktnummer.

Die Suchmodi werden in Prioritätsreihenfolge ausgewählt:

  1. Titel- und Produktnamensuche
  2. mehrere Dokumentnummern
  3. einzelne Dokumentnummer
  4. Produktnummer
  5. reine Filterung
  6. freie Volltextsuche

Diese Reihenfolge ist wichtig. Sobald ein früher Modus greift, werden spätere Modi nicht mehr ausgeführt.

7.4 GET /api/get_tcs_fields_for_product

Zweck: Lädt Produktvorbelegungen und baut die für einen Dokumenttyp relevanten Feldgruppen auf.

Query-Parameter:

  • productCode, verpflichtend
  • documentType, optional

Dokumenttyp-Priorität:

expliziter Query-Parameter
    vor
im Produkt gespeicherter Dokumenttyp

Response:

{
  "TCS_FIELDS": [
    {
      "id": "group-id",
      "name": "Group name",
      "fields": []
    }
  ],
  "PRESETTINGS": {
    "productType": null,
    "documentType": null,
    "language": null,
    "savedAt": null,
    "source": "original",
    "customSentences": null,
    "selectedExamples": null
  }
}

Wenn kein Produkt existiert, wird ein temporäres Grundobjekt erzeugt. Der Endpunkt kann deshalb auch für neue Produkte verwendet werden.

7.5 GET /api/get_word_count_for_chapter

Zweck: Liefert die konfigurierte Wortzahl eines Kapitels.

Query-Parameter: chapter

Erfolg:

{
  "words": 200
}

Risiko: DATABASE.get('chapters').get(chapter).get(...) schlägt fehl, wenn das Kapitel unbekannt ist. Der Fehler wird als 404 zurückgegeben.

7.6 POST /api/upload_product

Zweck: Speichert Produktfelder und den UI-Zustand.

Pflichtfeld: productCode

Vor dem Speichern werden leere Werte für folgende Felder aus dem Produktcache ergänzt:

  • frame aus frames
  • productlinetest aus prod_line
  • mainsys aus main_system_affected

selectedExamples und customSentences werden als JSON-Strings gespeichert. Zusätzlich setzt die Route:

  • lastSavedAt in UTC,
  • lastSavedBy,
  • productNumber, falls noch nicht vorhanden.

Danach folgen:

DATA_LOADER.updateByProductCode
→ DATA_LOADER.upload(True)
→ update_database()

Damit wird nicht nur der Datensatz aktualisiert, sondern auch der persistierte Datenbestand und anschließend die geteilte Runtime-Datenbank aktualisiert.

7.7 POST /api/delete_product

Zweck: Löscht einen Produktdatensatz.

Berechtigung: Nur Administratoren.

Ablauf: löschen, hochladen, globale Datenbank aktualisieren.

Hinweis: Die Fehlermeldung enthält einen fest codierten persönlichen Ansprechpartner. Dies sollte durch eine rollenbasierte oder konfigurierbare Supportangabe ersetzt werden.

7.8 GET /api/get_generated_texts_for_product

Zweck: Lädt gespeicherte Review-Texte für alle Kapitel eines Dokumenttyps.

Für jedes Kapitel wird im Produktdatensatz der Schlüssel gebildet:

review_text_key = f"reviewText_{chapter}"

Nur nicht leere Werte werden zurückgegeben:

{
  "generatedTexts": {
    "Chapter A": "...",
    "Chapter B": "..."
  }
}

7.9 GET /api/get_products

Zweck: Gibt die gecachte Produktliste zurück.

Datenquelle: get_products_cached().

7.10 POST /api/chat_review

Zweck: Startet einen gestreamten Review-Chat für einen bestehenden generierten Text.

Request-Felder:

  • text: aktuelle Benutzerfrage,
  • reviewText: zu überarbeitender Text,
  • selectedExamples: optionale Referenzen,
  • conversation: bisheriger Chatverlauf.

Wenn die Conversation nicht mit einer Systemnachricht beginnt, wird eine feste Systemnachricht vorangestellt. Anschließend werden Review-Text, Beispiele und Nutzerfrage zu einer neuen User-Nachricht kombiniert.

Der LLM-Aufruf verwendet das Conversation-Format:

start_stream_oai(
    connectionID,
    conversation=conversation,
    deployment_name="gpt-4o",
)

Auch hier erhält das Frontend nur die CID.


8. Beispielsuchlogik im Detail

8.1 Tokennormalisierung

normalize_token implementiert eine einfache englische Singularisierung:

  • iesy
  • bestimmte Pluralendungen wie ses, xes, ches → Kürzung
  • abschließendes s → Entfernung, außer bei ss

Diese Heuristik ist keine vollständige linguistische Stammformanalyse. Sie ist für englische technische Suchbegriffe gedacht und kann bei unregelmäßigen Wörtern falsche Normalformen erzeugen.

8.2 Query-Aufbereitung

prepare_query:

  1. extrahiert nur alphanumerische ASCII-Tokens,
  2. normalisiert sie,
  3. entfernt Duplikate unter Erhalt der Reihenfolge.

Umlaute und andere Unicode-Buchstaben werden durch das Muster [a-zA-Z0-9]+ nicht vollständig unterstützt.

8.3 Proximity-Matching

proximity_match_text sucht Präfixtreffer jedes Query-Tokens und prüft anschließend, ob alle normalisierten Query-Tokens innerhalb eines Zeichenfensters von standardmäßig 60 Zeichen vorkommen.

Das bedeutet:

  • Alle Suchbegriffe müssen lokal nahe beieinander stehen.
  • Reihenfolge ist nicht vorgeschrieben.
  • Präfixe sind erlaubt.
  • Die Einheit ist ein Zeichenfenster, keine Token- oder Satzdistanz.

8.4 Filtersemantik

filters_match kombiniert Kategorien per UND und Werte innerhalb einer Kategorie per ODER:

(Product Line A ODER Product Line B)
UND
(Level 3 ODER Level 5)

Leere Wertelisten deaktivieren die Einschränkung faktisch, auch wenn der zugehörige Aktiv-Flag gesetzt ist.

8.5 Ergebnisformatierung und Gruppierung

format_example begrenzt nur die Vorschau auf 250 Zeichen. Der vollständige Text bleibt im API-Ergebnis enthalten.

group_examples_by_product gruppiert nach Produktnummer und sortiert:

  1. absteigend nach Dokumentanzahl,
  2. aufsteigend nach Produktnummer.

Fehlende Produktnummern werden als Unknown Product zusammengefasst.


9. Produkt- und Feldmodell

9.1 Effektiver Dokumenttyp

Beim Laden der TCS-Felder gilt:

effective_document_type = normalize(documentType) or presettings["documentType"]

Dadurch kann das Frontend einen gespeicherten Dokumenttyp überschreiben. Ohne effektiven Dokumenttyp werden nur Vorbelegungen und keine Felder geliefert.

9.2 Feldakkumulation

Für alle Kapitel des Dokumenttyps werden die benötigten Felder gesammelt. OrderedDict.fromkeys verhindert Duplikate und bewahrt die Reihenfolge.

Die Kernfelder productNumber und productTitle werden immer zuerst aufgenommen.

9.3 Felddetails

Jedes Feld erhält unter anderem:

  • ID,
  • Anzeigename,
  • Definition,
  • Guideline,
  • Placeholder,
  • Read-only-Status,
  • Sortierpriorität,
  • Editierbarkeit,
  • gespeicherten Wert.

Anschließend werden die Felder anhand von DATABASE['groups'] gruppiert. Felder, die in keiner Gruppe vorkommen, werden nicht in TCS_FIELDS ausgegeben.

9.4 Persistenzformat

Ausgewählte Beispiele und benutzerdefinierte Sätze werden beim Speichern JSON-serialisiert und beim Laden über safe_json_load wieder deserialisiert.

safe_json_load gibt bei ungültigem JSON den ursprünglichen String zurück. Das verhindert einen harten Fehler, erzeugt aber einen variablen Rückgabetyp. Das Frontend muss daher derzeit mit Liste, Dictionary oder String umgehen können.


10. Hilfsfunktionen außerhalb des aktiven Hauptflusses

Die Datei enthält zwei Transformationsfunktionen, die von keiner der gezeigten Routen aufgerufen werden:

translate_tcs_fields_to_grouped_json(df)

Transformiert eine tabellarische Feldkonfiguration anhand einer GROUP_ORDER-Zeile in gruppiertes JSON.

translate_document_types_to_grouped_json(df, admin=False)

Transformiert eine tabellarische Dokumenttyp-/Kapitelkonfiguration in die Bereiche:

  • productTypes
  • documentTypes
  • chapters

Diese Funktionen könnten aus einem früheren Initialisierungs- oder Admin-Workflow stammen. Vor einer Entfernung ist eine repositoryweite Verwendungsanalyse erforderlich.

11. Entwickler-Kurzreferenz

Start einer Generation

POST /api/generatev2
  → get_generation_prompt(http=False)
    → Systeminstruktion auswählen
    → Kapitelkonfiguration laden
    → TCS-Felder einfügen
    → Phrase Libraries einfügen
    → ausgewählte Beispiele einfügen
    → Custom Sentences einfügen
  → start_stream_oai(CID, prompt, systemMessage, "gpt-4o")
  → CID an Frontend

Laden der Generation-Maske

GET /api/get_tcs_fields_for_product
  → Produkt über DATA_LOADER suchen
  → PRESETTINGS normalisieren
  → effektiven Dokumenttyp bestimmen
  → Felder aller Kapitel akkumulieren
  → Felddetails aus DATABASE laden
  → Felder nach DATABASE.groups gruppieren

Speichern

POST /api/upload_product
  → fehlende Stammdaten aus Produktcache ergänzen
  → Listen als JSON serialisieren
  → Auditfelder setzen
  → DATA_LOADER aktualisieren
  → persistieren
  → Runtime-Datenbank aktualisieren

Wichtigste Stellen für Erweiterungen

  • Dokumenttyp- und Kapitelregeln: DATABASE
  • UI und Interaktion: flask/generation/generation.html
  • Promptaufbau: get_generation_prompt
  • Referenzsuche: get_examples und Suchhilfsfunktionen
  • Produktfelder: get_tcs_fields_for_product
  • Persistenz: upload_product
  • Review-Assistenz: chat_review
  • LLM-Laufzeit: start_stream_oai in energyai_elements.py

12. Fazit

Die Generation basiert auf einem konfigurationsgetriebenen Kapitelmodell. Das Frontend liefert Dokumenttyp, Kapitel, Sprache, Produktfelder und optionale Beispiele. generation.py reichert diese Daten mit Instruktionen, Kapitelregeln und Phrase Libraries aus DATABASE an und startet anschließend einen gestreamten LLM-Aufruf. Produktzustände, ausgewählte Beispiele und Review-Texte werden über DATA_LOADER persistiert.