import argparse from pathlib import Path from .io_utils import read_job_description from .preprocess import ( load_candidates, normalize_candidates, prefilter_raw_active_candidates, prefilter_raw_role_candidates, ) from .retrieval import retrieve_top_k, save_processed from .scoring import rank_candidates, save_submission def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="Rank candidates for a job description.") parser.add_argument("--candidates", required=True, help="Path to candidates CSV/JSON/JSONL file.") parser.add_argument("--job", required=True, help="Path to job description text file.") parser.add_argument("--output", default="outputs/ranked_candidates.csv", help="Output CSV path.") parser.add_argument( "--processed-output", default=None, help="Optional path for normalized candidate profiles. If omitted, raw candidates are not written.", ) parser.add_argument( "--retrieved-output", default="outputs/retrieved_top_1000.csv", help="Where to save the retrieved top-k candidate pool before final ranking.", ) parser.add_argument("--top-k", type=int, default=1000, help="Candidates to retrieve semantically.") parser.add_argument( "--tfidf-prefilter-k", type=int, default=3000, help="Candidates to keep after fast raw HashingVectorizer prefilter before normalization.", ) return parser.parse_args() def main() -> None: args = parse_args() job_description = read_job_description(args.job) raw = load_candidates(args.candidates) raw = prefilter_raw_active_candidates(raw) raw = prefilter_raw_role_candidates(raw, job_description, top_n=args.tfidf_prefilter_k) candidates = normalize_candidates(raw) if args.processed_output: save_processed(candidates, args.processed_output) retrieved = retrieve_top_k( candidates, job_description, top_k=args.top_k, tfidf_prefilter_k=None, ) retrieved_output_path = Path(args.retrieved_output) retrieved_output_path.parent.mkdir(parents=True, exist_ok=True) retrieved.to_csv(retrieved_output_path, index=False, encoding="utf-8") print(f"Saved retrieved top {len(retrieved)} candidates to {retrieved_output_path}") ranked = rank_candidates(retrieved, job_description) output_path = Path(args.output) save_submission(ranked, str(output_path), top_n=100) print(f"Saved ranked candidates to {output_path}") if __name__ == "__main__": main()