Files

45 lines
2.6 KiB
JavaScript

// Riascolta le voci del gioco (make ascolta): ogni mp3 di assets/voices/ passa da `mbot ascolta` (faster-whisper sulla
// GPU, skill «trascrittore») e si confronta col testo letto dalla voce. Elenca quelle che dicono altro: si rifanno
// con `node tools/voci.mjs --rifai 'pezzo di testo'`, oppure si aggiunge una riga a tools/pronuncia.json.
// node tools/ascolta.mjs [--min 0.8] [testo...] (con un testo: solo le battute che lo contengono)
import { execFileSync } from 'node:child_process';
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
import { spoken } from './pronuncia.mjs';
const ROOT = new URL('..', import.meta.url).pathname;
const index = JSON.parse(readFileSync(join(ROOT, 'assets/voices/index.json'), 'utf8'));
const args = process.argv.slice(2), at = args.indexOf('--min');
const min = at >= 0 ? args.splice(at, 2)[1] : '0.8';
const only = args;
// I numeri Whisper li scrive in cifre («Nove.» → «9.»): per il confronto le cifre tornano parole.
const NUMERI = ['zero', 'uno', 'due', 'tre', 'quattro', 'cinque', 'sei', 'sette', 'otto', 'nove', 'dieci', 'undici', 'dodici'];
const plain = t => t.toLowerCase().normalize('NFD').replace(/[̀-ͯ]/g, '').replace(/[^a-z0-9]+/g, ' ').trim();
const jobs = Object.entries(index)
.map(([key, e]) => ({ who: key.split('|')[0], text: key.slice(key.indexOf('|') + 1), file: join(ROOT, 'assets/voices', e.file) }))
.filter(j => !only.length || only.some(o => j.text.includes(o)))
.map(j => ({ ...j, expect: spoken(j.text) }));
const dir = join(tmpdir(), 'leggenda-regolo-ascolto');
mkdirSync(dir, { recursive: true });
writeFileSync(join(dir, 'ascolto.json'), JSON.stringify(jobs.map(({ file, expect }) => ({ file, expect }))));
let out = '';
try {
out = execFileSync('mbot', ['ascolta', '--jobs', join(dir, 'ascolto.json'), '--json', '--min', min],
{ encoding: 'utf8', maxBuffer: 64 << 20, stdio: ['ignore', 'pipe', 'inherit'] });
} catch (e) { out = e.stdout ?? ''; }
const byFile = new Map(jobs.map(j => [j.file, j]));
const bad = [];
for (const line of out.split('\n').filter(l => l.startsWith('{'))) {
const r = JSON.parse(line);
if (r.ok !== false) continue;
const j = byFile.get(r.file), heard = r.text ?? r.heard ?? '';
if (j && plain(heard.replace(/\b(\d{1,2})\b/g, (m, n) => NUMERI[+n] ?? m)) === plain(j.expect)) continue;
bad.push({ ...j, heard, score: r.score ?? r.similarity });
}
for (const b of bad) console.log(`${b.score ?? '?'} ${b.who}: «${b.text}»\n sentito: «${b.heard}»`);
console.log(`${jobs.length} voci ascoltate, ${bad.length} da guardare`);