Diarisierung: Marker-Zwangsbedingungen absichern, Voiceprints als cannot-link; LLM: Sektions-Pfad ab 9k Zeichen
#79 verlor einen von vier Sprechern und lieferte eine 1082-Zeichen-Zusammenfassung. Diarisierung: ein zweiter, falsch verankerter Marker verschmolz Saschas Cluster in Merles (Kosinus -0,727). must-link prueft jetzt die akustische Aehnlichkeit, Anker werden nach Trefferqualitaet gewichtet, und enrolled Stimmen wirken als cannot-link -- damit ist der Box-Besitzer immer ein eigener Sprecher. LLM: der Whole-Pass komprimierte das erste Thema weg. Sektions-Pfad jetzt ab 9000 Zeichen, kleinere Chunks, woertlicher Kontext aus dem Vorgaenger-Chunk und ein gezielter Pruef-Aufruf gegen ueberdehnte Einzelaussagen. #79: 4 Sprecher, Zusammenfassung ~5300 Zeichen, 7 Themenbloecke. Regression: #70 -> 4, #68 -> 2, #74 -> 20 Sprecher unveraendert.
This commit is contained in:
+50
-4
@@ -22,9 +22,12 @@ flowchart TB
|
||||
FOLD -- nein --> STRONG["starker Cluster"]
|
||||
WEAK --> MK
|
||||
STRONG --> MK{"Live-Namensmarker vorhanden?"}
|
||||
MK -- ja --> CON["must-link: gleicher Name = 1 Cluster<br/>cannot-link: verschiedene Namen<br/>dürfen NIE verschmelzen"]
|
||||
MK -- nein --> B
|
||||
CON --> B["Stufe B: weiter mergen bis Schwelle<br/>(GMM-Wert) ODER bis gepinnte Anzahl"]
|
||||
MK -- ja --> CON["must-link: gleicher Name = 1 Cluster,<br/>ABER nur wenn die Cluster akustisch passen<br/>(cos ≥ 0,6 × gelernte Schwelle) —<br/>sonst Marker verwerfen (falsch getippter Zeitpunkt)<br/>cannot-link: verschiedene Namen verschmelzen NIE"]
|
||||
MK -- nein --> VP
|
||||
CON --> VP{"Bekannte Stimmabdrücke?"}
|
||||
VP -- ja --> VPC["Cluster ohne Marker gegen Voiceprints prüfen<br/>(RAW-Kosinus ≥ 0,55 + Abstand 0,05 zum Zweitbesten,<br/>ein Name höchstens 1 Cluster)<br/>→ zusätzliches cannot-link<br/>sichert vor allem den Box-Besitzer"]
|
||||
VP -- nein --> B
|
||||
VPC --> B["Stufe B: weiter mergen bis Schwelle<br/>(GMM-Wert) ODER bis gepinnte Anzahl"]
|
||||
GMM --> B
|
||||
B --> LAB["Turn-Label = dauergewichtete<br/>Mehrheit seiner Fenster"]
|
||||
LAB --> OUT["finale Sprecher<br/>(#74: 44 → 20)"]
|
||||
@@ -93,7 +96,50 @@ sequenceDiagram
|
||||
`applyMarkers()` führt sie zusammen (nutzergestützter Fix für Rest-Übersegmentierung).
|
||||
- **Nachtragen:** im Detail einer Aufnahme kann an der aktuellen Abspielposition ein Marker gesetzt werden
|
||||
(`POST /api/recordings/:id/markers`), „↻ Zuordnen" rechnet die Zuordnung neu (`apply-markers`, ohne sherpa).
|
||||
- Marker-Namen sind manuell = autoritativ; die akustische Auto-Identifikation füllt nur Lücken.
|
||||
- Marker-Namen sind manuell = autoritativ; die akustische Auto-Identifikation füllt nur Lücken —
|
||||
**mit einer Ausnahme, siehe unten** (unsicher verankerter Marker verliert gegen einen Stimmabdruck).
|
||||
|
||||
## Ein falsch getippter Marker kostete einen Sprecher (2026-07-29)
|
||||
|
||||
**Symptom (Aufnahme #79, 23-min-Jour-fixe, 4 Personen):** nur 3 Sprecher, Sascha fehlte komplett.
|
||||
|
||||
**Ursache, gemessen im Labor:** Stufe A + Faltung lieferten korrekt **4 starke Cluster**. Es gab 4 Marker
|
||||
mit 3 Namen — „Merle" war zweimal getippt worden, der zweite davon landete auf **Saschas** Cluster. Das
|
||||
alte must-link verschmolz beide „Merle"-Cluster bedingungslos, also Sascha in Merle hinein. Ihre
|
||||
Kosinus-Ähnlichkeit war **−0,727**, d. h. das Signal war eindeutig da — es wurde nur nicht ausgewertet.
|
||||
|
||||
**Drei Absicherungen:**
|
||||
|
||||
| Ebene | vorher | jetzt |
|
||||
|---|---|---|
|
||||
| Anker-Gewicht (`markerAnchors`) | jeder Marker zählt 1 | Marker IM Turn zählt 1,0, bei 25 s Tippverzögerung 0,2 |
|
||||
| must-link (`clusterWindows`) | verschmilzt immer | nur bei `cos ≥ 0,6 × gelernter Schwelle`, sonst Marker verwerfen + loggen |
|
||||
| Cluster-Fold (`applyMarkers`, server.js) | ab `conf ≠ low` | **nur `conf = high`**; `mid` darf noch benennen, aber nicht mehr verschmelzen |
|
||||
|
||||
Zusätzlich: trägt EIN Cluster Marker mehrerer Namen, war er schon vor Stufe B verschmolzen — das wird
|
||||
jetzt als Warnung geloggt statt still den lauteren Vote zu nehmen.
|
||||
|
||||
## Stimmabdrücke als Trennkriterium — der Besitzer zählt immer (2026-07-29)
|
||||
|
||||
Die Stimm-Identifikation lief bisher **nach** dem Clustering (`identifySpeakers`): sie konnte benennen,
|
||||
was herauskam, aber nie verhindern, dass zwei bekannte Personen in einem Cluster landen. Gerade der
|
||||
Besitzer der Box ist enrolled und spricht in JEDER Aufnahme — genau er verschwand in #79.
|
||||
|
||||
Jetzt gehen die Voiceprints **in** die Diarisierung (`diarize(wav, n, {markers, voiceprints})`, gefüllt in
|
||||
`rediarize()` und `transcribeAndAnalyze()`). Jedes noch namenlose Cluster wird gegen die Abdrücke geprüft;
|
||||
sitzt einer sicher darauf, wirkt der Name wie ein Marker-Tag = cannot-link.
|
||||
|
||||
- Vergleich im **RAW**-Raum (Voiceprints sind unzentriert gespeichert), deshalb streng: `DIAR_VP_MIN` 0,55
|
||||
**und** 0,05 Abstand zum Zweitbesten, ein Name beansprucht höchstens ein Cluster (bester Score gewinnt).
|
||||
- Namensschlüssel = **Vorname, kleingeschrieben**: derselbe Mensch ist als „Sascha" und „Sascha Wolf"
|
||||
enrolled (ebenso Kim/Kim Nebendahl, Fabienne/Fabienne Nachtsheim) — zwei Einträge dürfen nicht zu einem
|
||||
cannot-link zwischen seinen eigenen Clustern führen.
|
||||
- Gegenprobe ohne Regression: #79 → 4 (vorher 3), #70 → 4, #68 → 2, #74 → 20 (unverändert mit und ohne
|
||||
Voiceprints). Auf #79 wird Sascha mit cos 0,861 erkannt, auf #74 fünfzehn Personen (Kai 0,656 … Niklas 0,966).
|
||||
|
||||
**Nachwirkung im server:** ein Name, der aus einem Marker mit `conf ≠ high` stammt, verliert gegen einen
|
||||
widersprechenden Stimmabdruck (`identify #id: Stimmabdruck "X" schlägt unsicheren Marker "Y"`). In #79
|
||||
hatte der Marker bei 6,6 s Saschas Cluster „Markus" getauft.
|
||||
|
||||
## Harte Grenzen / Sackgassen
|
||||
|
||||
|
||||
Reference in New Issue
Block a user