Spaces:
Sleeping
Sleeping
File size: 3,327 Bytes
7111e04 b9fa4a6 | 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 | ---
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:
```text
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
```powershell
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`:
```text
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`.
|