v1.0.178: fix async classify polling — frontend ждёт done>=total через batch-progress, fix путь логов

This commit is contained in:
2026-06-25 14:41:41 +04:00
parent 4e9dd94433
commit f143894e10
2 changed files with 37 additions and 9 deletions
+29 -2
View File
@@ -1,3 +1,4 @@
// ⛔ НЕ МЕНЯТЬ БЕЗ РАЗРЕШЕНИЯ НАЕЛЯ ⛔
// Contracts App — весь JS на VM (contracts.kube5s.ru)
// Lucee: только домен + index.cfm-скелет
var VM_API = 'https://contracts.kube5s.ru';
@@ -140,7 +141,10 @@ async function runClassify() {
btn.innerHTML = '<span class="spinner"></span> Классификация... ' + Math.round((Date.now() - start) / 1000) + 'с';
}, 1000);
// Poll progress каждые 2с
var totalFiles = 0;
var classifyDone = false;
// Poll progress каждые 2с — работает и для sync, и для async classify
var pollTimer = setInterval(async function() {
try {
var r = await fetch(VM_API + '/api/batch-progress?batch=' + state.batchId);
@@ -148,9 +152,16 @@ async function runClassify() {
if (d.ok && d.counts) {
var done = (d.counts.classified || 0) + (d.counts.failed || 0);
var total = d.total || 0;
if (total > 0) totalFiles = total;
btn.innerHTML = '<span class="spinner"></span> Классификация... ' + done + '/' + total + ' (' + Math.round((Date.now() - start) / 1000) + 'с)';
if (done >= total && total > 0) {
clearInterval(pollTimer);
clearInterval(timer);
classifyDone = true;
btn.innerHTML = '✓ ' + done + '/' + total + ' классифицировано (' + Math.round((Date.now() - start) / 1000) + 'с)';
stepDone('stepClassify');
stepActive('stepGroups');
loadGroupsAction();
}
}
} catch(e) {}
@@ -163,23 +174,39 @@ async function runClassify() {
body: JSON.stringify({batch_id: state.batchId})
});
var data = await resp.json();
// sync classify: ответ уже содержит done
if (data.ok && data.done !== undefined) {
clearInterval(timer);
clearInterval(pollTimer);
if (data.ok) {
classifyDone = true;
btn.innerHTML = '✓ ' + data.done + '/' + data.total + ' классифицировано (' + Math.round((Date.now() - start) / 1000) + 'с)';
stepDone('stepClassify');
stepActive('stepGroups');
loadGroupsAction();
} else if (data.ok) {
// async classify: 202 — ждём poll до done>=total
totalFiles = data.total || 0;
if (totalFiles === 0) {
clearInterval(timer);
clearInterval(pollTimer);
btn.innerHTML = '✗ нет файлов для классификации';
btn.disabled = false;
}
} else {
clearInterval(timer);
clearInterval(pollTimer);
btn.innerHTML = '✗ ' + (data.error || 'ошибка');
btn.disabled = false;
}
} catch(e) {
if (!classifyDone) {
clearInterval(timer);
clearInterval(pollTimer);
btn.innerHTML = '✗ ' + e.message;
btn.disabled = false;
}
}
}
// loadGroups, buildGroupCard, markGroupDone → groups.js (Фаза 2)
+2 -1
View File
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
# ⛔ НЕ МЕНЯТЬ БЕЗ РАЗРЕШЕНИЯ НАЕЛЯ ⛔
"""Contracts VM server — thin HTTP router. All logic in db/ and services/."""
from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingMixIn, TCPServer
@@ -267,7 +268,7 @@ class Handler(BaseHTTPRequestHandler):
# Запустить classify_worker.py в отдельном процессе
# Лог в /home/naeel/contracts/logs/ вместо DEVNULL
log_dir = "/home/naeel/contracts/logs"
log_dir = "/home/naeel/nubes/contracts/logs"
os.makedirs(log_dir, exist_ok=True)
log_path = os.path.join(log_dir, f"classify_{batch_id}.log")
log_file = open(log_path, "w")