Files
srbhr--resume-matcher/apps/backend/app/schemas/refinement.py
T
wehub-resource-sync 5bdf4cc89a
Publish Docker Image / publish (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:36 +08:00

126 lines
4.4 KiB
Python

"""Pydantic models for multi-pass resume refinement."""
from pydantic import BaseModel, Field
class RefinementConfig(BaseModel):
"""Configuration for refinement passes."""
enable_keyword_injection: bool = True
enable_ai_phrase_removal: bool = True
enable_master_alignment_check: bool = True
max_refinement_passes: int = Field(default=2, ge=1, le=5)
class KeywordGapAnalysis(BaseModel):
"""Result of keyword gap analysis."""
missing_keywords: list[str] = Field(default_factory=list)
injectable_keywords: list[str] = Field(
default_factory=list,
description="Missing keywords that exist in master resume (safe to add)",
)
non_injectable_keywords: list[str] = Field(
default_factory=list,
description="Missing keywords not in master resume (cannot add truthfully)",
)
current_match_percentage: float = Field(
default=0.0, ge=0.0, le=100.0, description="Current keyword match percentage"
)
potential_match_percentage: float = Field(
default=0.0,
ge=0.0,
le=100.0,
description="Potential match if injectable keywords are added",
)
class AlignmentViolation(BaseModel):
"""Single alignment violation between tailored and master resume."""
field_path: str = Field(description="Path to the violated field in resume data")
violation_type: str = Field(
description="Type: fabricated_skill, skill_variant, fabricated_cert, fabricated_company, invented_content"
)
value: str = Field(description="The violating value")
severity: str = Field(
default="warning", description="Severity: critical, warning, or info"
)
class AlignmentReport(BaseModel):
"""Master resume alignment validation result."""
is_aligned: bool = Field(
default=True, description="True if no critical violations found"
)
violations: list[AlignmentViolation] = Field(default_factory=list)
confidence_score: float = Field(
default=1.0,
ge=0.0,
le=1.0,
description="Alignment confidence (1.0 = perfect alignment)",
)
class RefinementStats(BaseModel):
"""Statistics from the refinement process for API responses."""
passes_completed: int = Field(default=0, ge=0, description="Number of passes run")
keywords_injected: int = Field(
default=0, ge=0, description="Number of keywords injected"
)
ai_phrases_removed: list[str] = Field(
default_factory=list, description="List of AI phrases that were removed"
)
alignment_violations_fixed: int = Field(
default=0, ge=0, description="Number of alignment violations corrected"
)
initial_match_percentage: float = Field(
default=0.0,
ge=0.0,
le=100.0,
description="Keyword match before refinement",
)
final_match_percentage: float = Field(
default=0.0, ge=0.0, le=100.0, description="Keyword match after refinement"
)
class RefinementResult(BaseModel):
"""Complete result from the refinement process."""
refined_data: dict = Field(
default_factory=dict, description="The refined resume data"
)
passes_completed: int = Field(default=0, ge=0)
keyword_analysis: KeywordGapAnalysis | None = None
alignment_report: AlignmentReport | None = None
ai_phrases_removed: list[str] = Field(default_factory=list)
final_match_percentage: float = Field(default=0.0, ge=0.0, le=100.0)
def to_stats(self, initial_match: float = 0.0) -> RefinementStats:
"""Convert to RefinementStats for API response."""
return RefinementStats(
passes_completed=self.passes_completed,
keywords_injected=(
len(self.keyword_analysis.injectable_keywords)
if self.keyword_analysis and self.keyword_analysis.injectable_keywords
else 0
),
ai_phrases_removed=self.ai_phrases_removed,
alignment_violations_fixed=(
len(
[
v
for v in self.alignment_report.violations
if v.severity == "critical"
]
)
if self.alignment_report and self.alignment_report.violations
else 0
),
initial_match_percentage=initial_match,
final_match_percentage=self.final_match_percentage,
)