DICTADO

 Perfecto, vamos a crear una pequeña aplicación en Node.js con Express que permita:

✅ Funcionalidades:

  1. Transcripción en vivo por micrófono (dictado).

  2. Subida de archivo .wav para transcripción.


🧩 Estructura del proyecto

transcriptor/
├── model/                  # Modelo Vosk descargado aquí
├── uploads/               # Carpeta para audios subidos
├── public/
│   └── index.html         # Interfaz web
├── app.js                 # Servidor Express
├── transcribe_file.js     # Lógica para transcribir archivos
├── dictado.js             # Transcripción en vivo (mic)
├── package.json

🧰 Paso 1: Instalar dependencias

npm init -y
npm install express multer vosk mic wav

🖥️ Paso 2: app.js (servidor Express)

const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs');
const { transcribeFile } = require('./transcribe_file');

const app = express();
const PORT = 3000;

const upload = multer({ dest: 'uploads/' });

app.use(express.static('public'));

app.post('/upload', upload.single('audiofile'), async (req, res) => {
    const filePath = req.file.path;

    try {
        const texto = await transcribeFile(filePath);
        fs.unlinkSync(filePath); // Opcional: eliminar el archivo subido
        res.json({ resultado: texto });
    } catch (err) {
        console.error(err);
        res.status(500).send("Error al transcribir");
    }
});

app.listen(PORT, () => {
    console.log(`Servidor en http://localhost:${PORT}`);
});

📄 Paso 3: transcribe_file.js

const fs = require('fs');
const wav = require('wav');
const vosk = require('vosk');

const MODEL_PATH = './model';
const SAMPLE_RATE = 16000;

vosk.setLogLevel(0);

const model = new vosk.Model(MODEL_PATH);

function transcribeFile(audioPath) {
    return new Promise((resolve, reject) => {
        const wfReader = new wav.Reader();
        const recognizer = new vosk.Recognizer({ model: model, sampleRate: SAMPLE_RATE });

        wfReader.on('format', (format) => {
            if (format.audioFormat !== 1 || format.sampleRate !== SAMPLE_RATE || format.channels !== 1) {
                return reject("Formato de audio no válido (debe ser WAV PCM 16kHz mono)");
            }

            wfReader.on('data', (data) => recognizer.acceptWaveform(data));

            wfReader.on('end', () => {
                const final = recognizer.finalResult();
                recognizer.free();
                resolve(final.text);
            });
        });

        fs.createReadStream(audioPath).pipe(wfReader);
    });
}

module.exports = { transcribeFile };

🎤 Paso 4: dictado.js (opcional para correr por consola)

const vosk = require('vosk');
const mic = require('mic');
const fs = require('fs');

const MODEL_PATH = './model';
const SAMPLE_RATE = 16000;

if (!fs.existsSync(MODEL_PATH)) {
    console.error("Modelo no encontrado:", MODEL_PATH);
    process.exit(1);
}

const model = new vosk.Model(MODEL_PATH);
const recognizer = new vosk.Recognizer({ model: model, sampleRate: SAMPLE_RATE });

const microphone = mic({
    rate: String(SAMPLE_RATE),
    channels: '1',
    debug: false,
    exitOnSilence: 6
});

const micInputStream = microphone.getAudioStream();

micInputStream.on('data', (data) => {
    if (recognizer.acceptWaveform(data)) {
        console.log("➡", recognizer.result().text);
    } else {
        process.stdout.write(`\r🔄 ${recognizer.partialResult().partial}`);
    }
});

micInputStream.on('silence', () => {
    console.log("\n🎤 Silencio detectado");
});

console.log("🎙️ Dictado en vivo iniciado. Habla...");
microphone.start();

🌐 Paso 5: public/index.html

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <title>Transcriptor Vosk</title>
</head>
<body>
  <h1>Sube un archivo de audio (.wav 16kHz mono)</h1>
  <form id="formulario" enctype="multipart/form-data">
    <input type="file" name="audiofile" accept=".wav" required>
    <button type="submit">Transcribir</button>
  </form>

  <h2>Resultado</h2>
  <pre id="resultado"></pre>

  <script>
    document.getElementById("formulario").addEventListener("submit", async (e) => {
      e.preventDefault();
      const formData = new FormData(e.target);
      const response = await fetch('/upload', {
        method: 'POST',
        body: formData
      });

      const data = await response.json();
      document.getElementById("resultado").innerText = data.resultado || "No se reconoció nada.";
    });
  </script>
</body>
</html>

✅ Para ejecutar todo:

  1. Ejecuta el servidor:

    node app.js
    
  2. Abre en el navegador:
    👉 http://localhost:3000

  3. Usa dictado.js para modo consola (dictado en vivo):

    node dictado.js
    

¿Quieres que te ayude a agregar conversión automática de MP3 a WAV al subir archivos, o usar Dropzone.js para mejorar la interfaz?


 Nueva vista web para dictado por voz en tiempo real (dictado.html)

Guarda este archivo en public/dictado.html:

html
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <title>Dictado por micrófono</title> <style> body { font-family: Arial; padding: 20px; } #texto { white-space: pre-wrap; border: 1px solid #ccc; padding: 10px; min-height: 100px; } button { padding: 10px 20px; margin-top: 10px; } </style> </head> <body> <h1>Dictado en vivo desde el navegador</h1> <button onclick="iniciarDictado()">🎙️ Iniciar Dictado</button> <button onclick="detenerDictado()">🛑 Detener</button> <h2>Texto dictado:</h2> <div id="texto"></div> <script> let reconocimiento; let texto = ""; function iniciarDictado() { const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; if (!SpeechRecognition) { alert("Tu navegador no soporta la Web Speech API."); return; } reconocimiento = new SpeechRecognition(); reconocimiento.lang = "es-ES"; reconocimiento.continuous = true; reconocimiento.interimResults = true; reconocimiento.onresult = (event) => { let parcial = ''; for (let i = event.resultIndex; i < event.results.length; ++i) { const transcripcion = event.results[i][0].transcript; if (event.results[i].isFinal) { texto += transcripcion + '\n'; } else { parcial += transcripcion; } } document.getElementById("texto").innerText = texto + parcial; }; reconocimiento.onerror = (e) => { console.error("Error:", e.error); }; reconocimiento.start(); } function detenerDictado() { if (reconocimiento) { reconocimiento.stop(); } } </script> </body> </html>

🚀 Agrega esta ruta al menú o accede directamente

Una vez que corras node app.js, puedes abrir el navegador:

👉 http://localhost:3000/dictado.html


🆚 Comparación: Web Speech API vs Vosk

CaracterísticaWeb Speech API (navegador)Vosk (Node.js)
Acceso desde navegador❌ Solo desde consola/backend
Funciona offline
PrecisiónMuy buena (requiere Internet)Muy buena (offline)
Idioma configurable
Procesa archivos

¿Quieres una opción para enviar el texto dictado al backend y guardarlo, por ejemplo, como .txt o para almacenarlo con una carpeta de expediente? Te puedo ayudar con eso también.


¡Buena observación! ✅
En este caso no necesitas actualizar app.js, porque ya agregaste esta línea en el servidor:

app.use(express.static('public'));

Eso significa que cualquier archivo que esté en la carpeta public/ será accesible directamente desde el navegador. Así que:

📁 Si tienes este archivo:

public/dictado.html

Entonces podrás abrirlo simplemente desde:

👉 http://localhost:3000/dictado.html


🧪 ¿Cómo verificar?

  1. Asegúrate de que el archivo dictado.html está dentro del directorio public/.

  2. Levanta el servidor:

    node app.js
    
  3. Abre en tu navegador:
    http://localhost:3000/dictado.html


📝 Si quieres agregar un pequeño menú de navegación (opcional)

Puedes modificar index.html o crear un menu.html:

<h2>Opciones</h2>
<ul>
  <li><a href="dictado.html">🎙️ Dictado en vivo</a></li>
  <li><a href="index.html">📂 Subir archivo .wav</a></li>
</ul>

¿Te gustaría que también el texto dictado desde la web se guarde automáticamente como archivo .txt en el servidor?

Comentarios

Entradas más populares de este blog

9-Nuestra Primera Plantilla con EJS

6-Middleware?

Cómo Iniciar un Proyecto Node.js