feat(analyse): Kontextnotiz zum Gespraech nach dem Stop
Ein Freitextfeld ("Kontext zum Gespraech") in der Detailansicht, nach dem
Stop aufgeklappt. Der Text geht als Hintergrundwissen in die LLM-Analyse:
Personen, Firmen, Anlass und Eigennamen muessen nicht mehr aus dem
fehlerbehafteten ASR-Text erraten werden.
Bewusst EIN Feld statt eines Formulars mit Teilnehmer-/Anlass-/Begriffs-
feldern (Entscheidung des Nutzers): die Box benutzen auch technisch nicht
versierte Menschen. Gefuehrt wird ueber den Platzhaltertext, die Struktur
zieht die Analyse selbst aus der Prosa.
- recordings.context_note/-_at, db.setContextNote/getContextNote
- PATCH /api/recordings/:id/context; Antwort `applies` sagt ehrlich, ob die
Notiz die laufende Verarbeitung noch erreicht (auto/running/reanalyze)
- analyzeRecording liest die Notiz erst kurz vor dem LLM-Aufruf, damit
waehrend der minutenlangen Vorstufen Getipptes noch zaehlt
- llm.contextBlock: eigener """-Block mit Verbot, daraus Aussagen, Ergebnisse
oder Aufgaben abzuleiten (sonst schreibt das 4B-Modell die Notiz als
Gesagtes zurueck); eingespeist in Single-, Whole- und Sektions-Pfad
- zwei Deckel: 1200 Zeichen fuer Prompts, die die Notiz einmal sehen,
600 fuer die Chunk-Prompts (dort landet sie in jedem Chunk von 3200)
- GUI-Karte zeichnet sich selbst neu (kein openRecording -> Audio laeuft
weiter), ungespeicherter Text ueberlebt den Neuaufbau nach der Analyse
Verifiziert an #97: Kontext greift (korrekte Namen, richtiges Thema), die
absichtlich eingelegten Fremdfakten der Testnotiz erscheinen nicht in der
Zusammenfassung. Alte Analyse danach zurueckgeschrieben.
Doku: Kapitel 05 (neuer Abschnitt + Flussdiagramm + Deckel-Tabelle),
Kapitel 03 (Sequenzdiagramm + API), Changelog 2026-08-17.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+22
-1
@@ -319,7 +319,12 @@ async function analyzeRecording(id) {
|
||||
// Remember which label each speaker had in the LLM input, so renaming a
|
||||
// speaker later can patch the finished text (relabelAnalysis).
|
||||
await db.setSpeakerLabels(id, labels).catch(() => {});
|
||||
const a = await llm.analyze(text, { labeled, glossary });
|
||||
// Kontextnotiz des Nutzers (Freitext, nach dem Stop getippt) geht als
|
||||
// Hintergrundwissen mit. Bewusst JETZT frisch gelesen und nicht aus `rec`
|
||||
// von oben: die Sprecher-Erkennung darüber braucht Minuten, der Nutzer tippt
|
||||
// in dieser Zeit — was bis hierher gespeichert ist, zählt noch mit.
|
||||
const note = await db.getContextNote(id).catch(() => '');
|
||||
const a = await llm.analyze(text, { labeled, glossary, context: note });
|
||||
// Participants = the ACOUSTICALLY diarized speakers (named where known),
|
||||
// not the LLM's list — the model returned every name MENTIONED in the
|
||||
// conversation as a "Teilnehmer" (11 names on a 3-person call, #69).
|
||||
@@ -479,6 +484,22 @@ app.patch('/api/recordings/:id/title', wrap(async (req, res) => {
|
||||
res.json({ ok: true, id, title: row.title, title_locked: !!row.title_locked });
|
||||
}));
|
||||
|
||||
// Kontextnotiz speichern (leerer Text löscht sie). Der Rückgabewert `applies`
|
||||
// sagt der GUI ehrlich, ob die Notiz die LAUFENDE Analyse noch erreicht — das
|
||||
// entscheidet sich daran, wie weit die Verarbeitung ist:
|
||||
// 'auto' = wird noch transkribiert; die Analyse liest die Notiz danach
|
||||
// 'running' = Analyse läuft bereits, sie kann die Notiz verpasst haben
|
||||
// 'reanalyze' = Analyse ist fertig/fehlgeschlagen → nur ein neuer Lauf nutzt sie
|
||||
app.patch('/api/recordings/:id/context', wrap(async (req, res) => {
|
||||
const id = +req.params.id;
|
||||
const row = await db.setContextNote(id, (req.body && req.body.context_note) || '');
|
||||
if (!row) return res.status(404).json({ error: 'not found' });
|
||||
const applies = row.status === 'transcribing' ? 'auto'
|
||||
: row.analysis_status === 'pending' ? 'running' : 'reanalyze';
|
||||
res.json({ ok: true, id, context_note: row.context_note || '',
|
||||
context_note_at: row.context_note_at, applies, max: db.CONTEXT_MAX });
|
||||
}));
|
||||
|
||||
// --- Trash -------------------------------------------------------------------
|
||||
// Delete = move to the bin. Nothing on disk is touched until the retention
|
||||
// window expires, so a restore brings back audio, transcript and analysis.
|
||||
|
||||
Reference in New Issue
Block a user