Files
DatTT127 f705113711 update
2026-06-24 10:33:07 +07:00

212 lines
13 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Architecture Review: VKIST Ultrasound Codebase</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#2563eb',
secondary: '#64748b'
}
}
}
}
</script>
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
<script>
mermaid.initialize({
startOnLoad: true,
theme: 'neutral',
});
</script>
</head>
<body class="bg-gray-50 text-gray-800 antialiased p-6 md:p-12">
<main class="max-w-5xl mx-auto">
<header class="mb-8 border-b border-gray-200 pb-6">
<h1 class="text-3xl font-extrabold text-gray-900 mb-2">Architecture Review: VKIST Ultrasound Codebase</h1>
<p class="text-lg text-gray-600">Identified deepening opportunities to improve testability and AI-navigability.</p>
</header>
<article class="bg-white rounded-xl shadow-sm border border-gray-200 p-6 md:p-8 mb-8 transition-shadow hover:shadow-md">
<div class="flex flex-col md:flex-row md:items-center justify-between gap-4 mb-6">
<h2 class="text-2xl font-bold text-gray-900">Candidate: Refactor app.py into modular services</h2>
<div>
<span class="px-3 py-1 rounded-full text-xs font-semibold uppercase tracking-wider bg-red-100 text-red-800">
Priority: Strong
</span>
</div>
</div>
<div class="space-y-4 mb-6">
<p class="text-sm bg-gray-50 p-3 rounded-lg border border-gray-100 text-gray-700">
<strong class="text-gray-900">Files Affected:</strong> <code class="text-blue-600">app.py</code>
<span class="text-gray-400 mx-2"></span>
<strong class="text-gray-900">Proposed:</strong>
<code class="bg-white px-1.5 py-0.5 rounded border text-xs">inference_pipeline.py</code>,
<code class="bg-white px-1.5 py-0.5 rounded border text-xs">model_loader.py</code>,
<code class="bg-white px-1.5 py-0.5 rounded border text-xs">preprocessor.py</code>,
<code class="bg-white px-1.5 py-0.5 rounded border text-xs">postprocessor.py</code>
</p>
<div>
<h3 class="text-sm font-semibold uppercase tracking-wider text-gray-500 mb-1">The Problem</h3>
<p class="text-gray-700 leading-relaxed">
The main application file (<code class="bg-gray-100 px-1 rounded text-sm text-red-600">app.py</code>) is acting as a "god object". It manages web framework setup, model loading, inference pipelines, preprocessing, postprocessing, utilities, and API endpoints simultaneously. This creates **low architectural depth** (the interface is nearly as complex as its implementation), **poor testability** (isolated pipeline units cannot be targeted), and **low locality** (unrelated logic must be parsed to fix individual features).
</p>
</div>
<div>
<h3 class="text-sm font-semibold uppercase tracking-wider text-gray-500 mb-1">Proposed Solution</h3>
<p class="text-gray-700 mb-2">Split operational concerns into highly focused, cleanly encapsulated modules:</p>
<ul class="space-y-2 text-gray-700 pl-4 list-disc">
<li><strong><code class="text-gray-900">ModelLoader</code>:</strong> Handles asynchronous loading and persistent caching of PyTorch weights (angle, inflammation, segmentation models).</li>
<li><strong><code class="text-gray-900">Preprocessor</code>:</strong> Isolates structural image transformations and CLAHE enhancement parameters.</li>
<li><strong><code class="text-gray-900">InferencePipeline</code>:</strong> Orchestrates execution flows: angle classification <span class="text-gray-400"></span> inflammation detection <span class="text-gray-400"></span> conditional segmentation <span class="text-gray-400"></span> sizing/severity metrics.</li>
<li><strong><code class="text-gray-900">Postprocessor</code>:</strong> Houses structural thickness evaluations, severity metrics calculations, and visual overlay generators.</li>
<li><strong><code class="text-gray-900">APIHandler</code>:</strong> A thin, declarative FastAPI endpoint wrapper delegating exclusively to the primary <code class="text-sm">InferencePipeline</code>.</li>
</ul>
</div>
<div>
<h3 class="text-sm font-semibold uppercase tracking-wider text-gray-500 mb-1">Expected Architecture Benefits</h3>
<ul class="grid grid-cols-1 md:grid-cols-2 gap-3 text-gray-700">
<li class="bg-blue-50/50 p-3 rounded-lg border border-blue-100">
<strong class="text-blue-900 block mb-0.5">Architectural Depth</strong> High complexity is hidden beneath simple interfaces (e.g., <code class="text-xs">analyze_image(img) -> Result</code>).
</li>
<li class="bg-blue-50/50 p-3 rounded-lg border border-blue-100">
<strong class="text-blue-900 block mb-0.5">High Code Locality</strong> Bugs in sizing algorithms map cleanly to the postprocessor without risking model caching logic.
</li>
<li class="bg-blue-50/50 p-3 rounded-lg border border-blue-100">
<strong class="text-blue-900 block mb-0.5">Simplified Testing</strong> Individual pipeline states and weights can be unit-tested seamlessly using mock behaviors.
</li>
<li class="bg-blue-50/50 p-3 rounded-lg border border-blue-100">
<strong class="text-blue-900 block mb-0.5">AI and Dev Navigation</strong> Highly categorized file trees accelerate context gathering for language models and onboarding engineers.
</li>
</ul>
</div>
</div>
<div class="grid grid-cols-1 xl:grid-cols-2 gap-6 mt-8">
<div class="border border-gray-200 rounded-xl p-4 bg-gray-50">
<h4 class="text-base font-bold text-gray-800 mb-3 flex items-center gap-2">
<span class="w-2.5 h-2.5 rounded-full bg-red-500"></span> Before (Shallow Architecture)
</h4>
<div class="mermaid bg-white p-4 rounded-lg border border-gray-100 shadow-inner overflow-x-auto">
graph TD
A[FastAPI Endpoint] --> B[load_angle_model]
A --> C[load_inflammation_model]
A --> D[load_segmentation_model_sup]
A --> E[load_segmentation_model_post]
A --> F[predict_angle]
A --> G[predict_inflammation]
A --> H[segment_image]
A --> I[measure_thickness_new]
A --> J[analyze_inflammation_severity]
A --> K[create_segmentation_overlay]
A --> L[apply_clahe]
A --> M[save_patient_data]
style A fill:#f87171,stroke:#ef4444,stroke-width:2px,color:#fff
style B fill:#fee2e2,stroke:#f87171
style C fill:#fee2e2,stroke:#f87171
style D fill:#fee2e2,stroke:#f87171
style E fill:#fee2e2,stroke:#f87171
style F fill:#fee2e2,stroke:#f87171
style G fill:#fee2e2,stroke:#f87171
style H fill:#fee2e2,stroke:#f87171
style I fill:#fee2e2,stroke:#f87171
style J fill:#fee2e2,stroke:#f87171
style K fill:#fee2e2,stroke:#f87171
style L fill:#fee2e2,stroke:#f87171
style M fill:#fee2e2,stroke:#f87171
</div>
</div>
<div class="border border-gray-200 rounded-xl p-4 bg-gray-50">
<h4 class="text-base font-bold text-gray-800 mb-3 flex items-center gap-2">
<span class="w-2.5 h-2.5 rounded-full bg-green-500"></span> After (Deepened Architecture)
</h4>
<div class="mermaid bg-white p-4 rounded-lg border border-gray-100 shadow-inner overflow-x-auto">
graph TD
subgraph API [API Gateway Router]
A[FastAPI Endpoint] --> B[InferencePipeline.analyze]
end
subgraph InferencePipeline [Core Workflow Orchestrator]
B --> C[ModelLoader.get_angle_model]
B --> D[Preprocess]
B --> E[predict_angle]
E --> F{Inflammation?}
F -->|Yes| G[ModelLoader.get_inflammation_model]
G --> H[predict_inflammation]
H --> I{Inflammation Detected?}
I -->|Yes| J[ModelLoader.get_seg_model_sup/post]
J --> K[segment_image]
K --> L[measure_thickness]
K --> M[analyze_severity]
L --> N[Result: Measurement]
M --> O[Result: Severity]
K --> P[Result: Segmentation Masks]
E -->|No| Q[Result: Angle Only]
F -->|No| Q
end
subgraph ModelLoader [Model Assets Lifecycle]
C --> C1[Load Angle Model]
G --> G1[Load Inflammation Model]
J --> J1[Load Segmentation Model]
end
subgraph Preprocessor [Image Engineering]
D --> D1[Transforms]
D --> D2[CLAHE]
end
subgraph Postprocessor [Metrics & Artifact Generation]
L --> L1[Thickness Calc]
M --> M1[Severity Scoring]
end
style A fill:#3b82f6,stroke:#2563eb,stroke-width:2px,color:#fff
style B fill:#dbeafe,stroke:#60a5fa
style C fill:#dbeafe,stroke:#60a5fa
style D fill:#dbeafe,stroke:#60a5fa
style E fill:#dbeafe,stroke:#60a5fa
style F fill:#dbeafe,stroke:#60a5fa
style G fill:#dbeafe,stroke:#60a5fa
style H fill:#dbeafe,stroke:#60a5fa
style I fill:#dbeafe,stroke:#60a5fa
style J fill:#dbeafe,stroke:#60a5fa
style K fill:#dbeafe,stroke:#60a5fa
style L fill:#dbeafe,stroke:#60a5fa
style M fill:#dbeafe,stroke:#60a5fa
style N fill:#e0f2fe,stroke:#0284c7
style O fill:#e0f2fe,stroke:#0284c7
style P fill:#e0f2fe,stroke:#0284c7
style Q fill:#e0f2fe,stroke:#0284c7
style C1 fill:#f3e8ff,stroke:#a855f7
style G1 fill:#f3e8ff,stroke:#a855f7
style J1 fill:#f3e8ff,stroke:#a855f7
style D1 fill:#fef3c7,stroke:#d97706
style D2 fill:#fef3c7,stroke:#d97706
style L1 fill:#ecfccb,stroke:#65a30d
style M1 fill:#ecfccb,stroke:#65a30d
</div>
</div>
</div>
</article>
<footer class="text-center text-sm text-gray-500 mt-12">
<p>Total candidates identified: <span class="font-semibold text-gray-700">1</span></p>
</footer>
</main>
</body>
</html>