setu / docs /pdf_processing_architecture.md
khagu's picture
chore: finally untrack large database files
3998131
# PDF Processing System Architecture
## System Overview
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Frontend (Next.js) β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ PDF Upload Component β”‚ β”‚
β”‚ β”‚ β€’ File input β”‚ β”‚
β”‚ β”‚ β€’ Drag & drop β”‚ β”‚
β”‚ β”‚ β€’ Progress indicator β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
HTTP/FormData
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ FastAPI Backend β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ POST /api/v1/process-pdf β”‚
β”‚ └─► Extract sentences only β”‚
β”‚ β”‚
β”‚ POST /api/v1/process-pdf-to-bias β”‚
β”‚ └─► Extract + Analyze bias (complete pipeline) β”‚
β”‚ β”‚
β”‚ GET /api/v1/pdf-health β”‚
β”‚ └─► Service status check β”‚
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚
β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ PDF Bytes β”‚ β”‚ PDFProcessor β”‚
β”‚ β”‚ β”‚ (utility/) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Step 1: Extract Text β”‚
β”‚ PyMuPDF (fitz) β”‚
β”‚ β€’ Read PDF pages β”‚
β”‚ β€’ Extract raw text β”‚
β”‚ β€’ Handle multi-page β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Step 2: Clean Text β”‚
β”‚ Regex Processing β”‚
β”‚ β€’ Remove extra whitespace β”‚
β”‚ β€’ Normalize formatting β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Step 3: Segment Sentences β”‚
β”‚ Nepali-aware Regex β”‚
β”‚ β€’ Split on ΰ€¦ΰ€£ΰ₯ΰ€‘ (ΰ₯€) β”‚
β”‚ β€’ Handle punctuation β”‚
β”‚ β€’ Filter short fragments β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Step 4: Refine (Optional) β”‚
β”‚ Mistral LLM API β”‚
β”‚ β€’ Correct segmentation β”‚
β”‚ β€’ Remove duplicates β”‚
β”‚ β€’ JSON formatting β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚
β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Sentences β”‚ β”‚ Return JSON β”‚
β”‚ List β”‚ β”‚ Array β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚ β”‚
β”‚ β–Ό β–Ό
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚ Option A: β”‚ β”‚ Option B: β”‚
β”‚ β”‚ Return to β”‚ β”‚ Pass to Bias β”‚
β”‚ β”‚ User β”‚ β”‚ Detection β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
β”‚ β–Ό
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚ Bias Detection Modelβ”‚
β”‚ β”‚ DistilBERT Nepali β”‚
β”‚ β”‚ (module_b) β”‚
β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ β€’ Classify sentence β”‚
β”‚ β”‚ β€’ 11 categories: β”‚
β”‚ β”‚ - neutral β”‚
β”‚ β”‚ - gender β”‚
β”‚ β”‚ - caste β”‚
β”‚ β”‚ - religion β”‚
β”‚ β”‚ - political β”‚
β”‚ β”‚ - age β”‚
β”‚ β”‚ - disability β”‚
β”‚ β”‚ - appearance β”‚
β”‚ β”‚ - social status β”‚
β”‚ β”‚ - religiosity β”‚
β”‚ β”‚ - ambiguity β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Response to User β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β€’ Extracted sentences β”‚
β”‚ β€’ Bias classification results β”‚
β”‚ β€’ Confidence scores β”‚
β”‚ β€’ Biased/neutral counts β”‚
β”‚ β€’ Processing metadata β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Frontend Display β”‚
β”‚ β€’ Show results β”‚
β”‚ β€’ Highlight biases β”‚
β”‚ β€’ Display stats β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
## Data Flow Diagram
```
INPUT: PDF File
β”‚
β”œβ”€ Metadata
β”‚ β”œβ”€ Filename
β”‚ β”œβ”€ File size
β”‚ └─ Upload timestamp
β”‚
└─ Binary content
β”‚
β–Ό
PDFProcessor.process_pdf_from_bytes()
β”‚
β”œβ”€ extract_text_from_pdf()
β”‚ β”‚ Uses: PyMuPDF.fitz.open()
β”‚ β”‚ Output: Raw text string + page count
β”‚ └─ ~200-500ms
β”‚
β”œβ”€ clean_text()
β”‚ β”‚ Uses: Regex replacements
β”‚ β”‚ Output: Normalized text string
β”‚ └─ ~50ms
β”‚
β”œβ”€ split_into_sentences()
β”‚ β”‚ Uses: Nepali-aware regex patterns
β”‚ β”‚ Output: List[sentences]
β”‚ └─ ~50-150ms
β”‚
└─ refine_sentences_with_llm() [OPTIONAL]
β”‚ Uses: Mistral API
β”‚ Input: JSON-formatted sentences
β”‚ Output: Refined List[sentences]
└─ ~2-5s (includes API latency)
β–Ό
OUTPUT 1 (Extract Only):
{
"success": true,
"sentences": ["ΰ€΅ΰ€Ύΰ€•ΰ₯ΰ€― ΰ₯§", "ΰ€΅ΰ€Ύΰ€•ΰ₯ΰ€― ΰ₯¨", ...],
"total_sentences": 15,
"raw_text": "ΰ€«ΰ₯ΰ€² text...",
"filename": "doc.pdf"
}
OUTPUT 2 (Extract + Bias):
{
"success": true,
"total_sentences": 15,
"biased_count": 2,
"neutral_count": 13,
"results": [
{
"sentence": "ΰ€΅ΰ€Ύΰ€•ΰ₯ΰ€― ΰ₯§",
"category": "neutral",
"confidence": 0.95,
"is_biased": false
},
...
],
"filename": "doc.pdf"
}
```
## Component Architecture
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ utility/ module β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ PDFProcessor Class β”‚
β”‚ β”œβ”€ __init__(mistral_api_key) β”‚
β”‚ β”‚ └─ Initialize MistralClient β”‚
β”‚ β”‚ β”‚
β”‚ β”œβ”€ extract_text_from_pdf(pdf_path) β”‚
β”‚ β”‚ β”œβ”€ fitz.open(pdf_path) β”‚
β”‚ β”‚ β”œβ”€ Iterate pages β”‚
β”‚ β”‚ β”œβ”€ get_text("text") β”‚
β”‚ β”‚ └─ Return: raw text β”‚
β”‚ β”‚ β”‚
β”‚ β”œβ”€ clean_text(text) β”‚
β”‚ β”‚ β”œβ”€ Remove newlines β”‚
β”‚ β”‚ β”œβ”€ Normalize spaces β”‚
β”‚ β”‚ └─ Return: cleaned text β”‚
β”‚ β”‚ β”‚
β”‚ β”œβ”€ split_into_sentences(text) β”‚
β”‚ β”‚ β”œβ”€ Apply Nepali regex patterns β”‚
β”‚ β”‚ β”œβ”€ Filter short fragments β”‚
β”‚ β”‚ └─ Return: sentence list β”‚
β”‚ β”‚ β”‚
β”‚ β”œβ”€ refine_sentences_with_llm(sentences) β”‚
β”‚ β”‚ β”œβ”€ Format as JSON β”‚
β”‚ β”‚ β”œβ”€ Send to Mistral API β”‚
β”‚ β”‚ β”œβ”€ Parse JSON response β”‚
β”‚ β”‚ └─ Return: refined sentences β”‚
β”‚ β”‚ β”‚
β”‚ β”œβ”€ process_pdf(pdf_path, refine_with_llm) β”‚
β”‚ β”‚ └─ Complete pipeline (file path) β”‚
β”‚ β”‚ β”‚
β”‚ └─ process_pdf_from_bytes(pdf_bytes, refine_with_llm) β”‚
β”‚ └─ Complete pipeline (bytes) β”‚
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ api/routes/ module β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ pdf_processing.py (FastAPI Routes) β”‚
β”‚ β”œβ”€ POST /api/v1/process-pdf β”‚
β”‚ β”‚ β”œβ”€ Receive: file (UploadFile), refine_with_llm β”‚
β”‚ β”‚ β”œβ”€ Call: PDFProcessor.process_pdf_from_bytes() β”‚
β”‚ β”‚ └─ Return: PDFProcessingResponse β”‚
β”‚ β”‚ β”‚
β”‚ β”œβ”€ POST /api/v1/process-pdf-to-bias β”‚
β”‚ β”‚ β”œβ”€ Receive: file, refine_with_llm, confidence_threshold β”‚
β”‚ β”‚ β”œβ”€ Call: PDFProcessor.process_pdf_from_bytes() β”‚
β”‚ β”‚ β”œβ”€ Call: run_bias_detection() β”‚
β”‚ β”‚ └─ Return: PDFToBiasDetectionResponse β”‚
β”‚ β”‚ β”‚
β”‚ └─ GET /api/v1/pdf-health β”‚
β”‚ β”œβ”€ Check: PDFProcessor availability β”‚
β”‚ β”œβ”€ Check: Mistral client status β”‚
β”‚ └─ Return: health status β”‚
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ api/schemas.py (Pydantic Models) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ PDFProcessingRequest / Response β”‚
β”‚ PDFToBiasDetectionRequest / Response β”‚
β”‚ BiasResult (reused from bias_detection) β”‚
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ External Dependencies β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ PyMuPDF (fitz) β”‚
β”‚ └─ PDF text extraction β”‚
β”‚ β”‚
β”‚ Mistral API Client β”‚
β”‚ └─ LLM-based sentence refinement β”‚
β”‚ β”‚
β”‚ FastAPI β”‚
β”‚ └─ API framework (from module_a) β”‚
β”‚ β”‚
β”‚ Pydantic β”‚
β”‚ └─ Data validation β”‚
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
## Processing Timeline
```
Timeline for Single PDF (~10 KB):
Time Component Duration Cumulative
────────────────────────────────────────────────────
0ms β”œβ”€ API receives upload ~5ms 5ms
β”‚
5ms β”œβ”€ Read bytes ~10ms 15ms
β”‚
15ms β”œβ”€ PyMuPDF extraction ~200ms 215ms
β”‚
215ms β”œβ”€ Text cleaning ~30ms 245ms
β”‚
245ms β”œβ”€ Sentence split ~100ms 345ms
β”‚
345ms β”œβ”€ LLM refinement ~3500ms 3845ms
β”‚ (if enabled)
β”‚
3845msβ”œβ”€ Bias detection ~500ms 4345ms
β”‚ (if enabled)
β”‚
4345ms└─ Return response ~5ms 4350ms
Total Time:
β”œβ”€ With LLM + Bias: ~4.3 seconds
β”œβ”€ With LLM only: ~3.8 seconds
β”œβ”€ Without LLM: ~0.35 seconds
└─ Bias only: ~0.5 seconds (sentence extraction)
```
## Error Handling Flow
```
API Request
β”‚
β”œβ”€ Validate file
β”‚ β”œβ”€ Is PDF? β†’ No β†’ 400 Bad Request
β”‚ β”œβ”€ Is empty? β†’ Yes β†’ 400 Bad Request
β”‚ └─ Is valid? β†’ Continue
β”‚
└─ Process PDF
β”œβ”€ Extract text
β”‚ β”œβ”€ File not found? β†’ FileNotFoundError β†’ 500
β”‚ β”œβ”€ Permission denied? β†’ Exception β†’ 500
β”‚ └─ Success? β†’ Continue
β”‚
β”œβ”€ Split sentences
β”‚ β”œβ”€ No sentences? β†’ Warning in response β†’ 200 (empty results)
β”‚ └─ Success? β†’ Continue
β”‚
└─ Refine with LLM (if enabled)
β”œβ”€ API key missing? β†’ Warning, use regex β†’ 200 (fallback)
β”œβ”€ Network error? β†’ Warning, use regex β†’ 200 (fallback)
β”œβ”€ Invalid JSON? β†’ Warning, use regex β†’ 200 (fallback)
└─ Success? β†’ Return refined sentences β†’ 200
```
## State Diagram
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Idle β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
User uploads PDF
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Validating β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚
Invalid Valid
β”‚ β”‚
β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Error β”‚ β”‚ Extracting β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚
Success No Text
β”‚ β”‚
β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚Splitting β”‚ β”‚ Error β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚
Success No Sentences
β”‚ β”‚
β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚Refining β”‚ β”‚ Error β”‚
β”‚(Optional) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚
Success Failed
β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ β”‚
β–Ό β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Formatting β”‚ β”‚Fallbackβ”‚
β”‚Response β”‚ β”‚(Regex) β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Bias Detection β”‚
β”‚ (if enabled) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚
Success Error
β”‚ β”‚
β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚Format β”‚ β”‚Return β”‚
β”‚Response β”‚ β”‚Error β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
β”‚ β”‚
β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚Send Response β”‚
β”‚to Client β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
## Integration Points
```
Frontend (Next.js)
β”‚
β”œβ”€β–Ί /api/v1/process-pdf
β”‚ └─ Use for: Sentence extraction only
β”‚
β”œβ”€β–Ί /api/v1/process-pdf-to-bias
β”‚ └─ Use for: Full analysis (PDF β†’ Bias)
β”‚
└─► /api/v1/pdf-health
└─ Use for: Service status check
Internal Integration
β”‚
β”œβ”€β–Ί PDFProcessor class
β”‚ └─ Use in: Custom workflows
β”‚
└─► run_bias_detection() function
└─ Use in: Direct bias analysis
```
---
This architecture provides:
βœ… Scalable processing pipeline
βœ… Clear separation of concerns
βœ… Reusable components
βœ… Error resilience
βœ… Performance optimization options
βœ… Easy integration points