You've already forked DataMate
- 添加 urllib.parse.quote 用于文件名编码 - 实现 RFC 5987 标准支持 UTF-8 编码的文件名 - 修改 Content-Disposition 头部使用 filename* 参数 - 确保中文文件名在下载时正确显示
96 lines
2.7 KiB
Python
96 lines
2.7 KiB
Python
"""
|
|
标注数据导出接口
|
|
|
|
提供标注数据的批量导出功能,支持多种格式:
|
|
- JSON: Label Studio 原生格式
|
|
- JSONL: JSON Lines 格式
|
|
- CSV: 表格格式
|
|
- COCO: 目标检测格式
|
|
- YOLO: YOLO 格式
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from urllib.parse import quote
|
|
|
|
from fastapi import APIRouter, Depends, Path, Query
|
|
from fastapi.responses import Response
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.logging import get_logger
|
|
from app.db.session import get_db
|
|
from app.module.shared.schema import StandardResponse
|
|
|
|
from ..schema.export import (
|
|
ExportAnnotationsRequest,
|
|
ExportAnnotationsResponse,
|
|
ExportFormat,
|
|
)
|
|
from ..service.export import AnnotationExportService
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
router = APIRouter(
|
|
prefix="/export",
|
|
tags=["annotation/export"],
|
|
)
|
|
|
|
|
|
@router.get(
|
|
"/projects/{project_id}/stats",
|
|
response_model=StandardResponse[ExportAnnotationsResponse],
|
|
)
|
|
async def get_export_stats(
|
|
project_id: str = Path(..., description="标注项目ID"),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""获取导出统计信息(总文件数、已标注数等)"""
|
|
service = AnnotationExportService(db)
|
|
stats = await service.get_export_stats(project_id)
|
|
return StandardResponse(code=200, message="success", data=stats)
|
|
|
|
|
|
@router.get("/projects/{project_id}/download")
|
|
async def download_annotations(
|
|
project_id: str = Path(..., description="标注项目ID"),
|
|
format: ExportFormat = Query(default=ExportFormat.JSON, description="导出格式"),
|
|
include_data: bool = Query(default=False, description="是否包含原始数据"),
|
|
only_annotated: bool = Query(default=True, description="是否只导出已标注数据"),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""
|
|
下载标注数据
|
|
|
|
支持的格式:
|
|
- json: Label Studio 原生 JSON 格式
|
|
- jsonl: JSON Lines 格式(每行一条记录)
|
|
- csv: CSV 表格格式
|
|
- coco: COCO 目标检测格式
|
|
- yolo: YOLO 格式(ZIP 压缩包)
|
|
"""
|
|
service = AnnotationExportService(db)
|
|
|
|
request = ExportAnnotationsRequest(
|
|
format=format,
|
|
include_data=include_data,
|
|
only_annotated=only_annotated,
|
|
)
|
|
|
|
content, filename, content_type = await service.export_annotations(
|
|
project_id=project_id,
|
|
request=request,
|
|
)
|
|
|
|
# RFC 5987: 使用 filename* 支持 UTF-8 编码的文件名
|
|
encoded_filename = quote(filename, safe="")
|
|
content_disposition = f"attachment; filename*=UTF-8''{encoded_filename}"
|
|
|
|
return Response(
|
|
content=content,
|
|
media_type=content_type,
|
|
headers={
|
|
"Content-Disposition": content_disposition,
|
|
"Content-Length": str(len(content)),
|
|
},
|
|
)
|