From bba06bab6f4f01678cff812c44bcc577582577ee Mon Sep 17 00:00:00 2001 From: kim Date: Tue, 2 Jun 2026 15:15:08 +0900 Subject: [PATCH] Fix wizard re-run: skip existing PDF/text, preserve state across restarts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Server: - download-pdf-stream: check if PDF already exists (size > 1KB) → return cached path immediately, skip all network requests Client (startPrep): - save pdfPaths from prepLog before reset → skip PMC download if path known - skip text extraction if paperTexts[key] already loaded in memory - text from project open (onOpenProjChange) now survives "다시 실행" Co-Authored-By: Claude Sonnet 4.6 --- src/gateway/server-v2.ts | 7 +++++++ web-ui/pptx-wizard.html | 18 +++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/gateway/server-v2.ts b/src/gateway/server-v2.ts index 7e67b0e..8805fa3 100644 --- a/src/gateway/server-v2.ts +++ b/src/gateway/server-v2.ts @@ -9691,6 +9691,13 @@ app.post('/api/pptx/download-pdf-stream', requireGatewayAuth, async (req: expres const pdfDest = path.join(workspacePath, projectSlug ? pptxRelPath(projectSlug, `${pmcid}.pdf`) : `pubmed/${pmcid}.pdf`); fs.mkdirSync(path.dirname(pdfDest), { recursive: true }); + // 이미 다운로드된 PDF가 있으면 즉시 반환 + if (fs.existsSync(pdfDest) && fs.statSync(pdfDest).size > 1024) { + const relPath = path.relative(workspacePath, pdfDest).replace(/\\/g, '/'); + send({ type: 'done', success: true, path: relPath, stdout: relPath, _cached: true }); + res.end(); return; + } + // 1. OA API → FTP link + check OA send({ type: 'progress', msg: 'PMC OA 확인 중...' }); let oaXml = ''; diff --git a/web-ui/pptx-wizard.html b/web-ui/pptx-wizard.html index 6cc9a20..4d81c5f 100644 --- a/web-ui/pptx-wizard.html +++ b/web-ui/pptx-wizard.html @@ -1908,7 +1908,11 @@ async function startPrep() { if(btn.disabled) return; // 이미 실행 중 btn.disabled=true; btn.textContent='진행 중...'; setMsg(2,'준비 중...','var(--brand2)'); - const keys=Array.from(selected); prepLog={}; renderProgList(); extractedImages=[]; + const keys=Array.from(selected); + // prepLog 리셋 전에 기존 pdfPath 보존 (재실행 시 재다운로드 방지) + const savedPdfPaths={}; + for(const k of keys){ if(prepLog[k]?.pdfPath) savedPdfPaths[k]=prepLog[k].pdfPath; } + prepLog={}; renderProgList(); extractedImages=[]; document.getElementById('imgrid').innerHTML='
📷 이미지 캡처 버튼으로 추가하세요
'; // 프로젝트 slug 결정 — PDF/이미지를 프로젝트 폴더에 직접 저장 (항상 결정) @@ -1945,6 +1949,12 @@ async function startPrep() { prepLog[key].pdf='done'; prepLog[key].pdfPath=pdfPath; updProg(key); if(!pdfPath){ prepLog[key].img='fail'; prepLog[key].txt='fail'; prepLog[key].error='PDF 경로 확인 불가'; updProg(key); continue; } setMsg(2,paperLabel(key)+' 이미지 추출...','var(--brand2)'); + } else if(savedPdfPaths[key]) { + // 이전 실행에서 다운로드된 PDF — 재다운로드 스킵 + pdfPath=savedPdfPaths[key]; + prepLog[key].pdf='done'; prepLog[key].pdfPath=pdfPath; + setMsg(2,paperLabel(key)+' PDF 이미 있음 — 스킵','var(--muted)'); + updProg(key); } else { // PMC 다운로드 (SSE 스트리밍) setMsg(2,key+' PDF 다운로드...','var(--brand2)'); @@ -2033,8 +2043,10 @@ async function startPrep() { prepLog[key].img='skip'; updProg(key); } - // Text extract (토글 ON일 때만) - if(extractText && pdfPath){ + // Text extract (토글 ON일 때만, 이미 있으면 스킵) + if(extractText && pdfPath && paperTexts[key]){ + prepLog[key].txt='done'; updProg(key); // 이미 로드된 텍스트 유지 + } else if(extractText && pdfPath){ prepLog[key].txt='running'; updProg(key); setMsg(2,paperLabel(key)+' 텍스트 추출...','var(--brand2)'); try{