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();
}
}