Unstract FileManagement API:面向组织的文件列表、下载与上传 REST 接口全解析
【免费下载链接】unstractLLM-Driven Extraction of Unstructured Data — Built for API Deployments & ETL Pipeline Workflows项目地址: https://gitcode.com/GitHub_Trending/un/unstract
本文以仓库中的 FileManagement API 文档 为主体,系统讲解 Unstract 后端中面向组织(Organization)的文件管理接口:列出文件(List File)、下载文件(Download)、上传文件(Upload)。读完本文,你不仅能掌握这三个 REST 接口的完整调用方式、参数与响应结构,还能结合 backend/file_management/views.py 与 backend/file_management/file_management_helper.py 等源码,理解接口背后如何通过 Connector 与UnstractFileSystem抽象对接不同的文件存储后端,以及文件上传的格式与大小限制是如何在序列化器层被强制校验的。
接口总览
backend/file_management/api_doc.md 中定义了三个核心接口,均挂载在组织作用域路径/unstract/<org_id>/之下:
| 功能 | 方法 | 路径 | 说明 |
|---|---|---|---|
| List File(列出文件) | GET | /unstract/<org_id>/file | 按connector_id和path列出指定目录下的文件 |
| Download(下载文件) | GET | /unstract/<org_id>/file/download | 以流式响应返回指定文件内容 |
| Upload(上传文件) | POST | /unstract/<org_id>/file/upload | 向指定目录上传一个或多个文件 |
三个接口都以connector_id为关键参数——Unstract 通过 Connector 实例抽象不同的文件存储后端(本地存储、Google Drive、S3 等),文件操作实际是委托给对应 Connector 的文件系统实现的。
组织作用域路由:URL 中的<org_id>如何生效
接口路径中的<org_id>(如示例中的org_KIYj2cJ9Yisdewi4)并不由file_management应用自己解析。从源码结构看,backend/middleware/organization_middleware.py 中的OrganizationMiddleware使用正则^/api/(?P<version>v[12])/unstract/(?P<org_id>[^/]+)/匹配请求路径,将org_id写入request.organization_id,并把路径改写为/api/{version}/unstract/前缀后的相对路径。随后 backend/backend/urls_v2.py 第 29 行将file_management.urls挂载到根路径,file/、file/download等子路由便自然衔接在后。
因此,api_doc.md 中的完整示例 URL 实际对应:
<base_url>/unstract/org_KIYj2cJ9Yisdewi4/file?connector_id=11&path=/
其中<org_id>是组织标识,用于多租户隔离与鉴权上下文;connector_id与path是业务查询参数。
List File:列出目录下的文件
请求
GET /unstract/<org_id>/file?connector_id=<id>&path=<path>Sample URL(原文档示例):
<base_url>/unstract/org_KIYj2cJ9Yisdewi4/file?connector_id=11&path=/
查询参数由 backend/file_management/serializer.py 中的FileListRequestSerializer校验:
connector_id:UUIDField,必填,对应数据库中ConnectorInstance主键;path:CharField,必填,要列出的目录路径,根目录可传/。
响应结构
返回的每个条目由FileInfoSerializer序列化,字段固定为 5 个:
{ "name": "文件/目录名", "type": "file 或 directory", "modified_at": "最后修改时间", "content_type": "MIME 类型", "size": 10240 }这些字段的取值逻辑可以在 backend/file_management/file_management_dto.py 的FileInformation数据类中确认:name来自文件系统返回的条目名(经os.path.normpath归一化),modified_at解析LastModified字段,content_type优先使用后端返回的ContentType,缺失时由mimetypes.guess_type推断(见 file_management_helper.py 中get_files方法)。
源码实现要点
backend/file_management/views.py 中FileManagementViewSet.list的调用链为:
- 按
connector_id查询ConnectorInstance,不存在则抛出 404(ConnectorInstanceNotFound); FileManagerHelper.get_file_system(connector_instance)根据 Connector 类型构造对应的UnstractFileSystem实例;FileManagerHelper.list_files(file_system, path)内部通过fs.ls(file_path, detail=True)递归读取一级目录条目,并过滤掉与目录自身同名的条目。
值得注意的是,当path为空或为/时,实现会回退使用file_system.path(Connector 元数据中配置的根路径),因此对配置了固定根路径的 Connector,path=/实际列出的是该根路径下的内容。
Download:以流式响应下载文件
请求
GET /unstract/<org_id>/file/download?connector_id=<id>&path=<path>Sample URL(原文档示例):
<base_url>/unstract/org_KIYj2cJ9Yisdewi4/file/download?connector_id=12&path=root/MaskTwo-design
查询参数与 List 相同,由FileListRequestSerializer校验(见 views.py 中get_serializer_class对downloadaction 的映射)。
流式下载的实现细节
download_file位于 backend/file_management/file_management_helper.py,其关键行为对调用方有三点实际影响:
- 类型校验:先调用
fs.info(file_path)获取元数据,若type不是file(例如传入了目录路径),抛出InvalidFileType(404),即该接口只能下载单个文件; - Content-Type 推断:优先取后端返回的
ContentType;若无,先试mimetypes.guess_type;仍无法确定时读取文件前 500 字节,用python-magic(magic.from_buffer)嗅探真实 MIME 类型,再设置到响应的content_type; - 流式返回:使用 Django 的
StreamingHttpResponse包装文件流,并设置Content-Disposition: attachment; filename=<base_name>,使浏览器按附件下载,文件名为路径中的 basename。
对 Google Drive 一类后端,若底层抛出ApiRequestError(如 OAuth 凭证失效),则转换为 400 的ConnectorApiRequestError("Failed to stream file")返回给客户端。
Upload:上传文件(含格式与大小限制)
请求
POST /unstract/<org_id>/file/uploadSample URL(原文档示例):
<base_url>/unstract/org_KIYj2cJ9Yisdewi4/file/upload
原文档给出的 Body 结构为:
{ "file": "<multiple files>", "connector_id": "<Connector Id>", "path": "<File location>" }需要说明的是,从序列化器定义看,file字段是ListField(child=FileField())(见 backend/file_management/serializer.py),因此实际请求应使用multipart/form-data编码:file可重复传多个文件,connector_id与path作为表单字段提交。
上传限制:PDF 与 200 MB
FileUploadSerializer对file字段挂接了FileValidator,其约束常量定义在 backend/file_management/constants.py:
| 约束项 | 取值 | 含义 |
|---|---|---|
FILE_UPLOAD_ALLOWED_EXT | ["pdf"] | 允许上传的文件扩展名,当前仅 PDF |
FILE_UPLOAD_ALLOWED_MIME | ["application/pdf"] | 允许的 MIME 类型 |
FILE_UPLOAD_MAX_SIZE | 200 * 1024 * 1024(约 200 MB) | 单个文件最大字节数 |
min_size | 0 | 不设最小尺寸 |
也就是说,当前版本的上传接口面向 PDF 文件设计(与 Unstract 以 PDF 为主要非结构化数据源的场景一致),且单文件上限为 200 MB。校验不通过会在序列化器层面直接拒绝请求,不会触达存储后端。
上传的实现
views.py 的uploadaction 遍历serializer.validated_data.get("file")中的每个上传文件,逐个调用FileManagerHelper.upload_file。后者在 file_management_helper.py 中的行为:
- 与 List 相同的回退逻辑:
path为空或/时使用file_system.path作为实际目录; - 拼接
path + "/" + file_name,通过fs.open(file_path, mode="wb")以二进制写入远程文件系统; - 兼容
bytes与文件对象两种输入。
全部写入成功后,接口返回:
{ "message": "Files are uploaded successfully!" }错误码速查
backend/file_management/exceptions.py 定义了该模块对外可见的错误语义,调用方可以据此做分支处理:
| 异常 | 状态码 | 消息 | 典型触发场景 |
|---|---|---|---|
ConnectorInstanceNotFound | 404 | Connector instance does not exist | connector_id在数据库中不存在 |
ConnectorClassNotFound | 404 | Connector class does not exist | Connector 类型无对应文件系统实现 |
ConnectorOAuthError | 401 | Unauthorized client during OAuth | OAuth 访问令牌刷新失败(List 场景) |
ConnectorApiRequestError | 400 | Failed to stream file | 底层存储 API 请求失败(如 Drive 的ApiRequestError) |
InvalidFileType | 404 | Invalid file type | 下载路径指向的是目录而非文件 |
FileListError | 500 | Error occured while listing files | 列目录时底层fs.ls抛错 |
MissingConnectorParams | 400 | Missing params in connector metadata | Connector 缺少必需的路径元数据 |
其中 List 接口的异常映射在 views.py 中可以逐一对应:DoesNotExist→ 404、HttpAccessTokenRefreshError→ 401、ConnectorError→ 500 的FileListError。
底层抽象:Connector 到文件系统的映射
三个接口共同依赖FileManagerHelper.get_file_system,其逻辑为:读取ConnectorInstance.connector_metadata,在unstract.connectors.filesystems的connectors注册表中按connector.connector_id查找,找到后以元数据为配置实例化对应的UnstractFileSystem子类,未找到则抛ConnectorClassNotFound。该注册表定义于 unstract/filesystem 包(unstract/connectors/filesystems)。从源码结构看,这套抽象使得上层 API 对具体存储无感知——同一套/file端点既可以操作本地存储,也可以操作云端文件服务,差异被封装在 Connector 实例的元数据与对应的文件系统实现中。
相关扩展端点
除了原文档描述的三个接口,backend/file_management/urls.py 中还注册了file/delete(GET,按document_id删除 Prompt Studio 文档记录及对应文件),并在prompt_studio相关 URL 模块中映射了upload_for_ide、fetch_contents_ide、list_ide等 IDE 场景端点(见 views.py)。这些端点服务于 Prompt Studio 的本地文档管理链路,与面向 Connector 的通用文件接口在参数模型上不同:删除接口使用FileInfoIdeSerializer(document_id、tool_id),路径由FileManagerHelper.handle_sub_directory_for_tenants按org_id / user_id / tool_id分层解析。理解这一分层路径结构,有助于把握 Unstract 对多租户文件目录的隔离设计。
小结
- 三个接口的调用形态与参数约束以 backend/file_management/api_doc.md 为准:List 与 Download 均为
GET+connector_id/path查询参数,Upload 为POSTmultipart 请求; - 上传接口当前仅允许 PDF、单文件上限 200 MB(constants.py);
- 响应与错误语义可在 serializer.py、exceptions.py 中逐一对照;
- 若要在自定义集成中使用这些接口,建议优先处理 401/404/400 三类状态码,分别对应 OAuth 失效、资源不存在与请求/流式错误。
【免费下载链接】unstractLLM-Driven Extraction of Unstructured Data — Built for API Deployments & ETL Pipeline Workflows项目地址: https://gitcode.com/GitHub_Trending/un/unstract
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考