Live sermon translation into 100+ languages, running entirely on one Mac per campus: audio in, voice detection, Whisper on the GPU, NLLB-200 in its own process, and a built-in web server the congregation reads from on their phones. No audio leaves the building. This is the source only. What used to sit beside it — 14 GB of speech and translation models, 8 GB of voice bundles, 6 GB of natural voices, the Electron caches, and the app data holding the operator PIN and every service transcript — is machine state and downloaded assets, and stays in the NAS backup where it belongs. The vendored node, cloudflared and Windows ffmpeg binaries are out too (533 MB, re-fetched for packaging); the browser-side runtime beside them is kept, so a checkout still serves the congregation page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
43 lines
2.3 KiB
JavaScript
43 lines
2.3 KiB
JavaScript
import { pipeline, env } from '@huggingface/transformers';
|
|
import os from 'os'; import path from 'path';
|
|
env.allowLocalModels=false;
|
|
env.cacheDir=path.join(os.homedir(),'Library/Application Support/Church Translate Models');
|
|
const pipe=await pipeline('translation','Xenova/nllb-200-distilled-600M',{dtype:'fp32'});
|
|
const say=async(t)=>{const o=await pipe(t,{src_lang:'eng_Latn',tgt_lang:'spa_Latn'});return (Array.isArray(o)?o[0]:o).translation_text.trim();};
|
|
|
|
/* Classify which form of address NLLB reached for. */
|
|
function reg(s){
|
|
const hits=[];
|
|
if (/\bvosotros\b|\bvuestr[oa]s?\b|\bos\b(?!\s*[.,])/i.test(s)) hits.push('VOSOTROS');
|
|
if (/\bustedes\b/i.test(s)) hits.push('ustedes');
|
|
if (/\busted\b/i.test(s)) hits.push('usted');
|
|
/* vosotros verb endings */
|
|
if (/\w(áis|éis|ís)\b/.test(s)) hits.push('VOSOTROS-verb');
|
|
/* tú imperatives / 2sg endings */
|
|
if (/\b(mira|abre|vuelve|ven|escucha|piensa|deja|pon|ve|di|haz|sé)\b/i.test(s)) hits.push('tú');
|
|
/* ustedes imperative/3pl */
|
|
if (/\w(en|an)\b/.test(s) && /\b(abran|miren|vengan|escuchen|piensen|dejen|pongan|vayan|digan|hagan|estén|sean|levanten|inclinen)\b/i.test(s)) hits.push('ustedes-verb');
|
|
return hits.length?hits.join('+'):'—';
|
|
}
|
|
|
|
const LINES=[
|
|
'Open your Bibles.','Open your Bibles to John chapter three.','Bow your heads with me.',
|
|
'Stand to your feet.','Turn to the person next to you.','Listen to me carefully.',
|
|
'I want you to understand this.','God has a plan for you.','You are the light of the world.',
|
|
'You cannot serve two masters.','Do you believe that?','Are you following me?',
|
|
'Lift your hands.','Close your eyes.','Repeat after me.','Come to the altar.',
|
|
'Give thanks to the Lord.','Pray with me.','Look at verse four with me.',
|
|
'Remember what He did for you.','You have been forgiven.','Do not be afraid.',
|
|
'Love one another.','Forgive those who hurt you.','Trust in the Lord with all your heart.'
|
|
];
|
|
console.log('English -> Spanish [register NLLB chose]');
|
|
console.log('='.repeat(78));
|
|
const tally={};
|
|
for (const t of LINES) {
|
|
const s=await say(t); const r=reg(s);
|
|
for (const k of r.split('+')) tally[k]=(tally[k]||0)+1;
|
|
console.log(' '+t+'\n '+s+'\n ['+r+']');
|
|
}
|
|
console.log('\nTALLY across '+LINES.length+' direct-address sentences:');
|
|
for (const [k,v] of Object.entries(tally).sort((a,b)=>b[1]-a[1])) console.log(' '+String(v).padStart(3)+' '+k);
|