Files
church-translate/app/_test-e2e2.mjs
christianandClaude Opus 5 c9eef0672c Church Translate, as it runs at the campuses
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>
2026-09-23 15:41:21 -04:00

40 lines
1.8 KiB
JavaScript

/* The full chain, and specifically: does the ENGLISH the listener sees stay
exactly as spoken while the translation improves? */
import { pipeline, env } from '@huggingface/transformers';
import { createRequire } from 'module';
import os from 'os'; import path from 'path'; import fs from 'fs'; import vm from 'vm';
const require = createRequire(import.meta.url);
const Liturgy=require('./liturgy.js'), Guard=require('./mt-guard.js'), Preach=require('./preach.js');
const src=fs.readFileSync('engine.js','utf8');
const sb={console}; vm.createContext(sb);
vm.runInContext(src.match(/^const ABBREV_TAIL = .*$/m)[0], sb);
const grab=(n)=>{const i=src.indexOf('function '+n+'(');let d=0;for(let k=src.indexOf('{',i);k<src.length;k++){if(src[k]==='{')d++;else if(src[k]==='}'&&--d===0)return src.slice(i,k+1);}};
vm.runInContext(grab('splitSentences'), sb);
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 UTTERANCES=[
'Open up to the book of John.',
'Circle that in your Bible. Amen.',
'Let that sink in.',
'Open up to the book of John. God is good. Amen.',
'We are going to talk about Peter in the Bible.'
];
for (const u of UTTERANCES) {
console.log('\nSPOKEN / shown in English: "'+u+'"');
for (const lang of ['spa_Latn','por_Latn','fra_Latn']) {
const parts=[];
for (const s of sb.splitSentences(u)) {
const set=Liturgy.lookup(s,lang);
if (set) { parts.push(set); continue; }
const forMt=Preach.forTranslation(s);
const o=await pipe(forMt,{src_lang:'eng_Latn',tgt_lang:lang});
const raw=(Array.isArray(o)?o[0]:o).translation_text.trim();
parts.push(Guard.clean(forMt,raw).text);
}
console.log(' '+lang.slice(0,3)+' '+parts.join(' '));
}
}