v1.0.163: classify UI — batch_id, Классифицировать button, group cards
This commit is contained in:
+84
-1
@@ -11,6 +11,7 @@ var fileInput = document.getElementById('fileInput');
|
|||||||
var fileTable = document.getElementById('fileTable');
|
var fileTable = document.getElementById('fileTable');
|
||||||
var fileQueue = [];
|
var fileQueue = [];
|
||||||
var contractId = null;
|
var contractId = null;
|
||||||
|
var batchId = crypto.randomUUID(); // классификация: привязка всех файлов сессии
|
||||||
|
|
||||||
function formatSize(bytes) {
|
function formatSize(bytes) {
|
||||||
if (!bytes || bytes === 0) return '—';
|
if (!bytes || bytes === 0) return '—';
|
||||||
@@ -207,13 +208,94 @@ fileInput.addEventListener('change', async function() {
|
|||||||
|
|
||||||
fileInput.value = '';
|
fileInput.value = '';
|
||||||
fileInput.disabled = false;
|
fileInput.disabled = false;
|
||||||
// Показать кнопки LLM после авто-парсинга
|
// Показать кнопки после авто-парсинга
|
||||||
var llmBtn = document.getElementById('llmBtn');
|
var llmBtn = document.getElementById('llmBtn');
|
||||||
llmBtn.style.display = 'flex';
|
llmBtn.style.display = 'flex';
|
||||||
llmBtn.disabled = false;
|
llmBtn.disabled = false;
|
||||||
|
showClassifyBtn();
|
||||||
lucide.createIcons();
|
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 = '<i data-lucide="tags" style="width:16px;height:16px;"></i> Классифицировать';
|
||||||
|
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 = '<span class="spinner"></span> Классификация...';
|
||||||
|
|
||||||
|
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 = '<div style="font-weight:600;margin-bottom:8px;">📋 Найдено групп: ' + data.groups.length + '</div>';
|
||||||
|
|
||||||
|
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 = '<div style="font-weight:600;margin-bottom:6px;">' +
|
||||||
|
(isUnresolved ? '❓ Не распознано' : '📄 ' + (g.contract_number || 'Без номера') + ' — ' + (g.counterparty || 'контрагент не определён')) +
|
||||||
|
'</div>' +
|
||||||
|
'<div style="font-size:12px;">' +
|
||||||
|
g.documents.map(function(d) {
|
||||||
|
return '<div style="padding:2px 0;">' +
|
||||||
|
'<span style="color:var(--muted);">[' + (d.doc_type || '?') + ']</span> ' +
|
||||||
|
d.filename +
|
||||||
|
(d.doc_date ? ' <span style="color:var(--muted);">' + d.doc_date + '</span>' : '') +
|
||||||
|
'</div>';
|
||||||
|
}).join('') +
|
||||||
|
'</div>';
|
||||||
|
if (!isUnresolved) {
|
||||||
|
card.innerHTML += '<button class="btn" style="margin-top:6px;font-size:12px;height:28px;" onclick="runCompareForGroup(\'' + gi + '\')">▶ Сравнить</button>';
|
||||||
|
}
|
||||||
|
diffBody.appendChild(card);
|
||||||
|
});
|
||||||
|
lucide.createIcons();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.runCompareForGroup = function(gi) {
|
||||||
|
// TODO: run /process-v2 for the specific contract
|
||||||
|
alert('Сравнение для группы ' + gi + ' — в разработке');
|
||||||
|
};
|
||||||
|
|
||||||
function uploadFile(file, onProgress) {
|
function uploadFile(file, onProgress) {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
// .doc → конвертация в docx
|
// .doc → конвертация в docx
|
||||||
@@ -226,6 +308,7 @@ function uploadFile(file, onProgress) {
|
|||||||
var fd = new FormData();
|
var fd = new FormData();
|
||||||
fd.append('files', uploadFile, uploadName);
|
fd.append('files', uploadFile, uploadName);
|
||||||
if (contractId) fd.append('contract_id', contractId);
|
if (contractId) fd.append('contract_id', contractId);
|
||||||
|
fd.append('batch_id', batchId);
|
||||||
xhr.open('POST', UPLOAD_URL);
|
xhr.open('POST', UPLOAD_URL);
|
||||||
xhr.upload.onprogress = function(e) {
|
xhr.upload.onprogress = function(e) {
|
||||||
if (e.lengthComputable && onProgress) onProgress(Math.round(e.loaded / e.total * 100));
|
if (e.lengthComputable && onProgress) onProgress(Math.round(e.loaded / e.total * 100));
|
||||||
|
|||||||
@@ -75,7 +75,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="topbar">
|
<div class="topbar">
|
||||||
<img src="/nubes-logo.svg" alt="Nubes">
|
<img src="/nubes-logo.svg" alt="Nubes">
|
||||||
<span class="title">Сверка договоров — LLM AI-driven Event Sourcing <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.0.162 — Lucee</span></span>
|
<span class="title">Сверка договоров — LLM AI-driven Event Sourcing <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.0.163 — Lucee</span></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
|||||||
Reference in New Issue
Block a user