Skip to content

finnschwall/ragviewerscratchpad

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RAG Annotation Prototype

FastAPI prototype for retrieval-augmented paper annotation. Given a query (a question or proxy for one), it scores all chunks of a paper and highlights the most relevant passages in a rendered paper view.


Running

cd rag_prototype
pip install fastapi "uvicorn[standard]" jinja2 
#if not already there also: sentence-transformers
uvicorn main:app --reload --port 8000

Open http://localhost:8000 → redirects to the paper view. Enter a query, press Score (or Enter).


Project structure

rag_prototype/
├── config.py            # Paper registry and path constants
├── paper_loader.py      # Loads OCR + chunk JSON; builds block→chunk mapping
├── renderer.py          # OCR sections → annotated HTML
├── main.py              # FastAPI routes
├── retrieval/
│   ├── base.py          # Chunk / ScoredChunk dataclasses + Scorer protocol
│   ├── cross_encoder.py # CrossEncoder implementation (Qwen3-Reranker-0.6B)
│   └── __init__.py      # Swap retrieval backend here — nothing else changes
├── templates/paper.html # Two-pane layout (Jinja2)
└── static/
    ├── style.css        # Layout, highlight gradient, result cards
    └── app.js           # Score flow, highlighting, bidirectional navigation

Key architectural decisions

Retrieval is a pluggable protocol

retrieval/base.py defines a Scorer protocol with a single method:

def score(self, query: str, chunks: list[Chunk]) -> list[ScoredChunk]: ...

The active backend is set in retrieval/__init__.py. Switching from cross-encoder to bi-encoder (or a hybrid) means changing one import.

Block → chunk mapping is 1:1

Each OCR block belongs to at most one chunk. paper_loader.py builds a dict[block_id → chunk_id]. Blocks carry a single data-chunk-id attribute; app.js reads it directly to apply the block's score.

Paper is rendered from the normalized OCR JSON, not from a PDF

The normalized OCR JSON (RAG_research_paper/data/normalized/) has a clean section → content-block hierarchy. renderer.py walks this and emits HTML where every block carries:

  • data-block-id — the OCR pipeline's stable identifier
  • data-chunk-id — the chunk this block belongs to (empty if unmapped)

Tables use the HTML already present in table_body; figures and table images are served via /images/{paper_key}/{filename}.

Highlighting is pure CSS + JS, no re-render

After scoring, app.js sets a CSS custom property --block-hl on each relevant block (interpolating between #e0f0ff and #1a6fa8 by normalised score). The server is not involved — the paper HTML stays in the DOM and only styles change.

Bidirectional navigation

Clicking a chunk card in the results panel scrolls the paper to that chunk's first block. Clicking any block in the paper scrolls the results panel to the corresponding card.

Double-clicking any block in the paper opens a modal showing the raw JSON for that chunk (chunk_id, text, section path, page span, source_block_ids). Score data is merged in when scoring has been run. This works without scoring, making it useful for debugging the chunker directly.


Adding papers

Add an entry to the PAPERS dict in config.py:

"my_paper_key": {
    "ocr_json":    REPO_ROOT / "RAG_research_paper/data/normalized/my_paper_key.json",
    "chunks_json": REPO_ROOT / "RAG_research_paper/data/chunks/my_paper_key.json",
    "images_dir":  REPO_ROOT / "research_paper_ocr/data_ocr/mineru_raw/my_paper_key/.../auto",
}

The paper is then available at /papers/my_paper_key.


Integration path (SEER Django)

Prototype component Django equivalent
config.py PAPERS dict PaperDocument / PaperChunk model query
paper_loader.py QuerySet + serialisation layer
renderer.py Django template tag or mark_safe() helper
/api/{key}/score endpoint HTMX endpoint called from annotation view
retrieval/ module Django service, model loaded in AppConfig.ready()
Image serving Django MEDIA_URL / CDN

The Scorer protocol, Chunk, and ScoredChunk dataclasses are pure Python and import into Django unchanged.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors