audio-transcripter
Version:
Lightweight TypeScript library for transcribing audio files using Google Gemini 2.0 models. Supports local files, remote URLs, and Blobs.
206 lines (205 loc) • 8.98 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.runTranscription = runTranscription;
exports.runTranscriptionWithBlob = runTranscriptionWithBlob;
const fs = __importStar(require("node:fs/promises"));
const node_path_1 = __importDefault(require("node:path"));
const chalk_1 = __importDefault(require("chalk"));
const transcriber_1 = require("./transcriber");
const checkUrlExists_1 = require("./utils/checkUrlExists");
/**
* Transcribe audio from a local file path or a remote URL.
*
* @param {TranscriptionConfig} config - Configuration options for transcription.
* @param {string} config.audioFile - Path to a local audio file or URL of a remote audio file.
* @param {string} [config.style='conversational'] - Transcription style, e.g., 'conversational' or 'formal'.
* @param {string} [config.language='english'] - Language code or name of the audio language.
* @param {boolean} [config.verbose=true] - Enable verbose logging of processing steps and errors.
* @param {number} [config.timeout=5000] - Timeout in milliseconds for checking remote URL availability.
*
* @returns {Promise<RunTranscriptionResult>} A promise that resolves to a structured transcription result
* including success status, transcription text (if successful), or error message.
*
* @throws Will not throw errors but return structured error results on failures such as:
* - Invalid or missing audio file path/URL
* - Local file not found or inaccessible
* - Remote URL unreachable or timing out
* - Unexpected errors during transcription process
*
* @example
* const result = await runTranscription({ audioFile: "./audio.wav" });
* if (result.success) {
* console.log("Transcription:", result.transcription);
* } else {
* console.error("Error:", result.error);
* }
*/
async function runTranscription(config) {
const { audioFile, style = "conversational", language = "english", verbose = true, timeout = 5000, } = config;
// Validate audioFile early
if (typeof audioFile !== "string" || audioFile.trim() === "") {
return {
success: false,
error: "Invalid audioFile parameter: must be a non-empty string",
};
}
try {
const isRemote = /^https?:\/\//i.test(audioFile);
let filePath = audioFile;
if (!isRemote) {
const resolvedPath = node_path_1.default.resolve(audioFile);
await fs.access(resolvedPath);
if (verbose) {
console.log(chalk_1.default.blueBright(`[info] Processing audio: ${resolvedPath}`));
}
filePath = resolvedPath;
}
else {
if (verbose) {
console.log(chalk_1.default.blueBright(`[info] Fetching remote audio: ${audioFile}`));
}
const checkResult = await (0, checkUrlExists_1.checkUrlExists)(audioFile, {
timeout,
});
if (!checkResult.exists) {
const statusText = checkResult.status !== undefined ? checkResult.status : "unknown";
const errorMsg = `[error] Remote URL not reachable (status: ${statusText}): ${audioFile}`;
console.error(chalk_1.default.red(errorMsg));
return { success: false, error: errorMsg };
}
}
if (verbose) {
console.time("TranscriptionTime");
}
const transcription = await (0, transcriber_1.transcribeAudio)(filePath, {
style,
language,
sourceType: isRemote ? "remote" : "local",
});
if (verbose) {
console.timeEnd("TranscriptionTime");
}
if (transcription) {
if (verbose) {
console.log(chalk_1.default.greenBright("\n--- Transcription ---\n"));
console.log(transcription);
console.log(chalk_1.default.greenBright("\n--- Done ---\n"));
}
return { success: true, transcription };
}
else {
const warningMsg = "[warn] No transcription result returned.";
if (verbose) {
console.log(chalk_1.default.yellow(warningMsg));
}
return { success: false, error: "No transcription result returned." };
}
}
catch (err) {
if (typeof err === "object" &&
err !== null &&
"code" in err &&
err.code === "ENOENT") {
const errorMsg = `[error] File not found: ${audioFile}`;
console.error(chalk_1.default.red(errorMsg));
return { success: false, error: errorMsg };
}
else {
const errorMessage = err instanceof Error ? err.message : String(err ?? "Unknown error");
console.error(chalk_1.default.red("[error] Unexpected error:"), errorMessage);
return { success: false, error: `Unexpected error: ${errorMessage}` };
}
}
}
/**
* Transcribe audio from a Blob object.
*
* @param {Blob} audioBlob - The audio Blob to transcribe.
* @param {Omit<TranscriptionConfig, "audioFile">} options - Transcription options excluding audioFile.
* @param {string} [options.style='conversational'] - Transcription style.
* @param {string} [options.language='english'] - Language of the audio.
* @param {boolean} [options.verbose=true] - Enable verbose logging.
*
* @returns {Promise<RunTranscriptionResult>} The transcription result with success status and error or transcription.
*/
async function runTranscriptionWithBlob(audioBlob, options) {
const { style = "conversational", language = "english", verbose = true, } = options ?? {};
if (!audioBlob || typeof audioBlob.arrayBuffer !== "function") {
const errorMsg = "Invalid audioBlob parameter: must be a valid Blob object.";
if (verbose)
console.error(chalk_1.default.red(`[error] ${errorMsg}`));
return { success: false, error: errorMsg };
}
try {
if (verbose) {
console.log(chalk_1.default.blueBright("[info] Processing audio Blob for transcription"));
console.time("TranscriptionTime");
}
const arrayBuffer = await audioBlob.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
const transcription = await (0, transcriber_1.transcribeAudio)(buffer, {
style,
language,
sourceType: "buffer",
});
if (verbose) {
console.timeEnd("TranscriptionTime");
}
if (transcription) {
if (verbose) {
console.log(chalk_1.default.greenBright("\n--- Transcription ---\n"));
console.log(transcription);
console.log(chalk_1.default.greenBright("\n--- Done ---\n"));
}
return { success: true, transcription };
}
else {
const warnMsg = "[warn] No transcription result returned.";
if (verbose)
console.log(chalk_1.default.yellow(warnMsg));
return { success: false, error: "No transcription result returned." };
}
}
catch (err) {
const errMsg = err instanceof Error ? err.message : String(err ?? "Unknown error");
if (verbose)
console.error(chalk_1.default.red(`[error] Unexpected error: ${errMsg}`));
return { success: false, error: `Unexpected error: ${errMsg}` };
}
}