文件夹系统(中文译文)
原始 DeepWiki 页面:https://deepwiki.com/open-webui/open-webui/8.2-folder-system
翻译时间:2026-06-09T16:09:35.516Z
翻译模型:deepseek-chat
原文字符数:12854
项目:Open WebUI (open-webui)
---
文件夹系统
相关源文件
以下文件用于生成此 Wiki 页面:
backend/open_webui/models/folders.pybackend/open_webui/routers/folders.pysrc/lib/apis/folders/index.tssrc/lib/components/chat/Placeholder/FolderTitle.sveltesrc/lib/components/chat/Tags.sveltesrc/lib/components/common/ConfirmDialog.sveltesrc/lib/components/common/DragGhost.sveltesrc/lib/components/common/Dropdown.sveltesrc/lib/components/common/EmojiPicker.sveltesrc/lib/components/common/Folder.sveltesrc/lib/components/layout/Navbar/Menu.sveltesrc/lib/components/layout/Sidebar.sveltesrc/lib/components/layout/Sidebar/ChatItem.sveltesrc/lib/components/layout/Sidebar/ChatMenu.sveltesrc/lib/components/layout/Sidebar/Folders.sveltesrc/lib/components/layout/Sidebar/Folders/FolderMenu.sveltesrc/lib/components/layout/Sidebar/Folders/FolderModal.sveltesrc/lib/components/layout/Sidebar/RecursiveFolder.sveltesrc/lib/components/workspace/Models/Knowledge/KnowledgeSelector.svelte
概述
文件夹系统为 Open WebUI 侧边栏中的聊天提供了层级化组织能力。用户可以创建嵌套的文件夹结构来分类和管理对话,类似于文件系统。该系统支持 CRUD 操作、拖拽重组以及配置继承——文件夹可以为包含的聊天定义默认系统提示和知识集。
关于侧边栏容器的信息,请参阅侧边栏架构。关于聊天项操作的详细信息,请参阅聊天项管理。
数据模型
数据库模式
文件夹系统由 folder 表支撑,支持父子关系以及按用户归属。
文件夹表结构:
| 列名 | 类型 | 描述 |
|---|---|---|
id | Text | 主键,文件夹标识符 backend/open_webui/models/folders.py:26-26 |
parent_id | Text (nullable) | 父文件夹引用,根文件夹为 null backend/open_webui/models/folders.py:27-27 |
user_id | Text | 文件夹所有者 backend/open_webui/models/folders.py:28-28 |
name | Text | 文件夹显示名称 backend/open_webui/models/folders.py:29-29 |
items | JSON (nullable) | 包含项的元数据 backend/open_webui/models/folders.py:30-30 |
meta | JSON (nullable) | UI 元数据(例如图标 emoji、background_image_url) backend/open_webui/models/folders.py:31-31 |
data | JSON (nullable) | 文件夹配置(system_prompt、files/knowledge) backend/open_webui/models/folders.py:32-32 |
is_expanded | Boolean | 展开/折叠的 UI 状态 backend/open_webui/models/folders.py:33-33 |
created_at | BigInteger | 创建时间戳 backend/open_webui/models/folders.py:34-34 |
updated_at | BigInteger | 最后修改时间戳 backend/open_webui/models/folders.py:35-35 |
chat 表也包含一个 folder_id 列,建立了聊天与文件夹之间的多对一关系 backend/open_webui/models/chats.py:24-24。
来源: backend/open_webui/models/folders.py:26-35, backend/open_webui/models/chats.py:24-24
文件夹-聊天关系图
erDiagram
"Folders(SQLTable)" ||--o{ "Folders(SQLTable)" : "parent_id"
"Folders(SQLTable)" ||--o{ "Chats(SQLTable)" : "contains"
"Users(SQLTable)" ||--o{ "Folders(SQLTable)" : "owns"
"Folders(SQLTable)" {
text id PK
text parent_id FK
text user_id FK
text name
json items
json meta
json data
boolean is_expanded
biginteger created_at
biginteger updated_at
}
"Chats(SQLTable)" {
text id PK
text folder_id FK
text title
boolean pinned
json chat
}
来源: backend/open_webui/models/folders.py:26-35, backend/open_webui/models/chats.py:24-24
前端架构
组件层次结构
文件夹 UI 由多个嵌套组件组成,由侧边栏协调:
graph TD
Sidebar["Sidebar.svelte<br/>主容器"]
FolderWrapper["Folder.svelte<br/>通用可折叠包装器"]
Folders["Folders.svelte<br/>顶层文件夹列表"]
RecursiveFolder["RecursiveFolder.svelte<br/>自递归文件夹单元"]
ChatItem["ChatItem.svelte<br/>聊天条目"]
FolderMenu["FolderMenu.svelte<br/>上下文菜单"]
FolderModal["FolderModal.svelte<br/>创建/编辑对话框"]
Sidebar --> FolderWrapper
FolderWrapper --> Folders
Folders --> RecursiveFolder
RecursiveFolder --> RecursiveFolder
RecursiveFolder --> ChatItem
RecursiveFolder --> FolderMenu
Sidebar --> FolderModal
来源: src/lib/components/layout/Sidebar.svelte:61-70, src/lib/components/layout/Sidebar/RecursiveFolder.svelte:40-43
状态管理与初始化
文件夹系统在多个层级维护状态。Sidebar.svelte 中的初始化逻辑执行两遍算法,在内存中构建树结构。
文件夹树构建算法:
- 第一遍: 从 API 列表中将所有文件夹条目初始化到
folders映射中src/lib/components/layout/Sidebar.svelte:188-196。 - 第二遍: 再次遍历列表,将子 ID 追加到各自父级的
childrenIds数组中src/lib/components/layout/Sidebar.svelte:199-210。 - 排序: 子项按
updated_at时间戳排序src/lib/components/layout/Sidebar.svelte:212-214。
graph LR
API["getFolders() API"]
FolderList["原始文件夹数组"]
Pass1["第一遍:映射 ID<br/>folders[id] = folder"]
Pass2["第二遍:链接父级<br/>parent.childrenIds.push(id)"]
Store["_folders store 已更新"]
API --> FolderList
FolderList --> Pass1
Pass1 --> Pass2
Pass2 --> Store
来源: src/lib/components/layout/Sidebar.svelte:175-217
API 层
文件夹操作
前端通过 src/lib/apis/folders/index.ts 中的专用 API 客户端与后端通信。
| 函数 | 方法 | 端点 | 用途 |
|---|---|---|---|
createNewFolder | POST | /folders/ | 创建新文件夹 src/lib/apis/folders/index.ts:9-35 |
getFolders | GET | /folders/ | 获取所有用户文件夹 src/lib/apis/folders/index.ts:37-58 |
getFolderById | GET | /folders/{id} | 获取单个文件夹 src/lib/apis/folders/index.ts:60-82 |
updateFolderById | POST | /folders/{id}/update | 更新名称/元数据/数据 src/lib/apis/folders/index.ts:84-111 |
updateFolderParentIdById | POST | /folders/{id}/update/parent | 在层级中移动文件夹 src/lib/apis/folders/index.ts:138-164 |
deleteFolderById | DELETE | /folders/{id} | 删除文件夹 src/lib/apis/folders/index.ts:249-275 |
来源: src/lib/apis/folders/index.ts:1-275, backend/open_webui/routers/folders.py:39-41
后端路由逻辑
后端路由器 folders.py 处理授权和数据完整性:
- 访问控制: 所有路由都需要经过验证的用户
backend/open_webui/routers/folders.py:50。管理员或具有features.folders权限的用户可以访问文件夹backend/open_webui/routers/folders.py:59-68。 - 数据完整性: 获取文件夹时,后端验证所有
parent_id引用是否有效。如果父级缺失,子项将被移动到根级别backend/open_webui/routers/folders.py:75-76。 - 文件访问验证: 存储在文件夹
data中的文件和集合会根据用户的读取权限进行过滤backend/open_webui/routers/folders.py:78-94。
来源: backend/open_webui/routers/folders.py:47-98
递归文件夹渲染
RecursiveFolder 组件
RecursiveFolder.svelte 组件实现自递归以渲染嵌套层级。
- 懒加载: 文件夹仅在展开时(
open = true)通过getChatListByFolderId获取其聊天列表src/lib/components/layout/Sidebar/RecursiveFolder.svelte:369-384。 - 注册表模式: 每个文件夹将其
setFolderItems方法注册到全局folderRegistry中。这使得父组件能够命令式地触发特定文件夹内容的刷新src/lib/components/layout/Sidebar/RecursiveFolder.svelte:257-261。
来源: src/lib/components/layout/Sidebar/RecursiveFolder.svelte:1-384
拖拽系统
Open WebUI 实现了复杂的拖拽系统,用于组织聊天和文件夹。
拖拽源实现
被拖拽的项(聊天或文件夹)将其身份编码为 JSON 存储在 dataTransfer 对象中:
// ChatItem.svelte
event.dataTransfer.setData('text/plain', JSON.stringify({ type: 'chat', id: id }));
// RecursiveFolder.svelte
event.dataTransfer.setData('text/plain', JSON.stringify({ type: 'folder', id: folderId }));
来源: src/lib/components/layout/Sidebar/ChatItem.svelte:251-257, src/lib/components/layout/Sidebar/RecursiveFolder.svelte:224-235
放置目标逻辑
RecursiveFolder 组件按以下逻辑处理放置操作:
- 文件夹到文件夹: 调用
updateFolderParentIdById来嵌套被拖拽的文件夹src/lib/components/layout/Sidebar/RecursiveFolder.svelte:144-153。 - 聊天到文件夹: 调用
updateChatFolderIdById将聊天移动到目标文件夹中src/lib/components/layout/Sidebar/RecursiveFolder.svelte:154-194。 - JSON 文件放置: 如果放置了 JSON 文件,组件会解析它并分发一个
import事件,以批量导入聊天到该文件夹src/lib/components/layout/Sidebar/RecursiveFolder.svelte:103-122。
来源: src/lib/components/layout/Sidebar/RecursiveFolder.svelte:87-206
文件夹配置与继承
文件夹充当其包含聊天的配置容器。
文件夹模态框设置
FolderModal.svelte 组件允许用户配置:
- 元数据: 名称和自定义背景图片
src/lib/components/layout/Sidebar/Folders/FolderModal.svelte:139-211。 - 系统提示: 应用于文件夹内聊天的默认提示
src/lib/components/layout/Sidebar/Folders/FolderModal.svelte:215-229。 - 知识: 与文件夹关联的文件和集合,用于 RAG
src/lib/components/layout/Sidebar/Folders/FolderModal.svelte:231-241。
来源: src/lib/components/layout/Sidebar/Folders/FolderModal.svelte:1-255
验证与限制
系统在文件夹配置期间强制执行限制:
- 文件上传状态: 如果文件仍处于"上传中"状态,则阻止保存
src/lib/components/layout/Sidebar/Folders/FolderModal.svelte:40-44。 - 最大文件数: 强制执行系统配置中的
folder_max_file_countsrc/lib/components/layout/Sidebar/Folders/FolderModal.svelte:46-54。
来源: src/lib/components/layout/Sidebar/Folders/FolderModal.svelte:37-64
操作总结
| 操作 | 实现细节 |
|---|---|
| 重命名 | 通过双击或上下文菜单触发;调用 updateFolderById src/lib/components/layout/Sidebar/RecursiveFolder.svelte:306-349。 |
| 删除 | 支持仅删除文件夹(聊天变为孤立)或删除文件夹及其内容 src/lib/components/layout/Sidebar/RecursiveFolder.svelte:292-304。 |
| 导出 | 获取文件夹中的所有聊天,并使用 fileSaver 保存为 JSON 文件 src/lib/components/layout/Sidebar/RecursiveFolder.svelte:402-416。 |
| 展开状态 | 通过防抖持久化到后端,以防止过多的 API 调用 src/lib/components/layout/Sidebar/RecursiveFolder.svelte:351-367。 |
来源: src/lib/components/layout/Sidebar/RecursiveFolder.svelte:292-416