Spaces:
Sleeping
Sleeping
| # MediShield AI Document Classifier β Architecture & Design | |
| Complete technical architecture documentation for the insurance document classification system. | |
| --- | |
| ## π System Architecture Overview | |
| ``` | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β Browser / Client β | |
| β Drag & Drop UI Β· frontend/index.html β | |
| ββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββ | |
| β POST /classify (multipart/form-data) | |
| βΌ | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β FastAPI Server Β· src/api.py Β· Port 8000 β | |
| β β | |
| β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β | |
| β β asyncio.gather β Concurrent Processing β β | |
| β β β β | |
| β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β | |
| β β β Orchestrator: src/classifier.py β β β | |
| β β β β β β | |
| β β β ββββββββββββββββ bill_* ββββββββββββββββββββββββ β β β | |
| β β β β Stage 1 ββββββββββββΆβ doc_type = "bill" β β β β | |
| β β β β Rules Engine β β method = "rules" β β β β | |
| β β β β β ββββββββββββββββββββββββ β β β | |
| β β β ββββββββ¬ββββββββ β β β | |
| β β β β others β β β | |
| β β β βΌ β β β | |
| β β β ββββββββββββββββ KYC kw ββββββββββββββββββββββββ β β β | |
| β β β β Stage 2 ββββββββββββΆβ doc_type = "kyc" β β β β | |
| β β β β KYC OCR β β method = "ocr" β β β β | |
| β β β β (easyocr) β ββββββββββββββββββββββββ β β β | |
| β β β ββββββββ¬ββββββββ β β β | |
| β β β β no KYC match β β β | |
| β β β βΌ β β β | |
| β β β ββββββββββββββββ ββββββββββββββββββββββββ β β β | |
| β β β β Stage 3 ββββββββββββΆβ doc_type = "image" β β β β | |
| β β β β Gemini LLM β β sub_type = category β β β β | |
| β β β β β β method = "llm" β β β β | |
| β β β ββββββββββββββββ ββββββββββββββββββββββββ β β β | |
| β β β β β β | |
| β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β | |
| β β β β | |
| β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β | |
| β β β Monitoring: src/monitoring.py β β β | |
| β β β @traceable spans Β· token counts Β· latency metrics β β β | |
| β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β | |
| β β β β | |
| β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β | |
| β β | |
| β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β | |
| β β Response JSON: { β β | |
| β β filename, doc_type, sub_type, method, β β | |
| β β latency_ms, tokens_used, confidence_score β β | |
| β β } β β | |
| β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ¬βββ β | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββΌβββββββ | |
| β | |
| βΌ | |
| ββββββββββββββββββββββββ | |
| β Frontend UI β | |
| β Results table with β | |
| β color-coded badges β | |
| ββββββββββββββββββββββββ | |
| ``` | |
| --- | |
| ## π Three-Stage Classification Pipeline | |
| ### Stage 1: Rules Engine (src/rules_engine.py) | |
| **Trigger:** Filename analysis | |
| **Method:** Regex pattern matching | |
| **Cost:** $0 | |
| **Speed:** <1ms | |
| **Success Rate:** ~70% of documents | |
| ```python | |
| def rules_engine(filename: str, image_data: bytes) -> Optional[Dict]: | |
| """ | |
| Match documents by filename patterns. | |
| Fast, zero-cost, high-precision. | |
| """ | |
| # Example patterns | |
| if filename.startswith("bill_"): | |
| return { | |
| "doc_type": "bill", | |
| "method": "rules", | |
| "confidence": 1.0, | |
| "latency_ms": 0.5 | |
| } | |
| return None | |
| ``` | |
| **Patterns matched:** | |
| - `bill_*` β doc_type = "bill" | |
| - `invoice_*` β doc_type = "invoice" | |
| - `receipt_*` β doc_type = "receipt" | |
| **When to use:** Fast, immediate classification when metadata is reliable. | |
| --- | |
| ### Stage 2: KYC OCR Detection (src/kyc_detector.py) | |
| **Trigger:** Documents unmatched at Stage 1 | |
| **Method:** easyOCR text extraction + keyword matching | |
| **Cost:** ~$0.001 per document | |
| **Speed:** 1-2 seconds | |
| **Success Rate:** ~20% of remaining documents (~6% of total) | |
| ```python | |
| def kyc_detector(image_data: bytes) -> Optional[Dict]: | |
| """ | |
| Detect KYC documents (Aadhaar, PAN, Passport) via OCR. | |
| Medium speed, cheap, reliable for document types. | |
| """ | |
| # Use easyOCR to extract text | |
| ocr_text = easyocr.recognize(image_data) | |
| # Match against KYC keywords | |
| kyc_keywords = ["aadhaar", "pan", "passport", "voter id", "driving license"] | |
| if any(keyword in ocr_text.lower() for keyword in kyc_keywords): | |
| return { | |
| "doc_type": "kyc", | |
| "sub_type": detect_kyc_subtype(ocr_text), | |
| "method": "ocr", | |
| "confidence": 0.95, | |
| "latency_ms": 1500 | |
| } | |
| return None | |
| ``` | |
| **Document types detected:** | |
| - Aadhaar β sub_type = "aadhaar" | |
| - PAN β sub_type = "pan" | |
| - Passport β sub_type = "passport" | |
| - Voter ID β sub_type = "voter_id" | |
| - Driving License β sub_type = "driving_license" | |
| **When to use:** When OCR is fast enough and keyword matching is reliable. | |
| --- | |
| ### Stage 3: Gemini LLM Classification (src/llm_classifier.py) | |
| **Trigger:** All documents unmatched at Stages 1 & 2 | |
| **Method:** Gemini API (gemma-4-31b-it) | |
| **Cost:** ~$0.01 per document | |
| **Speed:** 2-4 seconds | |
| **Success Rate:** ~10% of documents (only complex cases) | |
| ```python | |
| def llm_classifier(image_data: bytes, ocr_text: str) -> Dict: | |
| """ | |
| Full AI classification for complex/ambiguous documents. | |
| Slow, expensive, but handles edge cases. | |
| """ | |
| prompt = f""" | |
| Classify this insurance document. | |
| OCR extracted text (may be partial/noisy): | |
| {ocr_text} | |
| Image provided for visual analysis. | |
| Respond with JSON: | |
| {{ | |
| "doc_type": "image|letter|form|other", | |
| "sub_type": "prescription|lab_report|claim_form|...", | |
| "confidence": 0.0-1.0, | |
| "reasoning": "brief explanation" | |
| }} | |
| """ | |
| response = gemini_api.generate( | |
| image=image_data, | |
| text=prompt | |
| ) | |
| return { | |
| "doc_type": response.doc_type, | |
| "sub_type": response.sub_type, | |
| "method": "llm", | |
| "confidence": response.confidence, | |
| "latency_ms": elapsed_time, | |
| "tokens_used": response.usage.total_tokens | |
| } | |
| ``` | |
| **Document types classified:** | |
| - Prescriptions | |
| - Lab reports | |
| - Claim forms | |
| - Medical letters | |
| - X-ray reports | |
| - Test certificates | |
| - Insurance documents (various) | |
| **When to use:** Complex, ambiguous cases where Rules + OCR aren't sufficient. | |
| --- | |
| ## β‘ Async Concurrency Architecture | |
| ### Request Flow | |
| ``` | |
| FastAPI Handler (src/api.py) | |
| β | |
| ββ Read multipart form data | |
| ββ Extract file list: [file1.pdf, file2.pdf, ...] | |
| β | |
| βΌ | |
| asyncio.gather([ | |
| executor.submit(classify_document, file1), | |
| executor.submit(classify_document, file2), | |
| ... | |
| ]) | |
| β | |
| ββ Runs all files in PARALLEL thread pool | |
| Each file: Stage1 β Stage2 β Stage3 (cascading, any can short-circuit) | |
| β | |
| βΌ | |
| Collect results, emit LangSmith traces | |
| β | |
| βΌ | |
| Return JSON response | |
| ``` | |
| ### Performance Characteristics | |
| **Scenario A: All Stage 1 matches (bills with bill_ prefix)** | |
| - Input: 10 bills | |
| - Processing: 10 Γ <1ms = ~10ms total | |
| - Response time: ~100ms (overhead) | |
| **Scenario B: Mixed (70% rules, 20% OCR, 10% LLM)** | |
| - Input: 100 documents | |
| - Stage 1: 70 docs Γ <1ms = ~0.07s | |
| - Stage 2: 20 docs Γ 1.5s = ~30s parallel (1 thread per doc) | |
| - Stage 3: 10 docs Γ 3s = ~30s parallel (1 thread per doc) | |
| - **Total: ~30s** (OCR & LLM run in parallel, limited by slowest) | |
| **Optimization:** With N worker threads and M documents: | |
| - If M β€ N: perfect parallelism, time β max(latencies) | |
| - If M > N: queued, time β sum(latencies) / N | |
| --- | |
| ## π Monitoring & Observability | |
| ### LangSmith Tracing (@traceable decorator) | |
| Each stage emits structured spans to LangSmith: | |
| ```python | |
| from langsmith import traceable | |
| @traceable(name="rules_engine") | |
| def rules_engine(filename: str): | |
| # Automatic tracing: | |
| # - Execution time | |
| # - Input/output | |
| # - Errors | |
| pass | |
| @traceable(name="kyc_ocr") | |
| def kyc_detector(image_data: bytes): | |
| # Token usage tracked automatically | |
| # Latency metrics collected | |
| pass | |
| @traceable(name="gemini_llm") | |
| def llm_classifier(image_data: bytes): | |
| # Detailed LLM call tracing | |
| # Token usage: input + output | |
| # Model name, parameters, latency | |
| pass | |
| ``` | |
| ### Metrics Collected | |
| **Per-request metrics:** | |
| - Request ID | |
| - Number of documents | |
| - Document types (histogram) | |
| - Total latency (ms) | |
| - Breakdown by stage | |
| - Token usage (for LLM stage) | |
| - Classification confidence scores | |
| **Real-time dashboards:** | |
| - Azure Monitor: logs, alerts, performance | |
| - LangSmith: traces, token usage, latency percentiles | |
| --- | |
| ## π Deployment Architecture | |
| ### Azure Container Apps Stack | |
| ``` | |
| βββββββββββββββββββββββββββββββββββββββββββ | |
| β Azure Container Apps (ACA) β | |
| β - 0.5 vCPU, 2GB RAM per replica β | |
| β - Min 1 replica, Max 3 (auto-scale) β | |
| β - HTTPS endpoint β | |
| β - Auto-scaling on CPU/memory β | |
| ββββββββββββββββββ¬βββββββββββββββββββββββββββ | |
| β | |
| ββββββββββββββΌβββββββββββββ | |
| β β β | |
| βΌ βΌ βΌ | |
| ββββββββββ ββββββββββ ββββββββββ | |
| βReplica1β βReplica2β βReplica3β | |
| β(running) β(standby) β(standby) | |
| ββββββββββ ββββββββββ ββββββββββ | |
| β | |
| βββββββββββββββββββ¬ββββββββββββββββββ | |
| β β | |
| βββββββββββββββββββΌβββββββ ββββββββββΌβββββββ | |
| β Azure Monitor β β LangSmith β | |
| β - Logs β β - Traces β | |
| β - Performance β β - Token usageβ | |
| β - Alerts β β - Latency β | |
| ββββββββββββββββββββββββββ βββββββββββββββββ | |
| ``` | |
| ### Container Image | |
| **Dockerfile:** | |
| ```dockerfile | |
| FROM python:3.12-slim | |
| WORKDIR /app | |
| # Install dependencies | |
| COPY requirements.txt . | |
| RUN pip install -r requirements.txt | |
| # Copy source | |
| COPY src/ ./src/ | |
| COPY frontend/ ./frontend/ | |
| # Expose port | |
| EXPOSE 8000 | |
| # Run with uvicorn | |
| CMD ["uvicorn", "src.api:app", "--host", "0.0.0.0", "--port", "8000"] | |
| ``` | |
| **Image stored in:** Azure Container Registry (medishieldacr.azurecr.io) | |
| --- | |
| ## π Security Architecture | |
| ### API Security | |
| - **HTTPS only** via Azure Container Apps | |
| - **CORS:** Configured for frontend origin | |
| - **File validation:** Size limits, MIME type checks | |
| - **Input sanitization:** Filename validation, size bounds | |
| ### Data Privacy | |
| - **No persistent storage:** Processed files deleted after classification | |
| - **Transient memory:** Results live only in response | |
| - **Encrypted in transit:** TLS 1.2+ | |
| - **Audit logs:** All classifications logged to Azure Monitor | |
| ### Secrets Management | |
| - **Environment variables** via Azure Container Apps secrets | |
| - **Gemini API key:** Never in code, via env | |
| - **LangSmith key:** Via env, read-only service key | |
| --- | |
| ## π Scalability Analysis | |
| ### Current Setup | |
| - **Max throughput:** ~1000 documents/hour (with 1 replica, max 3s per doc) | |
| - **Bottleneck:** Gemini API rate limits (~100 requests/minute) | |
| - With 10% of docs hitting Gemini β ~100 docs/min Γ 10 = 1000 docs/min | |
| - Actual: limited by API quotas | |
| ### Scaling Options | |
| 1. **Increase replicas:** Auto-scaling to 3 replicas β 3x throughput | |
| 2. **Batch processing:** Collect documents, process asynchronously β decoupled throughput | |
| 3. **Queue-based:** Azure Service Bus β robust handling of traffic spikes | |
| 4. **Cache results:** Store common patterns (frequent filenames) β reduce processing | |
| --- | |
| ## π§ͺ Testing Strategy | |
| ### 117 Passing Tests | |
| **Unit tests (70):** | |
| - Stage 1 rules engine (10 test cases) | |
| - Stage 2 OCR patterns (15 test cases) | |
| - Stage 3 LLM prompt formatting (10 test cases) | |
| - Async orchestration (15 test cases) | |
| - Monitoring/tracing (10 test cases) | |
| - Response validation (10 test cases) | |
| **Integration tests (30):** | |
| - End-to-end classification pipeline (10 test cases) | |
| - Multi-file concurrent processing (5 test cases) | |
| - Error handling & retry logic (5 test cases) | |
| - API endpoint validation (5 test cases) | |
| - LangSmith trace verification (5 test cases) | |
| **Performance tests (10):** | |
| - Latency benchmarks (Stage 1, 2, 3) | |
| - Concurrency stress tests | |
| - Memory usage profiling | |
| **Edge cases (7):** | |
| - Empty files | |
| - Corrupt images | |
| - Unicode filenames | |
| - Very large files | |
| - Timeout handling | |
| --- | |
| ## π Cost Model | |
| ### Per-Document Costs | |
| | Stage | Cost | Trigger | Frequency | | |
| |-------|------|---------|-----------| | |
| | Stage 1 (Rules) | $0.00 | Filename pattern | 70% | | |
| | Stage 2 (OCR) | ~$0.001 | easyOCR library | 20% | | |
| | Stage 3 (LLM) | ~$0.01 | Gemini API call | 10% | | |
| **Expected cost per document:** (0.7 Γ $0) + (0.2 Γ $0.001) + (0.1 Γ $0.01) = **$0.0013** | |
| **Annual cost (1M documents):** 1,000,000 Γ $0.0013 = **$1,300** (AI costs only) | |
| **Infrastructure:** Azure Container Apps ~$50-100/month (compute + storage) | |
| **Total monthly:** ~$200 (AI + compute + monitoring) | |
| ### vs. Manual Labor | |
| - **Manual operator:** ~$3,000/month salary | |
| - **12 operators:** $36,000/month | |
| - **2 remaining operators:** $6,000/month | |
| - **Savings:** ~$30,000/month | |
| **ROI:** Pays for itself in <1 week of savings. | |
| --- | |
| ## π Continuous Improvement | |
| ### Metrics to Monitor | |
| 1. **Accuracy by stage:** Track Stage 3 confidence scores | |
| 2. **False negatives:** Documents incorrectly classified at Stage 1 or 2 | |
| 3. **Latency trends:** Identify performance regressions | |
| 4. **Token usage:** Monitor Gemini API efficiency | |
| 5. **Cost per document:** Optimize stage cascade | |
| ### Feedback Loop | |
| ``` | |
| Production metrics β Identify misclassifications | |
| β | |
| Add new rules β Retrain Stage 1/2 | |
| β | |
| Deploy β Test in staging | |
| β | |
| Compare accuracy vs production | |
| β | |
| If better: deploy; else: revert | |
| ``` | |
| --- | |
| ## π Related Documentation | |
| - [WORKFLOW_DIAGRAM.md](./WORKFLOW_DIAGRAM.md) β Mermaid diagrams | |
| - [DIAGRAMS.md](./DIAGRAMS.md) β Interactive Excalidraw diagrams | |
| - [README.md](./README.md) β Project overview | |
| - [src/api.py](./src/api.py) β API implementation | |
| - [src/classifier.py](./src/classifier.py) β Pipeline orchestration | |
| --- | |
| Generated: April 26, 2026 | |
| Document version: 2.0 (architecture diagrams added) | |