From 78c4730196e154b1acae7742a293ffcab347723b Mon Sep 17 00:00:00 2001 From: vakabunga Date: Sat, 14 Mar 2026 16:41:12 +0300 Subject: [PATCH] fix: adaptive LLM progress estimation and emit 85% on stream end Hardcoded EXPECTED_CHARS (15k) caused progress to stall at ~20-25% for short statements. Now expected size is derived from input text length. Also emit an explicit 85% event when the LLM stream finishes, and throttle SSE events to 300ms to reduce browser overhead. --- backend/src/services/pdfToStatement.ts | 27 ++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/backend/src/services/pdfToStatement.ts b/backend/src/services/pdfToStatement.ts index d351ae7..6bc8401 100644 --- a/backend/src/services/pdfToStatement.ts +++ b/backend/src/services/pdfToStatement.ts @@ -145,7 +145,10 @@ export async function convertPdfToStatement( export type ProgressStage = 'pdf' | 'llm' | 'import'; export type OnProgress = (stage: ProgressStage, progress: number, message: string) => void; -const EXPECTED_CHARS = 15_000; +const LLM_PROGRESS_MIN = 10; +const LLM_PROGRESS_MAX = 85; +const LLM_PROGRESS_RANGE = LLM_PROGRESS_MAX - LLM_PROGRESS_MIN; +const THROTTLE_MS = 300; export async function convertPdfToStatementStreaming( buffer: Buffer, @@ -202,22 +205,34 @@ export async function convertPdfToStatementStreaming( stream: true, }); + // Estimate expected output size as ~2x the input PDF text length, clamped + const expectedChars = Math.max(2_000, Math.min(text.length * 2, 30_000)); + let accumulated = ''; let charsReceived = 0; + let lastEmitTime = 0; for await (const chunk of stream) { const delta = chunk.choices[0]?.delta?.content; if (delta) { accumulated += delta; charsReceived += delta.length; - const llmProgress = Math.min( - 85, - Math.round((charsReceived / EXPECTED_CHARS) * 75 + 10), - ); - onProgress('llm', llmProgress, 'Конвертация через LLM...'); + + const now = Date.now(); + if (now - lastEmitTime >= THROTTLE_MS) { + const ratio = Math.min(1, charsReceived / expectedChars); + const llmProgress = Math.min( + LLM_PROGRESS_MAX, + Math.round(ratio * LLM_PROGRESS_RANGE + LLM_PROGRESS_MIN), + ); + onProgress('llm', llmProgress, 'Конвертация через LLM...'); + lastEmitTime = now; + } } } + onProgress('llm', LLM_PROGRESS_MAX, 'LLM завершил, обработка результата...'); + const content = accumulated.trim(); if (!content) { return {