|
|
"""Pydantic schemas for API requests and responses.""" |
|
|
|
|
|
from typing import Literal |
|
|
|
|
|
from pydantic import BaseModel, Field |
|
|
|
|
|
|
|
|
class CasesResponse(BaseModel): |
|
|
"""Response for GET /api/cases.""" |
|
|
|
|
|
cases: list[str] |
|
|
|
|
|
|
|
|
class SegmentRequest(BaseModel): |
|
|
"""Request body for POST /api/segment.""" |
|
|
|
|
|
case_id: str |
|
|
fast_mode: bool = True |
|
|
|
|
|
|
|
|
class SegmentResponse(BaseModel): |
|
|
"""Segmentation result data (embedded in job response when completed).""" |
|
|
|
|
|
caseId: str |
|
|
diceScore: float | None |
|
|
volumeMl: float | None |
|
|
elapsedSeconds: float |
|
|
dwiUrl: str |
|
|
predictionUrl: str |
|
|
warning: str | None = Field( |
|
|
None, description="Warning message about result storage (e.g., ephemeral disk)" |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
JobStatusType = Literal["pending", "running", "completed", "failed"] |
|
|
|
|
|
|
|
|
class CreateJobResponse(BaseModel): |
|
|
"""Response for POST /api/segment (async job creation). |
|
|
|
|
|
Returns immediately with job ID. Client should poll GET /api/jobs/{jobId} |
|
|
for status updates and results. |
|
|
""" |
|
|
|
|
|
jobId: str = Field(..., description="Unique job identifier for polling") |
|
|
status: JobStatusType = Field(..., description="Initial job status (always 'pending')") |
|
|
message: str = Field(..., description="Human-readable status message") |
|
|
|
|
|
|
|
|
class JobStatusResponse(BaseModel): |
|
|
"""Response for GET /api/jobs/{job_id}. |
|
|
|
|
|
Provides current job status, progress, and results when completed. |
|
|
""" |
|
|
|
|
|
jobId: str = Field(..., description="Unique job identifier") |
|
|
status: JobStatusType = Field(..., description="Current job status") |
|
|
progress: int = Field(..., ge=0, le=100, description="Progress percentage (0-100)") |
|
|
progressMessage: str = Field(..., description="Human-readable progress status") |
|
|
elapsedSeconds: float | None = Field( |
|
|
None, description="Time elapsed since job started (seconds)" |
|
|
) |
|
|
result: SegmentResponse | None = Field( |
|
|
None, description="Segmentation results (only present when status='completed')" |
|
|
) |
|
|
error: str | None = Field(None, description="Error message (only present when status='failed')") |
|
|
|
|
|
|
|
|
class ErrorResponse(BaseModel): |
|
|
"""Standard error response body.""" |
|
|
|
|
|
detail: str = Field(..., description="Error description") |
|
|
|