Harshit Ghosh
Landing page init
5d2b6e2
{% extends "base.html" %}
{% block title %}Upload Scan β€” AI Medical Intelligence Pipeline{% endblock %}
{% block content %}
<section class="breadcrumb">
<a href="{{ url_for('home') }}">Home</a>
<span class="sep">/</span>
<span>Upload Scans</span>
</section>
<section class="upload-hero">
<h1>Upload DICOM Scans</h1>
<p>
Upload one or many CT brain scans for AI-powered hemorrhage screening.
A single exam may contain hundreds of slices β€” all modes below handle
that seamlessly.
</p>
</section>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<div class="flash-messages">
{% for category, message in messages %}
<div class="flash flash-{{ category }}">{{ message }}</div>
{% endfor %}
</div>
{% endif %}
{% endwith %}
<!-- ── Tab navigation ──────────────────────────────────────────────── -->
<div class="upload-tabs" role="tablist">
<button class="upload-tab active" data-tab="single" role="tab">Single File</button>
<button class="upload-tab" data-tab="multi" role="tab">Multi-File / ZIP</button>
{% if local_mode %}
<button class="upload-tab" data-tab="dirscan" role="tab">Scan Directory</button>
{% endif %}
</div>
<!-- ════════════════════════════════════════════════════════════════════ -->
<!-- TAB 1 β€” Single .dcm file -->
<!-- ════════════════════════════════════════════════════════════════════ -->
<section class="panel upload-panel tab-panel active" id="tab-single">
<form method="post" action="{{ url_for('analyze') }}" enctype="multipart/form-data" id="singleForm">
<div class="dropzone" id="dropzoneSingle">
<svg width="56" height="56" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"
stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
<polyline points="17 8 12 3 7 8" />
<line x1="12" y1="3" x2="12" y2="15" />
</svg>
<p class="dropzone-text">Drag &amp; drop a .dcm file here</p>
<p class="muted small">or click to browse</p>
<input type="file" name="file" id="singleInput" accept=".dcm" hidden />
</div>
<div class="file-info" id="singleInfo" style="display: none">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
<polyline points="14 2 14 8 20 8" />
</svg>
<span id="singleFileName"></span>
<button type="button" class="btn btn-sm btn-ghost js-clear-single">Remove</button>
</div>
<button type="submit" class="btn btn-primary" id="singleSubmit" disabled>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M22 12h-4l-3 9L9 3l-3 9H2" />
</svg>
Analyze Scan
</button>
</form>
<div class="loading-overlay" id="singleOverlay" style="display: none">
<div class="spinner"></div>
<p>Running AI analysis&hellip;</p>
<p class="muted small">This may take a moment on first run while the model loads.</p>
</div>
</section>
<!-- ════════════════════════════════════════════════════════════════════ -->
<!-- TAB 2 β€” Multi-file / ZIP upload -->
<!-- ════════════════════════════════════════════════════════════════════ -->
<section class="panel upload-panel tab-panel" id="tab-multi">
<form method="post" action="{{ url_for('analyze') }}" enctype="multipart/form-data" id="multiForm">
<div class="dropzone" id="dropzoneMulti">
<svg width="56" height="56" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"
stroke-linecap="round" stroke-linejoin="round">
<rect x="2" y="7" width="20" height="14" rx="2" />
<path d="M16 7V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2" />
</svg>
<p class="dropzone-text">Drag &amp; drop .dcm files or a .zip archive</p>
<p class="muted small">Select multiple files, or a single .zip containing DICOM slices</p>
<input type="file" name="file" id="multiInput" accept=".dcm,.zip" multiple hidden />
</div>
<div class="file-info" id="multiInfo" style="display: none">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="2" y="7" width="20" height="14" rx="2" />
<path d="M16 7V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2" />
</svg>
<span id="multiFileName"></span>
<button type="button" class="btn btn-sm btn-ghost js-clear-multi">Remove all</button>
</div>
<button type="submit" class="btn btn-primary" id="multiSubmit" disabled>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M22 12h-4l-3 9L9 3l-3 9H2" />
</svg>
Analyze Batch
</button>
</form>
<div class="loading-overlay" id="multiOverlay" style="display: none">
<div class="spinner"></div>
<p>Uploading files&hellip;</p>
<p class="muted small">Large batches may take a moment to upload.</p>
</div>
</section>
<!-- ════════════════════════════════════════════════════════════════════ -->
<!-- TAB 3 β€” Directory scan (local mode only) -->
<!-- ════════════════════════════════════════════════════════════════════ -->
{% if local_mode %}
<section class="panel upload-panel tab-panel" id="tab-dirscan">
<form method="post" action="{{ url_for('analyze_directory') }}" id="dirForm">
<label class="dir-label" for="dirPath">
Server-side directory containing .dcm files
</label>
<div class="dir-input-row">
<input type="text" name="dir_path" id="dirPath" class="input" placeholder="D:\scans\patient_001"
spellcheck="false" autocomplete="off" />
<button type="submit" class="btn btn-primary" id="dirSubmit">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8" />
<line x1="21" y1="21" x2="16.65" y2="16.65" />
</svg>
Scan &amp; Analyze
</button>
</div>
<p class="muted small" style="margin-top: 8px">
The server will recursively find all <code>.dcm</code> files in this
directory and its sub-folders, then run inference on each.
This option is only available when running locally.
</p>
</form>
</section>
{% endif %}
<!-- ── How it works ────────────────────────────────────────────────── -->
<section class="panel" style="margin-top: 16px">
<h3>How It Works</h3>
<div class="steps-grid">
<div class="step">
<div class="step-num">1</div>
<div class="step-text">
<strong>Upload</strong>
<p class="muted small">Select DICOM files, a ZIP, or enter a directory path</p>
</div>
</div>
<div class="step">
<div class="step-num">2</div>
<div class="step-text">
<strong>Process</strong>
<p class="muted small">CT windowing &amp; preprocessing on each slice</p>
</div>
</div>
<div class="step">
<div class="step-num">3</div>
<div class="step-text">
<strong>Analyze</strong>
<p class="muted small">EfficientNet-B4 model with calibrated scoring</p>
</div>
</div>
<div class="step">
<div class="step-num">4</div>
<div class="step-text">
<strong>Report</strong>
<p class="muted small">Grad-CAM visualization &amp; clinical report per slice</p>
</div>
</div>
</div>
</section>
{% endblock %}
{% block scripts %}
<script src="{{ url_for('static', filename='js/upload.js') }}" defer></script>
{% endblock %}