Pablan, as it stands
Self-hosted knowledge management for SMEs: a split-screen Markdown editor whose sections an LLM refines while you write, and RAG question answering over the documents that result. FastAPI + Postgres/pgvector on the back, SvelteKit on the front, everything OpenAI-compatible and self-hostable. Squashed into a single commit; the development history stays local. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CA43ZJda8Rbp2hKXNy8f6b
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
from app.rag.chunking import TARGET_CHUNK_CHARS, chunk_markdown
|
||||
|
||||
|
||||
def test_heading_paths_follow_hierarchy() -> None:
|
||||
md = (
|
||||
"Intro before any heading.\n\n"
|
||||
"## Wartung\n\nWöchentlich schmieren.\n\n"
|
||||
"### Schmierstoffe\n\nNur GX-220 verwenden.\n\n"
|
||||
"## Sicherheit\n\nLichtvorhang nie überbrücken.\n"
|
||||
)
|
||||
chunks = chunk_markdown(md, "Maschinenhandbuch")
|
||||
paths = [chunk.heading_path for chunk in chunks]
|
||||
assert paths == [
|
||||
"Maschinenhandbuch",
|
||||
"Maschinenhandbuch › Wartung",
|
||||
"Maschinenhandbuch › Wartung › Schmierstoffe",
|
||||
"Maschinenhandbuch › Sicherheit",
|
||||
]
|
||||
assert "GX-220" in chunks[2].content
|
||||
|
||||
|
||||
def test_leading_h1_equal_to_title_is_not_duplicated() -> None:
|
||||
md = "# Handbuch\n\nText direkt unter dem Titel.\n\n## Details\n\nMehr.\n"
|
||||
chunks = chunk_markdown(md, "Handbuch")
|
||||
assert chunks[0].heading_path == "Handbuch"
|
||||
assert chunks[1].heading_path == "Handbuch › Details"
|
||||
|
||||
|
||||
def test_oversized_section_is_split_at_paragraphs() -> None:
|
||||
paragraph = "Absatz mit ausreichend vielen Wörtern für den Test. " * 20
|
||||
md = "## Lang\n\n" + "\n\n".join([paragraph] * 5)
|
||||
chunks = chunk_markdown(md, "Doc")
|
||||
assert len(chunks) > 1
|
||||
assert all(len(chunk.content) <= TARGET_CHUNK_CHARS + 100 for chunk in chunks)
|
||||
assert all(chunk.heading_path == "Doc › Lang" for chunk in chunks)
|
||||
|
||||
|
||||
def test_code_fences_are_never_split() -> None:
|
||||
fence = "```\n" + "\n\n".join(["zeile eins", "zeile zwei", "zeile drei"]) + "\n```"
|
||||
filler = "Wort " * 500
|
||||
md = f"## Code\n\n{filler}\n\n{fence}\n\n{filler}"
|
||||
chunks = chunk_markdown(md, "Doc")
|
||||
fenced = [chunk for chunk in chunks if "```" in chunk.content]
|
||||
for chunk in fenced:
|
||||
assert chunk.content.count("```") % 2 == 0, "chunk split inside a fence"
|
||||
|
||||
|
||||
def test_heading_inside_fence_is_not_a_section() -> None:
|
||||
md = "## Skript\n\n```\n# kein heading, nur ein Kommentar\necho hi\n```\n"
|
||||
chunks = chunk_markdown(md, "Doc")
|
||||
assert len(chunks) == 1
|
||||
assert chunks[0].heading_path == "Doc › Skript"
|
||||
|
||||
|
||||
def test_empty_document_yields_no_chunks() -> None:
|
||||
assert chunk_markdown("", "Leer") == []
|
||||
assert chunk_markdown("\n\n \n", "Leer") == []
|
||||
Reference in New Issue
Block a user