feat(validation): chunk screenshots by max_images limit + fix websocket crash

- analyze_dashboard_multimodal now splits screenshots into chunks
  of max_images (from provider config) and sends them in parallel
- Results merged: worst status, deduped issues by (severity, msg, loc)
- New helper methods: _deduplicate_issues, _merge_chunk_results, _call_llm_for_images
- Plugin passes db_provider.max_images to the LLM client
- Report UI shows 'Chunked ×N' badge when analysis used multiple chunks
- i18n: added 'chunked' / 'По частям' key to validation.json
- Fix: isinstance(StopIteration) -> isinstance(_ws_exc, StopIteration)
  which crashed the websocket and broke task execution mid-flight
- Fix: update test mocks (_FakeLLMClient, _FakeScreenshotService)
This commit is contained in:
2026-05-31 22:43:06 +03:00
parent 9b938fcb81
commit 2760fa09ea
7 changed files with 134 additions and 18 deletions

View File

@@ -212,5 +212,6 @@
"path_b": "Path B — Text-only",
"no_issues": "No issues detected",
"no_logs": "No logs available",
"no_screenshots": "No screenshots saved"
"no_screenshots": "No screenshots saved",
"chunked": "Chunked"
}

View File

@@ -212,5 +212,6 @@
"path_b": "Путь B — Только текст",
"no_issues": "Проблем не обнаружено",
"no_logs": "Нет доступных логов",
"no_screenshots": "Нет сохраненных скриншотов"
"no_screenshots": "Нет сохраненных скриншотов",
"chunked": "По частям"
}

View File

@@ -414,6 +414,11 @@
{#if dbPath === 'A'}
<span class="text-purple-600 font-medium">📸 {$t.validation?.path_a || 'Path A — Screenshot'}</span>
<span class="text-gray-400">| {$t.validation?.screenshots || 'Screenshots'} captured via browser automation</span>
{#if dashboard.chunk_count && dashboard.chunk_count > 1}
<span class="inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-amber-100 text-amber-700 text-xs font-medium">
{$t.validation?.chunked || 'Chunked'} ×{dashboard.chunk_count}
</span>
{/if}
{:else}
<span class="text-teal-600 font-medium">📝 {$t.validation?.path_b || 'Path B — Text-only'}</span>
<span class="text-gray-400">| {$t.validation?.issues || 'Issue'} detection via DOM extraction</span>