This commit is contained in:
Team3
2026-06-07 09:34:46 +02:00
parent 13eedd7753
commit 3f2c966d25
5 changed files with 76 additions and 13 deletions

View File

@@ -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))),
}]

View File

@@ -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 = {

View File

@@ -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) {
<template v-if="guideStatus(f.key) !== 'generating' && guideStatus(f.key) !== 'queued'">
<button
class="action-btn play"
:title="f.key === 'OnePager' || bausteine.ready ? 'Generieren' : 'Erst Bausteine erstellen'"
:disabled="f.key !== 'OnePager' && !bausteine.ready"
:title="playLock(f.key) || 'Generieren'"
:disabled="!!playLock(f.key)"
@click="handlePlay(f.key)"
></button>
</template>

View File

@@ -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": ["…", "…"]}}

View File

@@ -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}