Imported from alxlion/voxtral-live-translation (
AGENTS.md). Install upstream withnpx skills add alxlion/voxtral-live-translation. Copyright stays with the author.
Real-Time Audio Transcription & Translation
Rules
- Never run npm/node commands on the host. Always use Docker:
docker run --rm -v "$PWD":/app -w /app node:22-slim <command> - Never add
Co-Authored-By: Claudeto commit messages.
Project Overview
Astro SSR website that captures microphone audio, transcribes it in near-real-time using Mistral's Voxtral API, and translates it using DeepL's free API. Supports French-English bidirectional translation.
Tech Stack
- Framework: Astro with
@astrojs/nodeadapter (SSR, standalone mode) - Transcription: Mistral API (
voxtral-mini-latestmodel) via@mistralai/mistralai - Translation: DeepL Free API via
deepl-node - Frontend: Vanilla JS (no framework),
getUserMedia+MediaRecorder
Architecture
Microphone → 3s audio chunks → /api/transcribe (Mistral) → /api/translate (DeepL) → Display
- Audio is captured in 3-second chunks via
MediaRecorderwithtimeslice - Each chunk is sent as
FormDatato the transcription API endpoint - Transcribed text is then sent as JSON to the translation API endpoint
- Chunks process concurrently (not queued) with placeholder elements to preserve order
- Blobs smaller than ~1KB are skipped (silence/noise)
File Structure
src/
env.d.ts # TypeScript env var declarations
pages/
index.astro # UI + client-side audio/fetch logic
api/
transcribe.ts # POST: audio blob → Mistral → { text, language }
translate.ts # POST: { text, sourceLang, targetLang } → DeepL → { translatedText }
styles/
global.css # Dark theme, two-panel layout
Environment Variables
Required in .env:
MISTRAL_API_KEY— from https://console.mistral.aiDEEPL_API_KEY— from https://www.deepl.com/en/your-account/keys (Free plan)
Development
Always run npm/node commands inside a Docker container, not on the host. Use:
# Build
docker run --rm -v "$PWD":/app -w /app node:22-slim npm run build
# Dev server
docker run --rm -v "$PWD":/app -w /app -p 4003:4003 node:22-slim npm run dev
# Install dependencies
docker run --rm -v "$PWD":/app -w /app node:22-slim npm install
API Endpoints
POST /api/transcribe
- Input:
FormDatawithaudio(File) andlanguage(string:froren) - Output:
{ text: string, language: string }
POST /api/translate
- Input: JSON
{ text: string, sourceLang: string, targetLang: string } - Output:
{ translatedText: string, detectedSourceLang: string } - Note: DeepL requires
en-USoren-GBfor English target (noten); French target isfr
Key Decisions
- 3-second chunks: Balances latency vs transcription quality
complete()notstream(): For 3s audio, round-trip is ~1.5s; streaming adds complexity for minimal gain- HTTP fetch, no WebSocket: Fetch every 3s has negligible overhead vs WebSocket
- FormData for audio: Binary in JSON requires base64 (+33% size); FormData sends raw binary
- No frontend framework: DOM manipulation is trivial (append
<p>elements)