openfree commited on
Commit
2b60da4
·
verified ·
1 Parent(s): 6adfc90

style: 흡수 서비스(사주·AI글판별·건축도면) JGOS 톤 래퍼 적용 — 제목·설명·카드형 프레임·안내문

Browse files
Files changed (1) hide show
  1. static/index.html +765 -739
static/index.html CHANGED
@@ -1,739 +1,765 @@
1
- <!DOCTYPE html>
2
- <html lang="ko">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
6
- <meta name="theme-color" content="#0052a4">
7
- <title>[제안 테스트] JGOS · 행정 AI 서비스 특화 모델</title>
8
- <link rel="preconnect" href="https://fonts.googleapis.com">
9
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
- <link rel="stylesheet" href="/static/style.css?v=20260612a">
11
- <script src="https://cdn.jsdelivr.net/npm/marked@14.1.3/marked.min.js"></script>
12
- <script src="https://cdn.jsdelivr.net/npm/dompurify@3.1.7/dist/purify.min.js"></script>
13
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/styles/github.min.css">
14
- <script src="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/highlight.min.js"></script>
15
- <style id="ax-modal-fix">#ax-modal[hidden]{display:none !important;}</style>
16
-
17
-
18
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css">
19
- <style id="jgos-apple-css">
20
- :root{
21
- --bg:#F5F5F7; --surface:#FFFFFF; --surface-2:rgba(255,255,255,.72);
22
- --ink:#1D1D1F; --ink-2:#4B4F55; --ink-3:#86868B; --hair:rgba(0,0,0,.09);
23
- --blue:#0071E3; --green:#00875A; --amber:#8A6414;
24
- --r-lg:22px; --r-md:16px;
25
- --sh:0 1px 2px rgba(0,0,0,.04), 0 12px 32px -20px rgba(0,0,0,.30);
26
- --sh-hi:0 2px 6px rgba(0,0,0,.06), 0 24px 48px -24px rgba(0,0,0,.34);
27
- }
28
- @media (prefers-color-scheme: dark){
29
- :root{
30
- --bg:#000000; --surface:#1C1C1E; --surface-2:rgba(28,28,30,.72);
31
- --ink:#F5F5F7; --ink-2:#C7C9CC; --ink-3:#8E8E93; --hair:rgba(255,255,255,.12);
32
- --blue:#0A84FF; --green:#30D158; --amber:#FFD60A;
33
- --sh:0 1px 2px rgba(0,0,0,.5), 0 12px 32px -20px rgba(0,0,0,.9);
34
- --sh-hi:0 2px 8px rgba(0,0,0,.6), 0 24px 56px -26px rgba(0,0,0,1);
35
- }
36
- }
37
- body,#app,#main{background:var(--bg)!important;color:var(--ink)!important;
38
- font-family:"Pretendard Variable",Pretendard,-apple-system,BlinkMacSystemFont,"Apple SD Gothic Neo",system-ui,sans-serif!important;
39
- -webkit-font-smoothing:antialiased;letter-spacing:-.011em}
40
-
41
- #topbar{background:var(--surface-2)!important;backdrop-filter:saturate(180%) blur(20px);
42
- -webkit-backdrop-filter:saturate(180%) blur(20px);
43
- border-bottom:1px solid var(--hair)!important;box-shadow:none!important}
44
- .title-main{font-size:17px!important;font-weight:650!important;letter-spacing:-.02em!important;color:var(--ink)!important}
45
- .title-sub{font-size:12.5px!important;color:var(--ink-3)!important;font-weight:400!important}
46
- .top-tabs{gap:2px!important}
47
- .top-tab{background:transparent!important;border:0!important;color:var(--ink-2)!important;
48
- font-size:13.5px!important;font-weight:500!important;padding:7px 13px!important;border-radius:980px!important;
49
- transition:background .18s,color .18s}
50
- .top-tab:hover{background:rgba(127,127,127,.12)!important;color:var(--ink)!important}
51
- .top-tab.active{background:var(--ink)!important;color:var(--bg)!important;font-weight:600!important}
52
- #sidebar{background:var(--surface-2)!important;backdrop-filter:blur(20px);border-right:1px solid var(--hair)!important}
53
- .status-pill{border-radius:980px!important;font-size:11.5px!important;color:var(--ink-3)!important;background:transparent!important;border:1px solid var(--hair)!important}
54
-
55
- #view-home{padding:0 0 88px;overflow-y:auto;background:var(--bg)}
56
- .svc-wrap{max-width:1040px;margin:0 auto;padding:0 22px}
57
- .svc-hero{position:relative;margin:44px 0 40px;padding:64px 48px;border-radius:var(--r-lg);
58
- background:linear-gradient(158deg,#0A2540 0%,#123A63 45%,#0071E3 130%);color:#fff;cursor:pointer;
59
- overflow:hidden;box-shadow:var(--sh);transition:transform .3s cubic-bezier(.2,.8,.2,1),box-shadow .3s}
60
- .svc-hero::after{content:"";position:absolute;inset:auto -18% -62% auto;width:520px;height:520px;border-radius:50%;
61
- background:radial-gradient(circle,rgba(255,255,255,.16),transparent 66%);pointer-events:none}
62
- .svc-hero:hover{transform:translateY(-3px);box-shadow:var(--sh-hi)}
63
- .svc-hero .eyebrow{font-size:12.5px;letter-spacing:.02em;font-weight:600;color:rgba(255,255,255,.72)}
64
- .svc-hero h2{margin:14px 0 12px;font-size:clamp(32px,5vw,52px);font-weight:700;letter-spacing:-.035em;line-height:1.08}
65
- .svc-hero p{margin:0;font-size:17px;line-height:1.62;color:rgba(255,255,255,.88);max-width:34em;font-weight:400}
66
- .svc-hero .go{display:inline-flex;align-items:center;gap:7px;margin-top:26px;background:#fff;color:#0A2540;
67
- border-radius:980px;padding:12px 24px;font-weight:600;font-size:15px;letter-spacing:-.01em}
68
-
69
- .svc-group{margin-top:52px}
70
- .svc-group h3{font-size:26px;font-weight:680;letter-spacing:-.025em;margin:0 0 20px;padding:0;border:0;color:var(--ink)}
71
- .svc-grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fill,minmax(238px,1fr))}
72
- .svc-card{background:var(--surface);border:0;border-radius:var(--r-md);padding:24px 22px 20px;
73
- display:flex;flex-direction:column;gap:8px;cursor:pointer;box-shadow:var(--sh);
74
- transition:transform .28s cubic-bezier(.2,.8,.2,1),box-shadow .28s}
75
- .svc-card:hover,.svc-card:focus-visible{transform:translateY(-4px);box-shadow:var(--sh-hi);outline:none}
76
- .svc-card .row{display:flex;align-items:flex-start;gap:9px}
77
- .svc-card h4{margin:0;font-size:17px;font-weight:620;letter-spacing:-.02em;line-height:1.35;color:var(--ink)}
78
- .svc-card p{margin:0;font-size:13.5px;line-height:1.62;color:var(--ink-3);font-weight:400}
79
- .svc-st{flex:none;margin-left:auto;font-size:11px;font-weight:600;padding:3px 9px;border-radius:980px;white-space:nowrap}
80
- .st-live{background:rgba(0,135,90,.11);color:var(--green)}
81
- .st-soon{background:rgba(138,100,20,.12);color:var(--amber)}
82
- .svc-card.soon{cursor:default;box-shadow:none;background:transparent;border:1px solid var(--hair)}
83
- .svc-card.soon:hover{transform:none;box-shadow:none}
84
-
85
- #view-saju{padding:0 0 88px;overflow-y:auto;background:var(--bg)}
86
- .saju-wrap{max-width:880px;margin:0 auto;padding:52px 22px 0}
87
- .saju-head h2{font-size:clamp(30px,4.4vw,44px);font-weight:700;letter-spacing:-.035em;margin:0 0 10px}
88
- .saju-head p{margin:0 0 30px;color:var(--ink-3);font-size:16px;line-height:1.6}
89
- .saju-form{background:var(--surface);border-radius:var(--r-md);padding:22px;box-shadow:var(--sh)}
90
- .saju-row{display:flex;flex-wrap:wrap;gap:14px;align-items:flex-end}
91
- .saju-row label{display:flex;flex-direction:column;gap:7px;font-size:12.5px;font-weight:600;color:var(--ink-3);flex:1 1 150px}
92
- .saju-row input,.saju-row select{font-family:inherit;font-size:15px;color:var(--ink);background:var(--bg);
93
- border:1px solid var(--hair);border-radius:11px;padding:11px 13px;font-weight:450;-webkit-appearance:none;appearance:none}
94
- .saju-row input:focus,.saju-row select:focus{outline:none;border-color:var(--blue);box-shadow:0 0 0 3.5px rgba(0,113,227,.16)}
95
- #sj-go{flex:0 0 auto;background:var(--blue);color:#fff;border:0;border-radius:980px;padding:12px 26px;
96
- font-family:inherit;font-size:15px;font-weight:600;cursor:pointer;letter-spacing:-.01em;transition:opacity .18s}
97
- #sj-go:hover{opacity:.86}
98
- #sj-go:disabled{opacity:.45;cursor:default}
99
- .saju-msg{margin-top:18px;padding:14px 16px;border-radius:12px;background:var(--surface);color:var(--ink-2);font-size:14px;box-shadow:var(--sh)}
100
- .saju-result{margin-top:26px;display:flex;flex-direction:column;gap:16px}
101
- .sj-card{background:var(--surface);border-radius:var(--r-md);padding:26px 24px;box-shadow:var(--sh)}
102
- .sj-card h3{margin:0 0 4px;font-size:13px;font-weight:600;color:var(--ink-3)}
103
- .sj-pillars{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-top:16px}
104
- .sj-p{text-align:center;background:var(--bg);border-radius:13px;padding:18px 8px}
105
- .sj-p .lab{font-size:11.5px;color:var(--ink-3);font-weight:600}
106
- .sj-p .han{font-size:clamp(26px,4.6vw,38px);font-weight:600;letter-spacing:-.02em;margin:8px 0 2px;line-height:1.1}
107
- .sj-p .kor{font-size:13px;color:var(--ink-2)}
108
- .sj-meta{display:flex;flex-wrap:wrap;gap:9px;margin-top:18px}
109
- .sj-tag{background:var(--bg);border-radius:980px;padding:7px 14px;font-size:13px;color:var(--ink-2);font-weight:500}
110
- .sj-tag b{color:var(--ink);font-weight:640}
111
- .sj-bars{display:flex;flex-direction:column;gap:11px;margin-top:16px}
112
- .sj-bar{display:grid;grid-template-columns:34px 1fr 46px;align-items:center;gap:12px;font-size:13.5px}
113
- .sj-bar .n{font-weight:620;color:var(--ink)}
114
- .sj-bar .t{height:8px;border-radius:980px;background:rgba(127,127,127,.16);overflow:hidden}
115
- .sj-bar .f{height:100%;border-radius:980px;background:var(--blue);transition:width .7s cubic-bezier(.2,.8,.2,1)}
116
- .sj-bar .v{text-align:right;color:var(--ink-3);font-variant-numeric:tabular-nums}
117
- .saju-note{margin:26px 0 0;font-size:12.5px;color:var(--ink-3);text-align:center}
118
-
119
- #view-building,#view-texray,#view-saju{padding:0;background:var(--bg)}
120
- #building-frame,#texray-frame,#saju-frame{width:100%;height:calc(100vh - 168px);border:0;display:block;background:var(--bg)}
121
- @media(max-width:720px){.svc-hero{padding:44px 26px}.sj-pillars{grid-template-columns:repeat(2,1fr)}}
122
- @media (prefers-reduced-motion:reduce){*{transition:none!important}}
123
- </style>
124
- </head>
125
- <body>
126
- <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>
127
- <div id="app">
128
-
129
- <!-- ===== 모바일 햄버거 ===== -->
130
- <button id="hamburger-btn" aria-label="메뉴 열기">
131
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
132
- <line x1="3" y1="6" x2="21" y2="6"/>
133
- <line x1="3" y1="12" x2="21" y2="12"/>
134
- <line x1="3" y1="18" x2="21" y2="18"/>
135
- </svg>
136
- </button>
137
-
138
- <!-- ===== 사이드바 ===== -->
139
- <aside id="sidebar">
140
- <div class="sidebar-head">
141
- <div class="brand-top">
142
- <div class="emblem">🏛️</div>
143
- <div>
144
- <div class="brand-title">전남광주 통합특별시</div>
145
- <div class="brand-sub">시민의 AI</div>
146
- </div>
147
- </div>
148
- <button id="new-chat-btn" title="새 대화">+ 새 상담</button>
149
- </div>
150
- <div class="sidebar-section-label">최근 상담</div>
151
- <ul id="chat-list"></ul>
152
- <div class="sidebar-foot">
153
- <div class="brand-small">
154
- <strong>Powered by @비드래프트</strong>
155
- <small>JGOS v0.1 preview</small>
156
- </div>
157
- </div>
158
- </aside>
159
-
160
- <main id="main">
161
- <!-- ===== 상단 시민포털 헤더 ===== -->
162
- <header id="topbar">
163
- <div class="topbar-left">
164
- <button id="sidebar-toggle" class="mobile-only" aria-label="사이드바">☰</button>
165
- <div class="title-block">
166
- <div class="title-main">🏛️ 전남광주 통합특별시 · 시민의 AI</div>
167
- <div class="title-sub">행정 특화 언어모델 <b>JGOS</b> 탑재 · 행정·법령·관광·민원 안내</div>
168
- </div>
169
- </div>
170
- <nav class="top-tabs">
171
- <button class="top-tab active" data-view="home">🏠 서비스</button>
172
- <button class="top-tab" data-view="chat">💬 JGOS 챗봇</button>
173
- <button class="top-tab" data-view="building">🏗️ 건축 도면</button>
174
- <button class="top-tab" data-view="office">📑 무료 오피스</button>
175
- <button class="top-tab" data-view="image">🎨 이미지 생성</button>
176
- <button class="top-tab" data-view="saju">🔮 사주</button>
177
- <button class="top-tab" data-view="texray">🔍 AI 글 판별</button>
178
- <button class="top-tab" data-view="ax">🏛️ 행정 AX(테스트)</button>
179
- </nav>
180
- <div class="topbar-right">
181
- <span class="status-pill" id="status">● 정상</span>
182
- </div>
183
- </header>
184
-
185
- <div id="view-chat">
186
- <div id="messages-wrap">
187
- <div id="messages"></div>
188
-
189
- <!-- ===== 첫 화면 시민포털 (메시지 0건 시 표시) ===== -->
190
- <div id="portal" class="portal">
191
- <div class="portal-hero">
192
- <div class="hero-emblem">🏛️</div>
193
- <h1 class="hero-title">전남광주 통합특별시민과<br>함께하는 AI <strong>JGOS</strong></h1>
194
- <p class="hero-sub">행정·민원·법령·관광·교통·문화·통계·산업·농수산 정보를<br>친절하게 안내해 드립니다. 무엇이 궁금하신가요?</p>
195
- </div>
196
-
197
- <!-- ===== 방안1: 히어로 파일 드롭존 ===== -->
198
- <button class="hero-dropzone" id="hero-dropzone" type="button">
199
- <div class="hd-icon">📎</div>
200
- <div class="hd-main">파일을 끌어다 놓거나 클릭하세요</div>
201
- <div class="hd-sub">HWP · 이미지 · PDF · 엑셀 무엇이든 올리면 <strong>바로 분석</strong>해 드립니다</div>
202
- <div class="hd-badge">🇰🇷 타 AI가 못 읽는 <strong>한글 HWP</strong>도 분석하는 sovereign AI</div>
203
- <!-- 방안2: 지원 형식 아이콘 띠 -->
204
- <div class="fmt-strip">
205
- <span class="fmt hwp">HWP</span><span class="fmt hwp">HWPX</span>
206
- <span class="fmt pdf">PDF</span><span class="fmt doc">DOCX</span>
207
- <span class="fmt xls">XLSX</span><span class="fmt ppt">PPTX</span>
208
- <span class="fmt csv">CSV</span><span class="fmt img">이미지</span>
209
- <span class="fmt more">+10종</span>
210
- </div>
211
- </button>
212
-
213
- <!-- 8개 카테고리 큰 카드 -->
214
- <div class="cat-grid">
215
- <button class="cat-card" data-q="민원 처리 절차와 필요한 서류를 알려주세요.">
216
- <div class="cat-emoji">📝</div>
217
- <div class="cat-name">민원</div>
218
- <div class="cat-desc">절차·서류·전화</div>
219
- </button>
220
- <button class="cat-card" data-q="전남광주통합특별법의 주요 조항을 알려주세요.">
221
- <div class="cat-emoji">📜</div>
222
- <div class="cat-name">법령</div>
223
- <div class="cat-desc">특별법·조례</div>
224
- </button>
225
- <button class="cat-card" data-q="전남광주 통합특별시 관광 명소를 추천해 주세요.">
226
- <div class="cat-emoji">🗺️</div>
227
- <div class="cat-name">관광</div>
228
- <div class="cat-desc">22 시군 + 5구</div>
229
- </button>
230
- <button class="cat-card" data-q="전남광주 통합특별시 교통편을 안내해 주세요.">
231
- <div class="cat-emoji">🚆</div>
232
- <div class="cat-name">교통</div>
233
- <div class="cat-desc">KTX·공항·페리</div>
234
- </button>
235
- <button class="cat-card" data-q="전남광주 통합특별시의 농수산 특산품을 알려주세요.">
236
- <div class="cat-emoji">🌾</div>
237
- <div class="cat-name">농수산</div>
238
- <div class="cat-desc">GI ���산·수산물</div>
239
- </button>
240
- <button class="cat-card" data-q="전남광주 통합특별시의 주요 산업과 경제 규모를 알려주세요.">
241
- <div class="cat-emoji">🏭</div>
242
- <div class="cat-name">산업</div>
243
- <div class="cat-desc">경제·기업</div>
244
- </button>
245
- <button class="cat-card" data-q="전남광주 통합특별시의 인구 통계와 지역 현황을 알려주세요.">
246
- <div class="cat-emoji">📊</div>
247
- <div class="cat-name">통계</div>
248
- <div class="cat-desc">인구·경제</div>
249
- </button>
250
- <button class="cat-card" data-attach="true">
251
- <div class="cat-emoji">📎</div>
252
- <div class="cat-name">첨부문서</div>
253
- <div class="cat-desc">HWP·PDF·이미지</div>
254
- </button>
255
- </div>
256
-
257
- <!-- 추천 질문 (자주 묻는) -->
258
- <div class="quick-section">
259
- <div class="quick-label">자주 묻는 질문</div>
260
- <div class="quick-grid">
261
- <button class="quick-btn" data-q="전남광주 통합특별시장과 광주 5개 구청장, 전남 시장·군수 당선인이 각각 누구인가요?">🏛️ 지자체장 당선인</button>
262
- <button class="quick-btn" data-q="전남광주(광주·전남) 지역구 국회의원 명단을 알려주세요.">🗳️ 지역구 국회의원</button>
263
- <button class="quick-btn" data-q="주민등록증 재발급 절차와 필요한 서류는?">📇 주민등록증 재발급</button>
264
- <button class="quick-btn" data-q="전남광주 통합특별시 인구는?">👥 통합특별시 인구</button>
265
- <button class="quick-btn" data-q="보성 녹차밭 관광 안내 부탁해.">🍃 보성 녹차밭</button>
266
- <button class="quick-btn" data-q="전남광주통합특별법 제6조 내용은?">📜 특별법 제6조</button>
267
- <button class="quick-btn" data-q="전남광주 통합특별시청 대표 전화번호와 부서 안내는?">📞 시청 대표번호</button>
268
- <button class="quick-btn" data-q="여수에서 가볼 만한 곳 3곳만 추천해.">🏖️ 여수 가볼 곳</button>
269
- <button class="quick-btn" data-q="5·18 민주화운동 기록관 위치와 관람 안내는?">🏛️ 5·18 기록관</button>
270
- <button class="quick-btn" data-q="2026년 7월 1일 전남광주 통합특별시 출범의 의미와 일정은?">🎌 7·1 출범</button>
271
- </div>
272
- </div>
273
-
274
- <!-- 신뢰 배지 (첫 화면 only — NIA 본문은 composer footer에서 영구 표시) -->
275
- <div class="portal-foot">
276
- <div class="trust-line">
277
- <span class="trust-badge">🔒 sovereign AI</span>
278
- <span class="trust-badge">📅 기준일 2026-06-01</span>
279
- <span class="trust-badge">📚 RAG 21,192 청크</span>
280
- <span class="trust-badge">⚖️ 정식 행정 안내 아님 · 062-120 확인 권장</span>
281
- </div>
282
- </div>
283
- </div>
284
- </div>
285
-
286
- <!-- ===== 입력 영역 ===== -->
287
- <footer id="composer">
288
- <div class="warn-bar" id="warn-bar" hidden>
289
- ✅ 2026년 6월 3일 지방선거 완료 — 민형배 통합특별시장 당선(7월 1일 취임). 단체장·지역구 국회의원 명단 반영 완료.
290
- </div>
291
- <div class="attach-row" id="attach-row"></div>
292
- <div class="input-row">
293
- <button id="attach-btn" title="파일 첨부 (HWP/HWPX/PDF/DOCX/PPTX/XLSX/XLS/CSV/이미지)" aria-label="파일 첨부">📎</button>
294
- <button id="web-btn" title="웹검색 — 켜면 네이버·웹에서 최신 정보를 함께 검색합니다" aria-label="웹검색 켜기/끄기" aria-pressed="false">🔍</button>
295
- <button id="minwon-btn" title="민원 — 켜면 질문을 민원으로 보고 담당 부서·연락처를 찾아드립니다" aria-label="민원 모드 켜기/끄기" aria-pressed="false">📞</button>
296
- <input type="file" id="file-input" hidden multiple
297
- accept=".hwp,.hwpx,.pdf,.docx,.pptx,.xlsx,.xls,.csv,.txt,.md,.jpg,.jpeg,.png,.gif,.webp">
298
- <textarea id="input" rows="1" placeholder="질문을 입력하거나 파일을 첨부하세요 (Shift+Enter 줄바꿈)"></textarea>
299
- <button id="send-btn" title="전송 (Enter)" aria-label="전송">
300
- <svg viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>
301
- </button>
302
- </div>
303
-
304
- <!-- ===== NIA K-AI 1위 출처 문구 (항상 표시 — 모든 화면 하단) ===== -->
305
- <div class="nia-disclaimer">
306
- 본 모델은 과학기술정보통신부·한국지능정보사회진흥원(NIA) K-AI 리더보드 1위 달성 모델을 기반으로,
307
- 전남광주 통합특별시 관련 공개정보를 추가 학습·최적화한 한국어 특화 모델입니다.
308
- 한국어 처리 능력과 한국 문화·사회·행정·전문 분야에 대한 이해를 바탕으로
309
- 시민 질의에 정확하고 친절하게 응답합니다.
310
- </div>
311
- </footer>
312
- </div><!-- /view-chat -->
313
-
314
- <!-- ===== 무료 오피스 (HanSoo 엔진 흡수 · same-origin iframe 임베디드) ===== -->
315
-
316
- <section id="view-home" hidden>
317
- <div class="svc-wrap">
318
-
319
- <div class="svc-hero" data-view="chat">
320
- <div class="eyebrow">가장 먼저 · 무엇이든 물어보세요</div>
321
- <h2>JGOS 챗봇</h2>
322
- <p>전입신고부터 재산세 납부 기한까지. 전남광주 통합특별시 행정에 맞춰 만든 우리 시 전용 AI가 24시간 답합니다.</p>
323
- <span class="go">상담 시작하기 →</span>
324
- </div>
325
-
326
- <div class="svc-group">
327
- <h3>지금 바로 쓰는 서비스</h3>
328
- <div class="svc-grid">
329
- <div class="svc-card" data-view="building" tabindex="0"><div class="row"><h4>🏗️ 건축 도면 만들기</h4><span class="svc-st st-live">가동</span></div><p>말로 설명하면 평면도와 도면 파일(DXF)을 만들어 드립니다.</p></div>
330
- <div class="svc-card" data-view="office" tabindex="0"><div class="row"><h4>📑 무료 오피스</h4><span class="svc-st st-live">가동</span></div><p>한글(HWP)·PDF 문서를 설치 없이 열고 고치고 저장합니다.</p></div>
331
- <div class="svc-card" data-view="image" tabindex="0"><div class="row"><h4>🎨 이미지 만들기</h4><span class="svc-st st-live">가동</span></div><p>가게 홍보물, 마을 안내문에 쓸 그림을 말로 설명해 만듭니다.</p></div>
332
- <div class="svc-card" data-view="ax" tabindex="0"><div class="row"><h4>🏛️ 엑셀 자동 통합</h4><span class="svc-st st-live">가동</span></div><p>양식이 제각각인 부서 파일을 하나의 표로 합칩니다.</p></div>
333
- <div class="svc-card" data-view="chat" data-q="이 파일 내용을 정리해 주세요." tabindex="0"><div class="row"><h4>📎 파일 분석</h4><span class="svc-st st-live">가동</span></div><p>고지서·계약서 사진을 올리면 무슨 내용인지 풀어 설명합니다.</p></div>
334
- <div class="svc-card" data-view="saju" tabindex="0"><div class="row"><h4>🔮 사주</h4><span class="svc-st st-live">가동</span></div><p>만세력·오행·대운·세운까지 AGI 명리 분석. 순한맛·매운맛 골라 보세요.</p></div>
335
- <div class="svc-card" data-view="texray" tabindex="0"><div class="row"><h4>🔍 AI 글 판별</h4><span class="svc-st st-live">가동</span></div><p>제출물이 AI로 쓰였는지, 베낀 곳이 있는지 검사합니다.</p></div>
336
- <div class="svc-card" data-view="chat" data-q="전남광주 통합특별시 관광 명소와 특산품, 교통편을 안내해 주세요." tabindex="0"><div class="row"><h4>🚄 관광·특산·교통</h4><span class="svc-st st-live">가동</span></div><p>명소, 지리적표시 특산품, KTX·공항·페리를 한자리에서.</p></div>
337
- <div class="svc-card" data-view="chat" data-q="전남광주통합특별법의 주요 조항을 알려주세요." tabindex="0"><div class="row"><h4>⚖️ 특별법·조례</h4><span class="svc-st st-live">가동</span></div><p>통합특별법과 시 조례 내용을 찾아 설명합니다.</p></div>
338
- <div class="svc-card" data-view="chat" data-q="어려운 행정 용어를 어르신도 알아듣기 쉬운 말로 풀어서 설명해 주세요." tabindex="0"><div class="row"><h4>🧓 쉬운 말로 듣기</h4><span class="svc-st st-live">가동</span></div><p>어려운 행정 용어를 알아듣기 쉬운 말로 바꿔 안내합니다.</p></div>
339
- </div>
340
- </div>
341
-
342
- <div class="svc-group">
343
- <h3>준비 중인 서비스</h3>
344
- <div class="svc-grid">
345
- <div class="svc-card soon"><div class="row"><h4>📄 문서 판독</h4><span class="svc-st st-soon">준비 중</span></div><p>손글씨 서식·진단서를 읽어 표로 정리합니다.</p></div>
346
- <div class="svc-card soon"><div class="row"><h4>🗣️ 안내 아바타</h4><span class="svc-st st-soon">준비 중</span></div><p>사람 얼굴로 말하며 안내합니다. 글보다 말이 편한 분께.</p></div>
347
- <div class="svc-card soon"><div class="row"><h4>☎️ AI 전화상담</h4><span class="svc-st st-soon">준비 중</span></div><p>인터넷을 안 쓰셔도 전화 한 통이면 됩니다.</p></div>
348
- <div class="svc-card soon"><div class="row"><h4>🛡️ 어르신 생활반응</h4><span class="svc-st st-soon">준비 중</span></div><p>카메라 없이 집 안 움직임을 살펴 이상이 길어지면 알립니다.</p></div>
349
- <div class="svc-card soon"><div class="row"><h4>🌾 영농 상담</h4><span class="svc-st st-soon">준비 중</span></div><p>작물 시기, 판로, 지원 사업을 물어보세요.</p></div>
350
- <div class="svc-card soon"><div class="row"><h4>🏢 조달·나라장터</h4><span class="svc-st st-soon">준비 중</span></div><p>우리 시 기업이 낼 수 있는 공고를 찾아 드립니다.</p></div>
351
- <div class="svc-card soon"><div class="row"><h4>💡 ���허·지식재산</h4><span class="svc-st st-soon">준비 중</span></div><p>아이디어가 이미 나온 것인지 확인하고 출원을 돕습니다.</p></div>
352
- </div>
353
- </div>
354
-
355
- </div>
356
- </section>
357
-
358
- <section id="view-building" hidden>
359
- <iframe id="building-frame" title="건축 도면 만들기" src="about:blank"></iframe>
360
- </section>
361
-
362
-
363
- <section id="view-saju" hidden>
364
- <iframe id="saju-frame" title="사주" src="about:blank"></iframe>
365
- </section>
366
-
367
- <section id="view-texray" hidden>
368
- <iframe id="texray-frame" title="AI 글 판별" src="about:blank"></iframe>
369
- </section>
370
-
371
- <section id="view-office" hidden>
372
- <iframe id="office-frame" title="무료 오피스 (HWP·DOCX·XLSX·PPTX·PDF)"
373
- allow="clipboard-read; clipboard-write"></iframe>
374
- </section>
375
-
376
- <!-- ===== JGOS-Image (Qwen-Image-2512 한글 이미지 생성) ===== -->
377
- <section id="view-image" hidden>
378
- <div class="img-studio">
379
- <div class="img-head">
380
- <h2>🎨 이미지 생성 <small>한국형 AI 이미지 · 한국 인물·배경 · 영문 텍스트 · Qwen-Image-2512</small></h2>
381
- </div>
382
- <div class="img-examples">
383
- <button class="img-ex" data-p="전남광주 통합특별시 출범 기념 포스터, 한국 시민들이 함께 모인 장면, 영문 제목 'Better Together', 밝고 희망찬">🎌 출범 포스터</button>
384
- <button class="img-ex" data-p="보성 녹차밭 관광 포스터, 한국 전통 정취, 영문 문구 'Green Healing Tour', 청량하고 시원한">🍃 관광 홍보</button>
385
- <button class="img-ex" data-p="민원 안내 인포그래픽, 깔끔한 한국 행정 디자인, 영문 제목 'Civil Service Guide', 아이콘">📋 민원 안내</button>
386
- <button class="img-ex" data-p="전남 청정 농수산물 홍보, 한국 농촌 배경, 영문 문구 'Fresh Local Food', 풍성한">🌾 특산물</button>
387
- </div>
388
- <div class="img-opts">
389
- <label class="img-opt-label">📐 비율
390
- <select id="img-ratio">
391
- <option value="1:1" selected>⬜ 정사각형 1:1</option>
392
- <option value="3:4">📄 세로 3:4 (포스터)</option>
393
- <option value="9:16">📱 세로 9:16 (모바일)</option>
394
- <option value="4:3">🖼️ 가로 4:3</option>
395
- <option value="16:9">🖥️ 가로 16:9 (배너)</option>
396
- </select>
397
- </label>
398
- </div>
399
- <div class="img-input-row">
400
- <textarea id="img-prompt" rows="2" placeholder="원하는 이미지를 설명하세요 (예: 여수 밤바다 야경, 영문 문구 'Visit Yeosu')"></textarea>
401
- <button id="img-gen-btn">🎨 생성</button>
402
- </div>
403
- <div id="img-status" class="img-status" hidden></div>
404
- <div id="img-result" class="img-result"></div>
405
- <div class="img-foot">⚖️ AI 생성 이미지 · 공식 행정자료 아님 · 상업적 이용 시 별도 검토</div>
406
- </div>
407
- </section>
408
-
409
- <!-- ===== 🎓 AI 교육 (AI 시민 대학) ===== -->
410
- <section id="view-edu" hidden>
411
- <div class="edu-wrap">
412
- <div class="edu-head">
413
- <h2>🎓 AI 시민 대학 <small>AI 선생님에게 배우고 바로 실습하세요 · 누구나 무료</small></h2>
414
- </div>
415
- <div class="edu-cat-title">📱 JGOS 100% 활용</div>
416
- <div class="edu-cards">
417
- <button class="edu-card" data-q="JGOS에서 민원을 어떻게 물어보나요? 처음 쓰는 사람도 알 수 있게 쉽게 알려주세요." data-go="chat">① 민원 물어보기</button>
418
- <button class="edu-card" data-q="JGOS 무료 오피스로 한글(HWP) 문서를 편집하고 저장하는 법을 알려주세요." data-go="office">② HWP 편집</button>
419
- <button class="edu-card" data-q="JGOS 이미지 생성 기능 사용법과 좋은 설명(프롬프트) 쓰는 법을 알려주세요." data-go="image">③ 이미지 생성</button>
420
- <button class="edu-card" data-q="JGOS에 PDF나 사진 파일을 올려서 내용을 분석하는 방법을 알려주세요." data-go="chat">④ 파일 분석</button>
421
- </div>
422
- <div class="edu-cat-title">🤖 AI 기본 소양</div>
423
- <div class="edu-cards">
424
- <button class="edu-card" data-q="AI가 무엇인지 어르신도 이해하기 쉽게 비유를 들어 설명해주세요.">⑤ AI란 무엇?</button>
425
- <button class="edu-card" data-q="AI에게 질문을 잘 하는 방법(프롬프트)을 쉬운 예시와 함께 알려주세요.">⑥ 질문 잘하기</button>
426
- <button class="edu-card" data-q="AI가 만든 가짜 정보(환각)를 구별하고 조심하는 방법을 알려주세요.">⑦ 가짜정보 판별</button>
427
- <button class="edu-card" data-q="AI를 사용할 때 내 개인정보를 안전하게 지키는 방법을 알려주세요.">⑧ 개인정보 보호</button>
428
- </div>
429
- <div class="edu-cat-title">🌱 생활 맞춤</div>
430
- <div class="edu-cards">
431
- <button class="edu-card" data-q="컴퓨터가 익숙하지 않은 어르신을 위해 AI를 처음 사용하는 법을 아주 쉽고 천천히 알려주세요.">⑨ 어르신 첫걸음</button>
432
- <button class="edu-card" data-q="소상공인이 AI로 가게 홍보물과 안내 문서를 만드는 방법을 알려주세요.">⑩ 소상공인 홍보</button>
433
- <button class="edu-card" data-q="학생이 AI를 공부와 학습에 올바르고 똑똑하게 활용하는 방법을 알려주세요.">⑪ 학생 학습</button>
434
- <button class="edu-card" data-q="농어민이 AI로 농수산물 홍보·판매와 영농 정보를 활용하는 방법을 알려주세요.">⑫ 농어민 활용</button>
435
- </div>
436
- <div class="edu-teacher">
437
- <div class="edu-teacher-head">🧑‍🏫 AI 선생님 — 무엇이든 편하게 물어보세요</div>
438
- <div id="edu-messages" class="edu-messages"></div>
439
- <div id="edu-goto" class="edu-goto" hidden></div>
440
- <div class="edu-input-row">
441
- <textarea id="edu-input" rows="1" placeholder="예: AI가 뭐예요? / 프롬프트가 뭔가요?"></textarea>
442
- <button id="edu-send">질문</button>
443
- </div>
444
- </div>
445
- <div class="edu-foot">🎓 전남광주 통합특별시 AI 시민 대학 · 모든 시민 무료 · 위 강의를 누르면 AI 선생님이 설명해 드려요</div>
446
- </div>
447
- </section>
448
-
449
- <!-- ===== 🏛️ 행정 AX 데이터 통합 (테스트 데모) ===== -->
450
- <section id="view-ax" hidden>
451
- <div class="ax-container">
452
- <div class="ax-header">
453
- <h2>🏛️ 행정 AX 데이터 통합 — 테스트 데모</h2>
454
- <p class="ax-desc">이종 파일 포맷·서식의 행정 데이터를 자동으로 인식·정규화·통합합니다</p>
455
- </div>
456
-
457
- <!-- Demo 1: 이종 Excel 통합 -->
458
- <div class="ax-demo-card">
459
- <div class="ax-demo-header">
460
- <span class="ax-demo-badge">Demo 1</span>
461
- <h3>📊 이종 Excel 자동 통합</h3>
462
- <p>27개 지자체가 제각각 다른 서식으로 제출한 Excel을 자동으로 표준화·통합합니다</p>
463
- </div>
464
- <div class="ax-demo-files">
465
- <div class="ax-files-label">📁 예제 파일 (클릭하여 미리보기)</div>
466
- <div class="ax-file-icons" id="ax-excel-demos"><!-- JS로 채움 --></div>
467
- </div>
468
- <div class="ax-upload-zone" id="ax-excel-drop">
469
- <div class="ax-upload-inner">
470
- <span class="ax-upload-icon">📤</span>
471
- <div>Excel/CSV 파일을 여기에 드래그하거나 클릭하세요</div>
472
- <div class="ax-upload-hint">XLSX, XLS, CSV — 여러 파일 동시 업로드 가능</div>
473
- </div>
474
- <input type="file" id="ax-excel-input" hidden multiple accept=".xlsx,.xls,.csv">
475
- </div>
476
- <div class="ax-actions">
477
- <button class="ax-btn ax-btn-primary" id="ax-excel-run" disabled>
478
- <span>⚡</span> 통합 실행
479
- </button>
480
- <span class="ax-file-count" id="ax-excel-count"></span>
481
- </div>
482
- <div class="ax-result-area" id="ax-excel-result" hidden></div>
483
- </div>
484
-
485
- <!-- Demo 2: 이종 포맷 통합 -->
486
- <div class="ax-demo-card">
487
- <div class="ax-demo-header">
488
- <span class="ax-demo-badge ax-demo-badge-2">Demo 2</span>
489
- <h3>🗂️ 이종 포맷 자동 통합</h3>
490
- <p>HWP, XLSX, CSV, PPTX, DOCX, PDF — 7가지 다른 포맷의 데이터를 하나의 표로 통합합니다</p>
491
- </div>
492
- <div class="ax-demo-files">
493
- <div class="ax-files-label">📁 예제 파일 7종 (클릭하여 미리보기)</div>
494
- <div class="ax-file-icons" id="ax-format-demos"><!-- JS로 채움 --></div>
495
- </div>
496
- <div class="ax-upload-zone" id="ax-format-drop">
497
- <div class="ax-upload-inner">
498
- <span class="ax-upload-icon">📤</span>
499
- <div>이종 포맷 파일을 여기에 드래그하거나 클릭하세요</div>
500
- <div class="ax-upload-hint">HWPX, XLSX, CSV, PPTX, DOCX, PDF — 혼합 업로드 가능</div>
501
- </div>
502
- <input type="file" id="ax-format-input" hidden multiple accept=".hwp,.hwpx,.xlsx,.xls,.csv,.docx,.pptx,.pdf">
503
- </div>
504
- <div class="ax-actions">
505
- <button class="ax-btn ax-btn-primary ax-btn-2" id="ax-format-run" disabled>
506
- <span>⚡</span> 통합 실행
507
- </button>
508
- <span class="ax-file-count" id="ax-format-count"></span>
509
- </div>
510
- <div class="ax-result-area" id="ax-format-result" hidden></div>
511
- </div>
512
- </div>
513
-
514
- <!-- 파일 미리보기 모달 -->
515
- <div id="ax-modal" class="ax-modal-overlay" hidden>
516
- <div class="ax-modal-box">
517
- <div class="ax-modal-header">
518
- <span id="ax-modal-title">파일 미리보기</span>
519
- <button class="ax-modal-close" id="ax-modal-close">✕</button>
520
- </div>
521
- <div class="ax-modal-body" id="ax-modal-body">
522
- <div class="ax-loading">⏳ 불러오는 중...</div>
523
- </div>
524
- </div>
525
- </div>
526
- </section>
527
- </main>
528
-
529
- <!-- 모바일 사이드바 백드롭 -->
530
- <div id="sidebar-backdrop" hidden></div>
531
- </div>
532
-
533
- <div id="drag-overlay" hidden>
534
- <div class="drop-card">
535
- 📂 여기에 파일을 놓으세요
536
- <small>HWP · HWPX · PDF · DOCX · PPTX · XLSX · CSV · 이미지<br>(ESC 또는 클릭으로 닫기)</small>
537
- </div>
538
- </div>
539
-
540
- <script src="/static/jgos_app_v611.js?v=612"></script>
541
-
542
- <script>
543
- /* JGOS AX 미리보기 — 인라인 (캐시 우회, v611-INLINE) */
544
- window.axPreviewDemo = async function(filename, label){
545
- var modal=document.getElementById("ax-modal");
546
- var body=document.getElementById("ax-modal-body");
547
- var title=document.getElementById("ax-modal-title");
548
- if(!modal||!body)return;
549
- if(title)title.textContent="\uD83D\uDCC4 "+label+" \u2014 \uBBF8\uB9AC\uBCF4\uAE30";
550
- body.innerHTML='<div class="ax-loading">\u23F3 \uBD88\uB7EC\uC624\uB294 \uC911... [INLINE]</div>';
551
- modal.hidden=false;
552
- try{
553
- var r=await fetch("/api/demo/preview/"+encodeURIComponent(filename)+"?t="+Date.now());
554
- if(!r.ok){body.innerHTML="<p style=\'color:#b91c1c\'>\uC11C\uBC84 \uC624\uB958 ("+r.status+")</p>";return;}
555
- var d=await r.json();
556
- body.innerHTML=(d.rows>0)?(d.html||"<p>\uBE48 \uACB0\uACFC</p>"):"<p style=\'color:#92400e\'>\u26A0\uFE0F \uD30C\uC2F1 \uC2E4\uD328</p>";
557
- }catch(e){
558
- body.innerHTML="<p style=\'color:red\'>\uC624\uB958: "+(e&&e.message?e.message:e)+"</p>";
559
- }
560
- };
561
- /* 칩 onclick 재바인딩 (외부 js가 이미 그렸어도 인라인 함수로 연결) */
562
- (function(){
563
- function rebind(){
564
- document.querySelectorAll(".ax-file-chip").forEach(function(chip){
565
- chip.onclick=function(){ window.axPreviewDemo(chip.dataset.demo, chip.dataset.label); };
566
- });
567
- }
568
- if(document.readyState!=="loading")setTimeout(rebind,300);
569
- else document.addEventListener("DOMContentLoaded",function(){setTimeout(rebind,300);});
570
- // 탭 전환 후에도 재바인딩
571
- document.addEventListener("click",function(e){
572
- var t=e.target.closest&&e.target.closest('[data-view="ax"]');
573
- if(t)setTimeout(rebind,400);
574
- });
575
- })();
576
- console.log("[JGOS] AX inline preview v611-INLINE loaded");
577
- </script>
578
-
579
-
580
- <script>
581
- /* JGOS AX 예제 바로 실행 버튼 — DEMO-RUN-v1 */
582
- (function(){
583
- async function runDemoMerge(btn, resultId, demoType){
584
- var result=document.getElementById(resultId);
585
- var old=btn.innerHTML; btn.disabled=true; btn.innerHTML="\u23F3 \uD1B5\uD569 \uC911...";
586
- if(result){result.hidden=false;result.innerHTML='<div class="ax-loading">\u23F3 \uC608\uC81C \uD1B5\uD569 \uC911...</div>';}
587
- try{
588
- var r=await fetch("/api/demo/merge/"+demoType+"?t="+Date.now());
589
- var d=await r.json();
590
- if(result){
591
- 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("");
592
- result.innerHTML='<div class="ax-source-list">'+src+'</div>'+(d.html||"");
593
- }
594
- }catch(e){if(result)result.innerHTML="<p style=\'color:red\'>\uC624\uB958: "+(e&&e.message?e.message:e)+"</p>";}
595
- btn.disabled=false; btn.innerHTML=old;
596
- }
597
- function addBtn(runBtnId, resultId, demoType){
598
- var runBtn=document.getElementById(runBtnId);
599
- if(!runBtn) return;
600
- if(document.getElementById(runBtnId+"-demo")) return;
601
- var btn=document.createElement("button");
602
- btn.id=runBtnId+"-demo";
603
- btn.className=runBtn.className;
604
- btn.style.background="#0d7377";
605
- btn.style.marginLeft="8px";
606
- btn.innerHTML="\uD83D\uDCC2 \uC608\uC81C\uB85C \uBC14\uB85C \uD1B5\uD569";
607
- runBtn.parentNode.insertBefore(btn, runBtn.nextSibling);
608
- btn.onclick=function(){ runDemoMerge(btn, resultId, demoType); };
609
- }
610
- function setup(){
611
- addBtn("ax-excel-run","ax-excel-result","excel");
612
- addBtn("ax-format-run","ax-format-result","formats");
613
- }
614
- if(document.readyState!=="loading") setTimeout(setup,500);
615
- else document.addEventListener("DOMContentLoaded",function(){setTimeout(setup,500);});
616
- document.addEventListener("click",function(e){
617
- var t=e.target.closest&&e.target.closest('[data-view="ax"]');
618
- if(t) setTimeout(setup,500);
619
- });
620
- console.log("[JGOS] AX demo-run buttons v1 loaded");
621
- })();
622
- </script>
623
-
624
-
625
- <script>
626
- /* AX-INTEGRATE-v2: 통합 결과 표시 + XLSX 다운로드 */
627
- (function(){
628
- function chip(s){return '<span class="ax-source-chip">'+(s["\uD3EC\uB9F7"]||"")+" "+(s["\uD30C\uC77C"]||"")+" ("+(s["\uAC74\uC218"]||0)+"\uAC74)</span>";}
629
- window.__axShow=function(resultId,d){
630
- var result=document.getElementById(resultId);
631
- if(!result)return;
632
- result.hidden=false;
633
- var src=(d.sources||[]).map(chip).join("");
634
- result.innerHTML='<div class="ax-source-list">'+src+'</div>'+(d.html||"");
635
- if(d.records&&d.records.length){
636
- var dl=document.createElement("button");
637
- 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";
638
- dl.textContent="\uD83D\uDCE5 \uD1B5\uD569\uBCF8 XLSX \uB2E4\uC6B4\uB85C\uB4DC ("+d.records.length+"\uAC74)";
639
- dl.onclick=async function(){
640
- var o=dl.textContent; dl.disabled=true; dl.textContent="\u23F3 \uC0DD\uC131 \uC911...";
641
- try{
642
- 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"})});
643
- if(!rr.ok)throw new Error("\uC11C\uBC84 "+rr.status);
644
- var b=await rr.blob(); var u=URL.createObjectURL(b);
645
- var a=document.createElement("a"); a.href=u; a.download="JGOS_\uD589\uC815AX_\uD1B5\uD569\uACB0\uACFC.xlsx";
646
- document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(u);
647
- }catch(e){alert("\uB2E4\uC6B4\uB85C\uB4DC \uC2E4\uD328: "+(e.message||e));}
648
- dl.disabled=false; dl.textContent=o;
649
- };
650
- result.appendChild(dl);
651
- }
652
- };
653
- async function exampleMerge(btn,resultId,type){
654
- var o=btn.innerHTML; btn.disabled=true; btn.innerHTML="\u23F3 \uD1B5\uD569 \uC911...";
655
- var result=document.getElementById(resultId);
656
- if(result){result.hidden=false;result.innerHTML='<div class="ax-loading">\u23F3 \uC608\uC81C \uD1B5\uD569 \uC911...</div>';}
657
- try{var r=await fetch("/api/demo/merge/"+type+"?t="+Date.now());var d=await r.json();window.__axShow(resultId,d);}
658
- catch(e){if(result)result.innerHTML="<p style=\'color:red\'>\uC624\uB958: "+(e.message||e)+"</p>";}
659
- btn.disabled=false; btn.innerHTML=o;
660
- }
661
- async function uploadMerge(btn,inputId,resultId,apiPath){
662
- var input=document.getElementById(inputId);
663
- if(!input||!input.files||!input.files.length){alert("\uD30C\uC77C\uC744 \uC120\uD0DD\uD558\uC138\uC694");return;}
664
- var o=btn.innerHTML; btn.disabled=true; btn.innerHTML="\u23F3 \uD1B5\uD569 \uC911...";
665
- var result=document.getElementById(resultId);
666
- if(result){result.hidden=false;result.innerHTML='<div class="ax-loading">\u23F3 \uD1B5\uD569 \uC911...</div>';}
667
- var fd=new FormData(); for(var i=0;i<input.files.length;i++)fd.append("files",input.files[i]);
668
- try{var r=await fetch(apiPath,{method:"POST",body:fd});var d=await r.json();window.__axShow(resultId,d);}
669
- catch(e){if(result)result.innerHTML="<p style=\'color:red\'>\uC624\uB958: "+(e.message||e)+"</p>";}
670
- btn.disabled=false; btn.innerHTML=o;
671
- }
672
- function setup(){
673
- var er=document.getElementById("ax-excel-run");
674
- if(er)er.onclick=function(){uploadMerge(er,"ax-excel-input","ax-excel-result","/api/excel/merge");};
675
- var fr=document.getElementById("ax-format-run");
676
- if(fr)fr.onclick=function(){uploadMerge(fr,"ax-format-input","ax-format-result","/api/files/merge-formats");};
677
- [["ax-excel-run","ax-excel-result","excel"],["ax-format-run","ax-format-result","formats"]].forEach(function(x){
678
- var run=document.getElementById(x[0]); if(!run)return;
679
- var id=x[0]+"-demo"; var b=document.getElementById(id);
680
- 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);}
681
- b.onclick=function(){exampleMerge(b,x[1],x[2]);};
682
- });
683
- }
684
- if(document.readyState!=="loading")setTimeout(setup,600);
685
- else document.addEventListener("DOMContentLoaded",function(){setTimeout(setup,600);});
686
- document.addEventListener("click",function(e){var t=e.target.closest&&e.target.closest('[data-view="ax"]');if(t)setTimeout(setup,600);});
687
- console.log("[JGOS] AX integrate+download v2 loaded");
688
- })();
689
- </script>
690
-
691
-
692
- <script id="jgos-home-js">
693
- /* 서비스 첫화면 + 건축도면 뷰 — 기존 showView/switchTab 을 감싸서 확장 (원본 JS 무수정) */
694
- (function(){
695
- var home=document.getElementById('view-home');
696
- var build=document.getElementById('view-building');
697
- var saju=document.getElementById('view-saju');
698
- var tex=document.getElementById('view-texray');
699
- var texf=document.getElementById('texray-frame');var texLoaded=false;
700
- var sajuf=document.getElementById('saju-frame');var sajuLoaded=false;
701
- var frame=document.getElementById('building-frame');
702
- var chat=document.getElementById('view-chat');
703
- var loaded=false;
704
- function paint(name){
705
- home.hidden = name!=='home';
706
- build.hidden = name!=='building';
707
- saju.hidden = name!=='saju';
708
- tex.hidden = name!=='texray';
709
- if(name==='texray' && !texLoaded){ texf.src='https://ginigen-TeXray.hf.space/'; texLoaded=true; }
710
- if(name==='saju' && !sajuLoaded){ sajuf.src='https://ginigen-SAJU.hf.space/'; sajuLoaded=true; }
711
- if(name==='building' && !loaded){ frame.src='https://VIDraft-building.hf.space/'; loaded=true; }
712
- if(name!=='chat'){ if(chat) chat.style.display='none'; }
713
- }
714
- function go(name){
715
- document.querySelectorAll('.top-tab').forEach(function(t){
716
- t.classList.toggle('active', t.dataset.view===name);
717
- });
718
- if(typeof showView==='function') showView(['home','building','saju','texray'].indexOf(name)>=0 ? '__none__' : name);
719
- paint(name);
720
- }
721
- window.jgosGo = go;
722
- document.querySelectorAll('.top-tab').forEach(function(t){
723
- t.addEventListener('click', function(){ go(t.dataset.view); });
724
- });
725
- document.addEventListener('click', function(e){
726
- var c=e.target.closest('.svc-card, .svc-hero');
727
- if(!c || c.classList.contains('soon')) return;
728
- var v=c.dataset.view; if(!v) return;
729
- go(v);
730
- if(v==='chat' && c.dataset.q){
731
- var box=document.querySelector('#composer-input, #input, textarea');
732
- if(box){ box.value=c.dataset.q; box.focus(); }
733
- }
734
- });
735
- go('home'); /* 첫 화면 = 서비스 */
736
- })();
737
- </script>
738
- </body>
739
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="ko">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
6
+ <meta name="theme-color" content="#0052a4">
7
+ <title>[제안 테스트] JGOS · 행정 AI 서비스 특화 모델</title>
8
+ <link rel="preconnect" href="https://fonts.googleapis.com">
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link rel="stylesheet" href="/static/style.css?v=20260612a">
11
+ <script src="https://cdn.jsdelivr.net/npm/marked@14.1.3/marked.min.js"></script>
12
+ <script src="https://cdn.jsdelivr.net/npm/dompurify@3.1.7/dist/purify.min.js"></script>
13
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/styles/github.min.css">
14
+ <script src="https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/highlight.min.js"></script>
15
+ <style id="ax-modal-fix">#ax-modal[hidden]{display:none !important;}</style>
16
+
17
+
18
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css">
19
+ <style id="jgos-apple-css">
20
+ :root{
21
+ --bg:#F5F5F7; --surface:#FFFFFF; --surface-2:rgba(255,255,255,.72);
22
+ --ink:#1D1D1F; --ink-2:#4B4F55; --ink-3:#86868B; --hair:rgba(0,0,0,.09);
23
+ --blue:#0071E3; --green:#00875A; --amber:#8A6414;
24
+ --r-lg:22px; --r-md:16px;
25
+ --sh:0 1px 2px rgba(0,0,0,.04), 0 12px 32px -20px rgba(0,0,0,.30);
26
+ --sh-hi:0 2px 6px rgba(0,0,0,.06), 0 24px 48px -24px rgba(0,0,0,.34);
27
+ }
28
+ @media (prefers-color-scheme: dark){
29
+ :root{
30
+ --bg:#000000; --surface:#1C1C1E; --surface-2:rgba(28,28,30,.72);
31
+ --ink:#F5F5F7; --ink-2:#C7C9CC; --ink-3:#8E8E93; --hair:rgba(255,255,255,.12);
32
+ --blue:#0A84FF; --green:#30D158; --amber:#FFD60A;
33
+ --sh:0 1px 2px rgba(0,0,0,.5), 0 12px 32px -20px rgba(0,0,0,.9);
34
+ --sh-hi:0 2px 8px rgba(0,0,0,.6), 0 24px 56px -26px rgba(0,0,0,1);
35
+ }
36
+ }
37
+ body,#app,#main{background:var(--bg)!important;color:var(--ink)!important;
38
+ font-family:"Pretendard Variable",Pretendard,-apple-system,BlinkMacSystemFont,"Apple SD Gothic Neo",system-ui,sans-serif!important;
39
+ -webkit-font-smoothing:antialiased;letter-spacing:-.011em}
40
+
41
+ #topbar{background:var(--surface-2)!important;backdrop-filter:saturate(180%) blur(20px);
42
+ -webkit-backdrop-filter:saturate(180%) blur(20px);
43
+ border-bottom:1px solid var(--hair)!important;box-shadow:none!important}
44
+ .title-main{font-size:17px!important;font-weight:650!important;letter-spacing:-.02em!important;color:var(--ink)!important}
45
+ .title-sub{font-size:12.5px!important;color:var(--ink-3)!important;font-weight:400!important}
46
+ .top-tabs{gap:2px!important}
47
+ .top-tab{background:transparent!important;border:0!important;color:var(--ink-2)!important;
48
+ font-size:13.5px!important;font-weight:500!important;padding:7px 13px!important;border-radius:980px!important;
49
+ transition:background .18s,color .18s}
50
+ .top-tab:hover{background:rgba(127,127,127,.12)!important;color:var(--ink)!important}
51
+ .top-tab.active{background:var(--ink)!important;color:var(--bg)!important;font-weight:600!important}
52
+ #sidebar{background:var(--surface-2)!important;backdrop-filter:blur(20px);border-right:1px solid var(--hair)!important}
53
+ .status-pill{border-radius:980px!important;font-size:11.5px!important;color:var(--ink-3)!important;background:transparent!important;border:1px solid var(--hair)!important}
54
+
55
+ #view-home{padding:0 0 88px;overflow-y:auto;background:var(--bg)}
56
+ .svc-wrap{max-width:1040px;margin:0 auto;padding:0 22px}
57
+ .svc-hero{position:relative;margin:44px 0 40px;padding:64px 48px;border-radius:var(--r-lg);
58
+ background:linear-gradient(158deg,#0A2540 0%,#123A63 45%,#0071E3 130%);color:#fff;cursor:pointer;
59
+ overflow:hidden;box-shadow:var(--sh);transition:transform .3s cubic-bezier(.2,.8,.2,1),box-shadow .3s}
60
+ .svc-hero::after{content:"";position:absolute;inset:auto -18% -62% auto;width:520px;height:520px;border-radius:50%;
61
+ background:radial-gradient(circle,rgba(255,255,255,.16),transparent 66%);pointer-events:none}
62
+ .svc-hero:hover{transform:translateY(-3px);box-shadow:var(--sh-hi)}
63
+ .svc-hero .eyebrow{font-size:12.5px;letter-spacing:.02em;font-weight:600;color:rgba(255,255,255,.72)}
64
+ .svc-hero h2{margin:14px 0 12px;font-size:clamp(32px,5vw,52px);font-weight:700;letter-spacing:-.035em;line-height:1.08}
65
+ .svc-hero p{margin:0;font-size:17px;line-height:1.62;color:rgba(255,255,255,.88);max-width:34em;font-weight:400}
66
+ .svc-hero .go{display:inline-flex;align-items:center;gap:7px;margin-top:26px;background:#fff;color:#0A2540;
67
+ border-radius:980px;padding:12px 24px;font-weight:600;font-size:15px;letter-spacing:-.01em}
68
+
69
+ .svc-group{margin-top:52px}
70
+ .svc-group h3{font-size:26px;font-weight:680;letter-spacing:-.025em;margin:0 0 20px;padding:0;border:0;color:var(--ink)}
71
+ .svc-grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fill,minmax(238px,1fr))}
72
+ .svc-card{background:var(--surface);border:0;border-radius:var(--r-md);padding:24px 22px 20px;
73
+ display:flex;flex-direction:column;gap:8px;cursor:pointer;box-shadow:var(--sh);
74
+ transition:transform .28s cubic-bezier(.2,.8,.2,1),box-shadow .28s}
75
+ .svc-card:hover,.svc-card:focus-visible{transform:translateY(-4px);box-shadow:var(--sh-hi);outline:none}
76
+ .svc-card .row{display:flex;align-items:flex-start;gap:9px}
77
+ .svc-card h4{margin:0;font-size:17px;font-weight:620;letter-spacing:-.02em;line-height:1.35;color:var(--ink)}
78
+ .svc-card p{margin:0;font-size:13.5px;line-height:1.62;color:var(--ink-3);font-weight:400}
79
+ .svc-st{flex:none;margin-left:auto;font-size:11px;font-weight:600;padding:3px 9px;border-radius:980px;white-space:nowrap}
80
+ .st-live{background:rgba(0,135,90,.11);color:var(--green)}
81
+ .st-soon{background:rgba(138,100,20,.12);color:var(--amber)}
82
+ .svc-card.soon{cursor:default;box-shadow:none;background:transparent;border:1px solid var(--hair)}
83
+ .svc-card.soon:hover{transform:none;box-shadow:none}
84
+
85
+ #view-saju{padding:0 0 88px;overflow-y:auto;background:var(--bg)}
86
+ .saju-wrap{max-width:880px;margin:0 auto;padding:52px 22px 0}
87
+ .saju-head h2{font-size:clamp(30px,4.4vw,44px);font-weight:700;letter-spacing:-.035em;margin:0 0 10px}
88
+ .saju-head p{margin:0 0 30px;color:var(--ink-3);font-size:16px;line-height:1.6}
89
+ .saju-form{background:var(--surface);border-radius:var(--r-md);padding:22px;box-shadow:var(--sh)}
90
+ .saju-row{display:flex;flex-wrap:wrap;gap:14px;align-items:flex-end}
91
+ .saju-row label{display:flex;flex-direction:column;gap:7px;font-size:12.5px;font-weight:600;color:var(--ink-3);flex:1 1 150px}
92
+ .saju-row input,.saju-row select{font-family:inherit;font-size:15px;color:var(--ink);background:var(--bg);
93
+ border:1px solid var(--hair);border-radius:11px;padding:11px 13px;font-weight:450;-webkit-appearance:none;appearance:none}
94
+ .saju-row input:focus,.saju-row select:focus{outline:none;border-color:var(--blue);box-shadow:0 0 0 3.5px rgba(0,113,227,.16)}
95
+ #sj-go{flex:0 0 auto;background:var(--blue);color:#fff;border:0;border-radius:980px;padding:12px 26px;
96
+ font-family:inherit;font-size:15px;font-weight:600;cursor:pointer;letter-spacing:-.01em;transition:opacity .18s}
97
+ #sj-go:hover{opacity:.86}
98
+ #sj-go:disabled{opacity:.45;cursor:default}
99
+ .saju-msg{margin-top:18px;padding:14px 16px;border-radius:12px;background:var(--surface);color:var(--ink-2);font-size:14px;box-shadow:var(--sh)}
100
+ .saju-result{margin-top:26px;display:flex;flex-direction:column;gap:16px}
101
+ .sj-card{background:var(--surface);border-radius:var(--r-md);padding:26px 24px;box-shadow:var(--sh)}
102
+ .sj-card h3{margin:0 0 4px;font-size:13px;font-weight:600;color:var(--ink-3)}
103
+ .sj-pillars{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-top:16px}
104
+ .sj-p{text-align:center;background:var(--bg);border-radius:13px;padding:18px 8px}
105
+ .sj-p .lab{font-size:11.5px;color:var(--ink-3);font-weight:600}
106
+ .sj-p .han{font-size:clamp(26px,4.6vw,38px);font-weight:600;letter-spacing:-.02em;margin:8px 0 2px;line-height:1.1}
107
+ .sj-p .kor{font-size:13px;color:var(--ink-2)}
108
+ .sj-meta{display:flex;flex-wrap:wrap;gap:9px;margin-top:18px}
109
+ .sj-tag{background:var(--bg);border-radius:980px;padding:7px 14px;font-size:13px;color:var(--ink-2);font-weight:500}
110
+ .sj-tag b{color:var(--ink);font-weight:640}
111
+ .sj-bars{display:flex;flex-direction:column;gap:11px;margin-top:16px}
112
+ .sj-bar{display:grid;grid-template-columns:34px 1fr 46px;align-items:center;gap:12px;font-size:13.5px}
113
+ .sj-bar .n{font-weight:620;color:var(--ink)}
114
+ .sj-bar .t{height:8px;border-radius:980px;background:rgba(127,127,127,.16);overflow:hidden}
115
+ .sj-bar .f{height:100%;border-radius:980px;background:var(--blue);transition:width .7s cubic-bezier(.2,.8,.2,1)}
116
+ .sj-bar .v{text-align:right;color:var(--ink-3);font-variant-numeric:tabular-nums}
117
+ .saju-note{margin:26px 0 0;font-size:12.5px;color:var(--ink-3);text-align:center}
118
+
119
+ #view-saju,#view-texray,#view-building{padding:0 0 60px;overflow-y:auto;background:var(--bg)}
120
+ .emb-wrap{max-width:1040px;margin:0 auto;padding:44px 22px 0}
121
+ .emb-head h2{font-size:clamp(28px,4.2vw,40px);font-weight:700;letter-spacing:-.035em;margin:0 0 10px}
122
+ .emb-head p{margin:0 0 26px;color:var(--ink-3);font-size:16px;line-height:1.62;max-width:56ch}
123
+ .emb-frame{background:var(--surface);border-radius:var(--r-md);box-shadow:var(--sh);overflow:hidden}
124
+ .emb-frame iframe{width:100%;height:min(78vh,860px);border:0;display:block;background:var(--surface)}
125
+ .emb-note{margin:18px 0 0;font-size:12.5px;color:var(--ink-3);text-align:center}
126
+ @media(max-width:720px){.svc-hero{padding:44px 26px}.sj-pillars{grid-template-columns:repeat(2,1fr)}}
127
+ @media (prefers-reduced-motion:reduce){*{transition:none!important}}
128
+ </style>
129
+ </head>
130
+ <body>
131
+ <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>
132
+ <div id="app">
133
+
134
+ <!-- ===== 모바일 햄버거 ===== -->
135
+ <button id="hamburger-btn" aria-label="메뉴 열기">
136
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
137
+ <line x1="3" y1="6" x2="21" y2="6"/>
138
+ <line x1="3" y1="12" x2="21" y2="12"/>
139
+ <line x1="3" y1="18" x2="21" y2="18"/>
140
+ </svg>
141
+ </button>
142
+
143
+ <!-- ===== 사이드바 ===== -->
144
+ <aside id="sidebar">
145
+ <div class="sidebar-head">
146
+ <div class="brand-top">
147
+ <div class="emblem">🏛️</div>
148
+ <div>
149
+ <div class="brand-title">전남광주 통합특별시</div>
150
+ <div class="brand-sub">시민의 AI</div>
151
+ </div>
152
+ </div>
153
+ <button id="new-chat-btn" title="새 대화">+ 새 상담</button>
154
+ </div>
155
+ <div class="sidebar-section-label">최근 상담</div>
156
+ <ul id="chat-list"></ul>
157
+ <div class="sidebar-foot">
158
+ <div class="brand-small">
159
+ <strong>Powered by @비드래프트</strong>
160
+ <small>JGOS v0.1 preview</small>
161
+ </div>
162
+ </div>
163
+ </aside>
164
+
165
+ <main id="main">
166
+ <!-- ===== 상단 시민포털 헤더 ===== -->
167
+ <header id="topbar">
168
+ <div class="topbar-left">
169
+ <button id="sidebar-toggle" class="mobile-only" aria-label="사이드바">☰</button>
170
+ <div class="title-block">
171
+ <div class="title-main">🏛️ 전남광주 통합특별시 · 시민의 AI</div>
172
+ <div class="title-sub">행정 특화 언어모델 <b>JGOS</b> 탑재 · 행정·법령·관광·민원 안내</div>
173
+ </div>
174
+ </div>
175
+ <nav class="top-tabs">
176
+ <button class="top-tab active" data-view="home">🏠 서비스</button>
177
+ <button class="top-tab" data-view="chat">💬 JGOS 챗봇</button>
178
+ <button class="top-tab" data-view="building">🏗️ 건축 도면</button>
179
+ <button class="top-tab" data-view="office">📑 무료 오피스</button>
180
+ <button class="top-tab" data-view="image">🎨 이미지 생성</button>
181
+ <button class="top-tab" data-view="saju">🔮 사주</button>
182
+ <button class="top-tab" data-view="texray">🔍 AI 글 판별</button>
183
+ <button class="top-tab" data-view="ax">🏛️ 행정 AX(테스트)</button>
184
+ </nav>
185
+ <div class="topbar-right">
186
+ <span class="status-pill" id="status">● 정상</span>
187
+ </div>
188
+ </header>
189
+
190
+ <div id="view-chat">
191
+ <div id="messages-wrap">
192
+ <div id="messages"></div>
193
+
194
+ <!-- ===== 첫 화면 시민포털 (메시지 0건 시 표시) ===== -->
195
+ <div id="portal" class="portal">
196
+ <div class="portal-hero">
197
+ <div class="hero-emblem">🏛️</div>
198
+ <h1 class="hero-title">전남광주 통합특별시민과<br>함께하는 AI <strong>JGOS</strong></h1>
199
+ <p class="hero-sub">행정·민원·법령·관광·교통·문화·통계·산업·농수산 정보를<br>친절하게 안내해 드립니다. 무엇이 궁금하신가요?</p>
200
+ </div>
201
+
202
+ <!-- ===== 방안1: 히어로 파일 드롭존 ===== -->
203
+ <button class="hero-dropzone" id="hero-dropzone" type="button">
204
+ <div class="hd-icon">📎</div>
205
+ <div class="hd-main">파일을 끌어다 놓거나 클릭하세요</div>
206
+ <div class="hd-sub">HWP · 이미지 · PDF · 엑셀 무엇이든 올리면 <strong>바로 분석</strong>해 드립니다</div>
207
+ <div class="hd-badge">🇰🇷 타 AI가 못 읽는 <strong>한글 HWP</strong>도 분석하는 sovereign AI</div>
208
+ <!-- 방안2: 지원 형식 아이콘 띠 -->
209
+ <div class="fmt-strip">
210
+ <span class="fmt hwp">HWP</span><span class="fmt hwp">HWPX</span>
211
+ <span class="fmt pdf">PDF</span><span class="fmt doc">DOCX</span>
212
+ <span class="fmt xls">XLSX</span><span class="fmt ppt">PPTX</span>
213
+ <span class="fmt csv">CSV</span><span class="fmt img">이미지</span>
214
+ <span class="fmt more">+10종</span>
215
+ </div>
216
+ </button>
217
+
218
+ <!-- 8개 카테고리 큰 카드 -->
219
+ <div class="cat-grid">
220
+ <button class="cat-card" data-q="민원 처리 절차와 필요한 서류를 알려주세요.">
221
+ <div class="cat-emoji">📝</div>
222
+ <div class="cat-name">민원</div>
223
+ <div class="cat-desc">절차·서류·전화</div>
224
+ </button>
225
+ <button class="cat-card" data-q="전남광주통합특별법의 주요 조항을 알려주세요.">
226
+ <div class="cat-emoji">📜</div>
227
+ <div class="cat-name">법령</div>
228
+ <div class="cat-desc">특별법·조례</div>
229
+ </button>
230
+ <button class="cat-card" data-q="전남광주 통합특별시 관광 명소를 추천해 주세요.">
231
+ <div class="cat-emoji">🗺️</div>
232
+ <div class="cat-name">관광</div>
233
+ <div class="cat-desc">22 시군 + 5구</div>
234
+ </button>
235
+ <button class="cat-card" data-q="전남광주 통합특별시 교통편을 안내해 주세요.">
236
+ <div class="cat-emoji">🚆</div>
237
+ <div class="cat-name">교통</div>
238
+ <div class="cat-desc">KTX·공항·페리</div>
239
+ </button>
240
+ <button class="cat-card" data-q="전남광주 통합특별시의 농수산 특산품을 알려주세요.">
241
+ <div class="cat-emoji">🌾</div>
242
+ <div class="cat-name">농수산</div>
243
+ <div class="cat-desc">GI 특산·수산물</div>
244
+ </button>
245
+ <button class="cat-card" data-q="전남광주 통합특별시의 주요 산업과 경제 규모를 알려주세요.">
246
+ <div class="cat-emoji">🏭</div>
247
+ <div class="cat-name">산업</div>
248
+ <div class="cat-desc">경제·기업</div>
249
+ </button>
250
+ <button class="cat-card" data-q="전남광주 통합특별시의 인구 통계와 지역 현황을 알려주세요.">
251
+ <div class="cat-emoji">📊</div>
252
+ <div class="cat-name">통계</div>
253
+ <div class="cat-desc">인구·경제</div>
254
+ </button>
255
+ <button class="cat-card" data-attach="true">
256
+ <div class="cat-emoji">📎</div>
257
+ <div class="cat-name">첨부문서</div>
258
+ <div class="cat-desc">HWP·PDF·이미지</div>
259
+ </button>
260
+ </div>
261
+
262
+ <!-- 추천 질문 (자주 묻는) -->
263
+ <div class="quick-section">
264
+ <div class="quick-label">자주 묻는 질문</div>
265
+ <div class="quick-grid">
266
+ <button class="quick-btn" data-q="전남광주 통합특별시장과 광주 5개 구청장, 전남 시장·군수 당선인이 각각 누구인가요?">🏛️ 지자체장 당선인</button>
267
+ <button class="quick-btn" data-q="전남광주(광주·전남) 지역구 국회의원 명단을 알려주세요.">🗳️ 지역구 국회의원</button>
268
+ <button class="quick-btn" data-q="주민등록증 재발급 절차와 필요한 서류는?">📇 주민등록증 재발급</button>
269
+ <button class="quick-btn" data-q="전남광주 통합특별시 인구는?">👥 통합특별시 인구</button>
270
+ <button class="quick-btn" data-q="보성 녹차밭 관광 안내 부탁해.">🍃 보성 녹차밭</button>
271
+ <button class="quick-btn" data-q="전남광주통합특별법 제6조 내용은?">📜 특별법 제6조</button>
272
+ <button class="quick-btn" data-q="전남광주 통합특별시청 대표 전화번호와 부서 안내는?">📞 시청 대표번호</button>
273
+ <button class="quick-btn" data-q="여수에서 가볼 만한 곳 3곳만 추천해.">🏖️ 여수 가볼 곳</button>
274
+ <button class="quick-btn" data-q="5·18 민주화운동 기록관 위치와 관람 안내는?">🏛️ 5·18 기록관</button>
275
+ <button class="quick-btn" data-q="2026년 7월 1일 전남광주 통합특별시 출범의 의미와 일정은?">🎌 7·1 출범</button>
276
+ </div>
277
+ </div>
278
+
279
+ <!-- 신뢰 배지 (첫 화면 only — NIA 본문은 composer footer에서 영구 표시) -->
280
+ <div class="portal-foot">
281
+ <div class="trust-line">
282
+ <span class="trust-badge">🔒 sovereign AI</span>
283
+ <span class="trust-badge">📅 기준일 2026-06-01</span>
284
+ <span class="trust-badge">📚 RAG 21,192 청크</span>
285
+ <span class="trust-badge">⚖️ 정식 행정 안내 아님 · 062-120 확인 권장</span>
286
+ </div>
287
+ </div>
288
+ </div>
289
+ </div>
290
+
291
+ <!-- ===== 입력 영역 ===== -->
292
+ <footer id="composer">
293
+ <div class="warn-bar" id="warn-bar" hidden>
294
+ ✅ 2026년 6월 3일 지방선거 완료 — 민형배 통합특별시장 당선(7월 1일 취임). 단체장·지역구 국회의원 명단 반영 완료.
295
+ </div>
296
+ <div class="attach-row" id="attach-row"></div>
297
+ <div class="input-row">
298
+ <button id="attach-btn" title="파일 첨부 (HWP/HWPX/PDF/DOCX/PPTX/XLSX/XLS/CSV/이미지)" aria-label="파일 첨부">📎</button>
299
+ <button id="web-btn" title="웹검색 — 켜면 네이버·웹에서 최신 정보를 함께 검색합니다" aria-label="웹검색 켜기/끄기" aria-pressed="false">🔍</button>
300
+ <button id="minwon-btn" title="민원 — 켜면 질문을 민원으로 보고 담당 부서·연락처를 찾아드립니다" aria-label="민원 모드 켜기/끄기" aria-pressed="false">📞</button>
301
+ <input type="file" id="file-input" hidden multiple
302
+ accept=".hwp,.hwpx,.pdf,.docx,.pptx,.xlsx,.xls,.csv,.txt,.md,.jpg,.jpeg,.png,.gif,.webp">
303
+ <textarea id="input" rows="1" placeholder="질문을 입력하거나 파일을 첨부하세요 (Shift+Enter 줄바꿈)"></textarea>
304
+ <button id="send-btn" title="전송 (Enter)" aria-label="전송">
305
+ <svg viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>
306
+ </button>
307
+ </div>
308
+
309
+ <!-- ===== NIA K-AI 1위 출처 문구 (항상 표시 — 모든 화면 하단) ===== -->
310
+ <div class="nia-disclaimer">
311
+ 본 모델은 과학기술정보통신부·한국지능정보사회진흥원(NIA) K-AI 리더보드 1위 달성 모델을 기반으로,
312
+ 전남광주 통합특별시 관련 공개정보를 추가 학습·최적화한 한국어 특화 모델입니다.
313
+ 한국어 처리 능력과 한국 문화·사회·행정·전문 분야에 대한 이해를 바탕으로
314
+ 시민 질의에 정확하고 친절하게 응답합니다.
315
+ </div>
316
+ </footer>
317
+ </div><!-- /view-chat -->
318
+
319
+ <!-- ===== 무료 오피스 (HanSoo 엔진 흡수 · same-origin iframe 임베디드) ===== -->
320
+
321
+ <section id="view-home" hidden>
322
+ <div class="svc-wrap">
323
+
324
+ <div class="svc-hero" data-view="chat">
325
+ <div class="eyebrow">가장 먼저 · 무엇이든 물어보세요</div>
326
+ <h2>JGOS 챗봇</h2>
327
+ <p>전입신고부터 재산세 납부 기한까지. 전남광주 통합특별시 행정에 맞춰 만든 우리 시 전용 AI가 24시간 답합니다.</p>
328
+ <span class="go">상담 시작하기 →</span>
329
+ </div>
330
+
331
+ <div class="svc-group">
332
+ <h3>지금 바로 쓰는 서비스</h3>
333
+ <div class="svc-grid">
334
+ <div class="svc-card" data-view="building" tabindex="0"><div class="row"><h4>🏗️ 건축 도면 만들기</h4><span class="svc-st st-live">가동</span></div><p>말로 설명하면 평면도와 도면 파일(DXF)을 만들어 드립니다.</p></div>
335
+ <div class="svc-card" data-view="office" tabindex="0"><div class="row"><h4>📑 무료 오피스</h4><span class="svc-st st-live">가동</span></div><p>한글(HWP)·PDF 문서를 설치 없이 열고 고치고 저장합니다.</p></div>
336
+ <div class="svc-card" data-view="image" tabindex="0"><div class="row"><h4>🎨 이미지 만들기</h4><span class="svc-st st-live">가동</span></div><p>가게 홍보물, 마을 안내문에 쓸 그림을 말로 설명해 만듭니다.</p></div>
337
+ <div class="svc-card" data-view="ax" tabindex="0"><div class="row"><h4>🏛️ 엑셀 자동 통합</h4><span class="svc-st st-live">가동</span></div><p>양식이 제각각인 부서 파일을 하나의 표로 합칩니다.</p></div>
338
+ <div class="svc-card" data-view="chat" data-q="이 파일 내용을 정리해 주세요." tabindex="0"><div class="row"><h4>📎 파일 분석</h4><span class="svc-st st-live">가동</span></div><p>고지서·계약서 사진을 올리면 무슨 내용인지 풀어 설명합니다.</p></div>
339
+ <div class="svc-card" data-view="saju" tabindex="0"><div class="row"><h4>🔮 사주</h4><span class="svc-st st-live">가동</span></div><p>만세력·오행·대운·세운까지 AGI 명리 분석. 순한맛·매운맛 골라 보세요.</p></div>
340
+ <div class="svc-card" data-view="texray" tabindex="0"><div class="row"><h4>🔍 AI 글 판별</h4><span class="svc-st st-live">가동</span></div><p>제출물이 AI로 쓰였는지, 베낀 곳이 있는지 검사합니다.</p></div>
341
+ <div class="svc-card" data-view="chat" data-q="전남광주 통합특별시 관광 명소와 특산품, 교통편을 안내해 주세요." tabindex="0"><div class="row"><h4>🚄 관광·특산·교통</h4><span class="svc-st st-live">가동</span></div><p>명소, 지리적표시 특산품, KTX·공항·페리를 한자리에서.</p></div>
342
+ <div class="svc-card" data-view="chat" data-q="전남광주통합특별법의 주요 조항을 알려주세요." tabindex="0"><div class="row"><h4>⚖️ 특별법·조례</h4><span class="svc-st st-live">가동</span></div><p>통합특별법과 시 조례 내용을 찾아 설명합니다.</p></div>
343
+ <div class="svc-card" data-view="chat" data-q="어려운 행정 용어를 어르신도 알아듣기 쉬운 말로 풀어서 설명해 주세요." tabindex="0"><div class="row"><h4>🧓 쉬운 말로 듣기</h4><span class="svc-st st-live">가동</span></div><p>어려운 행정 용어를 알아듣기 쉬운 말로 바꿔 안내합니다.</p></div>
344
+ </div>
345
+ </div>
346
+
347
+ <div class="svc-group">
348
+ <h3>준비 중인 서비스</h3>
349
+ <div class="svc-grid">
350
+ <div class="svc-card soon"><div class="row"><h4>📄 문서 판독</h4><span class="svc-st st-soon">준비 중</span></div><p>손글씨 서식·진단서를 읽어 표로 정리합니다.</p></div>
351
+ <div class="svc-card soon"><div class="row"><h4>🗣️ 안내 아바타</h4><span class="svc-st st-soon">준비 중</span></div><p>사람 얼굴로 말하며 안내합니다. 글보다 말이 편한 분께.</p></div>
352
+ <div class="svc-card soon"><div class="row"><h4>☎️ AI 전화상담</h4><span class="svc-st st-soon">준비 중</span></div><p>인터넷을 안 쓰셔도 전화 한 통이면 됩니다.</p></div>
353
+ <div class="svc-card soon"><div class="row"><h4>🛡️ 어르신 생활반응</h4><span class="svc-st st-soon">준비 중</span></div><p>카메라 없이 집 안 움직임을 살펴 이상이 길어지면 알립니다.</p></div>
354
+ <div class="svc-card soon"><div class="row"><h4>🌾 영농 상담</h4><span class="svc-st st-soon">준비 중</span></div><p>작물 시기, 판로, 지원 사업을 물어보세요.</p></div>
355
+ <div class="svc-card soon"><div class="row"><h4>🏢 조달·나라장터</h4><span class="svc-st st-soon">준비 중</span></div><p>우리 시 기업이 낼 수 있는 공고를 찾아 드립니다.</p></div>
356
+ <div class="svc-card soon"><div class="row"><h4>💡 특허·지식재산</h4><span class="svc-st st-soon">준비 중</span></div><p>아이디어가 이미 나온 것인지 확인하고 출원을 돕습니다.</p></div>
357
+ </div>
358
+ </div>
359
+
360
+ </div>
361
+ </section>
362
+
363
+ <section id="view-building" hidden>
364
+ <div class="emb-wrap">
365
+ <div class="emb-head">
366
+ <h2>건축 도면 만들기</h2>
367
+ <p>원하는 건물을 말로 설명하면 평면도와 도면 파일(DXF)을 만들어 드립니다.</p>
368
+ </div>
369
+ <div class="emb-frame"><iframe id="building-frame" title="건축 도면 만들기" src="about:blank" loading="lazy"></iframe></div>
370
+ <p class="emb-note">생성된 도면은 초안입니다. 인허가 제출 전 건축사 확인이 필요합니다.</p>
371
+ </div>
372
+ </section>
373
+
374
+
375
+ <section id="view-saju" hidden>
376
+ <div class="emb-wrap">
377
+ <div class="emb-head">
378
+ <h2>사주</h2>
379
+ <p>생년월일시를 넣으면 만세력·오행·대운·세운을 분석해 드립니다. 순한맛(물닭 💧)과 매운맛(불닭 🌶️) 중에 골라 보세요.</p>
380
+ </div>
381
+ <div class="emb-frame"><iframe id="saju-frame" title="사주" src="about:blank" loading="lazy"></iframe></div>
382
+ <p class="emb-note">전통 명리학 해석이며 행정 안내가 아닙니다. 재미로 참고하세요.</p>
383
+ </div>
384
+ </section>
385
+
386
+ <section id="view-texray" hidden>
387
+ <div class="emb-wrap">
388
+ <div class="emb-head">
389
+ <h2>AI 글 판별</h2>
390
+ <p>제출한 글이 AI로 쓰였는지, 다른 곳에서 베낀 부분이 있는지 검사합니다.</p>
391
+ </div>
392
+ <div class="emb-frame"><iframe id="texray-frame" title="AI 글 판별" src="about:blank" loading="lazy"></iframe></div>
393
+ <p class="emb-note">판별 결과는 참고 자료입니다. 최종 판단은 담당자가 하십시오.</p>
394
+ </div>
395
+ </section>
396
+
397
+ <section id="view-office" hidden>
398
+ <iframe id="office-frame" title="무료 오피스 (HWP·DOCX·XLSX·PPTX·PDF)"
399
+ allow="clipboard-read; clipboard-write"></iframe>
400
+ </section>
401
+
402
+ <!-- ===== JGOS-Image (Qwen-Image-2512 한글 이미지 생성) ===== -->
403
+ <section id="view-image" hidden>
404
+ <div class="img-studio">
405
+ <div class="img-head">
406
+ <h2>🎨 이미지 생성 <small>한국형 AI 이미지 · 한국 인물·배경 · 영문 텍스트 · Qwen-Image-2512</small></h2>
407
+ </div>
408
+ <div class="img-examples">
409
+ <button class="img-ex" data-p="전남광주 통합특별시 출범 기념 포스터, 한국 시민들이 함께 모인 장면, 영문 제목 'Better Together', 밝고 희망찬">🎌 출범 포스터</button>
410
+ <button class="img-ex" data-p="보성 녹차밭 관광 포스터, 한국 전통 정취, 영문 문구 'Green Healing Tour', 청량하고 시원한">🍃 관광 홍보</button>
411
+ <button class="img-ex" data-p="민원 안내 인포그래픽, 깔끔한 한국 행정 디자인, 영문 제목 'Civil Service Guide', 아이콘">📋 민원 안내</button>
412
+ <button class="img-ex" data-p="전남 청정 농수산물 홍보, 한국 농촌 배경, 영문 문구 'Fresh Local Food', 풍성한">🌾 특산물</button>
413
+ </div>
414
+ <div class="img-opts">
415
+ <label class="img-opt-label">📐 비율
416
+ <select id="img-ratio">
417
+ <option value="1:1" selected>⬜ 정사각형 1:1</option>
418
+ <option value="3:4">📄 세로 3:4 (포스터)</option>
419
+ <option value="9:16">📱 세로 9:16 (모바일)</option>
420
+ <option value="4:3">🖼️ 가로 4:3</option>
421
+ <option value="16:9">🖥️ 가로 16:9 (배너)</option>
422
+ </select>
423
+ </label>
424
+ </div>
425
+ <div class="img-input-row">
426
+ <textarea id="img-prompt" rows="2" placeholder="원하는 이미지를 설명하세요 (예: 여수 밤바다 야경, 영문 문구 'Visit Yeosu')"></textarea>
427
+ <button id="img-gen-btn">🎨 생성</button>
428
+ </div>
429
+ <div id="img-status" class="img-status" hidden></div>
430
+ <div id="img-result" class="img-result"></div>
431
+ <div class="img-foot">⚖️ AI 생성 이미지 · 공식 행정자료 아님 · 상업적 이용 시 별도 검토</div>
432
+ </div>
433
+ </section>
434
+
435
+ <!-- ===== 🎓 AI 교육 (AI 시민 대학) ===== -->
436
+ <section id="view-edu" hidden>
437
+ <div class="edu-wrap">
438
+ <div class="edu-head">
439
+ <h2>🎓 AI 시민 대학 <small>AI 선생님에게 배우고 바로 실습하세요 · 누구나 무료</small></h2>
440
+ </div>
441
+ <div class="edu-cat-title">📱 JGOS 100% 활용</div>
442
+ <div class="edu-cards">
443
+ <button class="edu-card" data-q="JGOS에서 민원을 어떻게 물어보나요? 처음 쓰는 사람도 알 수 있게 쉽게 알려주세요." data-go="chat">① 민원 물어보기</button>
444
+ <button class="edu-card" data-q="JGOS 무료 오피스로 한글(HWP) 문서를 편집하고 저장하는 법을 알려주세요." data-go="office">② HWP 편집</button>
445
+ <button class="edu-card" data-q="JGOS 이미지 생성 기능 사용법과 좋은 설명(프롬프트) 쓰는 법을 알려주세요." data-go="image">③ 이미지 생성</button>
446
+ <button class="edu-card" data-q="JGOS에 PDF나 사진 파일을 올려서 내용을 분석하는 방법을 알려주세요." data-go="chat">④ 파일 분석</button>
447
+ </div>
448
+ <div class="edu-cat-title">🤖 AI 기본 소양</div>
449
+ <div class="edu-cards">
450
+ <button class="edu-card" data-q="AI가 무엇인지 어르신도 이해하기 쉽게 비유를 들어 설명해주세요.">⑤ AI란 무엇?</button>
451
+ <button class="edu-card" data-q="AI에게 질문을 잘 하는 방법(프롬프트)을 쉬운 예시와 함께 알려주세요.">⑥ 질문 잘하기</button>
452
+ <button class="edu-card" data-q="AI가 만든 가짜 정보(환각)를 구별하고 조심하는 방법을 알려주세요.">⑦ 가짜정보 판별</button>
453
+ <button class="edu-card" data-q="AI를 사용할 때 내 개인정보를 안전하게 지키는 방법을 알려주세요.">⑧ 개인정보 보호</button>
454
+ </div>
455
+ <div class="edu-cat-title">🌱 생활 맞춤</div>
456
+ <div class="edu-cards">
457
+ <button class="edu-card" data-q="컴퓨터가 익숙하지 않은 어르신을 위해 AI를 처음 사용하는 법을 아주 쉽고 천천히 알려주세요.">⑨ 어르신 첫걸음</button>
458
+ <button class="edu-card" data-q="소상공인이 AI로 가게 홍보물과 안내 문서를 만드는 방법을 알려주세요.">⑩ 소상공인 홍보</button>
459
+ <button class="edu-card" data-q="학생이 AI를 공부와 학습에 올바르고 똑똑하게 활용하는 방법을 알려주세요.">⑪ 학생 학습</button>
460
+ <button class="edu-card" data-q="농어민이 AI로 농수산물 홍보·판매와 영농 정보를 활용하는 방법을 알려주세요.">⑫ 농어민 활용</button>
461
+ </div>
462
+ <div class="edu-teacher">
463
+ <div class="edu-teacher-head">🧑‍🏫 AI 선생님 — 무엇이든 편하게 물어보세요</div>
464
+ <div id="edu-messages" class="edu-messages"></div>
465
+ <div id="edu-goto" class="edu-goto" hidden></div>
466
+ <div class="edu-input-row">
467
+ <textarea id="edu-input" rows="1" placeholder="예: AI가 뭐예요? / 프롬프트가 뭔가요?"></textarea>
468
+ <button id="edu-send">질문</button>
469
+ </div>
470
+ </div>
471
+ <div class="edu-foot">🎓 전남광주 통합특별시 AI 시민 대학 · 모든 시민 무료 · 위 강의를 누르면 AI 선생님이 설명해 드려요</div>
472
+ </div>
473
+ </section>
474
+
475
+ <!-- ===== 🏛️ 행정 AX 데이터 통합 (테스트 데모) ===== -->
476
+ <section id="view-ax" hidden>
477
+ <div class="ax-container">
478
+ <div class="ax-header">
479
+ <h2>🏛️ 행정 AX 데이터 통합 — 테스트 데모</h2>
480
+ <p class="ax-desc">이종 파일 포맷·서식의 행정 데이터를 자동으로 인식·정규화·통합합니다</p>
481
+ </div>
482
+
483
+ <!-- Demo 1: 이종 Excel 통합 -->
484
+ <div class="ax-demo-card">
485
+ <div class="ax-demo-header">
486
+ <span class="ax-demo-badge">Demo 1</span>
487
+ <h3>📊 이종 Excel 자동 통합</h3>
488
+ <p>27개 지자체가 제각각 다른 서식으로 제출한 Excel을 자동으로 표준화·통합합니다</p>
489
+ </div>
490
+ <div class="ax-demo-files">
491
+ <div class="ax-files-label">📁 예제 파일 (클릭하여 미리보기)</div>
492
+ <div class="ax-file-icons" id="ax-excel-demos"><!-- JS로 채움 --></div>
493
+ </div>
494
+ <div class="ax-upload-zone" id="ax-excel-drop">
495
+ <div class="ax-upload-inner">
496
+ <span class="ax-upload-icon">📤</span>
497
+ <div>Excel/CSV 파일을 여기에 드래그하거나 클릭하세요</div>
498
+ <div class="ax-upload-hint">XLSX, XLS, CSV — 여러 파일 동시 업로드 가능</div>
499
+ </div>
500
+ <input type="file" id="ax-excel-input" hidden multiple accept=".xlsx,.xls,.csv">
501
+ </div>
502
+ <div class="ax-actions">
503
+ <button class="ax-btn ax-btn-primary" id="ax-excel-run" disabled>
504
+ <span>⚡</span> 통합 실행
505
+ </button>
506
+ <span class="ax-file-count" id="ax-excel-count"></span>
507
+ </div>
508
+ <div class="ax-result-area" id="ax-excel-result" hidden></div>
509
+ </div>
510
+
511
+ <!-- Demo 2: 이종 포맷 통합 -->
512
+ <div class="ax-demo-card">
513
+ <div class="ax-demo-header">
514
+ <span class="ax-demo-badge ax-demo-badge-2">Demo 2</span>
515
+ <h3>🗂️ 이종 포맷 자동 통합</h3>
516
+ <p>HWP, XLSX, CSV, PPTX, DOCX, PDF — 7가지 다른 포맷의 데이터를 하나의 표로 통합합니다</p>
517
+ </div>
518
+ <div class="ax-demo-files">
519
+ <div class="ax-files-label">📁 예제 파일 7종 (클릭하여 미리보기)</div>
520
+ <div class="ax-file-icons" id="ax-format-demos"><!-- JS로 채움 --></div>
521
+ </div>
522
+ <div class="ax-upload-zone" id="ax-format-drop">
523
+ <div class="ax-upload-inner">
524
+ <span class="ax-upload-icon">📤</span>
525
+ <div>이종 포맷 파일을 여기에 드래그하거나 클릭하세요</div>
526
+ <div class="ax-upload-hint">HWPX, XLSX, CSV, PPTX, DOCX, PDF — 혼합 업로드 가능</div>
527
+ </div>
528
+ <input type="file" id="ax-format-input" hidden multiple accept=".hwp,.hwpx,.xlsx,.xls,.csv,.docx,.pptx,.pdf">
529
+ </div>
530
+ <div class="ax-actions">
531
+ <button class="ax-btn ax-btn-primary ax-btn-2" id="ax-format-run" disabled>
532
+ <span>⚡</span> 통합 실행
533
+ </button>
534
+ <span class="ax-file-count" id="ax-format-count"></span>
535
+ </div>
536
+ <div class="ax-result-area" id="ax-format-result" hidden></div>
537
+ </div>
538
+ </div>
539
+
540
+ <!-- 파일 미리보기 모달 -->
541
+ <div id="ax-modal" class="ax-modal-overlay" hidden>
542
+ <div class="ax-modal-box">
543
+ <div class="ax-modal-header">
544
+ <span id="ax-modal-title">파일 미리보기</span>
545
+ <button class="ax-modal-close" id="ax-modal-close">✕</button>
546
+ </div>
547
+ <div class="ax-modal-body" id="ax-modal-body">
548
+ <div class="ax-loading">⏳ 불러오는 중...</div>
549
+ </div>
550
+ </div>
551
+ </div>
552
+ </section>
553
+ </main>
554
+
555
+ <!-- 모바일 사이드바 백드롭 -->
556
+ <div id="sidebar-backdrop" hidden></div>
557
+ </div>
558
+
559
+ <div id="drag-overlay" hidden>
560
+ <div class="drop-card">
561
+ 📂 여기에 파일을 놓으세요
562
+ <small>HWP · HWPX · PDF · DOCX · PPTX · XLSX · CSV · 이미지<br>(ESC 또는 클릭으로 닫기)</small>
563
+ </div>
564
+ </div>
565
+
566
+ <script src="/static/jgos_app_v611.js?v=612"></script>
567
+
568
+ <script>
569
+ /* JGOS AX 미리보기 — 인라인 (캐시 우회, v611-INLINE) */
570
+ window.axPreviewDemo = async function(filename, label){
571
+ var modal=document.getElementById("ax-modal");
572
+ var body=document.getElementById("ax-modal-body");
573
+ var title=document.getElementById("ax-modal-title");
574
+ if(!modal||!body)return;
575
+ if(title)title.textContent="\uD83D\uDCC4 "+label+" \u2014 \uBBF8\uB9AC\uBCF4\uAE30";
576
+ body.innerHTML='<div class="ax-loading">\u23F3 \uBD88\uB7EC\uC624\uB294 \uC911... [INLINE]</div>';
577
+ modal.hidden=false;
578
+ try{
579
+ var r=await fetch("/api/demo/preview/"+encodeURIComponent(filename)+"?t="+Date.now());
580
+ if(!r.ok){body.innerHTML="<p style=\'color:#b91c1c\'>\uC11C\uBC84 \uC624\uB958 ("+r.status+")</p>";return;}
581
+ var d=await r.json();
582
+ body.innerHTML=(d.rows>0)?(d.html||"<p>\uBE48 \uACB0\uACFC</p>"):"<p style=\'color:#92400e\'>\u26A0\uFE0F \uD30C\uC2F1 \uC2E4\uD328</p>";
583
+ }catch(e){
584
+ body.innerHTML="<p style=\'color:red\'>\uC624\uB958: "+(e&&e.message?e.message:e)+"</p>";
585
+ }
586
+ };
587
+ /* 칩 onclick 재바인딩 (외부 js가 이미 그렸어도 인라인 함수로 연결) */
588
+ (function(){
589
+ function rebind(){
590
+ document.querySelectorAll(".ax-file-chip").forEach(function(chip){
591
+ chip.onclick=function(){ window.axPreviewDemo(chip.dataset.demo, chip.dataset.label); };
592
+ });
593
+ }
594
+ if(document.readyState!=="loading")setTimeout(rebind,300);
595
+ else document.addEventListener("DOMContentLoaded",function(){setTimeout(rebind,300);});
596
+ // 탭 전환 후에도 재바인딩
597
+ document.addEventListener("click",function(e){
598
+ var t=e.target.closest&&e.target.closest('[data-view="ax"]');
599
+ if(t)setTimeout(rebind,400);
600
+ });
601
+ })();
602
+ console.log("[JGOS] AX inline preview v611-INLINE loaded");
603
+ </script>
604
+
605
+
606
+ <script>
607
+ /* JGOS AX 예제 바로 실행 버튼 — DEMO-RUN-v1 */
608
+ (function(){
609
+ async function runDemoMerge(btn, resultId, demoType){
610
+ var result=document.getElementById(resultId);
611
+ var old=btn.innerHTML; btn.disabled=true; btn.innerHTML="\u23F3 \uD1B5\uD569 \uC911...";
612
+ if(result){result.hidden=false;result.innerHTML='<div class="ax-loading">\u23F3 \uC608\uC81C \uD1B5\uD569 \uC911...</div>';}
613
+ try{
614
+ var r=await fetch("/api/demo/merge/"+demoType+"?t="+Date.now());
615
+ var d=await r.json();
616
+ if(result){
617
+ 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("");
618
+ result.innerHTML='<div class="ax-source-list">'+src+'</div>'+(d.html||"");
619
+ }
620
+ }catch(e){if(result)result.innerHTML="<p style=\'color:red\'>\uC624\uB958: "+(e&&e.message?e.message:e)+"</p>";}
621
+ btn.disabled=false; btn.innerHTML=old;
622
+ }
623
+ function addBtn(runBtnId, resultId, demoType){
624
+ var runBtn=document.getElementById(runBtnId);
625
+ if(!runBtn) return;
626
+ if(document.getElementById(runBtnId+"-demo")) return;
627
+ var btn=document.createElement("button");
628
+ btn.id=runBtnId+"-demo";
629
+ btn.className=runBtn.className;
630
+ btn.style.background="#0d7377";
631
+ btn.style.marginLeft="8px";
632
+ btn.innerHTML="\uD83D\uDCC2 \uC608\uC81C\uB85C \uBC14\uB85C \uD1B5\uD569";
633
+ runBtn.parentNode.insertBefore(btn, runBtn.nextSibling);
634
+ btn.onclick=function(){ runDemoMerge(btn, resultId, demoType); };
635
+ }
636
+ function setup(){
637
+ addBtn("ax-excel-run","ax-excel-result","excel");
638
+ addBtn("ax-format-run","ax-format-result","formats");
639
+ }
640
+ if(document.readyState!=="loading") setTimeout(setup,500);
641
+ else document.addEventListener("DOMContentLoaded",function(){setTimeout(setup,500);});
642
+ document.addEventListener("click",function(e){
643
+ var t=e.target.closest&&e.target.closest('[data-view="ax"]');
644
+ if(t) setTimeout(setup,500);
645
+ });
646
+ console.log("[JGOS] AX demo-run buttons v1 loaded");
647
+ })();
648
+ </script>
649
+
650
+
651
+ <script>
652
+ /* AX-INTEGRATE-v2: 통합 결과 표시 + XLSX 다운로드 */
653
+ (function(){
654
+ function chip(s){return '<span class="ax-source-chip">'+(s["\uD3EC\uB9F7"]||"")+" "+(s["\uD30C\uC77C"]||"")+" ("+(s["\uAC74\uC218"]||0)+"\uAC74)</span>";}
655
+ window.__axShow=function(resultId,d){
656
+ var result=document.getElementById(resultId);
657
+ if(!result)return;
658
+ result.hidden=false;
659
+ var src=(d.sources||[]).map(chip).join("");
660
+ result.innerHTML='<div class="ax-source-list">'+src+'</div>'+(d.html||"");
661
+ if(d.records&&d.records.length){
662
+ var dl=document.createElement("button");
663
+ 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";
664
+ dl.textContent="\uD83D\uDCE5 \uD1B5\uD569\uBCF8 XLSX \uB2E4\uC6B4\uB85C\uB4DC ("+d.records.length+"\uAC74)";
665
+ dl.onclick=async function(){
666
+ var o=dl.textContent; dl.disabled=true; dl.textContent="\u23F3 \uC0DD\uC131 \uC911...";
667
+ try{
668
+ 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"})});
669
+ if(!rr.ok)throw new Error("\uC11C\uBC84 "+rr.status);
670
+ var b=await rr.blob(); var u=URL.createObjectURL(b);
671
+ var a=document.createElement("a"); a.href=u; a.download="JGOS_\uD589\uC815AX_\uD1B5\uD569\uACB0\uACFC.xlsx";
672
+ document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(u);
673
+ }catch(e){alert("\uB2E4\uC6B4\uB85C\uB4DC \uC2E4\uD328: "+(e.message||e));}
674
+ dl.disabled=false; dl.textContent=o;
675
+ };
676
+ result.appendChild(dl);
677
+ }
678
+ };
679
+ async function exampleMerge(btn,resultId,type){
680
+ var o=btn.innerHTML; btn.disabled=true; btn.innerHTML="\u23F3 \uD1B5\uD569 \uC911...";
681
+ var result=document.getElementById(resultId);
682
+ if(result){result.hidden=false;result.innerHTML='<div class="ax-loading">\u23F3 \uC608\uC81C \uD1B5\uD569 \uC911...</div>';}
683
+ try{var r=await fetch("/api/demo/merge/"+type+"?t="+Date.now());var d=await r.json();window.__axShow(resultId,d);}
684
+ catch(e){if(result)result.innerHTML="<p style=\'color:red\'>\uC624\uB958: "+(e.message||e)+"</p>";}
685
+ btn.disabled=false; btn.innerHTML=o;
686
+ }
687
+ async function uploadMerge(btn,inputId,resultId,apiPath){
688
+ var input=document.getElementById(inputId);
689
+ if(!input||!input.files||!input.files.length){alert("\uD30C\uC77C\uC744 \uC120\uD0DD\uD558\uC138\uC694");return;}
690
+ var o=btn.innerHTML; btn.disabled=true; btn.innerHTML="\u23F3 \uD1B5\uD569 \uC911...";
691
+ var result=document.getElementById(resultId);
692
+ if(result){result.hidden=false;result.innerHTML='<div class="ax-loading">\u23F3 \uD1B5\uD569 \uC911...</div>';}
693
+ var fd=new FormData(); for(var i=0;i<input.files.length;i++)fd.append("files",input.files[i]);
694
+ try{var r=await fetch(apiPath,{method:"POST",body:fd});var d=await r.json();window.__axShow(resultId,d);}
695
+ catch(e){if(result)result.innerHTML="<p style=\'color:red\'>\uC624\uB958: "+(e.message||e)+"</p>";}
696
+ btn.disabled=false; btn.innerHTML=o;
697
+ }
698
+ function setup(){
699
+ var er=document.getElementById("ax-excel-run");
700
+ if(er)er.onclick=function(){uploadMerge(er,"ax-excel-input","ax-excel-result","/api/excel/merge");};
701
+ var fr=document.getElementById("ax-format-run");
702
+ if(fr)fr.onclick=function(){uploadMerge(fr,"ax-format-input","ax-format-result","/api/files/merge-formats");};
703
+ [["ax-excel-run","ax-excel-result","excel"],["ax-format-run","ax-format-result","formats"]].forEach(function(x){
704
+ var run=document.getElementById(x[0]); if(!run)return;
705
+ var id=x[0]+"-demo"; var b=document.getElementById(id);
706
+ 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);}
707
+ b.onclick=function(){exampleMerge(b,x[1],x[2]);};
708
+ });
709
+ }
710
+ if(document.readyState!=="loading")setTimeout(setup,600);
711
+ else document.addEventListener("DOMContentLoaded",function(){setTimeout(setup,600);});
712
+ document.addEventListener("click",function(e){var t=e.target.closest&&e.target.closest('[data-view="ax"]');if(t)setTimeout(setup,600);});
713
+ console.log("[JGOS] AX integrate+download v2 loaded");
714
+ })();
715
+ </script>
716
+
717
+
718
+ <script id="jgos-home-js">
719
+ /* 서비스 첫화면 + 건축도면 뷰 — 기존 showView/switchTab 을 감싸서 확장 (원본 JS 무수정) */
720
+ (function(){
721
+ var home=document.getElementById('view-home');
722
+ var build=document.getElementById('view-building');
723
+ var saju=document.getElementById('view-saju');
724
+ var tex=document.getElementById('view-texray');
725
+ var texf=document.getElementById('texray-frame');var texLoaded=false;
726
+ var sajuf=document.getElementById('saju-frame');var sajuLoaded=false;
727
+ var frame=document.getElementById('building-frame');
728
+ var chat=document.getElementById('view-chat');
729
+ var loaded=false;
730
+ function paint(name){
731
+ home.hidden = name!=='home';
732
+ build.hidden = name!=='building';
733
+ saju.hidden = name!=='saju';
734
+ tex.hidden = name!=='texray';
735
+ if(name==='texray' && !texLoaded){ texf.src='https://ginigen-TeXray.hf.space/'; texLoaded=true; }
736
+ if(name==='saju' && !sajuLoaded){ sajuf.src='https://ginigen-SAJU.hf.space/'; sajuLoaded=true; }
737
+ if(name==='building' && !loaded){ frame.src='https://VIDraft-building.hf.space/'; loaded=true; }
738
+ if(name!=='chat'){ if(chat) chat.style.display='none'; }
739
+ }
740
+ function go(name){
741
+ document.querySelectorAll('.top-tab').forEach(function(t){
742
+ t.classList.toggle('active', t.dataset.view===name);
743
+ });
744
+ if(typeof showView==='function') showView(['home','building','saju','texray'].indexOf(name)>=0 ? '__none__' : name);
745
+ paint(name);
746
+ }
747
+ window.jgosGo = go;
748
+ document.querySelectorAll('.top-tab').forEach(function(t){
749
+ t.addEventListener('click', function(){ go(t.dataset.view); });
750
+ });
751
+ document.addEventListener('click', function(e){
752
+ var c=e.target.closest('.svc-card, .svc-hero');
753
+ if(!c || c.classList.contains('soon')) return;
754
+ var v=c.dataset.view; if(!v) return;
755
+ go(v);
756
+ if(v==='chat' && c.dataset.q){
757
+ var box=document.querySelector('#composer-input, #input, textarea');
758
+ if(box){ box.value=c.dataset.q; box.focus(); }
759
+ }
760
+ });
761
+ go('home'); /* 첫 화면 = 서비스 */
762
+ })();
763
+ </script>
764
+ </body>
765
+ </html>