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:
@@ -0,0 +1,60 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8">
|
||||
<title>group + channel CSS check</title><link rel="stylesheet" href="./engine.css"></head>
|
||||
<body>
|
||||
<header class="head"><div class="brand"><span class="mark"></span><span>Church Translate</span>
|
||||
<span class="build" id="buildTag">3.11.0 · 75</span></div></header>
|
||||
<main class="page">
|
||||
<section class="hero" data-state="ready"><h1>Hero spans both columns</h1></section>
|
||||
<div class="col-main">
|
||||
<section class="group" id="g1" data-open="true">
|
||||
<button class="group-head" type="button"><span class="chev"></span><h2>Input</h2>
|
||||
<span class="group-sub">Dante Virtual Soundcard · ch 1</span></button>
|
||||
<div class="group-body" id="g1b"><div class="group-inner">
|
||||
<div class="chanbox"><div class="chanhead"><label style="margin:0">Channels</label>
|
||||
<span class="hint" id="chanNote" style="margin:0">channel 1</span>
|
||||
<button class="btn">Mix all</button></div>
|
||||
<div class="chanlist" id="chanList"></div></div>
|
||||
<p class="hint">Some content so the section has height.</p>
|
||||
</div></div>
|
||||
</section>
|
||||
<section class="group" id="g2"><button class="group-head" type="button"><span class="chev"></span>
|
||||
<h2>Languages and voices</h2><span class="group-sub">9 on · 1 pinned</span></button>
|
||||
<div class="group-body" id="g2b"><div class="group-inner">
|
||||
<p>Line</p><p>Line</p><p>Line</p><p>Line</p><p>Line</p><p>Line</p><p>Line</p><p>Line</p>
|
||||
</div></div></section>
|
||||
<section class="group" id="g3"><button class="group-head" type="button"><span class="chev"></span>
|
||||
<h2>Settings</h2><span class="group-sub">no stream delay</span></button>
|
||||
<div class="group-body"><div class="group-inner"><p>Line</p><p>Line</p></div></div></section>
|
||||
<section class="card"><h2>Log</h2><div class="log"></div></section>
|
||||
</div>
|
||||
<aside class="col-rail"><section class="card rail-card"><h2>What the congregation opens</h2>
|
||||
<div class="qr" style="width:11rem;height:11rem;background:#fff;margin:0 auto .625rem"></div>
|
||||
<div class="railbtns"><button class="btn btn-primary">Copy address</button>
|
||||
<button class="btn">Printable poster</button></div>
|
||||
<h3 class="subhead">Operator page</h3>
|
||||
<div class="codeblock"><code>http://10.6.3.222:3100/operator</code><button class="btn">Copy</button></div>
|
||||
<button class="btn railwide">Open operator page</button></section></aside>
|
||||
</main>
|
||||
<script>
|
||||
for (const sec of document.querySelectorAll('.group')) {
|
||||
sec.querySelector('.group-head').addEventListener('click', () => {
|
||||
sec.dataset.open = sec.dataset.open === 'true' ? 'false' : 'true';
|
||||
});
|
||||
}
|
||||
const list = document.getElementById('chanList');
|
||||
for (let i = 0; i < 16; i++) {
|
||||
const r = document.createElement('button');
|
||||
r.type = 'button'; r.className = 'chanrow' + (i === 0 ? ' on' : ''); r.dataset.ch = i;
|
||||
r.innerHTML = '<b>' + (i+1) + '</b><span class="chanbar"><i class="chanbar-fill"></i></span>';
|
||||
list.appendChild(r);
|
||||
}
|
||||
let t = 0;
|
||||
setInterval(() => { t += .3;
|
||||
[...list.children].forEach((row, i) => {
|
||||
const v = i === 0 ? Math.abs(Math.sin(t)) : i === 5 ? Math.abs(Math.cos(t*1.7))*.6 : Math.random()*.05;
|
||||
const f = row.querySelector('.chanbar-fill');
|
||||
f.style.width = (v*100).toFixed(0) + '%'; f.classList.toggle('hot', v > .35);
|
||||
});
|
||||
}, 120);
|
||||
</script>
|
||||
</body></html>
|
||||
Reference in New Issue
Block a user