zhenhai18 commited on
Commit
3cee05d
·
verified ·
1 Parent(s): 5956616

这个好像只是个前端界面,没有设计交互,后端服务支持吧,需要在次基础上开发和完善后端服务和业务交互。 - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +1162 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Kmlu
3
- emoji: 📚
4
- colorFrom: blue
5
- colorTo: gray
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: kmlu
3
+ emoji: 🐳
4
+ colorFrom: purple
5
+ colorTo: red
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1162 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>智能知识库管理系统</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
+ .sidebar-collapsed {
11
+ width: 70px;
12
+ }
13
+ .sidebar-collapsed .nav-text {
14
+ display: none;
15
+ }
16
+ .sidebar-expanded {
17
+ width: 250px;
18
+ }
19
+ .content-collapsed {
20
+ margin-left: 70px;
21
+ }
22
+ .content-expanded {
23
+ margin-left: 250px;
24
+ }
25
+ .folder-item:hover, .file-item:hover {
26
+ background-color: rgba(59, 130, 246, 0.1);
27
+ }
28
+ .tree-view {
29
+ transition: all 0.3s ease;
30
+ }
31
+ .tree-node {
32
+ cursor: pointer;
33
+ }
34
+ .context-menu {
35
+ position: absolute;
36
+ z-index: 1000;
37
+ background: white;
38
+ border-radius: 4px;
39
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
40
+ display: none;
41
+ }
42
+ .context-menu-item {
43
+ padding: 8px 16px;
44
+ cursor: pointer;
45
+ }
46
+ .context-menu-item:hover {
47
+ background-color: #f0f0f0;
48
+ }
49
+ .json-viewer {
50
+ background-color: #f8f8f8;
51
+ border-radius: 4px;
52
+ padding: 10px;
53
+ overflow-x: auto;
54
+ }
55
+ .loading-spinner {
56
+ animation: spin 1s linear infinite;
57
+ }
58
+ @keyframes spin {
59
+ 0% { transform: rotate(0deg); }
60
+ 100% { transform: rotate(360deg); }
61
+ }
62
+ .chat-bubble {
63
+ max-width: 70%;
64
+ padding: 10px 15px;
65
+ border-radius: 18px;
66
+ margin-bottom: 10px;
67
+ }
68
+ .user-bubble {
69
+ background-color: #3b82f6;
70
+ color: white;
71
+ margin-left: auto;
72
+ }
73
+ .ai-bubble {
74
+ background-color: #f3f4f6;
75
+ color: #333;
76
+ margin-right: auto;
77
+ }
78
+ </style>
79
+ </head>
80
+ <body class="bg-gray-50">
81
+ <div class="flex h-screen overflow-hidden">
82
+ <!-- 侧边栏 -->
83
+ <div id="sidebar" class="sidebar-expanded bg-white shadow-md flex flex-col h-full transition-all duration-300">
84
+ <div class="flex items-center justify-between p-4 border-b">
85
+ <div class="flex items-center">
86
+ <i class="fas fa-brain text-blue-500 text-xl mr-2"></i>
87
+ <span class="text-lg font-semibold">智能知识库</span>
88
+ </div>
89
+ <button id="toggleSidebar" class="text-gray-500 hover:text-gray-700">
90
+ <i class="fas fa-bars"></i>
91
+ </button>
92
+ </div>
93
+
94
+ <div class="flex-1 overflow-y-auto p-2">
95
+ <div class="flex items-center justify-between mb-2 px-2">
96
+ <span class="text-sm font-medium text-gray-500">知识库结构</span>
97
+ <button id="createRootFolder" class="text-blue-500 hover:text-blue-700 text-sm">
98
+ <i class="fas fa-plus"></i>
99
+ <span class="nav-text ml-1">新增</span>
100
+ </button>
101
+ </div>
102
+
103
+ <div id="knowledgeTree" class="tree-view space-y-1">
104
+ <!-- 动态生成的知识库树结构 -->
105
+ </div>
106
+ </div>
107
+
108
+ <div class="p-4 border-t">
109
+ <button class="w-full bg-blue-500 hover:bg-blue-600 text-white py-2 px-4 rounded-md flex items-center justify-center">
110
+ <i class="fas fa-cloud-upload-alt mr-2"></i>
111
+ <span class="nav-text">同步云端</span>
112
+ </button>
113
+ </div>
114
+ </div>
115
+
116
+ <!-- 主内容区 -->
117
+ <div class="content-expanded flex-1 flex flex-col overflow-hidden transition-all duration-300">
118
+ <!-- 顶部导航 -->
119
+ <header class="bg-white shadow-sm p-4 flex items-center justify-between">
120
+ <div class="flex items-center">
121
+ <h1 class="text-xl font-semibold text-gray-800" id="currentLocation">知识库管理</h1>
122
+ </div>
123
+ <div class="flex items-center space-x-4">
124
+ <div class="relative">
125
+ <input type="text" placeholder="搜索知识库..." class="pl-10 pr-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
126
+ <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
127
+ </div>
128
+ <div class="flex items-center space-x-2">
129
+ <button class="bg-blue-500 hover:bg-blue-600 text-white p-2 rounded-full">
130
+ <i class="fas fa-user"></i>
131
+ </button>
132
+ <button class="bg-gray-100 hover:bg-gray-200 text-gray-700 p-2 rounded-full">
133
+ <i class="fas fa-cog"></i>
134
+ </button>
135
+ </div>
136
+ </div>
137
+ </header>
138
+
139
+ <!-- 主内容面板 -->
140
+ <main class="flex-1 overflow-hidden flex">
141
+ <!-- 文件夹内容区 -->
142
+ <div id="folderContent" class="w-2/3 bg-white border-r overflow-y-auto p-6">
143
+ <div class="flex items-center justify-between mb-6">
144
+ <h2 class="text-lg font-semibold">文件夹内容</h2>
145
+ <div class="flex space-x-2">
146
+ <button id="uploadFileBtn" class="flex items-center bg-blue-500 hover:bg-blue-600 text-white px-3 py-1 rounded text-sm">
147
+ <i class="fas fa-upload mr-1"></i> 上传文件
148
+ <input type="file" id="fileInput" class="hidden" multiple>
149
+ </button>
150
+ <button id="createFolderBtn" class="flex items-center bg-green-500 hover:bg-green-600 text-white px-3 py-1 rounded text-sm">
151
+ <i class="fas fa-folder-plus mr-1"></i> 新建文件夹
152
+ </button>
153
+ </div>
154
+ </div>
155
+
156
+ <!-- 面包屑导航 -->
157
+ <div id="breadcrumb" class="flex items-center text-sm text-gray-600 mb-6">
158
+ <span class="hover:text-blue-500 cursor-pointer">知识库</span>
159
+ </div>
160
+
161
+ <!-- 文件列表 -->
162
+ <div id="fileList" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
163
+ <!-- 动态生成的文件和文件夹列表 -->
164
+ <div class="text-center py-10 text-gray-400">
165
+ <i class="fas fa-folder-open text-4xl mb-2"></i>
166
+ <p>当前文件夹为空</p>
167
+ </div>
168
+ </div>
169
+
170
+ <!-- 文件预览面板 -->
171
+ <div id="filePreview" class="hidden mt-6 p-4 border rounded-lg bg-gray-50">
172
+ <div class="flex justify-between items-center mb-4">
173
+ <h3 class="font-medium">文件预览</h3>
174
+ <div>
175
+ <button class="text-gray-500 hover:text-gray-700 mr-2">
176
+ <i class="fas fa-download"></i>
177
+ </button>
178
+ <button class="text-gray-500 hover:text-gray-700">
179
+ <i class="fas fa-times"></i>
180
+ </button>
181
+ </div>
182
+ </div>
183
+ <div id="previewContent" class="max-h-80 overflow-auto">
184
+ <!-- 动态生成的文件预览内容 -->
185
+ </div>
186
+ </div>
187
+ </div>
188
+
189
+ <!-- AI助手面板 -->
190
+ <div id="aiPanel" class="w-1/3 bg-white p-4 overflow-y-auto">
191
+ <div class="sticky top-0 bg-white pb-2 border-b mb-4">
192
+ <div class="flex items-center justify-between">
193
+ <h2 class="text-lg font-semibold">AI知识助手</h2>
194
+ <div class="flex space-x-2">
195
+ <button class="text-gray-500 hover:text-gray-700">
196
+ <i class="fas fa-history"></i>
197
+ </button>
198
+ </div>
199
+ </div>
200
+
201
+ <div class="mt-4">
202
+ <div class="flex items-center space-x-2 mb-2">
203
+ <label class="text-sm font-medium text-gray-700">AI模型:</label>
204
+ <select id="aiModelSelect" class="flex-1 border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
205
+ <option value="gpt-4">GPT-4</option>
206
+ <option value="gpt-3.5-turbo">GPT-3.5 Turbo</option>
207
+ <option value="claude-2">Claude 2</option>
208
+ <option value="llama-2">Llama 2</option>
209
+ </select>
210
+ </div>
211
+
212
+ <div class="flex items-center space-x-2">
213
+ <label class="text-sm font-medium text-gray-700">检索方式:</label>
214
+ <select id="searchMethodSelect" class="flex-1 border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
215
+ <option value="semantic">语义检索</option>
216
+ <option value="keyword">关键词检索</option>
217
+ <option value="hybrid">混合检索</option>
218
+ </select>
219
+ </div>
220
+ </div>
221
+ </div>
222
+
223
+ <!-- 聊天消息区 -->
224
+ <div id="chatContainer" class="space-y-3 mb-4">
225
+ <div class="chat-bubble ai-bubble">
226
+ <div class="font-medium mb-1">AI助手</div>
227
+ <p>您好!我是您的AI知识助手。您可以向我提问关于知识库中的任何内容,或者让我根据现有知识生成新的文档。</p>
228
+ </div>
229
+ </div>
230
+
231
+ <!-- 聊天输入区 -->
232
+ <div class="sticky bottom-0 bg-white pt-4">
233
+ <div class="flex space-x-2 mb-4">
234
+ <button class="bg-yellow-100 hover:bg-yellow-200 text-yellow-800 px-3 py-1 rounded text-sm">
235
+ <i class="fas fa-lightbulb mr-1"></i> 文档观点
236
+ </button>
237
+ <button class="bg-purple-100 hover:bg-purple-200 text-purple-800 px-3 py-1 rounded text-sm">
238
+ <i class="fas fa-file-alt mr-1"></i> 文档摘要
239
+ </button>
240
+ <button id="generateDocBtn" class="bg-green-100 hover:bg-green-200 text-green-800 px-3 py-1 rounded text-sm">
241
+ <i class="fas fa-magic mr-1"></i> 生成文档
242
+ </button>
243
+ </div>
244
+
245
+ <div class="relative">
246
+ <textarea id="chatInput" rows="3" class="w-full border rounded-lg p-3 pr-10 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="输入您的问题或文档生成要求..."></textarea>
247
+ <button id="sendChatBtn" class="absolute right-2 bottom-2 bg-blue-500 text-white p-1 rounded-md hover:bg-blue-600">
248
+ <i class="fas fa-paper-plane"></i>
249
+ </button>
250
+ </div>
251
+ </div>
252
+ </div>
253
+ </main>
254
+ </div>
255
+ </div>
256
+
257
+ <!-- 上下文菜单 -->
258
+ <div id="contextMenu" class="context-menu">
259
+ <div class="context-menu-item rename-item"><i class="fas fa-edit mr-2"></i>重命名</div>
260
+ <div class="context-menu-item move-item"><i class="fas fa-share mr-2"></i>移动</div>
261
+ <div class="context-menu-item delete-item"><i class="fas fa-trash mr-2"></i>删除</div>
262
+ <div class="border-t"></div>
263
+ <div class="context-menu-item properties-item"><i class="fas fa-info-circle mr-2"></i>属性</div>
264
+ </div>
265
+
266
+ <!-- 模态框 -->
267
+ <div id="modalOverlay" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50 flex items-center justify-center">
268
+ <div id="modal" class="bg-white rounded-lg w-full max-w-md">
269
+ <div class="flex justify-between items-center p-4 border-b">
270
+ <h3 id="modalTitle" class="text-lg font-medium">模态框标题</h3>
271
+ <button id="closeModal" class="text-gray-500 hover:text-gray-700">
272
+ <i class="fas fa-times"></i>
273
+ </button>
274
+ </div>
275
+ <div id="modalContent" class="p-4">
276
+ <!-- 动态内容 -->
277
+ </div>
278
+ <div class="flex justify-end p-4 border-t space-x-2">
279
+ <button id="cancelModal" class="px-4 py-2 border rounded-md hover:bg-gray-50">取消</button>
280
+ <button id="confirmModal" class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600">确认</button>
281
+ </div>
282
+ </div>
283
+ </div>
284
+
285
+ <!-- 文档生成设置模态框 -->
286
+ <div id="docGenModal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50 flex items-center justify-center">
287
+ <div class="bg-white rounded-lg w-full max-w-xl">
288
+ <div class="flex justify-between items-center p-4 border-b">
289
+ <h3 class="text-lg font-medium">文档生成设置</h3>
290
+ <button id="closeDocGenModal" class="text-gray-500 hover:text-gray-700">
291
+ <i class="fas fa-times"></i>
292
+ </button>
293
+ </div>
294
+ <div class="p-4 space-y-4">
295
+ <div>
296
+ <label class="block text-sm font-medium text-gray-700 mb-1">文档类型</label>
297
+ <select id="docType" class="w-full border rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
298
+ <option value="report">报告</option>
299
+ <option value="summary">摘要</option>
300
+ <option value="manual">手册</option>
301
+ <option value="article">文章</option>
302
+ <option value="presentation">演示文稿</option>
303
+ </select>
304
+ </div>
305
+
306
+ <div>
307
+ <label class="block text-sm font-medium text-gray-700 mb-1">文档风格</label>
308
+ <div class="grid grid-cols-2 gap-2">
309
+ <button class="style-btn border px-3 py-2 rounded-lg hover:bg-gray-50" data-style="professional">专业正式</button>
310
+ <button class="style-btn border px-3 py-2 rounded-lg hover:bg-gray-50" data-style="concise">简洁明了</button>
311
+ <button class="style-btn border px-3 py-2 rounded-lg hover:bg-gray-50" data-style="detailed">详细深入</button>
312
+ <button class="style-btn border px-3 py-2 rounded-lg hover:bg-gray-50" data-style="persuasive">有说服力</button>
313
+ </div>
314
+ </div>
315
+
316
+ <div>
317
+ <label class="block text-sm font-medium text-gray-700 mb-1">文档长度</label>
318
+ <div class="flex items-center space-x-2">
319
+ <input type="range" id="docLength" min="100" max="5000" step="100" value="1500" class="w-full">
320
+ <span id="lengthDisplay" class="text-sm text-gray-600">1500字</span>
321
+ </div>
322
+ </div>
323
+
324
+ <div>
325
+ <label class="block text-sm font-medium text-gray-700 mb-1">具体要求</label>
326
+ <textarea id="docRequirements" rows="4" class="w-full border rounded-lg p-3 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="输入您的具体要求,例如格式、重点内容等..."></textarea>
327
+ </div>
328
+ </div>
329
+ <div class="flex justify-between p-4 border-t">
330
+ <button id="cancelDocGen" class="px-4 py-2 border rounded-md hover:bg-gray-50">取消</button>
331
+ <button id="startDocGen" class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600">开始生成</button>
332
+ </div>
333
+ </div>
334
+ </div>
335
+
336
+ <script>
337
+ // API 基础配置
338
+ const API_BASE_URL = '/api';
339
+ const API_ENDPOINTS = {
340
+ auth: {
341
+ check: '/auth/check',
342
+ login: '/auth/login',
343
+ logout: '/auth/logout'
344
+ },
345
+ knowledge: {
346
+ tree: '/knowledge/tree',
347
+ folder: '/knowledge/folder',
348
+ file: '/knowledge/file',
349
+ search: '/knowledge/search',
350
+ upload: '/knowledge/upload'
351
+ },
352
+ ai: {
353
+ chat: '/ai/chat',
354
+ generate: '/ai/generate',
355
+ summarize: '/ai/summarize'
356
+ }
357
+ };
358
+
359
+ // 检查用户登录状态
360
+ async function checkAuth() {
361
+ try {
362
+ const response = await fetch('/api/auth/check');
363
+ if (!response.ok) {
364
+ window.location.href = '/login';
365
+ }
366
+ } catch (error) {
367
+ window.location.href = '/login';
368
+ }
369
+ }
370
+
371
+ // 显示错误消息
372
+ function showError(message) {
373
+ const errorDiv = document.createElement('div');
374
+ errorDiv.className = 'bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-4';
375
+ errorDiv.innerHTML = `<p>${message}</p>`;
376
+ document.body.prepend(errorDiv);
377
+ setTimeout(() => errorDiv.remove(), 5000);
378
+ }
379
+
380
+ // 显示加载状态
381
+ function showLoading(selector) {
382
+ const container = document.querySelector(selector);
383
+ if (container) {
384
+ container.innerHTML = `
385
+ <div class="flex justify-center items-center py-10">
386
+ <i class="fas fa-spinner fa-spin text-blue-500 text-2xl"></i>
387
+ <span class="ml-2">加载中...</span>
388
+ </div>
389
+ `;
390
+ }
391
+ }
392
+
393
+ document.addEventListener('DOMContentLoaded', async function() {
394
+ try {
395
+ await checkAuth();
396
+ showLoading('#knowledgeTree');
397
+ await loadKnowledgeTree();
398
+ } catch (error) {
399
+ console.error('Initialization error:', error);
400
+ showError('初始化失败,请刷新页面重试');
401
+ }
402
+ // 知识库数据
403
+ let knowledgeBase = {};
404
+
405
+ // 从API加载知识库树
406
+ async function loadKnowledgeTree() {
407
+ try {
408
+ const response = await fetch(`${API_BASE_URL}${API_ENDPOINTS.knowledge.tree}`);
409
+ if (!response.ok) throw new Error('Failed to load knowledge tree');
410
+ knowledgeBase = await response.json();
411
+ renderKnowledgeTree();
412
+ renderFileList(knowledgeBase);
413
+ } catch (error) {
414
+ console.error('Error loading knowledge tree:', error);
415
+ showError('加载知识库失败,请稍后重试');
416
+ }
417
+ }
418
+ {
419
+ id: 'folder1',
420
+ name: '产品文档',
421
+ type: 'folder',
422
+ children: [
423
+ {
424
+ id: 'file1',
425
+ name: '用户手册.pdf',
426
+ type: 'file',
427
+ size: '2.4 MB',
428
+ lastModified: '2023-10-15'
429
+ },
430
+ {
431
+ id: 'file2',
432
+ name: 'API文档.md',
433
+ type: 'file',
434
+ size: '124 KB',
435
+ lastModified: '2023-10-10'
436
+ }
437
+ ]
438
+ },
439
+ {
440
+ id: 'folder2',
441
+ name: '研究资料',
442
+ type: 'folder',
443
+ children: [
444
+ {
445
+ id: 'file3',
446
+ name: '市场分析.xlsx',
447
+ type: 'file',
448
+ size: '3.7 MB',
449
+ lastModified: '2023-09-25'
450
+ },
451
+ {
452
+ id: 'file4',
453
+ name: '用户调研报告.docx',
454
+ type: 'file',
455
+ size: '1.2 MB',
456
+ lastModified: '2023-09-18'
457
+ }
458
+ ]
459
+ },
460
+ {
461
+ id: 'file5',
462
+ name: '公司简介.docx',
463
+ type: 'file',
464
+ size: '456 KB',
465
+ lastModified: '2023-08-30'
466
+ }
467
+ ]
468
+ };
469
+
470
+ let currentFolder = {...knowledgeBase};
471
+ let breadcrumbStack = [knowledgeBase];
472
+
473
+ // DOM元素
474
+ const sidebar = document.getElementById('sidebar');
475
+ const toggleSidebarBtn = document.getElementById('toggleSidebar');
476
+ const contentArea = document.querySelector('.content-expanded');
477
+ const knowledgeTree = document.getElementById('knowledgeTree');
478
+ const breadcrumb = document.getElementById('breadcrumb');
479
+ const fileList = document.getElementById('fileList');
480
+ const currentLocation = document.getElementById('currentLocation');
481
+ const chatContainer = document.getElementById('chatContainer');
482
+ const chatInput = document.getElementById('chatInput');
483
+ const sendChatBtn = document.getElementById('sendChatBtn');
484
+ const generateDocBtn = document.getElementById('generateDocBtn');
485
+ const contextMenu = document.getElementById('contextMenu');
486
+ const modalOverlay = document.getElementById('modalOverlay');
487
+ const modal = document.getElementById('modal');
488
+ const modalTitle = document.getElementById('modalTitle');
489
+ const modalContent = document.getElementById('modalContent');
490
+ const confirmModal = document.getElementById('confirmModal');
491
+ const cancelModal = document.getElementById('cancelModal');
492
+ const closeModal = document.getElementById('closeModal');
493
+ const docGenModal = document.getElementById('docGenModal');
494
+ const closeDocGenModal = document.getElementById('closeDocGenModal');
495
+ const cancelDocGen = document.getElementById('cancelDocGen');
496
+ const startDocGen = document.getElementById('startDocGen');
497
+ const docLength = document.getElementById('docLength');
498
+ const lengthDisplay = document.getElementById('lengthDisplay');
499
+
500
+ // 初始化UI
501
+ // 处理文件上传
502
+ async function handleFileUpload(files, folderId = currentFolder.id) {
503
+ const formData = new FormData();
504
+ for (let i = 0; i < files.length; i++) {
505
+ formData.append('files', files[i]);
506
+ }
507
+ formData.append('folderId', folderId);
508
+
509
+ try {
510
+ showLoading('#fileList');
511
+ const response = await fetch(`${API_BASE_URL}${API_ENDPOINTS.knowledge.upload}`, {
512
+ method: 'POST',
513
+ body: formData
514
+ });
515
+
516
+ if (!response.ok) throw new Error('上传失败');
517
+ const result = await response.json();
518
+
519
+ // 刷新当前文件夹内容
520
+ await loadFolderContent(currentFolder.id);
521
+ showSuccess('文件上传成功');
522
+ } catch (error) {
523
+ console.error('Upload error:', error);
524
+ showError('文件上传失败');
525
+ }
526
+ }
527
+
528
+ document.addEventListener('DOMContentLoaded', function() {
529
+ // 文件上传事件监听
530
+ document.getElementById('fileInput').addEventListener('change', (e) => {
531
+ if (e.target.files.length > 0) {
532
+ handleFileUpload(e.target.files);
533
+ }
534
+ });
535
+ renderKnowledgeTree();
536
+ renderFileList(currentFolder);
537
+ renderBreadcrumb();
538
+
539
+ // 设置当前位置
540
+ currentLocation.textContent = currentFolder.name;
541
+
542
+ // 添加事件监听器
543
+ toggleSidebarBtn.addEventListener('click', toggleSidebar);
544
+ sendChatBtn.addEventListener('click', sendMessage);
545
+ chatInput.addEventListener('keypress', function(e) {
546
+ if (e.key === 'Enter' && !e.shiftKey) {
547
+ e.preventDefault();
548
+ sendMessage();
549
+ }
550
+ });
551
+ generateDocBtn.addEventListener('click', showDocGenModal);
552
+ document.addEventListener('click', closeContextMenu);
553
+ confirmModal.addEventListener('click', handleModalConfirm);
554
+ cancelModal.addEventListener('click', closeModalWindow);
555
+ closeModal.addEventListener('click', closeModalWindow);
556
+ docLength.addEventListener('input', updateLengthDisplay);
557
+ closeDocGenModal.addEventListener('click', () => docGenModal.classList.add('hidden'));
558
+ cancelDocGen.addEventListener('click', () => docGenModal.classList.add('hidden'));
559
+ startDocGen.addEventListener('click', generateDocument);
560
+
561
+ // 样式按钮事件
562
+ document.querySelectorAll('.style-btn').forEach(btn => {
563
+ btn.addEventListener('click', function() {
564
+ document.querySelectorAll('.style-btn').forEach(b => b.classList.remove('bg-blue-100', 'border-blue-500'));
565
+ this.classList.add('bg-blue-100', 'border-blue-500');
566
+ });
567
+ });
568
+ });
569
+
570
+ // 渲染知识库树
571
+ function renderKnowledgeTree() {
572
+ knowledgeTree.innerHTML = '';
573
+ renderTreeItem(knowledgeBase, knowledgeTree);
574
+
575
+ function renderTreeItem(item, container) {
576
+ const treeItem = document.createElement('div');
577
+ treeItem.className = 'tree-node';
578
+ treeItem.dataset.id = item.id;
579
+
580
+ const itemContent = document.createElement('div');
581
+ itemContent.className = 'flex items-center py-1 px-2 rounded hover:bg-gray-100';
582
+
583
+ const icon = document.createElement('i');
584
+ icon.className = item.type === 'folder' ? 'fas fa-folder text-yellow-400 mr-2' : 'fas fa-file text-gray-400 mr-2';
585
+
586
+ const name = document.createElement('span');
587
+ name.className = 'text-sm nav-text';
588
+ name.textContent = item.name;
589
+
590
+ itemContent.appendChild(icon);
591
+ itemContent.appendChild(name);
592
+ treeItem.appendChild(itemContent);
593
+
594
+ if (item.type === 'folder' && item.children && item.children.length > 0) {
595
+ const toggleIcon = document.createElement('i');
596
+ toggleIcon.className = 'fas fa-chevron-down text-xs ml-auto nav-text';
597
+
598
+ const childrenContainer = document.createElement('div');
599
+ childrenContainer.className = 'ml-4 hidden';
600
+
601
+ item.children.forEach(child => {
602
+ renderTreeItem(child, childrenContainer);
603
+ });
604
+
605
+ itemContent.appendChild(toggleIcon);
606
+ treeItem.appendChild(childrenContainer);
607
+
608
+ itemContent.addEventListener('click', function(e) {
609
+ e.stopPropagation();
610
+ if (e.target === toggleIcon || e.target.parentElement === toggleIcon) {
611
+ childrenContainer.classList.toggle('hidden');
612
+ toggleIcon.classList.toggle('fa-chevron-down');
613
+ toggleIcon.classList.toggle('fa-chevron-right');
614
+ } else {
615
+ navigateToFolder(item);
616
+ }
617
+ });
618
+ } else {
619
+ itemContent.addEventListener('click', function(e) {
620
+ e.stopPropagation();
621
+ if (item.type === 'file') {
622
+ previewFile(item);
623
+ }
624
+ });
625
+ }
626
+
627
+ // 为树项目添加上下文菜单
628
+ treeItem.addEventListener('contextmenu', function(e) {
629
+ e.preventDefault();
630
+ e.stopPropagation();
631
+ showContextMenu(e, item);
632
+ });
633
+
634
+ container.appendChild(treeItem);
635
+ }
636
+ }
637
+
638
+ // 渲染文件列表
639
+ function renderFileList(folder) {
640
+ fileList.innerHTML = '';
641
+
642
+ if (!folder.children || folder.children.length === 0) {
643
+ const emptyMsg = document.createElement('div');
644
+ emptyMsg.className = 'text-center py-10 text-gray-400 col-span-3';
645
+ emptyMsg.innerHTML = `
646
+ <i class="fas fa-folder-open text-4xl mb-2"></i>
647
+ <p>当前文件夹为空</p>
648
+ `;
649
+ fileList.appendChild(emptyMsg);
650
+ return;
651
+ }
652
+
653
+ folder.children.forEach(item => {
654
+ const fileCard = document.createElement('div');
655
+ fileCard.className = item.type === 'folder' ? 'folder-item p-3 border rounded-lg cursor-pointer flex flex-col items-center' : 'file-item p-3 border rounded-lg cursor-pointer flex flex-col items-center';
656
+
657
+ const icon = document.createElement('i');
658
+ icon.className = item.type === 'folder' ? 'fas fa-folder text-yellow-400 mb-2 text-4xl' : getFileIcon(item.name);
659
+
660
+ const name = document.createElement('div');
661
+ name.className = 'text-sm font-medium text-center truncate w-full';
662
+ name.textContent = item.name;
663
+
664
+ const meta = document.createElement('div');
665
+ meta.className = 'text-xs text-gray-500 mt-1';
666
+ meta.textContent = item.size || '';
667
+
668
+ fileCard.appendChild(icon);
669
+ fileCard.appendChild(name);
670
+ fileCard.appendChild(meta);
671
+
672
+ fileCard.addEventListener('click', function() {
673
+ if (item.type === 'folder') {
674
+ navigateToFolder(item);
675
+ } else {
676
+ previewFile(item);
677
+ }
678
+ });
679
+
680
+ // 添加上下文菜单
681
+ fileCard.addEventListener('contextmenu', function(e) {
682
+ e.preventDefault();
683
+ e.stopPropagation();
684
+ showContextMenu(e, item);
685
+ });
686
+
687
+ fileList.appendChild(fileCard);
688
+ });
689
+ }
690
+
691
+ // 获取文件图标
692
+ function getFileIcon(filename) {
693
+ const ext = filename.split('.').pop().toLowerCase();
694
+ switch(ext) {
695
+ case 'pdf':
696
+ return 'fas fa-file-pdf text-red-400 mb-2 text-4xl';
697
+ case 'doc':
698
+ case 'docx':
699
+ return 'fas fa-file-word text-blue-400 mb-2 text-4xl';
700
+ case 'xls':
701
+ case 'xlsx':
702
+ return 'fas fa-file-excel text-green-400 mb-2 text-4xl';
703
+ case 'ppt':
704
+ case 'pptx':
705
+ return 'fas fa-file-powerpoint text-orange-400 mb-2 text-4xl';
706
+ case 'txt':
707
+ return 'fas fa-file-alt text-gray-400 mb-2 text-4xl';
708
+ case 'md':
709
+ return 'fas fa-markdown text-gray-600 mb-2 text-4xl';
710
+ default:
711
+ return 'fas fa-file text-gray-400 mb-2 text-4xl';
712
+ }
713
+ }
714
+
715
+ // 渲染面包屑导航
716
+ function renderBreadcrumb() {
717
+ breadcrumb.innerHTML = '';
718
+
719
+ breadcrumbStack.forEach((folder, index) => {
720
+ const crumb = document.createElement('span');
721
+ crumb.className = 'hover:text-blue-500 cursor-pointer';
722
+ crumb.textContent = folder.name;
723
+
724
+ crumb.addEventListener('click', function() {
725
+ const newStack = breadcrumbStack.slice(0, index + 1);
726
+ const targetFolder = newStack[newStack.length - 1];
727
+
728
+ // 找到完整的文件夹对象(包括children)
729
+ let fullFolder = findFullFolder(knowledgeBase, targetFolder.id);
730
+
731
+ breadcrumbStack = newStack;
732
+ currentFolder = fullFolder;
733
+ renderFileList(currentFolder);
734
+ renderBreadcrumb();
735
+ currentLocation.textContent = currentFolder.name;
736
+ });
737
+
738
+ breadcrumb.appendChild(crumb);
739
+
740
+ if (index < breadcrumbStack.length - 1) {
741
+ const separator = document.createElement('span');
742
+ separator.className = 'mx-1';
743
+ separator.textContent = '>';
744
+ breadcrumb.appendChild(separator);
745
+ }
746
+ });
747
+ }
748
+
749
+ // 在知识库中找到完整的文件夹对象
750
+ function findFullFolder(startFolder, id) {
751
+ if (startFolder.id === id) {
752
+ return {...startFolder};
753
+ }
754
+
755
+ if (startFolder.children) {
756
+ for (let child of startFolder.children) {
757
+ if (child.id === id) {
758
+ return {...child};
759
+ }
760
+
761
+ if (child.type === 'folder') {
762
+ const found = findFullFolder(child, id);
763
+ if (found) return found;
764
+ }
765
+ }
766
+ }
767
+
768
+ return null;
769
+ }
770
+
771
+ // 加载文件夹内容
772
+ async function loadFolderContent(folderId) {
773
+ try {
774
+ const response = await fetch(`${API_BASE_URL}${API_ENDPOINTS.knowledge.folder}/${folderId}`);
775
+ if (!response.ok) throw new Error('Failed to load folder');
776
+ const folderData = await response.json();
777
+ currentFolder = folderData;
778
+ renderFileList(currentFolder);
779
+ renderBreadcrumb();
780
+ } catch (error) {
781
+ console.error('Error loading folder:', error);
782
+ showError('加载文件夹内容失败');
783
+ }
784
+ }
785
+
786
+ // 导航到文件夹
787
+ async function navigateToFolder(folder) {
788
+ const fullFolder = findFullFolder(knowledgeBase, folder.id);
789
+ if (fullFolder) {
790
+ currentFolder = fullFolder;
791
+ breadcrumbStack.push(currentFolder);
792
+ renderFileList(currentFolder);
793
+ renderBreadcrumb();
794
+ currentLocation.textContent = currentFolder.name;
795
+ }
796
+ }
797
+
798
+ // 预览文件
799
+ function previewFile(file) {
800
+ const previewContent = document.getElementById('previewContent');
801
+ previewContent.innerHTML = '';
802
+
803
+ // 模拟不同文件类型的预览
804
+ if (file.name.endsWith('.pdf')) {
805
+ previewContent.innerHTML = `
806
+ <div class="text-center py-10">
807
+ <i class="fas fa-file-pdf text-6xl text-red-400 mb-4"></i>
808
+ <h4 class="font-medium mb-2">${file.name}</h4>
809
+ <p class="text-sm text-gray-500">这是PDF文件的预览占位符</p>
810
+ </div>
811
+ `;
812
+ } else if (file.name.endsWith('.docx') || file.name.endsWith('.doc')) {
813
+ previewContent.innerHTML = `
814
+ <div class="space-y-4">
815
+ <h3 class="text-xl font-bold">${file.name.replace('.docx', '').replace('.doc', '')}</h3>
816
+ <p class="text-sm">这是Word文档的预览占位符。</p>
817
+ <p class="text-sm">在实际应用中,这里将显示文档的实际内容。</p>
818
+ </div>
819
+ `;
820
+ } else if (file.name.endsWith('.xlsx') || file.name.endsWith('.xls')) {
821
+ previewContent.innerHTML = `
822
+ <table class="min-w-full divide-y divide-gray-200">
823
+ <thead class="bg-gray-50">
824
+ <tr>
825
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">项目</th>
826
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">2023</th>
827
+ <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">2022</th>
828
+ </tr>
829
+ </thead>
830
+ <tbody class="bg-white divide-y divide-gray-200">
831
+ <tr>
832
+ <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">收入</td>
833
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$1,200,000</td>
834
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$980,000</td>
835
+ </tr>
836
+ <tr>
837
+ <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">支出</td>
838
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$750,000</td>
839
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">$620,000</td>
840
+ </tr>
841
+ </tbody>
842
+ </table>
843
+ <p class="text-xs text-gray-500 mt-2">这是Excel表格的预览占位符</p>
844
+ `;
845
+ } else if (file.name.endsWith('.md')) {
846
+ previewContent.innerHTML = `
847
+ <div class="prose max-w-none">
848
+ <h1>${file.name.replace('.md', '')}</h1>
849
+ <p>这是Markdown文件的预览。</p>
850
+ <ul>
851
+ <li>可以渲染Markdown语法</li>
852
+ <li>支持标题、列表、代码等</li>
853
+ </ul>
854
+ <pre><code>const example = "这里是代码块";</code></pre>
855
+ </div>
856
+ `;
857
+ } else {
858
+ previewContent.innerHTML = `
859
+ <div>
860
+ <table class="min-w-full divide-y divide-gray-200">
861
+ <tbody>
862
+ <tr>
863
+ <td class="px-4 py-2 whitespace-nowrap text-sm font-medium text-gray-500">文件名</td>
864
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-600">${file.name}</td>
865
+ </tr>
866
+ <tr>
867
+ <td class="px-4 py-2 whitespace-nowrap text-sm font-medium text-gray-500">大小</td>
868
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-600">${file.size}</td>
869
+ </tr>
870
+ <tr>
871
+ <td class="px-4 py-2 whitespace-nowrap text-sm font-medium text-gray-500">修改日期</td>
872
+ <td class="px-4 py-2 whitespace-nowrap text-sm text-gray-600">${file.lastModified}</td>
873
+ </tr>
874
+ </tbody>
875
+ </table>
876
+ </div>
877
+ `;
878
+ }
879
+
880
+ document.getElementById('filePreview').classList.remove('hidden');
881
+ }
882
+
883
+ // 切换侧边栏
884
+ function toggleSidebar() {
885
+ sidebar.classList.toggle('sidebar-collapsed');
886
+ sidebar.classList.toggle('sidebar-expanded');
887
+ contentArea.classList.toggle('content-collapsed');
888
+ contentArea.classList.toggle('content-expanded');
889
+ }
890
+
891
+ // 获取聊天上下文
892
+ function getChatContext() {
893
+ return {
894
+ currentFolder: currentFolder.id,
895
+ recentFiles: breadcrumbStack.map(f => f.id),
896
+ chatHistory: Array.from(chatContainer.children)
897
+ .filter(el => el.classList.contains('chat-bubble'))
898
+ .map(el => ({
899
+ role: el.classList.contains('user-bubble') ? 'user' : 'assistant',
900
+ content: el.querySelector('div:last-child').textContent
901
+ }))
902
+ };
903
+ }
904
+
905
+ // 发送消息
906
+ async function sendMessage() {
907
+ const message = chatInput.value.trim();
908
+ if (!message) return;
909
+
910
+ // 添加用户消息到聊天界面
911
+ addMessageToChat('user', message);
912
+
913
+ // 清空输入框
914
+ chatInput.value = '';
915
+
916
+ // 调用AI服务API
917
+ try {
918
+ const response = await fetch('/api/ai/chat', {
919
+ method: 'POST',
920
+ headers: { 'Content-Type': 'application/json' },
921
+ body: JSON.stringify({
922
+ message: message,
923
+ context: getChatContext() // 当前聊天上下文
924
+ })
925
+ });
926
+ const data = await response.json();
927
+ addMessageToChat('ai', data.response);
928
+ } catch (error) {
929
+ addMessageToChat('ai', '抱歉,AI服务暂时不可用');
930
+ }
931
+ }
932
+
933
+ // 添加消息到聊天界面
934
+ function addMessageToChat(sender, message) {
935
+ const messageElement = document.createElement('div');
936
+ messageElement.className = `chat-bubble ${sender === 'user' ? 'user-bubble' : 'ai-bubble'}`;
937
+
938
+ if (sender === 'ai') {
939
+ messageElement.innerHTML = `
940
+ <div class="font-medium mb-1">AI助手</div>
941
+ <div>${message}</div>
942
+ `;
943
+ } else {
944
+ messageElement.innerHTML = `
945
+ <div class="font-medium mb-1">您</div>
946
+ <div>${message}</div>
947
+ `;
948
+ }
949
+
950
+ chatContainer.appendChild(messageElement);
951
+ chatContainer.scrollTop = chatContainer.scrollHeight;
952
+ }
953
+
954
+ // 模拟AI回复
955
+ function generateAiResponse(message) {
956
+ const lowerMessage = message.toLowerCase();
957
+
958
+ if (lowerMessage.includes('你好') || lowerMessage.includes('hi')) {
959
+ return '您好!我是您的AI知识助手。我可以帮助您检索知识库中的信息,或者根据现有内容生成新的文档。';
960
+ } else if (lowerMessage.includes('帮助') || lowerMessage.includes('help') || lowerMessage.includes('功能')) {
961
+ return '我可以提供以下帮助:<br>1. 搜索知识库中的信息<br>2. 回答与知识库内容相关的问题<br>3. 生成总结或摘要<br>4. 根据要求创建新的文档<br>5. 分析文档内容提供见解';
962
+ } else if (lowerMessage.includes('产品') && lowerMessage.includes('文档')) {
963
+ return '根据知识库内容,我已找到以下产品文档:<br>1. 用户手册.pdf - 包含产品使用说明<br>2. API文档.md - REST API接口说明<br>是否需要我帮忙提取其中的特定信息?';
964
+ } else if (lowerMessage.includes('市场分析')) {
965
+ return '知识库中有一份"市场分析.xlsx"文档,该文档包含以下数据:<br>- 2023年市场增长率:12.5%<br>- 主要竞争对手分析<br>- 市场细分数据<br>需要我为您生成一份摘要吗?';
966
+ } else if (lowerMessage.includes('总结') || lowerMessage.includes('摘要')) {
967
+ return '我已分析了知识库中的相关内容,以下是摘要:<br>1. 产品文档提供了详细的用户指南和API说明<br>2. 研究资料中包含市场分析和用户调研<br>3. 知识库整体结构良好,但建议增加开发规范文档';
968
+ } else {
969
+ return '我已检索了知识库中的相关内容,但未找到完全匹配的信息。您可以尝试更具体地描述您的需求,或者让我帮助您生成基于现有内容的新文档。';
970
+ }
971
+ }
972
+
973
+ // 显示文档生成模态框
974
+ function showDocGenModal() {
975
+ docGenModal.classList.remove('hidden');
976
+ }
977
+
978
+ // 更新文档长度显示
979
+ function updateLengthDisplay() {
980
+ lengthDisplay.textContent = docLength.value + '字';
981
+ }
982
+
983
+ // 生成文档
984
+ async function generateDocument() {
985
+ const docType = document.getElementById('docType').value;
986
+ const docStyle = document.querySelector('.style-btn.bg-blue-100')?.dataset.style || 'professional';
987
+ const docLength = document.getElementById('docLength').value;
988
+ const docRequirements = document.getElementById('docRequirements').value;
989
+
990
+ try {
991
+ const response = await fetch(`${API_BASE_URL}${API_ENDPOINTS.ai.generate}`, {
992
+ method: 'POST',
993
+ headers: { 'Content-Type': 'application/json' },
994
+ body: JSON.stringify({
995
+ type: docType,
996
+ style: docStyle,
997
+ length: docLength,
998
+ requirements: docRequirements,
999
+ context: getChatContext()
1000
+ })
1001
+ });
1002
+
1003
+ if (!response.ok) throw new Error('生成失败');
1004
+ const result = await response.json();
1005
+
1006
+ // 显示生成的文档
1007
+ addMessageToChat('ai', `文档生成成功:<br><br><strong>${result.title}</strong><br><br>${result.content}`);
1008
+
1009
+ } catch (error) {
1010
+ console.error('Document generation error:', error);
1011
+ addMessageToChat('ai', '文档生成失败,请稍后重试');
1012
+ }
1013
+ const docType = document.getElementById('docType').value;
1014
+ const docRequirements = document.getElementById('docRequirements').value;
1015
+
1016
+ docGenModal.classList.add('hidden');
1017
+
1018
+ // 显示生成中的消息
1019
+ const generatingMsg = document.createElement('div');
1020
+ generatingMsg.className = 'chat-bubble ai-bubble flex items-center';
1021
+ generatingMsg.innerHTML = `
1022
+ <div class="mr-2 loading-spinner">
1023
+ <i class="fas fa-spinner"></i>
1024
+ </div>
1025
+ <div>正在为您生成文档...</div>
1026
+ `;
1027
+ chatContainer.appendChild(generatingMsg);
1028
+ chatContainer.scrollTop = chatContainer.scrollHeight;
1029
+
1030
+ // 模拟生成过程
1031
+ setTimeout(() => {
1032
+ chatContainer.removeChild(generatingMsg);
1033
+
1034
+ // 添加生成结果
1035
+ const generatedDocument = generateExampleDocument(docType, docRequirements);
1036
+ addMessageToChat('ai', `我已根据您的要求生成了一份文档:<br><br><strong>${generatedDocument.title}</strong><br><br>${generatedDocument.content}`);
1037
+
1038
+ // 询问用户是否要保存
1039
+ const savePrompt = document.createElement('div');
1040
+ savePrompt.className = 'chat-bubble ai-bubble';
1041
+ savePrompt.innerHTML = `
1042
+ <div>您想将生成的文档保存到知识库中吗?</div>
1043
+ <div class="flex space-x-2 mt-2">
1044
+ <button id="saveDocYes" class="bg-green-500 hover:bg-green-600 text-white px-3 py-1 rounded text-sm">保存</button>
1045
+ <button id="saveDocNo" class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-3 py-1 rounded text-sm">取消</button>
1046
+ </div>
1047
+ `;
1048
+ chatContainer.appendChild(savePrompt);
1049
+
1050
+ document.getElementById('saveDocYes').addEventListener('click', () => {
1051
+ savePrompt.innerHTML = '<div>文档已保存到"产品文档"文件夹。</div>';
1052
+ // 在实际应用中,这里会调用API保存文档
1053
+ });
1054
+
1055
+ document.getElementById('saveDocNo').addEventListener('click', () => {
1056
+ savePrompt.innerHTML = '<div>好的,没有保存文档。</div>';
1057
+ });
1058
+
1059
+ chatContainer.scrollTop = chatContainer.scrollHeight;
1060
+ }, 3000);
1061
+ }
1062
+
1063
+ // 生成示例文档
1064
+ function generateExampleDocument(type, requirements) {
1065
+ const titles = {
1066
+ report: '市场分析报告',
1067
+ summary: '项目摘要',
1068
+ manual: '用户手册',
1069
+ article: '技术文章',
1070
+ presentation: '演示文稿'
1071
+ };
1072
+
1073
+ const contents = {
1074
+ report: `市场分析报告(${new Date().getFullYear()}年)\n\n本报告分析了当前市场趋势和竞争对手情况。根据知识库中的研究资料,我们发现:\n\n1. 市场增长率预计为12.5%\n2. 主要竞争对手的市场份额为35%\n3. 客户满意度提升了8个百分点\n\n${requirements ? "\n额外要求:" + requirements : ""}`,
1075
+
1076
+ summary: `文档摘要\n\n本摘要基于知识库中的多个文档内容整合而成:\n\n1. 用户手册.pdf - 包含核心功能说明\n2. API文档.md - 详细接口规范\n3. 市场分析.xlsx - 最新市场数据\n\n关键结论:\n- 产品功能完整但文档需要更新\n- API接口设计良好\n- 市场前景乐观`,
1077
+
1078
+ manual: `用户手册\n\n产品名称: ${requirements || "默认产品"}\n\n版本: 1.0\n\n目录\n1. 简介\n2. 功能说明\n3. 常见问题\n\n第1章 简介\n本产品是一款基于先进技术的解决方案,旨在解决用户的核心需求。`,
1079
+
1080
+ article: `技术文章:${requirements || "知识管理的最佳实践"}\n\n随着信息量的爆炸式增长,高效的知识管理变得越来越重要。本文探讨了构建有效知识库系统的几种方法:\n\n1. 结构化分类\n2. 智能检索\n3. 人工智能辅助\n\n基于本知识库系统的经验,我们发现...`,
1081
+
1082
+ presentation: `演示文稿大纲:${requirements || "新产品发布会"}\n\n1. 封面\n2. 公司简介\n3. 产品概述\n4. 核心优势\n5. 市场前景\n6. Q&A\n\n每页主要内容:\n- 幻灯片1: 标题+产品图片\n- 幻灯片2: 公司里程碑\n- 幻灯片3: 产品功能概览`
1083
+ };
1084
+
1085
+ return {
1086
+ title: titles[type],
1087
+ content: contents[type]
1088
+ };
1089
+ }
1090
+
1091
+ // 显示上下文菜单
1092
+ function showContextMenu(e, item) {
1093
+ e.preventDefault();
1094
+
1095
+ contextMenu.style.display = 'block';
1096
+ contextMenu.style.left = e.pageX + 'px';
1097
+ contextMenu.style.top = e.pageY + 'px';
1098
+
1099
+ // 设置当前上下文项
1100
+ contextMenu.dataset.itemId = item.id;
1101
+ contextMenu.dataset.itemType = item.type;
1102
+
1103
+ // 阻止事件冒泡
1104
+ contextMenu.addEventListener('click', function(e) {
1105
+ e.stopPropagation();
1106
+ });
1107
+ }
1108
+
1109
+ // 关闭上下文菜单
1110
+ function closeContextMenu(e) {
1111
+ if (contextMenu.style.display === 'block' && e.target !== contextMenu) {
1112
+ contextMenu.style.display = 'none';
1113
+ }
1114
+ }
1115
+
1116
+ // 打开模态框
1117
+ function openModal(title, content, confirmCallback) {
1118
+ modalTitle.textContent = title;
1119
+ modalContent.innerHTML = content;
1120
+ modalOverlay.classList.remove('hidden');
1121
+
1122
+ // 临时存储确认回调
1123
+ modal.dataset.confirmCallback = confirmCallback ? confirmCallback.toString() : '';
1124
+ }
1125
+
1126
+ // 关闭模态框
1127
+ function closeModalWindow() {
1128
+ modalOverlay.classList.add('hidden');
1129
+ }
1130
+
1131
+ // 处理模态框确认
1132
+ function handleModalConfirm() {
1133
+ // 在实际应用中,这里会根据不同的模态框执行不同的操作
1134
+ closeModalWindow();
1135
+ }
1136
+
1137
+ // 示例:添加一个新的文件夹
1138
+ function addNewFolder() {
1139
+ openModal('新建文件夹', `
1140
+ <div class="space-y-4">
1141
+ <div>
1142
+ <label class="block text-sm font-medium text-gray-700 mb-1">文件夹名称</label>
1143
+ <input type="text" id="newFolderName" class="w-full border rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
1144
+ </div>
1145
+ <div>
1146
+ <label class="block text-sm font-medium text-gray-700 mb-1">位置</label>
1147
+ <select class="w-full border rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
1148
+ <option>${currentFolder.name}</option>
1149
+ </select>
1150
+ </div>
1151
+ </div>
1152
+ `, function() {
1153
+ const folderName = document.getElementById('newFolderName').value;
1154
+ if (folderName) {
1155
+ // 在实际应用中,这里会调用API创建文件夹
1156
+ alert(`文件夹"${folderName}"已创建`);
1157
+ }
1158
+ });
1159
+ }
1160
+ </script>
1161
+ <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=zhenhai18/kmlu" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1162
+ </html>