seawolf2357 commited on
Commit
d670d77
·
1 Parent(s): 81d6263

Delete chatbot.js

Browse files
Files changed (1) hide show
  1. chatbot.js +0 -496
chatbot.js DELETED
@@ -1,496 +0,0 @@
1
- /**
2
- * HumanGen.AI Chatbot Module
3
- * Static Space에서 Gradio 백엔드를 호출하는 챗봇
4
- *
5
- * 사용법: index.html 끝에 아래 스크립트 태그 추가
6
- * <script type="module" src="chatbot.js"></script>
7
- */
8
-
9
- import { Client } from "https://esm.sh/@gradio/client@1.4.0";
10
-
11
- // ============================================
12
- // 설정 - 본인의 Gradio Space 주소로 변경하세요!
13
- // ============================================
14
- const GRADIO_SPACE = "Heartsync/humangen-chatbot"; // 예: "seawolf2357/humangen-chatbot"
15
-
16
- // ============================================
17
- // 챗봇 UI 스타일
18
- // ============================================
19
- const chatbotStyles = `
20
- <style>
21
- /* 챗봇 컨테이너 */
22
- #hg-chatbot-container {
23
- position: fixed;
24
- bottom: 100px;
25
- right: 20px;
26
- z-index: 10000;
27
- font-family: 'Comic Neue', cursive, sans-serif;
28
- }
29
-
30
- /* 챗봇 토글 버튼 */
31
- #hg-chat-toggle {
32
- width: 65px;
33
- height: 65px;
34
- border-radius: 50%;
35
- background: linear-gradient(135deg, #3B82F6 0%, #8B5CF6 100%);
36
- border: 3px solid #1F2937;
37
- box-shadow: 4px 4px 0px #1F2937;
38
- cursor: pointer;
39
- display: flex;
40
- align-items: center;
41
- justify-content: center;
42
- font-size: 28px;
43
- transition: all 0.2s ease;
44
- animation: hg-pulse 2s infinite;
45
- }
46
-
47
- #hg-chat-toggle:hover {
48
- transform: translate(-2px, -2px);
49
- box-shadow: 6px 6px 0px #1F2937;
50
- }
51
-
52
- @keyframes hg-pulse {
53
- 0%, 100% { box-shadow: 4px 4px 0px #1F2937, 0 0 0 0 rgba(59, 130, 246, 0.4); }
54
- 50% { box-shadow: 4px 4px 0px #1F2937, 0 0 0 10px rgba(59, 130, 246, 0); }
55
- }
56
-
57
- /* 챗봇 윈도우 */
58
- #hg-chat-window {
59
- display: none;
60
- position: absolute;
61
- bottom: 80px;
62
- right: 0;
63
- width: 380px;
64
- max-width: calc(100vw - 40px);
65
- background: #FFFFFF;
66
- border: 3px solid #1F2937;
67
- border-radius: 16px;
68
- box-shadow: 8px 8px 0px #1F2937;
69
- overflow: hidden;
70
- animation: hg-slideUp 0.3s ease;
71
- }
72
-
73
- @keyframes hg-slideUp {
74
- from { opacity: 0; transform: translateY(20px); }
75
- to { opacity: 1; transform: translateY(0); }
76
- }
77
-
78
- /* 헤더 */
79
- #hg-chat-header {
80
- background: linear-gradient(135deg, #3B82F6 0%, #8B5CF6 100%);
81
- color: white;
82
- padding: 15px 20px;
83
- display: flex;
84
- justify-content: space-between;
85
- align-items: center;
86
- border-bottom: 3px solid #1F2937;
87
- }
88
-
89
- #hg-chat-header h3 {
90
- margin: 0;
91
- font-family: 'Bangers', cursive;
92
- font-size: 1.3rem;
93
- letter-spacing: 1px;
94
- text-shadow: 2px 2px 0px rgba(0,0,0,0.3);
95
- }
96
-
97
- #hg-chat-close {
98
- background: none;
99
- border: none;
100
- color: white;
101
- font-size: 24px;
102
- cursor: pointer;
103
- padding: 0;
104
- line-height: 1;
105
- }
106
-
107
- /* 메시지 영역 */
108
- #hg-chat-messages {
109
- height: 350px;
110
- overflow-y: auto;
111
- padding: 15px;
112
- background: #FEF9C3;
113
- background-image: radial-gradient(#1F2937 1px, transparent 1px);
114
- background-size: 15px 15px;
115
- }
116
-
117
- /* 메시지 스타일 */
118
- .hg-message {
119
- margin-bottom: 12px;
120
- display: flex;
121
- flex-direction: column;
122
- }
123
-
124
- .hg-message.user {
125
- align-items: flex-end;
126
- }
127
-
128
- .hg-message.bot {
129
- align-items: flex-start;
130
- }
131
-
132
- .hg-message-bubble {
133
- max-width: 85%;
134
- padding: 12px 16px;
135
- border-radius: 12px;
136
- border: 2px solid #1F2937;
137
- box-shadow: 3px 3px 0px #1F2937;
138
- font-size: 0.95rem;
139
- line-height: 1.5;
140
- word-wrap: break-word;
141
- }
142
-
143
- .hg-message.user .hg-message-bubble {
144
- background: linear-gradient(135deg, #3B82F6 0%, #8B5CF6 100%);
145
- color: white;
146
- border-radius: 12px 12px 0 12px;
147
- }
148
-
149
- .hg-message.bot .hg-message-bubble {
150
- background: white;
151
- color: #1F2937;
152
- border-radius: 12px 12px 12px 0;
153
- }
154
-
155
- /* 타이핑 인디케이터 */
156
- .hg-typing {
157
- display: flex;
158
- gap: 4px;
159
- padding: 8px 12px;
160
- }
161
-
162
- .hg-typing span {
163
- width: 8px;
164
- height: 8px;
165
- background: #3B82F6;
166
- border-radius: 50%;
167
- animation: hg-bounce 1.4s infinite ease-in-out;
168
- }
169
-
170
- .hg-typing span:nth-child(1) { animation-delay: 0s; }
171
- .hg-typing span:nth-child(2) { animation-delay: 0.2s; }
172
- .hg-typing span:nth-child(3) { animation-delay: 0.4s; }
173
-
174
- @keyframes hg-bounce {
175
- 0%, 80%, 100% { transform: scale(0); }
176
- 40% { transform: scale(1); }
177
- }
178
-
179
- /* 입력 영역 */
180
- #hg-chat-input-area {
181
- padding: 15px;
182
- border-top: 3px solid #1F2937;
183
- background: white;
184
- display: flex;
185
- gap: 10px;
186
- }
187
-
188
- #hg-chat-input {
189
- flex: 1;
190
- padding: 12px 15px;
191
- border: 2px solid #1F2937;
192
- border-radius: 8px;
193
- font-family: 'Comic Neue', cursive;
194
- font-size: 1rem;
195
- outline: none;
196
- transition: all 0.2s;
197
- }
198
-
199
- #hg-chat-input:focus {
200
- border-color: #3B82F6;
201
- box-shadow: 3px 3px 0px #3B82F6;
202
- }
203
-
204
- #hg-chat-send {
205
- padding: 12px 20px;
206
- background: linear-gradient(135deg, #3B82F6 0%, #8B5CF6 100%);
207
- color: white;
208
- border: 2px solid #1F2937;
209
- border-radius: 8px;
210
- font-family: 'Bangers', cursive;
211
- font-size: 1.1rem;
212
- cursor: pointer;
213
- box-shadow: 3px 3px 0px #1F2937;
214
- transition: all 0.15s;
215
- }
216
-
217
- #hg-chat-send:hover {
218
- transform: translate(-2px, -2px);
219
- box-shadow: 5px 5px 0px #1F2937;
220
- }
221
-
222
- #hg-chat-send:active {
223
- transform: translate(1px, 1px);
224
- box-shadow: 2px 2px 0px #1F2937;
225
- }
226
-
227
- #hg-chat-send:disabled {
228
- opacity: 0.6;
229
- cursor: not-allowed;
230
- }
231
-
232
- /* 빠른 질문 버튼 */
233
- #hg-quick-questions {
234
- padding: 10px 15px;
235
- background: #F3F4F6;
236
- border-top: 2px dashed #D1D5DB;
237
- display: flex;
238
- flex-wrap: wrap;
239
- gap: 6px;
240
- }
241
-
242
- .hg-quick-btn {
243
- padding: 6px 12px;
244
- background: white;
245
- border: 2px solid #1F2937;
246
- border-radius: 20px;
247
- font-size: 0.8rem;
248
- font-weight: 700;
249
- cursor: pointer;
250
- transition: all 0.15s;
251
- }
252
-
253
- .hg-quick-btn:hover {
254
- background: #FACC15;
255
- transform: translateY(-2px);
256
- }
257
-
258
- /* 모바일 반응형 */
259
- @media (max-width: 480px) {
260
- #hg-chat-window {
261
- width: calc(100vw - 30px);
262
- right: -5px;
263
- bottom: 75px;
264
- }
265
-
266
- #hg-chat-messages {
267
- height: 300px;
268
- }
269
- }
270
- </style>
271
- `;
272
-
273
- // ============================================
274
- // 챗봇 HTML 구조
275
- // ============================================
276
- const chatbotHTML = `
277
- <div id="hg-chatbot-container">
278
- <!-- 토글 버튼 -->
279
- <div id="hg-chat-toggle" title="AI 도우미와 대화하기">
280
- 💬
281
- </div>
282
-
283
- <!-- 챗봇 윈도우 -->
284
- <div id="hg-chat-window">
285
- <div id="hg-chat-header">
286
- <h3>🤖 AI 도우미</h3>
287
- <button id="hg-chat-close">✕</button>
288
- </div>
289
-
290
- <div id="hg-chat-messages">
291
- <div class="hg-message bot">
292
- <div class="hg-message-bubble">
293
- 안녕하세요! 👋 HumanGen.AI에 대해 궁금한 것이 있으시면 물어보세요!
294
- </div>
295
- </div>
296
- </div>
297
-
298
- <div id="hg-quick-questions">
299
- <button class="hg-quick-btn">서비스 종류</button>
300
- <button class="hg-quick-btn">이미지 생성</button>
301
- <button class="hg-quick-btn">비디오 생성</button>
302
- <button class="hg-quick-btn">한국어 지원</button>
303
- <button class="hg-quick-btn">요금 문의</button>
304
- </div>
305
-
306
- <div id="hg-chat-input-area">
307
- <input type="text" id="hg-chat-input" placeholder="메시지를 입력하세요..." autocomplete="off">
308
- <button id="hg-chat-send">전송</button>
309
- </div>
310
- </div>
311
- </div>
312
- `;
313
-
314
- // ============================================
315
- // 챗봇 클래스
316
- // ============================================
317
- class HumanGenChatbot {
318
- constructor() {
319
- this.client = null;
320
- this.history = [];
321
- this.isOpen = false;
322
- this.isLoading = false;
323
-
324
- this.init();
325
- }
326
-
327
- async init() {
328
- // 스타일 & HTML 삽입
329
- document.head.insertAdjacentHTML('beforeend', chatbotStyles);
330
- document.body.insertAdjacentHTML('beforeend', chatbotHTML);
331
-
332
- // DOM 요소
333
- this.container = document.getElementById('hg-chatbot-container');
334
- this.toggle = document.getElementById('hg-chat-toggle');
335
- this.window = document.getElementById('hg-chat-window');
336
- this.closeBtn = document.getElementById('hg-chat-close');
337
- this.messages = document.getElementById('hg-chat-messages');
338
- this.input = document.getElementById('hg-chat-input');
339
- this.sendBtn = document.getElementById('hg-chat-send');
340
- this.quickBtns = document.querySelectorAll('.hg-quick-btn');
341
-
342
- // 이벤트 바인딩
343
- this.toggle.addEventListener('click', () => this.toggleChat());
344
- this.closeBtn.addEventListener('click', () => this.toggleChat());
345
- this.sendBtn.addEventListener('click', () => this.sendMessage());
346
- this.input.addEventListener('keypress', (e) => {
347
- if (e.key === 'Enter' && !e.shiftKey) {
348
- e.preventDefault();
349
- this.sendMessage();
350
- }
351
- });
352
-
353
- // 빠른 질문 버튼
354
- this.quickBtns.forEach(btn => {
355
- btn.addEventListener('click', () => {
356
- this.input.value = btn.textContent + ' 알려줘';
357
- this.sendMessage();
358
- });
359
- });
360
-
361
- // Gradio 클라이언트 연결
362
- try {
363
- this.client = await Client.connect(GRADIO_SPACE);
364
- console.log('✅ HumanGen Chatbot 연결 성공');
365
-
366
- // 사용 가능한 API 엔드포인트 확인 (디버깅용)
367
- try {
368
- const apiInfo = await this.client.view_api();
369
- console.log('📡 사용 가능한 API:', apiInfo);
370
- } catch (e) {
371
- console.log('API 정보 조회 불가');
372
- }
373
- } catch (error) {
374
- console.error('❌ Chatbot 연결 실패:', error);
375
- this.showError('챗봇 서버 연결에 실패했습니다. 잠시 후 다시 시도해주세요.');
376
- }
377
- }
378
-
379
- toggleChat() {
380
- this.isOpen = !this.isOpen;
381
- this.window.style.display = this.isOpen ? 'block' : 'none';
382
- this.toggle.innerHTML = this.isOpen ? '✕' : '💬';
383
-
384
- if (this.isOpen) {
385
- this.input.focus();
386
- }
387
- }
388
-
389
- addMessage(content, isUser = false) {
390
- const messageDiv = document.createElement('div');
391
- messageDiv.className = `hg-message ${isUser ? 'user' : 'bot'}`;
392
- messageDiv.innerHTML = `<div class="hg-message-bubble">${this.formatMessage(content)}</div>`;
393
- this.messages.appendChild(messageDiv);
394
- this.scrollToBottom();
395
- }
396
-
397
- formatMessage(text) {
398
- // 마크다운 스타일 포맷팅
399
- return text
400
- .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
401
- .replace(/\*(.*?)\*/g, '<em>$1</em>')
402
- .replace(/`(.*?)`/g, '<code style="background:#F3F4F6;padding:2px 6px;border-radius:4px;">$1</code>')
403
- .replace(/(https?:\/\/[^\s]+)/g, '<a href="$1" target="_blank" style="color:#3B82F6;">$1</a>')
404
- .replace(/([a-z0-9-]+\.humangen\.ai)/gi, '<a href="https://$1" target="_blank" style="color:#3B82F6;font-weight:700;">$1</a>')
405
- .replace(/\n/g, '<br>');
406
- }
407
-
408
- showTyping() {
409
- const typingDiv = document.createElement('div');
410
- typingDiv.className = 'hg-message bot';
411
- typingDiv.id = 'hg-typing-indicator';
412
- typingDiv.innerHTML = `
413
- <div class="hg-message-bubble">
414
- <div class="hg-typing">
415
- <span></span><span></span><span></span>
416
- </div>
417
- </div>
418
- `;
419
- this.messages.appendChild(typingDiv);
420
- this.scrollToBottom();
421
- }
422
-
423
- hideTyping() {
424
- const typing = document.getElementById('hg-typing-indicator');
425
- if (typing) typing.remove();
426
- }
427
-
428
- showError(message) {
429
- this.addMessage(`⚠️ ${message}`, false);
430
- }
431
-
432
- scrollToBottom() {
433
- this.messages.scrollTop = this.messages.scrollHeight;
434
- }
435
-
436
- async sendMessage() {
437
- const message = this.input.value.trim();
438
- if (!message || this.isLoading) return;
439
-
440
- // 사용자 메시지 표시
441
- this.addMessage(message, true);
442
- this.input.value = '';
443
-
444
- // 로딩 상태
445
- this.isLoading = true;
446
- this.sendBtn.disabled = true;
447
- this.showTyping();
448
-
449
- try {
450
- if (!this.client) {
451
- throw new Error('서버에 연결되지 않았습니다.');
452
- }
453
-
454
- // Gradio API 호출 - /chat 엔드포인트, message만 전달
455
- const result = await this.client.predict("/chat", {
456
- message: message
457
- });
458
-
459
- this.hideTyping();
460
- console.log('API 응답:', result);
461
-
462
- // 응답 처리 - result.data가 문자열
463
- if (result.data) {
464
- this.addMessage(result.data, false);
465
- this.history.push([message, result.data]);
466
- } else {
467
- this.addMessage('응답을 받지 못했습니다.', false);
468
- }
469
-
470
- } catch (error) {
471
- console.error('메시지 전송 오류:', error);
472
- this.hideTyping();
473
- this.showError('메시지 전송에 실패했습니다: ' + error.message);
474
- } finally {
475
- this.isLoading = false;
476
- this.sendBtn.disabled = false;
477
- this.input.focus();
478
- }
479
- }
480
- }
481
-
482
- // ============================================
483
- // 초기화
484
- // ============================================
485
- document.addEventListener('DOMContentLoaded', () => {
486
- window.humangenChatbot = new HumanGenChatbot();
487
- });
488
-
489
- // 페이지 로드 후 바로 실행 (DOMContentLoaded 이미 발생한 경우)
490
- if (document.readyState === 'complete' || document.readyState === 'interactive') {
491
- setTimeout(() => {
492
- if (!window.humangenChatbot) {
493
- window.humangenChatbot = new HumanGenChatbot();
494
- }
495
- }, 100);
496
- }