diff --git a/deploy/app.js b/deploy/app.js index 901aa44..2ce4f0f 100644 --- a/deploy/app.js +++ b/deploy/app.js @@ -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 = ' Классификация... ' + 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 = ' Классификация... ' + 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,22 +174,38 @@ async function runClassify() { body: JSON.stringify({batch_id: state.batchId}) }); var data = await resp.json(); - clearInterval(timer); - clearInterval(pollTimer); - if (data.ok) { + + // sync classify: ответ уже содержит done + if (data.ok && data.done !== undefined) { + clearInterval(timer); + clearInterval(pollTimer); + 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) { - clearInterval(timer); - clearInterval(pollTimer); - btn.innerHTML = '✗ ' + e.message; - btn.disabled = false; + if (!classifyDone) { + clearInterval(timer); + clearInterval(pollTimer); + btn.innerHTML = '✗ ' + e.message; + btn.disabled = false; + } } } diff --git a/deploy/convert_server.py b/deploy/convert_server.py index 08edc9c..72c0932 100755 --- a/deploy/convert_server.py +++ b/deploy/convert_server.py @@ -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")