Kihagyás

LLM‑alapú dokumentumdaraboló modul

A modul Python alapú szolgáltatásként valósult meg, amelyet egy FastAPI-alapú REST API tesz elérhetővé.

Input:

  • A szolgáltatás egyetlen bemeneti paraméterként egy dokumentumfájlt vár, amely .pdf vagy .docx formátumban érkezhet.
  • A beérkező fájlt egy POST kérés keretében kell elküldeni az alábbi végpontra:
  • /api/llm-based-document-chunking
  • A fájlt a FastAPI automatikusan bytes típusra alakítja, amelyet a MainOrchestrator továbbít a teljes feldolgozási pipeline-nak.

Output:

  • A válasz egy JSON objektum, amely a következő két elemet tartalmazza:
  • chunks: A létrehozott szövegrészletek listája DataChunkDTO formátumban. Minden elem egyetlen Markdown chunkot tartalmaz (chunk: str).
  • totalTokenUsage: Ez tartalmazza az LLM-hívások során felhasznált tokenek számát (pl. prompt_tokens, completion_tokens, total_tokens).

1. Bevezetés

Ez a dokumentáció egy LLM alapú dokumentumfeldolgozó és -daraboló rendszer működését mutatja be. A modul fő célja, hogy különböző formátumú dokumentumokból (PDF, DOCX) strukturált, szemantikailag értelmes és könnyen kezelhető szövegrészleteket, ún. „chunkokat“ hozzon létre.

A folyamat kulcsa egy hierarchikus struktúrát építő prompt. Ez a prompt mondja meg az LLM-nek, hogy: - Mi legyen a végső kimenet: egy többszintű JSON struktúra, ahol minden elem (chunk) egy címsort (title), annak aktuális szinjét (level), a kezdősor számát (start_line) és az alárendelt elemek listáját (children) tartalmazza. - Hogyan ismerje fel az eltérő chunkokba tartozó szövegrészleteket: ne csak a Markdown szintaxisra ( #, ## stb.) támaszkodjon, hanem a tipikus tipográfiai és szemantikai jelekre is (nagybetűs sor, számozott bekezdés, egy új szekció szemantikai értelemben vett kezdete).

Ezzel a hierarchia‑vezérelt prompttal a rendszer képes: - Logikai szerkezetet építeni a dokumentum belső tematikus tagolásából, még akkor is, ha az eredeti forrás nem tartalmaz formális címsorjelölést. - Egyértelműen hozzárendelni az egyes albekezdéseket a megfelelő szülő‑elemhez. - Token‑takarékosan működni, mivel a prompt minden futásnál csak a hierarchikus JSON struktúrát adja vissza, így elkerülhető a teljes dokumentum output-ként való visszaadása.

A hierarchiadetektáló promptra épülve a feldolgozás egy többlépcsős pipeline‑ban valósul meg, amely magában foglalja a fájlok konverzióját, általános és gránit specifikus előfeldolgozási logikákat, az LLM által vezérelt hierarchiafelismerést, a modell által generált struktúra javítását, és végül a dokumentum feldarabolását.

2. Fő komponensek

A teljes munkafolyamat a bejövő API kéréstől a kész chunkok visszaadásáig a következő főbb lépésekre bontható:

Fájl Fő osztály / függvény Rövid leírás
llm_auto_chunking_api.py FastAPI router REST végpont /api/llm-based-document-chunking.
orchestrator.py MainOrchestrator A teljes pipeline koordinátora.
base.py BaseInitializer Globális konfigurációk betöltése, LLM‑kliens és spaCy inicializálás, segédobjektumok központi létrehozása.
text_to_md.py MarkdownConverter Többféle megoldással (Azure, docling) konvertál különböző formátumú dokumentumokat (PDF, DOCX) Markdownra.
base_preprocessor.py BasePreProcessor Általános előfeldolgozás az egységes struktúra kialakításának érdekében (HTML‑táblák, Markdown-táblák).
custom_preprocessor.py CustomPreProcessor A BasePreProcessor kiterjesztése, amely az ügyfélspecifikus előfeldolgozási szabályok megvalósítását teszi lehetővé.
llm_document_processor.py LLMDocumentProcessorWith* PromptOutput/StructuredOutput Iteratív LLM hívások (Gemini-output: prompt‑alapú, OpenAI-output: Pydantic‑struktúrált), részleges vagy csonka JSON‑válaszok javítása és egyesítése.
fix_json_structure.py JSONFixer Az LLM JSON output logikájának a javítása különböző szabályrendszerek mentén.
base_chunker.py BaseChunker A végső chunk objektum kialakítása az alapértelmezett feldolgozások mentén.
custom_chunker.py CustomChunker A BaseChunker kiterjesztése, amely az ügyfélspecifikus darabolási szabályok megvalósítását teszi lehetővé.

3. Részletes folyamatleírás

3.1 Konvertálás - MarkdownConverter (text_to_md.py)

Ez a rész felelős azért, hogy a különböző bemeneti fájlokat egységes Markdown szöveggé alakítsa.

  • Funciók:
  • A .pdf és .docx formátumokat támogatja.
    • Többféle konverziós „backendet“ képes használni, melyek a konfigurációban választhatók ki:
      • docling: Egy nyílt forráskódú könyvtár (markdown alapú táblázatok).
      • azure: Az Azure Document Intelligence szolgáltatás prebuilt-layout modelljét használja. Különösen hatékony a táblázatok és komplex elrendezések értelmezésében (HTML alapú táblázatok).
    • Ideiglenes fájlok kezelése::
    • A konverzióhoz a fájlt lemezre kell menteni, mert mind a docling, mind az azure fájlútvonalon keresztül dolgozik, nem bytes objektumokkal. Ezért a MarkdownConverter ideiglenes fájlokat hoz létre, amelyeket a feldolgozás végén automatikusan töröl.
    • A jövőben szükség esetén átalakítható, hogy közvetlenül bytes alapon működjön.
    • Azure oldal-limit:
    • Az Azure-alapú konverzió során a max_input_page paraméter határozza meg, hány oldalt lehet feldolgozni egy dokumentumból. Ez védi a rendszert a túl nagy dokumentumoktól, illetve a költségek optimalizálását szolgálja.
    • PDF → DOCX konverzió két lépésben (Azure előfeldolgozás):
      • A DOCX fájlok oldalainak számlálásához a rendszer PDF-formátumba konvertálja a dokumentumot, mert az DOCX nem tárolja az oldalak számozását. Ehhez két különböző konverter is rendelkezésre áll:
      • LibreOffice (soffice) – előnyben részesített megoldás a szerveren történő futtatás miatt.
      • docx2pdf – fallback opció Windows és macOS rendszereken, ha a LibreOffice nem elérhető vagy hibát jelez.
        • Elméletileg macOS‑en is futnia kellene, a gyakorlatban azonban több alkalommal hibát tapasztaltunk, ezért macOS alatt célszerű a LibreOffice‑alapú megoldást választani. Ügyelj arra, hogy a LibreOffice soffice (futtatható programfájlja) szerepeljen a PATH környezeti változóban.
        • Alternatív megoldás a PATH kihagyására: pdf_docx_to_md_azure függvény soffice command-ját írd át erre: "/Applications/LibreOffice.app/Contents/MacOS/soffice"

3.2 Előfeldolgozás - CustomPreProcessor & BasePreProcessor (custom_preprocessor.py & base_preprocessor.py)

Az előfeldolgozó komponens két rétegből áll össze: - BasePreProcessor: - Univerzális pipeline, amely minden bemeneti Markdownon lefut. - Biztosítja, hogy a további lépések (LLM, chunker) konzisztens, zajmentes inputot kapjanak – függetlenül a dokumentum struktúrájától. - Feladatai: - HTML Táblázat Tisztítás (HTMLTableCleaner): Kifejezetten az Azure által generált Markdown-ra optimalizálva. Eltávolítja az ismétlődő élőfejeket és élőlábakat, összevonja a több oldalra tört táblázatokat, és javítja a hibás HTML táblázat-struktúrákat. - Markdown Táblázat Tisztítás (MarkdownTableCleaner): Normalizálja a Markdown táblázatok elválasztó sorait és eltávolítja a felesleges szóközöket a cellákból. - Sorszámozás: Minden sort egy egyedi, lineXXXXXX: előtaggal lát el. Ez a sorszámozás szükséges a sorok azonosításához. - CustomPreProcessor: - A BasePreProcessor kiterjesztése, ahol ügyfélspecifikus szabályok foglalnak helyet. - Lehetővé teszi, hogy a rendszer az általános tisztításon túl reagáljon egyedi üzleti logikákra - Feladatai: - Jelenleg kizárólag a táblázatokra (Markdown és HTML formában) koncentrál és két fő területet érint: - Strukturális szintek bejelölése (LEVEL:N): - Az eredeti DOCX fájlokban gyakran előfordulnak olyan cellák, amelyek vizuálisan (lila háttérszínnel) kiemeltek, és szemantikailag címként értelmezhetők. - felismeri ezeket a cellákat, - kiolvassa a bal oldali behúzás mértékét - és a hozzájuk tartozó sorokat ellátja egy LEVEL:N előtaggal (ahol N a hierarchikus szintet jelöli), - Ez a lépés segít explicit szerkezeti jeleket adni az LLM‑nek, így jelentősen javítja a címfelismerés és az alárendeltségi viszonyok pontosságát. - Táblázatok újrarendezése: - Egyes dokumentumtípusoknál az egyes kiemelt sorok nem mindig logikai sorrendben szerepelnek a táblázatban. A CustomPreProcessor felismeri ezeket a DOCX táblázatsorokat: - külön gyűjti és elemzi, - az átalakított Markdown/HTML táblákban újrapozicionálja úgy, hogy azok logikailag összetartozó szakaszok után kerüljenek.

3.3 LLM alapú hierarchia építés - LLMDocumentProcessorWithStructuredOutput & LLMDocumentProcessorWithPromptOutput (llm_document_processor.py)

A dokumentumhierarchia felismerése a rendszer egyik központi feladata: a cél az, hogy a sorszámozott Markdown szövegből egy LLM segítségével strukturált, többszintű JSON készüljön.

A rendszer ehhez két külön osztályt használ, attól függően, hogy melyik LLM-et alkalmazzuk: - LLMDocumentProcessorWithStructuredOutput - OpenAI-hoz optimalizálva: - Kihasználja a modell azon képességét, hogy közvetlenül Pydantic modelleknek megfelelő, garantáltan helyes JSON struktúrát adjon vissza. Ez a megközelítés megbízhatóbb. - Kezeli azokat az eseteket is, amikor a modell a maximális token-hossz miatt megszakítja a generálást (LengthFinishReasonError), és megpróbálja a részleges eredményt is feldolgozni. - LLMDocumentProcessorWithPromptOutput - Geminihez optimalizálva: - A Gemini API ezzel szemben nem támogatja az önmagukra hivatkozó Pydantic modellek közvetlen visszaadását. Ezért ott prompt-alapú, szöveges JSON generálásra van szükség.

A két osztály közös működési elvei: - javítja a befejezetlen vagy hibás JSON-t, - iteratív feldolgozás, csak a még nem feldolgozott sorokat küldi el újra az LLM-nek, - az LLM részleges válaszait egyesíti, amíg a teljes struktúra össze nem áll.

Példa a várt JSON-kimenetre (HierarchicalChunk struktúrában):

[
  {
    "title": "1. Bevezetés",
    "level": 1,
    "start_line": "line000005",
    "has_children": "Y",
    "children": [
      {
        "title": "1.1 Célkitűzések",
        "level": 2,
        "start_line": "line000010",
        "has_children": "N",
        "children": []
      },
      {
        "title": "1.2 Fogalmak",
        "level": 2,
        "start_line": "line000020",
        "has_children": "Y",
        "children": [
          {
            "title": "1.2.1 Alapfogalmak",
            "level": 3,
            "start_line": "line000025",
            "has_children": "N",
            "children": []
          }
        ]
      }
    ]
  }
]

3.4 Hierarchia javítás - JSONFixer (fix_json_structure.py)

Az LLM által generált hierarchia tartalmazhat felesleges vagy logikailag pontatlan elemeket. A JSONFixer feladata ezeknek a hibáknak a szabályalapú korrekciója.

  • Funkciók:
  • Szintek korrekciója (fix_hierarchy_and_levels): Biztosítja, hogy a beágyazási szintek és a level attribútumok konzisztensek legyenek. Két lépésben dolgozik:
    • Újrahierarchizálás: Az elemeket újraosztja, hogy a megfelelő szintű elemek valóban a megfelelő elem alá kerüljenek.
    • Szintkorrekció: A szinteket újraszámolja, hogy azok valóban tükrözzék a hierarchia mélységét.
  • Felesleges elemek eltávolítása (postprocess_json): Különböző szabályok alapján eltávolít olyan elemeket, amelyek nem valódi címsorok.
  • Kezdő elem létrehozása: Ha a dokumentum nem címsorral kezdődik, egy „dummy“ elemet szúr be az elejére line000001-re, hogy a dokumentum legelején lévő szöveg se vesszen el.

3.5 Chunk létrehozás - CustomChunker & BaseChunker (custom_chunker.py és base_chunker.py)

Az utolsó lépésben a letisztított hierarchia és a sorszámozott szöveg alapján létrejönnek a végső szövegdarabok.

A daraboló komponens két rétegből áll össze: - BasePreProcessor: - Univerzális pipeline, amely minden bemeneten lefut. - Feladatai: - ChunkProcessor: A beágyazott hierarchiát lineáris listává bontja, hogy minden egyes elem önállóan feldolgozható legyen. - ChunkModifier: - Fejlécek generálása: Minden chunk elején automatikusan létrehoz egy több szintből álló fejlécet (dokumentumcím → fejezet → alfejezet), amely kontextust biztosít a chunkhoz. - Tábla-kezelés: Az Azure HTML-alapú tábláit <table> tagekkel egészíti ki, a Markdown-alapú táblákhoz pedig hiányzó elválasztó sorokat illeszt be. - Szűrés: Kizárja a valódi tartalom nélküli chunkokat. - ChunkLengthControl: - Méretkontroll: Gondoskodik arról, hogy egy chunk ne haladja meg a megadott max_chunk_size értéket. - Szegmentálás: Ha szükséges, tovább darabolja a chunkot: - A táblázatokat egyben hagyja, nem vágja szét. - A szöveget mondathatárok mentén darabolja, spaCy vagy HuSpaCy modell segítségével. - CustomPreProcessor: - A BaseChunker kiterjesztése, ahol ügyfélspecifikus szabályok foglalnak helyet. - Lehetővé teszi, hogy a rendszer az általános tisztításon túl reagáljon egyedi üzleti logikákra - Feladati: - Jelenleg csak egy extra szűrési lépés található benne a Markdown típusú táblázatokra vonatkozóan