SignLink is a real-time sign language video call platform that translates American Sign Language (ASL) gestures into live text and grammatically refined sentences. The system combines browser-based hand tracking with a temporal LSTM gesture recognition model, real-time WebRTC communication, and AI-powered grammar correction.
The application is built as a full-stack system consisting of a FastAPI inference backend, a Node.js + Socket.IO signaling server, and a browser frontend using MediaPipe Hands. The entire application is containerized with Docker and deployed on Microsoft Azure Container Apps.
- Realtime ASL recognition from live camera input
- WebRTC video calling with remote subtitle relay
- Sentence builder for instant detected word display
- Grammar correction via LLM-assisted sentence refinement
- Training pipeline for gesture sequence dataset creation and model training
- Real-time WebRTC video communication with Socket.IO signaling
- Browser-based hand tracking using MediaPipe Hands
- Temporal LSTM gesture recognition using rolling 20-frame landmark sequences
- FastAPI inference backend built with PyTorch
- Server-side confidence filtering (
CONFIDENCE_THRESHOLD) so low-confidence frames never reach the frontend - Client-side prediction smoothing — a rolling 5-frame majority vote stabilizes signs before they're added to a sentence
- Groq-powered grammar correction for detected sign sequences
- Session-isolated prediction buffers supporting multiple simultaneous conversations
- Single shared
ML_BACKEND_PORTsetting so the local backend port only has to be changed in one place - Dockerized frontend and backend
- Cloud deployment on Microsoft Azure Container Apps
- Azure Container Registry (ACR) for container image management
Camera
│
▼
MediaPipe Hands
│
▼
Feature Extraction (136 features/frame)
│
▼
FastAPI Backend
│
Rolling 20-frame Buffer (per session_id)
│
▼
LSTM Model (PyTorch)
│
▼
Confidence Filter (server-side)
│
▼
Predicted Sign
│
├────────► Live subtitles
│
▼
Majority-Vote Smoothing (client-side, 5-frame history)
│
▼
Sentence Builder
│
▼
Groq Grammar Correction
│
▼
Final Sentence
backend/api.py— main FastAPI backend serving/predict,/reset-buffer,/health, and/fix-grammar- loads
lstm_model.ptand performs sequence-based ASL inference, with per-session rolling buffers and server-side confidence filtering
frontend/server.js— Express + Socket.IO hub for video call signaling; also serves/config.jsso the browser can read shared.envvalues likeML_BACKEND_PORTpages/—lobby.html,setup.html,call.html, andcall-ended.htmluser interfacesjs/— client logic for camera processing, API requests, prediction smoothing, and subtitle displaycss/— styling for lobby, setup, call, and call-ended screens
training/- model training and dataset scripts
guide/— documentation for data collection, dataset generation, training, and testing
requirements.txt— Python runtime dependencies for the backendtraining/requirements-training.txt— training-specific dependencies
For guidance on each part of the repo, see training/guide/, backend/README.md, and frontend/README.md.
- Frontend lobby (
/) creates a room and the user picks a mode (signer/speaker). - Setup page (
/setup) confirms camera/mic access before joining. - Local camera frames are processed in the browser with MediaPipe Hands on the call page (
/video?room=ROOM_ID). - Landmark feature vectors (136 per frame) are sent to the backend
/predictendpoint, tagged with the room'ssession_idso concurrent calls never share a buffer. - Backend LSTM consumes a sliding 20-frame window of landmark frames and returns a sign prediction, filtered against
CONFIDENCE_THRESHOLDso low-confidence guesses never reach the client. - The frontend runs its own 5-frame majority-vote smoothing on top of that, displays the stabilized word instantly in the sentence builder, and relays it over Socket.IO.
- Pressing full stop (
.) sends the collected sign sentence to the/fix-grammarendpoint for LLM-based correction. - Ending the call (
/call-ended) shows the session duration and transcript, pulled fromsessionStorage.
- Python 3.9 or newer
- Node.js 16+ and npm
- A Groq API key for LLM grammar correction
Both the backend and frontend read from a shared .env file so the local backend port only needs to be set once. Create .env (at the project root, or duplicated into backend/.env and frontend/.env depending on your setup) with:
GROQ_API_KEY=your_api_key_here
ML_BACKEND_PORT=8000
api.py binds to ML_BACKEND_PORT on startup, and server.js reads the same value and exposes it to the browser via /config.js, so frontend/js/script.js always knows the correct local backend URL without hardcoding it. If you change the port, this is the only line you need to edit.
cd backend
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txtThis includes python-dotenv, used to load GROQ_API_KEY and ML_BACKEND_PORT from .env.
If you need training dependencies as well:
cd training
python3 -m venv venv_training
source venv_training/bin/activate
pip install -r requirements-training.txtcd frontend
npm installThis includes the Node dotenv package, used by server.js to read the same .env file as the backend.
# Local development (auto-restarts on code changes)
uvicorn api:app --reload --host 0.0.0.0 --port $ML_BACKEND_PORT
# Or, if api.py reads ML_BACKEND_PORT itself:
python api.pyYou shouldn't need to touch frontend/js/script.js directly to change the port — update ML_BACKEND_PORT in .env instead, and both the backend and the frontend's /config.js injection will pick it up.
In production, the frontend automatically detects the environment (via hostname) and communicates with the deployed Azure backend instead of the local one.
cd frontend
npm startThen open http://localhost:3000 in your browser.
Both frontend and backend are fully containerized.
Build and start the application locally:
docker compose up --buildThe application will be available at:
- Frontend:
http://localhost:3000 - Backend:
http://localhost:8000(or your configuredML_BACKEND_PORT)
The same Docker images are deployed to Microsoft Azure Container Apps through Azure Container Registry.
The production deployment uses:
- Microsoft Azure Container Apps
- Azure Container Registry (ACR)
- Docker
- FastAPI
- Node.js
- Azure Container App Secrets for secure
GROQ_API_KEYmanagement
Both frontend and backend are deployed independently, allowing each service to be updated without affecting the other.
Azure Container App
│
├── universal-link-frontend
│ │
│ ├── HTML
│ ├── CSS
│ ├── JS
│ ├── Socket.IO
│ └── WebRTC
│
└── universal-link-backend
│
├── FastAPI
├── PyTorch
├── LSTM
├── Groq
└── Prediction API
- Run the backend API first
- Run the frontend server second
- Open the lobby page and join a room
- Test live signing with the local sentence builder visible
- Use the training guides in
training/guide/if you want to extend the model or collect new data
- Dockerized both the FastAPI backend and Node.js frontend.
- Deployed the application on Microsoft Azure Container Apps.
- Added automatic switching between local and production backend URLs.
- Configured the Groq API key securely using Azure Container App secrets.
- Consolidated local backend port configuration into a single shared
ML_BACKEND_PORTenv var, read by bothapi.pyandserver.js(and relayed to the browser via/config.js), instead of a hardcoded port inscript.js.
- Improved temporal buffer handling to prevent unnecessary resets caused by brief hand tracking failures.
- Added a per-session
GESTURE_TIMEOUTso the backend buffer auto-clears after roughly a second of inactivity, starting a fresh gesture window. - Added client-side majority-vote smoothing (5-frame rolling history) on top of server-side filtering, so a sign only registers once it's been consistently predicted.
- Added backend buffer status (
buffering,buffer_size) to the frontend for improved prediction handling and debugging. - Fixed runtime issues affecting subtitle updates and sentence generation.
- Improve prediction accuracy with a larger ASL training dataset.
- Further tune temporal smoothing thresholds for more stable real-time predictions.
- Add TURN server support for improved WebRTC connectivity beyond the current public relay.
- Extend the supported ASL vocabulary and sentence construction.
- Optimize inference speed and reduce container image size.
- Improve the mobile experience and overall UI.
frontend/server.jsis the signaling server for WebRTC and socket communication, and also serves/config.jsso the browser can read shared.envvalues.backend/api.pyis the inference server for ASL prediction and grammar correction.training/guide/contains step-by-step instructions for data collection, dataset generation, LSTM training, and testing.- See
backend/README.mdandfrontend/README.mdfor endpoint-level and pipeline-level detail not covered here.