Inclusa AI is a real-time accessibility platform that converts live speech into synchronized transcription, AI sign-language gestures, and an AI avatar for physical, virtual, and hybrid presentation audiences.
This repository is the backend monorepo: NestJS services (TypeScript) for the API/sync/recording/notification layers, and FastAPI services (Python) for the Speech, AI, and Analytics ML pipelines.
- Architecture
- Pipelines
- Repository layout
- Services, ports & protocols
- Inter-service contracts
- Quick start
- Local development
- End-to-end demo path
- Environment variables
- Tooling
- Key technology decisions
- Roadmap
βββββββββββββββββββββββββββββββββββββββββββββββ
Presenter mic / audio β CLIENTS β
β β audience & presenter apps (PPTX.js/PDF.js β
β audio frames (WS) β render slides beside accessibility panels) β
βΌ βββββββββββββββββ²ββββββββββββββββββββββββββββββ
ββββββββββββββββββββ β Socket.IO (per-session rooms)
β asr-service β β
β (Speech Pipeline) β ββββββββββ΄ββββββββββ
β Google STT / Whisper β sync-service β β Redis-backed Socket.IO adapter
ββββββββββ¬ββββββββββ β (WS fan-out) β (horizontal scale)
β TranscriptChunk ββββββββββ²ββββββββββ
βΌ ββ publish ββββββββββββββββββ€ subscribe (wildcards)
ββββββββββββββββββββββββββββββββββββββββββββ NATS ββββββββββββββββββββββββββββββββββββββββ
β inclusa.pipeline.transcript.* inclusa.pipeline.gesture.* inclusa.pipeline.avatar.* β
β inclusa.pipeline.session.* inclusa.pipeline.engagement.* inclusa.notifications β
βββββ²ββββββββββββ²ββββββββββββ²ββββββββββββ²βββββββββββββββ²ββββββββββββββββββββββββ²ββββββββββββ
β β β β β β
ββββββββ΄ββββ βββββββ΄βββββ ββββββ΄ββββββ βββββ΄βββββββ βββββββ΄ββββββββββ ββββββββββ΄βββββββββββ
βnlp-serviceβ βtranslationβ β gesture β β avatar β β presenter- β β recording-service β
β (AI) β β (AI) β β (AI) β β (AI) β β insights β β (Recording Pipe.) β
β segment β β textβsign β βMediaPipe β βRPM+MP / β β (Audience β β persist timelines β
β β β β β Hands β βAudio2Faceβ β Analytics) β β β GCS β
βββββββββββββ βββββββββββββ ββββββββββββ ββββββββββββ βββββββββ¬ββββββββ βββββββββββββββββββββ
β EngagementSignal / nudges
βΌ
ββββββββββββββββββββββββ
REST (sessions, orgs, auth) ββββββββββββββββββββΊ β notification-service β β NATS queue consumer
ββββββββββββββββββββ β (Notification Pipe.) β (coaching, recording-ready,
β api-gateway β Auth0 JWT Β· TypeORM/Postgresβ email/push/webhook)β session lifecycle)
β Swagger @ /docs β ββββββββββββββββββββββββ
ββββββββββββββββββββ
Infra: Postgres (sessions/orgs) Β· Redis (Socket.IO adapter) Β· NATS w/ JetStream (pipeline + queue)
Data flow (one utterance): presenter audio β asr-service emits
TranscriptChunks β published to NATS β nlp/translation/gesture/avatar
services consume and emit GestureFrame/AvatarFrame β sync-service
subscribes to all pipeline subjects and fans out to the session's WebSocket room
β recording-service persists the synchronized timelines to GCS β
notification-service fires a "recording ready" alert. presenter-insights
runs asynchronously off the main path and emits EngagementSignals / coaching
nudges that surface through notification-service.
| Pipeline | Owned by | Responsibility |
|---|---|---|
| Speech | asr-service |
Streaming speech-to-text (Google STT primary, Whisper fallback). |
| AI | nlp-service, translation-service, gesture-service, avatar-service |
Segmentation β sign-language instruction data β hand gestures β avatar animation. |
| Audience Analytics | presenter-insights |
Engagement/pace analytics + coaching, async off the main pipeline. |
| Recording | recording-service |
Captures synced transcript/gesture/avatar timelines, writes to GCS. |
| Notification | notification-service |
Session/recording/coaching alerts, queue-driven over NATS. |
inclusa-ai/
βββ apps/
β βββ api-gateway/ # NestJS β auth, sessions, orgs, REST API, Swagger
β βββ sync-service/ # NestJS β WebSocket fan-out (Redis adapter, NATS subscriber)
β βββ recording-service/ # NestJS β Recording Pipeline β Cloud Storage (GCS)
β βββ notification-service/ # NestJS β Notification Pipeline (NATS queue consumer)
β βββ ml-services/ # Python (uv), NOT part of the npm workspace
β βββ asr-service/ # FastAPI β Speech Pipeline (Google STT / Whisper / mock)
β βββ nlp-service/ # FastAPI β AI: segmentation
β βββ translation-service/ # FastAPI β AI: text β sign instruction data
β βββ gesture-service/ # FastAPI β AI: MediaPipe Hands gestures
β βββ avatar-service/ # FastAPI β AI: RPM + MediaPipe (Audio2Face flag)
β βββ presenter-insights/ # FastAPI β Audience Analytics
β βββ shared/ # Shared pydantic schemas mirroring shared-types
βββ packages/
β βββ shared-types/ # TS pipeline contracts, WS events, DTOs (source of truth)
β βββ config/ # Shared eslint/prettier/tsconfig
βββ infra/
β βββ docker/ # Dockerfiles (nestjs.Dockerfile is parameterized by APP)
β βββ docker-compose.yml # Local dev: Postgres, Redis, NATS + all services
β βββ k8s/ # Placeholder manifests (not wired to local dev)
βββ .github/workflows/ci.yml # Lint/test/build affected apps + Python lint
βββ README.md
Note on
packages/proto: the original scaffold reserved this for gRPC.protofiles. We chose NATS over gRPC for inter-service transport (see decisions), so there is noprotopackage. The equivalent contract lives inpackages/shared-types(TS) andapps/ml-services/shared(Python).
| Service | Port | Protocol(s) | Talks to |
|---|---|---|---|
| api-gateway | 3000 | HTTP REST (+ Swagger /docs) |
Postgres, Auth0 |
| sync-service | 3001 | WebSocket (Socket.IO), subscribes NATS | Redis, NATS, clients |
| recording-service | 3002 | HTTP REST (POST /recordings), subscribes NATS |
NATS, GCS |
| notification-service | 3003 | HTTP REST (POST /notifications/test), NATS queue consumer |
NATS |
| asr-service | 8001 | HTTP + WebSocket (/transcribe/stream) |
(publishes NATS in full system) |
| nlp-service | 8002 | HTTP REST (POST /segment) |
β |
| translation-service | 8003 | HTTP REST (POST /translate) |
β |
| gesture-service | 8004 | HTTP REST (POST /gestures) |
β |
| avatar-service | 8005 | HTTP REST (POST /avatar/frames) |
β |
| presenter-insights | 8006 | HTTP REST (POST /insights) |
β |
| Postgres | 5432 | TCP | api-gateway |
| Redis | 6379 | TCP | sync-service (Socket.IO adapter) |
| NATS | 4222 / 8222 | NATS / monitoring | pipeline + notifications |
The canonical event contract is defined once in
packages/shared-types and mirrored field-for-field
in apps/ml-services/shared (Python). Core types:
TranscriptChunkβ Speech Pipeline output (interim + final).GestureFrameβ MediaPipe-style 21-point hand landmarks.AvatarFrameβ engine-agnostic blendshapes/bone rotations.SessionStateβ per-session source of truth broadcast by sync-service.EngagementSignalβ Audience Analytics output.
Transport: NATS (with JetStream) carries all pipeline-stage events
and the notification queue β one broker for streaming fan-out, stage
retries/backpressure, and durable notifications. REST is used only for
request/response operations (session/org CRUD in api-gateway, the ML services'
mock endpoints). WebSocket (Socket.IO) is the client-facing transport out of
sync-service. NATS subjects and WS event names are defined in
shared-types/src/events.ts.
Prerequisites: Docker + Docker Compose. (For running services outside Docker:
Node 20+, Python 3.11+, and uv.)
git clone <this-repo> && cd inclusa-backend
cp .env.example .env
docker compose -f infra/docker-compose.yml up --buildThis starts Postgres, Redis, NATS, all four NestJS apps, and all six Python ML services with hot-reload. Then:
- API Gateway Swagger: http://localhost:3000/docs
- Health checks:
:3000/health,:3001/health,:3002/health,:3003/health,:8001/health⦠- NATS monitoring: http://localhost:8222
Install once at the repo root (npm workspaces link @inclusa/* packages):
npm install
npm run build -w @inclusa/shared-types # build the shared contract firstRun a single NestJS app with hot reload (needs Postgres/Redis/NATS β start them
via docker compose ... up postgres redis nats):
npm run dev:api-gateway # or dev:sync / dev:recording / dev:notificationRun a Python service:
cd apps/ml-services/asr-service
uv run uvicorn main:app --reload --port 8001cd backend/api && npm run start:dev cd backend/realtime && npm run start:dev
## Environment variables
Copy `.env.example` to `.env` and fill the values. Typical entries (adjust to match your implementation):
APP_ENV=development PORT=8080 DATABASE_URL=postgres://user:pass@db:5432/inclusa REDIS_URL=redis://redis:6379 JWT_SECRET=supersecret ASR_PROVIDER=google|whisper GOOGLE_ASR_API_KEY=... WHISPER_MODEL_PATH=... AVATAR_SERVICE_URL=https://avatar.example.com AVATAR_API_KEY=... STORAGE_BUCKET=inclusa-recordings S3_ACCESS_KEY_ID=... S3_SECRET_ACCESS_KEY=... FIREBASE_PROJECT_ID=... AUTH0_DOMAIN=... AUTH0_CLIENT_ID=...
## Running tests
Run unit and integration tests using the project's test scripts. Example:
```bash
# Backend (NestJS)
cd backend
npm test
# Frontend
cd frontend
npm test
If integration tests require infra, start docker compose before running tests.
Options:
- Docker images + Kubernetes (recommended for production)
- Docker Compose for staging/smaller deployments
- Managed container platforms for selective components
The scaffold is wired so the full request path can be demonstrated with mock data (no real models or cloud creds):
- Speech in β open a WS to
ws://localhost:8001/transcribe/stream?sessionId=demo(orPOST /transcribe/mock). The mock ASR provider streamsTranscriptChunks. - Pipeline β the AI stub services (
/segment,/translate,/gestures,/avatar/frames) return well-formed mock frames. - WS broadcast β publish any pipeline frame to NATS (
inclusa.pipeline.*) andsync-servicefans it out to thesession:demoroom. Sendechoover the socket to confirm wiring without the pipeline. - Recording write β
POST http://localhost:3002/recordings {"sessionId":"demo"}writes a placeholder object (local.storage/in mock mode, else GCS). - Notification fire β
POST http://localhost:3003/notifications/testpublishes aNotificationEvent; the queue consumer logs a mock alert.
- REST endpoints and WebSocket message formats are documented in
docs/API.md. - Realtime audio ingestion uses WebRTC; control and event delivery use WebSockets.
- Analytics are aggregate-only and do not identify individuals.
- If recordings are stored, obtain consent and define retention policies.
- Encrypt data at rest (S3) and in transit (TLS).
- Minimize storing raw audio where not needed; prefer ephemeral processing.
Every variable across all services is documented in
.env.example. Copy it to .env for docker-compose, or copy
each app's own .env.example for standalone runs. Safe defaults are set for
local dev: ASR_PROVIDER=mock, STORAGE_MOCK=true, AUTH_DEV_BYPASS=true,
FEATURE_AUDIO2FACE=false.
- TypeScript: ESLint + Prettier via the shared
packages/config. - Python: Ruff + Black (configured per service
pyproject.toml). - Pre-commit: Husky + lint-staged (
prettier --writeon staged TS/JS/JSON/MD). - CI:
.github/workflows/ci.ymllints/builds/tests only the affected NestJS workspaces on a PR, plus a Python lint job.
These were the open decisions in the original brief; the choices made here (and how to swap them):
- Inter-service transport β NATS (over gRPC). One broker serves both the low-latency pipeline fan-out and the notification queue, and gives retries/backpressure via JetStream. Swap point: pipeline stages could move to gRPC for per-hop latency, but you'd then need a separate queue (e.g. BullMQ) for notifications.
- ORM β TypeORM (over Prisma). Traditional NestJS fit with decorator
entities and DI. Entities live beside their modules (
SessionEntity). - JS tooling β plain npm workspaces (over pnpm/Turborepo) to keep the MVP
simple. CI approximates Turbo's
--filterwith change detection. - Auth β Auth0 JWT (RS256 + JWKS) for enterprise/education/government SSO.
AUTH_DEV_BYPASS=truelets you develop without a tenant. Swap point: Firebase Auth β replace the issuer/JWKS/audience injwt.strategy.ts. - ASR β Google STT primary, Whisper fallback, both behind one provider
interface (
core/providers); defaultmock. Swap withASR_PROVIDER. - Storage β GCS (aligns with Google STT).
STORAGE_MOCK=truewrites locally. - Avatar β Ready Player Me + MediaPipe, with NVIDIA Audio2Face behind the
FEATURE_AUDIO2FACEflag (needs GPU infra), not a hard dependency.
- Wire real Google STT / Whisper streaming in
asr-service. - Implement real MediaPipe Hands + TensorFlow gesture generation.
- Real capture/muxing of synchronized timelines in
recording-service. - Fan
notification-serviceout to email/push/webhook providers. - Flesh out
infra/k8soverlays (staging/production) with GPU node pools. Planned improvements: - Support additional sign languages and regional variants
- Improve avatar realism and gesture fidelity
- Reduce ASR latency and improve accuracy
- Integrations with presentation platforms (PowerPoint, Google Slides)
- Offline/low-bandwidth modes
- Captions lagging: check ASR response time, message bus latency, and networking issues
- Avatar desync: ensure clocks are synchronized between services and verify message ordering
- Missing gestures: check translator logs and fallback behavior when translation fails
This project does not include a license file yet. Add a LICENSE file (e.g., MIT) to declare terms.
Project maintainers:
- SynapGridTech