|
|
from pathlib import Path |
|
|
from langchain_core.tools import tool |
|
|
|
|
|
|
|
|
from src.backend.agents.cv_screening.cv_screener import screen_cv |
|
|
from src.backend.agents.cv_screening.utils import read_file |
|
|
from src.backend.database.candidates import ( |
|
|
write_cv_results_to_db, |
|
|
get_candidate_by_name, |
|
|
) |
|
|
|
|
|
@tool |
|
|
def cv_screening_workflow(candidate_full_name: str = "") -> str: |
|
|
""" |
|
|
Runs the deterministic CV screening workflow for a candidate. |
|
|
This is a fixed sequential process, not a reasoning agent. |
|
|
|
|
|
Steps: |
|
|
1. Retrieve candidate info from DB |
|
|
2. Read files (CV & Job Description) |
|
|
3. Evaluate CV |
|
|
4. Store results in DB & update status |
|
|
|
|
|
Args: |
|
|
candidate_full_name (str): The full name of the candidate to screen. |
|
|
|
|
|
Returns: |
|
|
str: A message indicating the outcome of the workflow. (β
or β) |
|
|
""" |
|
|
if not candidate_full_name: |
|
|
return "β Candidate name is required." |
|
|
|
|
|
|
|
|
print(f"π Looking up candidate: {candidate_full_name}") |
|
|
candidate = get_candidate_by_name(candidate_full_name) |
|
|
|
|
|
if not candidate: |
|
|
return f"β Candidate '{candidate_full_name}' not found in database." |
|
|
|
|
|
candidate_email = candidate["email"] |
|
|
cv_path_str = candidate["parsed_cv_file_path"] |
|
|
|
|
|
if not cv_path_str: |
|
|
return f"β No parsed CV path recorded for '{candidate_full_name}'." |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
root_dir = Path(__file__).resolve().parents[4] |
|
|
|
|
|
cv_path = root_dir / cv_path_str |
|
|
if not cv_path.exists(): |
|
|
|
|
|
cv_path = Path(cv_path_str) |
|
|
if not cv_path.exists(): |
|
|
|
|
|
legacy_path = root_dir / "src/database/cvs/parsed" / Path(cv_path_str).name |
|
|
if legacy_path.exists(): |
|
|
cv_path = legacy_path |
|
|
else: |
|
|
return f"β CV file not found at: {cv_path_str} or {legacy_path}" |
|
|
|
|
|
|
|
|
jd_path = root_dir / "src/backend/database/job_postings/ai_engineer.txt" |
|
|
|
|
|
if not jd_path.exists(): |
|
|
return f"β Job description not found at: {jd_path}" |
|
|
|
|
|
|
|
|
print(f"π Reading Job Description from: {jd_path}") |
|
|
jd_text = read_file(jd_path) |
|
|
|
|
|
print(f"π Reading CV from: {cv_path}") |
|
|
cv_text = read_file(cv_path) |
|
|
|
|
|
|
|
|
|
|
|
print("π§ Running LLM screening...") |
|
|
try: |
|
|
result = screen_cv(cv_text, jd_text) |
|
|
except Exception as e: |
|
|
return f"β Error during LLM screening: {str(e)}" |
|
|
|
|
|
|
|
|
print("πΎ Saving results to database...") |
|
|
try: |
|
|
write_cv_results_to_db( |
|
|
candidate_email=candidate_email, |
|
|
result=result, |
|
|
job_title="AI Engineer" |
|
|
) |
|
|
except Exception as e: |
|
|
return f"β Error saving results to DB: {str(e)}" |
|
|
|
|
|
return f"β
CV Screening Workflow completed successfully for {candidate_full_name}. Scores and feedback have been saved to the database." |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
|
|
|
|
|
import sys |
|
|
name = sys.argv[1] if len(sys.argv) > 1 else "Ada Lovelace" |
|
|
cv_screening_workflow(name) |
|
|
|