feat(kb): ingest rechtsprechung corpus
This commit is contained in:
@@ -8,6 +8,7 @@ import pytest
|
||||
from agent.retrieve import ChunkResult
|
||||
from agent.generate import (
|
||||
REFUSAL_MESSAGE,
|
||||
SYSTEM_PROMPT,
|
||||
UNCERTAIN_MESSAGE,
|
||||
answer_question,
|
||||
build_user_content,
|
||||
@@ -37,6 +38,10 @@ class TestValidateAnswer:
|
||||
assert validate_answer("Siehe lb-min-02 für Details.", ["lb-min-02"]) == []
|
||||
|
||||
|
||||
def test_system_prompt_requires_nonofficial_source_disclosure():
|
||||
assert "nicht amtlich" in SYSTEM_PROMPT
|
||||
|
||||
|
||||
class TestRefusalDetection:
|
||||
def test_refusal_phrase(self):
|
||||
assert looks_like_refusal("Dazu enthält die Wissensbasis keine Aussage.")
|
||||
|
||||
@@ -134,4 +134,109 @@ def test_ris_entry(tmp_path, monkeypatch):
|
||||
assert 'legal_bases: ["TestG"]' in md
|
||||
assert "## § 1. Geltungsbereich" in md
|
||||
assert "(1) Dieses Gesetz gilt für alle." in md
|
||||
assert "ris-nso-06" in md # ID-Zeile im Body
|
||||
assert "ris-nso-06" in md # ID-Zeile im Body
|
||||
|
||||
|
||||
def _rj_catalog():
|
||||
return {"source": "rj", "updated": None, "next_seq": 1, "entries": {}}
|
||||
|
||||
|
||||
def _rj_stats():
|
||||
return {"rj_written": 0, "rj_unparsed": [], "rj_empty": []}
|
||||
|
||||
|
||||
def test_rj_rechtssatz_preserves_court_date_and_norm(tmp_path, monkeypatch):
|
||||
root = tmp_path / ".rechtsprechung"
|
||||
source = root / "originale" / "JJR_test.md"
|
||||
source.parent.mkdir(parents=True)
|
||||
source.write_text(
|
||||
"# Rechtssatz\n\n"
|
||||
"**Gericht:** OGH\n"
|
||||
"**Entscheidungsdatum:** 15. 7. 1954\n"
|
||||
"**Geschäftszahl:** 4 Ob 100/54\n"
|
||||
"**Norm:** AngG § 26 Z 4\n"
|
||||
"**Rechtssatz:** Ein Austrittsgrund ist unverzüglich geltend zu machen.\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setattr(ing, "RJ_DIR", root)
|
||||
|
||||
slug, md = ing.rj_entry(source, _rj_catalog(), _rj_stats())
|
||||
|
||||
assert slug == "rj_jjr-test"
|
||||
assert "id: rj-rjs-001" in md
|
||||
assert 'chapter: "OGH-Rechtssatz"' in md
|
||||
assert "stand: 1954-07" in md
|
||||
assert 'legal_bases: ["AngG § 26 Z 4"]' in md
|
||||
assert "## Rechtssatz" in md
|
||||
|
||||
|
||||
def test_rj_volltext_splits_long_reasoning_at_paragraphs(tmp_path, monkeypatch):
|
||||
root = tmp_path / ".rechtsprechung"
|
||||
source = root / "originale" / "JJT_test.md"
|
||||
source.parent.mkdir(parents=True)
|
||||
paragraphs = [f"Absatz {i}: " + "x" * 900 for i in range(5)]
|
||||
source.write_text(
|
||||
"# Entscheidung\n\n"
|
||||
"**Gericht:** OGH\n"
|
||||
"**Entscheidungsdatum:** 1. 2. 2020\n"
|
||||
"**Geschäftszahl:** 1 Ob 2/20a\n\n---\n\n"
|
||||
+ "\n\n".join(paragraphs),
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setattr(ing, "RJ_DIR", root)
|
||||
|
||||
_, md = ing.rj_entry(source, _rj_catalog(), _rj_stats())
|
||||
|
||||
assert "## Begründung (1)" in md
|
||||
assert "## Begründung (2)" in md
|
||||
|
||||
|
||||
def test_rj_norm_supports_h2_and_flat_wording(tmp_path, monkeypatch):
|
||||
root = tmp_path / ".rechtsprechung"
|
||||
h2_source = root / "gesetze" / "AngG_§15.md"
|
||||
flat_source = root / "gesetze" / "ABGB_§1435.md"
|
||||
h2_source.parent.mkdir(parents=True)
|
||||
h2_source.write_text(
|
||||
"# Angestelltengesetz\n\n**Kurztitel:** Angestelltengesetz\n"
|
||||
"**Abkürzung:** AngG\n**§/Artikel/Anlage:** § 15\n\n---\n\n"
|
||||
"## § 15\n\nWortlaut.\n\n## Zuletzt aktualisiert am\n\n1. 7. 2023\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
flat_source.write_text(
|
||||
"# ABGB\n\n**Kurztitel:** ABGB\n**Abkürzung:** ABGB\n"
|
||||
"**§/Artikel/Anlage:** § 1435\n\n---\n\nDer Wortlaut ohne H2.\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setattr(ing, "RJ_DIR", root)
|
||||
catalog = _rj_catalog()
|
||||
|
||||
_, h2_md = ing.rj_entry(h2_source, catalog, _rj_stats())
|
||||
_, flat_md = ing.rj_entry(flat_source, catalog, _rj_stats())
|
||||
|
||||
assert "stand: 2023-07" in h2_md
|
||||
assert 'legal_bases: ["AngG § 15"]' in h2_md
|
||||
assert "## § 15 – Wortlaut" in h2_md
|
||||
assert "stand: 2026-09" in flat_md
|
||||
assert "stand-abruf" in flat_md
|
||||
assert "## Normtext" in flat_md
|
||||
|
||||
|
||||
def test_rj_eugh_marks_lexetius_copy_as_nonofficial(tmp_path, monkeypatch):
|
||||
root = tmp_path / ".rechtsprechung"
|
||||
source = root / "originale" / "EUGH_C-29-1991.md"
|
||||
source.parent.mkdir(parents=True)
|
||||
source.write_text(
|
||||
"# EuGH C-29/91\n\n"
|
||||
"**URL:** https://www.lexetius.com/1992,1\n"
|
||||
"**Offizielle Fassung:** https://eur-lex.europa.eu/example\n\n---\n\n"
|
||||
"Urteil vom 19. 5. 1992\n\nEntscheidungsgründe.",
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setattr(ing, "RJ_DIR", root)
|
||||
|
||||
_, md = ing.rj_entry(source, _rj_catalog(), _rj_stats())
|
||||
|
||||
assert 'work: "EuGH – Rechtsprechung (Textwiedergabe lexetius, nicht amtlich)"' in md
|
||||
assert "stand: 1992-05" in md
|
||||
assert "Textwiedergabe (nicht amtlich): https://www.lexetius.com/1992,1" in md
|
||||
assert "amtliche Fassung: https://eur-lex.europa.eu/example" in md
|
||||
|
||||
+13
-4
@@ -67,17 +67,17 @@ def test_real_corpus_loads_and_matches_registry():
|
||||
"""Integrationstest gegen die echte Wissensbasis (Gate inklusive)."""
|
||||
entries = load_kb("wissensbasis", verify_registry=True)
|
||||
ids = {e.id for e in entries}
|
||||
# 601 kuratierte (lb/wk) + 614 WKO-KV + 59 RIS-Gesetze
|
||||
assert len(entries) == 1274
|
||||
# 601 kuratierte (lb/wk) + 614 WKO-KV + 59 RIS-Gesetze + 348 Rechtsprechungsquellen
|
||||
assert len(entries) == 1622
|
||||
assert "lb-atz-07" in ids and "wk-akt-01" in ids
|
||||
assert "kv-kvt-001" in ids and "ris-url-01" in ids
|
||||
assert "kv-kvt-001" in ids and "ris-url-01" in ids and "rj-rjs-001" in ids
|
||||
atz = [e for e in entries if e.id == "lb-atz-07"][0]
|
||||
assert atz.topic == "altersteilzeit"
|
||||
assert any(s.title.startswith("Kernwerte") for s in atz.sections)
|
||||
|
||||
|
||||
def test_new_id_spaces_and_html_source(tmp_path):
|
||||
"""kv-/ris-IDs und html-only-Quellenangabe sind gültig; Unbekanntes nicht."""
|
||||
"""kv-/ris-/rj-IDs und html-/text-Quellenangaben sind gültig; Unbekanntes nicht."""
|
||||
kv = DOC_ATZ.replace("id: lb-min-01", "id: kv-kvt-001").replace(
|
||||
'source:\n pdf: ".lexis360/Lexis360_test_atz.pdf"\n'
|
||||
' text: ".lexis360/md/test_atz.md"',
|
||||
@@ -96,6 +96,15 @@ def test_new_id_spaces_and_html_source(tmp_path):
|
||||
p2.write_text(ris, encoding="utf-8")
|
||||
assert load_entry(p2).id == "ris-url-01"
|
||||
|
||||
rj = DOC_ATZ.replace("id: lb-min-01", "id: rj-rjs-001").replace(
|
||||
'source:\n pdf: ".lexis360/Lexis360_test_atz.pdf"\n'
|
||||
' text: ".lexis360/md/test_atz.md"',
|
||||
'source:\n text: ".rechtsprechung/originale/Test.md"',
|
||||
)
|
||||
p3 = tmp_path / "rj_doc.md"
|
||||
p3.write_text(rj, encoding="utf-8")
|
||||
assert load_entry(p3).id == "rj-rjs-001"
|
||||
|
||||
bad = DOC_ATZ.replace("id: lb-min-01", "id: xx-min-01")
|
||||
p3 = tmp_path / "bad.md"
|
||||
p3.write_text(bad, encoding="utf-8")
|
||||
|
||||
Reference in New Issue
Block a user