import fs from "node:fs";
import path from "node:path";
import os from "node:os";
import { z } from "zod";
import { tool } from "@anthropic-ai/claude-agent-sdk";
import { logger } from "../logger.js";
import { execFileWithTimeout } from "../utils/exec.js";
const WHISPER_MODEL = path.join(os.homedir(), ".local/share/whisper-cpp/ggml-large-v3-turbo.bin");
const WHISPER_MODEL_URL = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-turbo.bin?download=true";
function ok(text) {
    return { content: [{ type: "text", text }] };
}
function err(text) {
    return { content: [{ type: "text", text }], isError: true };
}
/**
 * Ensure the whisper model exists, downloading from HuggingFace if missing.
 */
async function ensureWhisperModel() {
    if (fs.existsSync(WHISPER_MODEL))
        return;
    logger.info("[transcribe_audio] Whisper model not found, downloading...");
    const dir = path.dirname(WHISPER_MODEL);
    fs.mkdirSync(dir, { recursive: true });
    await execFileWithTimeout("curl", ["-sL", "-o", WHISPER_MODEL, WHISPER_MODEL_URL], {
        timeout: 300_000,
    });
    if (!fs.existsSync(WHISPER_MODEL)) {
        throw new Error("Failed to download whisper model");
    }
    logger.info("[transcribe_audio] Whisper model downloaded successfully.");
}
/**
 * Download a file from a URL to a local path using curl.
 */
async function downloadFile(url, dest) {
    await execFileWithTimeout("curl", ["-sL", "-o", dest, url], { timeout: 60_000 });
}
/**
 * Convert any audio file to 16kHz mono WAV using ffmpeg.
 */
async function convertToWav(input, output) {
    await execFileWithTimeout("ffmpeg", ["-y", "-i", input, "-ar", "16000", "-ac", "1", output], { timeout: 60_000 });
}
/**
 * Transcribe a WAV file using whisper-cli.
 */
async function transcribe(wavPath) {
    const { stdout } = await execFileWithTimeout("whisper-cli", ["-m", WHISPER_MODEL, "-f", wavPath, "--no-timestamps", "-l", "auto"], { timeout: 120_000 });
    return stdout.trim();
}
/**
 * Transcribe an audio file (URL or local path) to text.
 * Used by the MCP tool and the Telegram channel for pre-transcription.
 */
export async function transcribeAudioFile(input) {
    const tmpDir = os.tmpdir();
    const id = `transcribe_${Date.now()}`;
    const rawPath = path.join(tmpDir, `${id}_raw`);
    const wavPath = path.join(tmpDir, `${id}.wav`);
    try {
        const isUrl = input.startsWith("http://") || input.startsWith("https://");
        let localPath;
        if (isUrl) {
            logger.info(`[transcribe_audio] Downloading: ${input}`);
            await downloadFile(input, rawPath);
            localPath = rawPath;
        }
        else {
            if (!fs.existsSync(input)) {
                throw new Error(`File not found: ${input}`);
            }
            localPath = input;
        }
        logger.info(`[transcribe_audio] Converting to WAV...`);
        await convertToWav(localPath, wavPath);
        await ensureWhisperModel();
        logger.info(`[transcribe_audio] Transcribing...`);
        const text = await transcribe(wavPath);
        return text || "[No speech detected]";
    }
    finally {
        for (const f of [rawPath, wavPath]) {
            try {
                fs.unlinkSync(f);
            }
            catch {
                // ignore
            }
        }
    }
}
export const transcribeAudioTool = tool("transcribe_audio", "Transcribe an audio file (URL or local path) to text. Supports OGG, MP3, WAV, M4A, and other common formats. Uses whisper.cpp with auto language detection (Chinese, English, etc.).", {
    input: z
        .string()
        .describe("Audio source: a URL (e.g. https://...) or a local file path (e.g. /tmp/audio.ogg)"),
}, async (args) => {
    try {
        const text = await transcribeAudioFile(args.input);
        return ok(text);
    }
    catch (error) {
        const msg = error instanceof Error ? error.message : String(error);
        logger.warn(`[transcribe_audio] Error: ${msg}`);
        return err(`Transcription failed: ${msg}`);
    }
});
//# sourceMappingURL=transcribe-audio.js.map