JGOS-Origin / static /index.html
openfree's picture
feat: minwon toggle (forced contact routing + minwon-focused answers) + IDF keyword weighting
1f34d8c verified
Raw
History Blame Contribute Delete
30.8 kB
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta name="theme-color" content="#0052a4">
<title>[제안 테스트] JGOS · 행정 AI 서비스 특화 모델</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="/static/style.css?v=20260612a">
<script src="https://cdn.jsdelivr.net/npm/marked@14.1.3/marked.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.1.7/dist/purify.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/styles/github.min.css">
<script src="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/highlight.min.js"></script>
<style id="ax-modal-fix">#ax-modal[hidden]{display:none !important;}</style>
</head>
<body>
<div id="proposal-banner" style="background:#b91c1c;color:#fff;text-align:center;padding:7px 12px;font-size:13px;font-weight:600;line-height:1.45;position:relative;z-index:9999;">⚠️ 본 서비스는 <b>제안용 테스트(시범) 버전</b>입니다 — 실제 행정 서비스가 아니며, 응답의 정확성을 보장하지 않습니다.</div>
<div id="app">
<!-- ===== 모바일 햄버거 ===== -->
<button id="hamburger-btn" aria-label="메뉴 열기">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="3" y1="6" x2="21" y2="6"/>
<line x1="3" y1="12" x2="21" y2="12"/>
<line x1="3" y1="18" x2="21" y2="18"/>
</svg>
</button>
<!-- ===== 사이드바 ===== -->
<aside id="sidebar">
<div class="sidebar-head">
<div class="brand-top">
<div class="emblem">🏛️</div>
<div>
<div class="brand-title">전남광주 통합특별시</div>
<div class="brand-sub">시민 AI 안내 서비스</div>
</div>
</div>
<button id="new-chat-btn" title="새 대화">+ 새 상담</button>
</div>
<div class="sidebar-section-label">최근 상담</div>
<ul id="chat-list"></ul>
<div class="sidebar-foot">
<div class="brand-small">
<strong>Powered by @비드래프트</strong>
<small>JGOS v0.1 preview</small>
</div>
</div>
</aside>
<main id="main">
<!-- ===== 상단 시민포털 헤더 ===== -->
<header id="topbar">
<div class="topbar-left">
<button id="sidebar-toggle" class="mobile-only" aria-label="사이드바"></button>
<div class="title-block">
<div class="title-main">🏛️ JGOS · 전남광주 통합특별시민과 함께하는 AI</div>
<div class="title-sub">320만 시민을 위한 한국어 sovereign AI · 행정·법령·관광·민원 안내</div>
</div>
</div>
<nav class="top-tabs">
<button class="top-tab active" data-view="chat">💬 AI 상담</button>
<button class="top-tab" data-view="office">📑 무료 오피스</button>
<button class="top-tab" data-view="image">🎨 이미지 생성</button>
<button class="top-tab" data-view="edu">🎓 AI 교육</button>
<button class="top-tab" data-view="ax">🏛️ 행정 AX(테스트)</button>
</nav>
<div class="topbar-right">
<span class="status-pill" id="status">● 정상</span>
</div>
</header>
<div id="view-chat">
<div id="messages-wrap">
<div id="messages"></div>
<!-- ===== 첫 화면 시민포털 (메시지 0건 시 표시) ===== -->
<div id="portal" class="portal">
<div class="portal-hero">
<div class="hero-emblem">🏛️</div>
<h1 class="hero-title">전남광주 통합특별시민과<br>함께하는 AI <strong>JGOS</strong></h1>
<p class="hero-sub">행정·민원·법령·관광·교통·문화·통계·산업·농수산 정보를<br>친절하게 안내해 드립니다. 무엇이 궁금하신가요?</p>
</div>
<!-- ===== 방안1: 히어로 파일 드롭존 ===== -->
<button class="hero-dropzone" id="hero-dropzone" type="button">
<div class="hd-icon">📎</div>
<div class="hd-main">파일을 끌어다 놓거나 클릭하세요</div>
<div class="hd-sub">HWP · 이미지 · PDF · 엑셀 무엇이든 올리면 <strong>바로 분석</strong>해 드립니다</div>
<div class="hd-badge">🇰🇷 타 AI가 못 읽는 <strong>한글 HWP</strong>도 분석하는 sovereign AI</div>
<!-- 방안2: 지원 형식 아이콘 띠 -->
<div class="fmt-strip">
<span class="fmt hwp">HWP</span><span class="fmt hwp">HWPX</span>
<span class="fmt pdf">PDF</span><span class="fmt doc">DOCX</span>
<span class="fmt xls">XLSX</span><span class="fmt ppt">PPTX</span>
<span class="fmt csv">CSV</span><span class="fmt img">이미지</span>
<span class="fmt more">+10종</span>
</div>
</button>
<!-- 8개 카테고리 큰 카드 -->
<div class="cat-grid">
<button class="cat-card" data-q="민원 처리 절차와 필요한 서류를 알려주세요.">
<div class="cat-emoji">📝</div>
<div class="cat-name">민원</div>
<div class="cat-desc">절차·서류·전화</div>
</button>
<button class="cat-card" data-q="전남광주통합특별법의 주요 조항을 알려주세요.">
<div class="cat-emoji">📜</div>
<div class="cat-name">법령</div>
<div class="cat-desc">특별법·조례</div>
</button>
<button class="cat-card" data-q="전남광주 통합특별시 관광 명소를 추천해 주세요.">
<div class="cat-emoji">🗺️</div>
<div class="cat-name">관광</div>
<div class="cat-desc">22 시군 + 5구</div>
</button>
<button class="cat-card" data-q="전남광주 통합특별시 교통편을 안내해 주세요.">
<div class="cat-emoji">🚆</div>
<div class="cat-name">교통</div>
<div class="cat-desc">KTX·공항·페리</div>
</button>
<button class="cat-card" data-q="전남광주 통합특별시의 농수산 특산품을 알려주세요.">
<div class="cat-emoji">🌾</div>
<div class="cat-name">농수산</div>
<div class="cat-desc">GI 특산·수산물</div>
</button>
<button class="cat-card" data-q="전남광주 통합특별시의 주요 산업과 경제 규모를 알려주세요.">
<div class="cat-emoji">🏭</div>
<div class="cat-name">산업</div>
<div class="cat-desc">경제·기업</div>
</button>
<button class="cat-card" data-q="전남광주 통합특별시의 인구 통계와 지역 현황을 알려주세요.">
<div class="cat-emoji">📊</div>
<div class="cat-name">통계</div>
<div class="cat-desc">인구·경제</div>
</button>
<button class="cat-card" data-attach="true">
<div class="cat-emoji">📎</div>
<div class="cat-name">첨부문서</div>
<div class="cat-desc">HWP·PDF·이미지</div>
</button>
</div>
<!-- 추천 질문 (자주 묻는) -->
<div class="quick-section">
<div class="quick-label">자주 묻는 질문</div>
<div class="quick-grid">
<button class="quick-btn" data-q="전남광주 통합특별시장과 광주 5개 구청장, 전남 시장·군수 당선인이 각각 누구인가요?">🏛️ 지자체장 당선인</button>
<button class="quick-btn" data-q="전남광주(광주·전남) 지역구 국회의원 명단을 알려주세요.">🗳️ 지역구 국회의원</button>
<button class="quick-btn" data-q="주민등록증 재발급 절차와 필요한 서류는?">📇 주민등록증 재발급</button>
<button class="quick-btn" data-q="전남광주 통합특별시 인구는?">👥 통합특별시 인구</button>
<button class="quick-btn" data-q="보성 녹차밭 관광 안내 부탁해.">🍃 보성 녹차밭</button>
<button class="quick-btn" data-q="전남광주통합특별법 제6조 내용은?">📜 특별법 제6조</button>
<button class="quick-btn" data-q="전남광주 통합특별시청 대표 전화번호와 부서 안내는?">📞 시청 대표번호</button>
<button class="quick-btn" data-q="여수에서 가볼 만한 곳 3곳만 추천해.">🏖️ 여수 가볼 곳</button>
<button class="quick-btn" data-q="5·18 민주화운동 기록관 위치와 관람 안내는?">🏛️ 5·18 기록관</button>
<button class="quick-btn" data-q="2026년 7월 1일 전남광주 통합특별시 출범의 의미와 일정은?">🎌 7·1 출범</button>
</div>
</div>
<!-- 신뢰 배지 (첫 화면 only — NIA 본문은 composer footer에서 영구 표시) -->
<div class="portal-foot">
<div class="trust-line">
<span class="trust-badge">🔒 sovereign AI</span>
<span class="trust-badge">📅 기준일 2026-06-01</span>
<span class="trust-badge">📚 RAG 21,192 청크</span>
<span class="trust-badge">⚖️ 정식 행정 안내 아님 · 062-120 확인 권장</span>
</div>
</div>
</div>
</div>
<!-- ===== 입력 영역 ===== -->
<footer id="composer">
<div class="warn-bar" id="warn-bar" hidden>
✅ 2026년 6월 3일 지방선거 완료 — 민형배 통합특별시장 당선(7월 1일 취임). 단체장·지역구 국회의원 명단 반영 완료.
</div>
<div class="attach-row" id="attach-row"></div>
<div class="input-row">
<button id="attach-btn" title="파일 첨부 (HWP/HWPX/PDF/DOCX/PPTX/XLSX/XLS/CSV/이미지)" aria-label="파일 첨부">📎</button>
<button id="web-btn" title="웹검색 — 켜면 네이버·웹에서 최신 정보를 함께 검색합니다" aria-label="웹검색 켜기/끄기" aria-pressed="false">🔍</button>
<button id="minwon-btn" title="민원 — 켜면 질문을 민원으로 보고 담당 부서·연락처를 찾아드립니다" aria-label="민원 모드 켜기/끄기" aria-pressed="false">📞</button>
<input type="file" id="file-input" hidden multiple
accept=".hwp,.hwpx,.pdf,.docx,.pptx,.xlsx,.xls,.csv,.txt,.md,.jpg,.jpeg,.png,.gif,.webp">
<textarea id="input" rows="1" placeholder="질문을 입력하거나 파일을 첨부하세요 (Shift+Enter 줄바꿈)"></textarea>
<button id="send-btn" title="전송 (Enter)" aria-label="전송">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>
</button>
</div>
<!-- ===== NIA K-AI 1위 출처 문구 (항상 표시 — 모든 화면 하단) ===== -->
<div class="nia-disclaimer">
본 모델은 과학기술정보통신부·한국지능정보사회진흥원(NIA) K-AI 리더보드 1위 달성 모델을 기반으로,
전남광주 통합특별시 관련 공개정보를 추가 학습·최적화한 한국어 특화 모델입니다.
한국어 처리 능력과 한국 문화·사회·행정·전문 분야에 대한 이해를 바탕으로
시민 질의에 정확하고 친절하게 응답합니다.
</div>
</footer>
</div><!-- /view-chat -->
<!-- ===== 무료 오피스 (HanSoo 엔진 흡수 · same-origin iframe 임베디드) ===== -->
<section id="view-office" hidden>
<iframe id="office-frame" title="무료 오피스 (HWP·DOCX·XLSX·PPTX·PDF)"
allow="clipboard-read; clipboard-write"></iframe>
</section>
<!-- ===== JGOS-Image (Qwen-Image-2512 한글 이미지 생성) ===== -->
<section id="view-image" hidden>
<div class="img-studio">
<div class="img-head">
<h2>🎨 이미지 생성 <small>한국형 AI 이미지 · 한국 인물·배경 · 영문 텍스트 · Qwen-Image-2512</small></h2>
</div>
<div class="img-examples">
<button class="img-ex" data-p="전남광주 통합특별시 출범 기념 포스터, 한국 시민들이 함께 모인 장면, 영문 제목 'Better Together', 밝고 희망찬">🎌 출범 포스터</button>
<button class="img-ex" data-p="보성 녹차밭 관광 포스터, 한국 전통 정취, 영문 문구 'Green Healing Tour', 청량하고 시원한">🍃 관광 홍보</button>
<button class="img-ex" data-p="민원 안내 인포그래픽, 깔끔한 한국 행정 디자인, 영문 제목 'Civil Service Guide', 아이콘">📋 민원 안내</button>
<button class="img-ex" data-p="전남 청정 농수산물 홍보, 한국 농촌 배경, 영문 문구 'Fresh Local Food', 풍성한">🌾 특산물</button>
</div>
<div class="img-opts">
<label class="img-opt-label">📐 비율
<select id="img-ratio">
<option value="1:1" selected>⬜ 정사각형 1:1</option>
<option value="3:4">📄 세로 3:4 (포스터)</option>
<option value="9:16">📱 세로 9:16 (모바일)</option>
<option value="4:3">🖼️ 가로 4:3</option>
<option value="16:9">🖥️ 가로 16:9 (배너)</option>
</select>
</label>
</div>
<div class="img-input-row">
<textarea id="img-prompt" rows="2" placeholder="원하는 이미지를 설명하세요 (예: 여수 밤바다 야경, 영문 문구 'Visit Yeosu')"></textarea>
<button id="img-gen-btn">🎨 생성</button>
</div>
<div id="img-status" class="img-status" hidden></div>
<div id="img-result" class="img-result"></div>
<div class="img-foot">⚖️ AI 생성 이미지 · 공식 행정자료 아님 · 상업적 이용 시 별도 검토</div>
</div>
</section>
<!-- ===== 🎓 AI 교육 (AI 시민 대학) ===== -->
<section id="view-edu" hidden>
<div class="edu-wrap">
<div class="edu-head">
<h2>🎓 AI 시민 대학 <small>AI 선생님에게 배우고 바로 실습하세요 · 누구나 무료</small></h2>
</div>
<div class="edu-cat-title">📱 JGOS 100% 활용</div>
<div class="edu-cards">
<button class="edu-card" data-q="JGOS에서 민원을 어떻게 물어보나요? 처음 쓰는 사람도 알 수 있게 쉽게 알려주세요." data-go="chat">① 민원 물어보기</button>
<button class="edu-card" data-q="JGOS 무료 오피스로 한글(HWP) 문서를 편집하고 저장하는 법을 알려주세요." data-go="office">② HWP 편집</button>
<button class="edu-card" data-q="JGOS 이미지 생성 기능 사용법과 좋은 설명(프롬프트) 쓰는 법을 알려주세요." data-go="image">③ 이미지 생성</button>
<button class="edu-card" data-q="JGOS에 PDF나 사진 파일을 올려서 내용을 분석하는 방법을 알려주세요." data-go="chat">④ 파일 분석</button>
</div>
<div class="edu-cat-title">🤖 AI 기본 소양</div>
<div class="edu-cards">
<button class="edu-card" data-q="AI가 무엇인지 어르신도 이해하기 쉽게 비유를 들어 설명해주세요.">⑤ AI란 무엇?</button>
<button class="edu-card" data-q="AI에게 질문을 잘 하는 방법(프롬프트)을 쉬운 예시와 함께 알려주세요.">⑥ 질문 잘하기</button>
<button class="edu-card" data-q="AI가 만든 가짜 정보(환각)를 구별하고 조심하는 방법을 알려주세요.">⑦ 가짜정보 판별</button>
<button class="edu-card" data-q="AI를 사용할 때 내 개인정보를 안전하게 지키는 방법을 알려주세요.">⑧ 개인정보 보호</button>
</div>
<div class="edu-cat-title">🌱 생활 맞춤</div>
<div class="edu-cards">
<button class="edu-card" data-q="컴퓨터가 익숙하지 않은 어르신을 위해 AI를 처음 사용하는 법을 아주 쉽고 천천히 알려주세요.">⑨ 어르신 첫걸음</button>
<button class="edu-card" data-q="소상공인이 AI로 가게 홍보물과 안내 문서를 만드는 방법을 알려주세요.">⑩ 소상공인 홍보</button>
<button class="edu-card" data-q="학생이 AI를 공부와 학습에 올바르고 똑똑하게 활용하는 방법을 알려주세요.">⑪ 학생 학습</button>
<button class="edu-card" data-q="농어민이 AI로 농수산물 홍보·판매와 영농 정보를 활용하는 방법을 알려주세요.">⑫ 농어민 활용</button>
</div>
<div class="edu-teacher">
<div class="edu-teacher-head">🧑‍🏫 AI 선생님 — 무엇이든 편하게 물어보세요</div>
<div id="edu-messages" class="edu-messages"></div>
<div id="edu-goto" class="edu-goto" hidden></div>
<div class="edu-input-row">
<textarea id="edu-input" rows="1" placeholder="예: AI가 뭐예요? / 프롬프트가 뭔가요?"></textarea>
<button id="edu-send">질문</button>
</div>
</div>
<div class="edu-foot">🎓 전남광주 통합특별시 AI 시민 대학 · 모든 시민 무료 · 위 강의를 누르면 AI 선생님이 설명해 드려요</div>
</div>
</section>
<!-- ===== 🏛️ 행정 AX 데이터 통합 (테스트 데모) ===== -->
<section id="view-ax" hidden>
<div class="ax-container">
<div class="ax-header">
<h2>🏛️ 행정 AX 데이터 통합 — 테스트 데모</h2>
<p class="ax-desc">이종 파일 포맷·서식의 행정 데이터를 자동으로 인식·정규화·통합합니다</p>
</div>
<!-- Demo 1: 이종 Excel 통합 -->
<div class="ax-demo-card">
<div class="ax-demo-header">
<span class="ax-demo-badge">Demo 1</span>
<h3>📊 이종 Excel 자동 통합</h3>
<p>27개 지자체가 제각각 다른 서식으로 제출한 Excel을 자동으로 표준화·통합합니다</p>
</div>
<div class="ax-demo-files">
<div class="ax-files-label">📁 예제 파일 (클릭하여 미리보기)</div>
<div class="ax-file-icons" id="ax-excel-demos"><!-- JS로 채움 --></div>
</div>
<div class="ax-upload-zone" id="ax-excel-drop">
<div class="ax-upload-inner">
<span class="ax-upload-icon">📤</span>
<div>Excel/CSV 파일을 여기에 드래그하거나 클릭하세요</div>
<div class="ax-upload-hint">XLSX, XLS, CSV — 여러 파일 동시 업로드 가능</div>
</div>
<input type="file" id="ax-excel-input" hidden multiple accept=".xlsx,.xls,.csv">
</div>
<div class="ax-actions">
<button class="ax-btn ax-btn-primary" id="ax-excel-run" disabled>
<span></span> 통합 실행
</button>
<span class="ax-file-count" id="ax-excel-count"></span>
</div>
<div class="ax-result-area" id="ax-excel-result" hidden></div>
</div>
<!-- Demo 2: 이종 포맷 통합 -->
<div class="ax-demo-card">
<div class="ax-demo-header">
<span class="ax-demo-badge ax-demo-badge-2">Demo 2</span>
<h3>🗂️ 이종 포맷 자동 통합</h3>
<p>HWP, XLSX, CSV, PPTX, DOCX, PDF — 7가지 다른 포맷의 데이터를 하나의 표로 통합합니다</p>
</div>
<div class="ax-demo-files">
<div class="ax-files-label">📁 예제 파일 7종 (클릭하여 미리보기)</div>
<div class="ax-file-icons" id="ax-format-demos"><!-- JS로 채움 --></div>
</div>
<div class="ax-upload-zone" id="ax-format-drop">
<div class="ax-upload-inner">
<span class="ax-upload-icon">📤</span>
<div>이종 포맷 파일을 여기에 드래그하거나 클릭하세요</div>
<div class="ax-upload-hint">HWPX, XLSX, CSV, PPTX, DOCX, PDF — 혼합 업로드 가능</div>
</div>
<input type="file" id="ax-format-input" hidden multiple accept=".hwp,.hwpx,.xlsx,.xls,.csv,.docx,.pptx,.pdf">
</div>
<div class="ax-actions">
<button class="ax-btn ax-btn-primary ax-btn-2" id="ax-format-run" disabled>
<span></span> 통합 실행
</button>
<span class="ax-file-count" id="ax-format-count"></span>
</div>
<div class="ax-result-area" id="ax-format-result" hidden></div>
</div>
</div>
<!-- 파일 미리보기 모달 -->
<div id="ax-modal" class="ax-modal-overlay" hidden>
<div class="ax-modal-box">
<div class="ax-modal-header">
<span id="ax-modal-title">파일 미리보기</span>
<button class="ax-modal-close" id="ax-modal-close"></button>
</div>
<div class="ax-modal-body" id="ax-modal-body">
<div class="ax-loading">⏳ 불러오는 중...</div>
</div>
</div>
</div>
</section>
</main>
<!-- 모바일 사이드바 백드롭 -->
<div id="sidebar-backdrop" hidden></div>
</div>
<div id="drag-overlay" hidden>
<div class="drop-card">
📂 여기에 파일을 놓으세요
<small>HWP · HWPX · PDF · DOCX · PPTX · XLSX · CSV · 이미지<br>(ESC 또는 클릭으로 닫기)</small>
</div>
</div>
<script src="/static/jgos_app_v611.js?v=612"></script>
<script>
/* JGOS AX 미리보기 — 인라인 (캐시 우회, v611-INLINE) */
window.axPreviewDemo = async function(filename, label){
var modal=document.getElementById("ax-modal");
var body=document.getElementById("ax-modal-body");
var title=document.getElementById("ax-modal-title");
if(!modal||!body)return;
if(title)title.textContent="\uD83D\uDCC4 "+label+" \u2014 \uBBF8\uB9AC\uBCF4\uAE30";
body.innerHTML='<div class="ax-loading">\u23F3 \uBD88\uB7EC\uC624\uB294 \uC911... [INLINE]</div>';
modal.hidden=false;
try{
var r=await fetch("/api/demo/preview/"+encodeURIComponent(filename)+"?t="+Date.now());
if(!r.ok){body.innerHTML="<p style=\'color:#b91c1c\'>\uC11C\uBC84 \uC624\uB958 ("+r.status+")</p>";return;}
var d=await r.json();
body.innerHTML=(d.rows>0)?(d.html||"<p>\uBE48 \uACB0\uACFC</p>"):"<p style=\'color:#92400e\'>\u26A0\uFE0F \uD30C\uC2F1 \uC2E4\uD328</p>";
}catch(e){
body.innerHTML="<p style=\'color:red\'>\uC624\uB958: "+(e&&e.message?e.message:e)+"</p>";
}
};
/* 칩 onclick 재바인딩 (외부 js가 이미 그렸어도 인라인 함수로 연결) */
(function(){
function rebind(){
document.querySelectorAll(".ax-file-chip").forEach(function(chip){
chip.onclick=function(){ window.axPreviewDemo(chip.dataset.demo, chip.dataset.label); };
});
}
if(document.readyState!=="loading")setTimeout(rebind,300);
else document.addEventListener("DOMContentLoaded",function(){setTimeout(rebind,300);});
// 탭 전환 후에도 재바인딩
document.addEventListener("click",function(e){
var t=e.target.closest&&e.target.closest('[data-view="ax"]');
if(t)setTimeout(rebind,400);
});
})();
console.log("[JGOS] AX inline preview v611-INLINE loaded");
</script>
<script>
/* JGOS AX 예제 바로 실행 버튼 — DEMO-RUN-v1 */
(function(){
async function runDemoMerge(btn, resultId, demoType){
var result=document.getElementById(resultId);
var old=btn.innerHTML; btn.disabled=true; btn.innerHTML="\u23F3 \uD1B5\uD569 \uC911...";
if(result){result.hidden=false;result.innerHTML='<div class="ax-loading">\u23F3 \uC608\uC81C \uD1B5\uD569 \uC911...</div>';}
try{
var r=await fetch("/api/demo/merge/"+demoType+"?t="+Date.now());
var d=await r.json();
if(result){
var src=(d.sources||[]).map(function(s){return '<span class="ax-source-chip">'+(s["\uD3EC\uB9F7"]||"")+' '+s["\uD30C\uC77C"]+' ('+s["\uAC74\uC218"]+'\uAC74)</span>';}).join("");
result.innerHTML='<div class="ax-source-list">'+src+'</div>'+(d.html||"");
}
}catch(e){if(result)result.innerHTML="<p style=\'color:red\'>\uC624\uB958: "+(e&&e.message?e.message:e)+"</p>";}
btn.disabled=false; btn.innerHTML=old;
}
function addBtn(runBtnId, resultId, demoType){
var runBtn=document.getElementById(runBtnId);
if(!runBtn) return;
if(document.getElementById(runBtnId+"-demo")) return;
var btn=document.createElement("button");
btn.id=runBtnId+"-demo";
btn.className=runBtn.className;
btn.style.background="#0d7377";
btn.style.marginLeft="8px";
btn.innerHTML="\uD83D\uDCC2 \uC608\uC81C\uB85C \uBC14\uB85C \uD1B5\uD569";
runBtn.parentNode.insertBefore(btn, runBtn.nextSibling);
btn.onclick=function(){ runDemoMerge(btn, resultId, demoType); };
}
function setup(){
addBtn("ax-excel-run","ax-excel-result","excel");
addBtn("ax-format-run","ax-format-result","formats");
}
if(document.readyState!=="loading") setTimeout(setup,500);
else document.addEventListener("DOMContentLoaded",function(){setTimeout(setup,500);});
document.addEventListener("click",function(e){
var t=e.target.closest&&e.target.closest('[data-view="ax"]');
if(t) setTimeout(setup,500);
});
console.log("[JGOS] AX demo-run buttons v1 loaded");
})();
</script>
<script>
/* AX-INTEGRATE-v2: 통합 결과 표시 + XLSX 다운로드 */
(function(){
function chip(s){return '<span class="ax-source-chip">'+(s["\uD3EC\uB9F7"]||"")+" "+(s["\uD30C\uC77C"]||"")+" ("+(s["\uAC74\uC218"]||0)+"\uAC74)</span>";}
window.__axShow=function(resultId,d){
var result=document.getElementById(resultId);
if(!result)return;
result.hidden=false;
var src=(d.sources||[]).map(chip).join("");
result.innerHTML='<div class="ax-source-list">'+src+'</div>'+(d.html||"");
if(d.records&&d.records.length){
var dl=document.createElement("button");
dl.style.cssText="background:#1d6f42;color:#fff;margin-top:14px;padding:11px 24px;border:none;border-radius:9px;font-weight:700;cursor:pointer;font-size:0.95rem";
dl.textContent="\uD83D\uDCE5 \uD1B5\uD569\uBCF8 XLSX \uB2E4\uC6B4\uB85C\uB4DC ("+d.records.length+"\uAC74)";
dl.onclick=async function(){
var o=dl.textContent; dl.disabled=true; dl.textContent="\u23F3 \uC0DD\uC131 \uC911...";
try{
var rr=await fetch("/api/export/xlsx",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({records:d.records,title:"JGOS \uD589\uC815AX \uD1B5\uD569\uACB0\uACFC"})});
if(!rr.ok)throw new Error("\uC11C\uBC84 "+rr.status);
var b=await rr.blob(); var u=URL.createObjectURL(b);
var a=document.createElement("a"); a.href=u; a.download="JGOS_\uD589\uC815AX_\uD1B5\uD569\uACB0\uACFC.xlsx";
document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(u);
}catch(e){alert("\uB2E4\uC6B4\uB85C\uB4DC \uC2E4\uD328: "+(e.message||e));}
dl.disabled=false; dl.textContent=o;
};
result.appendChild(dl);
}
};
async function exampleMerge(btn,resultId,type){
var o=btn.innerHTML; btn.disabled=true; btn.innerHTML="\u23F3 \uD1B5\uD569 \uC911...";
var result=document.getElementById(resultId);
if(result){result.hidden=false;result.innerHTML='<div class="ax-loading">\u23F3 \uC608\uC81C \uD1B5\uD569 \uC911...</div>';}
try{var r=await fetch("/api/demo/merge/"+type+"?t="+Date.now());var d=await r.json();window.__axShow(resultId,d);}
catch(e){if(result)result.innerHTML="<p style=\'color:red\'>\uC624\uB958: "+(e.message||e)+"</p>";}
btn.disabled=false; btn.innerHTML=o;
}
async function uploadMerge(btn,inputId,resultId,apiPath){
var input=document.getElementById(inputId);
if(!input||!input.files||!input.files.length){alert("\uD30C\uC77C\uC744 \uC120\uD0DD\uD558\uC138\uC694");return;}
var o=btn.innerHTML; btn.disabled=true; btn.innerHTML="\u23F3 \uD1B5\uD569 \uC911...";
var result=document.getElementById(resultId);
if(result){result.hidden=false;result.innerHTML='<div class="ax-loading">\u23F3 \uD1B5\uD569 \uC911...</div>';}
var fd=new FormData(); for(var i=0;i<input.files.length;i++)fd.append("files",input.files[i]);
try{var r=await fetch(apiPath,{method:"POST",body:fd});var d=await r.json();window.__axShow(resultId,d);}
catch(e){if(result)result.innerHTML="<p style=\'color:red\'>\uC624\uB958: "+(e.message||e)+"</p>";}
btn.disabled=false; btn.innerHTML=o;
}
function setup(){
var er=document.getElementById("ax-excel-run");
if(er)er.onclick=function(){uploadMerge(er,"ax-excel-input","ax-excel-result","/api/excel/merge");};
var fr=document.getElementById("ax-format-run");
if(fr)fr.onclick=function(){uploadMerge(fr,"ax-format-input","ax-format-result","/api/files/merge-formats");};
[["ax-excel-run","ax-excel-result","excel"],["ax-format-run","ax-format-result","formats"]].forEach(function(x){
var run=document.getElementById(x[0]); if(!run)return;
var id=x[0]+"-demo"; var b=document.getElementById(id);
if(!b){b=document.createElement("button");b.id=id;b.className=run.className;b.style.background="#0d7377";b.style.marginLeft="8px";b.innerHTML="\uD83D\uDCC2 \uC608\uC81C\uB85C \uBC14\uB85C \uD1B5\uD569";run.parentNode.insertBefore(b,run.nextSibling);}
b.onclick=function(){exampleMerge(b,x[1],x[2]);};
});
}
if(document.readyState!=="loading")setTimeout(setup,600);
else document.addEventListener("DOMContentLoaded",function(){setTimeout(setup,600);});
document.addEventListener("click",function(e){var t=e.target.closest&&e.target.closest('[data-view="ax"]');if(t)setTimeout(setup,600);});
console.log("[JGOS] AX integrate+download v2 loaded");
})();
</script>
</body>
</html>