mistpe commited on
Commit
de2b9bd
1 Parent(s): 8213b9e

Create index.html

Browse files
Files changed (1) hide show
  1. index.html +489 -0
index.html ADDED
@@ -0,0 +1,489 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
156
+ .search-results {
157
+ background-color: var(--search-result-background);
158
+ color: var(--text-color);
159
+ border: 1px solid var(--border-color);
160
+ }
161
+ .search-results summary {
162
+ cursor: pointer;
163
+ font-weight: bold;
164
+ }
165
+ .search-results ul {
166
+ list-style-type: none;
167
+ padding-left: 0;
168
+ }
169
+ .search-results li {
170
+ background-color: var(--chat-bubble-ai);
171
+ border: 1px solid var(--border-color);
172
+ }
173
+ /* 控制台消息条目样式 */
174
+ #status-log div {
175
+ background-color: var(--console-background);
176
+ color: var(--console-text);
177
+ border: 1px solid var(--border-color);
178
+ }
179
+ @media (max-width: 768px) {
180
+ .sidebar {
181
+ position: fixed;
182
+ right: -300px;
183
+ top: 0;
184
+ bottom: 0;
185
+ width: 300px;
186
+ z-index: 1000;
187
+ transition: right 0.3s ease-in-out;
188
+ }
189
+ .sidebar.open {
190
+ right: 0;
191
+ }
192
+ .sidebar-overlay {
193
+ display: none;
194
+ position: fixed;
195
+ top: 0;
196
+ left: 0;
197
+ right: 0;
198
+ bottom: 0;
199
+ background-color: rgba(0, 0, 0, 0.5);
200
+ z-index: 999;
201
+ }
202
+ .sidebar-overlay.show {
203
+ display: block;
204
+ }
205
+ }
206
+ </style>
207
+ </head>
208
+ <body class="h-screen flex flex-col md:flex-row p-4">
209
+ <!-- 主聊天窗口 -->
210
+ <div class="chat-container flex-grow md:w-3/4 p-4 flex flex-col h-screen mr-4">
211
+ <div id="chat-window" class="flex-grow overflow-y-auto mb-4 p-4 rounded-lg shadow-inner"></div>
212
+ <div class="relative">
213
+ <input id="user-input" type="text" class="w-full border p-2" placeholder="输入您的问题...">
214
+ <button id="send-btn" class="text-2xl">
215
+ <i class="fas fa-paper-plane"></i>
216
+ </button>
217
+ </div>
218
+ </div>
219
+
220
+ <!-- 右侧控制台 -->
221
+ <div class="sidebar console md:w-1/4 p-4 h-screen overflow-y-auto">
222
+ <h2 class="text-xl font-bold mb-4">运行状态</h2>
223
+ <div class="mb-4">
224
+ <div class="mb-2">
225
+ <span class="status-indicator" id="main-model-status"></span>
226
+ 主模型
227
+ </div>
228
+ <div class="mb-2">
229
+ <span class="status-indicator" id="sub-model-status"></span>
230
+ 次模型
231
+ </div>
232
+ <div class="mb-2">
233
+ <span class="status-indicator" id="search-status"></span>
234
+ 搜索
235
+ </div>
236
+ <div>
237
+ <span class="status-indicator" id="email-status"></span>
238
+ 邮件发送
239
+ </div>
240
+ </div>
241
+ <div id="status-log" class="p-2 rounded h-64 overflow-y-auto mb-4"></div>
242
+ <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">
243
+ <i class="fas fa-cog"></i> 设置
244
+ </button>
245
+ </div>
246
+
247
+ <!-- 移动端侧边栏切换按钮 -->
248
+ <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">
249
+ <i class="fas fa-bars"></i>
250
+ </button>
251
+
252
+ <!-- 移动端侧边栏遮罩 -->
253
+ <div id="sidebar-overlay" class="sidebar-overlay"></div>
254
+
255
+ <!-- 暗色模式切换按钮 -->
256
+ <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">
257
+ <i class="fas fa-moon"></i>
258
+ </button>
259
+
260
+ <!-- 设置对话框 -->
261
+ <div id="settings-modal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden flex items-center justify-center z-50">
262
+ <div class="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-xl">
263
+ <h2 class="text-xl font-bold mb-4">设置</h2>
264
+ <div class="mb-4">
265
+ <label for="max-history" class="block mb-2">保留对话轮数:</label>
266
+ <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">
267
+ </div>
268
+ <div class="flex justify-end">
269
+ <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>
270
+ <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>
271
+ </div>
272
+ </div>
273
+ </div>
274
+
275
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.0.2/marked.min.js"></script>
276
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
277
+ <script>
278
+ const chatWindow = document.getElementById('chat-window');
279
+ const userInput = document.getElementById('user-input');
280
+ const sendBtn = document.getElementById('send-btn');
281
+ const mainModelStatus = document.getElementById('main-model-status');
282
+ const subModelStatus = document.getElementById('sub-model-status');
283
+ const searchStatus = document.getElementById('search-status');
284
+ const emailStatus = document.getElementById('email-status');
285
+ const statusLog = document.getElementById('status-log');
286
+ const settingsBtn = document.getElementById('settings-btn');
287
+ const settingsModal = document.getElementById('settings-modal');
288
+ const saveSettingsBtn = document.getElementById('save-settings');
289
+ const cancelSettingsBtn = document.getElementById('cancel-settings');
290
+ const maxHistoryInput = document.getElementById('max-history');
291
+ const darkModeToggle = document.getElementById('dark-mode-toggle');
292
+ const sidebarToggle = document.getElementById('sidebar-toggle');
293
+ const sidebar = document.querySelector('.sidebar');
294
+ const sidebarOverlay = document.getElementById('sidebar-overlay');
295
+ let conversationHistory = [];
296
+ let maxHistory = 10;
297
+ function addMessage(content, isUser) {
298
+ const bubble = document.createElement('div');
299
+ bubble.className = `chat-bubble ${isUser ? 'user-bubble' : 'ai-bubble'}`;
300
+ bubble.innerHTML = isUser ? content : marked.parse(content);
301
+ chatWindow.appendChild(bubble);
302
+ chatWindow.scrollTop = chatWindow.scrollHeight;
303
+
304
+ bubble.querySelectorAll('pre code').forEach((block) => {
305
+ hljs.highlightBlock(block);
306
+ });
307
+
308
+ conversationHistory.push({
309
+ role: isUser ? 'user' : 'assistant',
310
+ content: content
311
+ });
312
+
313
+ if (conversationHistory.length > maxHistory * 2) {
314
+ conversationHistory = conversationHistory.slice(-maxHistory * 2);
315
+ }
316
+ }
317
+ function updateStatus(mainActive, subActive, searchActive, emailActive) {
318
+ mainModelStatus.className = `status-indicator ${mainActive ? 'status-active' : 'status-inactive'}`;
319
+ subModelStatus.className = `status-indicator ${subActive ? 'status-active' : 'status-inactive'}`;
320
+ searchStatus.className = `status-indicator ${searchActive ? 'status-active' : 'status-inactive'}`;
321
+ emailStatus.className = `status-indicator ${emailActive ? 'status-active' : 'status-inactive'}`;
322
+ }
323
+ function addStatusLog(message) {
324
+ const logEntry = document.createElement('div');
325
+ logEntry.className = 'mb-2 p-2 bg-white dark:bg-gray-700 rounded shadow';
326
+ logEntry.textContent = message;
327
+ statusLog.appendChild(logEntry);
328
+ statusLog.scrollTop = statusLog.scrollHeight;
329
+ }
330
+ function displaySearchResults(results, type) {
331
+ const searchResults = document.createElement('details');
332
+ searchResults.className = 'search-results mb-2 p-2 rounded';
333
+ const summary = document.createElement('summary');
334
+ summary.textContent = type === 'papers' ? '论文搜索结果' : '搜索结果';
335
+ searchResults.appendChild(summary);
336
+ const resultsList = document.createElement('ul');
337
+ resultsList.className = 'mt-2';
338
+ results.forEach(result => {
339
+ const li = document.createElement('li');
340
+ li.className = 'mb-2 p-2 rounded';
341
+ if (type === 'papers') {
342
+ li.innerHTML = `
343
+ <strong>标题:</strong> ${result.标题}<br>
344
+ <strong>作者:</strong> ${result.作者}<br>
345
+ <strong>DOI:</strong> ${result.DOI}<br>
346
+ <strong>ISBN:</strong> ${result.ISBN}<br>
347
+ <strong>摘要:</strong> ${result.摘要}
348
+ `;
349
+ } else {
350
+ li.innerHTML = `<strong>${result.title}</strong><br>${result.body}`;
351
+ }
352
+ resultsList.appendChild(li);
353
+ });
354
+ searchResults.appendChild(resultsList);
355
+ chatWindow.appendChild(searchResults);
356
+ }
357
+ async function sendMessage() {
358
+ const question = userInput.value.trim();
359
+ if (!question) return;
360
+ addMessage(question, true);
361
+ userInput.value = '';
362
+ updateStatus(false, false, false, false);
363
+ statusLog.innerHTML = '';
364
+ addStatusLog('开始处理问题...');
365
+ try {
366
+ const response = await fetch('/chat', {
367
+ method: 'POST',
368
+ headers: {
369
+ 'Content-Type': 'application/json'
370
+ },
371
+ body: JSON.stringify({
372
+ question,
373
+ history: conversationHistory.slice(-maxHistory * 2 + 1)
374
+ })
375
+ });
376
+ const data = await response.json();
377
+ data.status_log.forEach(log => addStatusLog(log));
378
+ updateStatus(true, true, data.search_used, data.email_sent);
379
+ if (data.search_used) {
380
+ if (Array.isArray(data.search_results) && data.search_results.length > 0 && 'DOI' in data.search_results[0]) {
381
+ displaySearchResults(data.search_results, 'papers');
382
+ } else {
383
+ displaySearchResults(data.search_results, 'web');
384
+ }
385
+ }
386
+ addMessage(data.response, false);
387
+ addStatusLog('回答完成');
388
+ } catch (error) {
389
+ console.error('Error:', error);
390
+ addMessage('发生错误,请稍后再试。', false);
391
+ updateStatus(false, false, false, false);
392
+ addStatusLog('发生错误');
393
+ }
394
+ }
395
+ sendBtn.addEventListener('click', sendMessage);
396
+ userInput.addEventListener('keypress', (e) => {
397
+ if (e.key === 'Enter') {
398
+ sendMessage();
399
+ }
400
+ });
401
+ // 设置相关功能
402
+ settingsBtn.addEventListener('click', () => {
403
+ settingsModal.classList.remove('hidden');
404
+ maxHistoryInput.value = maxHistory;
405
+ });
406
+ saveSettingsBtn.addEventListener('click', async () => {
407
+ const newMaxHistory = parseInt(maxHistoryInput.value);
408
+ if (newMaxHistory >= 1 && newMaxHistory <= 50) {
409
+ maxHistory = newMaxHistory;
410
+ try {
411
+ const response = await fetch('/settings', {
412
+ method: 'POST',
413
+ headers: {
414
+ 'Content-Type': 'application/json'
415
+ },
416
+ body: JSON.stringify({ max_history: maxHistory })
417
+ });
418
+ const data = await response.json();
419
+ if (data.status === 'success') {
420
+ alert('设置已保存');
421
+ } else {
422
+ alert('保存设置时出错');
423
+ }
424
+ } catch (error) {
425
+ console.error('Error:', error);
426
+ alert('保存设置时出错');
427
+ }
428
+ settingsModal.classList.add('hidden');
429
+ } else {
430
+ alert('请输入1到50之间的数字');
431
+ }
432
+ });
433
+ cancelSettingsBtn.addEventListener('click', () => {
434
+ settingsModal.classList.add('hidden');
435
+ });
436
+ // 暗色模式切换
437
+ darkModeToggle.addEventListener('click', () => {
438
+ document.body.classList.toggle('dark-mode');
439
+ updateDarkModeIcon();
440
+ });
441
+ function updateDarkModeIcon() {
442
+ const icon = darkModeToggle.querySelector('i');
443
+ if (document.body.classList.contains('dark-mode')) {
444
+ icon.classList.remove('fa-moon');
445
+ icon.classList.add('fa-sun');
446
+ } else {
447
+ icon.classList.remove('fa-sun');
448
+ icon.classList.add('fa-moon');
449
+ }
450
+ }
451
+ // 初始化暗色模式
452
+ function initDarkMode() {
453
+ if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
454
+ document.body.classList.add('dark-mode');
455
+ }
456
+ updateDarkModeIcon();
457
+ }
458
+ // 监听系统主题变化
459
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
460
+ if (e.matches) {
461
+ document.body.classList.add('dark-mode');
462
+ } else {
463
+ document.body.classList.remove('dark-mode');
464
+ }
465
+ updateDarkModeIcon();
466
+ });
467
+ // 侧边栏控制
468
+ sidebarToggle.addEventListener('click', () => {
469
+ sidebar.classList.toggle('open');
470
+ sidebarOverlay.classList.toggle('show');
471
+ });
472
+ sidebarOverlay.addEventListener('click', () => {
473
+ sidebar.classList.remove('open');
474
+ sidebarOverlay.classList.remove('show');
475
+ });
476
+ // 页面加载完成后初始化
477
+ window.addEventListener('load', () => {
478
+ initDarkMode();
479
+ });
480
+ // 监听窗口大小变化,在大屏幕时关闭侧边栏遮罩
481
+ window.addEventListener('resize', () => {
482
+ if (window.innerWidth >= 768) {
483
+ sidebar.classList.remove('open');
484
+ sidebarOverlay.classList.remove('show');
485
+ }
486
+ });
487
+ </script>
488
+ </body>
489
+ </html>