SSE streaming: прогресс по каждому файлу во время LLM (v1.0.53)
This commit is contained in:
@@ -61,7 +61,7 @@
|
||||
<body>
|
||||
<div class="topbar">
|
||||
<img src="/nubes-logo.svg" alt="Nubes">
|
||||
<span class="title">Сверка договоров — LLM <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.0.52 — Lucee</span></span>
|
||||
<span class="title">Сверка договоров — LLM <span style="font-weight:400;color:var(--muted);font-size:12px;">v1.0.53 — Lucee</span></span>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
@@ -332,7 +332,7 @@ document.getElementById('llmBtn').addEventListener('click', async function() {
|
||||
var diffBody = document.getElementById('diffBody');
|
||||
var diffStatus = document.getElementById('diffStatus');
|
||||
diffCard.style.display = 'block';
|
||||
diffBody.innerHTML = '⏳ LLM-извлечение...';
|
||||
diffBody.innerHTML = '';
|
||||
diffStatus.textContent = '⏳ 0.0с';
|
||||
|
||||
var llmStart = Date.now();
|
||||
@@ -340,28 +340,37 @@ document.getElementById('llmBtn').addEventListener('click', async function() {
|
||||
diffStatus.textContent = '⏳ ' + ((Date.now() - llmStart) / 1000).toFixed(1) + 'с';
|
||||
}, 200);
|
||||
|
||||
// ОДИН запрос — всё внутри: экстракция + сравнение
|
||||
try {
|
||||
var resp = await fetch('/process.cfm?contract_id=' + contractId);
|
||||
var data = await resp.json();
|
||||
// SSE — прогресс по каждому файлу
|
||||
var es = new EventSource('/process.cfm?contract_id=' + contractId);
|
||||
|
||||
if (data.OK) {
|
||||
// Показать результаты экстракции
|
||||
var extr = data.EXTRACTED || [];
|
||||
diffBody.innerHTML = '';
|
||||
extr.forEach(function(e) {
|
||||
if (e.ERROR) {
|
||||
diffBody.innerHTML += '<div style="font-size:12px;color:var(--destructive);">✗ ' + (e.FILENAME||e.SUPPLEMENT_ID) + ': ' + e.ERROR + '</div>';
|
||||
} else if (e.SKIPPED) {
|
||||
diffBody.innerHTML += '<div style="font-size:12px;color:var(--muted);">⏭ ' + (e.FILENAME||e.SUPPLEMENT_ID) + ' (уже извлечено, ' + e.ROWS_SAVED + ' строк)</div>';
|
||||
} else {
|
||||
diffBody.innerHTML += '<div style="font-size:12px;color:var(--green);">✓ ' + (e.FILENAME||e.SUPPLEMENT_ID) + ': ' + e.ROWS_SAVED + ' строк</div>';
|
||||
}
|
||||
});
|
||||
es.onmessage = function(e) {
|
||||
var d = JSON.parse(e.data);
|
||||
|
||||
if (d.type === 'extract_start') {
|
||||
diffBody.innerHTML += '<div style="font-size:12px;color:var(--muted);margin-top:2px;" id="ext-' + d.supplement_id + '">⏳ ' + d.filename + ' → LLM... <span class="file-timer" data-start="' + Date.now() + '">0.0с</span></div>';
|
||||
}
|
||||
else if (d.type === 'extract_done') {
|
||||
var el = document.getElementById('ext-' + d.supplement_id);
|
||||
if (el) el.innerHTML = '✓ <span style="color:var(--green);">' + d.filename + ': ' + d.count + ' строк (' + d.time_s + 'с)</span>';
|
||||
}
|
||||
else if (d.type === 'extract_skip') {
|
||||
diffBody.innerHTML += '<div style="font-size:12px;color:var(--muted);margin-top:2px;">⏭ ' + d.filename + ' (уже извлечено, ' + d.count + ' строк)</div>';
|
||||
}
|
||||
else if (d.type === 'extract_error') {
|
||||
var el = document.getElementById('ext-' + d.supplement_id);
|
||||
if (el) el.innerHTML = '✗ <span style="color:var(--destructive);">' + d.filename + ': ' + d.error + '</span>';
|
||||
else diffBody.innerHTML += '<div style="font-size:12px;color:var(--destructive);margin-top:2px;">✗ ' + d.filename + ': ' + d.error + '</div>';
|
||||
}
|
||||
else if (d.type === 'done') {
|
||||
clearInterval(timerInterval);
|
||||
es.close();
|
||||
diffStatus.textContent = '✓ ' + d.total_time_s + 'с';
|
||||
btn.innerHTML = '<i data-lucide="check" style="width:16px;height:16px;"></i> ✓ Готово';
|
||||
document.getElementById('chatCard').style.display = 'block';
|
||||
|
||||
// Сравнение
|
||||
diffBody.innerHTML += '<div style="margin-top:8px;font-weight:600;">📊 Сравнение:</div>';
|
||||
var all = data.ALL_CHANGES || [];
|
||||
var all = d.all_changes || [];
|
||||
if (all.length === 0) {
|
||||
diffBody.innerHTML += '<div style="color:var(--muted);font-size:12px;">Нет допников для сравнения.</div>';
|
||||
} else {
|
||||
@@ -369,7 +378,6 @@ document.getElementById('llmBtn').addEventListener('click', async function() {
|
||||
var s = ch.SUMMARY || {};
|
||||
diffBody.innerHTML += '<div style="font-weight:600;margin-top:12px;">📄 Допник (' + ch.TYPE + ')</div>';
|
||||
diffBody.innerHTML += '<div style="font-size:12px;margin-left:8px;"><span style="color:var(--green);">+' + (s.ADDED||0) + '</span> <span style="color:#eab308;">~' + (s.CHANGED||0) + '</span> <span style="color:var(--destructive);">-' + (s.DELETED||0) + '</span></div>';
|
||||
diffStatus.textContent = 'изм:' + (s.CHANGED||0) + ' +' + (s.ADDED||0) + ' -' + (s.DELETED||0);
|
||||
|
||||
var changes = ch.CHANGES || [];
|
||||
if (changes.length === 0) {
|
||||
@@ -386,19 +394,44 @@ document.getElementById('llmBtn').addEventListener('click', async function() {
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
diffBody.innerHTML = '<div style="color:var(--destructive);">✗ ' + (data.ERROR||'Неизвестная ошибка') + '</div>';
|
||||
lucide.createIcons();
|
||||
}
|
||||
} catch(e) {
|
||||
diffBody.innerHTML = '<div style="color:var(--destructive);">✗ ' + e.message + '</div>';
|
||||
}
|
||||
else if (d.type === 'error') {
|
||||
clearInterval(timerInterval);
|
||||
es.close();
|
||||
diffBody.innerHTML += '<div style="color:var(--destructive);margin-top:8px;">✗ ' + d.message + '</div>';
|
||||
btn.innerHTML = '<i data-lucide="scale" style="width:16px;height:16px;"></i> Сравнить (LLM)';
|
||||
btn.disabled = false;
|
||||
}
|
||||
};
|
||||
|
||||
clearInterval(timerInterval);
|
||||
diffStatus.textContent = '✓ ' + ((Date.now() - llmStart) / 1000).toFixed(1) + 'с';
|
||||
es.onerror = function() {
|
||||
clearInterval(timerInterval);
|
||||
es.close();
|
||||
if (diffBody.innerHTML === '') {
|
||||
diffBody.innerHTML = '<div style="color:var(--destructive);">✗ Ошибка соединения</div>';
|
||||
}
|
||||
btn.innerHTML = '<i data-lucide="scale" style="width:16px;height:16px;"></i> Сравнить (LLM)';
|
||||
btn.disabled = false;
|
||||
lucide.createIcons();
|
||||
};
|
||||
|
||||
btn.innerHTML = '<i data-lucide="check" style="width:16px;height:16px;"></i> ✓ Готово';
|
||||
document.getElementById('chatCard').style.display = 'block';
|
||||
lucide.createIcons();
|
||||
// Таймер для файловых строк
|
||||
var fileTimerInterval = setInterval(function() {
|
||||
var now = Date.now();
|
||||
document.querySelectorAll('.file-timer').forEach(function(el) {
|
||||
var start = parseInt(el.dataset.start);
|
||||
if (start) el.textContent = ((now - start) / 1000).toFixed(1) + 'с';
|
||||
});
|
||||
}, 200);
|
||||
|
||||
// Сохранить интервалы для очистки
|
||||
es._fileTimer = fileTimerInterval;
|
||||
var origClose = es.close;
|
||||
es.close = function() {
|
||||
clearInterval(fileTimerInterval);
|
||||
origClose.call(es);
|
||||
};
|
||||
});
|
||||
|
||||
function _dc(c, field) {
|
||||
|
||||
Reference in New Issue
Block a user