from datetime import date, datetime from typing import Literal, Optional from pydantic import BaseModel, Field class KeywordBase(BaseModel): city: str = Field(..., max_length=64, description="城市") job: str = Field(..., max_length=128, description="职位关键词") class KeywordCreate(KeywordBase): pass class KeywordUpdate(BaseModel): city: Optional[str] = Field(None, max_length=64, description="城市") job: Optional[str] = Field(None, max_length=128, description="职位关键词") class KeywordOut(KeywordBase): id: int last_requested_date: Optional[date] = None last_requested_at: Optional[datetime] = None crawl_status: str = "idle" last_completed_page: int = 0 total_pages: int = 0 jobs_found: int = 0 retry_count: int = 0 created_at: datetime updated_at: datetime class Config: from_attributes = True class PageProgressRequest(BaseModel): source: str = Field(..., pattern="^(boss|qcwy|zhilian)$") keyword_id: int page: int = Field(..., ge=1) total_pages: int = Field(0, ge=0) jobs_found: int = Field(0, ge=0) class CrawlCompleteRequest(BaseModel): source: str = Field(..., pattern="^(boss|qcwy|zhilian)$") keyword_id: int status: Literal["completed", "failed"] error_message: str = ""