โ† Back to list

๐Ÿง  Building a Speech-to-Text System with Vosk, Flask & React

Turn voice into text with a modern, containerized web app. This guide walks you through building and deploying a speech recognition systemโ€ฆ

Prabhat Ranjan Singh ยท 2025-06-29 12:36 ยท 0 claps ยท 2.5 min read
#vosk #flask-restful #reactjs #speech-to-text-conversion #nginx
Open on Medium โ†—
Wiki topics: ๐ŸŒ ยท Web Development โ˜๏ธ ยท DevOps & Cloud

๐Ÿง  Building a Speech-to-Text System with Vosk, Flask & React

Turn voice into text with a modern, containerized web app. This guide walks you through building and deploying a speech recognition system using open-source tools like Vosk, Flask, React, Docker, and NGINX.

๐Ÿš€ Project Overview

This project enables real-time speech-to-text transcription using Vosk models. It features:

  • ๐Ÿ—ฃ๏ธ Speech Recognition via Vosk
  • ๐ŸŽค Audio Uploads handled by Flask
  • ๐Ÿงฑ Frontend built with React (Vite.js)
  • ๐Ÿณ Dockerized deployment
  • ๐Ÿ” Secure Hosting with NGINX

๐Ÿงฐ Tech Stack

Component Technology Frontend React.js (Vite.js), Backend Flask (Python), Speech Recognition Vosk Models, Database (Optional)MongoDB / PostgreSQL, Containerization Docker & Docker Compose, Reverse Proxy NGINX, Deployment Ubuntu Server / AWS EC2

๐Ÿ“ Folder Structure

project-root/
โ”œโ”€โ”€ frontend/         # React frontend
โ”œโ”€โ”€ backend/          # Flask backend
โ”œโ”€โ”€ models/           # Vosk models
โ”œโ”€โ”€ uploads/          # Audio uploads
โ”œโ”€โ”€ docker-compose.yml
โ””โ”€โ”€ README.md

๐Ÿงช Backend Setup (Flask)

The backend uses Flask and Gunicorn, with Vosk models downloaded during container build.

FROM python:3.10
WORKDIR /app
RUN apt-get update && apt-get install -y ffmpeg wget unzip curl
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt gunicorn python-dotenv
RUN mkdir -p /app/models && \
    wget -O /app/models/vosk-model-en-us-0.22.zip https://alphacephei.com/vosk/models/vosk-model-en-us-0.22.zip && \
    unzip /app/models/vosk-model-en-us-0.22.zip -d /app/models && \
    rm /app/models/vosk-model-en-us-0.22.zip
COPY . .
ENV FLASK_ENV=production
ENV UPLOAD_FOLDER=/app/uploads
ENV VOSK_MODEL_PATH_EN=/app/models/vosk-model-en-us-0.22
EXPOSE 5000
HEALTHCHECK --interval=30s --timeout=5s --retries=3 CMD curl -f http://localhost:5000/healthz || exit 1
CMD ["gunicorn", "--workers", "4", "--bind", "0.0.0.0:5000", "app:app"]

๐ŸŽจ Frontend Setup (React + Vite)

FROM node:18
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install --frozen-lockfile
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "3000"]

๐ŸŒ NGINX Configuration

server {
  listen 80;
  server_name yourdomain.com ;
  location / {
    proxy_pass http://frontend:3000;
    proxy_set_header Host $host;
  }
  location /api/ {
    proxy_pass http://backend:5000;
    proxy_set_header Host $host;
  }
}

๐Ÿงฑ Docker Compose

version: '3.8'
services:
  frontend:
    build: ./frontend
    ports:
      - "3000:3000"
    volumes:
      - ./frontend:/app
    networks:
      - app-network
  backend:
    build: ./backend
    ports:
      - "5000:5000"
    volumes:
      - ./backend:/app
      - ./models:/app/models
      - ./uploads:/app/uploads
    networks:
      - app-network
  networks:
  app-network:
    driver: bridge

๐Ÿ Flask App Entry Point

from flask import Flask, request, jsonify
from vosk import Model, KaldiRecognizer
import wave
import os
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = '/app/uploads'
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024  # 100MB upload limit
@app.route('/api/speech-to-text', methods=['POST'])
def transcribe():
    audio_file = request.files['file']
    filepath = os.path.join(app.config['UPLOAD_FOLDER'], audio_file.filename)
    audio_file.save(filepath)
    wf = wave.open(filepath, "rb")
    model = Model("/app/models/vosk-model-en-us-0.22")
    rec = KaldiRecognizer(model, wf.getframerate())
    results = []
    while True:
        data = wf.readframes(4000)
        if len(data) == 0:
            break
        if rec.AcceptWaveform(data):
            results.append(rec.Result())
    return jsonify(results)
if __name__ == '__main__':
    app.run(host="0.0.0.0", port=5000)

โš™๏ธ Vite Config for WebSocket & Host Binding

import { defineConfig } from 'vite';
export default defineConfig({
  server: {
    host: '0.0.0.0',
    port: 3000,
    strictPort: true,
    allowedHosts: ['yourdomain.com'],
    hmr: {
      protocol: 'wss',
      host: 'yourdomain.com',
    }
  }
});

๐Ÿ› ๏ธ Troubleshooting Tips

โŒ Backend Not Accessible

docker logs backend
docker exec -it backend netstat -tulnp
docker restart backend

โŒ Frontend Not Loading

docker exec -it frontend netstat -tulnp
docker restart frontend

โŒ Firewall Blocking

sudo ufw allow 3000/tcp
sudo ufw allow 5000/tcp
sudo ufw reload

โŒ NGINX Not Forwarding

sudo journalctl -u nginx --no-pager | tail -50
sudo systemctl restart nginx
sudo systemctl reload nginx

โŒ File Upload Limit

# In nginx.conf
http {
  client_max_body_size 100M;
}
# In Flask app.py
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024

โœ… Final Checklist

Thank you.


๋ฉ”ํƒ€๋ฐ์ดํ„ฐ
post_id
d587d719dfca
slug
building-a-speech-to-text-system-with-vosk-flask-react-d587d719dfca
url
https://medium.com/@topi9864/building-a-speech-to-text-system-with-vosk-flask-react-d587d719dfca
canonical_url
https://medium.com/@topi9864/building-a-speech-to-text-system-with-vosk-flask-react-d587d719dfca
author_url
https://medium.com/@topi9864
status
ok
fetched_at
2026-06-10 15:53:41