From e0884ab04839995a807d0870f518f177085f3fb9 Mon Sep 17 00:00:00 2001 From: Jason Wang <56037774+JasonW404@users.noreply.github.com> Date: Thu, 30 Oct 2025 16:24:37 +0800 Subject: [PATCH] Develop py update schema (#37) * feature: implement endpoints with multi-level response models * refactor: move `/health` and `/config` endpoints to system module, remove example from base schemas * refactor: remove unused get_standard_response_model() --- .../datamate-python/app/module/__init__.py | 2 ++ .../module/annotation/interface/project.py | 6 ++-- .../app/module/annotation/schema/__init__.py | 10 +++--- .../app/module/annotation/schema/mapping.py | 11 +++--- .../app/module/annotation/schema/sync.py | 6 ++-- .../app/module/management/api/__init__.py | 0 .../app/module/management/api/system.py | 33 ----------------- .../app/module/management/service/__init__.py | 0 .../app/module/shared/schema/common.py | 24 ++----------- .../module/{management => system}/__init__.py | 0 .../app/module/system/interface/__init__.py | 7 ++++ .../app/module/system/interface/about.py | 36 +++++++++++++++++++ .../app/module/system/schema/__init__.py | 4 +++ .../app/module/system/schema/config.py | 11 ++++++ .../app/module/system/schema/health.py | 10 ++++++ 15 files changed, 89 insertions(+), 71 deletions(-) delete mode 100644 runtime/datamate-python/app/module/management/api/__init__.py delete mode 100644 runtime/datamate-python/app/module/management/api/system.py delete mode 100644 runtime/datamate-python/app/module/management/service/__init__.py rename runtime/datamate-python/app/module/{management => system}/__init__.py (100%) create mode 100644 runtime/datamate-python/app/module/system/interface/__init__.py create mode 100644 runtime/datamate-python/app/module/system/interface/about.py create mode 100644 runtime/datamate-python/app/module/system/schema/__init__.py create mode 100644 runtime/datamate-python/app/module/system/schema/config.py create mode 100644 runtime/datamate-python/app/module/system/schema/health.py diff --git a/runtime/datamate-python/app/module/__init__.py b/runtime/datamate-python/app/module/__init__.py index 4ca3782..a8b7d79 100644 --- a/runtime/datamate-python/app/module/__init__.py +++ b/runtime/datamate-python/app/module/__init__.py @@ -1,11 +1,13 @@ from fastapi import APIRouter +from .system.interface import router as system_router from .annotation.interface import router as annotation_router router = APIRouter( prefix="/api" ) +router.include_router(system_router) router.include_router(annotation_router) __all__ = ["router"] \ No newline at end of file diff --git a/runtime/datamate-python/app/module/annotation/interface/project.py b/runtime/datamate-python/app/module/annotation/interface/project.py index c22a3d9..5896e41 100644 --- a/runtime/datamate-python/app/module/annotation/interface/project.py +++ b/runtime/datamate-python/app/module/annotation/interface/project.py @@ -108,8 +108,7 @@ async def create_mapping( response_data = DatasetMappingCreateResponse( id=mapping.id, labeling_project_id=str(mapping.labeling_project_id), - labeling_project_name=mapping.name or project_name, - message="Dataset mapping created successfully" + labeling_project_name=mapping.name or project_name ) return StandardResponse( @@ -341,8 +340,7 @@ async def delete_mapping( message="success", data=DeleteDatasetResponse( id=id, - status="success", - message=f"Successfully deleted mapping and Label Studio project '{labeling_project_name}'" + status="success" ) ) diff --git a/runtime/datamate-python/app/module/annotation/schema/__init__.py b/runtime/datamate-python/app/module/annotation/schema/__init__.py index 289a327..bcbd6e9 100644 --- a/runtime/datamate-python/app/module/annotation/schema/__init__.py +++ b/runtime/datamate-python/app/module/annotation/schema/__init__.py @@ -1,24 +1,24 @@ from .mapping import ( - DatasetMappingBase, + _DatasetMappingBase, DatasetMappingCreateRequest, DatasetMappingCreateResponse, DatasetMappingUpdateRequest, DatasetMappingResponse, - DeleteDatasetResponse + DeleteDatasetResponse, ) from .sync import ( SyncDatasetRequest, - SyncDatasetResponse + SyncDatasetResponse, ) __all__ = [ - "DatasetMappingBase", + "_DatasetMappingBase", "DatasetMappingCreateRequest", "DatasetMappingCreateResponse", "DatasetMappingUpdateRequest", "DatasetMappingResponse", "SyncDatasetRequest", "SyncDatasetResponse", - "DeleteDatasetResponse" + "DeleteDatasetResponse", ] \ No newline at end of file diff --git a/runtime/datamate-python/app/module/annotation/schema/mapping.py b/runtime/datamate-python/app/module/annotation/schema/mapping.py index d0c80d8..212059b 100644 --- a/runtime/datamate-python/app/module/annotation/schema/mapping.py +++ b/runtime/datamate-python/app/module/annotation/schema/mapping.py @@ -3,12 +3,13 @@ from typing import Optional from datetime import datetime from app.module.shared.schema import BaseResponseModel +from app.module.shared.schema import StandardResponse -class DatasetMappingBase(BaseResponseModel): +class _DatasetMappingBase(BaseResponseModel): """数据集映射 基础模型""" dataset_id: str = Field(..., description="源数据集ID") -class DatasetMappingCreateRequest(DatasetMappingBase): +class DatasetMappingCreateRequest(_DatasetMappingBase): """数据集映射 创建 请求模型""" pass @@ -17,13 +18,12 @@ class DatasetMappingCreateResponse(BaseResponseModel): id: str = Field(..., description="映射UUID") labeling_project_id: str = Field(..., description="Label Studio项目ID") labeling_project_name: str = Field(..., description="Label Studio项目名称") - message: str = Field(..., description="响应消息") class DatasetMappingUpdateRequest(BaseResponseModel): """数据集映射 更新 请求模型""" dataset_id: Optional[str] = Field(None, description="源数据集ID") -class DatasetMappingResponse(DatasetMappingBase): +class DatasetMappingResponse(_DatasetMappingBase): """数据集映射 查询 响应模型""" id: str = Field(..., description="映射UUID") labeling_project_id: str = Field(..., description="标注项目ID") @@ -38,5 +38,4 @@ class DatasetMappingResponse(DatasetMappingBase): class DeleteDatasetResponse(BaseResponseModel): """删除数据集响应模型""" id: str = Field(..., description="映射UUID") - status: str = Field(..., description="删除状态") - message: str = Field(..., description="响应消息") \ No newline at end of file + status: str = Field(..., description="删除状态") \ No newline at end of file diff --git a/runtime/datamate-python/app/module/annotation/schema/sync.py b/runtime/datamate-python/app/module/annotation/schema/sync.py index 492d372..6604c8c 100644 --- a/runtime/datamate-python/app/module/annotation/schema/sync.py +++ b/runtime/datamate-python/app/module/annotation/schema/sync.py @@ -1,8 +1,7 @@ from pydantic import Field -from typing import Optional -from datetime import datetime from app.module.shared.schema import BaseResponseModel +from app.module.shared.schema import StandardResponse class SyncDatasetRequest(BaseResponseModel): @@ -17,3 +16,6 @@ class SyncDatasetResponse(BaseResponseModel): synced_files: int = Field(..., description="已同步文件数量") total_files: int = Field(0, description="总文件数量") message: str = Field(..., description="响应消息") + +class SyncDatasetResponseStd(StandardResponse[SyncDatasetResponse]): + pass \ No newline at end of file diff --git a/runtime/datamate-python/app/module/management/api/__init__.py b/runtime/datamate-python/app/module/management/api/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/runtime/datamate-python/app/module/management/api/system.py b/runtime/datamate-python/app/module/management/api/system.py deleted file mode 100644 index aa38d87..0000000 --- a/runtime/datamate-python/app/module/management/api/system.py +++ /dev/null @@ -1,33 +0,0 @@ -from fastapi import APIRouter -from typing import Dict, Any -from app.core.config import settings -from app.schemas import StandardResponse - -router = APIRouter() - -@router.get("/health", response_model=StandardResponse[Dict[str, Any]]) -async def health_check(): - """健康检查端点""" - return StandardResponse( - code=200, - message="success", - data={ - "status": "healthy", - "service": "Label Studio Adapter", - "version": settings.app_version - } - ) - -@router.get("/config", response_model=StandardResponse[Dict[str, Any]]) -async def get_config(): - """获取配置信息""" - return StandardResponse( - code=200, - message="success", - data={ - "app_name": settings.app_name, - "version": settings.app_version, - "label_studio_url": settings.label_studio_base_url, - "debug": settings.debug - } - ) \ No newline at end of file diff --git a/runtime/datamate-python/app/module/management/service/__init__.py b/runtime/datamate-python/app/module/management/service/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/runtime/datamate-python/app/module/shared/schema/common.py b/runtime/datamate-python/app/module/shared/schema/common.py index b0681d1..c79231a 100644 --- a/runtime/datamate-python/app/module/shared/schema/common.py +++ b/runtime/datamate-python/app/module/shared/schema/common.py @@ -1,7 +1,7 @@ """ 通用响应模型 """ -from typing import Generic, TypeVar, Optional, List +from typing import Generic, TypeVar, Optional, List, Type from pydantic import BaseModel, Field # 定义泛型类型变量 @@ -29,18 +29,11 @@ class StandardResponse(BaseResponseModel, Generic[T]): """ code: int = Field(..., description="HTTP状态码") message: str = Field(..., description="响应消息") - data: Optional[T] = Field(None, description="响应数据") - + data: T = Field(..., description="响应数据") + class Config: populate_by_name = True alias_generator = to_camel - json_schema_extra = { - "example": { - "code": 200, - "message": "success", - "data": {} - } - } class PaginatedData(BaseResponseModel, Generic[T]): """分页数据容器""" @@ -49,14 +42,3 @@ class PaginatedData(BaseResponseModel, Generic[T]): total_elements: int = Field(..., description="总条数") total_pages: int = Field(..., description="总页数") content: List[T] = Field(..., description="当前页数据") - - class Config: - json_schema_extra = { - "example": { - "page": 1, - "size": 20, - "totalElements": 100, - "totalPages": 5, - "content": [] - } - } diff --git a/runtime/datamate-python/app/module/management/__init__.py b/runtime/datamate-python/app/module/system/__init__.py similarity index 100% rename from runtime/datamate-python/app/module/management/__init__.py rename to runtime/datamate-python/app/module/system/__init__.py diff --git a/runtime/datamate-python/app/module/system/interface/__init__.py b/runtime/datamate-python/app/module/system/interface/__init__.py new file mode 100644 index 0000000..acd1023 --- /dev/null +++ b/runtime/datamate-python/app/module/system/interface/__init__.py @@ -0,0 +1,7 @@ +from fastapi import APIRouter + +from .about import router as about_router + +router = APIRouter() + +router.include_router(about_router) \ No newline at end of file diff --git a/runtime/datamate-python/app/module/system/interface/about.py b/runtime/datamate-python/app/module/system/interface/about.py new file mode 100644 index 0000000..f81b2ef --- /dev/null +++ b/runtime/datamate-python/app/module/system/interface/about.py @@ -0,0 +1,36 @@ +from fastapi import APIRouter +from typing import Dict, Any +from app.core.config import settings +from app.module.shared.schema import StandardResponse + +from ..schema import ConfigResponse, HealthResponse + +router = APIRouter() + +@router.get("/health", response_model=StandardResponse[HealthResponse]) +async def health_check(): + """健康检查端点""" + + return StandardResponse( + code=200, + message="success", + data=HealthResponse( + status="healthy", + service="Label Studio Adapter", + version=settings.app_version + ) + ) + +@router.get("/config", response_model=StandardResponse[ConfigResponse]) +async def get_config(): + """获取配置信息""" + return StandardResponse( + code=200, + message="success", + data=ConfigResponse( + app_name=settings.app_name, + version=settings.app_version, + label_studio_url=settings.label_studio_base_url, + debug=settings.debug + ) + ) \ No newline at end of file diff --git a/runtime/datamate-python/app/module/system/schema/__init__.py b/runtime/datamate-python/app/module/system/schema/__init__.py new file mode 100644 index 0000000..c2bcb38 --- /dev/null +++ b/runtime/datamate-python/app/module/system/schema/__init__.py @@ -0,0 +1,4 @@ +from .config import ConfigResponse +from .health import HealthResponse + +__all__ = ["ConfigResponse", "HealthResponse"] \ No newline at end of file diff --git a/runtime/datamate-python/app/module/system/schema/config.py b/runtime/datamate-python/app/module/system/schema/config.py new file mode 100644 index 0000000..279c156 --- /dev/null +++ b/runtime/datamate-python/app/module/system/schema/config.py @@ -0,0 +1,11 @@ +from pydantic import Field + +from app.module.shared.schema import BaseResponseModel +from app.module.shared.schema import StandardResponse + +class ConfigResponse(BaseResponseModel): + """配置信息响应模型""" + app_name: str = Field(..., description="应用名称") + version: str = Field(..., description="应用版本") + label_studio_url: str = Field(..., description="Label Studio基础URL") + debug: bool = Field(..., description="调试模式状态") \ No newline at end of file diff --git a/runtime/datamate-python/app/module/system/schema/health.py b/runtime/datamate-python/app/module/system/schema/health.py new file mode 100644 index 0000000..689ec50 --- /dev/null +++ b/runtime/datamate-python/app/module/system/schema/health.py @@ -0,0 +1,10 @@ +from pydantic import Field + +from app.module.shared.schema import BaseResponseModel +from app.module.shared.schema import StandardResponse + +class HealthResponse(BaseResponseModel): + """健康检查响应模型""" + status: str = Field(..., description="服务状态") + service: str = Field(..., description="服务名称") + version: str = Field(..., description="应用版本") \ No newline at end of file