| # System Architecture |
|
|
| VisionSeq is built as a decoupled, service-oriented system: a Next.js frontend, a FastAPI backend, and an in-process PyTorch inference service. This document describes each component, their responsibilities, and how a request flows end-to-end. |
|
|
| **Live system:** [huggingface.co/spaces/Hardik-25/VisionSeq](https://huggingface.co/spaces/Hardik-25/VisionSeq) |
|
|
| --- |
|
|
| ## Architecture Diagram |
|
|
| ```mermaid |
| graph TD |
| User([User Client]) -->|Web UI| FE[Next.js Frontend] |
| FE -->|REST API Requests| BE[FastAPI Backend] |
| BE -->|Preprocessed Tensor| INF[PyTorch Inference Service] |
| INF -->|Model weights| Model[ResNet-18 Multi-Head Classifier] |
| Model -->|Logits| Dec[Character Decoder] |
| Dec -->|Prediction & Confidence| BE |
| BE -->|JSON Response| FE |
| ``` |
|
|
| ## Design Principles |
|
|
| - **Separation of concerns:** the frontend never touches the model; it only speaks REST/JSON to the backend. The backend never renders UI; it only validates, orchestrates, and serves predictions. |
| - **Single model instance:** the model is loaded exactly once per process, not per request, eliminating repeated disk I/O and weight-loading latency from the hot path. |
| - **Non-blocking request handling:** CPU/GPU-bound work never runs directly on FastAPI's async event loop β it's offloaded to a threadpool so I/O-bound requests (like concurrent uploads) are never starved. |
| - **Fail fast, fail loud:** if model weights are missing or corrupted, the server refuses to start rather than serving broken predictions. |
|
|
| --- |
|
|
| ## Component Details |
|
|
| ### 1. Frontend β Next.js + Tailwind CSS |
|
|
| - **Presentation:** Responsive dashboard with glassmorphism styling, Framer Motion micro-interactions, and a live canvas preview of the uploaded image. |
| - **API integration:** Async client with support for both single and batch prediction, rendering per-character confidence breakdowns alongside the decoded sequence. |
| - **Config:** Backend base URL is injected via `NEXT_PUBLIC_API_URL`, keeping the frontend environment-agnostic across local, staging, and production deployments. |
|
|
| ### 2. Backend β FastAPI |
|
|
| - **API surface:** JSON endpoints for single prediction, batch prediction, model metadata, and health monitoring (see [API.md](API.md)). |
| - **Middleware:** A boundary-level `Content-Length` check rejects oversized uploads before the body is read, backed by a token-bucket rate limiter to protect compute resources from abuse. |
| - **Threadpool scheduling:** Preprocessing and inference are wrapped in `run_in_threadpool()`, keeping the event loop free to accept and parse concurrent requests while CPU/GPU work happens on background threads. |
|
|
| ### 3. ML Inference Service β PyTorch & ResNet-18 |
|
|
| - **Lifecycle:** Instantiated once at startup as a singleton (`InferenceService`), avoiding per-request model-loading overhead. |
| - **Execution mode:** Runs in `eval()` mode; a dummy `[1, 1, 100, 200]` tensor is pushed through the model during boot to trigger kernel compilation and CUDA context initialization ahead of the first real request. |
| - **Device selection:** Automatically targets `cuda` when available, with a transparent fallback to CPU β no configuration required to run in either environment. |
| - **Multi-position head:** CAPTCHA decoding is framed as 6 concurrent per-position classification tasks. A ResNet-18 backbone (modified for 1-channel input) is pooled to `[B, 512, 6]` and classified into a shared 31-class vocabulary per position β see the [Modeling Approach](../README.md#modeling-approach) section of the README for the full rationale. |
|
|
| --- |
|
|
| ## Request Data Pipeline |
|
|
| | Step | Stage | Detail | |
| |---|---|---| |
| | 1 | **Upload** | Client submits a distorted CAPTCHA image via `multipart/form-data`. | |
| | 2 | **Defensive check** | Middleware validates request size against `Content-Length` and checks the caller's rate-limit bucket. | |
| | 3 | **MIME verification** | API confirms the declared content type starts with `image/`. | |
| | 4 | **Streaming read** | Image bytes are read in 64KB chunks, aborting if the stream exceeds the 5MB limit β protects against missing/spoofed `Content-Length` headers. | |
| | 5 | **Structural integrity** | `PIL.Image.verify()` confirms the file is a physically valid image, not a disguised payload. | |
| | 6 | **Preprocessing** (threadpool) | Grayscale conversion, resize to `100Γ200`, normalization, tensor conversion to `[1, 1, 100, 200]`. | |
| | 7 | **Inference** (threadpool) | ResNet-18 forward pass produces raw logits of shape `[1, 6, 31]`. | |
| | 8 | **Decoding** | Softmax per position; the argmax index at each of the 6 positions maps to a character in the 31-symbol vocabulary. | |
| | 9 | **Telemetry** | Uptime and request counters are updated; structured logs capture request ID, latency, and prediction. | |
|
|
| --- |
|
|
| ## Why This Design |
|
|
| **Per-position classification over CTC.** Because every label in this dataset is exactly 6 characters, there's no variable-length alignment problem for CTC to solve β a shared linear head over 6 pooled feature vectors directly optimizes the actual objective with less architectural and training complexity. |
|
|
| **Threadpool over async-native inference.** PyTorch's synchronous CPU/GPU execution doesn't natively play well with `asyncio`; rather than rewriting the inference stack around async primitives, offloading to a threadpool is the minimal-risk way to keep the event loop responsive under concurrent load. |
|
|
| **Singleton over per-request instantiation.** Model loading (deserializing ~44MB of weights, initializing CUDA context) is orders of magnitude slower than a single forward pass β doing it once at startup, rather than per request, is what makes sub-200ms latency achievable at all. |
|
|
| --- |
|
|
| ## Related Documentation |
|
|
| - [API Specification](API.md) β endpoint contracts and payloads |
| - [Hardening Notes](HARDENING.md) β security and reliability measures layered onto this architecture |
| - [Engineering Audit](AUDIT.md) β independent review of this design |
| - [Deployment Guide](DEPLOYMENT.md) β running this architecture locally, via Docker, or in the cloud |
|
|