JARVIS is an Expo mobile app backed by a FastAPI assistant service. It demonstrates a full voice loop: record on device, stream audio to the backend, transcribe speech, build server-side memory/context, generate an answer, synthesize speech, and play the response in the app.
The project is portfolio-ready as a self-hosted AI assistant prototype. It can run in local fallback mode without provider keys for text testing, and it supports the full voice experience when provider credentials are configured.
Watch the demo: JARVIS Voice Assistant Demo
- Text ask -> assistant answer through the backend-owned
/api/v1/ai/processpipeline. - Voice ask -> speech transcription, context building, LLM response streaming, and spoken playback over WebSocket.
- Persistent conversation and knowledge storage using PostgreSQL, with Redis for working memory/cache.
- Local development fallback responses when model provider keys are missing.
- Deepgram Aura TTS by default, with Kokoro ONNX available as a local fallback.
graph LR
App[Expo App] -->|REST + WebSocket| API[FastAPI Backend]
API --> STT[Deepgram STT / Groq Whisper fallback]
API --> Context[Context Builder]
Context --> Postgres[(PostgreSQL)]
Context --> Redis[(Redis)]
API --> LLM[Groq Chat]
API --> TTS[Deepgram Aura / Kokoro fallback]
TTS --> App
| Mode | Requirements | Behavior |
|---|---|---|
| Text fallback | Backend running, no provider keys | Sends text prompts through REST and returns local-mode answers |
| Full text assistant | GROQ_API_KEY |
Uses Groq for generated assistant responses |
| Full voice loop | DEEPGRAM_API_KEY, GROQ_API_KEY, microphone permission |
Records speech, transcribes, answers, synthesizes speech, and plays audio |
| Local TTS fallback | Kokoro model files available | Synthesizes speech locally if Deepgram TTS is unavailable or disabled |
Mobile app:
cp .env.example .envFor Android emulator, keep:
EXPO_PUBLIC_API_URL=http://10.0.2.2:8000For iOS simulator or local web, use:
EXPO_PUBLIC_API_URL=http://127.0.0.1:8000Backend:
cp backend/.env.example backend/.envImportant backend values:
GROQ_API_KEY=your_groq_key
GROQ_CHAT_MODEL=openai/gpt-oss-120b
GROQ_FALLBACK_MODEL=llama-3.1-8b-instant
GROQ_STT_MODEL=whisper-large-v3-turbo
DEEPGRAM_API_KEY=your_deepgram_key
DEEPGRAM_STT_MODEL=nova-3
DEEPGRAM_TTS_MODEL=aura-2-thalia-en
# Optional local TTS fallback
KOKORO_MODEL_PATH=/absolute/path/to/backend/models/kokoro/kokoro-v1.0.int8.onnx
KOKORO_VOICES_PATH=/absolute/path/to/backend/models/kokoro/voices-v1.0.bin
KOKORO_DEFAULT_VOICE=af_sarah
KOKORO_DEFAULT_LANGUAGE=en-us
KOKORO_DEFAULT_SPEED=1.0
# Embeddings/knowledge features
OPENAI_API_KEY=
PINECONE_API_KEY=Provider secrets belong in backend/.env; the mobile app should only know the backend base URL.
npm run backend:setup
npm run backendThe backend listens on 0.0.0.0:8000, which lets physical phones on the same LAN reach it. Verify from the simulator, browser, or phone:
http://<backend-host>:8000/health
Expected response:
{"status":"healthy","version":"1.0.0","debug":true}npm install
npm startUseful variants:
npm run start:go -- --clear
npm run start:dev-client -- --clear
npm run android
npm run iosUse a Dev Client build when native modules are required.
The root docker-compose.yml runs backend support services such as PostgreSQL and Redis:
docker-compose up -dUse the same backend environment variables as local development.
Frontend checks:
npm run type-check
npm testBackend checks:
cd backend
pytestWebSocket voice protocol smoke test:
BACKEND_WS=ws://localhost:8000/api/v1/ws/voice/1 node scripts/ws_test_node.jsSee scripts/WSTEST.md for details.
| Symptom | Fix |
|---|---|
| Phone cannot connect to backend | Run npm run backend, confirm /health from the phone browser, and set EXPO_PUBLIC_API_URL to the Mac LAN IP |
| Android emulator cannot reach backend | Use EXPO_PUBLIC_API_URL=http://10.0.2.2:8000 |
| iOS simulator cannot reach backend | Use EXPO_PUBLIC_API_URL=http://127.0.0.1:8000 |
| WebSocket closes immediately | In local unauthenticated testing, set ALLOW_INSECURE_DEV_AUTH=true in backend/.env |
| Text works but voice does not transcribe | Check DEEPGRAM_API_KEY, GROQ_API_KEY, microphone permission, and backend logs |
| Voice transcribes but no audio plays | Check Deepgram TTS first, then Kokoro fallback paths if using local TTS |
| No memory/context appears in answers | Confirm PostgreSQL and Redis are running and inspect backend logs for context builder or fact extraction errors |
- Do not expose
/api/v1/ws/voice/{user_id}without JWT/session authentication. - Keep provider keys only on the backend.
- Replace the default
SECRET_KEYbefore production. - Use PostgreSQL backups and Redis persistence for durable assistant memory.
- See
backend/DEPLOYMENT_NOTES.mdfor deployment and operations guidance.