HR-ATS-Portal/backend/agent/decorators.py

73 lines
2.1 KiB
Python

"""Agent response parsers and input normalizers.
Pure module: no FastAPI imports, no HTTPException, and no module-level state.
Mirrors job/candidate/decorators.py — helpers that clean/shape data before or
after the graph nodes run.
"""
from __future__ import annotations
import uuid
def normalize_job_posts(job_posts) -> list[dict]:
if not job_posts:
return []
normalized=[]
for item in job_posts:
if not isinstance(item,dict):
continue
job_id=item.get("id")
if job_id is None:
continue
normalized.append({
"id":str(job_id),
"title":item.get("title") or "",
"description":item.get("description") or "",
"post_text":item.get("post_text") or "",
"requirements":item.get("requirements") or [],
"optional_skills":item.get("optional_skills") or [],
"location":item.get("location") or "",
"employment_type":item.get("employment_type") or "",
})
return normalized
def parse_match_response(data,allowed_ids) -> tuple[list[str],str,str,str]:
if not isinstance(data,dict):
raise RuntimeError(f"model did not return a JSON object: {data!r}")
allowed=set(allowed_ids or [])
raw_ids=data.get("suggested_job_post_ids") or []
if not isinstance(raw_ids,list):
raw_ids=[]
suggested=[]
seen=set()
for raw_id in raw_ids:
job_id=str(raw_id).strip()
if not job_id or job_id not in allowed or job_id in seen:
continue
try:
uuid.UUID(job_id)
except ValueError:
continue
seen.add(job_id)
suggested.append(job_id)
summary=data.get("summary")
if not isinstance(summary,str):
summary=""
reasoning=data.get("reasoning")
if isinstance(reasoning,list):
reasoning="\n".join(str(item) for item in reasoning)
if not isinstance(reasoning,str):
reasoning=""
experience=data.get("experience")
if not isinstance(experience,str):
experience=""
return suggested,summary.strip(),reasoning.strip(),experience.strip()