added easyOCR
This commit is contained in:
parent
37d6678577
commit
9f208b0606
27 changed files with 1780 additions and 112 deletions
|
|
@ -129,6 +129,34 @@
|
|||
.link-item button { padding: 4px 12px; font-size: 12px; }
|
||||
.link-item.inactive { opacity: 0.5; }
|
||||
|
||||
.mode-badge {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
.mode-badge.live { background: #1f6feb; color: #fff; }
|
||||
.mode-badge.live:hover { background: #388bfd; }
|
||||
.mode-badge.scrap { background: #9e6a03; color: #fff; }
|
||||
.mode-badge.scrap:hover { background: #d29922; }
|
||||
|
||||
.mode-select {
|
||||
padding: 6px 10px;
|
||||
background: #0d1117;
|
||||
border: 1px solid #30363d;
|
||||
border-radius: 6px;
|
||||
color: #e6edf3;
|
||||
font-size: 13px;
|
||||
outline: none;
|
||||
}
|
||||
.mode-select:focus { border-color: #58a6ff; }
|
||||
|
||||
/* Toggle switch */
|
||||
.toggle { position: relative; width: 36px; height: 20px; cursor: pointer; flex-shrink: 0; }
|
||||
.toggle input { opacity: 0; width: 0; height: 0; }
|
||||
|
|
@ -316,6 +344,41 @@
|
|||
}
|
||||
.detect-badge.ok { background: #238636; color: #fff; }
|
||||
.detect-badge.fallback { background: #9e6a03; color: #fff; }
|
||||
|
||||
/* Inventory grid */
|
||||
.inv-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.inv-free {
|
||||
font-size: 12px;
|
||||
color: #8b949e;
|
||||
font-weight: 600;
|
||||
}
|
||||
.inventory-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(12, 1fr);
|
||||
gap: 2px;
|
||||
background: #161b22;
|
||||
border: 1px solid #30363d;
|
||||
border-radius: 8px;
|
||||
padding: 10px;
|
||||
}
|
||||
.inv-cell {
|
||||
aspect-ratio: 1;
|
||||
border-radius: 3px;
|
||||
background: #0d1117;
|
||||
min-width: 0;
|
||||
}
|
||||
.inv-cell.occupied {
|
||||
background: #238636;
|
||||
}
|
||||
.inv-cell.item-top { border-top: 2px solid #3fb950; }
|
||||
.inv-cell.item-bottom { border-bottom: 2px solid #3fb950; }
|
||||
.inv-cell.item-left { border-left: 2px solid #3fb950; }
|
||||
.inv-cell.item-right { border-right: 2px solid #3fb950; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -359,11 +422,25 @@
|
|||
<button class="warning" id="pauseBtn" onclick="togglePause()">Pause</button>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="inv-header">
|
||||
<div class="section-title" style="margin-bottom:0">Inventory</div>
|
||||
<span class="inv-free" id="invFreeCount"></span>
|
||||
</div>
|
||||
<div class="inventory-grid" id="inventoryGrid">
|
||||
<div class="empty-state" style="grid-column:1/-1">No active scrap session</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-title">Trade Links</div>
|
||||
<div class="add-link">
|
||||
<input type="text" id="nameInput" placeholder="Name (optional)" style="max-width:180px" />
|
||||
<input type="text" id="urlInput" placeholder="Paste trade URL..." />
|
||||
<select id="modeInput" class="mode-select" style="width:90px">
|
||||
<option value="live">Live</option>
|
||||
<option value="scrap">Scrap</option>
|
||||
</select>
|
||||
<button class="primary" onclick="addLink()">Add</button>
|
||||
</div>
|
||||
<div class="links-list" id="linksList">
|
||||
|
|
@ -375,6 +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>
|
||||
</select>
|
||||
<button onclick="debugScreenshot()">Screenshot</button>
|
||||
<button onclick="debugOcr()">OCR Screen</button>
|
||||
<button onclick="debugHideout()">Go Hideout</button>
|
||||
|
|
@ -382,6 +463,7 @@
|
|||
<div class="debug-row">
|
||||
<button onclick="debugFindAndClick('ANGE')">ANGE</button>
|
||||
<button onclick="debugFindAndClick('STASH')">STASH</button>
|
||||
<button onclick="debugFindAndClick('SALVAGE BENCH', true)">SALVAGE</button>
|
||||
</div>
|
||||
<div class="debug-row">
|
||||
<button onclick="debugAngeOption('Currency')">Currency Exchange</button>
|
||||
|
|
@ -512,6 +594,9 @@
|
|||
// Settings (populate once on first status)
|
||||
if (status.settings) populateSettings(status.settings);
|
||||
|
||||
// Inventory grid
|
||||
renderInventory();
|
||||
|
||||
// Active links count
|
||||
document.getElementById('linksValue').textContent = status.links.filter(l => l.active).length;
|
||||
|
||||
|
|
@ -527,6 +612,7 @@
|
|||
<input type="checkbox" ${link.active ? 'checked' : ''} onchange="toggleLink('${esc(link.id)}', this.checked)" />
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<span class="mode-badge ${link.mode || 'live'}" onclick="cycleMode('${esc(link.id)}', '${link.mode || 'live'}')" title="Click to change mode">${esc(link.mode || 'live')}</span>
|
||||
<div class="link-info">
|
||||
<div class="link-name" contenteditable="true" spellcheck="false"
|
||||
onblur="renameLink('${esc(link.id)}', this.textContent)"
|
||||
|
|
@ -542,6 +628,41 @@
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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' : '';
|
||||
html += `<div class="inv-cell ${occupied}" data-r="${r}" data-c="${c}"></div>`;
|
||||
}
|
||||
}
|
||||
container.innerHTML = html;
|
||||
|
||||
for (const item of items) {
|
||||
for (let r = item.row; r < item.row + item.h; r++) {
|
||||
for (let c = item.col; c < item.col + item.w; c++) {
|
||||
const cell = container.querySelector(`[data-r="${r}"][data-c="${c}"]`);
|
||||
if (cell) {
|
||||
if (r === item.row) cell.classList.add('item-top');
|
||||
if (r === item.row + item.h - 1) cell.classList.add('item-bottom');
|
||||
if (c === item.col) cell.classList.add('item-left');
|
||||
if (c === item.col + item.w - 1) cell.classList.add('item-right');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addLog(data) {
|
||||
const panel = document.getElementById('logPanel');
|
||||
const line = document.createElement('div');
|
||||
|
|
@ -561,12 +682,13 @@
|
|||
async function addLink() {
|
||||
const urlEl = document.getElementById('urlInput');
|
||||
const nameEl = document.getElementById('nameInput');
|
||||
const modeEl = document.getElementById('modeInput');
|
||||
const url = urlEl.value.trim();
|
||||
if (!url) return;
|
||||
await fetch('/api/links', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ url, name: nameEl.value.trim() }),
|
||||
body: JSON.stringify({ url, name: nameEl.value.trim(), mode: modeEl.value }),
|
||||
});
|
||||
urlEl.value = '';
|
||||
nameEl.value = '';
|
||||
|
|
@ -596,6 +718,15 @@
|
|||
}, 300);
|
||||
}
|
||||
|
||||
async function cycleMode(id, currentMode) {
|
||||
const newMode = currentMode === 'live' ? 'scrap' : 'live';
|
||||
await fetch('/api/links/' + encodeURIComponent(id) + '/mode', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ mode: newMode }),
|
||||
});
|
||||
}
|
||||
|
||||
function esc(s) {
|
||||
const d = document.createElement('div');
|
||||
d.textContent = s;
|
||||
|
|
@ -795,14 +926,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
async function debugFindAndClick(directText) {
|
||||
async function debugFindAndClick(directText, fuzzy) {
|
||||
const text = directText || document.getElementById('debugTextInput').value.trim();
|
||||
if (!text) return;
|
||||
showDebugResult(`Finding and clicking "${text}"...`);
|
||||
showDebugResult(`Finding and clicking "${text}"${fuzzy ? ' (fuzzy)' : ''}...`);
|
||||
const res = await fetch('/api/debug/find-and-click', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ text }),
|
||||
body: JSON.stringify({ text, fuzzy: !!fuzzy }),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.found) {
|
||||
|
|
@ -855,7 +986,26 @@
|
|||
if (e.key === 'Enter') addLink();
|
||||
});
|
||||
|
||||
async function setOcrEngine(engine) {
|
||||
await fetch('/api/debug/ocr-engine', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ engine }),
|
||||
});
|
||||
}
|
||||
|
||||
async function loadOcrEngine() {
|
||||
try {
|
||||
const res = await fetch('/api/debug/ocr-engine');
|
||||
const data = await res.json();
|
||||
if (data.ok && data.engine) {
|
||||
document.getElementById('ocrEngineSelect').value = data.engine;
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
connect();
|
||||
loadOcrEngine();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue