v1.0.171: ▶ Сравнить группу via SSE + classify timer/progress
This commit is contained in:
+60
-13
@@ -197,7 +197,28 @@ function showClassifyBtn() {
|
|||||||
async function runClassify() {
|
async function runClassify() {
|
||||||
var btn = document.getElementById('classifyBtn');
|
var btn = document.getElementById('classifyBtn');
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
btn.innerHTML = '<span class="spinner"></span> Классификация...';
|
btn.innerHTML = '<span class="spinner"></span> Классификация... 0с';
|
||||||
|
|
||||||
|
var start = Date.now();
|
||||||
|
var timer = setInterval(function() {
|
||||||
|
btn.innerHTML = '<span class="spinner"></span> Классификация... ' + Math.round((Date.now() - start) / 1000) + 'с';
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
// Poll progress каждые 2с
|
||||||
|
var pollTimer = setInterval(async function() {
|
||||||
|
try {
|
||||||
|
var r = await fetch(VM_API + '/api/batch-progress?batch=' + batchId);
|
||||||
|
var d = await r.json();
|
||||||
|
if (d.ok && d.counts) {
|
||||||
|
var done = (d.counts.classified || 0) + (d.counts.failed || 0);
|
||||||
|
var total = d.total || 0;
|
||||||
|
btn.innerHTML = '<span class="spinner"></span> Классификация... ' + done + '/' + total + ' (' + Math.round((Date.now() - start) / 1000) + 'с)';
|
||||||
|
if (done >= total && total > 0) {
|
||||||
|
clearInterval(pollTimer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(e) {}
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var resp = await fetch(VM_API + '/api/classify-batch', {
|
var resp = await fetch(VM_API + '/api/classify-batch', {
|
||||||
@@ -206,14 +227,18 @@ async function runClassify() {
|
|||||||
body: JSON.stringify({batch_id: batchId})
|
body: JSON.stringify({batch_id: batchId})
|
||||||
});
|
});
|
||||||
var data = await resp.json();
|
var data = await resp.json();
|
||||||
|
clearInterval(timer);
|
||||||
|
clearInterval(pollTimer);
|
||||||
if (data.ok) {
|
if (data.ok) {
|
||||||
btn.innerHTML = '✓ ' + data.done + '/' + data.total + ' классифицировано';
|
btn.innerHTML = '✓ ' + data.done + '/' + data.total + ' классифицировано (' + Math.round((Date.now() - start) / 1000) + 'с)';
|
||||||
loadGroups();
|
loadGroups();
|
||||||
} else {
|
} else {
|
||||||
btn.innerHTML = '✗ ' + (data.error || 'ошибка');
|
btn.innerHTML = '✗ ' + (data.error || 'ошибка');
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
|
clearInterval(timer);
|
||||||
|
clearInterval(pollTimer);
|
||||||
btn.innerHTML = '✗ ' + e.message;
|
btn.innerHTML = '✗ ' + e.message;
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
}
|
}
|
||||||
@@ -283,27 +308,49 @@ window.runCompareForGroup = async function(gi) {
|
|||||||
|
|
||||||
var btn = event.target;
|
var btn = event.target;
|
||||||
btn.disabled = true;
|
btn.disabled = true;
|
||||||
btn.innerHTML = '<span class="spinner"></span> Применяю группу...';
|
btn.innerHTML = '<span class="spinner"></span> Применяю...';
|
||||||
|
|
||||||
// 1. Apply groups (creates contracts + supplements)
|
|
||||||
var ar = await fetch(VM_API + '/api/apply-groups', {
|
var ar = await fetch(VM_API + '/api/apply-groups', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify({batch_id: batchId, groups: [group]})
|
body: JSON.stringify({batch_id: batchId, groups: [group]})
|
||||||
});
|
});
|
||||||
var ad = await ar.json();
|
var ad = await ar.json();
|
||||||
if (!ad.ok) { btn.innerHTML = '✗ ' + ad.error; btn.disabled = false; return; }
|
if (!ad.ok || !ad.contract_ids || !ad.contract_ids.length) {
|
||||||
|
btn.innerHTML = '✗ ошибка'; btn.disabled = false; return;
|
||||||
|
}
|
||||||
|
|
||||||
// 2. Get the created contract_id from supplements
|
var cid = ad.contract_ids[0];
|
||||||
var sr = await fetch(VM_API + '/api/supplements?contract_id=&batch=' + batchId);
|
|
||||||
// Actually need contract_id — let's get it from groups data
|
|
||||||
|
|
||||||
btn.innerHTML = '<span class="spinner"></span> Сравнение...';
|
btn.innerHTML = '<span class="spinner"></span> Сравнение...';
|
||||||
|
|
||||||
// Use EventSource for process-v2 — but we need contract_id
|
var diffCard = document.getElementById('diffCard');
|
||||||
// For now: use the old compare flow with contractId
|
var diffBody = document.getElementById('diffBody');
|
||||||
btn.innerHTML = '✓ Готово — обновите страницу и нажмите «Общее сравнение»';
|
var diffStatus = document.getElementById('diffStatus');
|
||||||
btn.disabled = false;
|
diffCard.style.display = 'block';
|
||||||
|
diffBody.innerHTML = '';
|
||||||
|
diffStatus.textContent = '⏳ 0.0с';
|
||||||
|
|
||||||
|
var start = Date.now();
|
||||||
|
var timer = setInterval(function() {
|
||||||
|
diffStatus.textContent = '⏳ ' + ((Date.now() - start) / 1000).toFixed(1) + 'с';
|
||||||
|
}, 200);
|
||||||
|
|
||||||
|
var es = new EventSource(VM_API + '/process-v2?contract_id=' + cid);
|
||||||
|
es.onmessage = function(e) {
|
||||||
|
var d = JSON.parse(e.data);
|
||||||
|
if (d.type === 'done') {
|
||||||
|
clearInterval(timer); es.close();
|
||||||
|
diffStatus.textContent = '✓ ' + d.total_time_s + 'с';
|
||||||
|
btn.innerHTML = '✓ Готово'; btn.disabled = false;
|
||||||
|
} else if (d.type === 'applied') {
|
||||||
|
diffBody.innerHTML += '<div style="font-size:12px;margin-top:4px;">+' + (d.summary.added||0) + ' ~' + (d.summary.updated||0) + ' -' + (d.summary.deleted||0) + '</div>';
|
||||||
|
} else if (d.type === 'error') {
|
||||||
|
clearInterval(timer); es.close();
|
||||||
|
diffBody.innerHTML += '<div style="color:var(--destructive);">✗ ' + d.message + '</div>';
|
||||||
|
btn.innerHTML = '✗'; btn.disabled = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
es.onerror = function() { clearInterval(timer); es.close(); btn.innerHTML = '✗ соединение'; btn.disabled = false; };
|
||||||
};
|
};
|
||||||
|
|
||||||
function uploadFile(file, onProgress) {
|
function uploadFile(file, onProgress) {
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ def apply_groups(batch_id, groups_data):
|
|||||||
Возвращает {ok, created: количество созданных supplements}.
|
Возвращает {ok, created: количество созданных supplements}.
|
||||||
"""
|
"""
|
||||||
created = 0
|
created = 0
|
||||||
|
contract_ids = []
|
||||||
for g in groups_data:
|
for g in groups_data:
|
||||||
contract_number = g.get("contract_number", "")
|
contract_number = g.get("contract_number", "")
|
||||||
if contract_number == "__unresolved__":
|
if contract_number == "__unresolved__":
|
||||||
@@ -118,6 +119,7 @@ def apply_groups(batch_id, groups_data):
|
|||||||
# Create contract
|
# Create contract
|
||||||
c = db_contracts.insert(contract_number, counterparty)
|
c = db_contracts.insert(contract_number, counterparty)
|
||||||
contract_id = c["id"]
|
contract_id = c["id"]
|
||||||
|
contract_ids.append(contract_id)
|
||||||
|
|
||||||
# Create supplements in order
|
# Create supplements in order
|
||||||
for i, d in enumerate(docs):
|
for i, d in enumerate(docs):
|
||||||
@@ -126,4 +128,4 @@ def apply_groups(batch_id, groups_data):
|
|||||||
db_supplements.insert(contract_id, doc_id, supp_type)
|
db_supplements.insert(contract_id, doc_id, supp_type)
|
||||||
created += 1
|
created += 1
|
||||||
|
|
||||||
return {"ok": True, "created": created}
|
return {"ok": True, "created": created, "contract_ids": contract_ids}
|
||||||
|
|||||||
@@ -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.170 — Lucee</span></span>
|
<span class="title">Сверка договоров — LLM AI-driven Event Sourcing <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.0.171 — Lucee</span></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
|||||||
Reference in New Issue
Block a user