A conversational language learning app powered by Inworld AI Runtime. 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
- An AssemblyAI account and API key (for speech-to-text)
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
ASSEMBLY_AI_API_KEY=your_assemblyai_key| Service | Get Key From | Purpose |
|---|---|---|
| Inworld | platform.inworld.ai | AI conversations (Base64 API key) |
| AssemblyAI | assemblyai.com | Speech-to-text |
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
│ │ ├── config/ # Language, LLM & server configuration
│ │ ├── graphs/ # Inworld Runtime conversation graphs
│ │ │ ├── configs/ # Graph JSON configurations
│ │ │ └── nodes/ # Custom graph nodes
│ │ ├── helpers/ # Audio utils, connection management
│ │ ├── prompts/ # Nunjucks prompt templates
│ │ ├── services/ # Server components (WS handler, API routes)
│ │ ├── types/ # TypeScript types
│ │ ├── utils/ # Logger
│ │ └── server.ts # Entry point
│ └── vitest.config.ts # Backend test config
├── frontend/
│ ├── src/
│ │ ├── __tests__/ # Frontend unit tests
│ │ ├── components/ # React components
│ │ ├── config/ # Language configuration
│ │ ├── context/ # App state & auth
│ │ ├── hooks/ # Custom React hooks
│ │ ├── services/ # WebSocket client, audio, 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 and streams it via WebSocket
- Backend processes audio through an Inworld Runtime graph:
- AssemblyAI handles speech-to-text with voice activity detection
- LLM generates contextual responses in the target language
- TTS converts responses back to audio
- Flashcards are auto-generated from conversation vocabulary
- Response feedback provides grammar and usage corrections
When Supabase is configured, the app stores and retrieves user memories using semantic search:
- Automatic memory creation: Every few conversation turns, the system extracts memorable facts
- Semantic retrieval: Relevant memories are 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).
| Variable | Required | Description |
|---|---|---|
INWORLD_API_KEY |
Yes | Inworld AI Base64 API key |
ASSEMBLY_AI_API_KEY |
Yes | AssemblyAI API key |
PORT |
No | Server port (default: 3000) |
LOG_LEVEL |
No | trace, debug, info, warn, error, fatal (default: info) |
NODE_ENV |
No | Set to production for production log format |
ASSEMBLY_AI_EAGERNESS |
No | Turn detection: low, medium, high (default: high) |
SUPABASE_URL |
No | Supabase project URL (enables memory feature) |
SUPABASE_SECRET_KEY |
No | Supabase secret key (for backend memory storage) |
# Run all tests (backend + frontend)
npm test --prefix backend
# Backend tests only
npm run test:backend --prefix backend
# Frontend tests only
npm test --prefix frontend
# Watch mode (backend)
npm run test:watch --prefix backendTests cover critical paths: audio conversion, language configuration, storage persistence, and flashcard deduplication.
Bug Reports: GitHub Issues
General Questions: For general inquiries and support, please email us at [email protected]
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.
