File size: 14,964 Bytes
7c6ffa6 6515ef9 7c6ffa6 6515ef9 7c6ffa6 6515ef9 7c6ffa6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | ---
title: DocDoe Backend
emoji: π
colorFrom: indigo
colorTo: gray
sdk: docker
app_port: 7860
pinned: false
short_description: DocDoe FastAPI backend β tuition brain + study API
---
<!--
The YAML block above is Hugging Face Space metadata (must stay at the very top
of this file). When this backend/ folder is pushed to a Hugging Face Space, HF
reads it to build the FastAPI app as a Docker Space on port 7860. It is inert
in the main repo. Full runbook: backend/DEPLOY-huggingface.md.
-->
# AI Exam Success Backend
FastAPI foundation for the AI Exam Success Platform. This phase uses local file storage with an S3-compatible storage abstraction, SQLAlchemy models, Pydantic schemas, document chunk retrieval, pluggable AI providers, provider-based TTS/audio sync, and local Remotion MP4 export. AI mock mode is free by default; video voice generation now prefers Edge TTS for local real-audio testing when installed.
## Setup
```powershell
cd backend
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
```
Optional:
```powershell
Copy-Item .env.example .env
```
Set `DATABASE_URL` to PostgreSQL when you have Postgres running. Without a `.env`, the app uses a local SQLite development database so the mock API can run immediately.
## Auth Modes
Local development keeps auth friction low by default:
```powershell
AUTH_ENABLED="false"
AUTH_PROVIDER="dev"
ALLOW_INSECURE_DEV_AUTH="true"
```
This is deliberately limited to local development. Set `ALLOW_INSECURE_DEV_AUTH=true` only with a localhost frontend; any other deployment must enable real authentication.
JWT mode enables real email/password signup and login through the FastAPI backend:
```powershell
AUTH_ENABLED="true"
AUTH_PROVIDER="jwt"
JWT_SECRET_KEY="replace-with-a-long-random-secret"
JWT_ALGORITHM="HS256"
ACCESS_TOKEN_EXPIRE_MINUTES="10080"
```
Use `POST /auth/signup` or `POST /auth/login` to get an access token, then send it as:
```text
Authorization: Bearer <access_token>
```
Supabase mode is provider-ready for later hosted auth:
```powershell
AUTH_ENABLED="true"
AUTH_PROVIDER="supabase"
SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_JWT_SECRET="your-supabase-jwt-secret"
SUPABASE_ANON_KEY="your-supabase-anon-key"
```
The backend validates the Supabase JWT and creates a matching local user record when needed. Keep secrets server-side only; the frontend should use the anon key, never the JWT secret.
## AI Provider Modes
Mock mode is the default and needs no API key:
```powershell
AI_PROVIDER="mock"
```
Gemini mode uses the official `google-genai` SDK:
```powershell
AI_PROVIDER="gemini"
GEMINI_API_KEY="your-api-key"
GEMINI_MODEL_FLASH="gemini-2.5-flash"
GEMINI_MODEL_PRO="gemini-2.5-pro"
AI_FALLBACK_TO_MOCK="true"
```
When `AI_FALLBACK_TO_MOCK` is true, the backend logs Gemini failures safely and returns mock output instead of breaking the student flow.
## TTS Provider Modes
AI4Bharat Indic Parler-TTS is the preferred DocDoe teacher voice. It supports
Indian English and Malayalam, runs locally, and has no per-minute API cost.
The model repository is gated, so accept its access terms once and use a free
Hugging Face token for the initial download:
```powershell
py -3.11 -m venv .tts-venv
.\.tts-venv\Scripts\Activate.ps1
pip install -r requirements-tts-ai4bharat.txt
$env:HF_HUB_DISABLE_XET="1"
TTS_PROVIDER="ai4bharat"
TTS_DEFAULT_PROVIDER="ai4bharat"
VIDEO_TTS_PROVIDER="ai4bharat"
HUGGINGFACE_API_KEY="your-free-hugging-face-token"
AI4BHARAT_TTS_MODEL="ai4bharat/indic-parler-tts"
AI4BHARAT_TTS_SPEAKER="Anjali"
AI4BHARAT_TTS_DEVICE="auto"
AI4BHARAT_TTS_PRECISION="float32"
TTS_DEFAULT_VOICE="nila"
TTS_OUTPUT_DIR="public/generated/audio"
AUDIO_NORMALIZE="true"
```
Narration should keep scientific words in English and write Malayalam support
phrases in Malayalam script. The model automatically detects both languages.
Romanized Manglish can remain in subtitles, but native script is used internally
for dependable pronunciation.
On Windows, keep the pinned `sentencepiece==0.2.0` from the requirements file.
The newer 0.2.1 wheel can terminate the process while loading this model's
Malayalam tokenizer. The provider also retries the rare sampled output that
ends before a complete teaching sentence is spoken.
`float32` is the quality-first default and has been validated on the local RTX
3060 12 GB for clear Malayalam. Set `AI4BHARAT_TTS_PRECISION="float16"` only
when capacity matters more than Malayalam voice quality.
Edge TTS remains available as a lightweight development fallback when
`requirements-tts.txt` is installed.
Mock TTS is still available for silent timing tests only. Outputs are labeled `Silent mock audio`, and final rendering blocks silent mock audio unless explicitly allowed by the request.
Optional provider presets:
```powershell
TTS_PROVIDER="kokoro"
KOKORO_VOICE="af_heart"
KOKORO_SPEED="0.95"
```
`indic`, `hybrid`, `edge`, and `elevenlabs` provider classes are available behind the same interface. If a real provider is requested and fails, the backend returns a clear audio generation error instead of silently creating mock audio.
Generate sample audio props for Remotion:
```powershell
python scripts/generate_sample_tts.py --provider edge --voice-mode english_soft
python scripts/generate_sample_tts.py --provider mock --voice-mode ml_en_mix
```
## Storage Provider Modes
Local storage is the default and keeps the existing static URLs working:
```powershell
STORAGE_PROVIDER="local"
STORAGE_UPLOAD_PREFIX="uploads"
STORAGE_AUDIO_PREFIX="generated-audio"
STORAGE_VIDEO_PREFIX="generated-videos"
```
Cloud storage uses an S3-compatible client, so the same interface can target Cloudflare R2, AWS S3, Wasabi, or MinIO later:
```powershell
STORAGE_PROVIDER="r2"
STORAGE_BUCKET="your-bucket"
STORAGE_REGION="auto"
STORAGE_ENDPOINT_URL="https://<account-id>.r2.cloudflarestorage.com"
STORAGE_ACCESS_KEY_ID="your-access-key"
STORAGE_SECRET_ACCESS_KEY="your-secret-key"
STORAGE_PUBLIC_BASE_URL="https://media.example.com"
STORAGE_AUDIO_PREFIX="generated-audio"
STORAGE_VIDEO_PREFIX="generated-videos"
```
For AWS S3, set `STORAGE_PROVIDER="s3"` and use the bucket region. `STORAGE_PUBLIC_BASE_URL` should point to a public bucket URL, CDN, or custom domain. If cloud credentials or bucket settings are missing, the backend logs a safe warning and falls back to local storage.
Cloud buckets need public read access or a public CDN/domain for generated MP4/audio playback. Configure bucket CORS to allow `GET`/`HEAD` from the frontend origin during development and production.
## Local Video Rendering
Final MP4 export uses the local Remotion CLI through a fixed Node script. The backend writes render inputs to `generated-video-jobs/{video_id}/`, renders to `generated-videos/`, and saves a metadata JSON next to each MP4.
```powershell
GENERATED_VIDEO_JOBS_DIR="generated-video-jobs"
GENERATED_VIDEO_OUTPUT_DIR="generated-videos"
VIDEO_RENDER_TIMEOUT_SECONDS="420"
```
Render an existing audio-enhanced props file:
```powershell
npm run render:from-json -- --props public/generated/audio/sample-rest-api-en/scene-plan-with-audio.json --output generated-videos/manual-render.mp4
```
Render the built-in 9:16 anime visual explainer sample:
```powershell
npm run render:sample-anime-video
```
Generate and render the golden 60-second Photosynthesis anime explainer with real Edge TTS audio:
```powershell
npm run video:photosynthesis-real-audio
```
The final render flow validates audio before Remotion starts. Each scene must have a non-empty, duration-verified `audio_src`, and the finished MP4 is checked for an audio stream with `ffprobe` when available.
The user-facing flow should use render jobs:
```text
queued 0% -> running 10% -> preparing inputs 20% -> rendering 40% -> metadata 90% -> ready 100%
```
## Run
```powershell
uvicorn app.main:app --reload --host 127.0.0.1 --port 8000
```
Open:
- `http://127.0.0.1:8000/health`
- `http://127.0.0.1:8000/docs`
## Key Endpoints
- `GET /health`
- `POST /auth/signup`
- `POST /auth/login`
- `GET /auth/session`
- `GET /users/me`
- `PATCH /users/me`
- `POST /documents/upload`
- `GET /documents`
- `GET /documents/{document_id}`
- `GET /documents/{document_id}/preview`
- `GET /documents/{document_id}/chunks`
- `POST /documents/{document_id}/retrieve`
- `POST /documents/{document_id}/study-map`
- `POST /generations/notes`
- `POST /generations/simple-explanation`
- `POST /generations/exam-mode`
- `POST /quizzes/generate`
- `POST /flashcards/generate`
- `POST /previous-papers/upload`
- `POST /previous-papers/analyze`
- `POST /previous-papers/{paper_id}/extract-questions`
- `GET /previous-papers/{paper_id}/questions`
- `POST /previous-papers/analyze-structured`
- `POST /video/scene-plan`
- `POST /video/generate-audio`
- `POST /video/render-final`
- `POST /video/render-jobs`
- `GET /video/render-jobs`
- `GET /video/render-jobs/{job_id}`
- `DELETE /video/render-jobs/{job_id}`
- `GET /generated/audio/{user_id}/{video_id}/scene-001.wav` (owner-authenticated)
- `GET /generated/videos/{user_id}/{file_name}.mp4` (owner-authenticated)
## Local demo seed
Seed a realistic closed-beta demo dataset into your local database with a single command.
No provider calls, no secrets, no downloads β safe for air-gapped dev machines.
```powershell
cd backend
python scripts/seed_beta_demo.py
python scripts/seed_beta_demo.py --verbose # show every row created/skipped
```
What gets created:
| Entity | Detail |
|---|---|
| User | `demo@docdoe.in`, role: student. Local password defaults to `demo1234`; production requires `DOCDOE_DEMO_PASSWORD`. |
| Study profile | Kerala HSE +1 Computer Science |
| User plan | free trial, 100 generation limit, 30-day window |
| Documents (Γ4) | notes, question paper, synthetic non-personal classifier fixture, and chapter, each with 3 text chunks |
| Video jobs (Γ2) | `script_ready` (awaiting render) + `completed` (mock, no real file) |
The script is **idempotent** β running it twice creates no duplicates. Seeded content contains no real name, school, parent, phone number, address, or other personal information.
Stub `.txt` files are written to `uploads/demo_*.txt` so file paths are non-null.
Production seeding refuses to run unless a strong password is supplied:
```powershell
$env:DOCDOE_DEMO_PASSWORD = "use-a-generated-secret-with-16-plus-characters"
python scripts/seed_beta_demo.py
```
**Remove demo data:**
```powershell
python scripts/clear_beta_demo.py # delete demo records
python scripts/clear_beta_demo.py --dry-run # preview what would be deleted
```
`clear_beta_demo.py` deletes only the demo user and their associated rows.
It also removes the `uploads/demo_*.txt` stub files created by the seed script.
All other user data is untouched.
## Notes
- All user library endpoints are protected by `app/core/auth.py`. With auth disabled they use the demo student; with auth enabled they require a valid bearer token.
- Documents, generations, quizzes, flashcards, previous papers, structured previous questions, generated audio, and video render jobs are scoped to the current user. Request bodies are not trusted for `user_id`.
- Uploaded files are stored in `backend/uploads`.
- Database tables are created automatically on app startup for the MVP.
- The AI provider supports `MockAIProvider` and `GeminiAIProvider`.
- Gemini responses are requested as structured JSON and use retrieved chunks as context instead of sending full documents.
- The exam-tutor output style is shaped for simple meaning, keywords, memory tricks, exam answers, quick checks, and mistakes to avoid.
- Video scene plans support `visual_style`: `clean_explainer` or `anime_visual_explainer`, and `video_format`: `16:9` or `9:16`. The anime visual style uses original mascot panels, floating cards, icons, arrows, bottom subtitles, and short-form progressive reveal. It must not use copyrighted anime clips, copied characters, avatars, or real-person likenesses.
- `/video/generate-audio` accepts either the existing single `language` flow or a `languages` array and returns `audio_variants` for separate language-specific MP4 rendering later.
- Previous papers can be uploaded, converted into structured `PreviousQuestion` rows, and analyzed for repeated topics, chapter weightage, marks distribution, question-type distribution, high-probability topics, expected questions, and study priorities.
- Text extraction supports `.txt`, `.md`, and selectable-text `.pdf` files out of the box.
- Image OCR supports `.jpg`, `.jpeg`, `.png`, and `.webp` through `pytesseract`, but the Tesseract executable must be installed separately and available on `PATH`.
- Ready documents are split into overlapping chunks automatically after extraction.
- Retrieval currently uses simple keyword scoring with subject/chapter boosts. This is the RAG interface for later vector embeddings.
- Phase 13 adds `app/services/context_builder.py`, `app/services/study_intelligence.py`, and `app/services/ai_quality.py`. The context builder combines document metadata, retrieved chunks, latest study map, previous-paper signals, selected language/mode, and strict tutor rules before calling the AI provider.
- AI outputs now use richer exam-focused shapes for study maps, smart notes, simple explanation, exam mode, quizzes, flashcards, previous-paper analysis, and video scene plans. Mock mode mirrors those shapes so frontend development stays free.
- Rule-based AI quality scoring is attached where useful as `quality_score`, with clarity, exam focus, conciseness, usefulness, completeness, and missing-section checks.
- Video audio generation saves browser-accessible files under `public/generated/audio/{video_id}` by default and updates scene timing using detected audio duration plus a small padding.
- Generated audio and final MP4 files are uploaded through `app/services/storage_provider.py` when `STORAGE_PROVIDER` is `r2` or `s3`; local files remain as fallback.
- Final video rendering saves MP4 files under `generated-videos/` and writes `{video_id}.metadata.json` with duration, scene count, provider, storage object details, and warnings.
- Video render jobs are stored in the database so the frontend can poll progress and show render history at `/videos`.
- Local generated videos can consume disk. Periodically review `generated-videos/`, `generated-video-jobs/`, and `public/generated/audio/`; `app/services/video_cleanup.py` has dry-run helpers for old files.
- The default product voices are Nila, Nila Malayalam, and Nila Mix. They are voice directions and provider presets, not cloned or copyrighted character voices.
## OCR Setup On Windows
Install Tesseract OCR, then restart the terminal so `tesseract.exe` is on `PATH`.
```powershell
tesseract --version
```
If that command works, image uploads can extract text. If it does not, image uploads are saved but marked `failed` with a clear extraction error.
|