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()
This commit is contained in:
Jason Wang
2025-10-30 16:24:37 +08:00
committed by GitHub
parent 155603b1ca
commit e0884ab048
15 changed files with 89 additions and 71 deletions

View File

@@ -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"]

View File

@@ -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"
)
)

View File

@@ -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",
]

View File

@@ -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="响应消息")
status: str = Field(..., description="删除状态")

View File

@@ -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

View File

@@ -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
}
)

View File

@@ -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": []
}
}

View File

@@ -0,0 +1,7 @@
from fastapi import APIRouter
from .about import router as about_router
router = APIRouter()
router.include_router(about_router)

View File

@@ -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
)
)

View File

@@ -0,0 +1,4 @@
from .config import ConfigResponse
from .health import HealthResponse
__all__ = ["ConfigResponse", "HealthResponse"]

View File

@@ -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="调试模式状态")

View File

@@ -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="应用版本")