Skip to content

Repository files navigation

title SmartNotes AI
emoji 📝
colorFrom blue
colorTo green
sdk docker
app_port 7860
pinned false

SmartNotes PDF OCR

Project Metadata

Field Value
Project SmartNotes AI
App type FastAPI web app for PDF OCR and RAG-based question answering
Runtime Python 3.12
Default URL http://127.0.0.1:8000
Main entrypoint app.py
UI files templates/index.html, static/app.js, static/styles.css
OCR pipeline PyMuPDF, OpenCV, Gemini Vision OCR, TrOCR fallback
RAG pipeline Text cleaning, metadata extraction, parent/child chunks, embeddings, BM25, reranking, citations
Storage SQLite local fallback in data/smartnotes.sqlite; optional PostgreSQL via POSTGRES_DSN
Vector store Local fallback; optional Qdrant via QDRANT_URL
Docker Dockerfile exposes port 8000
Secrets Keep API keys in .env; do not commit .env

FastAPI app for PDF-to-text extraction using this route:

  1. Try PyMuPDF direct text extraction.
  2. If text exists, skip OCR, clean text, return final text.
  3. If no direct text exists, convert PDF pages to images with PyMuPDF.
  4. Preprocess images with OpenCV.
  5. For 20 pages or fewer, run Gemini Vision OCR.
  6. For more than 20 pages, run TrOCR first, then send low-confidence pages to Gemini Vision.
  7. Merge, clean, and return final text.

The UI uses /api/pdf-to-text-stream, so extracted text appears page by page instead of waiting for the full PDF to finish.

After extraction, the UI automatically calls /api/index-text-stream and runs the locked RAG workflow:

  • status processing
  • cleaning and metadata
  • parent chunks
  • fixed, recursive, and semantic child chunks
  • chunk recommendation
  • embeddings and embedding evaluation
  • Qdrant store when configured, local vector fallback otherwise
  • BM25 index
  • status indexed
  • query validation, rewrite, hybrid retrieval, top-50 candidates, reranking, grading
  • parent fetch, duplicate parent removal, context fitting, answer, citations, retrieved chunk view, logs, feedback

Useful optional env values:

POSTGRES_DSN=postgresql://user:password@localhost:5432/smartnotes
QDRANT_URL=http://localhost:6333
QDRANT_API_KEY=
EMBEDDING_MODEL=BAAI/bge-small-en-v1.5
RERANKER_MODEL=BAAI/bge-reranker-base
USE_LOCAL_EMBEDDING_MODEL=1
USE_LOCAL_RERANKER_MODEL=1
ANSWER_PROVIDER=gemini
ANSWER_MODEL=gemini-2.5-flash

Setup

python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
$env:GEMINI_API_KEY="your_api_key"
uvicorn app:app --reload

Open http://127.0.0.1:8000.

You can also put these values in env or .env:

GEMINI_API_KEY_1=your_first_api_key
GEMINI_API_KEY_2=your_second_api_key
GEMINI_API_KEY_3=your_third_api_key
GEMINI_API_KEY_4=your_fourth_api_key
GEMINI_MODELS=gemini-3.5-flash,gemini-2.5-flash,gemini-2.5-flash-lite
GEMINI_MAX_RETRIES=2
GEMINI_RETRY_DELAY=1.5
GEMINI_KEY_QUOTA_COOLDOWN=300

If one Gemini key returns a quota or rate-limit error, the app skips it temporarily and tries the next configured key. Successful calls advance through the keys in order, so _1, _2, _3, and _4 are used in rotation. If Gemini returns temporary 503 UNAVAILABLE high-demand errors, the app retries and then tries the next model in GEMINI_MODELS.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages