172 lines
4.1 KiB
Python
172 lines
4.1 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from enum import Enum
|
|
|
|
from pydantic import BaseModel, Field, field_validator, model_validator
|
|
|
|
|
|
class SalaryType(str, Enum):
|
|
daily = "daily"
|
|
hourly = "hourly"
|
|
monthly = "monthly"
|
|
task = "task"
|
|
|
|
|
|
class SourceType(str, Enum):
|
|
job_to_worker = "job_to_worker"
|
|
worker_to_job = "worker_to_job"
|
|
|
|
|
|
class Salary(BaseModel):
|
|
type: SalaryType = SalaryType.daily
|
|
amount: float = 0
|
|
currency: str = "CNY"
|
|
|
|
|
|
class SkillScore(BaseModel):
|
|
name: str
|
|
score: float = Field(ge=0, le=1)
|
|
|
|
|
|
class JobCard(BaseModel):
|
|
job_id: str
|
|
title: str
|
|
category: str
|
|
description: str
|
|
skills: list[str] = Field(default_factory=list)
|
|
city: str
|
|
region: str
|
|
location_detail: str
|
|
start_time: datetime
|
|
duration_hours: float = Field(gt=0)
|
|
headcount: int = Field(gt=0)
|
|
salary: Salary
|
|
work_mode: str
|
|
tags: list[str] = Field(default_factory=list)
|
|
confidence: float = Field(ge=0, le=1)
|
|
|
|
|
|
class WorkerCard(BaseModel):
|
|
worker_id: str
|
|
name: str
|
|
description: str
|
|
skills: list[SkillScore] = Field(default_factory=list)
|
|
cities: list[str] = Field(default_factory=list)
|
|
regions: list[str] = Field(default_factory=list)
|
|
availability: list[str] = Field(default_factory=list)
|
|
experience_tags: list[str] = Field(default_factory=list)
|
|
reliability_score: float = Field(ge=0, le=1)
|
|
profile_completion: float = Field(ge=0, le=1)
|
|
confidence: float = Field(ge=0, le=1)
|
|
|
|
|
|
class MatchBreakdown(BaseModel):
|
|
skill_score: float = Field(ge=0, le=1)
|
|
region_score: float = Field(ge=0, le=1)
|
|
time_score: float = Field(ge=0, le=1)
|
|
experience_score: float = Field(ge=0, le=1)
|
|
reliability_score: float = Field(ge=0, le=1)
|
|
|
|
|
|
class MatchResult(BaseModel):
|
|
match_id: str
|
|
source_type: SourceType
|
|
source_id: str
|
|
target_id: str
|
|
match_score: float = Field(ge=0, le=1)
|
|
breakdown: MatchBreakdown
|
|
reasons: list[str] = Field(default_factory=list, min_length=3)
|
|
|
|
|
|
class ExtractTextRequest(BaseModel):
|
|
text: str = Field(min_length=5)
|
|
|
|
|
|
class IngestJobRequest(BaseModel):
|
|
job: JobCard
|
|
|
|
|
|
class IngestWorkerRequest(BaseModel):
|
|
worker: WorkerCard
|
|
|
|
|
|
class MatchWorkersRequest(BaseModel):
|
|
job_id: str | None = None
|
|
job: JobCard | None = None
|
|
top_n: int = Field(default=10, ge=1, le=50)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_source(self) -> "MatchWorkersRequest":
|
|
if not self.job_id and not self.job:
|
|
raise ValueError("job_id 或 job 至少需要提供一个")
|
|
return self
|
|
|
|
|
|
class MatchJobsRequest(BaseModel):
|
|
worker_id: str | None = None
|
|
worker: WorkerCard | None = None
|
|
top_n: int = Field(default=10, ge=1, le=50)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_source(self) -> "MatchJobsRequest":
|
|
if not self.worker_id and not self.worker:
|
|
raise ValueError("worker_id 或 worker 至少需要提供一个")
|
|
return self
|
|
|
|
|
|
class ExtractResponse(BaseModel):
|
|
success: bool
|
|
data: JobCard | WorkerCard | None = None
|
|
errors: list[str] = Field(default_factory=list)
|
|
missing_fields: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class BootstrapResponse(BaseModel):
|
|
jobs: int
|
|
workers: int
|
|
skills: int
|
|
categories: int
|
|
regions: int
|
|
|
|
|
|
class HealthStatus(BaseModel):
|
|
service: str
|
|
database: str
|
|
rag: str
|
|
timestamp: datetime
|
|
|
|
|
|
class ListResponse(BaseModel):
|
|
items: list[dict]
|
|
total: int
|
|
|
|
|
|
class MatchResponse(BaseModel):
|
|
items: list[MatchResult]
|
|
|
|
|
|
class ExplainResponse(BaseModel):
|
|
match: MatchResult
|
|
|
|
|
|
class PromptOutput(BaseModel):
|
|
content: dict
|
|
raw_text: str
|
|
|
|
|
|
class QueryFilters(BaseModel):
|
|
entity_type: str
|
|
city: str | None = None
|
|
region: str | None = None
|
|
categories: list[str] = Field(default_factory=list)
|
|
tags: list[str] = Field(default_factory=list)
|
|
skills: list[str] = Field(default_factory=list)
|
|
|
|
@field_validator("entity_type")
|
|
@classmethod
|
|
def validate_entity_type(cls, value: str) -> str:
|
|
if value not in {"job", "worker"}:
|
|
raise ValueError("entity_type must be job or worker")
|
|
return value
|