The repository hosts two projects:
src/english_app_agent: LangGraph-based backend that orchestrates mnemonic/image/TTS generation.src/web: Next.js 14 chat UI that proxies requests to the Python agent.
This document focuses on the backend and assumes you manage Python dependencies with uv, which provides an ultra-fast drop-in replacement for pip/venv.
- Python 3.10+ (matching the agent code requirements)
uvinstalled globally- Optional: Node.js 18+ if you plan to run the frontend alongside the backend
-
Install dependencies
cd E:/code/English_app uv pip install -r requirements.txtThe
requirements.txtfile mirrors everything the agent imports (langgraph,fastapi,dashscope, etc.). uv creates and reuses an isolated environment automatically (stored under.venvunless configured otherwise). -
Set environment variables
- Copy
.env.example(if provided) or edit.envdirectly. - Typical keys:
DEEPSEEK_API_KEY,DASHSCOPE_API_KEY,GOOGLE_API_KEYfor LLM/image/TTS accessGET_API_KEYS_FROM_CONFIG=trueif you prefer passing keys viaRunnableConfig.configurable.apiKeys
- Copy
-
Run database- or cache-related services (if any). Currently the LangGraph flow relies on
InMemorySaver, so no external store is needed.
The FastAPI entry point lives at src/english_app_agent/server.py and exposes /health and /chat.
uv run uvicorn english_app_agent.server:app --app-dir src --reload --port 8000--app-dir srclets uvicorn find theenglish_app_agentpackage without alteringPYTHONPATH.--reloadis optional but useful while iterating on prompts or graph logic.- Set
AGENT_API_BASE_URL=http://127.0.0.1:8000in the frontend env so/api/chatproxies requests to this service.
The mnemonic agent injects skills at runtime using src/english_app_agent/skills_provider.py:
- Skills live under
skills/<skill-name>/SKILL.mdwith optionalreferences/files. SkillManagerdiscovers skills, selects with a keyword/BM25 selector, and injects the selected skill body into the mnemonic prompt.- References like
references/phoneme-mapping.mdare appended when present. - Skills refresh on a 60s TTL, so you can update files without restarting the server.
Every successful /chat response flows through a tiered storage manager:
- Local cache (default on) – Results are serialized to
~/.english_app_agent/cache. The cache trims itself when file count exceedsmax_entries(default 200). Tune viaEnglishAppConfig.storage.local_cache. - Remote database (optional) – Set
storage.remote_database.enable=trueand provide a SQLAlchemy URL (MySQL or PostgreSQL). Structured payloads are inserted into thechat_responsestable automatically. - Media mirroring (optional) – Enabling
storage.mediawithprovider="aliyun_oss"and valid OSS credentials instructs the backend to copy image/audio URLs into your bucket. The returnedfinal_output.media.*.urlwill reflect the mirrored location.
Feature flags can be toggled via environment variables or by supplying a JSON blob under the storage key inside RunnableConfig.configurable.
src/english_app_agent/storage_config.py reads settings from two sources (merged in this order):
RunnableConfig.configurable.storage(useful for per-request overrides).- Environment variables (best for
.env/deployment defaults).
Key env vars you can drop into .env:
# Local cache (defaults shown)
LOCAL_CACHE_ENABLE=true
LOCAL_CACHE_DIR=~/.english_app_agent/cache
LOCAL_CACHE_MAX_ENTRIES=200
# Remote DB
REMOTE_DB_ENABLE=false
REMOTE_DB_URL=postgresql+psycopg2://user:pass@host/dbname
# Media mirroring
MEDIA_ENABLE=true
MEDIA_PROVIDER=local_fs # or aliyun_oss / none
MEDIA_LOCAL_DIRECTORY=~/.english_app_agent/media
# Aliyun OSS-only fields:
MEDIA_BUCKET=your-bucket
MEDIA_ENDPOINT=https://oss-cn-hangzhou.aliyuncs.com
MEDIA_ACCESS_KEY_ID=...
MEDIA_ACCESS_KEY_SECRET=...
MEDIA_PREFIX=chat_media/
# Cache archive (optional OSS backup for records)
ARCHIVE_ENABLE=false
ARCHIVE_BUCKET=...
ARCHIVE_ENDPOINT=...
ARCHIVE_ACCESS_KEY_ID=...
ARCHIVE_ACCESS_KEY_SECRET=...
ARCHIVE_PREFIX=chat_cache/When editing storage_config.py, keep the Pydantic models aligned with these env names—each field uses a helper (_env_bool, _env_int, or os.getenv). On the frontend/CLI side, pass overrides like:
config = {
"configurable": {
"thread_id": "abc123",
"storage": {
"media": {"provider": "local_fs", "local_directory": "/tmp/english-app/media"}
}
}
}This lets you tailor caching/media policies per request without touching global env vars.
uv run python - <<'PY'
import asyncio
from english_app_agent.agent import app_agent
async def main():
state = await app_agent.ainvoke(
{"messages": [{"type": "human", "content": "Help me remember ambulance"}]},
config={"configurable": {"thread_id": "debug-cli"}}
)
print(state["reply_text"])
asyncio.run(main())
PYtest/test_main_agent_logic.py currently serves as a placeholder. When tests are added, run them with:
uv run python -m pytestcd src/web && npm installAGENT_API_BASE_URL=http://127.0.0.1:8000 npm run dev- The Next.js API route (
/api/chat) forwards chat payloads to the FastAPI backend, so keep both servers running for the full experience.
- CORS errors:
server.pyenables permissive CORS, but you can narrowallow_originsonce deployment domains are known. - API errors:
/api/chatsurfaces backend exceptions via JSON{ error: "..." }. Check the FastAPI logs for stack traces. - Missing keys: The agent reads provider keys from env vars unless
GET_API_KEYS_FROM_CONFIG=true, in which case pass them viaconfigurable.apiKeys.
When backend.data_dashboard is installed, the main FastAPI app automatically mounts it under /dashboard. Configure the repository connection via:
DATA_DASHBOARD_DATABASE_URL=postgresql+psycopg2://user:pass@host/dbnameIf the env var is missing you can still POST inline telemetry by hitting /dashboard/dashboard with events and memberships arrays (see src/backend/data_dashboard/README.md for a template). Run the unified server as usual:
uv run uvicorn english_app_agent.server:app --app-dir src --reload --port 8000The mounted sub-application also exposes /dashboard/health.
With uv managing dependencies and FastAPI hosting both the LangGraph flow and dashboard routes, the backend remains lightweight and easy to iterate alongside the Next.js frontend.