A conversational language learning app powered by Inworld AI's Realtime API. Practice speaking with an AI tutor, get real-time feedback on your responses, and build vocabulary with auto-generated flashcards.
- Node.js (v20 or higher)
- npm
- An Inworld AI account and API key
git clone https://github.com/inworld-ai/language-learning-node
cd language-learning-nodenpm installThis installs dependencies for the root, backend, and frontend automatically.
Create a backend/.env file:
INWORLD_API_KEY=your_inworld_base64_key| Service | Get Key From | Purpose |
|---|---|---|
| Inworld | platform.inworld.ai | Realtime voice AI (Base64) |
For development (with auto-reload on file changes):
npm run devThis starts both the backend (port 3000) and frontend dev server (port 5173) concurrently.
For production:
npm run build
npm startWithout Supabase, the app works in anonymous mode using localStorage.
a) Create a Supabase project at supabase.com
b) Push the database schema:
npx supabase login
npx supabase link --project-ref YOUR_PROJECT_REF
npx supabase db pushThis creates all tables, indexes, RLS policies, and the match_memories function for semantic search.
Find your project ref in the Supabase dashboard URL: supabase.com/dashboard/project/YOUR_PROJECT_REF
c) Add Supabase variables to backend/.env:
SUPABASE_URL=https://YOUR_PROJECT.supabase.co
SUPABASE_SECRET_KEY=your_secret_keyd) Create frontend/.env.local:
VITE_SUPABASE_URL=https://YOUR_PROJECT.supabase.co
VITE_SUPABASE_PUBLISHABLE_KEY=your_anon_keyFind these in: Supabase Dashboard > Settings > API
language-learning-node/
├── backend/
│ ├── src/
│ │ ├── __tests__/ # Backend unit tests (60 tests)
│ │ ├── config/ # Language, server & Supabase configuration
│ │ ├── helpers/ # Anki exporter, TTS audio generator
│ │ ├── services/ # Session manager, WS handler, LLM, memory
│ │ ├── types/ # TypeScript types
│ │ ├── utils/ # Logger
│ │ └── server.ts # Entry point
│ └── vitest.config.ts # Backend test config
├── frontend/
│ ├── src/
│ │ ├── components/ # React components (Chat, Flashcard, Sidebar, etc.)
│ │ ├── context/ # App state & auth (AppContext, AuthContext)
│ │ ├── hooks/ # Custom React hooks
│ │ ├── services/ # WebSocket client, audio player/handler, storage
│ │ ├── styles/ # CSS
│ │ └── types/ # TypeScript types
│ └── vitest.config.ts # Frontend test config
├── supabase/
│ └── migrations/ # Database schema
├── render.yaml # Render deployment config
└── package.json # Monorepo scripts
The app uses a real-time audio streaming architecture:
- Frontend captures microphone audio (24kHz PCM16) and streams it via WebSocket
- Backend proxies audio to an Inworld Realtime WebSocket session that handles:
- Speech-to-text (AssemblyAI u3-rt-pro via Inworld) with language hints
- LLM response generation (GPT-4.1-nano via Inworld LLM Router)
- Text-to-speech with language-specific voices
- Flashcards are auto-generated from conversation vocabulary via the Inworld LLM Router
- Response feedback provides grammar and usage corrections
- Anki export generates
.apkgfiles with embedded TTS pronunciation audio
When Supabase is configured, the app stores and retrieves user memories:
- Automatic memory creation: Every few conversation turns, the system extracts memorable facts via LLM
- 5-turn sliding window: Recent conversation context is injected into session instructions (non-blocking)
- Semantic retrieval: Relevant memories retrieved using vector similarity search (pgvector)
- Personalized responses: The AI uses retrieved memories to personalize conversations
Memory types:
learning_progress: Vocabulary struggles, grammar patterns, learning achievementspersonal_context: Interests, goals, preferences shared by the user
Without Supabase, the app works in anonymous mode using localStorage (no memory persistence).
English, Spanish, French, German, Italian, Portuguese — each with a dedicated teacher persona and voice.
| Variable | Required | Description |
|---|---|---|
INWORLD_API_KEY |
Yes | Inworld AI Base64 API key |
PORT |
No | Server port (default: 3000) |
LOG_LEVEL |
No | trace, debug, info, warn, error, fatal (default: info) |
VAD_EAGERNESS |
No | Turn detection: low, medium, high (default: low) |
SUPABASE_URL |
No | Supabase project URL (enables memory feature) |
SUPABASE_SECRET_KEY |
No | Supabase secret key (for backend memory storage) |
# Run all backend tests
cd backend && npx vitest run
# Watch mode
cd backend && npx vitest
# Type check
cd backend && npx tsc --noEmit
cd frontend && npx tsc --noEmitTests cover: session management, LLM integration, turn memory, language configuration, WebSocket handler wiring, and STT event handling.
Bug Reports: GitHub Issues
General Questions: For general inquiries and support, please email us at support@inworld.ai
We welcome contributions! Please see CONTRIBUTING.md for guidelines on how to contribute to this project.
This project is licensed under the MIT License - see the LICENSE file for details.
