update
This commit is contained in:
@@ -77,13 +77,13 @@ export async function chatBaustein({ topic, baustein, section, section_kompakt =
|
||||
|
||||
export async function pruefeBaustein({
|
||||
topic, baustein, section, section_kompakt = '', provider,
|
||||
aktion = 'frage', frage = '', letzte_bewertung = '', vermeide = [], anzahl = 5,
|
||||
aktion = 'frage', frage = '', letzte_bewertung = '', vermeide = [],
|
||||
tier2 = false, tier3 = false, messages = [], gruendlich = false,
|
||||
}) {
|
||||
const res = await fetch(`${BASE}/bausteine/pruefung`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ topic, baustein, section, section_kompakt, aktion, frage, letzte_bewertung, vermeide, anzahl, tier2, tier3, messages, provider, gruendlich }),
|
||||
body: JSON.stringify({ topic, baustein, section, section_kompakt, aktion, frage, letzte_bewertung, vermeide, tier2, tier3, messages, provider, gruendlich }),
|
||||
})
|
||||
return jsonOrThrow(res)
|
||||
}
|
||||
|
||||
@@ -137,24 +137,27 @@ function vermeideListe() {
|
||||
return [...gestellt, ...pool.value]
|
||||
}
|
||||
|
||||
// Pool als BATCH auffüllen: EIN Planer entwirft die fehlenden Fragen auf einmal
|
||||
// (verschieden by design), parallel geprüft → schnell und ohne ähnliche Dubletten.
|
||||
function poolFuellen() {
|
||||
if (inflight.value > 0) return
|
||||
const brauche = POOL_ZIEL - pool.value.length
|
||||
if (brauche <= 0 || poolMiss >= 3) return
|
||||
inflight.value++
|
||||
pruefeBaustein({
|
||||
function frageEinzeln() {
|
||||
// Ein Agent → eine Frage (Backend wählt zufälligen Typ + Subbaustein, dann Kritiker).
|
||||
return pruefeBaustein({
|
||||
topic: props.topic, baustein: props.baustein, section: props.section, section_kompakt: props.sectionKompakt,
|
||||
provider: props.provider, aktion: 'fragen', anzahl: brauche, messages: pruefDialog(), vermeide: vermeideListe(),
|
||||
})
|
||||
.then((res) => {
|
||||
const neu = (res.fragen || []).filter((f) => f && !istBekannt(f))
|
||||
if (neu.length) { pool.value.push(...neu); poolMiss = 0 }
|
||||
else poolMiss++
|
||||
})
|
||||
.catch(() => { poolMiss++ })
|
||||
.finally(() => { inflight.value--; if (pool.value.length < POOL_ZIEL) poolFuellen() })
|
||||
provider: props.provider, aktion: 'frage', messages: pruefDialog(), vermeide: vermeideListe(),
|
||||
}).then((res) => res.frage)
|
||||
}
|
||||
|
||||
// Pool PARALLEL auffüllen: pro fehlender Frage ein eigener Agent gleichzeitig.
|
||||
// Initial 5 parallel; nach Verbrauch genau die fehlende(n) nach.
|
||||
function poolFuellen() {
|
||||
while (pool.value.length + inflight.value < POOL_ZIEL && poolMiss < 3) {
|
||||
inflight.value++
|
||||
frageEinzeln()
|
||||
.then((text) => {
|
||||
if (text && !istBekannt(text)) { pool.value.push(text); poolMiss = 0 }
|
||||
else poolMiss++
|
||||
})
|
||||
.catch(() => { poolMiss++ })
|
||||
.finally(() => { inflight.value--; poolFuellen() })
|
||||
}
|
||||
}
|
||||
|
||||
// Eine Frage aus dem Pool nehmen; ist er leer, auf die erste eintreffende warten.
|
||||
@@ -211,47 +214,40 @@ function nachfragen() {
|
||||
)
|
||||
}
|
||||
|
||||
let letzteFeedbackMsg = null // Referenz auf die zuletzt gezeigte (provisorische) Bewertungs-Bubble
|
||||
let pruefenRun = 0 // nur die jüngste Hintergrund-Prüfung darf die Anzeige korrigieren
|
||||
let letzteFeedbackMsg = null // Referenz auf die zuletzt gezeigte Bewertungs-Bubble
|
||||
let pruefenRun = 0 // nur die jüngste Bewertung darf die Anzeige setzen
|
||||
|
||||
function bewerten(res) {
|
||||
letztesFeedback.value = res.feedback || ''
|
||||
pruefMessages.value.push({ role: 'assistant', kind: 'feedback', content: res.feedback || '', bewertung: res.bewertung, geprueft: false })
|
||||
letzteFeedbackMsg = pruefMessages.value[pruefMessages.value.length - 1]
|
||||
pruefPhase.value = 'bewertet'
|
||||
verdictPruefen() // im Hintergrund verbindlich prüfen lassen
|
||||
}
|
||||
|
||||
function antwortPayload() {
|
||||
// Basis/Streak führt der Server je Frage (frage = Anker). Frontend schickt sie nicht mehr.
|
||||
return { aktion: 'antwort', frage: aktuelleFrage.value, tier2: props.tier2, tier3: props.tier3 }
|
||||
}
|
||||
|
||||
// Hintergrund: voller Bewerter+Kritiker. Persistiert serverseitig; korrigiert die Anzeige bei Abweichung.
|
||||
// gruendlich=true: starkes Modell (role guide), manuell ausgelöst → sichtbarer Ladezustand.
|
||||
async function verdictPruefen(gruendlich = false) {
|
||||
// Antwort verbindlich prüfen — der Prüfer (Bewerter + Kritiker) vergibt die Punkte.
|
||||
// Während des Wartens zeigt das „…"-Bubble den Geprüft-Zustand. gruendlich=true:
|
||||
// starkes Modell, re-bewertet dieselbe Frage und aktualisiert die bestehende Bubble.
|
||||
async function bewertenLassen(gruendlich = false) {
|
||||
const meine = ++pruefenRun
|
||||
const ziel = letzteFeedbackMsg
|
||||
if (gruendlich) pruefLoading.value = true
|
||||
pruefStick.value = true
|
||||
pruefLoading.value = true
|
||||
pruefScroll()
|
||||
try {
|
||||
const res = await pruefeBaustein({
|
||||
topic: props.topic, baustein: props.baustein, section: props.section, section_kompakt: props.sectionKompakt,
|
||||
provider: props.provider, messages: pruefDialog(), ...antwortPayload(), aktion: 'antwort_pruefen', gruendlich,
|
||||
provider: props.provider, messages: pruefDialog(),
|
||||
aktion: 'antwort_pruefen', frage: aktuelleFrage.value, tier2: props.tier2, tier3: props.tier3, gruendlich,
|
||||
})
|
||||
// Server führt den Score (serialisiert, absolut) — IMMER übernehmen, auch wenn man
|
||||
// schon bei der nächsten Frage ist. Sonst geht die Korrektur verloren.
|
||||
if (meine !== pruefenRun) return
|
||||
applyPruefung(res)
|
||||
if (ziel) {
|
||||
if (res.bewertung !== ziel.bewertung || (res.feedback && res.feedback !== ziel.content)) {
|
||||
ziel.content = res.feedback || ziel.content
|
||||
ziel.bewertung = res.bewertung
|
||||
}
|
||||
ziel.geprueft = true
|
||||
letztesFeedback.value = res.feedback || ''
|
||||
if (gruendlich && letzteFeedbackMsg) {
|
||||
letzteFeedbackMsg.content = res.feedback || letzteFeedbackMsg.content
|
||||
letzteFeedbackMsg.bewertung = res.bewertung
|
||||
} else {
|
||||
pruefMessages.value.push({ role: 'assistant', kind: 'feedback', content: res.feedback || '', bewertung: res.bewertung, geprueft: true })
|
||||
letzteFeedbackMsg = pruefMessages.value[pruefMessages.value.length - 1]
|
||||
pruefPhase.value = 'bewertet'
|
||||
}
|
||||
pruefScroll()
|
||||
nextTick(() => pruefInputEl.value?.focus())
|
||||
} catch {
|
||||
if (ziel) ziel.geprueft = true
|
||||
if (meine === pruefenRun) pruefMessages.value.push({ role: 'assistant', kind: 'fehler', content: 'Hat nicht geklappt — bitte erneut.' })
|
||||
} finally {
|
||||
if (gruendlich && meine === pruefenRun) pruefLoading.value = false
|
||||
if (meine === pruefenRun) pruefLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,7 +256,7 @@ function antwortAbgeben() {
|
||||
if (!text || pruefLoading.value) return
|
||||
pruefMessages.value.push({ role: 'user', kind: 'antwort', content: text })
|
||||
pruefInput.value = ''
|
||||
pruefSenden(antwortPayload(), bewerten)
|
||||
bewertenLassen(false)
|
||||
}
|
||||
|
||||
// Lief schon eine Diskussion? Dann darf der Verlauf direkt bewertet werden.
|
||||
@@ -269,17 +265,17 @@ const hatDiskussion = computed(() => pruefMessages.value.some((m) => m.kind ===
|
||||
// „Verlauf bewerten": den bisherigen Dialog als Antwort werten (Feld wird ignoriert).
|
||||
function verlaufBewerten() {
|
||||
if (pruefLoading.value) return
|
||||
pruefSenden(antwortPayload(), bewerten)
|
||||
bewertenLassen(false)
|
||||
}
|
||||
|
||||
// „Gründlich prüfen": dieselbe Antwort, aber vom starken Modell (role guide) verbindlich neu bewerten.
|
||||
// „Gründlich prüfen": dieselbe Antwort vom starken Modell (role guide) neu bewerten.
|
||||
function gruendlichPruefen() {
|
||||
if (pruefLoading.value) return
|
||||
verdictPruefen(true)
|
||||
bewertenLassen(true)
|
||||
}
|
||||
|
||||
// Abbruch wie im Chat: Run-Counter hochzählen → laufendes Ergebnis (pruefSenden
|
||||
// und verdictPruefen) wird verworfen, Buttons sofort frei. Agent läuft serverseitig aus.
|
||||
// und bewertenLassen) wird verworfen, Buttons sofort frei. Agent läuft serverseitig aus.
|
||||
function pruefAbbrechen() {
|
||||
if (!pruefLoading.value) return
|
||||
pruefRun++
|
||||
@@ -296,7 +292,6 @@ onMounted(() => {
|
||||
if (props.mode !== 'full') return // Trigger-Modus (Liste): nur Tab-Leiste, keine Prüfungs-/Text-Logik
|
||||
window.addEventListener('keydown', onWindowKey)
|
||||
window.addEventListener('keydown', onPruefKey)
|
||||
poolFuellen() // Pool schon beim Öffnen vorfüllen — keine Wartezeit bei der ersten Frage
|
||||
})
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('keydown', onWindowKey)
|
||||
|
||||
Reference in New Issue
Block a user