update
This commit is contained in:
@@ -17,6 +17,7 @@ from config import (
|
||||
MODEL_BAUSTEIN_GEN,
|
||||
MODEL_BAUSTEIN_REWORK,
|
||||
MODEL_CHAT,
|
||||
MODEL_PROJECT_INDEX,
|
||||
STORAGE_DIR,
|
||||
)
|
||||
from database import (
|
||||
@@ -28,7 +29,7 @@ from database import (
|
||||
update_baustein,
|
||||
update_baustein_sort_orders,
|
||||
)
|
||||
from paths import final_paths, temp_paths
|
||||
from paths import final_paths, temp_paths, project_dir, project_cache_path
|
||||
|
||||
_semaphore = asyncio.Semaphore(MAX_CONCURRENT_GENERATIONS)
|
||||
_active_processes: dict[str, asyncio.subprocess.Process] = {}
|
||||
@@ -94,15 +95,48 @@ async def _render_pdf(html_path: Path, pdf_path: Path) -> tuple[bool, str]:
|
||||
return True, ""
|
||||
|
||||
|
||||
def _build_generator_prompt(topic: str, format_name: str, html_path: Path, instructions: str = "") -> str:
|
||||
def _build_project_index_prompt(name: str, cache_path: Path, has_cache: bool) -> str:
|
||||
src = project_dir(name)
|
||||
if has_cache:
|
||||
return f"""Es existiert bereits eine verdichtete Wissensdatei zum Projekt "{name}" unter {cache_path}.
|
||||
|
||||
Prüfe sie gegen das echte Projekt unter {src}.
|
||||
|
||||
SCHRITT 1: Lies die bestehende Wissensdatei {cache_path}.
|
||||
SCHRITT 2: Verschaffe dir mit Bash (ls/find) und Read einen vollständigen Überblick über {src}. Lies README, Doku-Ordner und den relevanten Quellcode.
|
||||
SCHRITT 3: Ergänze fehlende oder veraltete wichtige Informationen. Ein früherer Lauf war evtl. schlampig und hat Wichtiges ausgelassen.
|
||||
SCHRITT 4: Schreibe die vollständige, korrigierte Wissensdatei zurück nach {cache_path}.
|
||||
|
||||
Die Datei muss als alleinige Faktenbasis für einen Lern-Guide ausreichen. Erfasse: Zweck, Architektur, Abläufe, wichtige Dateien, Konfiguration, Befehle, Datenstrukturen, Besonderheiten. Schreibe NUR diese eine Datei."""
|
||||
|
||||
return f"""Lies das Projekt "{name}" vollständig ein und erstelle daraus eine verdichtete Wissensdatei.
|
||||
|
||||
SCHRITT 1: Verschaffe dir mit Bash (ls/find) einen Überblick über {src}.
|
||||
SCHRITT 2: Lies README, Doku-Ordner und den relevanten Quellcode mit dem Read-Tool.
|
||||
SCHRITT 3: Schreibe eine vollständige Wissensdatei nach {cache_path}.
|
||||
|
||||
Die Datei muss als alleinige Faktenbasis für einen Lern-Guide ausreichen. Erfasse: Zweck, Architektur, Abläufe, wichtige Dateien, Konfiguration, Befehle, Datenstrukturen, Besonderheiten. Lass nichts Wichtiges aus. Schreibe NUR diese eine Datei."""
|
||||
|
||||
|
||||
def _build_generator_prompt(topic: str, format_name: str, html_path: Path, instructions: str = "", project_content: str | None = None) -> str:
|
||||
spec = (TEMPLATES_DIR / "Format" / f"{format_name}.md").read_text(encoding="utf-8")
|
||||
reference = (TEMPLATES_DIR / "Referenz" / f"{format_name}.md").read_text(encoding="utf-8")
|
||||
|
||||
extra = f"\n\nZUSÄTZLICHE ANWEISUNGEN VOM NUTZER:\n{instructions}\n" if instructions else ""
|
||||
|
||||
if project_content:
|
||||
research_line = (
|
||||
f'Die folgenden PROJEKT-INHALTE sind die Quelle der Wahrheit für "{topic}". '
|
||||
"Nutze sie als primäre Faktenbasis. Recherchiere per Websuche nur ergänzend, "
|
||||
"um fehlende oder sich ändernde Fakten (z. B. aktuelle Versionsnummern externer Tools) zu prüfen.\n\n"
|
||||
f"PROJEKT-INHALTE (Quelle der Wahrheit):\n{project_content}"
|
||||
)
|
||||
else:
|
||||
research_line = f'Recherchiere zuerst die aktuelle Version und aktuelle Fakten zu "{topic}" per Websuche, damit Versionsnummern und Angaben stimmen.'
|
||||
|
||||
return f"""Erstelle einen Lern-Guide zum Thema "{topic}" im Format "{format_name}".
|
||||
|
||||
Recherchiere zuerst die aktuelle Version und aktuelle Fakten zu "{topic}" per Websuche, damit Versionsnummern und Angaben stimmen.
|
||||
{research_line}
|
||||
|
||||
Schreibe die HTML-Datei nach: {html_path}
|
||||
|
||||
@@ -144,16 +178,29 @@ Führe KEIN weasyprint aus, erzeuge KEINE PDF.
|
||||
"""
|
||||
|
||||
|
||||
def _build_content_review_prompt(topic: str, format_name: str, html_path: Path) -> str:
|
||||
def _build_content_review_prompt(topic: str, format_name: str, html_path: Path, project_content: str | None = None) -> str:
|
||||
spec = (TEMPLATES_DIR / "Format" / f"{format_name}.md").read_text(encoding="utf-8")
|
||||
|
||||
if project_content:
|
||||
check_step = (
|
||||
"SCHRITT 2 — Fakten prüfen:\n"
|
||||
f'Vergleiche den Inhalt mit den folgenden PROJEKT-INHALTEN (Quelle der Wahrheit) für "{topic}". '
|
||||
"Stimmen die Projekt-Fakten? Fehlt Wichtiges aus dem Projekt? "
|
||||
"Externe/aktuelle Fakten (Versionsnummern fremder Tools) ergänzend per WebSearch prüfen.\n\n"
|
||||
f"PROJEKT-INHALTE:\n{project_content}"
|
||||
)
|
||||
else:
|
||||
check_step = (
|
||||
"SCHRITT 2 — Fakten per Websuche prüfen:\n"
|
||||
f'Recherchiere mit WebSearch, ob Versionsnummern, Jahreszahlen und zentrale Fakten zu "{topic}" aktuell und korrekt sind.'
|
||||
)
|
||||
|
||||
return f"""Prüfe den Inhalt der HTML-Datei {html_path} für den "{format_name}" zum Thema "{topic}".
|
||||
|
||||
SCHRITT 1 — HTML-Datei lesen:
|
||||
Öffne die Datei {html_path} mit dem Read-Tool.
|
||||
|
||||
SCHRITT 2 — Fakten per Websuche prüfen:
|
||||
Recherchiere mit WebSearch, ob Versionsnummern, Jahreszahlen und zentrale Fakten zu "{topic}" aktuell und korrekt sind.
|
||||
{check_step}
|
||||
|
||||
SCHRITT 3 — Vollständigkeit prüfen anhand dieser Spezifikation:
|
||||
{spec}
|
||||
@@ -178,7 +225,7 @@ FAIL
|
||||
"""
|
||||
|
||||
|
||||
async def generate_guide(guide_id: str, topic: str, format_name: str, instructions: str = "") -> None:
|
||||
async def generate_guide(guide_id: str, topic: str, format_name: str, instructions: str = "", reindex: bool = False) -> None:
|
||||
async with _semaphore:
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
await update_guide(guide_id, status="generating", progress="Recherche…", updated_at=now)
|
||||
@@ -192,9 +239,31 @@ async def generate_guide(guide_id: str, topic: str, format_name: str, instructio
|
||||
current_step = "Generierung"
|
||||
current_timeout = AGENT_TIMEOUT
|
||||
|
||||
# Step 0: Projekt einlesen (nur wenn topic ein Projekt ist)
|
||||
project_content: str | None = None
|
||||
if project_dir(topic).is_dir():
|
||||
cache_path = project_cache_path(topic)
|
||||
if reindex or not cache_path.exists():
|
||||
await _set_progress(guide_id, "Lese Projekt…")
|
||||
current_step = "Projekt-Einlesen"
|
||||
index_prompt = _build_project_index_prompt(topic, cache_path, cache_path.exists())
|
||||
returncode, idx_out, idx_err = await _run_claude(
|
||||
guide_id, index_prompt, AGENT_TIMEOUT,
|
||||
tools="Read,Bash,Write", model=MODEL_PROJECT_INDEX,
|
||||
)
|
||||
if guide_id in _cancelled:
|
||||
return
|
||||
if returncode != 0:
|
||||
await _fail(guide_id, _claude_error("Projekt-Einlese-Fehler", returncode, idx_out, idx_err))
|
||||
return
|
||||
if not cache_path.exists():
|
||||
await _fail(guide_id, "Projekt-Wissensdatei wurde nicht erstellt")
|
||||
return
|
||||
project_content = cache_path.read_text(encoding="utf-8")
|
||||
|
||||
# Step 1: Generator-Agent erstellt HTML
|
||||
await _set_progress(guide_id, "Generiere HTML…")
|
||||
gen_prompt = _build_generator_prompt(topic, format_name, html_path, instructions)
|
||||
gen_prompt = _build_generator_prompt(topic, format_name, html_path, instructions, project_content)
|
||||
returncode, stdout, stderr = await _run_claude(guide_id, gen_prompt, AGENT_TIMEOUT, model=MODEL_GUIDE)
|
||||
|
||||
if guide_id in _cancelled:
|
||||
@@ -214,7 +283,7 @@ async def generate_guide(guide_id: str, topic: str, format_name: str, instructio
|
||||
await _set_progress(guide_id, "Prüfe Inhalt…")
|
||||
current_step = "Inhalts-Review"
|
||||
current_timeout = AGENT_TIMEOUT
|
||||
content_prompt = _build_content_review_prompt(topic, format_name, html_path)
|
||||
content_prompt = _build_content_review_prompt(topic, format_name, html_path, project_content)
|
||||
returncode, review_out, review_err = await _run_claude(guide_id, content_prompt, AGENT_TIMEOUT, model=MODEL_GUIDE)
|
||||
|
||||
if returncode != 0:
|
||||
|
||||
Reference in New Issue
Block a user