Diarization v2: Fenster-Clustering mit gelernter Schwelle + Live-Namensmarker
#74 (22 Teilnehmer) ergab automatisch 44 Sprecher, dieselbe Stimme mehrfach. Ursache gemessen: ein Zentroid pro sherpa-Cluster aus max. 3 Schnitten, fester Kosinus auf rohen Embeddings (Kreuz-Turn-Kosinus ~0,4 = keine Trennschaerfe). v2: sherpa liefert nur Turn-Grenzen, Identitaet aus 3-s-Fenster-Embeddings, Mittelwert-Zentrierung, Average-Linkage-AHC, Weak-Fold, Schwelle pro Aufnahme per 2-Gauss-EM gelernt. Validiert: #74 44->20, #70 ->4, #68 ->2. Live-Namensmarker: Namen waehrend der Aufnahme tippen; Zeitstempel benennt spaeter den Cluster und dient als must-/cannot-link-Zwangsbedingung.
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
// Replay the REAL production clustering (diar.js clusterWindows) on cached
|
||||
// window embeddings, so thresholds can be tuned without re-running sherpa or the
|
||||
// embedding pass. Usage:
|
||||
// [DIAR_COS_FINE=..] [DIAR_COS_FINAL=..] node lab-eval.mjs <emb.json> [expect] [numSpeakers] [markers.json]
|
||||
import fs from 'node:fs';
|
||||
import { clusterWindows } from './diar-v2.js';
|
||||
|
||||
const [file, expect, numSp, markerFile] = process.argv.slice(2);
|
||||
const d = JSON.parse(fs.readFileSync(file, 'utf8'));
|
||||
const ok = d.wins.filter(w => w.v).map(w => ({ ti: w.ti, start: w.s, end: w.e, vec: w.v }));
|
||||
const markers = markerFile ? JSON.parse(fs.readFileSync(markerFile, 'utf8')) : [];
|
||||
const segs = clusterWindows(d.turns, ok, +(numSp || 0), markers);
|
||||
|
||||
const talk = new Map(), first = new Map(), last = new Map();
|
||||
for (const s of segs) {
|
||||
talk.set(s.speaker, (talk.get(s.speaker) || 0) + (s.end - s.start));
|
||||
if (!first.has(s.speaker)) first.set(s.speaker, s.start);
|
||||
last.set(s.speaker, s.end);
|
||||
}
|
||||
const order = [...talk.entries()].sort((a, b) => b[1] - a[1]);
|
||||
console.log(`RESULT ${d.model.split('/').pop()} fine=${process.env.DIAR_COS_FINE || 0.35} final=${process.env.DIAR_COS_FINAL || 0.30}` +
|
||||
` → speakers=${order.length}${expect ? ` (expect ${expect})` : ''} segs=${segs.length}`);
|
||||
console.log(' ' + order.map(([sp, t]) => `${sp.replace('speaker_', '')}:${t.toFixed(0)}s[${(first.get(sp) / 60).toFixed(1)}-${(last.get(sp) / 60).toFixed(1)}]`).join(' '));
|
||||
Reference in New Issue
Block a user