# Architecture Documentation ## System Overview The Chest X-Ray Assistant is a distributed web application with a clear separation of concerns: ``` ┌─────────────────────────────────────────────────────────┐ │ USER BROWSER │ │ (Chrome, Safari, Firefox, etc.) │ └────────────────────┬────────────────────────────────────┘ │ HTTPS/443 │ ┌────────────────────▼────────────────────────────────────┐ │ NEXT.JS FRONTEND │ │ Deployed on Vercel │ │ │ │ • Landing page (app/page.tsx) │ │ • Assistant interface (app/assistant/page.tsx) │ │ • Chat UI with image upload │ │ • Medical-grade design system │ │ • Client-side React logic │ └────────────────────┬────────────────────────────────────┘ │ HTTPS API Calls │ POST /api/chat │ GET /health │ ┌────────────────────▼────────────────────────────────────┐ │ FASTAPI BACKEND │ │ Deployed on Railway/Render/AWS │ │ │ │ • RESTful API endpoints │ │ • Request validation │ │ • Image preprocessing │ │ • PyTorch model inference │ │ • Groq LLM integration │ │ • Deterministic output generation │ └─────────────────────────────────────────────────────────┘ ``` ## Component Details ### 1. Frontend (Next.js) **Responsibilities:** - User interface and interaction - Chat interface - Image upload handling - Display of analysis results - Navigation and routing **Key Files:** - `app/page.tsx` - Landing page - `app/assistant/page.tsx` - Main chat interface - `app/layout.tsx` - Root layout - `app/globals.css` - Global styles - `lib/utils.ts` - Utility functions **Data Flow:** ``` User Input → Form State → HTTP Request → Backend API ↓ Response ← State Update ← JSON Response ← Processing ``` **Design System:** ```typescript Colors: - medical-* (50-900): Neutral, professional tones - accent-* (500-600): Primary action colors Components: - Rounded corners (rounded-2xl, rounded-lg) - Soft shadows (shadow-medical, shadow-medical-lg) - Clean typography - Healthcare icons only ``` ### 2. Backend (FastAPI) **Responsibilities:** - API endpoint management - Input validation - Image preprocessing - Model inference - LLM interpretation - Response formatting **Key Files:** - `backend/main.py` - All backend logic **Core Functions:** ```python # 1. Image Preprocessing preprocess_image(image_bytes: bytes) -> torch.Tensor - Load image from bytes - Convert to grayscale (1 channel) - Resize to 224x224 - Convert to tensor - Normalize with fixed values - Return batch tensor # 2. Model Inference run_inference(image_tensor: torch.Tensor) -> Dict[str, float] - Load model (if not loaded) - Run forward pass (no gradient) - Apply sigmoid activation - Return structured probabilities # 3. LLM Interpretation interpret_with_llm(conditions: Dict, message: str) -> str - Format probabilities for prompt - Call Groq API with LLaMA model - Enforce safety constraints - Return educational explanation # 4. Chat Without Image chat_without_image(message: str) -> str - Handle general medical questions - Provide educational info only - No image data implication ``` **Endpoints:** ``` POST /api/chat Input: FormData with optional 'message' and/or 'image' Output: { "response": str, "has_image_analysis": bool, "conditions": Dict[str, float] | null } GET /health Output: { "status": "healthy", "model_loaded": bool, "device": str } ``` ## Deterministic Pipeline The system guarantees deterministic behavior through: ### 1. Preprocessing Determinism ```python # Fixed transformations - no randomness transform = transforms.Compose([ transforms.Resize((224, 224)), # Fixed size transforms.ToTensor(), # Deterministic conversion transforms.Normalize([0.5], [0.5]), # Fixed values ]) ``` ### 2. Model Inference Determinism ```python # Eval mode - no dropout model.eval() # No gradient - deterministic forward pass with torch.no_grad(): outputs = model(image_tensor) # Sigmoid - deterministic activation probabilities = torch.sigmoid(outputs) ``` ### 3. LLM Determinism ```python # Low temperature for consistent outputs temperature=0.3 # Strict system prompt prevents hallucination system_prompt = """ You must NOT hallucinate conditions. You must NOT diagnose. You must ALWAYS include a disclaimer. """ ``` ## Data Flow Diagrams ### Image Analysis Flow ``` User uploads X-ray image ↓ Frontend validates file type and size ↓ FormData sent to backend ↓ Backend validates content-type ↓ preprocess_image() - Load image - Convert to grayscale - Resize to 224x224 - Normalize ↓ run_inference() - Load model (once) - Forward pass (no grad) - Apply sigmoid ↓ interpret_with_llm() - Format probabilities - Call Groq API - Enforce safety ↓ Return JSON to frontend ↓ Display results with disclaimers ``` ### Chat Without Image Flow ``` User types medical question ↓ Frontend sends text message ↓ Backend detects no image ↓ chat_without_image() - Call Groq API - Provide educational info - No image implication ↓ Return response to frontend ↓ Display in chat interface ``` ## Model Architecture ### CheXpert CNN ``` Input: [1, 224, 224] (grayscale image) ↓ ┌─────────────────────────────┐ │ Conv2d(1, 32, 3x3) │ │ BatchNorm2d(32) │ │ ReLU │ │ MaxPool2d(2x2) │ → [32, 112, 112] └─────────────────────────────┘ ↓ ┌─────────────────────────────┐ │ Conv2d(32, 64, 3x3) │ │ BatchNorm2d(64) │ │ ReLU │ │ MaxPool2d(2x2) │ → [64, 56, 56] └─────────────────────────────┘ ↓ ┌─────────────────────────────┐ │ Conv2d(64, 128, 3x3) │ │ BatchNorm2d(128) │ │ ReLU │ │ MaxPool2d(2x2) │ → [128, 28, 28] └─────────────────────────────┘ ↓ ┌─────────────────────────────┐ │ Conv2d(128, 256, 3x3) │ │ BatchNorm2d(256) │ │ ReLU │ │ MaxPool2d(2x2) │ → [256, 14, 14] └─────────────────────────────┘ ↓ Flatten: 256 × 14 × 14 = 50176 ↓ ┌─────────────────────────────┐ │ Linear(50176, 512) │ │ ReLU │ │ Dropout(0.5) │ │ Linear(512, 14) │ → [14] (logits) └─────────────────────────────┘ ↓ Sigmoid activation ↓ Output: [14] probabilities (0-1) ``` ### CheXpert Conditions ``` Index Condition 0 No Finding 1 Enlarged Cardiomediastinum 2 Cardiomegaly 3 Lung Opacity 4 Lung Lesion 5 Edema 6 Consolidation 7 Pneumonia 8 Atelectasis 9 Pneumothorax 10 Pleural Effusion 11 Pleural Other 12 Fracture 13 Support Devices ``` ## Safety Architecture ### 1. Medical Safety **Input Validation:** ```python # Image type check if not image.content_type.startswith('image/'): raise HTTPException(status_code=400) # File size limit (frontend) if (file.size > 10 * 1024 * 1024): alert('File too large') ``` **Output Constraints:** ```python system_prompt = """ CRITICAL RULES (you must follow all): 1. You are NOT a doctor and do NOT provide medical diagnoses 2. DO NOT claim any condition is definitely present or absent 3. Always emphasize uncertainty 4. Include a clear disclaimer at the end 5. Reference only the conditions provided 6. Do NOT hallucinate or invent conditions """ ``` **UI Disclaimers:** ```typescript // Every AI response includes disclaimer

Important: This tool is for educational purposes only...

``` ### 2. Privacy Architecture **No Data Persistence:** ```python # Image bytes processed and discarded image_bytes = await image.read() # → Processed # → Never saved to disk # → Never sent to third-party services ``` **No Logging of Images:** ```python # Only metadata logged logger.info(f"Inference completed") # No image content ``` **Ephemeral Processing:** ``` Image uploaded → Processed → Response sent → Image discarded ``` ### 3. Technical Safety **Error Handling:** ```python try: # Operation except HTTPException: raise # Re-raise HTTP errors except Exception as e: logger.error(f"Error: {str(e)}") raise HTTPException(status_code=500) # Generic error message ``` **CORS Configuration:** ```python app.add_middleware( CORSMiddleware, allow_origins=["*"], # Configure for production allow_methods=["*"], allow_headers=["*"], ) ``` **Environment Variables:** ```bash # Secrets never in code GROQ_API_KEY=from_environment MODEL_PATH=from_environment ``` ## Deployment Architecture ### Frontend (Vercel) ``` User Request ↓ Vercel Edge Network (global) ↓ Next.js Build Output ↓ React Hydration ↓ Interactive UI ``` **Vercel Features Used:** - Serverless functions (not used here - backend is separate) - Static asset optimization - Automatic HTTPS - Global CDN - Zero-configuration deployment ### Backend (Railway) ``` HTTP Request ↓ Railway Container ↓ FastAPI Application ↓ Uvicorn Server ↓ Response ``` **Railway Features Used:** - Container-based deployment - Automatic SSL - Horizontal scaling - Environment variable management - Health checks ## Performance Characteristics ### Latency Breakdown ``` Image Upload: 0.5-2s (depends on file size) Preprocessing: 0.1-0.3s Model Inference: 1-3s (CPU) LLM Generation: 1-2s (Groq API) ───────────────────────── Total: 2.5-7.3s typical ``` ### Throughput - **Frontend:** Unlimited (Vercel scales automatically) - **Backend:** ~10-20 requests/minute per container - **LLM API:** ~30 requests/minute (Groq free tier) ### Scalability **Frontend:** - Auto-scales with traffic - No cold starts for static pages - Serverless functions have cold starts (not used here) **Backend:** - Vertical scaling (more CPU/RAM) - Horizontal scaling (more containers) - Model loaded once per container (warm start) - Connection pooling for LLM API ## Security Considerations ### Attack Surface **Frontend:** - XSS prevention (React escapes by default) - CSRF protection (built-in to Next.js) - Content Security Policy (configured in vercel.json) **Backend:** - Input validation (type checking, size limits) - SQL injection (not applicable - no database) - Command injection (no shell commands) - Rate limiting (can be added with FastAPI) ### Compliance **HIPAA Considerations:** - No PHI stored - No data retention - No transmission to unauthorized parties - Access logs only (metadata) **Data Handling:** ``` User uploads image ↓ Processed in memory ↓ Analysis results generated ↓ Response sent to user ↓ Image discarded ↓ No persistence ``` ## Monitoring and Observability ### Logging Strategy ```python # Backend logging logger.info("Model loaded successfully") logger.error(f"Inference error: {str(e)}") # No image content logged ``` ### Health Checks ```python @app.get("/health") async def health_check(): return { "status": "healthy", "model_loaded": model is not None, "device": INFERENCE_DEVICE, } ``` ### Metrics to Monitor - API response time - Error rate - Groq API quota usage - Backend memory usage - Model loading time - LLM generation time ## Extensibility ### Adding New Models 1. Update model architecture in `backend/main.py` 2. Update preprocessing if needed 3. Update output classes 4. Retrain model 5. Update checkpoint file 6. Test thoroughly ### Adding New Features **Frontend:** - Create new pages/routes - Add components - Follow existing patterns - Ensure medical-grade design **Backend:** - Add new endpoints - Update API documentation - Maintain deterministic behavior - Add appropriate validation ## Technology Justification ### Why Next.js? - Server-side rendering for SEO - API routes for backend communication - Built-in optimization - Vercel deployment integration ### Why FastAPI? - Type safety - Automatic API documentation - Async support - Easy validation ### Why PyTorch? - Medical imaging standard - CheXpert model compatibility - Flexible architecture - Strong community ### Why Groq? - Fast inference - LLaMA model quality - Cost-effective - Reliable API ## Constraints and Limitations ### Technical Limitations 1. **Model Accuracy**: mAUROC ~0.49 (baseline CheXpert) 2. **Inference Speed**: CPU-based (1-3s per image) 3. **LLM Latency**: Depends on Groq API (1-2s) 4. **Image Size**: Limited to 10MB uploads 5. **Concurrent Users**: Limited by backend resources ### Design Constraints 1. **No Glassmorphism**: Medical-grade design only 2. **No Dark Themes**: Clean, light UI 3. **No Sci-Fi Elements**: Healthcare icons only 4. **No Diagnostic Claims**: Educational only 5. **No Data Persistence**: Privacy-first ### Operational Constraints 1. **Separate Deployments**: Frontend (Vercel) + Backend (Railway) 2. **Model File Size**: Must be uploaded separately 3. **Groq API Key**: Required and must be configured 4. **PyTorch Installation**: Requires compatible environment --- This architecture ensures the system is: - **Deterministic**: Same input → same output - **Safe**: Medical-grade constraints - **Scalable**: Can handle production traffic - **Maintainable**: Clear separation of concerns - **Deployable**: Production-ready on Vercel/Railway