From e28f680abbc94e38e044ef7238b563cd99fd6f42 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Sat, 31 Jan 2026 18:54:05 +0800 Subject: [PATCH] =?UTF-8?q?feat(annotation):=20=E6=B7=BB=E5=8A=A0=E6=A0=87?= =?UTF-8?q?=E6=B3=A8=E9=A1=B9=E7=9B=AE=E4=BF=A1=E6=81=AF=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 引入 DatasetMappingUpdateRequest 请求模型支持 name、description、template_id 和 label_config 字段更新 - 在项目接口中添加 PUT /{project_id} 端点用于更新标注项目信息 - 实现更新逻辑包括映射记录查询、配置信息处理和数据库更新操作 - 集成标准响应格式返回更新结果 - 添加异常处理和日志记录确保操作可追溯性 --- .../module/annotation/interface/project.py | 97 ++++++++++++++++++- .../app/module/annotation/schema/mapping.py | 19 +++- 2 files changed, 112 insertions(+), 4 deletions(-) diff --git a/runtime/datamate-python/app/module/annotation/interface/project.py b/runtime/datamate-python/app/module/annotation/interface/project.py index 12d77c1..95eaa1f 100644 --- a/runtime/datamate-python/app/module/annotation/interface/project.py +++ b/runtime/datamate-python/app/module/annotation/interface/project.py @@ -3,7 +3,7 @@ import math import uuid from fastapi import APIRouter, Depends, HTTPException, Query, Path -from sqlalchemy import select +from sqlalchemy import select, update from sqlalchemy.ext.asyncio import AsyncSession from app.db.session import get_db @@ -17,6 +17,7 @@ from ..service.template import AnnotationTemplateService from ..schema import ( DatasetMappingCreateRequest, DatasetMappingCreateResponse, + DatasetMappingUpdateRequest, DeleteDatasetResponse, DatasetMappingResponse, ) @@ -382,3 +383,97 @@ async def delete_mapping( except Exception as e: logger.error(f"Error deleting mapping: {e}") raise HTTPException(status_code=500, detail="Internal server error") + + +@router.put("/{project_id}", response_model=StandardResponse[DatasetMappingResponse]) +async def update_mapping( + project_id: str = Path(..., description="映射UUID(path param)"), + request: DatasetMappingUpdateRequest = None, + db: AsyncSession = Depends(get_db) +): + """ + 更新标注项目信息 + + 通过 path 参数 `project_id` 指定要更新的映射(映射的 UUID)。 + 支持更新的字段: + - name: 标注项目名称 + - description: 标注项目描述 + - template_id: 标注模板ID + - label_config: Label Studio XML配置 + """ + try: + logger.info(f"Update mapping request received: project_id={project_id!r}") + + service = DatasetMappingService(db) + + # 使用 mapping UUID 查询映射记录 + mapping = await service.get_mapping_by_uuid(project_id) + + if not mapping: + raise HTTPException( + status_code=404, + detail=f"Mapping not found: {project_id}" + ) + + # 构建更新数据 + update_values = {} + if request.name is not None: + update_values["name"] = request.name + + # 从 configuration 字段中读取和更新 description 和 label_config + configuration = {} + if mapping.configuration: + configuration = mapping.configuration.copy() if isinstance(mapping.configuration, dict) else {} + + if request.description is not None: + configuration["description"] = request.description + if request.label_config is not None: + configuration["label_config"] = request.label_config + + if configuration: + update_values["configuration"] = configuration + + if request.template_id is not None: + update_values["template_id"] = request.template_id + + if not update_values: + # 没有要更新的字段,直接返回当前数据 + return StandardResponse( + code=200, + message="success", + data=mapping + ) + + # 执行更新 + from datetime import datetime + update_values["updated_at"] = datetime.now() + + result = await db.execute( + update(LabelingProject) + .where(LabelingProject.id == project_id) + .values(**update_values) + ) + await db.commit() + + if result.rowcount == 0: + raise HTTPException( + status_code=500, + detail="Failed to update mapping" + ) + + # 重新获取更新后的数据 + updated_mapping = await service.get_mapping_by_uuid(project_id) + + logger.info(f"Successfully updated mapping: {project_id}") + + return StandardResponse( + code=200, + message="success", + data=updated_mapping + ) + + except HTTPException: + raise + except Exception as e: + logger.error(f"Error updating mapping: {e}") + raise HTTPException(status_code=500, detail="Internal server error") diff --git a/runtime/datamate-python/app/module/annotation/schema/mapping.py b/runtime/datamate-python/app/module/annotation/schema/mapping.py index 7e7ef6c..e510477 100644 --- a/runtime/datamate-python/app/module/annotation/schema/mapping.py +++ b/runtime/datamate-python/app/module/annotation/schema/mapping.py @@ -39,9 +39,22 @@ class DatasetMappingCreateResponse(BaseResponseModel): labeling_project_id: str = Field(..., description="Label Studio项目ID") labeling_project_name: str = Field(..., description="Label Studio项目名称") -class DatasetMappingUpdateRequest(BaseResponseModel): - """数据集映射 更新 请求模型""" - dataset_id: Optional[str] = Field(None, description="源数据集ID") +class DatasetMappingUpdateRequest(BaseModel): + """数据集映射 更新 请求模型 + + 支持更新的字段: + - name: 标注项目名称 + - description: 标注项目描述 + - template_id: 标注模板ID + - label_config: Label Studio XML配置 + """ + name: Optional[str] = Field(None, alias="name", description="标注项目名称") + description: Optional[str] = Field(None, alias="description", description="标注项目描述") + template_id: Optional[str] = Field(None, alias="templateId", description="标注模板ID") + label_config: Optional[str] = Field(None, alias="labelConfig", description="Label Studio XML配置") + + class Config: + validate_by_name = True class DatasetMappingResponse(BaseModel): """数据集映射 查询 响应模型"""