feat: KI-Bewertungs-Versionierung — alte Versionen behalten
Backend: - DELETE vor INSERT entfernt — neue Bewertungen werden hinzugefügt - erstellt_at Timestamp bei jeder Neubewertung - API liefert ki_versionen[] (ältere Versionen, neueste zuerst) Frontend (Explorer + Vorlagen-Detail): - Neueste Version als Hauptanzeige (wie bisher) - Button 'X vorherige Versionen' → aufklappbar - Jede Version mit Zeitstempel + prompt_version
This commit is contained in:
parent
df917725e2
commit
3fd1bc5bd7
@ -85,6 +85,7 @@ class VorlageDetail(BaseModel):
|
||||
kette_id: int | None = None
|
||||
umsetzungsbewertungen: list[UmsetzungsBewertung] = []
|
||||
ampel: dict | None = None
|
||||
ki_versionen: list[dict] | None = None
|
||||
|
||||
|
||||
class KettenGliedOut(BaseModel):
|
||||
|
||||
@ -162,12 +162,12 @@ def _run_zusammenfassung(vorlage_id: int, anmerkung: str, job_id: str):
|
||||
_jobs[job_id] = {"status": "error", "error": str(result)}
|
||||
return
|
||||
|
||||
# Delete old, insert new
|
||||
conn.execute("DELETE FROM ki_bewertungen WHERE vorlage_id = ? AND typ = 'zusammenfassung'", (vorlage_id,))
|
||||
# Keep old versions, insert new
|
||||
conn.execute(
|
||||
"""INSERT INTO ki_bewertungen (vorlage_id, typ, begruendung, anmerkungen, modell, prompt_version)
|
||||
VALUES (?, 'zusammenfassung', ?, ?, 'qwen-plus-latest', 'v2-reeval')""",
|
||||
(vorlage_id, result.get("zusammenfassung"), json.dumps(result, ensure_ascii=False)),
|
||||
"""INSERT INTO ki_bewertungen (vorlage_id, typ, begruendung, anmerkungen, modell, prompt_version, erstellt_at)
|
||||
VALUES (?, 'zusammenfassung', ?, ?, 'qwen-plus-latest', 'v2-reeval', ?)""",
|
||||
(vorlage_id, result.get("zusammenfassung"), json.dumps(result, ensure_ascii=False),
|
||||
datetime.now().isoformat()),
|
||||
)
|
||||
if result.get("kernforderung"):
|
||||
conn.execute("UPDATE vorlagen SET thema_kurz = ? WHERE id = ?", (result["kernforderung"][:200], vorlage_id))
|
||||
@ -249,19 +249,16 @@ def _run_ketten_bewertung(kette_id: int, anmerkung: str, job_id: str):
|
||||
_jobs[job_id] = {"status": "error", "error": str(result)}
|
||||
return
|
||||
|
||||
# Delete old umsetzung_match, insert new
|
||||
# Keep old versions, insert new
|
||||
conn.execute(
|
||||
"DELETE FROM ki_bewertungen WHERE vorlage_id = ? AND typ = 'umsetzung_match'",
|
||||
(kette["ursprung_id"],),
|
||||
)
|
||||
conn.execute(
|
||||
"""INSERT INTO ki_bewertungen (vorlage_id, typ, score, begruendung, anmerkungen, modell, prompt_version)
|
||||
VALUES (?, 'umsetzung_match', ?, ?, ?, 'qwen-plus-latest', 'v2-reeval')""",
|
||||
"""INSERT INTO ki_bewertungen (vorlage_id, typ, score, begruendung, anmerkungen, modell, prompt_version, erstellt_at)
|
||||
VALUES (?, 'umsetzung_match', ?, ?, ?, 'qwen-plus-latest', 'v2-reeval', ?)""",
|
||||
(
|
||||
kette["ursprung_id"],
|
||||
result.get("score"),
|
||||
result.get("begruendung"),
|
||||
json.dumps(result, ensure_ascii=False),
|
||||
datetime.now().isoformat(),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@ -297,16 +297,28 @@ def get_vorlage(vorlage_id: int, conn=Depends(_db)):
|
||||
if kette_info and kette_info["strang"]:
|
||||
kette_ampel = get_ampel(kette_info["strang"], kette_info["status"] or "")
|
||||
|
||||
# KI-Zusammenfassung
|
||||
ki_row = conn.execute(
|
||||
"SELECT anmerkungen FROM ki_bewertungen WHERE vorlage_id = ? AND typ = 'zusammenfassung' LIMIT 1",
|
||||
# KI-Zusammenfassung (alle Versionen, neueste zuerst)
|
||||
ki_rows = conn.execute(
|
||||
"SELECT anmerkungen, erstellt_at, prompt_version FROM ki_bewertungen WHERE vorlage_id = ? AND typ = 'zusammenfassung' ORDER BY id DESC",
|
||||
(vorlage_id,),
|
||||
).fetchone()
|
||||
).fetchall()
|
||||
ki_zusammenfassung = None
|
||||
if ki_row and ki_row["anmerkungen"]:
|
||||
ki_versionen = []
|
||||
for i, ki_row in enumerate(ki_rows):
|
||||
if ki_row["anmerkungen"]:
|
||||
try:
|
||||
ki_data = json.loads(ki_row["anmerkungen"])
|
||||
if i == 0:
|
||||
ki_zusammenfassung = KiZusammenfassung(**ki_data)
|
||||
else:
|
||||
ki_versionen.append({
|
||||
"zusammenfassung": ki_data.get("zusammenfassung", ""),
|
||||
"kernforderung": ki_data.get("kernforderung", ""),
|
||||
"begruendung": ki_data.get("begruendung", ""),
|
||||
"thema": ki_data.get("thema", ""),
|
||||
"erstellt_at": ki_row["erstellt_at"],
|
||||
"prompt_version": ki_row["prompt_version"],
|
||||
})
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
pass
|
||||
|
||||
@ -351,4 +363,5 @@ def get_vorlage(vorlage_id: int, conn=Depends(_db)):
|
||||
ki_zusammenfassung=ki_zusammenfassung,
|
||||
umsetzungsbewertungen=umsetzungsbewertungen,
|
||||
ampel=kette_ampel,
|
||||
ki_versionen=ki_versionen if ki_versionen else None,
|
||||
)
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
// Mobile tab
|
||||
let mobileTab = $state<'liste' | 'kette' | 'detail'>('liste');
|
||||
let showVolltext = $state(false);
|
||||
let showVersionen = $state(false);
|
||||
|
||||
const STRANG_TABS = [
|
||||
{ value: '', label: 'Alle' },
|
||||
@ -438,6 +439,33 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Vorherige KI-Versionen -->
|
||||
{#if selectedVorlage.ki_versionen?.length}
|
||||
<div>
|
||||
<button onclick={() => showVersionen = !showVersionen}
|
||||
class="text-xs text-gray-500 hover:text-gray-700 flex items-center gap-1">
|
||||
<span>{showVersionen ? '▼' : '▶'}</span>
|
||||
{selectedVorlage.ki_versionen.length} vorherige Version{selectedVorlage.ki_versionen.length > 1 ? 'en' : ''}
|
||||
</button>
|
||||
{#if showVersionen}
|
||||
<div class="mt-2 space-y-3">
|
||||
{#each selectedVorlage.ki_versionen as v, i}
|
||||
<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<span class="text-xs text-gray-400">Version {selectedVorlage.ki_versionen.length - i} · {v.erstellt_at || 'unbekannt'}</span>
|
||||
<span class="text-[10px] px-1.5 py-0.5 rounded bg-gray-200 text-gray-500">{v.prompt_version || ''}</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-600">{v.zusammenfassung}</p>
|
||||
{#if v.kernforderung}
|
||||
<p class="text-xs text-gray-500 mt-1"><strong>Kernforderung:</strong> {v.kernforderung}</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Umsetzungsbewertung -->
|
||||
{#if selectedVorlage.umsetzungsbewertungen?.length}
|
||||
<div class="rounded-xl border border-gray-200 p-5">
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
let error: string | null = $state(null);
|
||||
let showVolltext = $state(false);
|
||||
let showReeval = $state(false);
|
||||
let showVersionen = $state(false);
|
||||
let reevalAnmerkung = $state('');
|
||||
let reevalStatus = $state<'idle' | 'running' | 'done' | 'error'>('idle');
|
||||
let reevalError = $state('');
|
||||
@ -201,6 +202,33 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Vorherige KI-Versionen -->
|
||||
{#if vorlage.ki_versionen?.length}
|
||||
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
|
||||
<button onclick={() => showVersionen = !showVersionen}
|
||||
class="text-sm text-gray-500 hover:text-gray-700 flex items-center gap-1.5">
|
||||
<span>{showVersionen ? '▼' : '▶'}</span>
|
||||
{vorlage.ki_versionen.length} vorherige KI-Version{vorlage.ki_versionen.length > 1 ? 'en' : ''}
|
||||
</button>
|
||||
{#if showVersionen}
|
||||
<div class="mt-3 space-y-3">
|
||||
{#each vorlage.ki_versionen as v, i}
|
||||
<div class="rounded-lg border border-gray-200 bg-gray-50 p-4">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<span class="text-xs text-gray-400">Version {vorlage.ki_versionen.length - i} · {v.erstellt_at || 'unbekannt'}</span>
|
||||
<span class="text-[10px] px-1.5 py-0.5 rounded bg-gray-200 text-gray-500">{v.prompt_version || ''}</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-600">{v.zusammenfassung}</p>
|
||||
{#if v.kernforderung}
|
||||
<p class="text-xs text-gray-500 mt-1"><strong>Kernforderung:</strong> {v.kernforderung}</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Umsetzungsbewertung -->
|
||||
{#if vorlage.umsetzungsbewertungen?.length}
|
||||
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user