owenkaplinsky's picture
update from github stable code (#3)
3370983 verified
"""
Database Query Schemas.
Flexible schemas for querying any table in the recruitment database.
"""
from datetime import datetime
from typing import Any, Optional
from uuid import UUID
from enum import Enum
from pydantic import BaseModel, Field
# ==================================================================================
# ENUMS
# ==================================================================================
class TableName(str, Enum):
"""Available tables for querying."""
candidates = "candidates"
cv_screening_results = "cv_screening_results"
voice_screening_results = "voice_screening_results"
interview_scheduling = "interview_scheduling"
final_decision = "final_decision"
class SortOrder(str, Enum):
"""Sort order options."""
asc = "asc"
desc = "desc"
# ==================================================================================
# REQUEST SCHEMAS
# ==================================================================================
class QueryRequest(BaseModel):
"""Flexible query request for any table."""
table: TableName = Field(..., description="Table to query")
# Filtering
filters: Optional[dict[str, Any]] = Field(
default=None,
description="Key-value filters (e.g., {'email': 'john@example.com', 'status': 'applied'})"
)
# Field selection
fields: Optional[list[str]] = Field(
default=None,
description="Specific fields to return. If None, returns all fields."
)
# Include related data
include_relations: Optional[bool] = Field(
default=False,
description="Include related tables (only for candidates table)"
)
# Pagination
limit: Optional[int] = Field(default=100, ge=1, le=1000, description="Max records to return")
offset: Optional[int] = Field(default=0, ge=0, description="Number of records to skip")
# Sorting
sort_by: Optional[str] = Field(default=None, description="Field to sort by")
sort_order: SortOrder = Field(default=SortOrder.desc, description="Sort order")
model_config = {
"json_schema_extra": {
"examples": [
{
"table": "candidates",
"filters": {"status": "applied"},
"fields": ["id", "full_name", "email", "status"],
"limit": 10
},
{
"table": "cv_screening_results",
"filters": {"overall_fit_score": {"$gte": 0.8}},
"sort_by": "overall_fit_score",
"sort_order": "desc"
}
]
}
}
# ==================================================================================
# RESPONSE SCHEMAS
# ==================================================================================
class CandidateResponse(BaseModel):
"""Candidate data response."""
id: UUID
full_name: str
email: str
phone_number: Optional[str] = None
cv_file_path: Optional[str] = None
parsed_cv_file_path: Optional[str] = None
status: str
created_at: datetime
updated_at: datetime
# Related data (populated when include_relations=True)
cv_screening_results: Optional[list[dict[str, Any]]] = None
voice_screening_results: Optional[list[dict[str, Any]]] = None
interview_scheduling: Optional[list[dict[str, Any]]] = None
final_decision: Optional[dict[str, Any]] = None
model_config = {"from_attributes": True}
class CVScreeningResponse(BaseModel):
"""CV Screening result response."""
id: UUID
candidate_id: UUID
job_title: Optional[str] = None
skills_match_score: Optional[float] = None
experience_match_score: Optional[float] = None
education_match_score: Optional[float] = None
overall_fit_score: Optional[float] = None
llm_feedback: Optional[str] = None
reasoning_trace: Optional[dict[str, Any]] = None
timestamp: datetime
model_config = {"from_attributes": True}
class VoiceScreeningResponse(BaseModel):
"""Voice Screening result response."""
id: UUID
candidate_id: UUID
call_sid: Optional[str] = None
transcript_text: Optional[str] = None
sentiment_score: Optional[float] = None
confidence_score: Optional[float] = None
communication_score: Optional[float] = None
llm_summary: Optional[str] = None
llm_judgment_json: Optional[dict[str, Any]] = None
audio_url: Optional[str] = None
timestamp: datetime
model_config = {"from_attributes": True}
class InterviewSchedulingResponse(BaseModel):
"""Interview scheduling response."""
id: UUID
candidate_id: UUID
calendar_event_id: Optional[str] = None
event_summary: Optional[str] = None
start_time: Optional[datetime] = None
end_time: Optional[datetime] = None
status: Optional[str] = None
timestamp: datetime
model_config = {"from_attributes": True}
class FinalDecisionResponse(BaseModel):
"""Final decision response."""
id: UUID
candidate_id: UUID
overall_score: Optional[float] = None
decision: Optional[str] = None
llm_rationale: Optional[str] = None
human_notes: Optional[str] = None
timestamp: datetime
model_config = {"from_attributes": True}
class QueryResponse(BaseModel):
"""Generic query response wrapper."""
success: bool
table: str
total_count: int
returned_count: int
offset: int
data: list[dict[str, Any]]
message: Optional[str] = None
class SingleRecordResponse(BaseModel):
"""Single record response."""
success: bool
table: str
data: Optional[dict[str, Any]] = None
message: Optional[str] = None