🚀 파이프라인
시나리오 상세 보고서
×
관련 기사
×
시계열 차트
×
GPT-4 기반 HTML 보고서 생성
×
GPT-4 기반 HTML 보고서 생성 중...
생성된 HTML 코드가 여기에 표시됩니다.
HTML 다운로드
코드 복사
미리보기
GPT4 보고서
×
안에 그대로 붙여넣기 (function () { 'use strict'; /* ===== 실행 버튼 탐색 ===== */ let _topRunBtn = null; function getTopRunBtn() { if (_topRunBtn && document.body.contains(_topRunBtn)) return _topRunBtn; _topRunBtn = document.querySelector('#top-pipeline-btn') || document.querySelector('#run-pipeline-btn') || document.querySelector('#analyze-start-btn') || document.querySelector('button[data-action="run-pipeline"]') || document.querySelector('button#analyze-start') || document.querySelector('button.top-run'); return _topRunBtn; } function setTopButtonState(state, label) { const btn = getTopRunBtn(); if (!btn) return; const txt = String(label || '').trim(); if (state === 'idle') { btn.disabled = false; btn.removeAttribute('aria-busy'); if (txt) btn.textContent = txt; } else if (state === 'running') { btn.disabled = true; btn.setAttribute('aria-busy','true'); if (txt) btn.textContent = txt; } else if (state === 'report') { btn.disabled = false; btn.removeAttribute('aria-busy'); btn.textContent = '보고서 작성'; } else if (state === 'retry') { btn.disabled = false; btn.removeAttribute('aria-busy'); btn.textContent = '다시 실행'; } } function showStatus(message) { // 기존 showStatus가 있으면 그대로 사용 if (typeof window.showStatus === 'function') return window.showStatus(message); const el = document.querySelector('#send-status') || document.querySelector('.status'); if (el) el.textContent = String(message || ''); } /* ===== 공용 셀렉터 유틸 ===== */ function getCardEl(id) { return ( document.querySelector(`#card-${id}`) || document.querySelector(`[data-card="${id}"]`) || document.querySelector(`.${id}-module-box`) || null ); } function getLineEl(id) { return ( document.querySelector(`.pipeline-line.to-${id}`) || document.querySelector(`[data-to="${id}"]`) || null ); } /* ===== 효과 타임라인: 선(flow)+박스(active) 1분씩 순차 ===== */ const Effects = { order: ['gpt0','gpt1','gpt2','gpt3','gpt4'], durMs: 60000, // 1분 timers: [], running: false, start({ order, durationMs } = {}) { this.stop(); if (Array.isArray(order) && order.length) this.order = order.slice(); if (typeof durationMs === 'number' && durationMs > 0) this.durMs = durationMs; this.running = true; let acc = 0; this.order.forEach((id, idx) => { const tStart = setTimeout(() => { if (!this.running) return; if (idx > 0) this._stopOne(this.order[idx-1]); this._startOne(id); }, acc); this.timers.push(tStart); acc += this.durMs; const tEnd = setTimeout(() => { if (!this.running) return; this._stopOne(id); }, acc); this.timers.push(tEnd); }); const tAllEnd = setTimeout(() => this.stop(), acc + 10); this.timers.push(tAllEnd); }, stop() { this.running = false; this.timers.forEach(t => clearTimeout(t)); this.timers = []; this._stopAll(); }, _startOne(id) { const card = getCardEl(id); if (card) card.classList.add('active'); // D3가 있으면 D3로, 없으면 DOM class로 폴백 const line = getLineEl(id); if (window.d3 && typeof d3.selectAll === 'function') { try { d3.selectAll('.pipeline-line').classed('flow', false); if (line) d3.select(line).classed('flow', true); } catch(e) { if (line) line.classList.add('flow'); } } else { // 아직 선이 동적으로 생성 안됐을 수 있으므로, 재시도 루프(최대 3초) if (line) { line.classList.add('flow'); } else { let tries = 0; const interval = setInterval(() => { const l = getLineEl(id); if (l) { l.classList.add('flow'); clearInterval(interval); } if (++tries > 30) clearInterval(interval); }, 100); } } }, _stopOne(id) { const card = getCardEl(id); if (card) card.classList.remove('active'); const line = getLineEl(id); if (window.d3 && typeof d3.selectAll === 'function') { try { d3.selectAll('.pipeline-line').classed('flow', false); } catch(e) { if (line) line.classList.remove('flow'); } } else { if (line) line.classList.remove('flow'); } }, _stopAll() { ['gpt0','gpt1','gpt2','gpt3','gpt4'].forEach(id => this._stopOne(id)); } }; /* ===== 파이프라인 실행(효과와 완전 분리) ===== */ async function startPipelineWithEffects() { Effects.start({ durationMs: 60000 }); // 필요 시 60000 → 20000 등으로 조절 try { setTopButtonState('running','1/4단계: gpt0 실행'); if (typeof window.executePipelineSteps === 'function') { await window.executePipelineSteps((step, desc) => { showStatus(`📊 ${step}/4단계: ${desc}`); setTopButtonState('running', `${step}/4단계: ${desc}`); }); } else { // 폴백(실행기 없을 때 간단 타임라인만 진행) showStatus('📊 2/4단계: gpt1 실행'); await new Promise(r=>setTimeout(r,1200)); showStatus('📊 3/4단계: gpt2 실행'); await new Promise(r=>setTimeout(r,1200)); showStatus('📊 4/4단계: gpt3 실행'); await new Promise(r=>setTimeout(r,1200)); } setTopButtonState('report'); showStatus('🎉 분석 완료! "보고서 작성" 버튼으로 결과를 생성하세요.'); } catch (err) { console.error('❌ 파이프라인 실행 오류:', err); setTopButtonState('retry'); showStatus(`❌ 오류: ${err.message || err}`); } finally { Effects.stop(); } } /* ===== 초기 바인딩 ===== */ document.addEventListener('DOMContentLoaded', () => { setTopButtonState('idle','분석 시작'); const btn = getTopRunBtn(); if (btn) { btn.removeAttribute('onclick'); btn.addEventListener('click', () => startPipelineWithEffects()); } // 외부에서 제어할 수 있도록 노출 window.startPipelineWithEffects = startPipelineWithEffects; window.pipelineEffects = Effects; }); })();