DocDoeAI / README.md
asnannp's picture
deploy: sync backend to Space root (learn-lesson HF cache fix)
6515ef9
|
Raw
History Blame Contribute Delete
15 kB
metadata
title: DocDoe Backend
emoji: πŸ“š
colorFrom: indigo
colorTo: gray
sdk: docker
app_port: 7860
pinned: false
short_description: DocDoe FastAPI backend β€” tuition brain + study API

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

cd backend
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt

Optional:

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:

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:

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:

Authorization: Bearer <access_token>

Supabase mode is provider-ready for later hosted auth:

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:

AI_PROVIDER="mock"

Gemini mode uses the official google-genai SDK:

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:

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:

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:

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:

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:

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.

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:

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:

npm run render:sample-anime-video

Generate and render the golden 60-second Photosynthesis anime explainer with real Edge TTS audio:

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:

queued 0% -> running 10% -> preparing inputs 20% -> rendering 40% -> metadata 90% -> ready 100%

Run

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.

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:

$env:DOCDOE_DEMO_PASSWORD = "use-a-generated-secret-with-16-plus-characters"
python scripts/seed_beta_demo.py

Remove demo data:

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.

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.