ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Label Studio 本地文件存储(Local Files Storage)完整指南:离线环境下的数据导入、文件服务与标注导出

Label Studio 本地文件存储(Local Files Storage)完整指南:离线环境下的数据导入、文件服务与标注导出 Label Studio 本地文件存储Local Files Storage完整指南离线环境下的数据导入、文件服务与标注导出【免费下载链接】label-studioLabel Studio is a multi-type data labeling and annotation tool with standardized output format项目地址: https://gitcode.com/GitHub_Trending/la/label-studio导读Label Studio 的 Local Files Storage本地文件存储让自托管部署可以在不依赖任何对象存储服务的前提下直接从服务器文件系统读取图片、音频、视频、文档等媒体数据并将标注结果写回磁盘。它专为离线air-gapped环境或数据不允许离开宿主机的工作流设计在社区版中提供了开箱即用的我的数据目录自动探测机制。读完本文你将掌握如何在 Label Studio 中配置本地文件存储的三个核心操作——导入/同步Import/Sync、文件服务Serve与标注导出Export理解其底层路径规范化、权限校验与缓存机制并能够独立排查 403/404 等常见故障。概述三个核心操作本地文件存储的核心价值体现在三个相互独立又彼此衔接的操作上导入/同步Import/Sync——扫描一个目录为每个文件创建指向本地文件的标注任务文件服务Serve——通过/data/local-files/?d...端点把文件字节流式传输给标注界面导出Export——把完成的标注以 JSON 文件形式写入目标目录。架构配置、导入、文件服务与导出的完整链路整个本地文件存储的数据流可以用下面这张流程图概括该图源自 localfiles/README.md 中的架构图语义与代码实现一致Configuration: - 环境变量: LOCAL_FILES_SERVING_ENABLED, LOCAL_FILES_DOCUMENT_ROOT - 社区版自动探测: mydata / label-studio-data Import Flow: UI Add Source Storage → Serializernormalize path, validate_connection → LocalFilesImportStorage → Sync → iter_objects扫描目录 → use_blob_urlstrue: 为每个文件创建任务URL 为 /data/local-files/?dpath → use_blob_urlsfalse: 读取 JSON 文件作为任务定义 → 任务写入数据库 → 建立 LocalFilesImportStorageLink File Serving Flow: 标注界面请求 /data/local-files/?drelative/path → localfiles_data 视图 → 校验认证 → safe_join(DOCUMENT_ROOT, path) 规范化路径 → 查找所有 storage.path 是文件目录前缀的存储 → 校验 project.has_permission → 允许: 使用 RangedFileResponse 流式返回文件并带 ETag → 拒绝: 403 Forbidden路径不存在: 404 Not Found Export Flow: 标注保存 → post_save 信号 → LocalFilesExportStorage.save_annotation → 写入 JSON 到 storage.path/annotation_id.json → 建立 LocalFilesExportStorageLink 标注删除 → pre_delete 信号 → delete_annotation 删除 JSON 文件各环节对应的源码位置环节源码文件关键实现路径规范化functions.pynormalize_storage_path目录自动探测functions.pyautodetect_local_files_root存储模型与校验models.pyLocalFilesMixin、validate_connection文件服务端点views.pylocalfiles_data视图REST APIapi.pyImport/Export 系列 API 视图表单字段定义form_layout.yml前端表单布局路由注册io_storages/urls.py/api/storages/localfiles/与/data/local-files/关键概念存储模型Storage Models本地文件存储在数据库中对应四个模型类职责划分非常清晰模型用途LocalFilesMixin共享字段path、regex_filter、use_blob_urls与校验逻辑LocalFilesImportStorage源存储Source Storage扫描目录、创建任务LocalFilesExportStorage目标存储Target Storage把标注写成 JSON 文件LocalFilesImportStorageLink把任务关联到导入存储追踪哪个文件创建了哪个任务LocalFilesExportStorageLink把标注关联到导出存储追踪已导出的文件从源码看LocalFilesMixin的三个核心字段定义在 models.pypath本地绝对路径TextField在clean()与save()两个时机都会执行normalize_storage_path规范化regex_filter过滤对象的正则表达式命中才导入use_blob_urls布尔值决定文件是被当作 BLOB 生成 URL还是被当作任务定义 JSON 解析默认False。导入模式Import Modes同步导入存储时use_blob_urls决定文件如何变成任务use_blob_urlsTrue默认Files模式每个文件变成一个任务任务中唯一的 data 字段指向/data/local-files/?d相对路径。最适合标注图片、音频、视频这类单媒体文件。use_blob_urlsFalseTasks模式每个.json/.jsonl文件被解析为任务定义适用于任务结构复杂或有多个 data 字段的场景。这一分支逻辑实现在LocalFilesImportStorageBase.get_data()models.py中use_blob_urlsTrue时构造{settings.DATA_UNDEFINED_NAME: f{settings.HOSTNAME}/data/local-files/?d{quote(relative_path)}}形式的任务否则调用load_tasks_json读取文件内容。表单中对应的选择项定义在 form_layout.ymlUI 文案为 Files - Automatically creates a task for each storage object 与 Tasks - Treat each JSON or JSONL file as a task definition。目录扫描由iter_objects()models.py完成它使用path.glob(*)或path.rglob(*)当recursive_scan开启时遍历目录按文件名升序排序保证任务 ID 与文件名顺序一致跳过目录项并用regex_filter正则匹配文件名regex.match注意是 match 而非 search即从文件名开头匹配。路径处理Path Handling所有存储路径在保存前都会被规范化normalize_storage_path见 functions.py去除尾部斜杠/data/images/→/data/images把反斜杠转换为当前操作系统的路径分隔符Linux 上C:\data→C:/data折叠冗余分隔符/data//images→/data/images。这一步是为了防止存储路径与请求路径不一致导致的 404 错误——因为权限检查见下文会对请求文件所在目录与storage.path做字符串前缀匹配任何格式不一致都会导致匹配失败。权限模型Permission Model/data/local-files/?d...端点强制执行四重校验对应 views.py 的实现顺序用户必须已认证视图装饰器permission_classes([IsAuthenticated])LOCAL_FILES_SERVING_ENABLED必须为true否则直接返回 403请求文件的所在目录必须位于至少一个LocalFilesImportStorage.path之内——实现方式是LocalFilesImportStorage.objects.annotate(_full_pathValue(full_path_dir)).filter(_full_path__startswithF(path))即对请求文件目录做数据库前缀匹配用户必须对该存储所属项目有访问权限storage.project.has_permission(request.user)。配置指南环境变量变量默认值说明LOCAL_FILES_SERVING_ENABLEDfalse必须设为true才能通过/data/local-files/提供文件服务LOCAL_FILES_DOCUMENT_ROOT/根目录基础目录所有存储路径必须是它的子目录ENABLE_LOCAL_FILES_STORAGEtrue是否把 Local Files 作为存储选项展示这些默认值与解析逻辑定义在 core/settings/base.pyENABLE_LOCAL_FILES_STORAGE get_bool_env(ENABLE_LOCAL_FILES_STORAGE, defaultTrue) LOCAL_FILES_SERVING_ENABLED get_bool_env(LOCAL_FILES_SERVING_ENABLED, defaultFalse) LOCAL_FILES_DOCUMENT_ROOT get_env(LOCAL_FILES_DOCUMENT_ROOT, defaultos.path.abspath(os.sep))变量名可以加LABEL_STUDIO_或HEARTEX_前缀按此顺序检测例如LABEL_STUDIO_LOCAL_FILES_SERVING_ENABLEDtrue。ENABLE_LOCAL_FILES_STORAGEfalse时Local Files 存储选项会在 API 注册阶段被隐藏——io_storages/all_api.py 中依据该开关决定是否注册相关视图。社区版自动探测Community Edition Auto-Detection当LOCAL_FILES_DOCUMENT_ROOT与LOCAL_FILES_SERVING_ENABLED都未设置时社区版会自动在当前工作目录下查找mydata或label-studio-data目录候选名定义在 functions.py 的AUTO_ROOT_CANDIDATES元组中。若找到则把该目录设为文档根并开启本地文件服务。对应逻辑在 core/settings/base.pyif ( VERSION_EDITION Community and not has_env(LOCAL_FILES_DOCUMENT_ROOT) and not has_env(LOCAL_FILES_SERVING_ENABLED) ): from label_studio.io_storages.localfiles.functions import autodetect_local_files_root _autodetected_root autodetect_local_files_root() if _autodetected_root: LOCAL_FILES_DOCUMENT_ROOT _autodetected_root LOCAL_FILES_SERVING_ENABLED TrueDocker 快捷方式把宿主机目录挂载到容器内的/label-studio/mydata即可在不设置任何环境变量的情况下启用本地文件存储。生产环境配置export LABEL_STUDIO_LOCAL_FILES_SERVING_ENABLEDtrue export LABEL_STUDIO_LOCAL_FILES_DOCUMENT_ROOT/data/labelstudio # 目录结构 # /data/labelstudio/ ← DOCUMENT_ROOT # /data/labelstudio/project1/ ← 项目 1 的存储路径 # /data/labelstudio/project2/ ← 项目 2 的存储路径注意每个存储路径都必须是LOCAL_FILES_DOCUMENT_ROOT的子目录不能等于文档根本身。这一限制在validate_connection()models.py中有三重校验路径必须存在Path.exists()否则报 does not exist路径不能与LOCAL_FILES_DOCUMENT_ROOT相同cannot be the same ... by security reasons路径必须是文档根的子目录document_root not in path.parents时报错并提示如{DOCUMENT_ROOT}/dataset1的示例。此外若LOCAL_FILES_SERVING_ENABLED为False创建存储时会直接报校验错误提示先设置环境变量并重启社区版还会附上community_auto_hint()的提示创建mydata或label-studio-data目录可自动启用。使用指南用本地文件创建任务在项目Settings → Cloud Storage → Add Source Storage → Local Files中配置导入存储将Absolute local path绝对本地路径设置为LOCAL_FILES_DOCUMENT_ROOT的子目录选择导入方式Files每个媒体文件自动创建一个任务Tasks把 JSON/JSONL 文件作为任务定义读取点击Sync扫描目录并创建任务。表单中还可选填File Filter Regex如.*csv、.*(jpe?g|png|tiff)、.*\w-\d.text只导入文件名匹配正则的文件对应LocalFilesMixin.regex_filter字段与iter_objects中的过滤逻辑Recursive scan开启后可递归扫描子目录。手动导入任务引用本地文件通过 JSON 手动导入任务时用以下格式引用本地文件{ data: { image: /data/local-files/?dproject1/images/photo.jpg, audio: /data/local-files/?dproject1/audio/recording.wav } }?d之后的路径是相对于LOCAL_FILES_DOCUMENT_ROOT的。服务端收到请求后会先posixpath.normpath(path).lstrip(/)规范化相对路径再通过 Django 的safe_join(local_serving_document_root, path)拼接出安全绝对路径views.py从而把路径逃逸path traversal风险限制在文档根之内。导出标注在项目Settings → Cloud Storage → Add Target Storage → Local Files中配置目标存储标注保存后会自动写成 JSON 文件文件命名规则为annotation_id.json位于存储路径下。导出由 Django 信号驱动models.pypost_save信号export_annotation_to_local_files标注保存后遍历项目下所有io_storages_localfilesexportstorages关联的导出存储调用save_annotation()save_annotation()models.py把序列化后的标注用json.dump(..., indent2)写入{storage_path}/{annotation_id}.json并创建LocalFilesExportStorageLinkpre_delete信号delete_annotation_from_local_files标注删除时若对应存储的can_delete_objects为True则删除磁盘上的 JSON 文件文件已缺失时仅记录 warning并清理关联记录。测试用例 test_localfiles_export.py 验证了这一行为can_delete_objectsTrue时删除标注会同步删除导出文件与链接can_delete_objectsFalse时导出文件保留。同步工作流测试见 fsm/tests/test_storage_sync_workflows.py。API 参考REST 端点端点方法说明/api/storages/localfiles/GET, POST列出/创建导入存储/api/storages/localfiles/{id}/GET, PATCH, DELETE管理指定导入存储/api/storages/localfiles/{id}/syncPOST触发同步/api/storages/export/localfiles/GET, POST列出/创建导出存储/data/local-files/?d{path}GET提供文件内容服务非 REST 端点上述路由注册在 io_storages/urls.py除此之外还有localfiles/validate连接校验、localfiles/form表单布局、localfiles/files文件列表以及对应的 export 系列端点。对应的 API 视图类定义在 api.py序列化器在 serializers.py——其中validate()会先规范化path再实例化存储模型调用validate_connection()把 Django/DRF 校验错误统一转为字符串格式返回给前端。文件服务细节/data/local-files/视图views.py的行为服务被禁用或用户无权限 → 返回403文件不存在或没有匹配的存储 → 返回404客户端If-None-Match与当前 ETag 匹配 → 返回304 Not Modified支持HTTP Range 请求用于视频/音频的拖动播放通过RangedFileResponse实现views.py。缓存实现细节build_localfile_response()views.py基于文件修改时间纳秒与文件大小生成弱 ETag格式W/{mtime_ns:x}-{size:x}使浏览器可以在文件未变化时复用缓存MIME 类型通过mimetypes.guess_type探测未知类型回退为application/octet-stream。文件参考文件用途models.pyDjango 模型、normalize_storage_path应用、连接校验、信号处理器views.py/data/local-files/端点含 ETag 与 Range 支持serializers.pyDRF 序列化器、路径规范化、错误格式化api.pyREST API 视图类functions.pynormalize_storage_path、autodetect_local_files_rootform_layout.ymlUI 表单字段定义故障排查常见问题症状原因解决方案/data/local-files/返回 403文件服务被禁用设置LOCAL_FILES_SERVING_ENABLEDtrue并重启/data/local-files/返回 404没有匹配的存储或文件不存在检查存储路径是否为文件路径的前缀确认文件存在创建存储时校验报错路径不在文档根之下确保路径以LOCAL_FILES_DOCUMENT_ROOT开头且为子目录图片显示为裂图路径不匹配如尾部斜杠路径现在会自动规范化重新同步存储即可调试步骤检查环境变量echo $LABEL_STUDIO_LOCAL_FILES_SERVING_ENABLED echo $LABEL_STUDIO_LOCAL_FILES_DOCUMENT_ROOT直接测试文件访问注意需携带授权 Token 的-H请求头curl -I -H Authorization: Token your_token http://localhost:8080/data/local-files/?dproject1/test.jpg在 Django shell 中核查存储配置from io_storages.localfiles.models import LocalFilesImportStorage for s in LocalFilesImportStorage.objects.all(): print(f{s.project.title}: {s.path})安全注意事项默认禁用LOCAL_FILES_SERVING_ENABLEDfalse防止意外暴露文件系统路径包含所有请求都基于LOCAL_FILES_DOCUMENT_ROOT校验safe_join 前缀匹配路径逃逸被限制在文档根内项目权限用户只能访问其有权限的、且与该文件存在前缀关联的项目存储中的文件无目录列表仅提供明确的文件路径服务不提供目录浏览。警告不要在公开的多租户部署中启用本地文件服务。该特性专为单租户的本地on-premise部署设计。若你确实需要多租户场景应改用对象存储S3/GCS/Azure Blob等具备独立凭据隔离能力的存储后端。【免费下载链接】label-studioLabel Studio is a multi-type data labeling and annotation tool with standardized output format项目地址: https://gitcode.com/GitHub_Trending/la/label-studio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表