From 3f2c966d25647baddbef891cf03501e0f64d212e Mon Sep 17 00:00:00 2001 From: Team3 Date: Sun, 7 Jun 2026 09:34:46 +0200 Subject: [PATCH] update --- backend/generator.py | 4 ++- backend/routes.py | 33 ++++++++++++++----- frontend/src/components/TopicSidebar.vue | 23 +++++++++++-- .../OnePager-Recherche-Check-Projekt.md | 27 +++++++++++++++ templates/Prompt/OnePager-Recherche-Fix.md | 2 +- 5 files changed, 76 insertions(+), 13 deletions(-) create mode 100644 templates/Prompt/OnePager-Recherche-Check-Projekt.md diff --git a/backend/generator.py b/backend/generator.py index f47d155..f81f831 100644 --- a/backend/generator.py +++ b/backend/generator.py @@ -719,9 +719,11 @@ async def _generate_onepager( if project: source = _prompt("OnePager-Quelle-Projekt", project=project) recherche_template = "OnePager-Recherche-Projekt" + recherche_check_template = "OnePager-Recherche-Check-Projekt" else: source = _prompt("OnePager-Quelle-Thema", topic=topic) recherche_template = "OnePager-Recherche" + recherche_check_template = "OnePager-Recherche-Check" def recherche_payload(result=None): if not recherche_path.exists(): @@ -752,7 +754,7 @@ async def _generate_onepager( await _set_step(guide_id, 1, "Prüfe Recherche…") slots = [{ "key": f"{guide_id}-recherche-check", - "prompt": _prompt("OnePager-Recherche-Check", topic=topic, recherche=recherche, out_path=recherche_check_path), + "prompt": _prompt(recherche_check_template, topic=topic, recherche=recherche, out_path=recherche_check_path), "role": "fast", "capabilities": "files", "payload": (lambda result: _probleme_schema(_json_datei(recherche_check_path))), }] diff --git a/backend/routes.py b/backend/routes.py index 7201bdc..bd235dc 100644 --- a/backend/routes.py +++ b/backend/routes.py @@ -46,17 +46,16 @@ async def get_topics(): return db_topics + sorted(derived - set(db_topics)) -@router.get("/stats") -async def get_stats(): - """Tracker: Themen-Anzahl + pro Format erstellt/absolviert (alle Kapitel abgehakt).""" - guides = await list_guides() - themen = set(await db_list_topics()) | {g["topic"] for g in guides} | set(bausteine_topics()) - if PROJECTS_DIR.is_dir(): - themen |= {e.name for e in PROJECTS_DIR.iterdir() if e.is_dir()} +# Lernschulden-Regel: höchstens 5 erstellte, aber nicht absolvierte Guides. +# Darüber sind nur Neu-Generierungen bereits erstellter Guides erlaubt. +MAX_OFFENE_GUIDES = 5 + +async def _formate_stats() -> dict: + """Pro Format erstellt/absolviert (alle Kapitel abgehakt) — pro Thema zählt nur der neueste fertige Guide.""" + guides = await list_guides() formate = {} for fmt in ("MiniGuide", "Guide", "FullGuide"): - # Pro Thema zählt nur der neueste fertige Guide (Altläufe teilen die Content-Datei) neueste: dict[str, dict] = {} for g in guides: if g["format"] == fmt and g["status"] == "done": @@ -75,7 +74,17 @@ async def get_stats(): if titles and titles <= set(await list_progress(g["id"])): absolviert += 1 formate[fmt] = {"erstellt": len(neueste), "absolviert": absolviert} - return {"themen": len(themen), "formate": formate} + return formate + + +@router.get("/stats") +async def get_stats(): + """Tracker: Themen-Anzahl + pro Format erstellt/absolviert.""" + guides = await list_guides() + themen = set(await db_list_topics()) | {g["topic"] for g in guides} | set(bausteine_topics()) + if PROJECTS_DIR.is_dir(): + themen |= {e.name for e in PROJECTS_DIR.iterdir() if e.is_dir()} + return {"themen": len(themen), "formate": await _formate_stats()} @router.post("/topics") @@ -159,6 +168,12 @@ async def create(req: GuideCreateRequest): for g in await list_guides(): if g["topic"] == req.topic.strip() and g["format"] == req.format and g["status"] in ("queued", "generating"): raise HTTPException(409, "Generierung läuft bereits") + # Lernschulden-Regel: neue Guides nur, wenn weniger als 5 offene (erstellt, nicht absolviert) + if req.format != "OnePager" and not guide_content_path(req.topic.strip(), req.format).exists(): + formate = await _formate_stats() + offen = sum(v["erstellt"] - v["absolviert"] for v in formate.values()) + if offen >= MAX_OFFENE_GUIDES: + raise HTTPException(409, f"Erst Guides absolvieren — maximal {MAX_OFFENE_GUIDES} offene erlaubt ({offen} offen)") await create_topic(req.topic.strip()) now = datetime.now(timezone.utc).isoformat() guide = { diff --git a/frontend/src/components/TopicSidebar.vue b/frontend/src/components/TopicSidebar.vue index f71486e..b089cb4 100644 --- a/frontend/src/components/TopicSidebar.vue +++ b/frontend/src/components/TopicSidebar.vue @@ -128,7 +128,26 @@ function handleFormatClick(format) { } } +// Lernschulden-Regel: max. 5 erstellte, aber nicht absolvierte Guides — +// darüber sind nur Neu-Generierungen bereits erstellter Guides erlaubt. +const offeneGuides = computed(() => { + const f = props.stats?.formate || {} + return ['MiniGuide', 'Guide', 'FullGuide'].reduce( + (sum, k) => sum + ((f[k]?.erstellt ?? 0) - (f[k]?.absolviert ?? 0)), 0, + ) +}) + +function playLock(format) { + if (format === 'OnePager') return null + if (!props.bausteine.ready) return 'Erst Bausteine erstellen' + if (offeneGuides.value >= 5 && !props.doneByFormat[format]) { + return `Erst Guides absolvieren — ${offeneGuides.value} offen (max. 5)` + } + return null +} + function handlePlay(format) { + if (playLock(format)) return emit('formatClick', { format, instructions: '' }) } @@ -279,8 +298,8 @@ function confirmDeleteProject(name) { diff --git a/templates/Prompt/OnePager-Recherche-Check-Projekt.md b/templates/Prompt/OnePager-Recherche-Check-Projekt.md new file mode 100644 index 0000000..f95f16b --- /dev/null +++ b/templates/Prompt/OnePager-Recherche-Check-Projekt.md @@ -0,0 +1,27 @@ +Prüfe die Faktenbasis für einen OnePager zum Projekt "{topic}". + +FAKTENBASIS: +{recherche} + +Sie muss diese Dimensionen abdecken: +1. Kurzbeschreibung (Art des Projekts, Gegenstand) +2. Technische Daten (Technologie/Format, Umfang, Stand/Aktualität) +3. Kerneigenschaften (prägende Konzepte, Komponenten oder Inhalte) +4. Ein typisches Beispiel aus dem Projekt +5. Zusammenhänge (Umfeld, Abhängigkeiten, angrenzende Systeme/Themen) +6. Voraussetzungen +7. Moderne vs. veraltete Teile (oder die ausdrückliche Feststellung, dass nichts veraltet ist) + +Prüfe: +1. Ist jede Dimension mit konkreten Fakten aus den Projektdateien belegt (Namen, Zahlen — nicht vage)? +2. Hat jeder Punkt einen Dateipfad als Quelle? +3. Wirkt etwas erfunden — also nicht aus dem Projekt belegbar? + +Du PRÜFST nur und notierst Probleme — du änderst nichts. + +Schreibe NUR die JSON-Datei nach: {out_path} + +Format — alles in Ordnung: +{{"ok": true}} +Sonst (kurz und konkret, maximal 10 Punkte): +{{"probleme": ["…", "…"]}} diff --git a/templates/Prompt/OnePager-Recherche-Fix.md b/templates/Prompt/OnePager-Recherche-Fix.md index 19eb638..43f7d4c 100644 --- a/templates/Prompt/OnePager-Recherche-Fix.md +++ b/templates/Prompt/OnePager-Recherche-Fix.md @@ -8,7 +8,7 @@ BISHERIGE FAKTENBASIS: NOTIERTE PROBLEME (von der Prüfung): {probleme} -Behebe NUR die notierten Probleme — fehlende Dimensionen nachrecherchieren, Vages konkretisieren, Unbelegtes belegen oder streichen. Alles andere bleibt erhalten. +Behebe NUR die notierten Probleme — Fehlendes anhand der oben genannten Quelle ergänzen, Vages konkretisieren, Unbelegtes belegen oder streichen. Alles andere bleibt erhalten. Schreibe die VOLLSTÄNDIGE, überarbeitete Markdown-Datei nach: {out_path}