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>
This commit is contained in:
2026-09-23 15:41:21 -04:00
co-authored by Claude Opus 5
commit c9eef0672c
118 changed files with 36031 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
const fs=require('fs'),vm=require('vm');
const src=fs.readFileSync('engine.js','utf8');
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);}};
const sb={console};vm.createContext(sb);
vm.runInContext(src.match(/^const ABBREV_TAIL = .*$/m)[0], sb);
vm.runInContext(grab('splitSentences'), sb);
let pass=0,fail=0;
const t=(label,input,want)=>{const got=sb.splitSentences(input);const ok=JSON.stringify(got)===JSON.stringify(want);
console.log((ok?' PASS ':' FAIL ')+label);
if(!ok)console.log(' got '+JSON.stringify(got)+'\n want '+JSON.stringify(want));
ok?pass++:fail++;};
console.log('\nAMEN MUST SURVIVE');
t('amen after a sentence','God is good. Amen.',['God is good.','Amen.']);
t('amen alone','Amen.',['Amen.']);
t('two short sentences','Jesus wept. Amen.',['Jesus wept.','Amen.']);
t('hallelujah trailing','God is faithful. Hallelujah!',['God is faithful.','Hallelujah!']);
t('three shorts','Yes. Amen. Hallelujah.',['Yes.','Amen.','Hallelujah.']);
console.log('\nWHAT THE GLUE RULE WAS PROTECTING');
t('leading abbreviation','Dr. King said God is good.',['Dr. King said God is good.']);
t('mid abbreviation','We heard Dr. King speak today.',['We heard Dr. King speak today.']);
t('single initial','C. S. Lewis wrote that.',['C. S. Lewis wrote that.']);
t('decimal rejoined','It cost 3.5 million.',['It cost 3.5 million.']);
t('verse decimal','Read John 3.16 today.',['Read John 3.16 today.']);
t('saint','St. Paul wrote it.',['St. Paul wrote it.']);
console.log('\nORDINARY TEXT UNCHANGED');
t('one sentence','Today we are going to talk about Peter in the Bible.',
['Today we are going to talk about Peter in the Bible.']);
t('two full sentences','God is love. He gave His only Son.',['God is love.','He gave His only Son.']);
t('question','Do you believe that? I do.',['Do you believe that?','I do.']);
t('semicolon stays','The Lord is my shepherd; I shall not want.',
['The Lord is my shepherd; I shall not want.']);
console.log('\n'+pass+' passed, '+fail+' failed');
process.exit(fail?1:0);