from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parent.parent TEMPLATES_DIR = PROJECT_ROOT / "templates" STORAGE_DIR = PROJECT_ROOT / "storage" FRONTEND_DIST = PROJECT_ROOT / "frontend" / "dist" DB_PATH = STORAGE_DIR / "creator.db" PROJECTS_DIR = PROJECT_ROOT / "projects" UNI_DIR = PROJECT_ROOT / "uni" MAX_CONCURRENT_GENERATIONS = 10 # Lesbarkeits-Gate: deterministischer Prüfer (kleines deutsches Komplexitäts-Modell, # Skala 1–7). Zu schwere Sections gehen in die Lese-Prüfungs-Überarbeitung. # Fehlen transformers/torch oder das Modell → Gate stumm aus. LESBARKEIT_AKTIV = True LESBARKEIT_MODELL = "MiriUll/distilbert-german-text-complexity" # Anker auf der 1–7-Skala (TextComplexityDE): Leichte Sprache ~1,2; Wikipedia-Schnitt # ~3,22; ab MOS > 4 gilt ein Satz als „echt komplex" (Vereinfachungs-Grenze des Papers). LESBARKEIT_MAX = 3.5 # Section zu schwer, wenn der Satz-Schnitt darüber liegt LESBARKEIT_HART = 4.0 # Einzelsatz ab hier „hart" LESBARKEIT_HART_ANTEIL = 0.30 # … ODER wenn dieser Anteil der Sätze hart ist # Deckel für gleichzeitige CLI-Agenten-Prozesse (über alle Generierungen hinweg). # Eigene Spur für interaktive Aufrufe (Chat, Elemente), damit sie nicht hinter # laufenden Writern in der Warteschlange hängen. MAX_CONCURRENT_AGENTS = 10 MAX_CONCURRENT_INTERACTIVE = 8 # Grace-Fenster der Konsens-Races (Bausteine, Guide, OnePager): Nach dem ersten # gültigen Ergebnis dürfen die übrigen Agenten noch so viele Sekunden fertig # werden (Kill nur, wenn das Minimum schon steht). KONSENS_GRACE = 300 # Recherche-Race: längeres Grace-Fenster. Recherche treibt die ganze Bausteine-Anzahl; # bei langsamen Providern (z.B. MiniMax) sollen ALLE 5 Agenten fertig werden, nicht nur # das Quorum von 3. Pro-Agent-Timeout (TIMEOUTS["recherche"]=1800s) deckelt echte Hänger. RECHERCHE_GRACE = 900 # Cap der Klärungs- und Prüf-Loops: maximale Runden, bis alles entschieden sein # muss. In der letzten Runde MUSS der Mapping-Agent jeden Eintrag entscheiden; # Prüf-Loops lassen Rest-Beanstandungen danach stehen. KONSENS_MAX_RUNDEN = 3 # Crawler-Sichtung (Content/Noise) — deterministischer Regel-Filter statt LLM. # Match: Substring (klein) gegen URL UND Dateiname. Reihenfolge: keep > noise > min_chars > behalten. # Sonderregeln einfach hier ergänzen. CRAWL_KEEP_PATTERNS = ["learn-unit", "learn-course"] # immer Content CRAWL_NOISE_PATTERNS = [ # eindeutig themenfremd → raus "clubs", "events", "podcasts", "resources", "-u-", "academy", "pricing", "/plans", "career", "newsletter", "impressum", "login", ] CRAWL_MIN_CHARS = 400 # zu wenig Text → raus # Timeouts pro Agenten-Schritt: (Basis-Sekunden, Sekunden pro Baustein/Section). # Gilt für alle Provider gleich — wer zu langsam ist, wird neu gestartet bzw. überholt. TIMEOUTS = { "recherche": (1800, 0), # fix 30 min "recherche_mapping": (600, 3), # n = vorgemergte Einträge "auswahl_mapping": (600, 2), # n = Rest-Einträge (Bausteine-Inventar) "ergaenzung": (900, 0), # Themenfeld-Ergänzung bei Projekten (Web-Recherche) "plan": (300, 5), "plan_judge": (600, 5), # Judge liest bis zu 5 Gliederungen, n = Sections "inhalt": (600, 90), # Inhalte je Baustein im Chunk identifizieren (Websuche) "inhalt_check": (300, 10), # Inhalts-Prüfung je Baustein im Paket "subbaustein": (900, 45), # Subbausteine je Baustein im Chunk finden (Websuche) "subbaustein_check": (300, 15), # Judge entscheidet strittige Subbausteine im Chunk "stufe": (300, 10), # Subbausteine einstufen je Chunk "stufe_check": (300, 10), # Judge entscheidet strittige Stufen im Chunk "relevanz": (300, 10), # Subbausteine relevant/rand je Chunk "relevanz_check": (300, 10), # Judge entscheidet strittige Relevanz im Chunk "frage_muster": (300, 15), # Frage-Muster je Baustein (Subbausteine × Typen) "frage_muster_check": (300, 10), # Kritiker bereinigt die Muster-Tabelle je Baustein "writer": (600, 120), # pro Section im Chunk "lese_check": (300, 10), # pro Section im Paket } # Zweck je Format — fließt in den Gliederungs-Judge (was der Guide leisten soll). FORMAT_ZWECK = { "Guide": "einen fokussierten Guide — alles Relevante ohne Randthemen", "FullGuide": "einen Komplett-Guide — das ganze Thema inkl. Randthemen", "Rest": "einen Ergänzungs-Guide — nur die Randthemen", } # Provider-Stacks: komplett unabhängig, einer kann jederzeit entfernt werden. # Rollen: "quick" = Massenarbeit (Recherche, Einordnung), # "fast" = Interaktion + Voten (Chat, Prüfung, Klärung, Elemente), # "judge" = Mapping-/Judge-/Prüf-Agenten — kalt (niedrige Temperature, # ohne Thinking) für stabile Urteile; Claude/Lokal mappen auf "fast", # "guide" = große Generierung (Vorschläge, Writer). DEFAULT_PROVIDER = "claude" PROVIDERS = { "claude": { "cli": "claude", "guide": "claude-opus-4-8[1m]", "fast": "claude-sonnet-4-6", "judge": "claude-sonnet-4-6", # CLI kennt keine Temperature "quick": "claude-sonnet-4-6", "env_key": None, # Auth via CLAUDE_CODE_OAUTH_TOKEN oder ~/.claude }, # "minimax-kalt/…" ist KEIN eigener Stack, nur ein opencode-Provider-Eintrag # (dev-ops/opencode.json) mit niedriger Temperature; M3 dort ohne Thinking. "minimax": { "cli": "opencode", "guide": "minimax/MiniMax-M3", "fast": "minimax-kalt/MiniMax-M2.7-highspeed", "judge": "minimax-kalt/MiniMax-M3", "quick": "minimax/MiniMax-M2.7-highspeed", "env_key": "MINIMAX_API_KEY", }, "lokal": { "cli": "opencode", "guide": "ollama/qwen3.6:27b", "fast": "ollama/qwen3.5:9b", "judge": "ollama/qwen3.5:9b", "quick": "ollama/qwen3.5:9b", "env_key": None, "check_url": "http://localhost:11434/api/tags", # Ollama erreichbar? }, }