feat: Default to OCR scanner, auto-start camera, hide viewport after capture

- Default add-asset mode changed from barcode to OCR
- Auto-start OCR camera when switching to OCR mode or Add Asset tab
- Camera viewport hidden entirely after photo capture (no placeholder showing)
- Retake button added to all OCR result states (found, not-found, error)
- 'Retake' resets UI and re-starts camera for a new photo
This commit is contained in:
2026-06-01 19:12:01 -04:00
parent 03cf4b9281
commit 86975e2e2b
4 changed files with 42 additions and 22 deletions
Binary file not shown.
Binary file not shown.
+7 -13
View File
@@ -1,16 +1,10 @@
#!/bin/bash
# Restart canteen-asset-tracker server
cd /home/oplabs/projects/canteen-asset-tracker
# Kill existing server
pkill -f "python.*server.py" 2>/dev/null || true
pkill -f "uvicorn.*server:app.*8901" 2>/dev/null || true
sleep 1
# Activate venv and start
source .venv/bin/activate
nohup python server.py > /tmp/canteen-server.log 2>&1 &
echo "Server PID: $!"
sleep 3
# Check health
curl -s http://localhost:8901/health 2>/dev/null || curl -s http://localhost:8900/health 2>/dev/null || echo "Health check failed"
python -m uvicorn server:app --host 0.0.0.0 --port 8901 \
--ssl-keyfile key.pem --ssl-certfile cert.pem --log-level info \
> /tmp/canteen-server.log 2>&1 &
echo "PID=$!"
sleep 2
curl -sk https://localhost:8901/health 2>/dev/null
+35 -9
View File
@@ -2438,9 +2438,13 @@
el.classList.toggle('active', el.dataset.tab === tabId);
});
// Tab lifecycle hooks
if (tabId === 'tabAddAsset') startScanning();
else stopScanning();
// Tab lifecycle hooks — start the appropriate scanner
if (tabId === 'tabAddAsset') {
if (addAssetMode === 'ocr') startOcrCamera();
else startScanning();
} else {
stopScanning();
}
if (tabId === 'tabAssets') { loadAssets(); }
@@ -2553,7 +2557,7 @@
// ═══════════════════════════════════════════════════════════════════════
// ADD ASSET TAB — 3 Modes: Barcode, OCR, Manual
// ═══════════════════════════════════════════════════════════════════════
let addAssetMode = 'barcode';
let addAssetMode = 'ocr';
let stream = null;
let ocrStream = null;
let codeReader = null;
@@ -2582,6 +2586,8 @@
if (mode === 'barcode') {
startScanning();
} else if (mode === 'ocr') {
startOcrCamera();
}
}
@@ -3133,7 +3139,8 @@
<div class="or-id">${esc(data.machine_id)}${methodBadge}</div>
<div class="or-meta">${confLabel}</div>
${data.raw_text ? `<div class="or-raw">OCR text: ${esc(data.raw_text)}</div>` : ''}
<div class="or-searching" style="margin-top:8px;font-size:13px;color:var(--text2);">🔍 Searching for asset...</div>`;
<div class="or-searching" style="margin-top:8px;font-size:13px;color:var(--text2);">🔍 Searching for asset...</div>
<div style="margin-top:8px;"><button class="btn btn-outline btn-sm" onclick="retakeOcr()" style="width:100%;">🔄 Retake</button></div>`;
setOcrStatus('Machine ID found! Searching...', 'working');
// Auto-search the asset
@@ -3142,7 +3149,8 @@
el.innerHTML = `
<div style="font-size:16px;font-weight:600;color:var(--red);">No machine ID detected</div>
<div class="or-meta">Try again with better lighting and focus on the sticker.</div>
${data.raw_text ? `<div class="or-raw">OCR text: ${esc(data.raw_text)}</div>` : ''}`;
${data.raw_text ? `<div class="or-raw">OCR text: ${esc(data.raw_text)}</div>` : ''}
<div style="margin-top:8px;"><button class="btn btn-outline btn-sm" onclick="retakeOcr()" style="width:100%;">🔄 Try Again</button></div>`;
setOcrStatus('No machine ID found — try again', 'error');
}
@@ -3215,15 +3223,17 @@
el.innerHTML += `<div style="margin-top:8px;font-size:12px;color:var(--green);">${gi("📍")} GPS saved to asset</div>`;
AppState.ocrGpsSaved = false;
}
el.innerHTML += `<div style="margin-top:8px;">
<button class="btn btn-outline btn-sm" onclick="switchTab('tabAssets');viewAsset(${asset.id});" style="width:100%;">View Details</button>
el.innerHTML += `<div style="margin-top:8px;display:flex;gap:6px;">
<button class="btn btn-outline btn-sm" onclick="switchTab('tabAssets');viewAsset(${asset.id});" style="flex:1;">View Details</button>
<button class="btn btn-outline btn-sm" onclick="retakeOcr()" style="flex:1;">🔄 Retake</button>
</div>`;
} catch (e) {
if (e.message === 'Asset not found' || e.message.includes('404')) {
const el = document.getElementById('ocrResult');
el.innerHTML = `
<div class="or-id">${esc(machineId)} ❌</div>
<div class="or-meta" style="color:var(--amber);">Machine ID not found in database</div>`;
<div class="or-meta" style="color:var(--amber);">Machine ID not found in database</div>
<div style="margin-top:8px;"><button class="btn btn-outline btn-sm" onclick="retakeOcr()" style="width:100%;">🔄 Retake</button></div>`;
setOcrStatus('Asset not found — try scanning the barcode instead', 'error');
} else {
setOcrStatus('Lookup error: ' + e.message, 'error');
@@ -3262,6 +3272,18 @@
};
}
// ── Retake OCR photo after capture ──────────────────────────────────
function retakeOcr() {
// Reset the OCR UI for a new capture
document.getElementById('ocrResult').style.display = 'none';
document.getElementById('ocrResult').innerHTML = '';
document.getElementById('ocrGpsBadge').style.display = 'none';
setOcrStatus('', '');
const camArea = document.getElementById('ocrCameraArea');
if (camArea) camArea.style.display = '';
startOcrCamera();
}
async function captureOcr() {
const video = document.getElementById('ocrVideo');
if (!video || !ocrStream) return;
@@ -3275,6 +3297,10 @@
// Stop camera after capturing photo
stopOcrCamera();
// Hide the camera viewport entirely — don't show placeholder after capture
const camArea = document.getElementById('ocrCameraArea');
if (camArea) camArea.style.display = 'none';
setOcrStatus('Processing OCR...', 'working');
document.getElementById('ocrResult').style.display = 'none';