From 753b95b68983ea1b8dcc78af0e1c874eefec7253 Mon Sep 17 00:00:00 2001 From: team3 Date: Mon, 29 Jun 2026 01:46:34 +0200 Subject: [PATCH] update --- backend/bausteine.py | 31 ++++++++++++++++++++++++++++++- backend/config.py | 4 ++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/backend/bausteine.py b/backend/bausteine.py index 7d7638c..6732ad4 100644 --- a/backend/bausteine.py +++ b/backend/bausteine.py @@ -23,7 +23,7 @@ from pathlib import Path import database as db import embedding from agents import kill_process, cancel_scope, clear_scope, run_agent -from config import KONSENS_GRACE, RECHERCHE_GRACE, KONSENS_MAX_RUNDEN, DEFAULT_PROVIDER, CRAWL_KEEP_PATTERNS, CRAWL_NOISE_PATTERNS, CRAWL_MIN_CHARS, QUELLE_RELEVANZ_CHUNK, QUELLE_RELEVANZ_SNIPPET, EMBEDDING_AKTIV +from config import KONSENS_GRACE, RECHERCHE_GRACE, KONSENS_MAX_RUNDEN, DEFAULT_PROVIDER, CRAWL_KEEP_PATTERNS, CRAWL_NOISE_PATTERNS, CRAWL_MIN_CHARS, QUELLE_RELEVANZ_CHUNK, QUELLE_RELEVANZ_SNIPPET, EMBEDDING_AKTIV, EMBEDDING_SUB_DUP from fsutil import atomic_write_text, atomic_write_json from jsonio import read_json_file as _json_datei from paths import arbeit_dir, bausteine_path, frage_muster_path, project_dir, subbausteine_path, quelle_path, quelle_crawl_dir, safe_ordner @@ -845,12 +845,41 @@ async def _subbausteine_block(ctx: GenContext, set_p, files: dict, entries: dict if sn and sn not in have: await db.upsert_subbaustein(topic, norm_by_num[num], sn, titel, s) await db.set_subbaustein_felder(topic, norm_by_num[num], sn, status="konsens") + await _dedup_subbausteine(topic, roh) # Near-Dup-Filter je Baustein (deterministisch, kein LLM) if not roh: _bausteine_errors[topic] = "Keine Subbausteine ermittelt" return None return roh +async def _dedup_subbausteine(topic: str, roh: dict[str, list[str]]) -> None: + """Deterministischer Near-Duplicate-Filter pro Baustein: Subbausteine mit Cosine ≥ + EMBEDDING_SUB_DUP sind dieselbe Aussage (im engen Baustein-Kontext zuverlässig — kein LLM + nötig). Behält je Dublett-Gruppe den informativsten (längsten); Rest → DB verworfen + aus `roh`. + Modell fehlt → still überspringen (wie der übrige Embedding-Fallback).""" + if not EMBEDDING_AKTIV or not await asyncio.to_thread(embedding.verfuegbar): + return + for titel, subs in list(roh.items()): + if len(subs) < 2: + continue + sims = await asyncio.to_thread(embedding.embed_sims, subs) + if sims is None: + return + behalten: list[int] = [] + verworfen: list[int] = [] + for i in sorted(range(len(subs)), key=lambda x: (-len(subs[x]), x)): # informativster zuerst + if any(float(sims[i][j]) >= EMBEDDING_SUB_DUP for j in behalten): + verworfen.append(i) + else: + behalten.append(i) + if not verworfen: + continue + bnorm = _norm_titel(titel) + for i in verworfen: + await db.set_subbaustein_felder(topic, bnorm, _norm_titel(subs[i]), status="verworfen") + roh[titel] = [subs[i] for i in sorted(behalten)] # Original-Reihenfolge der Behaltenen + + async def _stufen_block(ctx: GenContext, set_p, files: dict, roh: dict, instructions: str) -> dict | None: """Block C: drei Phasen mit Barriere — Finden (einstufen), Wählen (Vote), Klären. Lokale IDs 1..n pro Paket, hinterher auf globale gid gemappt. diff --git a/backend/config.py b/backend/config.py index de692e4..e972405 100644 --- a/backend/config.py +++ b/backend/config.py @@ -37,6 +37,10 @@ EMBEDDING_MODELL = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2" # LLM-Listen kurz und stabil (belegt: Embedding-Block + LLM-Judge ≈ 95 % Precision). EMBEDDING_BLOCK_FLOOR = 0.5 # Mindest-Cosine, damit zwei Kandidaten in EINEN Block dürfen EMBEDDING_BLOCK_CAP = 25 # max. Titel je Block (LLM-Liste kurz/stabil halten) +# Subbaustein-Dedup: rein deterministisch (kein LLM). Subbausteine sind kurze Aussagen IM SELBEN +# Baustein-Kontext — ab dieser Cosine sind zwei dieselbe Aussage (an aak geprüft: ≥0,88 ausnahmslos +# echte Dubletten). Konservativ 0,90, damit verschiedene Aspekte (∈NP ≠ NP-schwer) getrennt bleiben. +EMBEDDING_SUB_DUP = 0.90 # Deckel für gleichzeitige CLI-Agenten-Prozesse (über alle Generierungen hinweg). # Eigene Spur für interaktive Aufrufe (Chat, Elemente), damit sie nicht hinter