Resumen

Construye con confianza un flujo de transcripción en Node.js: leer un .mp3 con el módulo fs, enviar el audio como Blob vía FormData a la API de OpenAI Whisper y guardar un TXT con la transcripción. Con un enfoque asíncrono, manejo de errores y rutas multiplataforma con path, obtendrás un script sólido y reutilizable.

¿Cómo preparar fs y path en Node.js para Whisper?

Para empezar, crea fs-openai.js y prepara los módulos nativos. Necesitarás tu API key de OpenAI para autenticar la solicitud y un archivo de audio .mp3 (por ejemplo, audio.mp3) para transcribir.

  • Usa fs para verificar existencia, leer y escribir archivos.
  • Usa path para rutas consistentes en macOS, Windows y GNU/Linux.
  • Trabaja con FormData para empaquetar el archivo y el modelo.
  • Convierte el buffer a Blob antes de adjuntarlo.
  • Envía la solicitud con fetch y método POST.
  • Incluye headers con Authorization: Bearer y tu API key.
  • Procesa la respuesta con response.json() y extrae data.text.
  • Guarda la transcripción con fs.writeFileSync en un TXT.

¿Qué requisitos y archivos necesitas para la API key y el audio .mp3?

  • Cuenta en OpenAI y tu API key activa.
  • Un archivo .mp3 accesible por ruta, por ejemplo: audio.mp3.
  • Un entorno con soporte para fetch, FormData y Blob.

¿Cuál es el flujo asíncrono de lectura, solicitud y guardado?

El núcleo es una función asíncrona con try/catch que valida el archivo, construye el FormData, llama a la API y persiste el resultado.

  • Valida existencia con fs.existsSync.
  • Lee el archivo binario con fs.readFileSync.
  • Crea FormData y un Blob con el buffer de audio.
  • Adjunta 'file' y 'model' (whisper-1) al FormData.
  • Llama a https://api.openai.com/v1/audio/transcriptions con POST.
  • Verifica response.ok y, si falla, lanza error con detalles.
  • Parsea la respuesta a JSON y toma data.text.
  • Genera el nombre de salida con path.join y guarda el TXT.
  • Muestra en consola la ruta del archivo guardado.
// fs-openai.js
const fs = require('fs');
const path = require('path');

async function transcriptAudio(audioFilePath, apiKey) {
  try {
    if (!fs.existsSync(audioFilePath)) {
      throw new Error('El archivo de audio no existe.');
    }

    const audioFile = fs.readFileSync(audioFilePath);

    const formData = new FormData();
    const blob = new Blob([audioFile]);
    formData.append('file', blob, path.basename(audioFilePath));
    formData.append('model', 'whisper-1');

    const response = await fetch('https://api.openai.com/v1/audio/transcriptions', {
      method: 'POST',
      headers: { Authorization: `Bearer ${apiKey}` },
      body: formData,
    });

    if (!response.ok) {
      const errorData = await response.json();
      throw new Error(`Error en la API: ${JSON.stringify(errorData)}`);
    }

    const data = await response.json();
    const transcription = data.text;

    const base = path.basename(audioFilePath, path.extname(audioFilePath));
    const outputFilePath = path.join(path.dirname(audioFilePath), `${base}.transcription.txt`);

    fs.writeFileSync(outputFilePath, transcription);
    console.log(`Transcripción guardada en: ${outputFilePath}`);

    return transcription;
  } catch (error) {
    console.error('Error durante la transcripción:', error.message);
    throw error;
  }
}

¿Cómo construir el output file path con path.join?

  • Toma el directorio con path.dirname(audioFilePath).
  • Extrae el nombre base con path.basename sin la extensión.
  • Obtén la extensión con path.extname para removerla del nombre.
  • Une directorio y nombre base con sufijo .transcription.txt usando path.join.

¿Cómo validar la respuesta y manejar errores de la API?

Controla las respuestas no exitosas y comunica el problema claramente. Esto evita falsos positivos y facilita depurar cuando el modelo o la clave no son válidos.

  • Verifica response.ok antes de leer el cuerpo.
  • Si falla, obtén detalles con response.json() en errorData.
  • Lanza un Error con JSON.stringify(errorData) para ver el motivo.
  • En catch, registra con console.error y el error.message.

¿Quieres que revisemos tu implementación o nombres de archivo y rutas? Cuéntame en un comentario qué parte te gustaría profundizar.