function updateGenerateBtnText() { const btnText = document.getElementById('generateBtnText'); if (!btnText) return; const hasFolder = folderPath && folderPath.trim() !== ''; const hasLinks = referenceLinks.length > 0; const hasHtml = inputContent && inputContent.trim() !== ''; if (hasFolder || (hasLinks && hasHtml)) { btnText.textContent = 'πŸ“‹ λͺ©μ°¨ ν™•μΈν•˜κΈ°'; } else { btnText.textContent = 'πŸš€ μƒμ„±ν•˜κΈ°'; } } async function generate() { const type = docTypes.find(t => t.id === currentDocType); if (!type) return; // β˜… μž…λ ₯ νƒ€μž… μžλ™ νŒλ³„ const hasFolder = folderPath && folderPath.trim() !== ''; const hasLinks = referenceLinks.length > 0; const hasHtml = inputContent && inputContent.trim() !== ''; if (hasFolder || (hasLinks && hasHtml)) { // μž…λ ₯ 1,2,3: 폴더/링크 β†’ νŒŒμ΄ν”„λΌμΈ β†’ λͺ©μ°¨ β†’ 생성 await generateDraft(); } else if (hasHtml) { // μž…λ ₯ 4: HTML β†’ ν˜•μ‹ λ³€ν™˜ await generateBriefing(); } else { alert('λ¨Όμ € 폴더 μœ„μΉ˜, μ°Έκ³  링크, λ˜λŠ” HTML을 μž…λ ₯ν•΄μ£Όμ„Έμš”.'); } } async function generateBriefing() { if (!inputContent && !folderPath && referenceLinks.length === 0) { alert('λ¨Όμ € 폴더 μœ„μΉ˜, μ°Έκ³  링크, λ˜λŠ” HTML을 μž…λ ₯ν•΄μ£Όμ„Έμš”.'); return; } const btn = document.getElementById('generateBtn'); const btnText = document.getElementById('generateBtnText'); const spinner = document.getElementById('generateSpinner'); btn.disabled = true; btnText.textContent = '생성 쀑...'; spinner.style.display = 'block'; resetSteps(); updateStep(0, 'done'); setStatus('생성 쀑...', true); try { for (let i = 1; i <= 7; i++) { updateStep(i, 'running'); await new Promise(r => setTimeout(r, 200)); updateStep(i, 'done'); } updateStep(8, 'running'); // νŽ˜μ΄μ§€ ꡬ성 κ°’ κ°€μ Έμ˜€κΈ° let pageOption = '2'; // κΈ°λ³Έκ°’ if (currentPageConfig === 'body-only') { pageOption = '1'; } else if (currentPageConfig === 'body-attach') { pageOption = String(1 + attachPageCount); // λ³Έλ¬Έ 1p + 첨뢀 np } const formData = new FormData(); formData.append('content', inputContent); formData.append('doc_type', currentDocType); formData.append('page_option', pageOption); formData.append('attach_pages', attachPageCount); formData.append('instruction', document.getElementById('globalInstructionInput').value); formData.append('write_mode', currentWriteMode); formData.append('folder_path', folderPath || ''); formData.append('links', JSON.stringify(referenceLinks || [])); const response = await fetch('/generate', { method: 'POST', body: formData }); const data = await response.json(); if (data.error) { throw new Error(data.error); } updateStep(8, 'done'); updateStep(9, 'running'); await new Promise(r => setTimeout(r, 300)); updateStep(9, 'done'); if (data.success && data.html) { generatedHTML = data.html; document.getElementById('placeholder').style.display = 'none'; const frame = document.getElementById('previewFrame'); frame.classList.add('active'); frame.srcdoc = generatedHTML; setTimeout(setupIframeSelection, 500); document.getElementById('feedbackBar').classList.add('show'); setStatus('생성 μ™„λ£Œ', true); } } catch (error) { alert('생성 였λ₯˜: ' + error.message); setStatus('였λ₯˜ λ°œμƒ', false); for (let i = 0; i <= 9; i++) { const item = document.querySelector(`.step-item[data-step="${i}"]`); if (item && item.classList.contains('running')) { updateStep(i, 'error'); } } } finally { btn.disabled = false; btnText.textContent = 'πŸš€ μƒμ„±ν•˜κΈ°'; spinner.style.display = 'none'; } } async function generateDraft() { if (!folderPath && !inputContent && referenceLinks.length === 0) { alert('λ¨Όμ € 폴더 μœ„μΉ˜, μ°Έκ³  링크, λ˜λŠ” HTML을 μž…λ ₯ν•΄μ£Όμ„Έμš”.'); return; } const btn = document.getElementById('generateBtn'); const btnText = document.getElementById('generateBtnText'); const spinner = document.getElementById('generateSpinner'); btn.disabled = true; btnText.textContent = '뢄석 쀑...'; spinner.style.display = 'block'; resetSteps(); updateStep(0, 'done'); setStatus('λͺ©μ°¨ 생성 쀑...', true); try { const hasFolder = folderPath && folderPath.trim() !== ''; const hasLinks = referenceLinks && referenceLinks.length > 0; const hasHtml = inputContent && inputContent.trim() !== ''; const needsPipeline = hasFolder || (hasLinks && hasHtml); if (needsPipeline) { // νŒŒμ΄ν”„λΌμΈ λͺ¨λ“œ: μ„œλ²„μ—μ„œ step3~7 μ‹€ν–‰ updateStep(1, 'running'); const tocResp = await fetch('/api/generate-toc', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ folder_path: folderPath, links: referenceLinks, domain_selected: selectedDomains && selectedDomains.length > 0, write_mode: currentWriteMode }) }); const tocData = await tocResp.json(); if (!tocData.success) { throw new Error(tocData.error || 'λͺ©μ°¨ 생성 μ‹€νŒ¨'); } // step 1~7 μ™„λ£Œ ν‘œμ‹œ for (let i = 1; i <= 7; i++) updateStep(i, 'done'); // λͺ©μ°¨ μ• λ‹ˆλ©”μ΄μ…˜ ν‘œμ‹œ if (tocData.toc_items && typeof displayTocWithAnimation === 'function') { displayTocWithAnimation(tocData.toc_items); } } else { // HTML μž…λ ₯ λͺ¨λ“œ: κ°€μ§œ μ§„ν–‰ (κΈ°μ‘΄) for (let i = 1; i <= 7; i++) { updateStep(i, 'running'); await new Promise(r => setTimeout(r, 500)); updateStep(i, 'done'); } } document.getElementById('feedbackBar').classList.remove('show'); setStatus('λͺ©μ°¨ 생성 μ™„λ£Œ - 확인 ν›„ μŠΉμΈν•΄μ£Όμ„Έμš”', true); } catch (error) { alert('λͺ©μ°¨ 생성 였λ₯˜: ' + error.message); setStatus('였λ₯˜ λ°œμƒ', false); } finally { btn.disabled = false; btnText.textContent = 'πŸ“‹ λͺ©μ°¨ ν™•μΈν•˜κΈ°'; spinner.style.display = 'none'; } } // ===== λͺ©μ°¨ μ• λ‹ˆλ©”μ΄μ…˜ ν‘œμ‹œ ===== function displayTocWithAnimation(tocItems) { const tocDisplay = document.getElementById('tocDisplayArea'); if (!tocDisplay) return; tocDisplay.style.display = 'block'; tocDisplay.innerHTML = ''; tocItems.forEach((item, index) => { const tocEl = document.createElement('div'); tocEl.className = 'toc-anim-item'; tocEl.style.opacity = '0'; tocEl.style.transform = 'translateY(12px)'; // ν‚€μ›Œλ“œ HTML 생성 const keywordsHtml = (item.keywords || []) .map(k => `${k}`) .join(''); const contentsHtml = (item.contents || []) .map(c => `
${c}
`) .join(''); tocEl.innerHTML = `
${item.num || (index + 1) + 'μž₯'}
${item.title}
${item.guide ? `
${item.guide}
` : ''} ${contentsHtml ? `
${contentsHtml}
` : ''} ${keywordsHtml ? `
${keywordsHtml}
` : ''} `; tocDisplay.appendChild(tocEl); // 순차적으둜 λ‚˜νƒ€λ‚¨ setTimeout(() => { tocEl.style.transition = 'all 0.4s ease'; tocEl.style.opacity = '1'; tocEl.style.transform = 'translateY(0)'; }, 300 + (index * 600)); }); // λͺ¨λ“  ν•­λͺ© ν‘œμ‹œ ν›„ μ•‘μ…˜λ°” ν‘œμ‹œ const totalDelay = 300 + (tocItems.length * 600) + 400; setTimeout(() => { document.getElementById('tocActionBar').classList.add('show'); document.getElementById('feedbackBar').classList.remove('show'); setStatus('λͺ©μ°¨ 생성 μ™„λ£Œ - 확인 ν›„ μŠΉμΈν•΄μ£Όμ„Έμš”', true); }, totalDelay); } // ===== λͺ©μ°¨ ν‘œμ‹œ μ΄ˆκΈ°ν™” ===== function hideTocDisplay() { const tocDisplay = document.getElementById('tocDisplayArea'); if (tocDisplay) { tocDisplay.style.display = 'none'; tocDisplay.innerHTML = ''; } } function editToc() { const tocContainer = document.getElementById('tocContainer'); if (tocContainer) { tocContainer.contentEditable = true; tocContainer.style.outline = '2px solid var(--ui-accent)'; } // μ• λ‹ˆλ©”μ΄μ…˜ λͺ©μ°¨λ„ νŽΈμ§‘ κ°€λŠ₯ν•˜κ²Œ const tocDisplay = document.getElementById('tocDisplayArea'); if (tocDisplay && tocDisplay.style.display !== 'none') { tocDisplay.contentEditable = true; tocDisplay.style.outline = '2px solid var(--ui-accent)'; } setStatus('λͺ©μ°¨ νŽΈμ§‘ λͺ¨λ“œ - 직접 μˆ˜μ • κ°€λŠ₯ν•©λ‹ˆλ‹€', true); } async function approveToc() { const btn = document.getElementById('approveBtn'); btn.disabled = true; btn.textContent = '⏳ 생성 쀑...'; document.getElementById('tocActionBar').classList.remove('show'); hideTocDisplay(); setStatus('μ΅œμ’… λ¬Έμ„œ 생성 쀑...', true); // μ§„ν–‰λ₯  ν‘œμ‹œ const progressArea = document.getElementById('genProgressArea'); if (progressArea) { progressArea.style.display = 'block'; } try { // Step 8: μ½˜ν…μΈ  생성 updateStep(8, 'running'); updateGenProgress(10, 'πŸ“š RAG 검색 쀑...'); await generateReport(); updateGenProgress(100, 'βœ… 생성 μ™„λ£Œ'); updateStep(8, 'done'); updateStep(9, 'running'); await new Promise(r => setTimeout(r, 300)); updateStep(9, 'done'); // μ§„ν–‰λ₯  숨기기 setTimeout(() => { if (progressArea) progressArea.style.display = 'none'; }, 1000); } catch (error) { alert('λ¬Έμ„œ 생성 였λ₯˜: ' + error.message); setStatus('였λ₯˜ λ°œμƒ', false); if (progressArea) progressArea.style.display = 'none'; } finally { btn.disabled = false; btn.textContent = 'βœ… 승인 & μƒμ„±ν•˜κΈ°'; } } // ===== 생성 μ§„ν–‰λ₯  μ—…λ°μ΄νŠΈ ===== function updateGenProgress(percent, message) { const bar = document.getElementById('genProgressBar'); const text = document.getElementById('genProgressText'); if (bar) bar.style.width = percent + '%'; if (text) text.textContent = message; } // === generateReport() ν•¨μˆ˜ 전체 ꡐ체 === async function generateReport() { const coverCheck = document.getElementById('cover'); const tocCheck = document.getElementById('toc'); const dividerCheck = document.getElementById('divider'); updateGenProgress(20, 'πŸ“‹ λͺ©μ°¨ 기반 ꡬ쑰화 쀑...'); // β˜… μž…λ ₯1,2,3일 λ•Œ (폴더/링크 있으면) const hasFolder = folderPath && folderPath.trim() !== ''; const hasLinks = referenceLinks && referenceLinks.length > 0; const hasHtml = inputContent && inputContent.trim() !== ''; if (hasFolder || (hasLinks && hasHtml)) { // νŽΈμ§‘λœ λͺ©μ°¨ μˆ˜μ§‘ const editedToc = collectEditedToc(); const response = await fetch('/api/generate-report-from-toc', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ toc_items: editedToc, write_mode: currentWriteMode, instruction: document.getElementById('globalInstructionInput').value, cover: coverCheck ? coverCheck.checked : true, toc: tocCheck ? tocCheck.checked : true, }) }); updateGenProgress(60, 'πŸ“ λ³Έλ¬Έ μž‘μ„± 쀑...'); const data = await response.json(); if (data.error) throw new Error(data.error); updateGenProgress(85, '🎨 λ ˆμ΄μ•„μ›ƒ 쑰립 쀑...'); await new Promise(r => setTimeout(r, 500)); if (data.success && data.html) { generatedHTML = data.html; showGeneratedHtml(generatedHTML); } } else { const response = await fetch('/generate-report', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content: inputContent, folder_path: folderPath, cover: coverCheck ? coverCheck.checked : true, toc: tocCheck ? tocCheck.checked : true, divider: dividerCheck ? dividerCheck.checked : false, instruction: document.getElementById('globalInstructionInput').value }) }); updateGenProgress(60, 'πŸ“ λ³Έλ¬Έ μž‘μ„± 쀑...'); const data = await response.json(); if (data.error) throw new Error(data.error); updateGenProgress(85, '🎨 λ ˆμ΄μ•„μ›ƒ 쑰립 쀑...'); await new Promise(r => setTimeout(r, 500)); if (data.success && data.html) { generatedHTML = data.html; showGeneratedHtml(generatedHTML); } } } // β˜… 곡톡 HTML ν‘œμ‹œ ν•¨μˆ˜ μΆ”κ°€ function showGeneratedHtml(html) { document.getElementById('placeholder').style.display = 'none'; const frame = document.getElementById('previewFrame'); frame.classList.add('active'); frame.srcdoc = html; setTimeout(setupIframeSelection, 500); document.getElementById('feedbackBar').classList.add('show'); updateGenProgress(100, 'βœ… 생성 μ™„λ£Œ'); setStatus('생성 μ™„λ£Œ', true); } // β˜… νŽΈμ§‘λœ λͺ©μ°¨ μˆ˜μ§‘ ν•¨μˆ˜ μΆ”κ°€ function collectEditedToc() { const tocDisplay = document.getElementById('tocDisplayArea'); if (!tocDisplay) return []; const items = []; tocDisplay.querySelectorAll('.toc-anim-item').forEach(el => { items.push({ num: el.querySelector('.toc-anim-num')?.textContent || '', title: el.querySelector('.toc-anim-title')?.textContent || '', guide: el.querySelector('.toc-anim-guide')?.textContent || '', keywords: Array.from(el.querySelectorAll('.toc-anim-keyword')) .map(k => k.textContent) }); }); return items; } // ===== ν”Όλ“œλ°± ===== async function submitFeedback() { const feedback = document.getElementById('feedbackInput').value.trim(); if (!feedback) { alert('μˆ˜μ • λ‚΄μš©μ„ μž…λ ₯ν•΄μ£Όμ„Έμš”.'); return; } if (!generatedHTML) { alert('λ¨Όμ € λ¬Έμ„œλ₯Ό μƒμ„±ν•΄μ£Όμ„Έμš”.'); return; } const btn = document.getElementById('feedbackBtn'); const btnText = document.getElementById('feedbackBtnText'); const spinner = document.getElementById('feedbackSpinner'); btn.disabled = true; btnText.textContent = '⏳ μˆ˜μ • 쀑...'; spinner.style.display = 'inline-block'; setStatus('μˆ˜μ • 쀑...', true); try { const response = await fetch('/refine', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ feedback: feedback, current_html: generatedHTML }) }); const data = await response.json(); if (data.error) { throw new Error(data.error); } if (data.success && data.html) { generatedHTML = data.html; document.getElementById('previewFrame').srcdoc = generatedHTML; document.getElementById('feedbackInput').value = ''; setTimeout(setupIframeSelection, 500); setStatus('μˆ˜μ • μ™„λ£Œ', true); } } catch (error) { alert('μˆ˜μ • 였λ₯˜: ' + error.message); setStatus('였λ₯˜ λ°œμƒ', false); } finally { btn.disabled = false; btnText.textContent = 'πŸ”„ μˆ˜μ • 반영'; spinner.style.display = 'none'; } } function regenerate() { if (confirm('ν˜„μž¬ κ²°κ³Όλ₯Ό 버리고 λ‹€μ‹œ μƒμ„±ν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?')) { hideTocDisplay(); generate(); } }