Transcend is a streamlined web application designed to provide near real-time subtitles for spoken audio. It uses the Groq Cloud API (Whisper) for speech-to-text and the DeepL API for high-fidelity translation, delivering a dual-language output to a React-based interface.
The application operates as a continuous loop between the client and the server to minimize processing overhead:
- Client-Side Capture: The browser runs an on-device VAD (
@ricky0123/vad-web) to slice the microphone stream into per-utterance audio segments. - Stream Transmission: Each utterance is shipped to the backend as a raw
ArrayBufferover a Socket.io WebSocket. - Transcription (Whisper via Groq): The Node.js server forwards the chunk to Groq.
- Sentence detection (client): The client accumulates transcripts and detects sentence boundaries (with abbreviation guards) or seals trailing fragments after a silence timeout.
- Translation (DeepL): Each completed sentence is sent back to the server as
finalize_segment, translated into the user-selected target language, and emitted back astranslation_result. - UI Update: The frontend renders transcript and translation side-by-side.
The server is idempotent on finalize_segment (per socket), so client retries return the cached translation rather than re-billing DeepL.
- Frontend: React 19 + Vite +
@ricky0123/vad-react - Backend: Node.js (≥ 18) + Express 5
- Real-time: Socket.io
- APIs: Groq (Whisper) and DeepL
transcend/
├── backend/
│ ├── server.js # WebSocket logic and API integration
│ ├── .env.example # API credential template
│ └── package.json
├── frontend/
│ ├── App.jsx # View router (home ↔ transcribe) + error boundary
│ ├── Home.jsx # Landing page
│ ├── Transcribe.jsx # Recording + transcript UI
│ ├── languages.js # Shared language list
│ ├── socket.js # Client-side WebSocket
│ ├── vite.config.js # Includes socket.io dev proxy
│ ├── .env.example
│ └── package.json
└── README.md
# 1. Backend
cd backend
cp .env.example .env # fill in GROQ_API_KEY and DEEPL_KEY
npm install
npm run dev # uses nodemon; or `npm start` for a one-shot run
# 2. Frontend (in a second terminal)
cd frontend
cp .env.example .env
npm install
npm run devOpen the printed Vite URL, click Start transcribing, and grant microphone access.
backend/.env
| Variable | Required | Default | Notes |
|---|---|---|---|
GROQ_API_KEY |
yes | — | Groq Cloud key — https://console.groq.com/keys |
DEEPL_KEY |
yes | — | DeepL API key — https://www.deepl.com/account/summary |
WHISPER_MODEL |
no | openai/whisper-large-v3-turbo |
Any Groq-hosted Whisper model. |
PORT |
no | 5000 |
|
ALLOWED_ORIGIN |
no | * (dev) / refuse (prod) |
Single origin, comma-separated list, or *. |
NODE_ENV |
no | development |
production fails fast on missing keys and tightens CORS defaults. |
frontend/.env
| Variable | Required | Default | Notes |
|---|---|---|---|
VITE_BACKEND_URL |
no | http://localhost:5000 |
Override to point at a remote backend. When unset, the Vite dev server proxies /socket.io for you. |
The backend optionally serves the built frontend from ../frontend/dist:
cd frontend && npm run build # produces frontend/dist/
cd ../backend && NODE_ENV=production \
GROQ_API_KEY=... DEEPL_KEY=... ALLOWED_ORIGIN=https://your-domain \
npm startIf you serve frontend and backend separately, the dist/ directory simply won't exist and the static-serving block is a no-op.