diff --git a/packages/core/src/content/transcript/providers/transcription-start.ts b/packages/core/src/content/transcript/providers/transcription-start.ts index d9004228..6d34fb59 100644 --- a/packages/core/src/content/transcript/providers/transcription-start.ts +++ b/packages/core/src/content/transcript/providers/transcription-start.ts @@ -24,6 +24,7 @@ export type TranscriptionAvailability = { hasFal: boolean; hasAnyProvider: boolean; geminiModelId: string; + effectiveEnv: Env; }; export async function resolveTranscriptionAvailability({ @@ -58,7 +59,7 @@ export async function resolveTranscriptionAvailability({ ? isOnnxCliConfigured(preferredOnnxModel, effectiveEnv) : false; - const hasLocalWhisper = await isWhisperCppReady(); + const hasLocalWhisper = await isWhisperCppReady(effectiveEnv); const hasGroq = Boolean(effective.groqApiKey); const hasAssemblyAi = Boolean(effective.assemblyaiApiKey); const hasGemini = Boolean(effective.geminiApiKey); @@ -78,6 +79,7 @@ export async function resolveTranscriptionAvailability({ hasFal, hasAnyProvider, geminiModelId: effective.geminiModel ?? resolveGeminiTranscriptionModel(effectiveEnv), + effectiveEnv, }; } @@ -124,7 +126,7 @@ export async function resolveTranscriptionStartInfo({ ? `onnx/${availability.preferredOnnxModel}` : "onnx" : providerHint === "cpp" - ? ((await resolveWhisperCppModelNameForDisplay()) ?? "whisper.cpp") + ? ((await resolveWhisperCppModelNameForDisplay(availability.effectiveEnv)) ?? "whisper.cpp") : resolveCloudModelId(availability); return { availability, providerHint, modelId }; diff --git a/packages/core/src/transcription/whisper/core.ts b/packages/core/src/transcription/whisper/core.ts index 9bf7a985..e51bc143 100644 --- a/packages/core/src/transcription/whisper/core.ts +++ b/packages/core/src/transcription/whisper/core.ts @@ -92,6 +92,7 @@ export async function transcribeMediaWithWhisper({ filename, totalDurationSeconds, onProgress, + env, notes, }); if (local) return local; @@ -192,6 +193,7 @@ export async function transcribeMediaFileWithWhisper({ mediaType, totalDurationSeconds, onProgress, + env, notes, }); if (local) return local; @@ -470,6 +472,7 @@ async function transcribeWithLocalWhisperBytes({ filename, totalDurationSeconds, onProgress, + env, notes, }: { bytes: Uint8Array; @@ -477,9 +480,10 @@ async function transcribeWithLocalWhisperBytes({ filename: string | null; totalDurationSeconds: number | null; onProgress?: ((event: WhisperProgressEvent) => void) | null; + env: Env; notes: string[]; }): Promise { - const localReady = await isWhisperCppReady(); + const localReady = await isWhisperCppReady(env); if (!localReady) return null; const nameHint = filename?.trim() ? basename(filename.trim()) : "media"; const tempFile = join( @@ -493,6 +497,7 @@ async function transcribeWithLocalWhisperBytes({ mediaType, totalDurationSeconds, onProgress, + env, }); if (result.text) { if (result.notes.length > 0) notes.push(...result.notes); @@ -513,15 +518,17 @@ async function transcribeWithLocalWhisperFile({ mediaType, totalDurationSeconds, onProgress, + env, notes, }: { filePath: string; mediaType: string; totalDurationSeconds: number | null; onProgress?: ((event: WhisperProgressEvent) => void) | null; + env: Env; notes: string[]; }): Promise { - const localReady = await isWhisperCppReady(); + const localReady = await isWhisperCppReady(env); if (!localReady) return null; onProgress?.({ partIndex: null, @@ -534,6 +541,7 @@ async function transcribeWithLocalWhisperFile({ mediaType, totalDurationSeconds, onProgress, + env, }); if (result.text) { if (result.notes.length > 0) notes.push(...result.notes); @@ -551,6 +559,7 @@ async function safeTranscribeWithWhisperCppFile(args: { mediaType: string; totalDurationSeconds: number | null; onProgress?: ((event: WhisperProgressEvent) => void) | null; + env: Env; }): Promise { try { return await transcribeWithWhisperCppFile(args); diff --git a/packages/core/src/transcription/whisper/whisper-cpp.ts b/packages/core/src/transcription/whisper/whisper-cpp.ts index e92c356a..93ce2322 100644 --- a/packages/core/src/transcription/whisper/whisper-cpp.ts +++ b/packages/core/src/transcription/whisper/whisper-cpp.ts @@ -16,15 +16,17 @@ import { import type { WhisperProgressEvent, WhisperTranscriptionResult } from "./types.js"; import { wrapError } from "./utils.js"; -export async function isWhisperCppReady(): Promise { - if (!isWhisperCppEnabled()) return false; - if (!(await isWhisperCliAvailable())) return false; - const model = await resolveWhisperCppModelPath(); +export async function isWhisperCppReady(env?: Record): Promise { + if (!isWhisperCppEnabled(env)) return false; + if (!(await isWhisperCliAvailable(env))) return false; + const model = await resolveWhisperCppModelPath(env); return Boolean(model); } -export async function resolveWhisperCppModelNameForDisplay(): Promise { - const modelPath = await resolveWhisperCppModelPath(); +export async function resolveWhisperCppModelNameForDisplay( + env?: Record, +): Promise { + const modelPath = await resolveWhisperCppModelPath(env); return modelPath ? resolveWhisperCppModelLabelFromPath(modelPath) : null; } @@ -33,14 +35,16 @@ export async function transcribeWithWhisperCppFile({ mediaType, totalDurationSeconds, onProgress, + env, }: { filePath: string; mediaType: string; totalDurationSeconds: number | null; onProgress?: ((event: WhisperProgressEvent) => void) | null; + env?: Record; }): Promise { const notes: string[] = []; - const modelPath = await resolveWhisperCppModelPath(); + const modelPath = await resolveWhisperCppModelPath(env); if (!modelPath) { return { text: null, @@ -116,7 +120,7 @@ export async function transcribeWithWhisperCppFile({ try { await new Promise((resolve, reject) => { - const { proc, handle } = spawnTracked(resolveWhisperCppBinary(), args, { + const { proc, handle } = spawnTracked(resolveWhisperCppBinary(env), args, { stdio: ["ignore", "ignore", "pipe"], label: "whisper.cpp", kind: "whisper.cpp", @@ -189,12 +193,13 @@ export async function transcribeWithWhisperCppFile({ } } -function isWhisperCppEnabled(): boolean { - return (process.env[DISABLE_LOCAL_WHISPER_CPP_ENV] ?? "").trim() !== "1"; +function isWhisperCppEnabled(env?: Record): boolean { + const source = env ?? process.env; + return (source[DISABLE_LOCAL_WHISPER_CPP_ENV] ?? "").trim() !== "1"; } -async function isWhisperCliAvailable(): Promise { - const bin = resolveWhisperCppBinary(); +async function isWhisperCliAvailable(env?: Record): Promise { + const bin = resolveWhisperCppBinary(env); return new Promise((resolve) => { const { proc } = spawnTracked(bin, ["--help"], { stdio: ["ignore", "ignore", "ignore"], @@ -207,13 +212,17 @@ async function isWhisperCliAvailable(): Promise { }); } -function resolveWhisperCppBinary(): string { - const override = (process.env[WHISPER_CPP_BINARY_ENV] ?? "").trim(); +function resolveWhisperCppBinary(env?: Record): string { + const source = env ?? process.env; + const override = (source[WHISPER_CPP_BINARY_ENV] ?? "").trim(); return override.length > 0 ? override : "whisper-cli"; } -async function resolveWhisperCppModelPath(): Promise { - const override = (process.env[WHISPER_CPP_MODEL_PATH_ENV] ?? "").trim(); +async function resolveWhisperCppModelPath( + env?: Record, +): Promise { + const source = env ?? process.env; + const override = (source[WHISPER_CPP_MODEL_PATH_ENV] ?? "").trim(); if (override) { try { const stat = await fs.stat(override); @@ -223,7 +232,7 @@ async function resolveWhisperCppModelPath(): Promise { } } - const home = (process.env.HOME ?? process.env.USERPROFILE ?? "").trim(); + const home = (source.HOME ?? source.USERPROFILE ?? "").trim(); const cacheCandidate = home ? join(home, ".summarize", "cache", "whisper-cpp", "models", "ggml-base.bin") : null;