Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <meta name="theme-color" content="#06111f" /> | |
| <meta name="description" content="A privacy-first AI system for detecting and reading water meters." /> | |
| <title>AquaVision AI | Water Meter Reader</title> | |
| <link rel="preconnect" href="https://cdn.jsdelivr.net" /> | |
| <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=Poppins:wght@400;500;600;700;800&display=swap" rel="stylesheet" /> | |
| <link rel="stylesheet" href="styles.css" /> | |
| <script src="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.23.2/dist/ort.min.js"></script> | |
| <script src="app.js" defer></script> | |
| </head> | |
| <body> | |
| <div class="ambient ambient-one"></div> | |
| <div class="ambient ambient-two"></div> | |
| <header class="topbar"> | |
| <a class="brand" href="#" aria-label="AquaVision AI home"> | |
| <span class="brand-icon" aria-hidden="true"> | |
| <svg viewBox="0 0 24 24"><path d="M12 2.5S5.7 9.2 5.7 14.2a6.3 6.3 0 0 0 12.6 0C18.3 9.2 12 2.5 12 2.5Z"/><path d="M9.2 15.1a3.1 3.1 0 0 0 3 2.5"/></svg> | |
| </span> | |
| <span><strong>AquaVision</strong><small>AI METER INTELLIGENCE</small></span> | |
| </a> | |
| <nav class="app-tabs" aria-label="Application sections"> | |
| <button class="app-tab active" type="button" data-tab="reader" aria-selected="true">Reader</button> | |
| <button class="app-tab" type="button" data-tab="performance" aria-selected="false">Performance</button> | |
| <button class="app-tab" type="button" data-tab="guide" aria-selected="false">Settings guide</button> | |
| <button class="app-tab" type="button" data-tab="history" aria-selected="false">History</button> | |
| <button class="app-tab" type="button" data-tab="team" aria-selected="false">Team</button> | |
| </nav> | |
| <div class="topbar-actions"> | |
| <span class="system-pill"><i id="headerStatusDot"></i><span id="headerStatus">Initializing AI</span></span> | |
| <a class="model-link" href="https://huggingface.co/kagabo/hf_water_meter_models" target="_blank" rel="noreferrer" aria-label="Open model on Hugging Face"><span>HF</span> Model</a> | |
| <a class="icon-link" href="https://github.com/kai-lucky72/watermeter-vision" target="_blank" rel="noreferrer" aria-label="View source code"> | |
| <svg viewBox="0 0 24 24"><path d="M9 19c-4.5 1.4-4.5-2.2-6.3-2.7M15 21v-3.5c0-1 .1-1.4-.5-2 2.8-.3 5.7-1.4 5.7-6.2A4.9 4.9 0 0 0 19 5.9a4.5 4.5 0 0 0-.1-3.3s-1-.3-3.5 1.3a12 12 0 0 0-6.3 0C6.6 2.3 5.6 2.6 5.6 2.6a4.5 4.5 0 0 0-.1 3.3 4.9 4.9 0 0 0-1.3 3.4c0 4.8 3 5.9 5.8 6.2-.5.5-.7 1.1-.7 2V21"/></svg> | |
| </a> | |
| </div> | |
| </header> | |
| <main class="page-shell"> | |
| <div id="tab-reader" class="tab-panel active" data-tab-panel="reader"> | |
| <section class="intro"> | |
| <div> | |
| <div class="kicker"><span></span> COMPUTER VISION SHOWCASE</div> | |
| <h1>Water Meter AI Reader</h1> | |
| <p>Upload a meter photo, run local AI detection, and review the extracted reading.</p> | |
| </div> | |
| <div class="model-card" aria-label="Model information"> | |
| <div class="model-card-head"> | |
| <span class="model-orbit"><i></i></span> | |
| <div><small>ACTIVE MODEL</small><strong>YOLO12n · AquaVision</strong></div> | |
| <span class="live-tag">LIVE</span> | |
| </div> | |
| <dl> | |
| <div><dt>Input</dt><dd>960 x 960</dd></div> | |
| <div><dt>Classes</dt><dd>12</dd></div> | |
| <div><dt>Runtime</dt><dd>ONNX Web</dd></div> | |
| </dl> | |
| </div> | |
| </section> | |
| <section class="settings-strip glass-panel" aria-label="Detection settings"> | |
| <div class="settings-strip-title"><span class="step-number">02</span><div><small>AI CONTROL</small><h2>Detection settings</h2></div></div> | |
| <label class="range-control"> | |
| <span><b>Detection confidence</b><output id="confidenceValue">10%</output></span> | |
| <input id="confidenceSlider" type="range" min="5" max="80" value="10" step="1" /> | |
| <small>Lower finds more boxes; higher keeps stronger boxes.</small> | |
| </label> | |
| <label class="range-control"> | |
| <span><b>Overlap filtering</b><output id="iouValue">45%</output></span> | |
| <input id="iouSlider" type="range" min="20" max="80" value="45" step="1" /> | |
| <small>Removes duplicate boxes covering the same digit.</small> | |
| </label> | |
| <label class="range-control unknown-control"> | |
| <span><b>Unknown threshold</b><output id="unknownValue">40%</output></span> | |
| <input id="unknownSlider" type="range" min="20" max="90" value="40" step="1" /> | |
| <small>Uncertain retained digits become <b>?</b> for review.</small> | |
| </label> | |
| </section> | |
| <section class="app-grid" aria-label="Water meter analysis workspace"> | |
| <aside class="control-column"> | |
| <article class="glass-panel upload-panel"> | |
| <div class="section-title"> | |
| <span class="step-number">01</span> | |
| <div><small>INPUT</small><h2>Add meter image</h2></div> | |
| <button id="clearButton" class="quiet-button" type="button" disabled>Clear</button> | |
| </div> | |
| <label id="dropZone" class="drop-zone" for="fileInput"> | |
| <input id="fileInput" type="file" accept="image/png,image/jpeg,image/webp" capture="environment" /> | |
| <span class="upload-symbol"> | |
| <svg viewBox="0 0 24 24"><path d="M12 16V4m0 0L7.5 8.5M12 4l4.5 4.5M5 14v4a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-4"/></svg> | |
| </span> | |
| <strong>Drop meter image here</strong> | |
| <span>or click to browse / use camera</span> | |
| <small>JPG, PNG, WEBP · max 20 MB</small> | |
| </label> | |
| <div class="photo-guide"> | |
| <svg viewBox="0 0 24 24"><path d="M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Z"/><path d="M12 16v-4m0-4h.01"/></svg> | |
| <p><strong>For the best reading</strong> Center the display, reduce glare, and keep all digits sharp.</p> | |
| </div> | |
| </article> | |
| <button id="runButton" class="analyze-button" type="button" disabled> | |
| <span class="button-icon"><svg viewBox="0 0 24 24"><path d="m13 2-2 8h7l-9 12 2-8H4l9-12Z"/></svg></span> | |
| <span><b id="runLabel">Preparing AI model</b><small>Run local computer vision</small></span> | |
| <svg class="button-arrow" viewBox="0 0 24 24"><path d="m9 18 6-6-6-6"/></svg> | |
| </button> | |
| <div id="modelStatus" class="model-status" role="status" aria-live="polite"><i class="loading"></i>Loading model for first use...</div> | |
| </aside> | |
| <section class="results-column"> | |
| <article class="glass-panel viewer-panel"> | |
| <div class="viewer-toolbar"> | |
| <div class="section-title compact"> | |
| <span class="step-number">03</span> | |
| <div><small>VISION OUTPUT</small><h2>Analysis viewer</h2></div> | |
| </div> | |
| <div class="viewer-actions"> | |
| <div class="view-switch" role="group" aria-label="Image view"> | |
| <button id="detectedViewButton" class="active" type="button">Detected</button> | |
| <button id="originalViewButton" type="button">Original</button> | |
| </div> | |
| <button id="downloadButton" class="tool-button" type="button" disabled aria-label="Download annotated result"> | |
| <svg viewBox="0 0 24 24"><path d="M12 3v12m0 0 4-4m-4 4-4-4M5 19h14"/></svg><span>Export</span> | |
| </button> | |
| </div> | |
| </div> | |
| <div id="canvasWrap" class="canvas-wrap empty"> | |
| <canvas id="resultCanvas" aria-label="Water meter detection result"></canvas> | |
| <div id="canvasPlaceholder" class="canvas-placeholder"> | |
| <span class="placeholder-reticle"><i></i><i></i><i></i><i></i><b></b></span> | |
| <strong>Awaiting meter image</strong> | |
| <p>Your AI detection result will appear in this workspace.</p> | |
| </div> | |
| <div class="scan-overlay" aria-hidden="true"><span></span></div> | |
| <div id="imageBadge" class="image-badge">ORIGINAL PREVIEW</div> | |
| </div> | |
| <div class="metric-strip"> | |
| <div><small>INFERENCE</small><strong id="timing">--</strong></div> | |
| <div><small>OBJECTS</small><strong id="detectionCount">--</strong></div> | |
| <div><small>AVG. CONFIDENCE</small><strong id="averageConfidence">--</strong></div> | |
| <div><small>DISPLAY WINDOW</small><strong id="windowStatus">--</strong></div> | |
| </div> | |
| </article> | |
| <div class="result-grid"> | |
| <article class="reading-panel glass-panel"> | |
| <div class="result-heading"><span>EXTRACTED READING</span><b id="readingState">WAITING</b></div> | |
| <div class="reading-line"> | |
| <output id="readingOutput">------</output> | |
| <button id="copyButton" type="button" disabled aria-label="Copy meter reading"> | |
| <svg viewBox="0 0 24 24"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg> | |
| </button> | |
| </div> | |
| <div class="raw-reading-row"><span>Raw model guess</span><output id="rawReadingOutput">------</output><b id="unknownCount">0 unknown</b></div> | |
| <div class="quality-row"> | |
| <span>Reading quality</span> | |
| <div class="quality-track"><i id="qualityBar"></i></div> | |
| <strong id="qualityLabel">Not analyzed</strong> | |
| </div> | |
| </article> | |
| <article class="digits-panel glass-panel"> | |
| <div class="result-heading"><span>DIGIT BREAKDOWN</span><b id="digitCount">0 DIGITS</b></div> | |
| <div id="confidenceOutput" class="digit-list"><p class="empty-copy">Run an analysis to inspect every detected digit.</p></div> | |
| </article> | |
| </div> | |
| </section> | |
| </section> | |
| </div> | |
| <div id="tab-team" class="tab-panel" data-tab-panel="team"> | |
| <section class="team-section"> | |
| <div class="performance-heading"> | |
| <div> | |
| <div class="kicker"><span></span> WMRS PROJECT TEAM</div> | |
| <h2>Built by Y3 students.</h2> | |
| <p>The Water Meter Reading System MVP was developed collaboratively by three Year 3 students.</p> | |
| </div> | |
| </div> | |
| <div class="team-grid"> | |
| <article class="team-card"><span>BE</span><div><small>Y3 STUDENT</small><h3>Benite</h3><p>Water Meter Reading System project team member.</p></div></article> | |
| <article class="team-card"><span>BS</span><div><small>Y3 STUDENT</small><h3>Beni Samuel</h3><p>Water Meter Reading System project team member.</p></div></article> | |
| <article class="team-card"><span>KL</span><div><small>Y3 STUDENT</small><h3>Kagabo Lucky</h3><p>Water Meter Reading System project team member.</p></div></article> | |
| </div> | |
| <article class="team-project glass-panel"><div><small>OUR SHARED PROJECT</small><h3>Water Meter Reading System MVP</h3></div><p>Computer vision for detecting water meters, locating their reading windows, recognizing digits, and safely flagging uncertain readings for human review.</p></article> | |
| </section> | |
| </div> | |
| <div id="tab-performance" class="tab-panel" data-tab-panel="performance"> | |
| <section class="performance-section" id="model-performance"> | |
| <div class="performance-heading"> | |
| <div> | |
| <div class="kicker"><span></span> AQUAVISION YOLO12N VALIDATION EVIDENCE</div> | |
| <h2>How well does the model perform?</h2> | |
| <p>Aggregate object-detection results from the final clean YOLO12n model on the held-out 52-image combat test set.</p> | |
| </div> | |
| <a class="evidence-link" href="https://github.com/kai-lucky72/watermeter-vision" target="_blank" rel="noreferrer">View evaluation source <span>↗</span></a> | |
| </div> | |
| <div class="metric-card-grid" aria-label="Model validation summary"> | |
| <article class="validation-metric"><div><span>PRECISION</span><strong>95.8<small>%</small></strong></div><p>Of the objects predicted, 95.8% were correct.</p><i style="--metric:95.8%"></i></article> | |
| <article class="validation-metric"><div><span>RECALL</span><strong>95.8<small>%</small></strong></div><p>Of the labeled objects, 95.8% were found.</p><i style="--metric:95.8%"></i></article> | |
| <article class="validation-metric featured"><div><span>mAP @ 0.50</span><strong>97.6<small>%</small></strong></div><p>Detection accuracy at 50% box overlap.</p><i style="--metric:97.6%"></i></article> | |
| <article class="validation-metric"><div><span>mAP @ 0.50–0.95</span><strong>60.1<small>%</small></strong></div><p>Stricter score averaged across multiple overlaps.</p><i style="--metric:60.1%"></i></article> | |
| </div> | |
| <article class="metric-comparison glass-panel"> | |
| <div class="chart-header"><div><small>AGGREGATE COMPARISON</small><h3>Validation metrics</h3></div><span>52 test images · higher is better</span></div> | |
| <div class="metric-bars" role="img" aria-label="Bar chart: Precision 95.8%, Recall 95.8%, mAP50 97.6%, mAP50-95 60.1%"> | |
| <div><span>Precision</span><b><i style="--value:95.8%"></i></b><strong>0.958</strong></div> | |
| <div><span>Recall</span><b><i style="--value:95.8%"></i></b><strong>0.958</strong></div> | |
| <div><span>mAP50</span><b><i style="--value:97.6%"></i></b><strong>0.976</strong></div> | |
| <div><span>mAP50–95</span><b><i style="--value:60.1%"></i></b><strong>0.601</strong></div> | |
| </div> | |
| <div class="chart-axis"><span>0</span><span>0.25</span><span>0.50</span><span>0.75</span><span>1.00</span></div> | |
| </article> | |
| <div class="evidence-heading"><div><small>DETAILED CURVES</small><h3>Explore the validation plots</h3></div><p>Select a plot to open the original full-resolution evidence.</p></div> | |
| <div class="evidence-grid"> | |
| <a class="evidence-card" href="metrics/precision-recall-curve.png" target="_blank"><img src="metrics/precision-recall-curve.png" alt="Precision-recall curve for all model classes" loading="lazy" /><div><strong>Precision–Recall curve</strong><span>Trade-off between precision and recall by class</span></div></a> | |
| <a class="evidence-card" href="metrics/f1-curve.png" target="_blank"><img src="metrics/f1-curve.png" alt="F1 confidence curve for all model classes" loading="lazy" /><div><strong>F1–Confidence curve</strong><span>Balance of precision and recall across thresholds</span></div></a> | |
| <a class="evidence-card" href="metrics/precision-curve.png" target="_blank"><img src="metrics/precision-curve.png" alt="Precision confidence curve for all model classes" loading="lazy" /><div><strong>Precision–Confidence</strong><span>Prediction correctness as confidence changes</span></div></a> | |
| <a class="evidence-card" href="metrics/recall-curve.png" target="_blank"><img src="metrics/recall-curve.png" alt="Recall confidence curve for all model classes" loading="lazy" /><div><strong>Recall–Confidence</strong><span>Detection coverage as confidence changes</span></div></a> | |
| <a class="evidence-card wide" href="metrics/confusion-matrix-normalized.png" target="_blank"><img src="metrics/confusion-matrix-normalized.png" alt="Normalized confusion matrix for meter, window, and digit classes" loading="lazy" /><div><strong>Normalized confusion matrix</strong><span>Where meter, window, and digit classes are correctly recognized or confused</span></div></a> | |
| </div> | |
| <p class="metrics-note"><strong>Interpretation note:</strong> These are object-detection validation metrics, not full meter-reading string accuracy. A complete reading also depends on finding the window, filtering digits, ordering them correctly, and applying the unknown rule.</p> | |
| </section> | |
| </div> | |
| <div id="tab-history" class="tab-panel" data-tab-panel="history"> | |
| <section class="history-section"> | |
| <div class="history-heading"> | |
| <div><div class="kicker"><span></span> LOCAL SESSION</div><h2>Recent readings</h2></div> | |
| <button id="clearHistoryButton" class="quiet-button" type="button">Clear history</button> | |
| </div> | |
| <div id="historyList" class="history-list"></div> | |
| </section> | |
| </div> | |
| <div id="tab-guide" class="tab-panel" data-tab-panel="guide"> | |
| <section class="guide-section"> | |
| <div class="performance-heading guide-heading"> | |
| <div> | |
| <div class="kicker"><span></span> SIMPLE SETUP GUIDE</div> | |
| <h2>Choose settings with confidence.</h2> | |
| <p>The model detects objects first, then the application filters duplicates and marks uncertain digits for review.</p> | |
| </div> | |
| <button id="applyRecommendedButton" class="evidence-link" type="button">Apply recommended settings</button> | |
| </div> | |
| <div class="guide-grid"> | |
| <article class="guide-card"><span>01</span><div><small>DETECTION CONFIDENCE</small><h3>Should this box be kept?</h3><p><b>Lower</b> values can recover faint digits but may add false boxes. <b>Higher</b> values show fewer, stronger detections.</p><strong>Recommended: 10%</strong></div></article> | |
| <article class="guide-card"><span>02</span><div><small>OVERLAP / IoU</small><h3>Is this a duplicate box?</h3><p>Controls how strongly overlapping predictions are removed. It does not change what digit the model guessed.</p><strong>Recommended: 45%</strong></div></article> | |
| <article class="guide-card"><span>03</span><div><small>UNKNOWN THRESHOLD</small><h3>Can this digit be trusted?</h3><p>A retained digit below this value becomes <b>?</b>. Its raw guess remains visible so a person can review it.</p><strong>Recommended: 40%</strong></div></article> | |
| </div> | |
| <article class="reading-flow glass-panel"> | |
| <div><span>1</span><strong>Detect</strong><small>YOLO finds meter, window and digit boxes.</small></div><i></i> | |
| <div><span>2</span><strong>Filter</strong><small>Confidence and IoU remove weak or duplicate boxes.</small></div><i></i> | |
| <div><span>3</span><strong>Order</strong><small>Digits inside the window are sorted left to right.</small></div><i></i> | |
| <div><span>4</span><strong>Review</strong><small>Uncertain digits become ? without becoming a model class.</small></div> | |
| </article> | |
| <div class="guide-note"><strong>Important:</strong> Unknown is post-processing, not one of the 12 trained classes. Changing this setting does not change the model's validation mAP.</div> | |
| </section> | |
| <section class="tech-strip"> | |
| <div><span>01</span><p><strong>Private by design</strong>Your image never leaves the device.</p></div> | |
| <div><span>02</span><p><strong>Custom YOLO model</strong>Trained for meter, window and digits.</p></div> | |
| <div><span>03</span><p><strong>Browser inference</strong>ONNX Runtime Web, no paid server.</p></div> | |
| </section> | |
| </div> | |
| </main> | |
| <footer> | |
| <div><strong>AquaVision AI</strong><span>Water Meter Reading System MVP</span></div> | |
| <div class="footer-links"><a href="https://huggingface.co/kagabo/hf_water_meter_models" target="_blank" rel="noreferrer">Model</a><a href="https://github.com/kai-lucky72/watermeter-vision" target="_blank" rel="noreferrer">GitHub</a></div> | |
| </footer> | |
| <div id="toast" class="toast" role="status" aria-live="polite"></div> | |
| </body> | |
| </html> | |