added test cases

This commit is contained in:
Boki 2026-02-12 13:08:19 -05:00
parent c1892230b7
commit 93e2234c4e
9 changed files with 320 additions and 141 deletions

View file

@ -452,16 +452,10 @@
<div class="section-title">Debug Tools</div>
<div class="debug-panel">
<div class="debug-row">
<select id="ocrEngineSelect" onchange="setOcrEngine(this.value)" style="padding:6px 10px;background:#0d1117;border:1px solid #30363d;border-radius:6px;color:#e6edf3;font-size:13px">
<option value="tesseract">Tesseract</option>
<option value="easyocr">EasyOCR</option>
<option value="paddleocr">PaddleOCR</option>
</select>
<select id="ocrPreprocessSelect" onchange="setOcrPreprocess(this.value)" style="padding:6px 10px;background:#0d1117;border:1px solid #30363d;border-radius:6px;color:#e6edf3;font-size:13px">
<option value="none">No Preprocess</option>
<option value="bgsub" selected>BgSub</option>
<option value="tophat">TopHat</option>
</select>
<button onclick="openOcrSettings()" title="OCR Settings" style="display:flex;align-items:center;gap:4px">
<svg width="14" height="14" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="10" cy="10" r="3"/><path d="M10 1.5v2M10 16.5v2M3.4 3.4l1.4 1.4M15.2 15.2l1.4 1.4M1.5 10h2M16.5 10h2M3.4 16.6l1.4-1.4M15.2 4.8l1.4-1.4"/></svg>
OCR Settings
</button>
<button onclick="debugScreenshot()">Screenshot</button>
<button onclick="debugOcr()">OCR Screen</button>
<button onclick="debugHideout()">Go Hideout</button>
@ -555,6 +549,115 @@
</div>
</div>
<div class="modal-overlay" id="ocrSettingsModal">
<div class="modal">
<div class="modal-header">
<h2>OCR Settings</h2>
<button class="modal-close" onclick="closeOcrSettings()">&times;</button>
</div>
<div style="margin-bottom:16px">
<div class="section-title" style="margin-bottom:6px">Engine</div>
<select id="ocrEngine" class="mode-select" style="width:100%">
<option value="tesseract">Tesseract</option>
<option value="easyocr">EasyOCR</option>
<option value="paddleocr">PaddleOCR</option>
</select>
</div>
<div style="margin-bottom:16px">
<div class="section-title" style="margin-bottom:6px">Screen OCR</div>
<select id="ocrScreenPreprocess" class="mode-select" style="width:100%" onchange="toggleOcrSections()">
<option value="none">None</option>
<option value="tophat">TopHat</option>
</select>
<div id="screenTophatParams" style="display:none;margin-top:8px">
<div class="settings-grid">
<div class="setting-row">
<label>Kernel Size</label>
<input type="number" id="ocrScreenKernel" value="41" />
</div>
</div>
</div>
</div>
<div style="margin-bottom:16px">
<div class="section-title" style="margin-bottom:6px">Tooltip OCR</div>
<select id="ocrTooltipPreprocess" class="mode-select" style="width:100%" onchange="toggleOcrSections()">
<option value="none">None</option>
<option value="bgsub">Background Subtraction</option>
<option value="tophat">TopHat</option>
</select>
<div id="tooltipBgsubParams" style="display:none;margin-top:8px">
<div class="settings-grid">
<div class="setting-row">
<label>Dim Percentile</label>
<input type="number" id="ocrDimPercentile" value="40" />
</div>
<div class="setting-row">
<label>Text Threshold</label>
<input type="number" id="ocrTextThresh" value="60" />
</div>
</div>
<div style="display:flex;align-items:center;gap:8px;margin-top:8px">
<label class="toggle">
<input type="checkbox" id="ocrSoftThreshold" />
<span class="slider"></span>
</label>
<span style="font-size:12px;color:#8b949e">Soft Threshold</span>
</div>
</div>
<div id="tooltipTophatParams" style="display:none;margin-top:8px">
<div class="settings-grid">
<div class="setting-row">
<label>Kernel Size</label>
<input type="number" id="ocrTooltipKernel" value="41" />
</div>
</div>
</div>
</div>
<div style="margin-bottom:16px">
<div class="section-title" style="margin-bottom:6px">Tooltip Detection</div>
<div class="settings-grid">
<div class="setting-row">
<label>Diff Threshold</label>
<input type="number" id="ocrDiffThresh" value="20" />
</div>
<div class="setting-row">
<label>Max Gap</label>
<input type="number" id="ocrMaxGap" value="20" />
</div>
<div class="setting-row">
<label>Trim Cutoff</label>
<input type="number" id="ocrTrimCutoff" value="0.4" step="0.1" />
</div>
<div class="setting-row">
<label>Upscale</label>
<input type="number" id="ocrUpscale" value="2" />
</div>
</div>
</div>
<div style="margin-bottom:16px">
<div class="section-title" style="margin-bottom:6px">Options</div>
<div style="display:flex;align-items:center;gap:8px">
<label class="toggle">
<input type="checkbox" id="ocrSaveDebugImages" checked />
<span class="slider"></span>
</label>
<span style="font-size:12px;color:#8b949e">Save debug images to disk</span>
</div>
</div>
<div class="settings-actions">
<span class="saved-badge" id="ocrSavedBadge">Saved</span>
<button onclick="closeOcrSettings()" style="margin-right:8px">Close</button>
<button class="primary" onclick="saveOcrSettings()">Save</button>
</div>
</div>
</div>
<script>
let ws;
let status = { paused: false, state: 'IDLE', links: [], tradesCompleted: 0, tradesFailed: 0, uptime: 0, settings: {} };
@ -639,18 +742,16 @@
function renderInventory() {
const container = document.getElementById('inventoryGrid');
const freeLabel = document.getElementById('invFreeCount');
if (!status.inventory) {
container.innerHTML = '<div class="empty-state" style="grid-column:1/-1">No active scrap session</div>';
freeLabel.textContent = '';
return;
}
const { grid, items, free } = status.inventory;
const grid = status.inventory ? status.inventory.grid : null;
const items = status.inventory ? status.inventory.items : [];
const free = status.inventory ? status.inventory.free : 60;
freeLabel.textContent = `${free}/60 free`;
let html = '';
for (let r = 0; r < 5; r++) {
for (let c = 0; c < 12; c++) {
const occupied = grid[r] && grid[r][c] ? 'occupied' : '';
const occupied = grid && grid[r] && grid[r][c] ? 'occupied' : '';
html += `<div class="inv-cell ${occupied}" data-r="${r}" data-c="${c}"></div>`;
}
}
@ -891,7 +992,7 @@
});
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') closeSettings();
if (e.key === 'Escape') { closeSettings(); closeOcrSettings(); }
});
async function saveSettings() {
@ -1010,46 +1111,98 @@
if (e.key === 'Enter') addLink();
});
// OCR engine/preprocess (sync — these are instant)
async function setOcrEngine(engine) {
await fetch('/api/debug/ocr-engine', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ engine }),
});
// --- OCR Settings modal ---
function openOcrSettings() {
loadOcrSettings();
document.getElementById('ocrSettingsModal').classList.add('open');
}
async function loadOcrEngine() {
function closeOcrSettings() {
document.getElementById('ocrSettingsModal').classList.remove('open');
}
document.getElementById('ocrSettingsModal').addEventListener('click', (e) => {
if (e.target === e.currentTarget) closeOcrSettings();
});
function toggleOcrSections() {
const screenPp = document.getElementById('ocrScreenPreprocess').value;
document.getElementById('screenTophatParams').style.display = screenPp === 'tophat' ? '' : 'none';
const tooltipPp = document.getElementById('ocrTooltipPreprocess').value;
document.getElementById('tooltipBgsubParams').style.display = tooltipPp === 'bgsub' ? '' : 'none';
document.getElementById('tooltipTophatParams').style.display = tooltipPp === 'tophat' ? '' : 'none';
}
async function loadOcrSettings() {
try {
const res = await fetch('/api/debug/ocr-engine');
const res = await fetch('/api/debug/ocr-settings');
const data = await res.json();
if (data.ok && data.engine) {
document.getElementById('ocrEngineSelect').value = data.engine;
}
if (!data.ok) return;
document.getElementById('ocrEngine').value = data.engine || 'easyocr';
document.getElementById('ocrScreenPreprocess').value = data.screenPreprocess || 'none';
document.getElementById('ocrTooltipPreprocess').value = data.tooltipPreprocess || 'bgsub';
document.getElementById('ocrSaveDebugImages').checked = data.saveDebugImages !== false;
const tp = data.tooltipParams || {};
document.getElementById('ocrDiffThresh').value = tp.diffThresh ?? 20;
document.getElementById('ocrMaxGap').value = tp.maxGap ?? 20;
document.getElementById('ocrTrimCutoff').value = tp.trimCutoff ?? 0.4;
document.getElementById('ocrUpscale').value = tp.upscale ?? 2;
document.getElementById('ocrDimPercentile').value = tp.dimPercentile ?? 40;
document.getElementById('ocrTextThresh').value = tp.textThresh ?? 60;
document.getElementById('ocrSoftThreshold').checked = !!tp.softThreshold;
document.getElementById('ocrScreenKernel').value = tp.kernelSize ?? 41;
document.getElementById('ocrTooltipKernel').value = tp.kernelSize ?? 41;
toggleOcrSections();
} catch {}
}
async function setOcrPreprocess(preprocess) {
await fetch('/api/debug/ocr-preprocess', {
async function saveOcrSettings() {
const tooltipPp = document.getElementById('ocrTooltipPreprocess').value;
const screenPp = document.getElementById('ocrScreenPreprocess').value;
const tooltipParams = {
diffThresh: parseInt(document.getElementById('ocrDiffThresh').value) || 20,
maxGap: parseInt(document.getElementById('ocrMaxGap').value) || 20,
trimCutoff: parseFloat(document.getElementById('ocrTrimCutoff').value) || 0.4,
upscale: parseInt(document.getElementById('ocrUpscale').value) || 2,
useBackgroundSub: tooltipPp === 'bgsub',
};
if (tooltipPp === 'bgsub') {
tooltipParams.dimPercentile = parseInt(document.getElementById('ocrDimPercentile').value) || 40;
tooltipParams.textThresh = parseInt(document.getElementById('ocrTextThresh').value) || 60;
tooltipParams.softThreshold = document.getElementById('ocrSoftThreshold').checked;
}
if (tooltipPp === 'tophat') {
tooltipParams.kernelSize = parseInt(document.getElementById('ocrTooltipKernel').value) || 41;
}
if (screenPp === 'tophat') {
tooltipParams.kernelSize = parseInt(document.getElementById('ocrScreenKernel').value) || 41;
}
const body = {
engine: document.getElementById('ocrEngine').value,
screenPreprocess: screenPp,
tooltipPreprocess: tooltipPp,
tooltipParams,
saveDebugImages: document.getElementById('ocrSaveDebugImages').checked,
};
await fetch('/api/debug/ocr-settings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ preprocess }),
body: JSON.stringify(body),
});
}
async function loadOcrPreprocess() {
try {
const res = await fetch('/api/debug/ocr-preprocess');
const data = await res.json();
if (data.ok && data.preprocess) {
document.getElementById('ocrPreprocessSelect').value = data.preprocess;
}
} catch {}
const badge = document.getElementById('ocrSavedBadge');
badge.classList.add('show');
setTimeout(() => badge.classList.remove('show'), 2000);
}
connect();
loadOcrEngine();
loadOcrPreprocess();
loadOcrSettings();
</script>
</body>
</html>