/* Does the batched path have a cliff at N=4..6? Sweep every N through the REAL service, interleaved A/B so machine load hits both arms equally. */ import { fork } from 'child_process'; import os from 'os'; import path from 'path'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const MODELS_DIR = path.join(os.homedir(), 'Library/Application Support/Church Translate Models'); const LANGS = ['spa_Latn','por_Latn','fra_Latn','zho_Hans','hat_Latn','hin_Deva','kor_Hang','vie_Latn','arb_Arab']; const TEXT = 'And I want you to understand that God has a plan for your life'; const child = fork(path.join(__dirname, 'mt-service.js'), [], { stdio: ['ignore','pipe','pipe','ipc'] }); child.stderr.on('data', () => {}); let seq = 0; const pending = new Map(); child.on('message', (m) => { if (m.type === 'ready') { pending.get('ready')(); return; } if (m.type === 'progress' || m.type === 'note') return; const w = pending.get(m.id); if (!w) return; pending.delete(m.id); if (m.type === 'error') w.reject(new Error(m.message)); else w.resolve(m.type === 'multi' ? m.texts : m.text); }); const send = (p) => new Promise((resolve, reject) => { const id = ++seq; pending.set(id, {resolve,reject}); child.send({...p, id}); }); const ready = new Promise(r => pending.set('ready', r)); child.send({ type:'load', model:'Xenova/nllb-200-distilled-600M', dtype:'fp32', cacheDir: MODELS_DIR }); await ready; const one = (t) => send({ type:'translate', text:TEXT, src:'eng_Latn', tgt:t }); const many = (ts) => send({ type:'translateMulti', text:TEXT, src:'eng_Latn', tgts:ts }); await one('spa_Latn'); await many(['spa_Latn','fra_Latn']); const REPS = 3; console.log(' N | serial(med) | batched(med) | speedup | identical'); console.log('---+-------------+--------------+---------+----------'); for (let n = 1; n <= 9; n++) { const langs = LANGS.slice(0, n); const S = [], B = []; let same = 0, tot = 0; for (let r = 0; r < REPS; r++) { let t = Date.now(); const so = {}; for (const l of langs) so[l] = await one(l); S.push(Date.now()-t); t = Date.now(); const bo = await many(langs); B.push(Date.now()-t); for (const l of langs) { tot++; if (so[l] === bo[l]) same++; } } const med = (a) => a.sort((x,y)=>x-y)[Math.floor(a.length/2)]; const s = med(S), b = med(B); console.log(String(n).padStart(2) + ' | ' + (s+'ms').padStart(11) + ' | ' + (b+'ms').padStart(12) + ' | ' + ((s/b).toFixed(2)+'x').padStart(7) + ' | ' + same + '/' + tot); } child.kill();