From 8a5d93a5c758ec454b796b25edab2f66c01ea436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Wed, 24 Jun 2026 08:27:29 +0400 Subject: [PATCH] =?UTF-8?q?v1.0.163:=20classify=20UI=20=E2=80=94=20batch?= =?UTF-8?q?=5Fid,=20=D0=9A=D0=BB=D0=B0=D1=81=D1=81=D0=B8=D1=84=D0=B8=D1=86?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20button,=20group=20?= =?UTF-8?q?cards?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/app.js | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++- index.cfm | 2 +- 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/deploy/app.js b/deploy/app.js index 5d60219..86b5e0d 100644 --- a/deploy/app.js +++ b/deploy/app.js @@ -11,6 +11,7 @@ var fileInput = document.getElementById('fileInput'); var fileTable = document.getElementById('fileTable'); var fileQueue = []; var contractId = null; +var batchId = crypto.randomUUID(); // классификация: привязка всех файлов сессии function formatSize(bytes) { if (!bytes || bytes === 0) return '—'; @@ -207,13 +208,94 @@ fileInput.addEventListener('change', async function() { fileInput.value = ''; fileInput.disabled = false; - // Показать кнопки LLM после авто-парсинга + // Показать кнопки после авто-парсинга var llmBtn = document.getElementById('llmBtn'); llmBtn.style.display = 'flex'; llmBtn.disabled = false; + showClassifyBtn(); lucide.createIcons(); }); +// ── Классификация ────────────────────────────────────────── +function showClassifyBtn() { + var btn = document.getElementById('classifyBtn'); + if (!btn) { + btn = document.createElement('button'); + btn.id = 'classifyBtn'; + btn.className = 'btn btn-primary'; + btn.style.cssText = 'width:100%;justify-content:center;margin-top:8px;background:var(--brand-primary);border-color:var(--brand-primary);'; + btn.innerHTML = ' Классифицировать'; + btn.addEventListener('click', runClassify); + document.getElementById('llmBtn').parentNode.insertBefore(btn, document.getElementById('llmBtn')); + } + btn.style.display = 'flex'; + btn.disabled = false; +} + +async function runClassify() { + var btn = document.getElementById('classifyBtn'); + btn.disabled = true; + btn.innerHTML = ' Классификация...'; + + try { + var resp = await fetch(VM_API + '/api/classify-batch', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({batch_id: batchId}) + }); + var data = await resp.json(); + if (data.ok) { + btn.innerHTML = '✓ ' + data.done + '/' + data.total + ' классифицировано'; + loadGroups(); + } else { + btn.innerHTML = '✗ ' + (data.error || 'ошибка'); + btn.disabled = false; + } + } catch(e) { + btn.innerHTML = '✗ ' + e.message; + btn.disabled = false; + } +} + +async function loadGroups() { + var resp = await fetch(VM_API + '/api/groups?batch=' + batchId); + var data = await resp.json(); + if (!data.ok || !data.groups) return; + + var diffBody = document.getElementById('diffBody'); + var diffCard = document.getElementById('diffCard'); + diffCard.style.display = 'block'; + diffBody.innerHTML = '
📋 Найдено групп: ' + data.groups.length + '
'; + + data.groups.forEach(function(g, gi) { + var isUnresolved = g.contract_number === '__unresolved__'; + var card = document.createElement('div'); + card.style.cssText = 'border:1px solid ' + (isUnresolved ? 'var(--destructive)' : 'var(--brand-gray)') + ';border-radius:6px;padding:10px;margin-bottom:8px;'; + card.innerHTML = '
' + + (isUnresolved ? '❓ Не распознано' : '📄 ' + (g.contract_number || 'Без номера') + ' — ' + (g.counterparty || 'контрагент не определён')) + + '
' + + '
' + + g.documents.map(function(d) { + return '
' + + '[' + (d.doc_type || '?') + '] ' + + d.filename + + (d.doc_date ? ' ' + d.doc_date + '' : '') + + '
'; + }).join('') + + '
'; + if (!isUnresolved) { + card.innerHTML += ''; + } + diffBody.appendChild(card); + }); + lucide.createIcons(); +} + +window.runCompareForGroup = function(gi) { + // TODO: run /process-v2 for the specific contract + alert('Сравнение для группы ' + gi + ' — в разработке'); +}; + function uploadFile(file, onProgress) { return new Promise(function(resolve, reject) { // .doc → конвертация в docx @@ -226,6 +308,7 @@ function uploadFile(file, onProgress) { var fd = new FormData(); fd.append('files', uploadFile, uploadName); if (contractId) fd.append('contract_id', contractId); + fd.append('batch_id', batchId); xhr.open('POST', UPLOAD_URL); xhr.upload.onprogress = function(e) { if (e.lengthComputable && onProgress) onProgress(Math.round(e.loaded / e.total * 100)); diff --git a/index.cfm b/index.cfm index 22ac895..4e84a5b 100644 --- a/index.cfm +++ b/index.cfm @@ -75,7 +75,7 @@
Nubes - Сверка договоров — LLM AI-driven Event Sourcing v1.0.162 — Lucee + Сверка договоров — LLM AI-driven Event Sourcing v1.0.163 — Lucee