raineye commited on
Commit
0cc9087
·
verified ·
1 Parent(s): 3b6855c

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +656 -631
index.html CHANGED
@@ -3,704 +3,729 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>DeepSeek Chat</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
- /* 自定义滚动条 */
11
- ::-webkit-scrollbar {
12
- width: 6px;
13
  }
14
- ::-webkit-scrollbar-track {
15
- background: #1a1a1a;
 
16
  }
17
- ::-webkit-scrollbar-thumb {
18
- background: #4b5563;
19
- border-radius: 3px;
20
  }
21
- ::-webkit-scrollbar-thumb:hover {
22
- background: #6b7280;
 
23
  }
24
-
25
- /* 打字动画 */
26
- @keyframes typing {
27
- from { width: 0 }
28
- to { width: 100% }
29
  }
30
-
31
- .typing-animation {
32
  overflow: hidden;
33
- white-space: nowrap;
34
- animation: typing 1s steps(40, end);
35
- }
36
-
37
- /* 消息气泡动画 */
38
- @keyframes fadeIn {
39
- from { opacity: 0; transform: translateY(10px); }
40
- to { opacity: 1; transform: translateY(0); }
41
- }
42
-
43
- .message-fade-in {
44
- animation: fadeIn 0.3s ease-out forwards;
45
- }
46
-
47
- /* 输入框聚焦效果 */
48
- .input-focus-effect:focus {
49
- box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.5);
50
- }
51
-
52
- /* 语音录制动画 */
53
- @keyframes pulse {
54
- 0% { opacity: 1; }
55
- 50% { opacity: 0.5; }
56
- 100% { opacity: 1; }
57
- }
58
-
59
- .recording-animation {
60
- animation: pulse 1.5s infinite;
61
- }
62
-
63
- /* 模态框动画 */
64
- @keyframes modalFadeIn {
65
- from { opacity: 0; transform: translateY(-20px); }
66
- to { opacity: 1; transform: translateY(0); }
67
- }
68
-
69
- .modal-animation {
70
- animation: modalFadeIn 0.3s ease-out;
71
  }
72
  </style>
73
  </head>
74
- <body class="bg-gray-900 text-gray-100 h-screen flex flex-col overflow-hidden">
75
- <!-- 顶部导航栏 -->
76
- <header class="bg-gray-800 border-b border-gray-700 py-3 px-4 flex items-center justify-between">
77
- <div class="flex items-center space-x-2">
78
- <div class="w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center">
79
- <i class="fas fa-robot text-white"></i>
 
80
  </div>
81
- <h1 class="text-xl font-bold text-white">DeepSeek Chat</h1>
82
- </div>
83
- <div class="flex items-center space-x-4">
84
- <button id="theme-toggle" class="text-gray-400 hover:text-white transition-colors">
85
- <i class="fas fa-moon"></i>
86
  </button>
87
- <button id="settings-button" class="text-gray-400 hover:text-white transition-colors">
88
- <i class="fas fa-cog"></i>
89
- </button>
90
- <button id="user-button" class="text-gray-400 hover:text-white transition-colors">
91
- <i class="fas fa-user"></i>
92
- </button>
93
- </div>
94
- </header>
95
-
96
- <!-- 主聊天区域 -->
97
- <main class="flex-1 overflow-y-auto p-4 space-y-6" id="chat-container">
98
- <!-- 欢迎消息 -->
99
- <div class="max-w-3xl mx-auto message-fade-in">
100
- <div class="flex space-x-3">
101
- <div class="flex-shrink-0">
102
- <div class="w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center">
103
- <i class="fas fa-robot text-white"></i>
104
  </div>
105
  </div>
106
- <div class="flex-1 min-w-0">
107
- <div class="bg-gray-800 rounded-lg p-4">
108
- <p class="text-white font-medium">DeepSeek Chat</p>
109
- <div class="mt-2 text-gray-300">
110
- <p>你好!我是DeepSeek Chat,一个强大的AI助手。我可以帮助你解答问题、提供建议、分析数据等等。</p>
111
- <p class="mt-2">你可以问我任何问题,我会尽力提供最准确和有用的回答。</p>
112
- </div>
113
  </div>
 
114
  </div>
115
- </div>
116
- </div>
117
 
118
- <!-- 示例问题 -->
119
- <div class="max-w-3xl mx-auto grid grid-cols-1 md:grid-cols-2 gap-3">
120
- <button class="bg-gray-800 hover:bg-gray-700 rounded-lg p-3 text-left transition-colors message-fade-in" onclick="insertExample(this)">
121
- <p class="text-sm text-gray-400">示例问题</p>
122
- <p class="mt-1 text-white">如何提高我的Python编程技能?</p>
123
- </button>
124
- <button class="bg-gray-800 hover:bg-gray-700 rounded-lg p-3 text-left transition-colors message-fade-in" onclick="insertExample(this)">
125
- <p class="text-sm text-gray-400">示例问题</p>
126
- <p class="mt-1 text-white">解释量子计算的基本概念</p>
127
- </button>
128
- <button class="bg-gray-800 hover:bg-gray-700 rounded-lg p-3 text-left transition-colors message-fade-in" onclick="insertExample(this)">
129
- <p class="text-sm text-gray-400">示例问题</p>
130
- <p class="mt-1 text-white">写一封专业的求职信</p>
131
- </button>
132
- <button class="bg-gray-800 hover:bg-gray-700 rounded-lg p-3 text-left transition-colors message-fade-in" onclick="insertExample(this)">
133
- <p class="text-sm text-gray-400">示例问题</p>
134
- <p class="mt-1 text-white">如何制定一个有效的学习计划?</p>
135
- </button>
136
- </div>
137
- </main>
138
-
139
- <!-- 输入区域 -->
140
- <div class="bg-gray-800 border-t border-gray-700 p-4">
141
- <div class="max-w-3xl mx-auto">
142
- <form id="chat-form" class="relative">
143
- <div class="flex items-end space-x-2">
144
- <div class="flex-1 relative">
145
- <textarea
146
- id="message-input"
147
- rows="1"
148
- class="w-full bg-gray-700 border border-gray-600 rounded-lg py-3 px-4 pr-12 text-white placeholder-gray-400 focus:outline-none input-focus-effect resize-none"
149
- placeholder="输入消息..."
150
- oninput="autoResize(this)"
151
- ></textarea>
152
- <div class="absolute right-2 bottom-2 flex space-x-1">
153
- <button type="button" id="attach-button" class="text-gray-400 hover:text-white p-1 rounded-full transition-colors">
154
- <i class="fas fa-paperclip"></i>
155
- </button>
156
- <button type="button" id="voice-button" class="text-gray-400 hover:text-white p-1 rounded-full transition-colors">
157
- <i class="fas fa-microphone"></i>
158
- </button>
159
  </div>
160
  </div>
161
- <button
162
- type="submit"
163
- id="send-button"
164
- class="bg-blue-600 hover:bg-blue-700 text-white rounded-lg p-3 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
165
- disabled
166
- >
167
- <i class="fas fa-paper-plane"></i>
168
- </button>
169
  </div>
170
- </form>
171
- <p class="text-xs text-gray-500 mt-2 text-center">DeepSeek Chat 可能会产生不准确的信息,请验证重要信息。</p>
172
- </div>
173
- </div>
174
 
175
- <!-- 文件选择模态框 -->
176
- <div id="file-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
177
- <div class="bg-gray-800 rounded-lg p-6 w-full max-w-md modal-animation">
178
- <div class="flex justify-between items-center mb-4">
179
- <h3 class="text-lg font-medium text-white">选择文件</h3>
180
- <button id="close-file-modal" class="text-gray-400 hover:text-white">
181
- <i class="fas fa-times"></i>
182
- </button>
183
- </div>
184
- <div class="border-2 border-dashed border-gray-600 rounded-lg p-8 text-center mb-4">
185
- <i class="fas fa-cloud-upload-alt text-4xl text-gray-400 mb-3"></i>
186
- <p class="text-gray-300 mb-2">拖放文件到这里或点击选择</p>
187
- <input type="file" id="file-input" class="hidden" multiple>
188
- <button id="select-file-button" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
189
- 选择文件
190
- </button>
191
- </div>
192
- <div id="selected-files" class="hidden">
193
- <p class="text-gray-300 mb-2">已选择文件:</p>
194
- <ul id="file-list" class="text-gray-400 text-sm"></ul>
195
- </div>
196
- <div class="flex justify-end space-x-3 mt-4">
197
- <button id="cancel-upload" class="px-4 py-2 rounded-lg border border-gray-600 text-gray-300 hover:bg-gray-700">
198
- 取消
199
- </button>
200
- <button id="confirm-upload" class="px-4 py-2 rounded-lg bg-blue-600 text-white hover:bg-blue-700">
201
- 上传
202
  </button>
203
- </div>
204
- </div>
205
- </div>
206
 
207
- <!-- 语音录制模态框 -->
208
- <div id="voice-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
209
- <div class="bg-gray-800 rounded-lg p-6 w-full max-w-md modal-animation">
210
- <div class="flex justify-between items-center mb-4">
211
- <h3 class="text-lg font-medium text-white">语音输入</h3>
212
- <button id="close-voice-modal" class="text-gray-400 hover:text-white">
213
- <i class="fas fa-times"></i>
214
- </button>
 
215
  </div>
216
- <div class="text-center mb-6">
217
- <div class="w-20 h-20 bg-gray-700 rounded-full flex items-center justify-center mx-auto mb-4">
218
- <i id="voice-icon" class="fas fa-microphone text-3xl text-blue-500"></i>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
  </div>
220
- <p id="voice-status" class="text-gray-300">点击下方按钮开始录音</p>
221
- <div class="mt-2 flex justify-center space-x-4">
222
- <div class="w-2 h-2 bg-gray-500 rounded-full"></div>
223
- <div class="w-2 h-2 bg-gray-500 rounded-full"></div>
224
- <div class="w-2 h-2 bg-gray-500 rounded-full"></div>
225
  </div>
226
  </div>
227
- <div class="flex justify-center">
228
- <button id="start-recording" class="px-6 py-3 rounded-full bg-red-600 text-white hover:bg-red-700 flex items-center">
229
- <i class="fas fa-microphone mr-2"></i>
230
- <span>开始录音</span>
231
- </button>
232
- <button id="stop-recording" class="px-6 py-3 rounded-full bg-gray-700 text-white hover:bg-gray-600 flex items-center hidden">
233
- <i class="fas fa-stop mr-2"></i>
234
- <span>停止</span>
235
- </button>
236
- </div>
237
- <div id="recording-timer" class="text-center mt-4 text-gray-400 hidden">
238
- <i class="fas fa-circle text-red-500 mr-2 recording-animation"></i>
239
- <span>00:00</span>
240
- </div>
241
  </div>
242
- </div>
243
 
244
- <!-- 设置模态框 -->
245
- <div id="settings-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
246
- <div class="bg-gray-800 rounded-lg p-6 w-full max-w-md modal-animation">
247
  <div class="flex justify-between items-center mb-4">
248
- <h3 class="text-lg font-medium text-white">设置</h3>
249
- <button id="close-settings-modal" class="text-gray-400 hover:text-white">
250
- <i class="fas fa-times"></i>
251
- </button>
252
- </div>
253
- <div class="space-y-4">
254
  <div>
255
- <label class="block text-gray-300 mb-2">语言</label>
256
- <select class="w-full bg-gray-700 border border-gray-600 rounded-lg py-2 px-3 text-white focus:outline-none focus:ring-2 focus:ring-blue-500">
257
- <option>简体中文</option>
258
- <option>English</option>
259
- <option>Español</option>
260
- <option>日本語</option>
261
- </select>
262
  </div>
263
  <div>
264
- <label class="block text-gray-300 mb-2">回答长度</label>
265
- <select class="w-full bg-gray-700 border border-gray-600 rounded-lg py-2 px-3 text-white focus:outline-none focus:ring-2 focus:ring-blue-500">
266
- <option>简短</option>
267
- <option selected>中等</option>
268
- <option>详细</option>
269
- </select>
270
- </div>
271
- <div class="flex items-center justify-between">
272
- <span class="text-gray-300">历史记录</span>
273
- <label class="relative inline-flex items-center cursor-pointer">
274
- <input type="checkbox" class="sr-only peer" checked>
275
- <div class="w-11 h-6 bg-gray-700 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-800 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
276
- </label>
277
  </div>
278
- <div class="flex items-center justify-between">
279
- <span class="text-gray-300">阅读模式</span>
280
- <label class="relative inline-flex items-center cursor-pointer">
281
- <input type="checkbox" class="sr-only peer">
282
- <div class="w-11 h-6 bg-gray-700 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-800 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
283
- </label>
284
- </div>
285
- </div>
286
- <div class="mt-6 flex justify-end space-x-3">
287
- <button id="cancel-settings" class="px-4 py-2 rounded-lg border border-gray-600 text-gray-300 hover:bg-gray-700">
288
- 取消
289
- </button>
290
- <button id="save-settings" class="px-4 py-2 rounded-lg bg-blue-600 text-white hover:bg-blue-700">
291
- 保存设置
292
- </button>
293
- </div>
294
- </div>
295
- </div>
296
-
297
- <!-- 用户信息模态框 -->
298
- <div id="user-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
299
- <div class="bg-gray-800 rounded-lg p-6 w-full max-w-md modal-animation">
300
- <div class="flex justify-between items-center mb-4">
301
- <h3 class="text-lg font-medium text-white">用户信息</h3>
302
- <button id="close-user-modal" class="text-gray-400 hover:text-white">
303
- <i class="fas fa-times"></i>
304
- </button>
305
- </div>
306
- <div class="flex flex-col items-center mb-6">
307
- <div class="w-20 h-20 bg-blue-600 rounded-full flex items-center justify-center mb-3">
308
- <i class="fas fa-user text-3xl text-white"></i>
309
  </div>
310
- <h4 class="text-white font-medium">访客用户</h4>
311
- <p class="text-gray-400 text-sm">未登录</p>
312
- </div>
313
- <div class="space-y-3">
314
- <button class="w-full flex items-center justify-between px-4 py-3 bg-gray-700 hover:bg-gray-600 rounded-lg transition-colors">
315
- <span class="text-gray-300">登录/注册</span>
316
- <i class="fas fa-chevron-right text-gray-400"></i>
317
- </button>
318
- <button class="w-full flex items-center justify-between px-4 py-3 bg-gray-700 hover:bg-gray-600 rounded-lg transition-colors">
319
- <span class="text-gray-300">订阅计划</span>
320
- <i class="fas fa-chevron-right text-gray-400"></i>
321
- </button>
322
- <button class="w-full flex items-center justify-between px-4 py-3 bg-gray-700 hover:bg-gray-600 rounded-lg transition-colors">
323
- <span class="text-gray-300">帮助中心</span>
324
- <i class="fas fa-chevron-right text-gray-400"></i>
325
- </button>
326
- <button class="w-full flex items-center justify-between px-4 py-3 bg-gray-700 hover:bg-gray-600 rounded-lg transition-colors">
327
- <span class="text-gray-300">反馈建议</span>
328
- <i class="fas fa-chevron-right text-gray-400"></i>
329
- </button>
330
- </div>
331
- <div class="mt-6">
332
- <button id="logout-button" class="w-full px-4 py-2 rounded-lg border border-gray-600 text-gray-300 hover:bg-gray-700">
333
- 退出登录
334
  </button>
335
  </div>
 
336
  </div>
337
  </div>
338
 
339
  <script>
340
- // 自动调整输入框高度
341
- function autoResize(textarea) {
342
- textarea.style.height = 'auto';
343
- textarea.style.height = textarea.scrollHeight + 'px';
344
-
345
- // 启用/禁用发送按钮
346
- document.getElementById('send-button').disabled = textarea.value.trim() === '';
347
- }
348
-
349
- // 插入示例问题
350
- function insertExample(button) {
351
- const question = button.querySelector('p:not(.text-sm)').textContent;
352
- const input = document.getElementById('message-input');
353
- input.value = question;
354
- autoResize(input);
355
- input.focus();
356
- }
357
-
358
- // 处理表单提交
359
- document.getElementById('chat-form').addEventListener('submit', function(e) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360
  e.preventDefault();
361
- const input = document.getElementById('message-input');
362
- const message = input.value.trim();
363
-
364
- if (message) {
365
- sendMessage(message);
366
- input.value = '';
367
- autoResize(input);
 
 
 
 
 
 
 
 
 
 
 
 
368
  }
369
- });
370
-
371
- // 发送消息
372
- function sendMessage(message) {
373
- const chatContainer = document.getElementById('chat-container');
374
 
375
- // 添加用户消息
376
- const userMessageDiv = document.createElement('div');
377
- userMessageDiv.className = 'max-w-3xl mx-auto message-fade-in';
378
- userMessageDiv.innerHTML = `
379
- <div class="flex space-x-3 justify-end">
380
- <div class="flex-1 min-w-0 flex justify-end">
381
- <div class="bg-blue-600 rounded-lg p-4 max-w-[80%]">
382
- <p class="text-white">${message}</p>
383
- </div>
384
- </div>
385
- <div class="flex-shrink-0">
386
- <div class="w-8 h-8 bg-gray-700 rounded-full flex items-center justify-center">
387
- <i class="fas fa-user text-gray-300"></i>
388
- </div>
389
- </div>
390
- </div>
391
- `;
392
- chatContainer.appendChild(userMessageDiv);
393
-
394
- // 滚动到底部
395
- chatContainer.scrollTop = chatContainer.scrollHeight;
396
 
397
- // 显示AI正在输入
398
- const aiTypingDiv = document.createElement('div');
399
- aiTypingDiv.className = 'max-w-3xl mx-auto message-fade-in';
400
- aiTypingDiv.innerHTML = `
401
- <div class="flex space-x-3">
402
- <div class="flex-shrink-0">
403
- <div class="w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center">
404
- <i class="fas fa-robot text-white"></i>
405
- </div>
406
- </div>
407
- <div class="flex-1 min-w-0">
408
- <div class="bg-gray-800 rounded-lg p-4">
409
- <div class="flex space-x-2 items-center">
410
- <div class="w-2 h-2 bg-gray-500 rounded-full animate-bounce" style="animation-delay: 0s"></div>
411
- <div class="w-2 h-2 bg-gray-500 rounded-full animate-bounce" style="animation-delay: 0.2s"></div>
412
- <div class="w-2 h-2 bg-gray-500 rounded-full animate-bounce" style="animation-delay: 0.4s"></div>
413
- </div>
414
- </div>
415
- </div>
416
- </div>
417
- `;
418
- chatContainer.appendChild(aiTypingDiv);
419
- chatContainer.scrollTop = chatContainer.scrollHeight;
420
-
421
- // 模拟AI回复(实际应用中这里应该是API调用)
422
- setTimeout(() => {
423
- // 移除"正在输入"状态
424
- chatContainer.removeChild(aiTypingDiv);
425
 
426
- // 添加AI回复
427
- const aiResponseDiv = document.createElement('div');
428
- aiResponseDiv.className = 'max-w-3xl mx-auto message-fade-in';
 
 
 
 
 
 
 
 
 
429
 
430
- // 模拟不同类型的回复
431
- const responses = [
432
- `我理解你想了解"${message}"。这是一个很好的问题。让我为你详细解释...`,
433
- `关于"${message}",有几个关键点需要考虑...`,
434
- `"${message}"是一个复杂的话题。简而言之...`,
435
- `我可以从几个角度回答"${message}"这个问题...`
436
- ];
437
 
438
- const randomResponse = responses[Math.floor(Math.random() * responses.length)];
 
 
439
 
440
- aiResponseDiv.innerHTML = `
441
- <div class="flex space-x-3">
442
- <div class="flex-shrink-0">
443
- <div class="w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center">
444
- <i class="fas fa-robot text-white"></i>
445
- </div>
446
- </div>
447
- <div class="flex-1 min-w-0">
448
- <div class="bg-gray-800 rounded-lg p-4">
449
- <p class="text-white font-medium">DeepSeek Chat</p>
450
- <div class="mt-2 text-gray-300">
451
- <p>${randomResponse}</p>
452
- <p class="mt-2">如果你需要更详细的信息或有其他问题,请随时告诉我。</p>
453
- </div>
454
- </div>
455
- </div>
456
- </div>
457
- `;
458
 
459
- chatContainer.appendChild(aiResponseDiv);
460
- chatContainer.scrollTop = chatContainer.scrollHeight;
461
- }, 1500);
462
- }
463
-
464
- // 主题切换
465
- document.getElementById('theme-toggle').addEventListener('click', function() {
466
- const html = document.documentElement;
467
- const isDark = html.classList.contains('dark');
 
 
468
 
469
- if (isDark) {
470
- html.classList.remove('dark');
471
- html.classList.add('light');
472
- this.innerHTML = '<i class="fas fa-sun"></i>';
473
- document.body.className = 'bg-gray-100 text-gray-900 h-screen flex flex-col overflow-hidden';
474
- } else {
475
- html.classList.remove('light');
476
- html.classList.add('dark');
477
- this.innerHTML = '<i class="fas fa-moon"></i>';
478
- document.body.className = 'bg-gray-900 text-gray-100 h-screen flex flex-col overflow-hidden';
479
- }
480
- });
481
-
482
- // 文件上传功能
483
- const fileModal = document.getElementById('file-modal');
484
- const attachButton = document.getElementById('attach-button');
485
- const closeFileModal = document.getElementById('close-file-modal');
486
- const selectFileButton = document.getElementById('select-file-button');
487
- const fileInput = document.getElementById('file-input');
488
- const cancelUpload = document.getElementById('cancel-upload');
489
- const confirmUpload = document.getElementById('confirm-upload');
490
- const selectedFiles = document.getElementById('selected-files');
491
- const fileList = document.getElementById('file-list');
492
-
493
- attachButton.addEventListener('click', () => {
494
- fileModal.classList.remove('hidden');
495
- });
496
-
497
- closeFileModal.addEventListener('click', () => {
498
- fileModal.classList.add('hidden');
499
- });
500
-
501
- selectFileButton.addEventListener('click', () => {
502
- fileInput.click();
503
- });
504
-
505
- fileInput.addEventListener('change', (e) => {
506
- if (e.target.files.length > 0) {
507
- fileList.innerHTML = '';
508
- for (let i = 0; i < e.target.files.length; i++) {
509
- const file = e.target.files[i];
510
- const listItem = document.createElement('li');
511
- listItem.textContent = `${file.name} (${formatFileSize(file.size)})`;
512
- fileList.appendChild(listItem);
513
- }
514
- selectedFiles.classList.remove('hidden');
515
  }
516
- });
517
-
518
- cancelUpload.addEventListener('click', () => {
519
- fileInput.value = '';
520
- selectedFiles.classList.add('hidden');
521
- fileModal.classList.add('hidden');
522
- });
523
-
524
- confirmUpload.addEventListener('click', () => {
525
- if (fileInput.files.length > 0) {
526
- // 这里应该是实际上传文件的代码
527
- alert(`${fileInput.files.length}个文件已选择,准备上传`);
528
- fileModal.classList.add('hidden');
529
-
530
- // 模拟上传成功后在聊天中显示
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
531
  setTimeout(() => {
532
- const chatContainer = document.getElementById('chat-container');
533
- const fileMessageDiv = document.createElement('div');
534
- fileMessageDiv.className = 'max-w-3xl mx-auto message-fade-in';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
535
 
536
- let filesHtml = '';
537
- for (let i = 0; i < fileInput.files.length; i++) {
538
- const file = fileInput.files[i];
539
- filesHtml += `
540
- <div class="flex items-center bg-gray-700 rounded-lg p-2 mt-2">
541
- <i class="fas fa-file-alt text-gray-400 mr-2"></i>
542
- <span class="text-gray-300 text-sm">${file.name}</span>
543
- <span class="text-gray-500 text-xs ml-auto">${formatFileSize(file.size)}</span>
544
- </div>
545
- `;
546
- }
547
 
548
- fileMessageDiv.innerHTML = `
549
- <div class="flex space-x-3 justify-end">
550
- <div class="flex-1 min-w-0 flex justify-end">
551
- <div class="bg-blue-600 rounded-lg p-4 max-w-[80%]">
552
- <p class="text-white">已上传文件:</p>
553
- ${filesHtml}
554
- </div>
555
- </div>
556
- <div class="flex-shrink-0">
557
- <div class="w-8 h-8 bg-gray-700 rounded-full flex items-center justify-center">
558
- <i class="fas fa-user text-gray-300"></i>
559
- </div>
560
- </div>
561
- </div>
562
- `;
563
 
564
- chatContainer.appendChild(fileMessageDiv);
565
- chatContainer.scrollTop = chatContainer.scrollHeight;
566
 
567
- // 清空文件选择
568
- fileInput.value = '';
569
- selectedFiles.classList.add('hidden');
570
- }, 500);
571
- } else {
572
- alert('请先选择文件');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
573
  }
574
- });
575
-
576
- // 语音输入功能
577
- const voiceModal = document.getElementById('voice-modal');
578
- const voiceButton = document.getElementById('voice-button');
579
- const closeVoiceModal = document.getElementById('close-voice-modal');
580
- const startRecording = document.getElementById('start-recording');
581
- const stopRecording = document.getElementById('stop-recording');
582
- const voiceStatus = document.getElementById('voice-status');
583
- const voiceIcon = document.getElementById('voice-icon');
584
- const recordingTimer = document.getElementById('recording-timer');
585
-
586
- let isRecording = false;
587
- let seconds = 0;
588
- let timerInterval;
589
-
590
- voiceButton.addEventListener('click', () => {
591
- voiceModal.classList.remove('hidden');
592
- });
593
-
594
- closeVoiceModal.addEventListener('click', () => {
595
- voiceModal.classList.add('hidden');
596
- stopRecordingFunc();
597
- });
598
-
599
- startRecording.addEventListener('click', () => {
600
- isRecording = true;
601
- startRecording.classList.add('hidden');
602
- stopRecording.classList.remove('hidden');
603
- voiceStatus.textContent = '正在录音...';
604
- voiceIcon.className = 'fas fa-microphone-alt text-3xl text-red-500';
605
- recordingTimer.classList.remove('hidden');
606
 
607
- // 开始计时
608
- seconds = 0;
609
- updateTimer();
610
- timerInterval = setInterval(updateTimer, 1000);
 
 
611
 
612
- // 这里应该是实际开始录音的代码
613
- console.log('录音开始');
614
- });
615
-
616
- stopRecording.addEventListener('click', stopRecordingFunc);
617
-
618
- function stopRecordingFunc() {
619
- if (!isRecording) return;
620
 
621
- isRecording = false;
622
- startRecording.classList.remove('hidden');
623
- stopRecording.classList.add('hidden');
624
- voiceStatus.textContent = '录音已停止';
625
- voiceIcon.className = 'fas fa-microphone text-3xl text-blue-500';
626
- clearInterval(timerInterval);
627
 
628
- // 这里应该是实际停止录音的代码
629
- console.log('录音停止');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
630
 
631
- // 模拟语音识别结果
632
  setTimeout(() => {
633
- const recognizedText = "这是模拟的语音识别结果。实际应用中这里应该是从语音识别API返回的文本。";
634
- document.getElementById('message-input').value = recognizedText;
635
- autoResize(document.getElementById('message-input'));
636
- voiceModal.classList.add('hidden');
637
- }, 1000);
638
- }
639
-
640
- function updateTimer() {
641
- seconds++;
642
- const minutes = Math.floor(seconds / 60);
643
- const remainingSeconds = seconds % 60;
644
- recordingTimer.querySelector('span').textContent =
645
- `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
646
- }
647
-
648
- // 设置功能
649
- const settingsModal = document.getElementById('settings-modal');
650
- const settingsButton = document.getElementById('settings-button');
651
- const closeSettingsModal = document.getElementById('close-settings-modal');
652
- const cancelSettings = document.getElementById('cancel-settings');
653
- const saveSettings = document.getElementById('save-settings');
654
-
655
- settingsButton.addEventListener('click', () => {
656
- settingsModal.classList.remove('hidden');
657
- });
658
-
659
- closeSettingsModal.addEventListener('click', () => {
660
- settingsModal.classList.add('hidden');
661
- });
662
-
663
- cancelSettings.addEventListener('click', () => {
664
- settingsModal.classList.add('hidden');
665
- });
666
-
667
- saveSettings.addEventListener('click', () => {
668
- alert('设置已保存');
669
- settingsModal.classList.add('hidden');
670
- });
671
-
672
- // 用户功能
673
- const userModal = document.getElementById('user-modal');
674
- const userButton = document.getElementById('user-button');
675
- const closeUserModal = document.getElementById('close-user-modal');
676
- const logoutButton = document.getElementById('logout-button');
677
-
678
- userButton.addEventListener('click', () => {
679
- userModal.classList.remove('hidden');
680
- });
681
-
682
- closeUserModal.addEventListener('click', () => {
683
- userModal.classList.add('hidden');
684
- });
685
-
686
- logoutButton.addEventListener('click', () => {
687
- alert('您已退出登录');
688
- userModal.classList.add('hidden');
689
- });
690
-
691
- // 辅助函数:格式化文件大小
692
- function formatFileSize(bytes) {
693
- if (bytes === 0) return '0 Bytes';
694
- const k = 1024;
695
- const sizes = ['Bytes', 'KB', 'MB', 'GB'];
696
- const i = Math.floor(Math.log(bytes) / Math.log(k));
697
- return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
698
  }
699
-
700
- // 初始化时自动调整输入框高度
701
- document.addEventListener('DOMContentLoaded', () => {
702
- autoResize(document.getElementById('message-input'));
703
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
704
  </script>
705
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=raineye/ds" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
706
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>图片优化大师 | 压缩图片 & 去除水印</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
+ .dropzone {
11
+ border: 2px dashed #cbd5e0;
12
+ transition: all 0.3s ease;
13
  }
14
+ .dropzone.active {
15
+ border-color: #4f46e5;
16
+ background-color: #f0f4ff;
17
  }
18
+ .progress-bar {
19
+ transition: width 0.3s ease;
 
20
  }
21
+ .watermark-preview {
22
+ position: relative;
23
+ overflow: hidden;
24
  }
25
+ .watermark-box {
26
+ position: absolute;
27
+ border: 2px dashed red;
28
+ background-color: rgba(255, 0, 0, 0.2);
 
29
  }
30
+ .settings-panel {
31
+ transition: all 0.3s ease;
32
  overflow: hidden;
33
+ }
34
+ .settings-panel.closed {
35
+ max-height: 0;
36
+ }
37
+ .settings-panel.open {
38
+ max-height: 500px;
39
+ }
40
+ .tooltip {
41
+ position: relative;
42
+ }
43
+ .tooltip-text {
44
+ visibility: hidden;
45
+ width: 200px;
46
+ background-color: #333;
47
+ color: #fff;
48
+ text-align: center;
49
+ border-radius: 6px;
50
+ padding: 5px;
51
+ position: absolute;
52
+ z-index: 1;
53
+ bottom: 125%;
54
+ left: 50%;
55
+ transform: translateX(-50%);
56
+ opacity: 0;
57
+ transition: opacity 0.3s;
58
+ }
59
+ .tooltip:hover .tooltip-text {
60
+ visibility: visible;
61
+ opacity: 1;
 
 
 
 
 
 
 
 
 
62
  }
63
  </style>
64
  </head>
65
+ <body class="bg-gray-50 min-h-screen">
66
+ <div class="container mx-auto px-4 py-8">
67
+ <!-- 顶部标题和按钮 -->
68
+ <header class="flex justify-between items-center mb-8">
69
+ <div>
70
+ <h1 class="text-3xl font-bold text-indigo-600">图片优化大师</h1>
71
+ <p class="text-gray-600">轻松压缩图片并去除水印</p>
72
  </div>
73
+ <button id="premium-btn" class="bg-gradient-to-r from-purple-500 to-indigo-600 text-white px-4 py-2 rounded-lg shadow-md hover:shadow-lg transition-all flex items-center">
74
+ <i class="fas fa-crown mr-2"></i>
75
+ 升级专业版
 
 
76
  </button>
77
+ </header>
78
+
79
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
80
+ <!-- 上传区域 -->
81
+ <div class="bg-white rounded-xl shadow-md p-6">
82
+ <div id="dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer mb-6">
83
+ <div class="flex flex-col items-center justify-center">
84
+ <i class="fas fa-cloud-upload-alt text-4xl text-indigo-500 mb-4"></i>
85
+ <h3 class="text-xl font-semibold mb-2">拖放图片到此处</h3>
86
+ <p class="text-gray-500 mb-4">或点击选择文件</p>
87
+ <input type="file" id="fileInput" class="hidden" accept="image/*" multiple>
88
+ <button id="browseBtn" class="bg-indigo-500 text-white px-6 py-2 rounded-lg hover:bg-indigo-600 transition">
89
+ 选择图片
90
+ </button>
 
 
 
91
  </div>
92
  </div>
93
+
94
+ <div id="fileInfo" class="hidden mb-6">
95
+ <div class="flex justify-between items-center mb-2">
96
+ <span class="font-medium">已选文件:</span>
97
+ <span id="fileCount" class="text-gray-600">0 个文件</span>
 
 
98
  </div>
99
+ <div id="fileList" class="border rounded-lg p-3 max-h-40 overflow-y-auto"></div>
100
  </div>
 
 
101
 
102
+ <!-- 高级设置面板 - 默认展开 -->
103
+ <div class="mb-6">
104
+ <button id="settingsToggle" class="flex justify-between items-center w-full bg-gray-100 hover:bg-gray-200 px-4 py-3 rounded-lg transition">
105
+ <span class="font-medium">高级设置</span>
106
+ <i class="fas fa-chevron-up transition-transform"></i>
107
+ </button>
108
+ <div id="settingsPanel" class="settings-panel open bg-gray-50 rounded-lg mt-2 px-4 py-3">
109
+ <div class="mb-4">
110
+ <label class="block text-gray-700 mb-2">压缩级别</label>
111
+ <div class="flex items-center">
112
+ <input type="range" id="compressionLevel" min="0" max="100" value="70" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
113
+ <span id="compressionValue" class="ml-3 text-gray-700 w-12 text-center">70%</span>
114
+ </div>
115
+ </div>
116
+ <div class="mb-4">
117
+ <label class="block text-gray-700 mb-2">输出格式</label>
118
+ <select id="outputFormat" class="w-full border rounded-lg px-3 py-2">
119
+ <option value="original">保持原格式</option>
120
+ <option value="jpeg">JPEG</option>
121
+ <option value="png">PNG</option>
122
+ <option value="webp">WebP</option>
123
+ </select>
124
+ </div>
125
+ <div class="flex items-center mb-4">
126
+ <input type="checkbox" id="removeMetadata" class="mr-2" checked>
127
+ <label for="removeMetadata" class="text-gray-700">移除元数据</label>
128
+ </div>
129
+ <div class="flex items-center">
130
+ <input type="checkbox" id="removeWatermark" class="mr-2" checked>
131
+ <label for="removeWatermark" class="text-gray-700">去除水印</label>
 
 
 
 
 
 
 
 
 
 
 
132
  </div>
133
  </div>
 
 
 
 
 
 
 
 
134
  </div>
 
 
 
 
135
 
136
+ <button id="processBtn" class="w-full bg-green-500 hover:bg-green-600 text-white py-3 rounded-lg font-medium transition flex items-center justify-center hidden">
137
+ <i class="fas fa-magic mr-2"></i>
138
+ 处理图片
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  </button>
 
 
 
140
 
141
+ <div id="progressContainer" class="hidden mt-6">
142
+ <div class="flex justify-between mb-1">
143
+ <span>处理中...</span>
144
+ <span id="progressPercent">0%</span>
145
+ </div>
146
+ <div class="w-full bg-gray-200 rounded-full h-2.5">
147
+ <div id="progressBar" class="progress-bar bg-indigo-600 h-2.5 rounded-full" style="width: 0%"></div>
148
+ </div>
149
+ </div>
150
  </div>
151
+
152
+ <!-- 水印去除工具 -->
153
+ <div class="bg-white rounded-xl shadow-md p-6">
154
+ <h2 class="text-xl font-semibold mb-4">水印去除工具</h2>
155
+ <div id="watermarkPreviewContainer" class="hidden">
156
+ <div class="watermark-preview mb-4 border rounded-lg overflow-hidden relative" style="height: 300px;">
157
+ <img id="watermarkPreview" src="#" alt="预览" class="w-full h-full object-contain">
158
+ <div id="watermarkBox" class="watermark-box hidden"></div>
159
+ </div>
160
+ <div class="flex justify-between mb-4">
161
+ <div>
162
+ <label class="block text-gray-700 mb-2">选择水印区域</label>
163
+ <div class="flex space-x-2">
164
+ <button id="selectBtn" class="bg-indigo-500 text-white px-3 py-1 rounded hover:bg-indigo-600">
165
+ <i class="fas fa-vector-square mr-1"></i> 选择
166
+ </button>
167
+ <button id="clearSelectionBtn" class="bg-gray-200 text-gray-700 px-3 py-1 rounded hover:bg-gray-300">
168
+ <i class="fas fa-eraser mr-1"></i> 清除
169
+ </button>
170
+ </div>
171
+ </div>
172
+ <div class="tooltip">
173
+ <button id="autoDetectBtn" class="bg-purple-500 text-white px-3 py-1 rounded hover:bg-purple-600">
174
+ <i class="fas fa-robot mr-1"></i> 自动检测
175
+ </button>
176
+ <span class="tooltip-text">我们的AI将尝试自动检测常见水印模式</span>
177
+ </div>
178
+ </div>
179
+ <div class="mb-4">
180
+ <label class="block text-gray-700 mb-2">去除强度</label>
181
+ <div class="flex items-center">
182
+ <input type="range" id="removalStrength" min="1" max="10" value="5" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
183
+ <span id="removalStrengthValue" class="ml-3 text-gray-700 w-12 text-center">5</span>
184
+ </div>
185
+ </div>
186
+ <button id="removeWatermarkBtn" class="w-full bg-red-500 hover:bg-red-600 text-white py-3 rounded-lg font-medium transition flex items-center justify-center">
187
+ <i class="fas fa-trash-alt mr-2"></i>
188
+ 去除水印
189
+ </button>
190
  </div>
191
+ <div id="noImageSelected" class="text-center py-12 text-gray-500">
192
+ <i class="fas fa-image fa-3x mb-4"></i>
193
+ <p>未选择用于去除水印的图片。</p>
194
+ <p>请先上传图片以使用此工具。</p>
 
195
  </div>
196
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  </div>
 
198
 
199
+ <!-- 结果展示区域 -->
200
+ <div id="resultsSection" class="hidden mt-8 bg-white rounded-xl shadow-md p-6">
201
+ <h2 class="text-xl font-semibold mb-4">处理结果</h2>
202
  <div class="flex justify-between items-center mb-4">
 
 
 
 
 
 
203
  <div>
204
+ <span class="text-gray-600">原始大小:</span>
205
+ <span id="originalSize" class="font-medium ml-2">-</span>
 
 
 
 
 
206
  </div>
207
  <div>
208
+ <span class="text-gray-600">压缩后大小:</span>
209
+ <span id="compressedSize" class="font-medium ml-2">-</span>
 
 
 
 
 
 
 
 
 
 
 
210
  </div>
211
+ <div>
212
+ <span class="text-gray-600">节省空间:</span>
213
+ <span id="savings" class="font-medium ml-2">-</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  </div>
215
+ <button id="downloadAllBtn" class="bg-indigo-500 text-white px-4 py-2 rounded-lg hover:bg-indigo-600 transition flex items-center">
216
+ <i class="fas fa-download mr-2"></i>
217
+ 全部下载
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  </button>
219
  </div>
220
+ <div id="resultsGrid" class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4"></div>
221
  </div>
222
  </div>
223
 
224
  <script>
225
+ // DOM元素
226
+ const dropzone = document.getElementById('dropzone');
227
+ const fileInput = document.getElementById('fileInput');
228
+ const browseBtn = document.getElementById('browseBtn');
229
+ const fileInfo = document.getElementById('fileInfo');
230
+ const fileList = document.getElementById('fileList');
231
+ const fileCount = document.getElementById('fileCount');
232
+ const processBtn = document.getElementById('processBtn');
233
+ const progressContainer = document.getElementById('progressContainer');
234
+ const progressBar = document.getElementById('progressBar');
235
+ const progressPercent = document.getElementById('progressPercent');
236
+ const compressionLevel = document.getElementById('compressionLevel');
237
+ const compressionValue = document.getElementById('compressionValue');
238
+ const outputFormat = document.getElementById('outputFormat');
239
+ const removeMetadata = document.getElementById('removeMetadata');
240
+ const removeWatermark = document.getElementById('removeWatermark');
241
+ const settingsToggle = document.getElementById('settingsToggle');
242
+ const settingsPanel = document.getElementById('settingsPanel');
243
+ const watermarkPreviewContainer = document.getElementById('watermarkPreviewContainer');
244
+ const watermarkPreview = document.getElementById('watermarkPreview');
245
+ const noImageSelected = document.getElementById('noImageSelected');
246
+ const selectBtn = document.getElementById('selectBtn');
247
+ const clearSelectionBtn = document.getElementById('clearSelectionBtn');
248
+ const autoDetectBtn = document.getElementById('autoDetectBtn');
249
+ const removalStrength = document.getElementById('removalStrength');
250
+ const removalStrengthValue = document.getElementById('removalStrengthValue');
251
+ const removeWatermarkBtn = document.getElementById('removeWatermarkBtn');
252
+ const watermarkBox = document.getElementById('watermarkBox');
253
+ const resultsSection = document.getElementById('resultsSection');
254
+ const resultsGrid = document.getElementById('resultsGrid');
255
+ const originalSize = document.getElementById('originalSize');
256
+ const compressedSize = document.getElementById('compressedSize');
257
+ const savings = document.getElementById('savings');
258
+ const downloadAllBtn = document.getElementById('downloadAllBtn');
259
+ const premiumBtn = document.getElementById('premium-btn');
260
+
261
+ // 变量
262
+ let selectedFiles = [];
263
+ let isSelectingWatermark = false;
264
+ let selectionStart = { x: 0, y: 0 };
265
+ let currentImageForWatermark = null;
266
+ let processedFiles = [];
267
+
268
+ // 事件监听
269
+ browseBtn.addEventListener('click', () => fileInput.click());
270
+ fileInput.addEventListener('change', handleFileSelect);
271
+ dropzone.addEventListener('dragover', handleDragOver);
272
+ dropzone.addEventListener('dragleave', handleDragLeave);
273
+ dropzone.addEventListener('drop', handleDrop);
274
+ processBtn.addEventListener('click', processImages);
275
+ compressionLevel.addEventListener('input', updateCompressionValue);
276
+ settingsToggle.addEventListener('click', toggleSettingsPanel);
277
+ removalStrength.addEventListener('input', updateRemovalStrengthValue);
278
+ selectBtn.addEventListener('click', startWatermarkSelection);
279
+ clearSelectionBtn.addEventListener('click', clearWatermarkSelection);
280
+ autoDetectBtn.addEventListener('click', autoDetectWatermark);
281
+ removeWatermarkBtn.addEventListener('click', processWatermarkRemoval);
282
+ downloadAllBtn.addEventListener('click', downloadAllProcessedFiles);
283
+ premiumBtn.addEventListener('click', showPremiumModal);
284
+
285
+ // 水印选择事件
286
+ watermarkPreview.addEventListener('mousedown', startSelection);
287
+ document.addEventListener('mousemove', updateSelection);
288
+ document.addEventListener('mouseup', endSelection);
289
+
290
+ // 函数
291
+ function handleFileSelect(e) {
292
+ const files = e.target.files || e.dataTransfer.files;
293
+ addFilesToSelection(files);
294
+ }
295
+
296
+ function handleDragOver(e) {
297
  e.preventDefault();
298
+ dropzone.classList.add('active');
299
+ }
300
+
301
+ function handleDragLeave() {
302
+ dropzone.classList.remove('active');
303
+ }
304
+
305
+ function handleDrop(e) {
306
+ e.preventDefault();
307
+ dropzone.classList.remove('active');
308
+ const files = e.dataTransfer.files;
309
+ addFilesToSelection(files);
310
+ }
311
+
312
+ function addFilesToSelection(files) {
313
+ for (let i = 0; i < files.length; i++) {
314
+ if (files[i].type.match('image.*')) {
315
+ selectedFiles.push(files[i]);
316
+ }
317
  }
 
 
 
 
 
318
 
319
+ updateFileList();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
 
321
+ if (selectedFiles.length > 0) {
322
+ fileInfo.classList.remove('hidden');
323
+ processBtn.classList.remove('hidden');
324
+ fileCount.textContent = `${selectedFiles.length} 个文件`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
 
326
+ // 设置第一张图片用于水印去除预览
327
+ if (!currentImageForWatermark) {
328
+ setImageForWatermarkRemoval(selectedFiles[0]);
329
+ }
330
+ }
331
+ }
332
+
333
+ function updateFileList() {
334
+ fileList.innerHTML = '';
335
+ selectedFiles.forEach((file, index) => {
336
+ const div = document.createElement('div');
337
+ div.className = 'flex justify-between items-center py-2 border-b last:border-b-0';
338
 
339
+ const fileName = document.createElement('span');
340
+ fileName.className = 'truncate';
341
+ fileName.textContent = file.name;
 
 
 
 
342
 
343
+ const fileSize = document.createElement('span');
344
+ fileSize.className = 'text-gray-500 text-sm';
345
+ fileSize.textContent = formatFileSize(file.size);
346
 
347
+ const removeBtn = document.createElement('button');
348
+ removeBtn.className = 'text-red-500 hover:text-red-700 ml-2';
349
+ removeBtn.innerHTML = '<i class="fas fa-times"></i>';
350
+ removeBtn.addEventListener('click', () => removeFile(index));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
 
352
+ div.appendChild(fileName);
353
+ div.appendChild(fileSize);
354
+ div.appendChild(removeBtn);
355
+ fileList.appendChild(div);
356
+ });
357
+ }
358
+
359
+ function removeFile(index) {
360
+ selectedFiles.splice(index, 1);
361
+ updateFileList();
362
+ fileCount.textContent = `${selectedFiles.length} 个文件`;
363
 
364
+ if (selectedFiles.length === 0) {
365
+ fileInfo.classList.add('hidden');
366
+ processBtn.classList.add('hidden');
367
+ watermarkPreviewContainer.classList.add('hidden');
368
+ noImageSelected.classList.remove('hidden');
369
+ currentImageForWatermark = null;
370
+ } else if (index === 0) {
371
+ setImageForWatermarkRemoval(selectedFiles[0]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
372
  }
373
+ }
374
+
375
+ function formatFileSize(bytes) {
376
+ if (bytes === 0) return '0 字节';
377
+ const k = 1024;
378
+ const sizes = ['字节', 'KB', 'MB', 'GB'];
379
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
380
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
381
+ }
382
+
383
+ function updateCompressionValue() {
384
+ compressionValue.textContent = `${compressionLevel.value}%`;
385
+ }
386
+
387
+ function updateRemovalStrengthValue() {
388
+ removalStrengthValue.textContent = removalStrength.value;
389
+ }
390
+
391
+ function toggleSettingsPanel() {
392
+ settingsPanel.classList.toggle('open');
393
+ const icon = settingsToggle.querySelector('i');
394
+ icon.classList.toggle('fa-chevron-down');
395
+ icon.classList.toggle('fa-chevron-up');
396
+ }
397
+
398
+ function processImages() {
399
+ if (selectedFiles.length === 0) return;
400
+
401
+ progressContainer.classList.remove('hidden');
402
+ processBtn.classList.add('hidden');
403
+
404
+ let processedCount = 0;
405
+ processedFiles = [];
406
+
407
+ // 模拟处理过程(实际应用中会使用真实的图片处理库)
408
+ selectedFiles.forEach((file, index) => {
409
  setTimeout(() => {
410
+ // 模拟处理时间
411
+ simulateProgress(index, () => {
412
+ processedCount++;
413
+
414
+ // 计算大小(模拟)
415
+ const originalSize = file.size;
416
+ const compressionRatio = parseInt(compressionLevel.value) / 100;
417
+ const compressedSize = Math.max(1000, originalSize * compressionRatio); // 确保最小大小
418
+
419
+ // 创建结果对象
420
+ const result = {
421
+ originalFile: file,
422
+ compressedFile: new File([file], `压缩_${file.name}`, { type: file.type }),
423
+ originalSize,
424
+ compressedSize,
425
+ downloadUrl = URL.createObjectURL(file) // 实际应用中会是处理后的文件
426
+ };
427
+
428
+ processedFiles.push(result);
429
+
430
+ // 更新进度
431
+ const progress = Math.round((processedCount / selectedFiles.length) * 100);
432
+ progressBar.style.width = `${progress}%`;
433
+ progressPercent.textContent = `${progress}%`;
434
+
435
+ // 所有文件处理完成
436
+ if (processedCount === selectedFiles.length) {
437
+ setTimeout(showResults, 500);
438
+ }
439
+ });
440
+ }, index * 500);
441
+ });
442
+ }
443
+
444
+ function simulateProgress(index, callback) {
445
+ let progress = 0;
446
+ const interval = setInterval(() => {
447
+ progress += 5;
448
+ const overallProgress = Math.min(100, ((index * 100) + progress) / selectedFiles.length);
449
+ progressBar.style.width = `${overallProgress}%`;
450
+ progressPercent.textContent = `${Math.round(overallProgress)}%`;
451
+
452
+ if (progress >= 100) {
453
+ clearInterval(interval);
454
+ callback();
455
+ }
456
+ }, 100);
457
+ }
458
+
459
+ function showResults() {
460
+ progressContainer.classList.add('hidden');
461
+ resultsSection.classList.remove('hidden');
462
+
463
+ // 计算总量
464
+ const totalOriginal = processedFiles.reduce((sum, file) => sum + file.originalSize, 0);
465
+ const totalCompressed = processedFiles.reduce((sum, file) => sum + file.compressedSize, 0);
466
+ const savingsPercentage = ((totalOriginal - totalCompressed) / totalOriginal * 100).toFixed(1);
467
+
468
+ originalSize.textContent = formatFileSize(totalOriginal);
469
+ compressedSize.textContent = formatFileSize(totalCompressed);
470
+ savings.textContent = `${savingsPercentage}% (${formatFileSize(totalOriginal - totalCompressed)})`;
471
+
472
+ // 显示结果
473
+ resultsGrid.innerHTML = '';
474
+ processedFiles.forEach((file, index) => {
475
+ const reader = new FileReader();
476
+ reader.onload = (e) => {
477
+ const resultCard = document.createElement('div');
478
+ resultCard.className = 'bg-gray-50 rounded-lg overflow-hidden border';
479
 
480
+ const imgContainer = document.createElement('div');
481
+ imgContainer.className = 'relative pt-[100%]';
 
 
 
 
 
 
 
 
 
482
 
483
+ const img = document.createElement('img');
484
+ img.src = e.target.result;
485
+ img.className = 'absolute top-0 left-0 w-full h-full object-cover';
486
+
487
+ const infoContainer = document.createElement('div');
488
+ infoContainer.className = 'p-3';
489
+
490
+ const fileName = document.createElement('div');
491
+ fileName.className = 'font-medium truncate mb-1';
492
+ fileName.textContent = file.originalFile.name;
493
+
494
+ const sizeInfo = document.createElement('div');
495
+ sizeInfo.className = 'flex justify-between text-sm text-gray-600 mb-2';
 
 
496
 
497
+ const originalSizeSpan = document.createElement('span');
498
+ originalSizeSpan.textContent = formatFileSize(file.originalSize);
499
 
500
+ const compressedSizeSpan = document.createElement('span');
501
+ compressedSizeSpan.className = 'text-green-600 font-medium';
502
+ compressedSizeSpan.textContent = formatFileSize(file.compressedSize);
503
+
504
+ sizeInfo.appendChild(originalSizeSpan);
505
+ sizeInfo.appendChild(compressedSizeSpan);
506
+
507
+ const downloadBtn = document.createElement('button');
508
+ downloadBtn.className = 'w-full bg-indigo-500 hover:bg-indigo-600 text-white py-2 rounded text-sm transition flex items-center justify-center';
509
+ downloadBtn.innerHTML = '<i class="fas fa-download mr-2"></i> 下载';
510
+ downloadBtn.addEventListener('click', () => downloadFile(file));
511
+
512
+ infoContainer.appendChild(fileName);
513
+ infoContainer.appendChild(sizeInfo);
514
+ infoContainer.appendChild(downloadBtn);
515
+
516
+ imgContainer.appendChild(img);
517
+ resultCard.appendChild(imgContainer);
518
+ resultCard.appendChild(infoContainer);
519
+
520
+ resultsGrid.appendChild(resultCard);
521
+ };
522
+ reader.readAsDataURL(file.originalFile);
523
+ });
524
+ }
525
+
526
+ function downloadFile(file) {
527
+ const a = document.createElement('a');
528
+ a.href = file.downloadUrl;
529
+ a.download = file.compressedFile.name;
530
+ document.body.appendChild(a);
531
+ a.click();
532
+ document.body.removeChild(a);
533
+ }
534
+
535
+ function downloadAllProcessedFiles() {
536
+ processedFiles.forEach((file, index) => {
537
+ setTimeout(() => {
538
+ downloadFile(file);
539
+ }, index * 500);
540
+ });
541
+ }
542
+
543
+ function setImageForWatermarkRemoval(file) {
544
+ const reader = new FileReader();
545
+ reader.onload = (e) => {
546
+ watermarkPreview.src = e.target.result;
547
+ watermarkPreviewContainer.classList.remove('hidden');
548
+ noImageSelected.classList.add('hidden');
549
+ currentImageForWatermark = file;
550
+ clearWatermarkSelection();
551
+ };
552
+ reader.readAsDataURL(file);
553
+ }
554
+
555
+ function startWatermarkSelection() {
556
+ isSelectingWatermark = true;
557
+ watermarkBox.classList.remove('hidden');
558
+ selectBtn.classList.add('bg-indigo-600');
559
+ }
560
+
561
+ function clearWatermarkSelection() {
562
+ watermarkBox.classList.add('hidden');
563
+ watermarkBox.style.width = '0';
564
+ watermarkBox.style.height = '0';
565
+ selectBtn.classList.remove('bg-indigo-600');
566
+ isSelectingWatermark = false;
567
+ }
568
+
569
+ function startSelection(e) {
570
+ if (!isSelectingWatermark) return;
571
+
572
+ e.preventDefault();
573
+ const rect = watermarkPreview.getBoundingClientRect();
574
+ selectionStart = {
575
+ x: e.clientX - rect.left,
576
+ y: e.clientY - rect.top
577
+ };
578
+
579
+ watermarkBox.style.left = `${selectionStart.x}px`;
580
+ watermarkBox.style.top = `${selectionStart.y}px`;
581
+ watermarkBox.style.width = '0';
582
+ watermarkBox.style.height = '0';
583
+ }
584
+
585
+ function updateSelection(e) {
586
+ if (!isSelectingWatermark || !selectionStart) return;
587
+
588
+ const rect = watermarkPreview.getBoundingClientRect();
589
+ const currentX = e.clientX - rect.left;
590
+ const currentY = e.clientY - rect.top;
591
+
592
+ const width = currentX - selectionStart.x;
593
+ const height = currentY - selectionStart.y;
594
+
595
+ watermarkBox.style.width = `${Math.abs(width)}px`;
596
+ watermarkBox.style.height = `${Math.abs(height)}px`;
597
+
598
+ if (width < 0) {
599
+ watermarkBox.style.left = `${currentX}px`;
600
  }
601
+ if (height < 0) {
602
+ watermarkBox.style.top = `${currentY}px`;
603
+ }
604
+ }
605
+
606
+ function endSelection() {
607
+ if (!isSelectingWatermark) return;
608
+ isSelectingWatermark = false;
609
+ selectBtn.classList.remove('bg-indigo-600');
610
+ }
611
+
612
+ function autoDetectWatermark() {
613
+ // 模拟AI检测
614
+ watermarkBox.classList.remove('hidden');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
615
 
616
+ // 随机位置用于演示(实际应用中会使用真实的检测)
617
+ const rect = watermarkPreview.getBoundingClientRect();
618
+ const width = Math.min(100, rect.width * 0.3);
619
+ const height = Math.min(50, rect.height * 0.1);
620
+ const left = Math.random() * (rect.width - width);
621
+ const top = rect.height - height - 10; // 通常在底部
622
 
623
+ watermarkBox.style.left = `${left}px`;
624
+ watermarkBox.style.top = `${top}px`;
625
+ watermarkBox.style.width = `${width}px`;
626
+ watermarkBox.style.height = `${height}px`;
 
 
 
 
627
 
628
+ // 显示成功消息
629
+ const originalText = autoDetectBtn.innerHTML;
630
+ autoDetectBtn.innerHTML = '<i class="fas fa-check mr-1"></i> 已检测!';
631
+ autoDetectBtn.classList.remove('bg-purple-500');
632
+ autoDetectBtn.classList.add('bg-green-500');
 
633
 
634
+ setTimeout(() => {
635
+ autoDetectBtn.innerHTML = originalText;
636
+ autoDetectBtn.classList.add('bg-purple-500');
637
+ autoDetectBtn.classList.remove('bg-green-500');
638
+ }, 2000);
639
+ }
640
+
641
+ function processWatermarkRemoval() {
642
+ if (!watermarkBox || watermarkBox.classList.contains('hidden')) {
643
+ alert('请先选择水印区域');
644
+ return;
645
+ }
646
+
647
+ // 模拟处理过程
648
+ removeWatermarkBtn.disabled = true;
649
+ removeWatermarkBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> 处理中...';
650
 
 
651
  setTimeout(() => {
652
+ // 实际应用中会真正处理图片
653
+ // 演示中只显示"成功"消息
654
+ removeWatermarkBtn.innerHTML = '<i class="fas fa-check mr-2"></i> 水印已去除!';
655
+ removeWatermarkBtn.classList.remove('bg-red-500');
656
+ removeWatermarkBtn.classList.add('bg-green-500');
657
+
658
+ setTimeout(() => {
659
+ removeWatermarkBtn.innerHTML = '<i class="fas fa-trash-alt mr-2"></i> 去除水印';
660
+ removeWatermarkBtn.classList.add('bg-red-500');
661
+ removeWatermarkBtn.classList.remove('bg-green-500');
662
+ removeWatermarkBtn.disabled = false;
663
+ }, 2000);
664
+ }, 2000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
665
  }
666
+
667
+ function showPremiumModal() {
668
+ // 创建模态框
669
+ const modal = document.createElement('div');
670
+ modal.className = 'fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50';
671
+ modal.innerHTML = `
672
+ <div class="bg-white rounded-xl p-6 max-w-md w-full mx-4">
673
+ <div class="flex justify-between items-center mb-4">
674
+ <h3 class="text-xl font-bold text-indigo-600">升级专业版</h3>
675
+ <button id="closeModal" class="text-gray-500 hover:text-gray-700">
676
+ <i class="fas fa-times"></i>
677
+ </button>
678
+ </div>
679
+ <div class="mb-6">
680
+ <div class="bg-indigo-50 rounded-lg p-4 mb-4">
681
+ <div class="flex items-center mb-2">
682
+ <i class="fas fa-check-circle text-green-500 mr-2"></i>
683
+ <span>自动去除所有水印</span>
684
+ </div>
685
+ <div class="flex items-center mb-2">
686
+ <i class="fas fa-check-circle text-green-500 mr-2"></i>
687
+ <span>批量处理无限图片</span>
688
+ </div>
689
+ <div class="flex items-center">
690
+ <i class="fas fa-check-circle text-green-500 mr-2"></i>
691
+ <span>优先技术支持</span>
692
+ </div>
693
+ </div>
694
+ <div class="text-center py-4">
695
+ <p class="text-3xl font-bold text-gray-800 mb-2">¥9.99<span class="text-lg text-gray-600">/月</span></p>
696
+ <p class="text-gray-600">或 ¥99.99/年 (节省20%)</p>
697
+ </div>
698
+ </div>
699
+ <button id="upgradeBtn" class="w-full bg-gradient-to-r from-purple-500 to-indigo-600 text-white py-3 rounded-lg font-medium hover:opacity-90 transition flex items-center justify-center">
700
+ <i class="fas fa-crown mr-2"></i>
701
+ 立即升级
702
+ </button>
703
+ </div>
704
+ `;
705
+
706
+ document.body.appendChild(modal);
707
+
708
+ // 添加事件监听
709
+ modal.querySelector('#closeModal').addEventListener('click', () => {
710
+ modal.remove();
711
+ });
712
+
713
+ modal.querySelector('#upgradeBtn').addEventListener('click', () => {
714
+ alert('感谢选择专业版! 正在跳转支付...');
715
+ modal.remove();
716
+ });
717
+
718
+ // 点击外部关闭模态框
719
+ modal.addEventListener('click', (e) => {
720
+ if (e.target === modal) {
721
+ modal.remove();
722
+ }
723
+ });
724
+ }
725
+
726
+ // 初始化
727
+ updateCompressionValue();
728
+ updateRemovalStrengthValue();
729
  </script>
730
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=raineye/ds" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
731
  </html>