mistpe commited on
Commit
7024ee0
1 Parent(s): 59bfb9e

Create index.html

Browse files
Files changed (1) hide show
  1. index.html +517 -0
index.html ADDED
@@ -0,0 +1,517 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>AI 对话系统</title>
7
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
8
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet">
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-dark.min.css">
10
+ <style>
11
+ :root {
12
+ --primary-color: #3498db;
13
+ --secondary-color: #2ecc71;
14
+ --background-color: #f5f5f5;
15
+ --chat-background: #ffffff;
16
+ --text-color: #333333;
17
+ --chat-bubble-user: #e8f5fe;
18
+ --chat-bubble-ai: #f0f0f0;
19
+ --sidebar-background: #ffffff;
20
+ --input-background: #ffffff;
21
+ --send-button-color: #4CAF50;
22
+ --console-background: #f8f9fa;
23
+ --console-text: #495057;
24
+ --fold-background: #f8f9fa;
25
+ --fold-text: #495057;
26
+ --border-color: transparent;
27
+ --search-result-background: #f8f9fa;
28
+ }
29
+ .dark-mode {
30
+ --primary-color: #3498db;
31
+ --secondary-color: #2ecc71;
32
+ --background-color: #1e2124;
33
+ --chat-background: #36393f;
34
+ --text-color: #dcddde;
35
+ --chat-bubble-user: #4e5d94;
36
+ --chat-bubble-ai: #40444b;
37
+ --sidebar-background: #2f3136;
38
+ --input-background: #40444b;
39
+ --send-button-color: #7289da;
40
+ --console-background: #2f3136;
41
+ --console-text: #dcddde;
42
+ --fold-background: #2f3136;
43
+ --fold-text: #dcddde;
44
+ --border-color: #ffffff;
45
+ --search-result-background: #2f3136;
46
+ }
47
+ body {
48
+ background-color: var(--background-color);
49
+ color: var(--text-color);
50
+ transition: all 0.3s ease;
51
+ }
52
+ .chat-container {
53
+ background-color: var(--chat-background);
54
+ transition: all 0.3s ease;
55
+ border-radius: 8px;
56
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
57
+ }
58
+ .chat-bubble {
59
+ max-width: 80%;
60
+ padding: 12px;
61
+ border-radius: 12px;
62
+ margin-bottom: 12px;
63
+ box-shadow: 0 1px 2px rgba(0,0,0,0.1);
64
+ transition: all 0.3s ease;
65
+ }
66
+ .user-bubble {
67
+ background-color: var(--chat-bubble-user);
68
+ color: var(--text-color);
69
+ margin-left: auto;
70
+ border-bottom-right-radius: 4px;
71
+ }
72
+ .ai-bubble {
73
+ background-color: var(--chat-bubble-ai);
74
+ color: var(--text-color);
75
+ margin-right: auto;
76
+ border-bottom-left-radius: 4px;
77
+ }
78
+ .dark-mode .chat-bubble {
79
+ border: 1px solid var(--border-color);
80
+ }
81
+ .status-indicator {
82
+ width: 12px;
83
+ height: 12px;
84
+ border-radius: 50%;
85
+ display: inline-block;
86
+ margin-right: 8px;
87
+ transition: all 0.3s ease;
88
+ }
89
+ .status-active {
90
+ background-color: var(--secondary-color);
91
+ }
92
+ .status-inactive {
93
+ background-color: #95a5a6;
94
+ }
95
+ .sidebar {
96
+ background-color: var(--sidebar-background);
97
+ transition: all 0.3s ease;
98
+ border-radius: 8px;
99
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
100
+ }
101
+ #user-input {
102
+ background-color: var(--input-background);
103
+ color: var(--text-color);
104
+ transition: all 0.3s ease;
105
+ border-radius: 8px;
106
+ padding-right: 40px;
107
+ }
108
+ #send-btn {
109
+ position: absolute;
110
+ right: 10px;
111
+ top: 50%;
112
+ transform: translateY(-50%);
113
+ background: none;
114
+ border: none;
115
+ color: var(--send-button-color);
116
+ font-size: 20px;
117
+ cursor: pointer;
118
+ transition: all 0.3s ease;
119
+ }
120
+ #send-btn:hover {
121
+ opacity: 0.8;
122
+ }
123
+ .console {
124
+ background-color: var(--console-background);
125
+ color: var(--console-text);
126
+ transition: all 0.3s ease;
127
+ border-radius: 8px;
128
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
129
+ }
130
+ #status-log {
131
+ background-color: var(--console-background);
132
+ color: var(--console-text);
133
+ transition: all 0.3s ease;
134
+ border: 1px solid var(--border-color);
135
+ }
136
+ /* 滚动条样式 */
137
+ ::-webkit-scrollbar {
138
+ width: 8px;
139
+ }
140
+ ::-webkit-scrollbar-track {
141
+ background: var(--chat-background);
142
+ }
143
+ ::-webkit-scrollbar-thumb {
144
+ background: var(--primary-color);
145
+ border-radius: 4px;
146
+ }
147
+ ::-webkit-scrollbar-thumb:hover {
148
+ background: var(--secondary-color);
149
+ }
150
+ /* 代码块样式 */
151
+ .hljs {
152
+ background: var(--fold-background) !important;
153
+ color: var(--fold-text) !important;
154
+ }
155
+ /* details {
156
+ background-color: var(--search-result-background);
157
+ color: var(--text-color);
158
+ border-radius: 8px;
159
+ padding: 10px;
160
+ margin-bottom: 10px;
161
+ transition: all 0.3s ease;
162
+ border: 1px solid var(--border-color);
163
+ }
164
+ summary {
165
+ cursor: pointer;
166
+ font-weight: bold;
167
+ color: var(--text-color);
168
+ }
169
+ details ul {
170
+ list-style-type: none;
171
+ padding-left: 0;
172
+ }
173
+ details li {
174
+ background-color: var(--chat-bubble-ai);
175
+ color: var(--text-color);
176
+ padding: 10px;
177
+ margin-top: 10px;
178
+ border-radius: 4px;
179
+ border: 1px solid var(--border-color);
180
+ }
181
+ details * {
182
+ background-color: var(--search-result-background);
183
+ } */
184
+ .search-results {
185
+ background-color: var(--search-result-background);
186
+ color: var(--text-color);
187
+ border: 1px solid var(--border-color);
188
+ }
189
+ .search-results summary {
190
+ cursor: pointer;
191
+ font-weight: bold;
192
+ }
193
+ .search-results ul {
194
+ list-style-type: none;
195
+ padding-left: 0;
196
+ }
197
+ .search-results li {
198
+ background-color: var(--chat-bubble-ai);
199
+ border: 1px solid var(--border-color);
200
+ }
201
+ /* 控制台消息条目样式 */
202
+ #status-log div {
203
+ background-color: var(--console-background);
204
+ color: var(--console-text);
205
+ border: 1px solid var(--border-color);
206
+ }
207
+ @media (max-width: 768px) {
208
+ .sidebar {
209
+ position: fixed;
210
+ right: -300px;
211
+ top: 0;
212
+ bottom: 0;
213
+ width: 300px;
214
+ z-index: 1000;
215
+ transition: right 0.3s ease-in-out;
216
+ }
217
+ .sidebar.open {
218
+ right: 0;
219
+ }
220
+ .sidebar-overlay {
221
+ display: none;
222
+ position: fixed;
223
+ top: 0;
224
+ left: 0;
225
+ right: 0;
226
+ bottom: 0;
227
+ background-color: rgba(0, 0, 0, 0.5);
228
+ z-index: 999;
229
+ }
230
+ .sidebar-overlay.show {
231
+ display: block;
232
+ }
233
+ }
234
+ </style>
235
+ </head>
236
+ <body class="h-screen flex flex-col md:flex-row p-4">
237
+ <!-- 主聊天窗口 -->
238
+ <div class="chat-container flex-grow md:w-3/4 p-4 flex flex-col h-screen mr-4">
239
+ <div id="chat-window" class="flex-grow overflow-y-auto mb-4 p-4 rounded-lg shadow-inner"></div>
240
+ <div class="relative">
241
+ <input id="user-input" type="text" class="w-full border p-2" placeholder="输入您的问题...">
242
+ <button id="send-btn" class="text-2xl">
243
+ <i class="fas fa-paper-plane"></i>
244
+ </button>
245
+ </div>
246
+ </div>
247
+
248
+ <!-- 右侧控制台 -->
249
+ <div class="sidebar console md:w-1/4 p-4 h-screen overflow-y-auto">
250
+ <h2 class="text-xl font-bold mb-4">运行状态</h2>
251
+ <div class="mb-4">
252
+ <div class="mb-2">
253
+ <span class="status-indicator" id="main-model-status"></span>
254
+ 主模型
255
+ </div>
256
+ <div class="mb-2">
257
+ <span class="status-indicator" id="sub-model-status"></span>
258
+ 次模型
259
+ </div>
260
+ <div class="mb-2">
261
+ <span class="status-indicator" id="search-status"></span>
262
+ 搜索
263
+ </div>
264
+ <div>
265
+ <span class="status-indicator" id="email-status"></span>
266
+ 邮件发送
267
+ </div>
268
+ </div>
269
+ <div id="status-log" class="p-2 rounded h-64 overflow-y-auto mb-4"></div>
270
+ <button id="settings-btn" class="w-full bg-gray-300 dark:bg-gray-600 text-gray-800 dark:text-white px-4 py-2 rounded hover:bg-gray-400 dark:hover:bg-gray-500 transition duration-200">
271
+ <i class="fas fa-cog"></i> 设置
272
+ </button>
273
+ </div>
274
+
275
+ <!-- 移动端侧边栏切换按钮 -->
276
+ <button id="sidebar-toggle" class="md:hidden fixed top-4 right-4 bg-gray-300 dark:bg-gray-600 text-gray-800 dark:text-white p-2 rounded-full shadow-lg hover:bg-gray-400 dark:hover:bg-gray-500 transition duration-200 z-50">
277
+ <i class="fas fa-bars"></i>
278
+ </button>
279
+
280
+ <!-- 移动端侧边栏遮罩 -->
281
+ <div id="sidebar-overlay" class="sidebar-overlay"></div>
282
+
283
+ <!-- 暗色模式切换按钮 -->
284
+ <button id="dark-mode-toggle" class="fixed top-4 left-4 bg-gray-300 dark:bg-gray-600 text-gray-800 dark:text-white p-2 rounded-full shadow-lg hover:bg-gray-400 dark:hover:bg-gray-500 transition duration-200">
285
+ <i class="fas fa-moon"></i>
286
+ </button>
287
+
288
+ <!-- 设置对话框 -->
289
+ <div id="settings-modal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden flex items-center justify-center z-50">
290
+ <div class="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-xl">
291
+ <h2 class="text-xl font-bold mb-4">设置</h2>
292
+ <div class="mb-4">
293
+ <label for="max-history" class="block mb-2">保留对话轮数:</label>
294
+ <input type="number" id="max-history" class="border rounded p-2 w-full dark:bg-gray-700 dark:text-white" min="1" max="50" value="10">
295
+ </div>
296
+ <div class="flex justify-end">
297
+ <button id="save-settings" class="bg-blue-500 text-white px-4 py-2 rounded mr-2 hover:bg-blue-600 transition duration-200">保存</button>
298
+ <button id="cancel-settings" class="bg-gray-300 dark:bg-gray-600 text-gray-800 dark:text-white px-4 py-2 rounded hover:bg-gray-400 dark:hover:bg-gray-500 transition duration-200">取消</button>
299
+ </div>
300
+ </div>
301
+ </div>
302
+
303
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.0.2/marked.min.js"></script>
304
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
305
+ <script>
306
+ const chatWindow = document.getElementById('chat-window');
307
+ const userInput = document.getElementById('user-input');
308
+ const sendBtn = document.getElementById('send-btn');
309
+ const mainModelStatus = document.getElementById('main-model-status');
310
+ const subModelStatus = document.getElementById('sub-model-status');
311
+ const searchStatus = document.getElementById('search-status');
312
+ const emailStatus = document.getElementById('email-status');
313
+ const statusLog = document.getElementById('status-log');
314
+ const settingsBtn = document.getElementById('settings-btn');
315
+ const settingsModal = document.getElementById('settings-modal');
316
+ const saveSettingsBtn = document.getElementById('save-settings');
317
+ const cancelSettingsBtn = document.getElementById('cancel-settings');
318
+ const maxHistoryInput = document.getElementById('max-history');
319
+ const darkModeToggle = document.getElementById('dark-mode-toggle');
320
+ const sidebarToggle = document.getElementById('sidebar-toggle');
321
+ const sidebar = document.querySelector('.sidebar');
322
+ const sidebarOverlay = document.getElementById('sidebar-overlay');
323
+ let conversationHistory = [];
324
+ let maxHistory = 10;
325
+ function addMessage(content, isUser) {
326
+ const bubble = document.createElement('div');
327
+ bubble.className = `chat-bubble ${isUser ? 'user-bubble' : 'ai-bubble'}`;
328
+ bubble.innerHTML = isUser ? content : marked.parse(content);
329
+ chatWindow.appendChild(bubble);
330
+ chatWindow.scrollTop = chatWindow.scrollHeight;
331
+
332
+ bubble.querySelectorAll('pre code').forEach((block) => {
333
+ hljs.highlightBlock(block);
334
+ });
335
+
336
+ conversationHistory.push({
337
+ role: isUser ? 'user' : 'assistant',
338
+ content: content
339
+ });
340
+
341
+ if (conversationHistory.length > maxHistory * 2) {
342
+ conversationHistory = conversationHistory.slice(-maxHistory * 2);
343
+ }
344
+ }
345
+ function updateStatus(mainActive, subActive, searchActive, emailActive) {
346
+ mainModelStatus.className = `status-indicator ${mainActive ? 'status-active' : 'status-inactive'}`;
347
+ subModelStatus.className = `status-indicator ${subActive ? 'status-active' : 'status-inactive'}`;
348
+ searchStatus.className = `status-indicator ${searchActive ? 'status-active' : 'status-inactive'}`;
349
+ emailStatus.className = `status-indicator ${emailActive ? 'status-active' : 'status-inactive'}`;
350
+ }
351
+ function addStatusLog(message) {
352
+ const logEntry = document.createElement('div');
353
+ logEntry.className = 'mb-2 p-2 bg-white dark:bg-gray-700 rounded shadow';
354
+ logEntry.textContent = message;
355
+ statusLog.appendChild(logEntry);
356
+ statusLog.scrollTop = statusLog.scrollHeight;
357
+ }
358
+ function displaySearchResults(results, type) {
359
+ const searchResults = document.createElement('details');
360
+ searchResults.className = 'search-results mb-2 p-2 rounded';
361
+ const summary = document.createElement('summary');
362
+ summary.textContent = type === 'papers' ? '论文搜索结果' : '搜索结果';
363
+ searchResults.appendChild(summary);
364
+ const resultsList = document.createElement('ul');
365
+ resultsList.className = 'mt-2';
366
+ results.forEach(result => {
367
+ const li = document.createElement('li');
368
+ li.className = 'mb-2 p-2 rounded';
369
+ if (type === 'papers') {
370
+ li.innerHTML = `
371
+ <strong>标题:</strong> ${result.标题}<br>
372
+ <strong>作者:</strong> ${result.作者}<br>
373
+ <strong>DOI:</strong> ${result.DOI}<br>
374
+ <strong>ISBN:</strong> ${result.ISBN}<br>
375
+ <strong>摘要:</strong> ${result.摘要}
376
+ `;
377
+ } else {
378
+ li.innerHTML = `<strong>${result.title}</strong><br>${result.body}`;
379
+ }
380
+ resultsList.appendChild(li);
381
+ });
382
+ searchResults.appendChild(resultsList);
383
+ chatWindow.appendChild(searchResults);
384
+ }
385
+ async function sendMessage() {
386
+ const question = userInput.value.trim();
387
+ if (!question) return;
388
+ addMessage(question, true);
389
+ userInput.value = '';
390
+ updateStatus(false, false, false, false);
391
+ statusLog.innerHTML = '';
392
+ addStatusLog('开始处理问题...');
393
+ try {
394
+ const response = await fetch('/chat', {
395
+ method: 'POST',
396
+ headers: {
397
+ 'Content-Type': 'application/json'
398
+ },
399
+ body: JSON.stringify({
400
+ question,
401
+ history: conversationHistory.slice(-maxHistory * 2 + 1)
402
+ })
403
+ });
404
+ const data = await response.json();
405
+ data.status_log.forEach(log => addStatusLog(log));
406
+ updateStatus(true, true, data.search_used, data.email_sent);
407
+ if (data.search_used) {
408
+ if (Array.isArray(data.search_results) && data.search_results.length > 0 && 'DOI' in data.search_results[0]) {
409
+ displaySearchResults(data.search_results, 'papers');
410
+ } else {
411
+ displaySearchResults(data.search_results, 'web');
412
+ }
413
+ }
414
+ addMessage(data.response, false);
415
+ addStatusLog('回答完成');
416
+ } catch (error) {
417
+ console.error('Error:', error);
418
+ addMessage('发生错误,请稍后再试。', false);
419
+ updateStatus(false, false, false, false);
420
+ addStatusLog('发生错误');
421
+ }
422
+ }
423
+ sendBtn.addEventListener('click', sendMessage);
424
+ userInput.addEventListener('keypress', (e) => {
425
+ if (e.key === 'Enter') {
426
+ sendMessage();
427
+ }
428
+ });
429
+ // 设置相关功能
430
+ settingsBtn.addEventListener('click', () => {
431
+ settingsModal.classList.remove('hidden');
432
+ maxHistoryInput.value = maxHistory;
433
+ });
434
+ saveSettingsBtn.addEventListener('click', async () => {
435
+ const newMaxHistory = parseInt(maxHistoryInput.value);
436
+ if (newMaxHistory >= 1 && newMaxHistory <= 50) {
437
+ maxHistory = newMaxHistory;
438
+ try {
439
+ const response = await fetch('/settings', {
440
+ method: 'POST',
441
+ headers: {
442
+ 'Content-Type': 'application/json'
443
+ },
444
+ body: JSON.stringify({ max_history: maxHistory })
445
+ });
446
+ const data = await response.json();
447
+ if (data.status === 'success') {
448
+ alert('设置已保存');
449
+ } else {
450
+ alert('保存设置时出错');
451
+ }
452
+ } catch (error) {
453
+ console.error('Error:', error);
454
+ alert('保存设置时出错');
455
+ }
456
+ settingsModal.classList.add('hidden');
457
+ } else {
458
+ alert('请输入1到50之间的数字');
459
+ }
460
+ });
461
+ cancelSettingsBtn.addEventListener('click', () => {
462
+ settingsModal.classList.add('hidden');
463
+ });
464
+ // 暗色模式切换
465
+ darkModeToggle.addEventListener('click', () => {
466
+ document.body.classList.toggle('dark-mode');
467
+ updateDarkModeIcon();
468
+ });
469
+ function updateDarkModeIcon() {
470
+ const icon = darkModeToggle.querySelector('i');
471
+ if (document.body.classList.contains('dark-mode')) {
472
+ icon.classList.remove('fa-moon');
473
+ icon.classList.add('fa-sun');
474
+ } else {
475
+ icon.classList.remove('fa-sun');
476
+ icon.classList.add('fa-moon');
477
+ }
478
+ }
479
+ // 初始化暗色模式
480
+ function initDarkMode() {
481
+ if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
482
+ document.body.classList.add('dark-mode');
483
+ }
484
+ updateDarkModeIcon();
485
+ }
486
+ // 监听系统主题变化
487
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
488
+ if (e.matches) {
489
+ document.body.classList.add('dark-mode');
490
+ } else {
491
+ document.body.classList.remove('dark-mode');
492
+ }
493
+ updateDarkModeIcon();
494
+ });
495
+ // 侧边栏控制
496
+ sidebarToggle.addEventListener('click', () => {
497
+ sidebar.classList.toggle('open');
498
+ sidebarOverlay.classList.toggle('show');
499
+ });
500
+ sidebarOverlay.addEventListener('click', () => {
501
+ sidebar.classList.remove('open');
502
+ sidebarOverlay.classList.remove('show');
503
+ });
504
+ // 页面加载完成后初始化
505
+ window.addEventListener('load', () => {
506
+ initDarkMode();
507
+ });
508
+ // 监听窗口大小变化,在大屏幕时关闭侧边栏遮罩
509
+ window.addEventListener('resize', () => {
510
+ if (window.innerWidth >= 768) {
511
+ sidebar.classList.remove('open');
512
+ sidebarOverlay.classList.remove('show');
513
+ }
514
+ });
515
+ </script>
516
+ </body>
517
+ </html>