Duy
feat: add About page with system spec link to web UI
2bdb3d6
Raw
History Blame Contribute Delete
17.5 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BOM Pattern Detection</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/static/css/style.css" />
</head>
<body>
<!-- Sidebar -->
<aside class="sidebar">
<div class="sidebar-logo">
<div class="logo-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
<rect x="2" y="2" width="9" height="9" rx="2" fill="#2563EB"/>
<rect x="13" y="2" width="9" height="9" rx="2" fill="#2563EB" opacity="0.5"/>
<rect x="2" y="13" width="9" height="9" rx="2" fill="#2563EB" opacity="0.5"/>
<rect x="13" y="13" width="9" height="9" rx="2" fill="#2563EB"/>
</svg>
</div>
<span class="logo-text">BOM Detector</span>
</div>
<nav class="sidebar-nav">
<a href="#" class="nav-item active" data-page="detect">
<svg width="18" height="18" 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>
<span>Detection</span>
</a>
<a href="#" class="nav-item" data-page="about">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/>
</svg>
<span>About</span>
</a>
</nav>
<div class="sidebar-section">
<div class="section-label">Algorithm</div>
<div class="setting-row">
<label class="toggle-label">
<span>Auto-tune mode</span>
<div class="toggle" id="autoToggle">
<input type="checkbox" id="autoMode" checked />
<span class="toggle-slider"></span>
</div>
</label>
</div>
<div class="setting-row">
<label class="toggle-label">
<span>VLM filter <span class="setting-tag">Qwen2-VL</span></span>
<div class="toggle" id="vlmToggle">
<input type="checkbox" id="useVlm" />
<span class="toggle-slider"></span>
</div>
</label>
<p class="setting-hint">Local vision-language model rejects false
positives on borderline matches. More accurate, slower (first run
downloads ~4.5&nbsp;GB).</p>
</div>
</div>
<div class="sidebar-section" id="manualSettings" style="display:none;">
<div class="section-label">Thresholds</div>
<div class="slider-group">
<div class="slider-row">
<span class="slider-label">NCC</span>
<span class="slider-val" id="nccVal">0.55</span>
</div>
<input type="range" class="slider" id="nccThreshold" min="0.1" max="0.9" step="0.01" value="0.55" />
</div>
<div class="slider-group">
<div class="slider-row">
<span class="slider-label">DINOv2 Cosine</span>
<span class="slider-val" id="dinoVal">0.84</span>
</div>
<input type="range" class="slider" id="dinoThreshold" min="0.5" max="0.99" step="0.01" value="0.84" />
</div>
<div class="slider-group">
<div class="slider-row">
<span class="slider-label">NMS IoU</span>
<span class="slider-val" id="nmsVal">0.40</span>
</div>
<input type="range" class="slider" id="nmsThreshold" min="0.1" max="0.9" step="0.01" value="0.40" />
</div>
</div>
<div class="sidebar-footer">
<div class="tech-badges">
<span class="badge">NCC</span>
<span class="badge">DINOv2</span>
<span class="badge">Zero-shot</span>
</div>
</div>
</aside>
<!-- Main content -->
<main class="main">
<header class="topbar">
<div class="topbar-left">
<h1 class="page-title">Pattern Detection</h1>
<span class="page-subtitle">BOM Engineering Drawings · Zero-shot</span>
</div>
<div class="topbar-right">
<div class="status-dot" id="statusDot"></div>
<span class="status-text" id="statusText">Ready</span>
</div>
</header>
<!-- Upload section -->
<section class="upload-section">
<div class="upload-grid">
<!-- Pattern upload -->
<div class="upload-card" id="patternDropzone">
<div class="upload-inner">
<div class="upload-icon">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<rect x="3" y="3" width="18" height="18" rx="3"/>
<circle cx="8.5" cy="8.5" r="1.5"/>
<polyline points="21 15 16 10 5 21"/>
</svg>
</div>
<div class="upload-label">Pattern Template</div>
<div class="upload-hint">Drop image or click to browse</div>
<input type="file" id="patternFile" accept="image/*" class="file-input" />
</div>
<div class="upload-preview" id="patternPreview" style="display:none;">
<img id="patternImg" alt="Pattern" />
<button class="clear-btn" id="clearPattern">×</button>
</div>
</div>
<!-- Drawing upload -->
<div class="upload-card" id="drawingDropzone">
<div class="upload-inner">
<div class="upload-icon">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<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"/>
<line x1="16" y1="13" x2="8" y2="13"/>
<line x1="16" y1="17" x2="8" y2="17"/>
<polyline points="10 9 9 9 8 9"/>
</svg>
</div>
<div class="upload-label">Engineering Drawing</div>
<div class="upload-hint">Drop image or click to browse</div>
<input type="file" id="drawingFile" accept="image/*" class="file-input" />
</div>
<div class="upload-preview" id="drawingPreview" style="display:none;">
<img id="drawingImg" alt="Drawing" />
<button class="clear-btn" id="clearDrawing">×</button>
</div>
</div>
</div>
<div class="run-row">
<button class="run-btn" id="runBtn" disabled>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
<polygon points="5 3 19 12 5 21 5 3"/>
</svg>
Run Detection
</button>
</div>
</section>
<!-- Stats row (hidden until result) -->
<section class="stats-row" id="statsRow" style="display:none;">
<div class="stat-card">
<div class="stat-value" id="statDetections"></div>
<div class="stat-label">Detections</div>
</div>
<div class="stat-card">
<div class="stat-value" id="statAvgConf"></div>
<div class="stat-label">Avg Confidence</div>
</div>
<div class="stat-card">
<div class="stat-value" id="statBestDino"></div>
<div class="stat-label">Best DINOv2</div>
</div>
<div class="stat-card">
<div class="stat-value" id="statTime"></div>
<div class="stat-label">Time (s)</div>
</div>
</section>
<!-- Results section (hidden until result) -->
<section class="results-section" id="resultsSection" style="display:none;">
<div class="results-grid">
<!-- Annotated output -->
<div class="result-card viz-card">
<div class="card-header">
<span class="card-title">Annotated Output</span>
<button class="download-btn" id="downloadBtn">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/>
<line x1="12" y1="15" x2="12" y2="3"/>
</svg>
Save
</button>
</div>
<div class="viz-container">
<img id="vizImage" alt="Detection result" />
</div>
</div>
<!-- Detection list -->
<div class="result-card detections-card">
<div class="card-header">
<span class="card-title">Detections</span>
<span class="card-count" id="detectionCount">0</span>
<button class="download-btn" id="csvBtn" style="display:none;" title="Download CSV">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/>
<line x1="12" y1="15" x2="12" y2="3"/>
</svg>
CSV
</button>
</div>
<div class="detections-list" id="detectionsList"></div>
</div>
</div>
</section>
<!-- Loading overlay -->
<div class="loading-overlay" id="loadingOverlay" style="display:none;">
<div class="loading-card">
<div class="spinner"></div>
<div class="loading-title">Detecting Patterns</div>
<div class="loading-sub" id="loadingStage">Initializing pipeline…</div>
</div>
</div>
<!-- ===== ABOUT PAGE ===== -->
<section class="about-page" id="aboutPage" style="display:none;">
<div class="about-hero">
<div class="about-hero-icon">
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
</svg>
</div>
<h2 class="about-title">BOM Pattern Detection</h2>
<p class="about-subtitle">Zero-shot symbol detection for engineering drawings · No training data required</p>
<div class="about-badges">
<span class="about-badge">NCC</span>
<span class="about-badge">DINOv2 ViT-S/14</span>
<span class="about-badge">Qwen2-VL-2B</span>
<span class="about-badge">Zero-shot</span>
</div>
</div>
<div class="about-grid">
<!-- Pipeline card -->
<div class="about-card about-card-wide">
<div class="about-card-title">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
Pipeline Architecture
</div>
<div class="pipeline-steps">
<div class="pipe-step">
<div class="pipe-num" style="background:#6366f1;">0</div>
<div class="pipe-body">
<div class="pipe-name">Preprocess</div>
<div class="pipe-desc">Adaptive binarize · Denoise</div>
</div>
<div class="pipe-time">&lt;0.5s</div>
</div>
<div class="pipe-arrow"></div>
<div class="pipe-step">
<div class="pipe-num" style="background:#2563eb;">1</div>
<div class="pipe-body">
<div class="pipe-name">NCC Matching</div>
<div class="pipe-desc">Multi-scale · Multi-angle · NMS</div>
</div>
<div class="pipe-time">15–60s CPU</div>
</div>
<div class="pipe-arrow"></div>
<div class="pipe-step">
<div class="pipe-num" style="background:#0e9f6e;">2</div>
<div class="pipe-body">
<div class="pipe-name">DINOv2 Verify</div>
<div class="pipe-desc">Cosine similarity · Derotate</div>
</div>
<div class="pipe-time">2–10s GPU</div>
</div>
<div class="pipe-arrow"></div>
<div class="pipe-step">
<div class="pipe-num" style="background:#0891b2;">2b</div>
<div class="pipe-body">
<div class="pipe-name">Struct Filters</div>
<div class="pipe-desc">Chamfer · NMS · Gap filter</div>
</div>
<div class="pipe-time">&lt;1s</div>
</div>
<div class="pipe-arrow" style="opacity:.5;"></div>
<div class="pipe-step" style="opacity:.7; border-style:dashed;">
<div class="pipe-num" style="background:#d97706;">3</div>
<div class="pipe-body">
<div class="pipe-name">VLM Filter</div>
<div class="pipe-desc">Qwen2-VL · Optional</div>
</div>
<div class="pipe-time">~0.4s/crop</div>
</div>
</div>
</div>
<!-- Key features -->
<div class="about-card">
<div class="about-card-title">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
Key Features
</div>
<ul class="about-list">
<li>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#16a34a" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
Fully zero-shot — no fine-tuning or labeled data
</li>
<li>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#16a34a" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
Multi-scale (0.7×–1.8×) &amp; multi-angle (±10°, 90°)
</li>
<li>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#16a34a" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
Handles simple and complex symbol templates
</li>
<li>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#16a34a" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
Optional VLM stage for hard FP rejection
</li>
<li>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#16a34a" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
CPU + GPU support · Docker ready
</li>
</ul>
</div>
<!-- Tech stack -->
<div class="about-card">
<div class="about-card-title">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
Tech Stack
</div>
<div class="tech-table">
<div class="tech-row"><span class="tech-layer">Stage 1</span><span class="tech-val">OpenCV NCC · <code>TM_CCOEFF_NORMED</code></span></div>
<div class="tech-row"><span class="tech-layer">Stage 2</span><span class="tech-val">DINOv2 ViT-S/14 · PyTorch</span></div>
<div class="tech-row"><span class="tech-layer">Stage 3</span><span class="tech-val">Qwen2-VL-2B · HuggingFace</span></div>
<div class="tech-row"><span class="tech-layer">Backend</span><span class="tech-val">FastAPI · Python 3.11</span></div>
<div class="tech-row"><span class="tech-layer">Deploy</span><span class="tech-val">Docker · HuggingFace Spaces</span></div>
</div>
</div>
<!-- Spec link card -->
<div class="about-card about-spec-card">
<div class="about-card-title">
<svg width="16" height="16" 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"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>
System Specification
</div>
<p class="about-spec-desc">Đặc tả kỹ thuật chi tiết toàn bộ hệ thống: kiến trúc pipeline, thuật toán từng stage, các quyết định thiết kế, kết quả thực nghiệm và hướng cải thiện.</p>
<div class="about-spec-meta">
<span>13 mục · Pipeline · Filters · VLM · Config · Results</span>
</div>
<a href="/spec" target="_blank" class="spec-link-btn">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
Mở đặc tả hệ thống
</a>
</div>
</div>
<div class="about-footer">
Sotatek AI/CV Engineer Assessment · 2026 ·
<a href="mailto:duydeodai2003@gmail.com">duydeodai2003@gmail.com</a>
</div>
</section>
</main>
<script src="/static/js/app.js"></script>
</body>
</html>