external.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. """
  2. Pydantic schemas for External API.
  3. Defines request and response models for external system integration.
  4. """
  5. from datetime import datetime
  6. from typing import Optional, List, Any
  7. from enum import Enum
  8. from pydantic import BaseModel, Field
  9. # ============== 枚举定义 ==============
  10. class TaskType(str, Enum):
  11. """支持的任务类型"""
  12. TEXT_CLASSIFICATION = "text_classification"
  13. IMAGE_CLASSIFICATION = "image_classification"
  14. OBJECT_DETECTION = "object_detection"
  15. NER = "ner"
  16. class ExternalExportFormat(str, Enum):
  17. """支持的导出格式"""
  18. JSON = "json"
  19. CSV = "csv"
  20. SHAREGPT = "sharegpt"
  21. YOLO = "yolo"
  22. COCO = "coco"
  23. ALPACA = "alpaca"
  24. # ============== 项目初始化相关 ==============
  25. class TaskDataItem(BaseModel):
  26. """单个任务数据项"""
  27. id: Optional[str] = Field(None, description="外部系统的数据ID,用于关联")
  28. content: str = Field(..., description="数据内容(文本或图像URL)")
  29. metadata: Optional[dict] = Field(None, description="额外元数据")
  30. class Config:
  31. json_schema_extra = {
  32. "example": {
  33. "id": "ext_001",
  34. "content": "https://example.com/image.jpg",
  35. "metadata": {"batch": "001", "source": "商品库"}
  36. }
  37. }
  38. class ProjectInitRequest(BaseModel):
  39. """项目初始化请求"""
  40. name: str = Field(..., min_length=1, description="项目名称")
  41. description: Optional[str] = Field("", description="项目描述")
  42. task_type: TaskType = Field(..., description="任务类型")
  43. data: List[TaskDataItem] = Field(..., min_length=1, description="任务数据列表")
  44. external_id: Optional[str] = Field(None, description="外部系统的项目ID,用于关联查询")
  45. class Config:
  46. json_schema_extra = {
  47. "example": {
  48. "name": "图像分类项目-批次001",
  49. "description": "对商品图片进行分类标注",
  50. "task_type": "image_classification",
  51. "data": [
  52. {
  53. "id": "ext_001",
  54. "content": "https://example.com/images/product1.jpg",
  55. "metadata": {"batch": "001"}
  56. }
  57. ],
  58. "external_id": "sample_center_proj_001"
  59. }
  60. }
  61. class ProjectInitResponse(BaseModel):
  62. """项目初始化响应"""
  63. project_id: str = Field(..., description="标注平台项目ID,样本中心需保存用于后续回调")
  64. project_name: str = Field(..., description="项目名称")
  65. task_count: int = Field(..., description="创建的任务数量")
  66. status: str = Field(..., description="项目状态")
  67. created_at: datetime = Field(..., description="创建时间")
  68. config: str = Field(..., description="实际使用的XML配置模板")
  69. external_id: Optional[str] = Field(None, description="外部系统的项目ID")
  70. class Config:
  71. json_schema_extra = {
  72. "example": {
  73. "project_id": "proj_abc123def456",
  74. "project_name": "图像分类项目-批次001",
  75. "task_count": 100,
  76. "status": "draft",
  77. "created_at": "2026-02-03T10:30:00Z",
  78. "config": "<View>...</View>",
  79. "external_id": "sample_center_proj_001"
  80. }
  81. }
  82. # ============== 进度查询相关 ==============
  83. class AnnotatorProgress(BaseModel):
  84. """标注人员进度"""
  85. user_id: str = Field(..., description="用户ID")
  86. username: str = Field(..., description="用户名")
  87. assigned_count: int = Field(..., description="分配的任务数")
  88. completed_count: int = Field(..., description="已完成数")
  89. in_progress_count: int = Field(..., description="进行中数")
  90. completion_rate: float = Field(..., description="个人完成率(0-100)")
  91. class ProgressResponse(BaseModel):
  92. """项目进度响应"""
  93. project_id: str = Field(..., description="项目ID")
  94. project_name: str = Field(..., description="项目名称")
  95. status: str = Field(..., description="项目状态")
  96. total_tasks: int = Field(..., description="总任务数")
  97. completed_tasks: int = Field(..., description="已完成任务数")
  98. in_progress_tasks: int = Field(..., description="进行中任务数")
  99. pending_tasks: int = Field(..., description="待处理任务数")
  100. completion_percentage: float = Field(..., description="完成百分比(0-100)")
  101. annotators: List[AnnotatorProgress] = Field(default_factory=list, description="标注人员列表")
  102. last_updated: Optional[datetime] = Field(None, description="最后更新时间")
  103. class Config:
  104. json_schema_extra = {
  105. "example": {
  106. "project_id": "proj_abc123def456",
  107. "project_name": "图像分类项目-批次001",
  108. "status": "in_progress",
  109. "total_tasks": 100,
  110. "completed_tasks": 45,
  111. "in_progress_tasks": 30,
  112. "pending_tasks": 25,
  113. "completion_percentage": 45.0,
  114. "annotators": [
  115. {
  116. "user_id": "user_001",
  117. "username": "annotator1",
  118. "assigned_count": 50,
  119. "completed_count": 25,
  120. "in_progress_count": 15,
  121. "completion_rate": 50.0
  122. }
  123. ],
  124. "last_updated": "2026-02-03T15:30:00Z"
  125. }
  126. }
  127. # ============== 数据导出相关 ==============
  128. class ExternalExportRequest(BaseModel):
  129. """导出请求"""
  130. format: ExternalExportFormat = Field(
  131. default=ExternalExportFormat.JSON,
  132. description="导出格式"
  133. )
  134. completed_only: bool = Field(
  135. default=True,
  136. description="是否只导出已完成的任务"
  137. )
  138. callback_url: Optional[str] = Field(
  139. None,
  140. description="回调URL,导出完成后通知样本中心"
  141. )
  142. class Config:
  143. json_schema_extra = {
  144. "example": {
  145. "format": "sharegpt",
  146. "completed_only": True,
  147. "callback_url": "https://sample-center.example.com/api/callback/export"
  148. }
  149. }
  150. class ExportedTaskData(BaseModel):
  151. """导出的任务数据"""
  152. task_id: str = Field(..., description="任务ID")
  153. external_id: Optional[str] = Field(None, description="外部系统的数据ID")
  154. original_data: dict = Field(..., description="原始数据")
  155. annotations: List[dict] = Field(default_factory=list, description="标注结果列表")
  156. status: str = Field(..., description="任务状态")
  157. annotator: Optional[str] = Field(None, description="标注人员")
  158. completed_at: Optional[datetime] = Field(None, description="完成时间")
  159. class ExternalExportResponse(BaseModel):
  160. """导出响应"""
  161. project_id: str = Field(..., description="项目ID")
  162. format: str = Field(..., description="导出格式")
  163. total_exported: int = Field(..., description="导出的任务数量")
  164. file_url: str = Field(..., description="文件下载URL")
  165. file_name: str = Field(..., description="文件名")
  166. file_size: Optional[int] = Field(None, description="文件大小(字节)")
  167. expires_at: Optional[datetime] = Field(None, description="下载链接过期时间")
  168. class Config:
  169. json_schema_extra = {
  170. "example": {
  171. "project_id": "proj_abc123def456",
  172. "format": "sharegpt",
  173. "total_exported": 45,
  174. "file_url": "/api/exports/export_789/download",
  175. "file_name": "export_proj_abc123_sharegpt_20260203.json",
  176. "file_size": 1024000,
  177. "expires_at": "2026-02-10T10:30:00Z"
  178. }
  179. }
  180. class ExportCallbackPayload(BaseModel):
  181. """导出完成回调载荷"""
  182. project_id: str = Field(..., description="项目ID")
  183. export_id: str = Field(..., description="导出任务ID")
  184. status: str = Field(..., description="状态:completed 或 failed")
  185. format: str = Field(..., description="导出格式")
  186. total_exported: int = Field(..., description="导出的任务数量")
  187. file_url: str = Field(..., description="文件下载URL(完整URL)")
  188. file_name: str = Field(..., description="文件名")
  189. file_size: int = Field(..., description="文件大小(字节)")
  190. error_message: Optional[str] = Field(None, description="错误信息(失败时)")
  191. # ============== 错误响应 ==============
  192. class ErrorResponse(BaseModel):
  193. """统一错误响应格式"""
  194. error_code: str = Field(..., description="错误码")
  195. message: str = Field(..., description="错误信息")
  196. details: Optional[dict] = Field(None, description="详细信息")
  197. class Config:
  198. json_schema_extra = {
  199. "example": {
  200. "error_code": "PROJECT_NOT_FOUND",
  201. "message": "项目不存在",
  202. "details": {"project_id": "proj_invalid"}
  203. }
  204. }