Spaces:
Sleeping
Sleeping
| 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`. | |