Focus on speedup and not hanging on large audio files.

This commit is contained in:
Lucas Winther committed 2026-07-15 13:01:22 +02:00
1 parent cba27fc728
commit 0bd5d326a5
7 files changed
+366 -2

No files matched your search

+29 -1
View File
@@ -282,6 +282,19 @@ export function createSidecar(command?: readonly string[]): Sidecar {
/** Default cap ≈ 2¼ hours of raw float32 16 kHz mono (64 kB/s). */
const DEFAULT_MAX_UPLOAD_BYTES = 512 * 1024 * 1024;
/**
* Effective upload cap (env-overridable). Exported so src/index.ts can raise
* Bun.serve's `maxRequestBodySize` to match — its 128 MB default would
* otherwise reject uploads longer than ~35 minutes of audio before this
* module ever sees them.
*/
export const MAX_UPLOAD_BYTES =
Number(process.env.TRANSCRIBE_MAX_UPLOAD_BYTES) || DEFAULT_MAX_UPLOAD_BYTES;
/** Keep the ndjson stream visibly alive through quiet stretches (D-021). */
const HEARTBEAT_INTERVAL_MS = 5_000;
const HEARTBEAT = new TextEncoder().encode("\n");
const LANGUAGE_RE = /^[a-z]{2,3}$/;
export interface TranscribeHandlers {
@@ -410,6 +423,20 @@ export function createTranscribeHandlers(deps: TranscribeDeps): TranscribeHandle
async start(controller) {
const enqueue = (line: TranscribeStreamLine) =>
controller.enqueue(encoder.encode(`${JSON.stringify(line)}\n`));
// Segment gaps can exceed any proxy/server idle timeout (model
// load/download before the first segment; slow decode windows on
// big models — 30 s+ observed on a 15-min file). Heartbeat blank
// lines keep the connection visibly alive; ServerEngine's line
// reader skips empty lines. A dead client makes the enqueue throw,
// which is caught here (request.signal separately cancels the
// sidecar pass).
const heartbeat = setInterval(() => {
try {
controller.enqueue(HEARTBEAT);
} catch {
clearInterval(heartbeat);
}
}, HEARTBEAT_INTERVAL_MS);
const chunks: TranscriptChunk[] = [];
try {
await deps.sidecar.transcribe(
@@ -445,6 +472,7 @@ export function createTranscribeHandlers(deps: TranscribeDeps): TranscribeHandle
message: error instanceof Error ? error.message : String(error),
});
} finally {
clearInterval(heartbeat);
await Bun.file(audioPath).unlink().catch(() => {});
try {
controller.close();
@@ -475,5 +503,5 @@ export const sidecar = createSidecar();
export const transcribe: TranscribeHandlers = createTranscribeHandlers({
sidecar,
getSessionUser: appGetSessionUser,
maxUploadBytes: Number(process.env.TRANSCRIBE_MAX_UPLOAD_BYTES) || undefined,
maxUploadBytes: MAX_UPLOAD_BYTES,
});