Transcripts: errors say which step failed and why
build-container / build (push) Successful in 12m23s

This commit is contained in:
nmemmert committed 2026-10-23 11:17:49 -04:00
1 parent 0534bf7c4b
commit 40a74e6cbe
1 file changed
+6 -2
+6 -2
View File
@@ -11,6 +11,8 @@ const podcast = require('./podcast');
const cfg = { api: '', model: '', dir: '', port: 8080 };
const MAX_AUDIO = 1.5 * 1024 ** 3, MAX_TEXT = 6 * 1024 * 1024;
function init({ dataDir, apiUrl, model, port }) { cfg.api = (apiUrl || '').replace(/\/$/, ''); cfg.model = model || 'Systran/faster-whisper-small'; cfg.dir = path.join(dataDir, 'transcripts'); cfg.port = port || 8080; fs.mkdirSync(cfg.dir, { recursive: true, mode: 0o700 }); }
/** "fetch failed" says nothing: name the step and the reason (connection refused, timed out...). */
const why = e => { const c = e && e.cause; return (c && (c.code || c.message)) || (e && e.message) || 'unknown error'; };
const fail = (status, message) => Object.assign(new Error(message), { status });
const json = (res, code, o) => { res.writeHead(code, { 'content-type': 'application/json', 'cache-control': 'no-store' }); res.end(JSON.stringify(o)); };
@@ -71,14 +73,16 @@ async function whisper(file, name) {
const form = new FormData();
form.append('file', await fs.openAsBlob(file), name || 'audio');
form.append('model', cfg.model); form.append('response_format', 'verbose_json'); form.append('timestamp_granularities[]', 'segment');
const r = await fetch(cfg.api + '/v1/audio/transcriptions', { method: 'POST', body: form, signal: AbortSignal.timeout(6 * 3600e3) });
let r; try { r = await fetch(cfg.api + '/v1/audio/transcriptions', { method: 'POST', body: form, signal: AbortSignal.timeout(6 * 3600e3) }); }
catch (e) { throw new Error(`Could not reach the transcription service at ${cfg.api} (${why(e)}). Is the whisper container running? Check its log.`); }
if (!r.ok) throw new Error('The transcription service said ' + r.status + ': ' + (await r.text()).slice(0, 200));
const j = await r.json();
return shape((j.segments || []).map(s => ({ t: Math.round(+s.start * 1000), text: clean(s.text) })).filter(x => x.text), 'Transcribed on your server');
}
/** Bring the audio over from this hub (as the person who asked, with their sign-in) into a temp file. */
async function fetchAudio(src, cookie, tmp) {
const r = await fetch('http://127.0.0.1:' + cfg.port + src, { headers: { cookie: cookie || '' }, redirect: 'follow', signal: AbortSignal.timeout(2 * 3600e3) });
let r; try { r = await fetch('http://127.0.0.1:' + cfg.port + src, { headers: { cookie: cookie || '' }, redirect: 'follow', signal: AbortSignal.timeout(2 * 3600e3) }); }
catch (e) { throw new Error(`Could not read the audio from this server (${why(e)})`); }
if (!r.ok || !r.body) throw new Error('Could not read the audio (' + r.status + ')');
if ((+r.headers.get('content-length') || 0) > MAX_AUDIO) throw new Error('That audio file is too large to transcribe');
let n = 0; const body = Readable.fromWeb(r.body); body.on('data', c => { n += c.length; if (n > MAX_AUDIO) body.destroy(new Error('That audio file is too large to transcribe')); });