diff --git a/CHANGELOG.md b/CHANGELOG.md index 52fde71..300c492 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi ## [Unreleased] ### Changed +- **OCR custom-card persistence.** Browser-local and server-backed custom OCR profiles are now merged during reloads, + so a newly added Baidu or other OCR engine remains visible while settings synchronize; the OCR page also shows an + actionable empty state when no profiles exist. - **OCR engine category.** Engines now includes local OCR/document-parser profiles for KDL Frontier Parser nano and Baidu Unlimited-OCR, with custom OCR profiles, connection probes, page-image API guidance, and future Magazine workflow integration documented in the TODO roadmap. diff --git a/VERSION b/VERSION index 61b813d..5bb76b5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.25.2 +1.25.3 diff --git a/static/index.html b/static/index.html index 9406c91..d57ac41 100644 --- a/static/index.html +++ b/static/index.html @@ -10,7 +10,7 @@ - + @@ -27,12 +27,12 @@ - - - - - - + + + + + + @@ -398,7 +398,7 @@ window.toggleNavTree = function(treeId, chevronId) { - + diff --git a/static/js/engines.js b/static/js/engines.js index c5566c1..7e08d66 100644 --- a/static/js/engines.js +++ b/static/js/engines.js @@ -236,10 +236,21 @@ if (document.getElementById('s-llms')?.classList.contains('is-active')) { // ── Custom engine card storage helpers ──────────────────────────────────── function loadCustomEngineCards() { - if (_appSettings && Array.isArray(_appSettings.custom_engine_cards) && _appSettings.custom_engine_cards.length) - return _appSettings.custom_engine_cards; - try { return JSON.parse(localStorage.getItem('engines-custom-cards') || '[]'); } - catch (e) { return []; } + let local = []; + try { local = JSON.parse(localStorage.getItem('engines-custom-cards') || '[]'); } + catch (e) { local = []; } + const server = _appSettings && Array.isArray(_appSettings.custom_engine_cards) + ? _appSettings.custom_engine_cards : []; + // Keep older browser-local cards visible while the server settings migrate + // or while a just-added card is still being persisted. Server entries win + // on the same id/name so edits do not produce duplicate cards. + const merged = [...server]; + const seen = new Set(merged.map(c => String(c?.id || c?.name || '').toLowerCase()).filter(Boolean)); + for (const card of local) { + const key = String(card?.id || card?.name || '').toLowerCase(); + if (key && !seen.has(key)) { merged.push(card); seen.add(key); } + } + return merged; } function saveCustomEngineCards(cards) { localStorage.setItem('engines-custom-cards', JSON.stringify(cards)); @@ -622,7 +633,12 @@ function renderLocalContainers(containers) { if (gridTts) gridTts.innerHTML = containers.filter(isTts).map(buildCardHtml).join(''); if (gridStt) gridStt.innerHTML = containers.filter(isStt).map(buildCardHtml).join(''); if (gridLlm) gridLlm.innerHTML = containers.filter(isLlm).map(buildCardHtml).join(''); - if (gridOcr) gridOcr.innerHTML = containers.filter(isOcr).map(buildCardHtml).join(''); + if (gridOcr) { + const ocrCards = containers.filter(isOcr); + gridOcr.innerHTML = ocrCards.length + ? ocrCards.map(buildCardHtml).join('') + : '
No OCR profiles configured yet. Use Add Custom to add one.
'; + } [gridTts, gridStt, gridLlm, gridOcr].forEach(grid => { if (!grid) return;