app/core/chunk_payload.py aktualisiert
Some checks failed
Deploy mindnet to llm-node / deploy (push) Failing after 1s
Some checks failed
Deploy mindnet to llm-node / deploy (push) Failing after 1s
This commit is contained in:
parent
a807cc8bd1
commit
22885a4857
|
|
@ -1,37 +1,150 @@
|
||||||
from __future__ import annotations
|
#!/usr/bin/env python3
|
||||||
from typing import Dict, List
|
# -*- coding: utf-8 -*-
|
||||||
from .chunker import Chunk
|
"""
|
||||||
from .parser import extract_wikilinks
|
Modul: app/core/chunk_payload.py
|
||||||
|
Version: 1.1.0
|
||||||
|
Datum: 2025-09-09
|
||||||
|
|
||||||
def make_chunk_payloads(note_meta: Dict, path: str, chunks: List[Chunk]) -> List[Dict]:
|
Kurzbeschreibung
|
||||||
res = []
|
----------------
|
||||||
|
Erzeugt Qdrant-Payloads für Text-Chunks einer Note. Jeder Chunk enthält
|
||||||
|
den tatsächlichen Text unter dem Schlüssel ``text``. Dadurch kann der
|
||||||
|
Exporter den vollständigen Body verlässlich aus Chunks rekonstruieren,
|
||||||
|
falls ``notes.payload.fulltext`` fehlt.
|
||||||
|
|
||||||
|
Wesentliche Features
|
||||||
|
--------------------
|
||||||
|
- Stabile, idempotente Payload-Struktur für Chunks
|
||||||
|
- Persistenter Chunk-Text (``text``)
|
||||||
|
- Extraktion von Wikilinks pro Chunk (``wikilinks`` & ``references``)
|
||||||
|
- Pfadübernahme (relativ zum Vault, wird vom Aufrufer geliefert)
|
||||||
|
- Bereinigung leerer Felder (keine ``None``/leere Collections im Payload)
|
||||||
|
|
||||||
|
Abhängigkeiten
|
||||||
|
--------------
|
||||||
|
- ``app.core.chunker.Chunk`` (Felder: id, index, char_start, char_end,
|
||||||
|
token_count, section_title, section_path, neighbors_prev, neighbors_next, text)
|
||||||
|
- ``app.core.parser.extract_wikilinks``
|
||||||
|
|
||||||
|
Beispiele (CLI – Sichtprüfung)
|
||||||
|
------------------------------
|
||||||
|
python3 -m app.core.chunk_payload --from-file ./vault/demo.md --print
|
||||||
|
|
||||||
|
Hinweis
|
||||||
|
-------
|
||||||
|
Die CLI ist ein Hilfsmittel zur Sichtprüfung. Im Produktpfad ruft der
|
||||||
|
Importer ``make_chunk_payloads(...)`` direkt auf.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
from typing import Dict, List, Any
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Projektinterne Imports
|
||||||
|
from app.core.chunker import Chunk
|
||||||
|
from app.core.parser import extract_wikilinks, parse_markdown
|
||||||
|
except Exception: # pragma: no cover - Fallback für relative Ausführung
|
||||||
|
from .chunker import Chunk # type: ignore
|
||||||
|
from .parser import extract_wikilinks, parse_markdown # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Utils
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def _drop_empty(d: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
"""Entfernt leere/None-Felder aus einem Dict (für saubere Payloads)."""
|
||||||
|
return {k: v for k, v in d.items() if v not in (None, [], {}, "")}
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Kernfunktion
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def make_chunk_payloads(note_meta: Dict[str, Any], path: str, chunks: List[Chunk]) -> List[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
Baut Payloads für alle ``chunks`` der gegebenen Note.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
note_meta : Dict[str, Any]
|
||||||
|
Minimale Metadaten der Note (mind. ``id``, ``title``; optional ``type``,
|
||||||
|
``area``, ``project``, ``tags``, ``lang``).
|
||||||
|
path : str
|
||||||
|
Relativer Pfad der Note innerhalb des Vaults (z. B. "area/topic/file.md").
|
||||||
|
chunks : List[Chunk]
|
||||||
|
Liste vorsegmentierter Chunks (vgl. app.core.chunker.Chunk).
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
List[Dict[str, Any]]
|
||||||
|
Payload-Objekte, bereit für Qdrant-Upserts.
|
||||||
|
"""
|
||||||
|
res: List[Dict[str, Any]] = []
|
||||||
for ch in chunks:
|
for ch in chunks:
|
||||||
wikilinks = extract_wikilinks(ch.text)
|
wikilinks = extract_wikilinks(getattr(ch, "text", "") or "")
|
||||||
payload = {
|
payload = {
|
||||||
"id": ch.id,
|
"id": getattr(ch, "id", None),
|
||||||
"note_id": note_meta["id"],
|
"note_id": note_meta.get("id"),
|
||||||
"note_title": note_meta["title"],
|
"note_title": note_meta.get("title"),
|
||||||
"chunk_index": ch.index,
|
"chunk_index": getattr(ch, "index", None),
|
||||||
"char_start": ch.char_start,
|
"char_start": getattr(ch, "char_start", None),
|
||||||
"char_end": ch.char_end,
|
"char_end": getattr(ch, "char_end", None),
|
||||||
"token_count": ch.token_count,
|
"token_count": getattr(ch, "token_count", None),
|
||||||
"type": note_meta.get("type"),
|
"section_title": getattr(ch, "section_title", None),
|
||||||
"area": note_meta.get("area"),
|
"section_path": getattr(ch, "section_path", None),
|
||||||
"project": note_meta.get("project"),
|
|
||||||
"tags": note_meta.get("tags", []),
|
|
||||||
"section_title": ch.section_title,
|
|
||||||
"section_path": ch.section_path,
|
|
||||||
"lang": note_meta.get("lang"),
|
"lang": note_meta.get("lang"),
|
||||||
"wikilinks": wikilinks,
|
"wikilinks": wikilinks,
|
||||||
"external_links": [], # (optional später ergänzen)
|
"external_links": [], # kann später ergänzt werden
|
||||||
"references": [{"target_id": w, "kind": "wikilink"} for w in wikilinks],
|
"references": [{"target_id": w, "kind": "wikilink"} for w in wikilinks],
|
||||||
"neighbors": {
|
"neighbors": {
|
||||||
"prev": ch.neighbors_prev,
|
"prev": getattr(ch, "neighbors_prev", None),
|
||||||
"next": ch.neighbors_next
|
"next": getattr(ch, "neighbors_next", None),
|
||||||
},
|
},
|
||||||
"path": path,
|
"path": path, # vom Aufrufer relativ geliefert
|
||||||
|
"text": getattr(ch, "text", None), # WICHTIG für Export/Rekonstruktion
|
||||||
}
|
}
|
||||||
# None/Leere bereinigen
|
res.append(_drop_empty(payload))
|
||||||
payload = {k: v for k, v in payload.items() if v not in (None, [], {})}
|
|
||||||
res.append(payload)
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# CLI – nur zur Sichtprüfung / Debug
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def _cli() -> None:
|
||||||
|
ap = argparse.ArgumentParser(description="Vorschau: Chunk-Payloads erzeugen und anzeigen")
|
||||||
|
ap.add_argument("--from-file", dest="src", required=True, help="Pfad zu einer Markdown-Datei")
|
||||||
|
ap.add_argument("--print", dest="do_print", action="store_true", help="Payload auf stdout ausgeben")
|
||||||
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
note = parse_markdown(args.src)
|
||||||
|
note_meta = {
|
||||||
|
"id": note.frontmatter.get("id") or note.frontmatter.get("note_id"),
|
||||||
|
"title": note.frontmatter.get("title"),
|
||||||
|
"type": note.frontmatter.get("type"),
|
||||||
|
"area": note.frontmatter.get("area"),
|
||||||
|
"project": note.frontmatter.get("project"),
|
||||||
|
"tags": note.frontmatter.get("tags", []),
|
||||||
|
"lang": note.frontmatter.get("lang"),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Chunking (benötigt app.core.chunker)
|
||||||
|
from app.core.chunker import chunk_markdown # lazy import
|
||||||
|
chunks = chunk_markdown(note.body or "")
|
||||||
|
|
||||||
|
# Vault-Root heuristisch relativieren (nur für Demo)
|
||||||
|
vault_root = os.path.dirname(os.path.dirname(args.src)) # heuristisch
|
||||||
|
rel_path = os.path.relpath(args.src, vault_root).replace("\\", "/").lstrip("/")
|
||||||
|
|
||||||
|
payloads = make_chunk_payloads(note_meta, rel_path, chunks)
|
||||||
|
|
||||||
|
if args.do_print:
|
||||||
|
print(json.dumps(payloads, ensure_ascii=False, indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": # pragma: no cover
|
||||||
|
_cli()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user