A language learning application with LLM-generated reading practice, click-to-translate word glosses, and sentence translations.
Arcadia Lang generates personalized reading texts for language learners:
- Global text pool - Texts are generated once and shared across users with matching language pairs
- Multi-profile support - Users can learn multiple languages with separate profiles
- Click-to-translate - Word glosses and sentence translations appear on hover/click
- Background generation - Texts are pre-generated so they're ready when users need them
# Install dependencies
uv sync
# Set required environment variables
export ARC_LANG_JWT_SECRET="your-secret-key"
export OPENROUTER_API_KEY="your-openrouter-key" # or use local LLM
# Start the server
./run.sh
# or: uv run uvicorn server.main:app --reload --host 0.0.0.0 --port 8000Visit http://localhost:8000, create an account, set up a profile with your target language, and start reading.
Global database (data/arcadia_lang.db):
accounts- User accounts with authprofiles- Language learning profiles (one per language pair per user)reading_texts- Generated texts shared across usersreading_text_translations- Sentence translationsreading_word_glosses- Word-level translations
Per-account databases (data/user_<id>.db):
lexemes- User's vocabulary knowledgeword_events- Interaction historyuser_reading_history- Which texts the user has read
- Background Worker (
server/services/background_worker.py) - Manages text pool, retries failed translations - Generation Orchestrator (
server/services/generation_orchestrator.py) - Coordinates text + translation generation - LLM Providers (
server/llm/) - OpenRouter, local LLM, and provider fallback chain
- User requests reading → system checks for available texts in pool
- If pool is low, background worker triggers generation
- Text content generated via LLM
- Parallel requests for word glosses and sentence translations
- Text marked "ready" when all components complete
- Failed translations automatically retried by background worker
ARC_LANG_JWT_SECRET- JWT signing secretOPENROUTER_API_KEY- For OpenRouter provider (or configure local LLM)
ARC_LLM_PROVIDERS- Provider order, e.g.,"openrouter,local"(default:"openrouter,local")LOCAL_LLM_BASE_URL- Base URL for local LLM providerARC_WORDS_PARALLEL- Number of parallel word gloss requests (default: 1)ARC_OR_WORDS_ATTEMPTS- Retry count for OpenRouter word requests
ARC_STARTUP_LANGS- Comma-separated languages to pre-generate on startup (e.g.,"es,zh")ARC_STARTUP_TEXTS_PER_LANG- Texts to generate per language on startup (default: 2)
Example:
export ARC_STARTUP_LANGS="es,zh"
export ARC_STARTUP_TEXTS_PER_LANG="3"# Run tests
./run_tests.sh
# or: uv run pytest tests/
# Run specific test
uv run pytest tests/unit/path/to/test.py -vAdmin users can access monitoring pages:
/admin/texts- View all texts in the pool with status (ready/pending/failed)/admin/accounts- View accounts, profiles, change subscription tiers
Currently supports:
- Chinese (zh) - Jieba tokenization, pinyin generation
- Spanish (es) - Regex tokenization
Target language for translations is typically English (en).