Improve L2 market parsing and data handling
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
# Dynamic Tooltip Crop Evidence
|
||||
|
||||
## Acceptance Evidence
|
||||
|
||||
- Browser geometry: a 1920 x 1080 reference keeps an intrinsic canvas of
|
||||
1920 x 1080 and renders at 3840 x 2160. The stage scroll width grows to
|
||||
3888 px, so the image is not squeezed back into the panel. See
|
||||
[calibration-2x.png](./calibration-2x.png).
|
||||
- Browser pointer smoke: drawing on the 2x canvas creates calibration regions
|
||||
and advances through all six calibration steps. The marker drag from display
|
||||
`(326.6, 604)` to `(426.6, 642)` mapped to source `(288, 259)` through
|
||||
`(338, 278)` and was subsequently found by anchor matching at 99.8%.
|
||||
- Real tooltip fixture: the complete calibration check finished 6/6 stages and
|
||||
parsed `Sword of Revolution`, quantity `1`, and `1,700,000 Adena` at 70% OCR
|
||||
confidence. The third descriptive tooltip row was not passed to item parsing.
|
||||
See [tooltip-diagnostics.png](./tooltip-diagnostics.png).
|
||||
- The wide tooltip region is used only for the `Price :` anchor search. The
|
||||
item OCR preview contains the fitted name and price rows, not the full search
|
||||
band.
|
||||
|
||||
## Verification
|
||||
|
||||
- `node.exe --test`: 18 tests passed, including white/yellow pixel masks,
|
||||
stopping a text run before distant UI noise, and fitting a short row whose
|
||||
legacy saved width crosses the frame edge.
|
||||
- `node.exe node_modules/vite/bin/vite.js build`: production build passed.
|
||||
Vite reports the existing large OpenCV chunk warning.
|
||||
- `git diff --check`: passed; Git only reported LF-to-CRLF conversion warnings.
|
||||
|
||||
## Review Notes
|
||||
|
||||
- PRE plan review: aligned after clarifying the single owner of the dynamic
|
||||
right edge, the no-wide-OCR fallback, and legacy calibration behavior.
|
||||
- POST plan review: aligned; saved screenshots and the unbounded-run regression
|
||||
close the evidence and no-wide-fallback gates.
|
||||
- Correctness review: no remaining findings after isolating fitted rows in a
|
||||
masked composite and applying yellow pixels only to the price row.
|
||||
- Maintainability review: no remaining findings after reading pixels directly
|
||||
from the source canvas and simplifying the text-run control flow.
|
||||
@@ -0,0 +1,10 @@
|
||||
# Goal: Dynamic Tooltip Crop
|
||||
|
||||
Use Krypton Execution to execute `docs/goals/dynamic-tooltip-crop/PLAN.md`.
|
||||
|
||||
Core rules:
|
||||
- Treat PLAN.md as the source plan.
|
||||
- Preserve intent, ownership, contract, cutover, evidence, and kill criteria.
|
||||
- Do not add a second wide-area OCR path.
|
||||
- Keep existing calibration data readable; fixed widths provide seed geometry only and must not be used as a wide OCR fallback. Empty masks produce diagnostics `not-found`.
|
||||
- Capture acceptance evidence in `EVIDENCE.md`.
|
||||
@@ -0,0 +1,69 @@
|
||||
# Dynamic Tooltip Crop Implementation Plan
|
||||
|
||||
**Intent:** Сделать ручную калибровку пиксель-точной при масштабе 2× и читать строки tooltip переменной ширины без OCR всего кадра.
|
||||
**Current Behavior:** Калибратор показывает кадр 1:1, а runtime после поиска `Price :` использует фиксированную ширину калиброванных строк названия и цены.
|
||||
**Expected Outcome:** Кадр размечается в масштабе 2×; найденные строки названия и итоговой цены tooltip локально подгоняются вправо по фактическим белым и жёлтым пикселям до первого устойчивого пустого промежутка, включая текст длиннее калиброванного образца.
|
||||
**Target-Perspective Output:** Пользователь выделяет мелкие области на увеличенном кадре и получает название и цену как для короткого, так и для длинного tooltip без постороннего текста за его правой границей.
|
||||
**Truth Owner:** `src/vision.js` владеет определением фактической правой границы OCR-строки; калибровка сохраняет стабильный левый край, положение и высоту строки относительно `Price :`.
|
||||
**Contract Boundary:** Чистый `findTextRunEnd(columns, gap)` находит конец первого текстового пробега. Canvas-wrapper `fitOcrTextRect(canvas, rect, options)` сканирует от калиброванного левого края до правой границы кадра, использует gap 12 px и padding 6 px, применяет white mask для названия и white+yellow для цены и возвращает frame-clamped rect либо `null`, если пробег не найден.
|
||||
**Cutover:** `analyzeFrame` подгоняет `nameRect` и `priceRect` перед `combineRects`; прямое использование фиксированной ширины прекращается.
|
||||
**Displaced Path:** Фиксированные ширины `itemNameRegion` и `itemPriceRegion` больше не задают окончательную границу и не используются как широкий OCR fallback; при пустой маске item OCR пропускается с диагностикой.
|
||||
**Value Density:** Один локальный пиксельный проход по двум тонким строкам вместо OCR широкой области или нескольких OCR-попыток.
|
||||
**Evidence Gate:** На реальном тестовом кадре 1920×1080 canvas отображается 3840×2160; выделение в 2× визуально совпадает с целевыми source-пикселями; реальный tooltip читается при искусственно короткой калиброванной ширине, а удалённый соседний текст не попадает в diagnostics crop/OCR.
|
||||
**Acceptance Evidence:** Browser geometry и screenshot выделения; границы двух реальных строк разной длины из предоставленного tooltip; diagnostics crop + parsed name/price этого tooltip при намеренно узкой калиброванной ширине; runnable-тест чистого определения конца текстового пробега; production build.
|
||||
**Evidence Lane:** Локальный браузер и `node --test`.
|
||||
**Kill Criteria:** В runtime нет второго OCR-пути по широкой области или широкого фиксированного fallback; `combineRects` не вызывается до успешной подгонки обеих строк.
|
||||
**Architecture Slice:** `src/main.js`, `src/vision.js`, `src/style.css`, `test/parser.test.js`, `README.md`; документация калибровки уточняет различие зоны поиска и OCR-строк.
|
||||
**Plan Review Gate:** Requires PRE review before execution.
|
||||
|
||||
## Architecture Slice
|
||||
|
||||
- Files to create: только этот goal-пакет.
|
||||
- Files to modify: `src/main.js`, `src/vision.js`, `src/style.css`, `test/parser.test.js`, `README.md`.
|
||||
- Files to avoid: сохранённый формат калибровки, парсер текста tooltip, market outbox и backend.
|
||||
- Source of truth: найденный `Price :` задаёт позицию; пиксели текущего кадра задают фактическую ширину.
|
||||
- Read path: кадр → поиск магазина → поиск `Price :` → калиброванные строки → подгонка по пикселям → OCR → parser.
|
||||
- Write path: без новых сохраняемых полей; существующая калибровка остаётся совместимой.
|
||||
- Contract boundary: чистый `findTextRunEnd` и canvas-wrapper `fitOcrTextRect` в vision-слое.
|
||||
- Integration points: два прямоугольника в `analyzeFrame`, CSS-размер canvas.
|
||||
- Migration/cutover: немедленный, без миграции данных.
|
||||
- Displaced path: фиксированная ширина перестаёт быть OCR fallback; пустая маска становится наблюдаемым `not-found` в diagnostics.
|
||||
- Acceptance evidence gate: 2× browser geometry + screenshot точного выделения + diagnostics реального tooltip + unit test длинной строки + full build.
|
||||
|
||||
## Runtime Invariants
|
||||
|
||||
- Левый край строк названия и цены стабилен относительно найденного `Price :`; переменной является правая граница.
|
||||
- Продукт сохраняет только название, количество и итоговую цену; остальные описательные строки tooltip не являются данными продукта.
|
||||
- `tooltipSearchRegion` может быть широкой горизонтальной полосой за пределами окна трейда, но исключает нижний `Price` основного окна; эта полоса используется только для template matching.
|
||||
- Сканирование OCR-строки начинается с её калиброванного левого края, идёт не дальше правой границы кадра, допускает внутренние промежутки меньше 12 px и добавляет не более 6 px после последнего текстового столбца.
|
||||
- Название использует белую маску; цена использует белую и жёлтую маски.
|
||||
- Если текстовый пробег не найден, OCR предмета не запускается, а diagnostics явно сообщает причину.
|
||||
|
||||
## Tasks
|
||||
|
||||
1. Последовательно изменить `src/main.js` и `src/style.css`: отображать calibration canvas ровно в 2× intrinsic size; координаты остаются корректными через существующий `canvasPoint`.
|
||||
- Allowed scope: только display size и crisp integer scaling.
|
||||
- Verification: браузер показывает intrinsic 1920×1080 и rendered 3840×2160; screenshot известного выделения совпадает с source-пикселями.
|
||||
2. Затем изменить `src/vision.js` и `test/parser.test.js`: добавить чистый `findTextRunEnd` и локальную подгонку правого края с раздельными масками, gap 12, padding 6 и `null` для пустой маски.
|
||||
- Allowed scope: preprocessing границы; без нового OCR-прохода и без зависимости canvas в Node.
|
||||
- Verification: `node --test` покрывает длинный текст, внутренние пробелы, удалённый шум и пустую маску.
|
||||
3. После задачи 2 интегрировать подгонку в `src/main.js` до `combineRects`; при `null` остановить item OCR и записать причину в diagnostics.
|
||||
- Allowed scope: существующий item OCR branch.
|
||||
- Verification: diagnostics показывают фактический локальный crop, а широкий search region и удалённый соседний текст не попадают в OCR.
|
||||
4. Обязательно обновить `README.md`: широкая полоса ищет только `Price :`; ширины строк являются начальными левыми/вертикальными ориентирами и подгоняются runtime.
|
||||
- Allowed scope: только инструкции выбора `tooltipSearch`, `itemName` и `itemPrice`.
|
||||
- Verification: README больше не требует калибровать ширину по самому длинному предмету.
|
||||
5. Прогнать прямые эквиваленты `npm test`, `npm run build`, `git diff --check` и визуальную проверку большого кадра; записать реальные результаты в `EVIDENCE.md`.
|
||||
- Acceptance evidence: geometry 2×, screenshot точного выделения, границы двух реальных строк, diagnostics OCR/parse и вывод проверочных команд.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Не определять всю рамку tooltip и не сохранять его описательные строки, потому что продукту нужны название, количество и итоговая цена.
|
||||
- Не искать `Price :` по всему кадру без ограничивающей полосы.
|
||||
- Не добавлять настройку масштаба или новый UI-контрол в этом срезе.
|
||||
- Не менять формат сохранённой калибровки.
|
||||
|
||||
## Risks
|
||||
|
||||
- Слишком короткий допустимый пробел обрежет текст; слишком длинный захватит соседний UI.
|
||||
- Горизонтальная рамка внутри строки может выглядеть как непрерывный текст; точные вертикальные калиброванные строки остаются обязательными, а пустой/неограниченный пробег должен завершаться `not-found`, не широким OCR.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
Reference in New Issue
Block a user