seawolf2357 commited on
Commit
3037806
Β·
verified Β·
1 Parent(s): 82f37e9

Create index.html

Browse files
Files changed (1) hide show
  1. index.html +709 -0
index.html ADDED
@@ -0,0 +1,709 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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">
6
+ <title> TeXray </title>
7
+ <link href="https://fonts.googleapis.com/css2?family=Sora:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&family=Noto+Sans+KR:wght@300;400;500;700;900&display=swap" rel="stylesheet">
8
+ <style>
9
+ /* ═══════════════════════════════════════════════════════════════
10
+ TeXray β€” Premium Dark Glassmorphism
11
+ ═══════════════════════════════════════════════════════════════ */
12
+ *{margin:0;padding:0;box-sizing:border-box;}
13
+ :root{
14
+ --bg-deep:#03030a;
15
+ --bg:#07071a;
16
+ --surface:rgba(14,14,38,0.65);
17
+ --surface-solid:#0c0c24;
18
+ --glass:rgba(18,18,50,0.45);
19
+ --glass2:rgba(24,24,60,0.55);
20
+ --glass-border:rgba(80,80,160,0.12);
21
+ --glass-border-hover:rgba(120,120,200,0.22);
22
+ --card-glow:rgba(100,80,220,0.06);
23
+ --text:#e8e8f4;
24
+ --text-dim:#9898c0;
25
+ --text-muted:#5a5a88;
26
+ --accent:#8b7aff;
27
+ --accent-bright:#a594ff;
28
+ --accent-glow:rgba(139,122,255,0.15);
29
+ --accent-glow2:rgba(139,122,255,0.08);
30
+ --teal:#3dd6c8;
31
+ --teal-glow:rgba(61,214,200,0.12);
32
+ --rose:#ff6b8a;
33
+ --rose-glow:rgba(255,107,138,0.12);
34
+ --amber:#ffb347;
35
+ --amber-glow:rgba(255,179,71,0.12);
36
+ --sky:#54b5ff;
37
+ --radius:16px;
38
+ --radius-sm:10px;
39
+ --radius-xs:6px;
40
+ --font-display:'Sora','Noto Sans KR',sans-serif;
41
+ --font-body:'Noto Sans KR','Sora',sans-serif;
42
+ --font-mono:'JetBrains Mono',monospace;
43
+ --transition:0.3s cubic-bezier(0.4,0,0.2,1);
44
+ }
45
+ html{scroll-behavior:smooth;}
46
+ body{
47
+ font-family:var(--font-body);
48
+ background:var(--bg-deep);
49
+ color:var(--text);
50
+ min-height:100vh;
51
+ overflow-x:hidden;
52
+ -webkit-font-smoothing:antialiased;
53
+ }
54
+ ::-webkit-scrollbar{width:6px;}
55
+ ::-webkit-scrollbar-track{background:transparent;}
56
+ ::-webkit-scrollbar-thumb{background:rgba(139,122,255,0.25);border-radius:10px;}
57
+ ::-webkit-scrollbar-thumb:hover{background:rgba(139,122,255,0.4);}
58
+ ::selection{background:rgba(139,122,255,0.3);color:#fff;}
59
+
60
+ /* ═══ CANVAS BACKGROUND ═══ */
61
+ #mesh-canvas{position:fixed;top:0;left:0;width:100%;height:100%;z-index:0;pointer-events:none;opacity:0.5;}
62
+ .noise-overlay{
63
+ position:fixed;top:0;left:0;width:100%;height:100%;z-index:1;pointer-events:none;opacity:0.025;
64
+ background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
65
+ background-size:128px;
66
+ }
67
+ .vignette{
68
+ position:fixed;top:0;left:0;width:100%;height:100%;z-index:1;pointer-events:none;
69
+ background:radial-gradient(ellipse 70% 60% at 50% 50%,transparent 0%,var(--bg-deep) 100%);
70
+ }
71
+
72
+ /* ═══ LAYOUT ═══ */
73
+ .app-wrapper{
74
+ position:relative;z-index:2;
75
+ display:flex;flex-direction:column;
76
+ min-height:100vh;
77
+ max-width:900px;
78
+ margin:0 auto;
79
+ padding:32px 24px 48px;
80
+ }
81
+
82
+ /* ═══ HEADER ═══ */
83
+ .header{text-align:center;padding:48px 0 36px;animation:headerIn 1s ease-out;}
84
+ @keyframes headerIn{from{opacity:0;transform:translateY(-24px);}to{opacity:1;transform:translateY(0);}}
85
+ .header-eyebrow{
86
+ font-family:var(--font-mono);font-size:11px;font-weight:500;
87
+ letter-spacing:5px;text-transform:uppercase;
88
+ color:var(--accent);margin-bottom:12px;opacity:0.7;
89
+ }
90
+ .header-title{
91
+ font-family:var(--font-display);font-size:52px;font-weight:800;
92
+ line-height:1.15;letter-spacing:-1.5px;margin-bottom:14px;
93
+ position:relative;display:inline-block;
94
+ }
95
+ .header-title .gradient-text{
96
+ background:linear-gradient(135deg,#a594ff 0%,#54b5ff 35%,#3dd6c8 65%,#a594ff 100%);
97
+ background-size:200% 200%;
98
+ -webkit-background-clip:text;-webkit-text-fill-color:transparent;
99
+ animation:shimmer 6s ease-in-out infinite;
100
+ }
101
+ @keyframes shimmer{0%,100%{background-position:0% 50%;}50%{background-position:100% 50%;}}
102
+ .header-subtitle{
103
+ font-size:14.5px;color:var(--text-dim);line-height:1.7;letter-spacing:0.2px;
104
+ max-width:520px;margin:0 auto 20px;
105
+ }
106
+ .header-subtitle b{color:var(--text);font-weight:600;}
107
+ .pill-row{display:flex;gap:6px;justify-content:center;flex-wrap:wrap;animation:fadeUp 1s 0.3s ease-out both;}
108
+ @keyframes fadeUp{from{opacity:0;transform:translateY(10px);}to{opacity:1;transform:translateY(0);}}
109
+ .pill{
110
+ padding:5px 14px;background:var(--glass);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
111
+ border:1px solid var(--glass-border);border-radius:24px;
112
+ font-family:var(--font-mono);font-size:10px;font-weight:500;color:var(--text-muted);
113
+ transition:var(--transition);
114
+ }
115
+ .pill:hover{border-color:var(--glass-border-hover);color:var(--text-dim);}
116
+
117
+ /* ═══ NAV TABS ═══ */
118
+ .nav{
119
+ display:flex;gap:4px;
120
+ background:var(--glass);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
121
+ border:1px solid var(--glass-border);border-radius:14px;padding:4px;
122
+ margin-bottom:28px;position:sticky;top:12px;z-index:100;
123
+ animation:fadeUp 1s 0.4s ease-out both;
124
+ }
125
+ .nav-item{
126
+ flex:1;display:flex;align-items:center;justify-content:center;gap:6px;
127
+ padding:13px 8px;border-radius:var(--radius-sm);cursor:pointer;
128
+ font-size:13px;font-weight:600;color:var(--text-muted);
129
+ transition:var(--transition);position:relative;user-select:none;
130
+ }
131
+ .nav-item:hover{color:var(--text-dim);background:rgba(139,122,255,0.06);}
132
+ .nav-item.active{
133
+ color:#fff;
134
+ background:linear-gradient(135deg,rgba(139,122,255,0.9),rgba(100,80,220,0.95));
135
+ box-shadow:0 4px 20px rgba(139,122,255,0.3),inset 0 1px 0 rgba(255,255,255,0.12);
136
+ }
137
+ .nav-icon{font-size:15px;}
138
+
139
+ /* ═══ PANELS ═══ */
140
+ .panel{display:none;animation:panelReveal 0.45s ease-out;}
141
+ .panel.active{display:block;}
142
+ @keyframes panelReveal{from{opacity:0;transform:translateY(16px) scale(0.995);}to{opacity:1;transform:translateY(0) scale(1);}}
143
+
144
+ /* ═══ GLASS CARD ═══ */
145
+ .card{
146
+ background:var(--glass);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
147
+ border:1px solid var(--glass-border);border-radius:var(--radius);
148
+ padding:28px;margin-bottom:20px;position:relative;overflow:hidden;
149
+ transition:border-color 0.4s,box-shadow 0.4s;
150
+ }
151
+ .card::before{
152
+ content:'';position:absolute;top:0;left:0;right:0;height:1px;
153
+ background:linear-gradient(90deg,transparent,rgba(139,122,255,0.2),transparent);
154
+ opacity:0;transition:opacity 0.4s;
155
+ }
156
+ .card:hover{border-color:var(--glass-border-hover);box-shadow:0 8px 40px var(--card-glow);}
157
+ .card:hover::before{opacity:1;}
158
+ .card-header{display:flex;align-items:center;gap:12px;margin-bottom:6px;}
159
+ .card-icon{
160
+ width:38px;height:38px;border-radius:var(--radius-sm);
161
+ display:flex;align-items:center;justify-content:center;font-size:18px;flex-shrink:0;
162
+ }
163
+ .card-icon.purple{background:var(--accent-glow);border:1px solid rgba(139,122,255,0.2);}
164
+ .card-icon.teal{background:var(--teal-glow);border:1px solid rgba(61,214,200,0.2);}
165
+ .card-icon.rose{background:var(--rose-glow);border:1px solid rgba(255,107,138,0.2);}
166
+ .card-icon.amber{background:var(--amber-glow);border:1px solid rgba(255,179,71,0.2);}
167
+ .card-title{font-family:var(--font-display);font-size:17px;font-weight:700;letter-spacing:-0.3px;}
168
+ .card-desc{
169
+ font-size:12.5px;color:var(--text-muted);line-height:1.65;
170
+ margin-bottom:18px;padding-left:50px;
171
+ }
172
+
173
+ /* ═══ TEXTAREA ═══ */
174
+ .input-group{margin-bottom:18px;}
175
+ .textarea-wrap{position:relative;}
176
+ textarea{
177
+ width:100%;min-height:200px;padding:18px 20px 32px;
178
+ background:rgba(8,8,28,0.6);border:1px solid var(--glass-border);
179
+ border-radius:var(--radius-sm);color:var(--text);
180
+ font-family:var(--font-body);font-size:14px;line-height:1.8;
181
+ resize:vertical;outline:none;
182
+ transition:border-color 0.35s,box-shadow 0.35s;
183
+ }
184
+ textarea:focus{
185
+ border-color:rgba(139,122,255,0.4);
186
+ box-shadow:0 0 0 3px var(--accent-glow),0 4px 20px rgba(0,0,0,0.3);
187
+ }
188
+ textarea::placeholder{color:var(--text-muted);font-size:13px;}
189
+ .char-counter{
190
+ position:absolute;bottom:10px;right:16px;
191
+ font-family:var(--font-mono);font-size:10px;color:var(--text-muted);
192
+ background:rgba(8,8,28,0.7);padding:2px 8px;border-radius:4px;pointer-events:none;
193
+ }
194
+
195
+ /* ═══ BUTTONS ═══ */
196
+ .btn-group{display:flex;gap:8px;flex-wrap:wrap;align-items:center;}
197
+ .btn{
198
+ padding:11px 22px;border:none;border-radius:var(--radius-sm);cursor:pointer;
199
+ font-family:var(--font-body);font-weight:600;font-size:13px;
200
+ transition:all 0.25s cubic-bezier(0.4,0,0.2,1);
201
+ position:relative;overflow:hidden;letter-spacing:0.2px;
202
+ }
203
+ .btn-primary{
204
+ background:linear-gradient(135deg,var(--accent),#6854e0);color:#fff;
205
+ box-shadow:0 4px 20px rgba(139,122,255,0.25),inset 0 1px 0 rgba(255,255,255,0.1);
206
+ }
207
+ .btn-primary:hover{transform:translateY(-2px);box-shadow:0 8px 32px rgba(139,122,255,0.35),inset 0 1px 0 rgba(255,255,255,0.15);}
208
+ .btn-primary:active{transform:translateY(0);box-shadow:0 2px 12px rgba(139,122,255,0.2);}
209
+ .btn-primary:disabled{opacity:0.45;cursor:not-allowed;transform:none!important;}
210
+ .btn-primary::after{
211
+ content:'';position:absolute;inset:0;
212
+ background:radial-gradient(circle at var(--x,50%) var(--y,50%),rgba(255,255,255,0.25) 0%,transparent 60%);
213
+ opacity:0;transition:opacity 0.5s;
214
+ }
215
+ .btn-primary:active::after{opacity:1;transition:none;}
216
+ .btn-ghost{
217
+ padding:9px 16px;background:rgba(255,255,255,0.03);color:var(--text-muted);
218
+ border:1px solid var(--glass-border);font-size:12px;border-radius:var(--radius-xs);
219
+ }
220
+ .btn-ghost:hover{background:rgba(139,122,255,0.08);color:var(--text-dim);border-color:var(--glass-border-hover);}
221
+
222
+ /* ═══ LOADING ═══ */
223
+ .loader{display:none;text-align:center;padding:48px 24px;}
224
+ .loader.active{display:block;}
225
+ .loader-ring{
226
+ width:44px;height:44px;
227
+ border:3px solid rgba(139,122,255,0.1);border-top-color:var(--accent);
228
+ border-radius:50%;animation:ring-spin 0.9s linear infinite;
229
+ margin:0 auto 16px;position:relative;
230
+ }
231
+ .loader-ring::after{
232
+ content:'';position:absolute;inset:4px;
233
+ border:2px solid transparent;border-top-color:var(--teal);
234
+ border-radius:50%;animation:ring-spin 1.4s linear infinite reverse;
235
+ }
236
+ @keyframes ring-spin{to{transform:rotate(360deg);}}
237
+ .loader-text{font-size:13px;color:var(--text-dim);animation:breathe 2s ease-in-out infinite;}
238
+ .loader-dots{display:inline-flex;gap:4px;margin-top:8px;}
239
+ .loader-dots span{
240
+ width:4px;height:4px;border-radius:50%;background:var(--accent);opacity:0.3;
241
+ animation:dotPulse 1.2s ease-in-out infinite;
242
+ }
243
+ .loader-dots span:nth-child(2){animation-delay:0.15s;}
244
+ .loader-dots span:nth-child(3){animation-delay:0.3s;}
245
+ @keyframes dotPulse{0%,100%{opacity:0.2;transform:scale(0.8);}50%{opacity:1;transform:scale(1.2);}}
246
+ @keyframes breathe{0%,100%{opacity:1;}50%{opacity:0.5;}}
247
+
248
+ /* ═══ RESULT ═══ */
249
+ .result-html{border-radius:var(--radius);overflow:hidden;margin-top:16px;animation:resultIn 0.5s ease-out;}
250
+ .result-html:empty{display:none;}
251
+ @keyframes resultIn{from{opacity:0;transform:translateY(12px);}to{opacity:1;transform:translateY(0);}}
252
+ .log-box{
253
+ background:rgba(8,8,28,0.7);border:1px solid var(--glass-border);
254
+ border-radius:var(--radius-xs);padding:14px 18px;
255
+ font-family:var(--font-mono);font-size:11px;color:var(--text-muted);
256
+ line-height:1.7;white-space:pre-wrap;margin-top:10px;backdrop-filter:blur(8px);
257
+ }
258
+ .log-box:empty{display:none;}
259
+
260
+ /* ═══ HUMANIZER RESULT ═══ */
261
+ .result-card{
262
+ background:var(--glass);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
263
+ border:1px solid rgba(61,214,200,0.2);border-radius:var(--radius);
264
+ padding:24px;position:relative;overflow:hidden;
265
+ }
266
+ .result-card::before{
267
+ content:'';position:absolute;top:0;left:0;right:0;height:2px;
268
+ background:linear-gradient(90deg,var(--teal),var(--accent),var(--teal));
269
+ }
270
+ .result-card-title{
271
+ display:flex;align-items:center;gap:8px;
272
+ font-family:var(--font-display);font-size:15px;font-weight:700;
273
+ color:var(--teal);margin-bottom:14px;
274
+ }
275
+ .converted-text{
276
+ background:rgba(8,8,28,0.5);border:1px solid var(--glass-border);
277
+ border-radius:var(--radius-sm);padding:18px 20px;
278
+ font-size:14px;line-height:1.9;position:relative;
279
+ white-space:pre-wrap;min-height:60px;color:var(--text);
280
+ }
281
+ .copy-btn{
282
+ position:absolute;top:10px;right:10px;
283
+ background:var(--glass2);backdrop-filter:blur(10px);
284
+ border:1px solid var(--glass-border);color:var(--text-muted);
285
+ padding:5px 12px;border-radius:var(--radius-xs);cursor:pointer;
286
+ font-family:var(--font-mono);font-size:10px;font-weight:600;
287
+ transition:all 0.25s;letter-spacing:0.5px;text-transform:uppercase;
288
+ }
289
+ .copy-btn:hover{background:var(--accent);color:#fff;border-color:var(--accent);}
290
+ .copy-btn.copied{background:var(--teal);color:#fff;border-color:var(--teal);}
291
+
292
+ /* ═══ FOOTER ═══ */
293
+ .footer{
294
+ text-align:center;margin-top:56px;padding:28px 0;
295
+ border-top:1px solid var(--glass-border);
296
+ animation:fadeUp 1s 0.6s ease-out both;
297
+ }
298
+ .footer-brand{font-family:var(--font-display);font-size:13px;font-weight:600;color:var(--text-muted);letter-spacing:0.5px;margin-bottom:6px;}
299
+ .footer-tech{font-family:var(--font-mono);font-size:10px;color:rgba(90,90,136,0.6);letter-spacing:1px;}
300
+ .footer-line{
301
+ width:40px;height:2px;
302
+ background:linear-gradient(90deg,transparent,var(--accent-glow2),var(--accent),var(--accent-glow2),transparent);
303
+ margin:12px auto;border-radius:2px;
304
+ }
305
+
306
+ /* ═══ RESULTS TABLE OVERRIDE ═══ */
307
+ .result-html table{border-collapse:collapse;width:100%;}
308
+ .result-html td,.result-html th{padding:8px 12px;border:1px solid var(--glass-border);}
309
+ .result-html th{background:rgba(139,122,255,0.08);}
310
+
311
+ /* ═══ STATUS DOT ═══ */
312
+ .status-dot{
313
+ width:6px;height:6px;border-radius:50%;background:var(--teal);
314
+ display:inline-block;animation:statusPulse 2s ease-in-out infinite;margin-right:4px;
315
+ }
316
+ @keyframes statusPulse{0%,100%{opacity:1;box-shadow:0 0 0 0 rgba(61,214,200,0.4);}50%{opacity:0.7;box-shadow:0 0 0 4px rgba(61,214,200,0);}}
317
+
318
+ /* ═══ FILE UPLOAD ═══ */
319
+ .file-drop{
320
+ border:2px dashed var(--glass-border);border-radius:var(--radius);
321
+ padding:32px;text-align:center;cursor:pointer;transition:all 0.3s;
322
+ background:rgba(8,8,28,0.4);position:relative;
323
+ }
324
+ .file-drop:hover,.file-drop.dragover{
325
+ border-color:var(--accent);background:var(--accent-glow);
326
+ }
327
+ .file-drop-icon{font-size:32px;margin-bottom:8px;}
328
+ .file-drop-text{font-size:13px;color:var(--text-muted);}
329
+ .file-drop-hint{font-size:10px;color:var(--text-muted);margin-top:6px;opacity:0.6;}
330
+ .file-drop input[type=file]{position:absolute;inset:0;opacity:0;cursor:pointer;}
331
+ .file-info{display:none;padding:12px 16px;background:var(--glass);border:1px solid var(--glass-border);border-radius:var(--radius-sm);margin-top:10px;font-size:12px;color:var(--text-dim);}
332
+ .file-info.active{display:flex;align-items:center;gap:10px;}
333
+ .file-info-name{font-weight:600;color:var(--text);}
334
+ .file-info-size{color:var(--text-muted);font-family:var(--font-mono);font-size:10px;}
335
+ .file-remove{cursor:pointer;color:var(--rose);font-size:14px;margin-left:auto;}
336
+
337
+ /* ═══ RESPONSIVE ═══ */
338
+ @media(max-width:640px){
339
+ .app-wrapper{padding:16px 12px 32px;}
340
+ .header{padding:32px 0 24px;}
341
+ .header-title{font-size:32px;letter-spacing:-0.5px;}
342
+ .header-subtitle{font-size:13px;}
343
+ .nav{flex-wrap:wrap;position:static;}
344
+ .nav-item{font-size:11px;padding:10px 6px;}
345
+ .nav-icon{font-size:13px;}
346
+ .card{padding:20px 16px;}
347
+ .card-desc{padding-left:0;margin-top:8px;}
348
+ textarea{min-height:160px;font-size:13px;padding:14px 16px 28px;}
349
+ .btn{padding:10px 16px;font-size:12px;}
350
+ .btn-group{gap:6px;}
351
+ }
352
+ </style>
353
+ </head>
354
+ <body>
355
+
356
+ <!-- Background -->
357
+ <canvas id="mesh-canvas"></canvas>
358
+ <div class="noise-overlay"></div>
359
+ <div class="vignette"></div>
360
+
361
+ <div class="app-wrapper">
362
+
363
+ <!-- Header -->
364
+ <header class="header">
365
+ <div class="header-eyebrow">AI Text Detector</div>
366
+ <h1 class="header-title"><span class="gradient-text">TeXray</span></h1>
367
+ <p class="header-subtitle">
368
+ <b>5μΆ• 앙상블 탐지</b> Β· <b>ν’ˆμ§ˆ μΈ‘μ •</b> Β· <b>LLM ꡐ차검증</b> Β· <b>Adversarial Humanizer</b> Β· <b>ν‘œμ ˆ 검사</b> Β· <b>λ¬Έμ„œ 뢄석</b>
369
+ </p>
370
+ <div class="pill-row">
371
+ <span class="pill">GPT-OSS 120B</span>
372
+ <span class="pill">Qwen3 32B</span>
373
+ <span class="pill">Kimi-K2</span>
374
+ <span class="pill">Brave + KCI + arXiv</span>
375
+ <span class="pill">PDFΒ·DOCXΒ·HWP</span>
376
+ <span class="pill"><span class="status-dot"></span>v4.0</span>
377
+ </div>
378
+ </header>
379
+
380
+ <!-- Nav -->
381
+ <nav class="nav">
382
+ <div class="nav-item active" data-tab="detect" onclick="switchTab('detect')"><span class="nav-icon">πŸ”</span><span>AI 뢄석</span></div>
383
+ <div class="nav-item" data-tab="highlight" onclick="switchTab('highlight')"><span class="nav-icon">🎨</span><span>ν•˜μ΄λΌμ΄νŠΈ</span></div>
384
+ <div class="nav-item" data-tab="humanize" onclick="switchTab('humanize')"><span class="nav-icon">βš”οΈ</span><span>AI→인간</span></div>
385
+ <div class="nav-item" data-tab="plagiarism" onclick="switchTab('plagiarism')"><span class="nav-icon">πŸ“‹</span><span>ν‘œμ ˆ</span></div>
386
+ <div class="nav-item" data-tab="document" onclick="switchTab('document')"><span class="nav-icon">πŸ“„</span><span>λ¬Έμ„œ</span></div>
387
+ </nav>
388
+
389
+ <!-- Panel 1 -->
390
+ <div class="panel active" id="panel-detect">
391
+ <div class="card">
392
+ <div class="card-header"><div class="card-icon purple">πŸ“„</div><div class="card-title">AI ν…μŠ€νŠΈ 뢄석</div></div>
393
+ <div class="card-desc">5μΆ• 앙상블(ν†΅κ³„Β·λ¬Έμ²΄Β·λ°˜λ³΅Β·κ΅¬μ‘°Β·μ§€λ¬Έ) + 6ν•­λͺ© ν’ˆμ§ˆ μΈ‘μ • + LLM 3λͺ¨λΈ κ΅μ°¨κ²€μ¦μœΌλ‘œ μ •λ°€ νŒλ³„ν•©λ‹ˆλ‹€.</div>
394
+ <div class="input-group"><div class="textarea-wrap">
395
+ <textarea id="input-detect" placeholder="AI νŒλ³„ν•  ν…μŠ€νŠΈλ₯Ό μž…λ ₯ν•˜μ„Έμš” (μ΅œμ†Œ 50자)" oninput="uc('input-detect','count-detect')"></textarea>
396
+ <div class="char-counter" id="count-detect">0자</div>
397
+ </div></div>
398
+ <div class="btn-group">
399
+ <button class="btn btn-primary" id="btn-detect" onclick="runDetect()">πŸš€ AI νŒλ³„ + ν’ˆμ§ˆ 뢄석</button>
400
+ <button class="btn btn-ghost" onclick="ls('input-detect','ai')">πŸ“ AI μ˜ˆμ‹œ</button>
401
+ <button class="btn btn-ghost" onclick="ls('input-detect','human')">✍️ 인간 μ˜ˆμ‹œ</button>
402
+ </div>
403
+ </div>
404
+ <div class="loader" id="loader-detect"><div class="loader-ring"></div><div class="loader-text">5μΆ• 뢄석 + LLM ꡐ차검증 쀑</div><div class="loader-dots"><span></span><span></span><span></span></div></div>
405
+ <div class="result-html" id="result-detect"></div><div class="log-box" id="log-detect"></div>
406
+ </div>
407
+
408
+ <!-- Panel 2 -->
409
+ <div class="panel" id="panel-highlight">
410
+ <div class="card">
411
+ <div class="card-header"><div class="card-icon teal">🎨</div><div class="card-title">λ¬Έμž₯별 ν•˜μ΄λΌμ΄νŠΈ</div></div>
412
+ <div class="card-desc">νƒ­1κ³Ό λ™μΌν•œ κΈ°μ€€μœΌλ‘œ λ¬Έμž₯별 AI ν™•λ₯ μ„ μƒ‰μƒμœΌλ‘œ ν‘œμ‹œν•©λ‹ˆλ‹€. 마우슀 μ˜€λ²„ μ‹œ νŒμ • κ·Όκ±°λ₯Ό ν™•μΈν•˜μ„Έμš”.</div>
413
+ <div class="input-group"><div class="textarea-wrap">
414
+ <textarea id="input-highlight" placeholder="λ¬Έμž₯별 AI ν™•λ₯  색상 ν‘œμ‹œ (μ΅œμ†Œ 30자)" oninput="uc('input-highlight','count-highlight')"></textarea>
415
+ <div class="char-counter" id="count-highlight">0자</div>
416
+ </div></div>
417
+ <div class="btn-group">
418
+ <button class="btn btn-primary" id="btn-highlight" onclick="runHighlight()">🎨 ν•˜μ΄λΌμ΄νŠΈ 뢄석</button>
419
+ <button class="btn btn-ghost" onclick="ls('input-highlight','ai')">πŸ“ AI μ˜ˆμ‹œ</button>
420
+ </div>
421
+ </div>
422
+ <div class="loader" id="loader-highlight"><div class="loader-ring"></div><div class="loader-text">λ¬Έμž₯ 뢄석 쀑</div><div class="loader-dots"><span></span><span></span><span></span></div></div>
423
+ <div class="result-html" id="result-highlight"></div>
424
+ </div>
425
+
426
+ <!-- Panel 3 -->
427
+ <div class="panel" id="panel-humanize">
428
+ <div class="card">
429
+ <div class="card-header"><div class="card-icon rose">βš”οΈ</div><div class="card-title">Adversarial Humanizer v2</div></div>
430
+ <div class="card-desc">탐지기 vs λ³€ν™˜κΈ° μžκΈ°λŒ€μ „ 루프. μ΅œλŒ€ 3λΌμš΄λ“œ 반볡 μ΅œμ ν™” β€” κ·œμΉ™/LLM/LLM+κ·œμΉ™ λ§€ λΌμš΄λ“œ 경쟁.</div>
431
+ <div class="input-group"><div class="textarea-wrap">
432
+ <textarea id="input-humanize" placeholder="AIκ°€ μž‘μ„±ν•œ ν…μŠ€νŠΈλ₯Ό μž…λ ₯ν•˜μ„Έμš” (μ΅œμ†Œ 50자)" oninput="uc('input-humanize','count-humanize')"></textarea>
433
+ <div class="char-counter" id="count-humanize">0자</div>
434
+ </div></div>
435
+ <div class="btn-group">
436
+ <button class="btn btn-primary" id="btn-humanize" onclick="runHumanize()">βš”οΈ μ λŒ€μ  λ³€ν™˜ + 검증</button>
437
+ <button class="btn btn-ghost" onclick="ls('input-humanize','ai')">πŸ“ AI μ˜ˆμ‹œ</button>
438
+ </div>
439
+ </div>
440
+ <div class="loader" id="loader-humanize"><div class="loader-ring"></div><div class="loader-text">κ·œμΉ™ β†’ LLM β†’ 3-way 비ꡐ β†’ 검증</div><div class="loader-dots"><span></span><span></span><span></span></div></div>
441
+ <div id="result-humanize-area" style="display:none;">
442
+ <div class="result-card">
443
+ <div class="result-card-title">βœ… λ³€ν™˜ μ™„λ£Œ</div>
444
+ <div class="converted-text" id="result-humanize-text"><button class="copy-btn" onclick="copyText()">COPY</button></div>
445
+ </div>
446
+ <div class="log-box" id="result-humanize-log"></div>
447
+ <div class="result-html" id="result-humanize-compare"></div>
448
+ </div>
449
+ </div>
450
+
451
+ <!-- Panel 4 -->
452
+ <div class="panel" id="panel-plagiarism">
453
+ <div class="card">
454
+ <div class="card-header"><div class="card-icon amber">πŸ“‹</div><div class="card-title">ν‘œμ ˆ 검사</div></div>
455
+ <div class="card-desc">Brave Search 병렬(μ΅œλŒ€ 20) + KCI Β· RISS Β· arXiv ν•™μˆ DB + Gemini Google Search 톡합 검사. API ν‚€ 없이도 자체 크둀링으둜 μž‘λ™ν•©λ‹ˆλ‹€.</div>
456
+ <div class="input-group"><div class="textarea-wrap">
457
+ <textarea id="input-plagiarism" placeholder="ν‘œμ ˆ 검사할 ν…μŠ€νŠΈλ₯Ό μž…λ ₯ν•˜μ„Έμš” (μ΅œμ†Œ 50자)" oninput="uc('input-plagiarism','count-plagiarism')"></textarea>
458
+ <div class="char-counter" id="count-plagiarism">0자</div>
459
+ </div></div>
460
+ <div class="btn-group">
461
+ <button class="btn btn-primary" id="btn-plagiarism" onclick="runPlagiarism()">πŸ“‹ ν‘œμ ˆ 검사 μ‹œμž‘</button>
462
+ <button class="btn btn-ghost" onclick="ls('input-plagiarism','ai')">πŸ“ AI μ˜ˆμ‹œ</button>
463
+ </div>
464
+ </div>
465
+ <div class="loader" id="loader-plagiarism"><div class="loader-ring"></div><div class="loader-text">웹검색 + ν•™μˆ DB + λ³΄κ³ μ„œ 생성</div><div class="loader-dots"><span></span><span></span><span></span></div></div>
466
+ <div id="result-plagiarism-area" style="display:none;">
467
+ <div class="result-html" id="result-plagiarism"></div>
468
+ <div class="log-box" id="result-plagiarism-log"></div>
469
+ </div>
470
+ </div>
471
+
472
+ <!-- Panel 5: Document Analysis -->
473
+ <div class="panel" id="panel-document">
474
+ <div class="card">
475
+ <div class="card-header"><div class="card-icon" style="background:rgba(84,181,255,0.12);border:1px solid rgba(84,181,255,0.2);">πŸ“„</div><div class="card-title">λ¬Έμ„œ AI 뢄석</div></div>
476
+ <div class="card-desc">PDF Β· DOCX Β· HWP Β· HWPX Β· TXT λ¬Έμ„œλ₯Ό μ—…λ‘œλ“œν•˜λ©΄ μ„Ήμ…˜λ³„ AI 탐지 히트맡 λ³΄κ³ μ„œλ₯Ό μƒμ„±ν•©λ‹ˆλ‹€.</div>
477
+ <div class="file-drop" id="file-drop" onclick="document.getElementById('file-input').click()">
478
+ <input type="file" id="file-input" accept=".pdf,.docx,.hwp,.hwpx,.txt,.md,.csv" onchange="handleFile(this)">
479
+ <div class="file-drop-icon">πŸ“‚</div>
480
+ <div class="file-drop-text">ν΄λ¦­ν•˜κ±°λ‚˜ νŒŒμΌμ„ λ“œλž˜κ·Έν•˜μ„Έμš”</div>
481
+ <div class="file-drop-hint">PDF Β· DOCX Β· HWP Β· HWPX Β· TXT Β· MD Β· CSV</div>
482
+ </div>
483
+ <div class="file-info" id="file-info">
484
+ <span>πŸ“Ž</span>
485
+ <span class="file-info-name" id="file-name"></span>
486
+ <span class="file-info-size" id="file-size"></span>
487
+ <span class="file-remove" onclick="clearFile()">βœ•</span>
488
+ </div>
489
+ <div style="margin-top:14px;">
490
+ <button class="btn btn-primary" id="btn-document" onclick="runDocument()">πŸ“„ λ¬Έμ„œ AI 뢄석</button>
491
+ </div>
492
+ </div>
493
+ <div class="loader" id="loader-document"><div class="loader-ring"></div><div class="loader-text">λ¬Έμ„œ μΆ”μΆœ + μ„Ήμ…˜λ³„ 뢄석 쀑</div><div class="loader-dots"><span></span><span></span><span></span></div></div>
494
+ <div id="result-document-area" style="display:none;">
495
+ <div class="result-html" id="result-document"></div>
496
+ <div class="log-box" id="result-document-log"></div>
497
+ </div>
498
+ </div>
499
+
500
+ <footer class="footer">
501
+ <div class="footer-brand">TeXray</div>
502
+ <div class="footer-line"></div>
503
+ <div class="footer-tech">KIWI Β· GROQ Β· BRAVE Β· KCI Β· RISS Β· ARXIV Β· GEMINI</div>
504
+ </footer>
505
+ </div>
506
+
507
+ <script>
508
+ /* ═══ MESH GRADIENT CANVAS (WebGL) ═══ */
509
+ (function(){
510
+ const c=document.getElementById('mesh-canvas');
511
+ const gl=c.getContext('webgl')||c.getContext('experimental-webgl');
512
+ if(!gl){
513
+ c.style.background='radial-gradient(ellipse at 20% 20%,rgba(139,122,255,0.08),transparent 50%),radial-gradient(ellipse at 80% 80%,rgba(61,214,200,0.06),transparent 50%),radial-gradient(ellipse at 50% 50%,rgba(255,107,138,0.04),transparent 40%)';
514
+ return;
515
+ }
516
+ function resize(){c.width=window.innerWidth;c.height=window.innerHeight;gl.viewport(0,0,c.width,c.height);}
517
+ resize();window.addEventListener('resize',resize);
518
+ const vs=`attribute vec2 p;void main(){gl_Position=vec4(p,0,1);}`;
519
+ const fs=`
520
+ precision mediump float;
521
+ uniform float t;
522
+ uniform vec2 r;
523
+ void main(){
524
+ vec2 u=gl_FragCoord.xy/r;
525
+ float n=sin(u.x*3.+t*0.3)*cos(u.y*2.5+t*0.2)*0.5+0.5;
526
+ float n2=cos(u.x*2.-t*0.15)*sin(u.y*3.5+t*0.25)*0.5+0.5;
527
+ float n3=sin((u.x+u.y)*2.+t*0.18)*0.5+0.5;
528
+ vec3 c1=vec3(0.545,0.478,1.0)*n*0.12;
529
+ vec3 c2=vec3(0.24,0.84,0.78)*n2*0.08;
530
+ vec3 c3=vec3(1.0,0.42,0.54)*n3*0.05;
531
+ float v=smoothstep(0.0,0.3,u.y)*smoothstep(1.0,0.7,u.y);
532
+ gl_FragColor=vec4((c1+c2+c3)*v,1.0);
533
+ }`;
534
+ function compile(src,type){const s=gl.createShader(type);gl.shaderSource(s,src);gl.compileShader(s);return s;}
535
+ const prog=gl.createProgram();
536
+ gl.attachShader(prog,compile(vs,gl.VERTEX_SHADER));
537
+ gl.attachShader(prog,compile(fs,gl.FRAGMENT_SHADER));
538
+ gl.linkProgram(prog);gl.useProgram(prog);
539
+ const buf=gl.createBuffer();
540
+ gl.bindBuffer(gl.ARRAY_BUFFER,buf);
541
+ gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),gl.STATIC_DRAW);
542
+ const pLoc=gl.getAttribLocation(prog,'p');
543
+ gl.enableVertexAttribArray(pLoc);
544
+ gl.vertexAttribPointer(pLoc,2,gl.FLOAT,false,0,0);
545
+ const tLoc=gl.getUniformLocation(prog,'t');
546
+ const rLoc=gl.getUniformLocation(prog,'r');
547
+ let start=performance.now();
548
+ function frame(){
549
+ const elapsed=(performance.now()-start)/1000;
550
+ gl.uniform1f(tLoc,elapsed);
551
+ gl.uniform2f(rLoc,c.width,c.height);
552
+ gl.drawArrays(gl.TRIANGLE_STRIP,0,4);
553
+ requestAnimationFrame(frame);
554
+ }
555
+ frame();
556
+ })();
557
+
558
+ /* ═══ API ═══ */
559
+ const B=window.location.origin;
560
+ const SA=`인곡지λŠ₯ κΈ°μˆ μ€ ν˜„λŒ€ μ‚¬νšŒμ—μ„œ 맀우 μ€‘μš”ν•œ 역할을 ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 특히 μžμ—°μ–΄ 처리 λΆ„μ•Όμ—μ„œμ˜ λ°œμ „μ€ λˆˆλΆ€μ‹  μ„±κ³Όλ₯Ό 거두고 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ 기술의 λ°œμ „μ€ λ‹€μ–‘ν•œ μ‚°μ—… 뢄야에 긍정적인 영ν–₯을 미치고 있으며, ν–₯ν›„ λ”μš± λ°œμ „ν•  κ²ƒμœΌλ‘œ μ˜ˆμƒλ©λ‹ˆλ‹€.\n\nλ˜ν•œ μƒμ„±ν˜• AI의 λ“±μž₯으둜 μ½˜ν…μΈ  μ œμž‘ 방식이 크게 λ³€ν™”ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό 톡해 기업듀은 효율적인 μ½˜ν…μΈ  생산이 κ°€λŠ₯ν•΄μ‘ŒμœΌλ©°, 개인 μ‚¬μš©μžλ“€λ„ λ‹€μ–‘ν•œ μ°½μž‘ ν™œλ™μ— AIλ₯Ό ν™œμš©ν•  수 있게 λ˜μ—ˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ AI λ¦¬ν„°λŸ¬μ‹œμ˜ μ€‘μš”μ„±μ΄ λ”μš± λΆ€κ°λ˜κ³  μžˆμŠ΅λ‹ˆλ‹€.\n\nλ‚˜μ•„κ°€ AI μœ€λ¦¬μ™€ κ·œμ œμ— λŒ€ν•œ λ…Όμ˜λ„ ν™œλ°œνžˆ μ§„ν–‰λ˜κ³  μžˆμŠ΅λ‹ˆλ‹€.`;
561
+ const SH=`μ•„ μ§„μ§œ μš”μ¦˜ AI λ•Œλ¬Έμ— 머리 μ•„ν”„λ‹€γ…‹γ…‹γ…‹ μ–΄μ œ chatgptν•œν…Œ 레포트 써달라고 ν–ˆλŠ”λ° μ™„μ „ κ΅κ³Όμ„œ 같은 κΈ€λ§Œ μ¨μ€˜μ„œ κ·Έλƒ₯ λ‚΄κ°€ λ‹€μ‹œ 썼음;;\n\n근데 생각해보면 AIκ°€ μ“΄ κΈ€μ΄λž‘ μ‚¬λžŒμ΄ μ“΄ 글이 ν™•μ‹€νžˆ λ‹€λ₯΄κΈ΄ ν•΄. λ­”κ°€... λ„ˆλ¬΄ κΉ”λ”ν•˜λ‹¬κΉŒ?\n\nκ΅μˆ˜λ‹˜μ΄ AI 탐지기 λŒλ¦°λ‹€κ³  ν•΄μ„œ μ’€ λ¬΄μ„œμš΄λ° γ… γ…  κ±±μ •λœλ‹€ μ§„μ‹¬μœΌλ‘œ.`;
562
+
563
+ function switchTab(t){
564
+ document.querySelectorAll('.nav-item').forEach(e=>e.classList.remove('active'));
565
+ document.querySelectorAll('.panel').forEach(e=>e.classList.remove('active'));
566
+ document.querySelector(`[data-tab="${t}"]`).classList.add('active');
567
+ document.getElementById(`panel-${t}`).classList.add('active');
568
+ }
569
+ function uc(a,b){document.getElementById(b).textContent=document.getElementById(a).value.length+'자';}
570
+ function ls(id,t){const e=document.getElementById(id);e.value=t==='ai'?SA:SH;e.dispatchEvent(new Event('input'));}
571
+ function sw(id){document.getElementById(id).classList.add('active');}
572
+ function hw(id){document.getElementById(id).classList.remove('active');}
573
+
574
+ async function gc(api,data){
575
+ const urls=[`${B}/gradio/gradio_api/call${api}`,`${B}/gradio/api${api}`,`${B}/gradio_api/call${api}`,`${B}/api${api}`];
576
+ for(const u of urls){
577
+ try{
578
+ const r=await fetch(u,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({data})});
579
+ if(!r.ok)continue;
580
+ const j=await r.json();if(!j.event_id)continue;
581
+ return new Promise((ok,no)=>{
582
+ const es=new EventSource(`${u}/${j.event_id}`);let d=false;
583
+ const handle=e=>{if(d)return;try{const raw=JSON.parse(e.data);const p=Array.isArray(raw)?raw:(raw&&raw.data?raw.data:null);if(p){d=true;es.close();ok(p);}}catch{}};
584
+ es.onmessage=handle;
585
+ es.addEventListener('complete',handle);
586
+ es.addEventListener('process_completed',e=>{if(d)return;try{const raw=JSON.parse(e.data);const out=raw&&raw.output&&raw.output.data?raw.output.data:null;if(out){d=true;es.close();ok(out);}}catch{}});
587
+ es.onerror=()=>{if(!d){d=true;es.close();no(new Error('μ—°κ²° 였λ₯˜'));}};
588
+ setTimeout(()=>{if(!d){d=true;es.close();no(new Error('μ‹œκ°„ 초과 (120s)'));}},120000);
589
+ });
590
+ }catch(e){continue;}
591
+ }
592
+ throw new Error('API μ—°κ²° μ‹€νŒ¨ β€” Gradio μ„œλ²„ 확인 ν•„μš”');
593
+ }
594
+
595
+ function showError(el,msg){
596
+ el.innerHTML=`<div style="padding:28px;text-align:center;color:var(--rose);font-size:14px;background:var(--glass);border:1px solid rgba(255,107,138,0.2);border-radius:var(--radius);">⚠️ ${msg}</div>`;
597
+ }
598
+
599
+ async function runDetect(){
600
+ const t=document.getElementById('input-detect').value;if(!t||t.length<50){alert('μ΅œμ†Œ 50자 이상 μž…λ ₯ν•΄μ£Όμ„Έμš”.');return;}
601
+ const b=document.getElementById('btn-detect');b.disabled=true;
602
+ document.getElementById('result-detect').innerHTML='';document.getElementById('log-detect').textContent='';sw('loader-detect');
603
+ try{const d=await gc('/run_detection',[t]);hw('loader-detect');document.getElementById('result-detect').innerHTML=d[0]||'';document.getElementById('log-detect').textContent=d[1]||'';}
604
+ catch(e){hw('loader-detect');showError(document.getElementById('result-detect'),e.message);}
605
+ b.disabled=false;
606
+ }
607
+ async function runHighlight(){
608
+ const t=document.getElementById('input-highlight').value;if(!t||t.length<30){alert('ν…μŠ€νŠΈλ₯Ό μž…λ ₯ν•΄μ£Όμ„Έμš”.');return;}
609
+ const b=document.getElementById('btn-highlight');b.disabled=true;sw('loader-highlight');
610
+ try{const d=await gc('/run_highlight',[t]);hw('loader-highlight');document.getElementById('result-highlight').innerHTML=d[0]||'';}
611
+ catch(e){hw('loader-highlight');showError(document.getElementById('result-highlight'),e.message);}
612
+ b.disabled=false;
613
+ }
614
+ async function runHumanize(){
615
+ const t=document.getElementById('input-humanize').value;if(!t||t.length<50){alert('μ΅œμ†Œ 50자 이상 μž…λ ₯ν•΄μ£Όμ„Έμš”.');return;}
616
+ const b=document.getElementById('btn-humanize');b.disabled=true;document.getElementById('result-humanize-area').style.display='none';sw('loader-humanize');
617
+ try{const d=await gc('/run_humanizer',[t]);hw('loader-humanize');document.getElementById('result-humanize-area').style.display='block';
618
+ const el=document.getElementById('result-humanize-text');el.innerHTML=`<button class="copy-btn" onclick="copyText()">COPY</button>${(d[0]||'').replace(/\n/g,'<br>')}`;
619
+ document.getElementById('result-humanize-log').textContent=d[1]||'';document.getElementById('result-humanize-compare').innerHTML=d[2]||'';}
620
+ catch(e){hw('loader-humanize');document.getElementById('result-humanize-area').style.display='block';showError(document.getElementById('result-humanize-text'),e.message);}
621
+ b.disabled=false;
622
+ }
623
+ async function runPlagiarism(){
624
+ const t=document.getElementById('input-plagiarism').value;if(!t||t.length<50){alert('μ΅œμ†Œ 50자 이상 μž…λ ₯ν•΄μ£Όμ„Έμš”.');return;}
625
+ const b=document.getElementById('btn-plagiarism');b.disabled=true;document.getElementById('result-plagiarism-area').style.display='none';sw('loader-plagiarism');
626
+ try{const d=await gc('/run_plagiarism',[t]);hw('loader-plagiarism');document.getElementById('result-plagiarism-area').style.display='block';
627
+ document.getElementById('result-plagiarism').innerHTML=d[0]||'';document.getElementById('result-plagiarism-log').textContent=d[1]||'';}
628
+ catch(e){hw('loader-plagiarism');document.getElementById('result-plagiarism-area').style.display='block';showError(document.getElementById('result-plagiarism'),e.message);}
629
+ b.disabled=false;
630
+ }
631
+ function copyText(){
632
+ const el=document.getElementById('result-humanize-text');
633
+ const t=el.textContent.replace('COPY','').replace('βœ“ COPIED','').trim();
634
+ navigator.clipboard.writeText(t).then(()=>{
635
+ const btn=el.querySelector('.copy-btn');btn.textContent='βœ“ COPIED';btn.classList.add('copied');
636
+ setTimeout(()=>{btn.textContent='COPY';btn.classList.remove('copied');},2000);
637
+ });
638
+ }
639
+ /* Ctrl+Enter shortcut */
640
+ document.addEventListener('keydown',e=>{
641
+ if(e.ctrlKey&&e.key==='Enter'){
642
+ const active=document.querySelector('.panel.active');
643
+ if(!active)return;
644
+ const btn=active.querySelector('.btn-primary');
645
+ if(btn&&!btn.disabled)btn.click();
646
+ }
647
+ });
648
+
649
+ /* ═══ DOCUMENT UPLOAD ═══ */
650
+ let selectedFile=null;
651
+ function handleFile(input){
652
+ if(input.files&&input.files[0]){
653
+ selectedFile=input.files[0];
654
+ document.getElementById('file-label').textContent='πŸ“Ž '+selectedFile.name+' ('+Math.round(selectedFile.size/1024)+'KB)';
655
+ document.getElementById('drop-zone').style.borderColor='rgba(139,122,255,0.4)';
656
+ }
657
+ }
658
+ /* Drag & drop */
659
+ const dz=document.getElementById('drop-zone');
660
+ if(dz){
661
+ dz.addEventListener('dragover',e=>{e.preventDefault();dz.style.borderColor='rgba(139,122,255,0.6)';dz.style.background='rgba(139,122,255,0.05)';});
662
+ dz.addEventListener('dragleave',()=>{dz.style.borderColor='';dz.style.background='';});
663
+ dz.addEventListener('drop',e=>{e.preventDefault();dz.style.borderColor='';dz.style.background='';
664
+ if(e.dataTransfer.files[0]){selectedFile=e.dataTransfer.files[0];document.getElementById('file-label').textContent='πŸ“Ž '+selectedFile.name;dz.style.borderColor='rgba(139,122,255,0.4)';}
665
+ });
666
+ }
667
+
668
+ async function runDocument(){
669
+ if(!selectedFile){alert('νŒŒμΌμ„ λ¨Όμ € μ—…λ‘œλ“œν•˜μ„Έμš”.');return;}
670
+ const btn=document.getElementById('btn-document');btn.disabled=true;
671
+ document.getElementById('result-document-area').style.display='none';
672
+ document.getElementById('report-download').style.display='none';
673
+ sw('loader-document');
674
+ try{
675
+ /* Step 1: Upload file to Gradio */
676
+ const formData=new FormData();formData.append('files',selectedFile);
677
+ const uploadUrls=[`${B}/gradio/gradio_api/upload`,`${B}/gradio/upload`,`${B}/gradio_api/upload`,`${B}/upload`];
678
+ let uploadedPath=null;
679
+ for(const uu of uploadUrls){
680
+ try{
681
+ const ur=await fetch(uu,{method:'POST',body:formData});
682
+ if(ur.ok){const uj=await ur.json();uploadedPath=Array.isArray(uj)?uj[0]:uj;break;}
683
+ }catch{}
684
+ }
685
+ if(!uploadedPath){throw new Error('파일 μ—…λ‘œλ“œ μ‹€νŒ¨');}
686
+
687
+ /* Step 2: Call API with file path */
688
+ const d=await gc('/run_document',[uploadedPath]);
689
+ hw('loader-document');
690
+ document.getElementById('result-document-area').style.display='block';
691
+ document.getElementById('result-document').innerHTML=d[0]||'';
692
+ document.getElementById('result-document-log').textContent=d[1]||'';
693
+ /* Step 3: Report download link */
694
+ if(d[2]){
695
+ const dl=document.getElementById('report-download');
696
+ dl.href=`${B}/gradio/gradio_api/file=`+encodeURIComponent(d[2]);
697
+ dl.style.display='inline-block';
698
+ dl.download='AI_Report.html';
699
+ }
700
+ }catch(e){
701
+ hw('loader-document');
702
+ document.getElementById('result-document-area').style.display='block';
703
+ showError(document.getElementById('result-document'),e.message);
704
+ }
705
+ btn.disabled=false;
706
+ }
707
+ </script>
708
+ </body>
709
+ </html>