This commit is contained in:
team3
2026-06-29 18:47:37 +02:00
parent 3382a426cf
commit 3e3559aa8f
4 changed files with 2 additions and 102 deletions

View File

@@ -47,15 +47,12 @@ STUFE_CHUNK = 100
RECHERCHE_BATCH = 20 # Crawl-Seiten je Batch
RECHERCHE_READERS = 2 # Reader-Agenten je Batch (Konsens ≥2 innerhalb des Batches)
RECHERCHE_THEMA_AGENTEN = 5 # Web-Modus (Quelle „thema", kein Crawl-Ordner)
RECHERCHE_KAPPE = 1800 # Sicherheits-Deckel je Batch-Agent
# uni/projekt: Skript-Text in Abschnitte ~dieser Größe chunken (gegen Lost-in-the-Middle bei
# großen Dokumenten). ~12k Zeichen ≈ 3k Token → sicher unter der Recall-Abfall-Schwelle.
RECHERCHE_ABSCHNITT_ZEICHEN = 12000
# Sichtung (Content/Noise) ist jetzt ein deterministischer Regel-Filter (config.CRAWL_*).
SUBBAUSTEIN_KAPPE = 900 # Subbaustein-Finde-Loop je Chunk (15 min)
KONSOLIDIERUNG_CHUNK = 600 # bis hierher EIN globaler Judge (dedupt alles); darüber chunked + Merge-Pass — nur Fallback-Pfad
DEDUP_MAX_RUNDEN = 3 # finaler Dedup-Pass: max. Iterationen (die kleinere Liste blockt je Runde neu)
DEDUP_MIN_DELTA = 3 # Abbruch, wenn eine Runde weniger als dieses % der Liste entfernt (konvergiert)
DEDUP_PAAR_FLOOR = 0.6 # Mindest-Cosine fürs Kandidaten-Paar (Complete-Link aggregiert → kein Chaining)
DEDUP_PAARE_CHUNK = 40 # Paare je Judge-Paket (Pairwise-Verifikation statt Block-Mischer)
FILTER_CHUNK = 35 # zu beurteilende Bausteine je Judge im Degradier-Pass (volle Liste als Kontext)
@@ -74,16 +71,6 @@ _bausteine_errors: dict[str, str] = {}
_bausteine_cancelled: set[str] = set()
_bausteine_step: dict[str, int] = {}
BAUSTEINE_STEPS = (
"Recherche", "Konsolidierung", "Klärung", "Dedup", "Bausteine-Filter",
"Subbausteine finden", "Subbausteine wählen", "Subbausteine klären",
"Fakten finden", "Fakten prüfen", "Fakten fix",
"Stufen finden", "Stufen wählen", "Stufen klären",
"Relevanz finden", "Relevanz wählen", "Relevanz klären",
"Gliederung",
"Fragen finden", "Fragen wählen", "Fragen klären", "Fragen prüfen",
"Karteikarten", "Beispiele",
)
ARTEFAKT_TYPEN = ("karteikarte", "beispiel")
@@ -1361,7 +1348,6 @@ async def _fakten_block(ctx, set_p, files: dict, roh: dict, q: dict, ordner, ins
return
idxs = chunks[ci]
rel_by = {bausteine[i][0]: bausteine[i][1] for i in idxs}
# nur die korrigierbaren Subs als Block
ziel = []
for bt, subs in rel_by.items():
betroffen = [s for s in subs if _norm_titel(s) in subs_norm]
@@ -1510,10 +1496,6 @@ async def _relevanz_block(ctx: GenContext, set_p, files: dict, sidecar: dict, in
return relevanz_by_id
def _norm_frage(t: str) -> str:
return " ".join(str(t or "").lower().split())
def _match_sub(agent_sub: str, rel: list[str]) -> str:
"""Subbaustein-Titel des Agenten auf den passenden relevanten Titel mappen — exakt,
dann normalisiert, dann Teilstring (der Agent lässt z. B. das Präfix „Frage: " weg).

View File

@@ -513,20 +513,6 @@ async def set_offene_frage(topic: str, baustein: str, frage: str, basis: int, st
await db.commit()
async def set_baustein_score(topic: str, baustein: str, score: int) -> int:
"""Setzt den Score absolut (vom Aufrufer geclampt) und liefert ihn zurück."""
db = await get_db()
await db.execute(
"""INSERT INTO baustein_progress (topic, baustein, gute_antworten, updated_at)
VALUES (?, ?, ?, ?)
ON CONFLICT(topic, baustein) DO UPDATE SET
gute_antworten = excluded.gute_antworten, updated_at = excluded.updated_at""",
(topic, baustein, score, _now()),
)
await db.commit()
return score
async def set_baustein_score_and_streak(topic: str, baustein: str, score: int, streak: int) -> tuple[int, int]:
"""Setzt Score + Streak atomar (vom Aufrufer geclampt). Liefert (score, streak)."""
db = await get_db()
@@ -550,40 +536,6 @@ async def delete_baustein_progress(topic: str, baustein: str) -> None:
await db.commit()
async def set_baustein_verstanden(topic: str, baustein: str) -> bool:
"""Markiert verstanden (Mastery); True nur beim ersten Mal. Sticky wie absolviert."""
db = await get_db()
now = _now()
await db.execute(
"INSERT OR IGNORE INTO baustein_progress (topic, baustein, gute_antworten, updated_at) VALUES (?, ?, 0, ?)",
(topic, baustein, now),
)
cursor = await db.execute(
"UPDATE baustein_progress SET verstanden = ?, updated_at = ? "
"WHERE topic = ? AND baustein = ? AND verstanden IS NULL",
(now, now, topic, baustein),
)
await db.commit()
return cursor.rowcount > 0
async def set_baustein_gemeistert(topic: str, baustein: str) -> bool:
"""Markiert gemeistert (Meisterpfad, Score 25); True nur beim ersten Mal. Sticky."""
db = await get_db()
now = _now()
await db.execute(
"INSERT OR IGNORE INTO baustein_progress (topic, baustein, gute_antworten, updated_at) VALUES (?, ?, 0, ?)",
(topic, baustein, now),
)
cursor = await db.execute(
"UPDATE baustein_progress SET gemeistert = ?, updated_at = ? "
"WHERE topic = ? AND baustein = ? AND gemeistert IS NULL",
(now, now, topic, baustein),
)
await db.commit()
return cursor.rowcount > 0
async def set_baustein_absolviert(topic: str, baustein: str) -> bool:
"""Markiert absolviert; True nur beim ersten Mal (steuert den Element-Task)."""
db = await get_db()
@@ -601,39 +553,6 @@ async def set_baustein_absolviert(topic: str, baustein: str) -> bool:
return cursor.rowcount > 0
async def count_relevant_subs(topic: str, baustein: str) -> int:
"""Anzahl relevanter Konsens-Subbausteine eines Bausteins (für den cap = 4×Subs)."""
from textkit import _norm_titel
db = await get_db()
cursor = await db.execute(
"SELECT COUNT(*) FROM subbausteine WHERE topic = ? AND baustein_norm = ? "
"AND status = 'konsens' AND relevanz != 'rand'",
(topic, _norm_titel(baustein)),
)
return (await cursor.fetchone())[0]
async def subs_count_roh(topic: str) -> dict[str, int]:
"""Relevante Konsens-Subbausteine je ROHEM Baustein-Titel (= Guide-Section-Titel) eines Themas."""
db = await get_db()
cursor = await db.execute(
"SELECT baustein, COUNT(*) FROM subbausteine WHERE topic = ? "
"AND status = 'konsens' AND relevanz != 'rand' GROUP BY baustein",
(topic,),
)
return {b: n for b, n in await cursor.fetchall()}
async def subs_count_alle() -> dict[tuple[str, str], int]:
"""Relevante Konsens-Subbausteine je (topic, baustein_norm) — für die Stufen-Ableitung."""
db = await get_db()
cursor = await db.execute(
"SELECT topic, baustein_norm, COUNT(*) FROM subbausteine "
"WHERE status = 'konsens' AND relevanz != 'rand' GROUP BY topic, baustein_norm"
)
return {(t, bn): n for t, bn, n in await cursor.fetchall()}
# Sub-Ebene aus den zwei orthogonalen Spalten: rand → 4 (V), sonst Stufe (Lernpfad-Position):
# anfaenger/NULL → 1, fortgeschritten → 2, experte → 3. Alte Werte (einfach/mittel/schwer) werden
# abwärtskompatibel mitgemappt. Steuert Guide-Ansicht A/F/E/V + cap (freigeschaltete Subs × 25).

View File

@@ -941,7 +941,6 @@ async def generate_guide(guide_id: str, topic: str, format_name: str, instructio
# --- On-Demand: eine Section prüfen / beheben / neu schreiben (Fokus, interaktiv) ---
SECTION_PRUEFEN_TIMEOUT = 300
SECTION_FIX_TIMEOUT = 600
def _section_spec() -> str:

View File

@@ -5,7 +5,7 @@ import uuid
from datetime import datetime, timezone
from fastapi import APIRouter, HTTPException
from fastapi.responses import FileResponse, Response
from fastapi.responses import Response
from agents import provider_available
from config import PROJECTS_DIR, UNI_DIR, PROVIDERS
@@ -15,7 +15,7 @@ from database import (
list_progress, set_progress, delete_progress,
create_element, list_elements, get_element, update_element, delete_element,
list_baustein_progress, get_baustein_progress, set_offene_frage,
set_baustein_score, set_baustein_score_and_streak, set_baustein_absolviert,
set_baustein_score_and_streak, set_baustein_absolviert,
delete_baustein_daten, delete_baustein_progress, subs_je_ebene, subs_je_ebene_roh,
delete_topic_pipeline, delete_quelle, get_guide_content, delete_guide_content,
get_sub_artefakte,