Spaces:
Runtime error
Runtime error
| #!/usr/bin/env python3 | |
| """ | |
| app.py β Gradio Sandbox for V7 Elite Ranker | |
| HuggingFace Spaces compatible. Upload β€100 candidates β get ranked CSV. | |
| """ | |
| import json | |
| import csv | |
| import sys | |
| import time | |
| import tempfile | |
| import traceback | |
| from pathlib import Path | |
| from io import StringIO | |
| import numpy as np | |
| import pandas as pd | |
| import gradio as gr | |
| # Ensure lib/ is importable | |
| sys.path.insert(0, str(Path(__file__).resolve().parent)) | |
| from lib import schema, features, honeypot, embeddings as emb_mod, scoring, reasoning | |
| from lib.jd_parser import get_jd | |
| from lib.hiring_intent import get_intent | |
| from lib.query_expansion import get_expanded_text | |
| from precompute import extract_features_v7 | |
| TOP_N = 100 | |
| # ββ Built-in 10-candidate sample for quick demo ββββββββββββββββββββββββββ | |
| SAMPLE_CANDIDATES = [ | |
| { | |
| "candidate_id": "CAND_0001001", | |
| "profile": { | |
| "anonymized_name": "Demo Elite", "headline": "Senior AI Engineer | RAG, Vector Search, Ranking", | |
| "summary": "8 years building production search and ranking systems. Led the recommendation engine at Razorpay serving 50M+ users. Deep expertise in embeddings, hybrid retrieval, and LLM fine-tuning. Shipped end-to-end systems from data pipeline to production API.", | |
| "location": "Bangalore", "country": "India", "years_of_experience": 8.2, | |
| "current_title": "Lead AI Engineer", "current_company": "Razorpay", | |
| "current_company_size": "1001-5000", "current_industry": "Fintech", | |
| "notice_period_days": 15, "open_to_relocation": True, | |
| "expected_salary_range_inr_lpa": {"min": 55, "max": 75}, | |
| "recruiter_response_rate": 0.85, "days_since_last_active": 2, | |
| "platform_trust_score": 0.9, "interview_completion_rate": 0.8, | |
| }, | |
| "career_history": [ | |
| {"company": "Razorpay", "title": "Lead AI Engineer", "start_date": "2022-03-01", "end_date": None, | |
| "duration_months": 38, "is_current": True, "industry": "Fintech", "company_size": "1001-5000", | |
| "description": "Built and owned the hybrid vector search ranking system serving 50M+ users. Designed the two-tower retrieval pipeline with FAISS, implemented learning-to-rank with XGBoost, and fine-tuned BGE embeddings for domain-specific retrieval. Reduced search latency by 40% while improving NDCG@10 by 15%. Managed a team of 3 engineers."}, | |
| {"company": "Amazon", "title": "SDE II", "start_date": "2018-06-01", "end_date": "2022-02-28", | |
| "duration_months": 45, "is_current": False, "industry": "E-commerce", "company_size": "10001+", | |
| "description": "Worked on A9 product search ranking. Implemented query understanding features and built the candidate generation pipeline for product search. Used Word2Vec embeddings for product similarity and improved search relevance metrics."}, | |
| {"company": "Flipkart", "title": "SDE I", "start_date": "2016-07-01", "end_date": "2018-05-31", | |
| "duration_months": 23, "is_current": False, "industry": "E-commerce", "company_size": "10001+", | |
| "description": "Built data pipelines for the recommendation system. Worked on collaborative filtering and content-based recommendation algorithms using Python and Spark."} | |
| ], | |
| "education": [{"institution": "IIT Bombay", "degree": "B.Tech", "field_of_study": "Computer Science", | |
| "start_year": 2012, "end_year": 2016, "grade": "9.1 CGPA", "tier": "tier_1"}], | |
| "skills": [{"name": "Python", "proficiency": "expert", "duration_months": 96}, | |
| {"name": "Machine Learning", "proficiency": "expert", "duration_months": 84}, | |
| {"name": "Vector Search", "proficiency": "advanced", "duration_months": 42}, | |
| {"name": "RAG", "proficiency": "advanced", "duration_months": 30}, | |
| {"name": "Embeddings", "proficiency": "expert", "duration_months": 60}, | |
| {"name": "FAISS", "proficiency": "advanced", "duration_months": 36}, | |
| {"name": "XGBoost", "proficiency": "advanced", "duration_months": 72}, | |
| {"name": "LLM Fine-tuning", "proficiency": "advanced", "duration_months": 24}], | |
| "assessments": [{"name": "ML System Design", "score": 92, "completed": True}], | |
| "endorsements_count": 28, "github_profile": {"has_public_repos": True, "public_repo_count": 12, "stargazers_total": 450} | |
| }, | |
| { | |
| "candidate_id": "CAND_0001002", | |
| "profile": { | |
| "anonymized_name": "LangChain Tourist", "headline": "AI Developer | LangChain, OpenAI, ChatGPT", | |
| "summary": "Recently transitioned to AI development. Built multiple LangChain prototypes and RAG chatbots using OpenAI APIs. Passionate about generative AI.", | |
| "location": "Mumbai", "country": "India", "years_of_experience": 4.5, | |
| "current_title": "AI Developer", "current_company": "TCS", | |
| "current_company_size": "10001+", "current_industry": "IT Services", | |
| "notice_period_days": 90, "open_to_relocation": False, | |
| "expected_salary_range_inr_lpa": {"min": 25, "max": 40}, | |
| "recruiter_response_rate": 0.15, "days_since_last_active": 180, | |
| "platform_trust_score": 0.4, "interview_completion_rate": 0.0, | |
| }, | |
| "career_history": [ | |
| {"company": "TCS", "title": "AI Developer", "start_date": "2024-01-01", "end_date": None, | |
| "duration_months": 18, "is_current": True, "industry": "IT Services", "company_size": "10001+", | |
| "description": "Building RAG chatbots using LangChain and OpenAI APIs for internal clients. Created a proof-of-concept document Q&A system using GPT-4 and Pinecone."}, | |
| {"company": "Infosys", "title": "Software Engineer", "start_date": "2021-07-01", "end_date": "2023-12-31", | |
| "duration_months": 30, "is_current": False, "industry": "IT Services", "company_size": "10001+", | |
| "description": "Java backend development for enterprise clients. Built REST APIs and maintained legacy systems."} | |
| ], | |
| "education": [{"institution": "VTU", "degree": "B.E.", "field_of_study": "Information Science", | |
| "start_year": 2017, "end_year": 2021, "grade": "7.2 CGPA", "tier": "tier_3"}], | |
| "skills": [{"name": "Python", "proficiency": "intermediate", "duration_months": 42}, | |
| {"name": "LangChain", "proficiency": "advanced", "duration_months": 14}, | |
| {"name": "OpenAI API", "proficiency": "advanced", "duration_months": 14}, | |
| {"name": "RAG", "proficiency": "intermediate", "duration_months": 10}, | |
| {"name": "Pinecone", "proficiency": "intermediate", "duration_months": 8}], | |
| "endorsements_count": 3, "github_profile": {"has_public_repos": False, "public_repo_count": 0, "stargazers_total": 0} | |
| }, | |
| { | |
| "candidate_id": "CAND_0001003", | |
| "profile": { | |
| "anonymized_name": "HR Manager Trap", "headline": "HR Manager | Recruitment, Talent Acquisition", | |
| "summary": "Experienced HR manager with 12 years in talent acquisition and recruitment. Recently completed a Coursera course on AI.", | |
| "location": "Delhi", "country": "India", "years_of_experience": 12.0, | |
| "current_title": "HR Manager", "current_company": "Wipro", | |
| "current_company_size": "10001+", "current_industry": "IT Services", | |
| "notice_period_days": 60, "open_to_relocation": False, | |
| "expected_salary_range_inr_lpa": {"min": 20, "max": 35}, | |
| "recruiter_response_rate": 0.9, "days_since_last_active": 1, | |
| "platform_trust_score": 0.8, "interview_completion_rate": 0.5, | |
| }, | |
| "career_history": [ | |
| {"company": "Wipro", "title": "HR Manager", "start_date": "2019-01-01", "end_date": None, | |
| "duration_months": 77, "is_current": True, "industry": "IT Services", "company_size": "10001+", | |
| "description": "Managing end-to-end recruitment for the AI/ML division. Hiring 50+ engineers per quarter. Completed Coursera AI for Everyone course."}, | |
| {"company": "Infosys", "title": "Talent Acquisition Lead", "start_date": "2014-01-01", "end_date": "2018-12-31", | |
| "duration_months": 60, "is_current": False, "industry": "IT Services", "company_size": "10001+", | |
| "description": "Led campus and lateral hiring for technology roles."} | |
| ], | |
| "education": [{"institution": "Delhi University", "degree": "MBA", "field_of_study": "HR", | |
| "start_year": 2012, "end_year": 2014, "grade": "7.5 CGPA", "tier": "tier_2"}], | |
| "skills": [{"name": "Recruitment", "proficiency": "expert", "duration_months": 144}, | |
| {"name": "Machine Learning", "proficiency": "beginner", "duration_months": 2}, | |
| {"name": "Python", "proficiency": "beginner", "duration_months": 3}], | |
| "endorsements_count": 45, "github_profile": {"has_public_repos": False, "public_repo_count": 0, "stargazers_total": 0} | |
| }, | |
| { | |
| "candidate_id": "CAND_0001004", | |
| "profile": { | |
| "anonymized_name": "Pre-LLM Veteran", "headline": "Staff ML Engineer | IR, Ranking, Recommendations", | |
| "summary": "10 years in information retrieval and ranking. Built search engines at Microsoft and recommendation systems at Netflix before the LLM era. Deep expertise in classic IR: BM25, learning-to-rank, two-tower models, approximate nearest neighbor search.", | |
| "location": "Pune", "country": "India", "years_of_experience": 10.5, | |
| "current_title": "Staff ML Engineer", "current_company": "Sarvam AI", | |
| "current_company_size": "51-200", "current_industry": "AI/ML", | |
| "notice_period_days": 20, "open_to_relocation": True, | |
| "expected_salary_range_inr_lpa": {"min": 60, "max": 85}, | |
| "recruiter_response_rate": 0.70, "days_since_last_active": 5, | |
| "platform_trust_score": 0.85, "interview_completion_rate": 0.75, | |
| }, | |
| "career_history": [ | |
| {"company": "Sarvam AI", "title": "Staff ML Engineer", "start_date": "2023-06-01", "end_date": None, | |
| "duration_months": 36, "is_current": True, "industry": "AI/ML", "company_size": "51-200", | |
| "description": "Leading the retrieval and ranking infrastructure for Indic language AI products. Built the hybrid retrieval pipeline combining sparse BM25 with dense BGE embeddings. Designed the evaluation framework with NDCG@10 and MRR metrics. Owns the entire ranking stack end-to-end."}, | |
| {"company": "Microsoft", "title": "Senior SDE", "start_date": "2018-04-01", "end_date": "2023-05-31", | |
| "duration_months": 62, "is_current": False, "industry": "Technology", "company_size": "10001+", | |
| "description": "Core contributor to Bing's document ranking pipeline. Implemented learning-to-rank features using LambdaMART. Built the query understanding module using transformer-based re-ranking. Optimized serving latency for 100+ billion document index."}, | |
| {"company": "Netflix", "title": "ML Engineer", "start_date": "2015-01-01", "end_date": "2018-03-31", | |
| "duration_months": 39, "is_current": False, "industry": "Entertainment", "company_size": "10001+", | |
| "description": "Built the recommendation ranking model for the home page. Worked on collaborative filtering, content-based filtering, and hybrid approaches. Improved click-through rate by 12% through better candidate generation and re-ranking."} | |
| ], | |
| "education": [{"institution": "IIT Delhi", "degree": "M.Tech", "field_of_study": "Computer Science", | |
| "start_year": 2013, "end_year": 2015, "grade": "9.4 CGPA", "tier": "tier_1"}], | |
| "skills": [{"name": "Python", "proficiency": "expert", "duration_months": 126}, | |
| {"name": "Machine Learning", "proficiency": "expert", "duration_months": 120}, | |
| {"name": "Information Retrieval", "proficiency": "expert", "duration_months": 120}, | |
| {"name": "Learning to Rank", "proficiency": "expert", "duration_months": 84}, | |
| {"name": "Vector Search", "proficiency": "expert", "duration_months": 48}, | |
| {"name": "Embeddings", "proficiency": "expert", "duration_months": 72}, | |
| {"name": "FAISS", "proficiency": "advanced", "duration_months": 36}, | |
| {"name": "BM25", "proficiency": "expert", "duration_months": 96}], | |
| "assessments": [{"name": "System Design", "score": 88, "completed": True}], | |
| "endorsements_count": 52, "github_profile": {"has_public_repos": True, "public_repo_count": 18, "stargazers_total": 1200} | |
| }, | |
| { | |
| "candidate_id": "CAND_0001005", | |
| "profile": { | |
| "anonymized_name": "Graphic Designer", "headline": "Senior Graphic Designer | Adobe, Figma, AI Art", | |
| "summary": "Creative professional with 7 years in graphic design. Recently started using Midjourney and DALL-E for AI art generation. Interested in AI roles.", | |
| "location": "Hyderabad", "country": "India", "years_of_experience": 7.0, | |
| "current_title": "Senior Graphic Designer", "current_company": "Accenture", | |
| "current_company_size": "10001+", "current_industry": "IT Services", | |
| "notice_period_days": 45, "open_to_relocation": False, | |
| "expected_salary_range_inr_lpa": {"min": 15, "max": 25}, | |
| "recruiter_response_rate": 0.50, "days_since_last_active": 30, | |
| "platform_trust_score": 0.6, "interview_completion_rate": 0.3, | |
| }, | |
| "career_history": [ | |
| {"company": "Accenture", "title": "Senior Graphic Designer", "start_date": "2021-01-01", "end_date": None, | |
| "duration_months": 53, "is_current": True, "industry": "IT Services", "company_size": "10001+", | |
| "description": "Leading design projects for Fortune 500 clients. Using AI tools like Midjourney and DALL-E for rapid prototyping."}, | |
| {"company": "Ogilvy", "title": "Graphic Designer", "start_date": "2018-06-01", "end_date": "2020-12-31", | |
| "duration_months": 31, "is_current": False, "industry": "Advertising", "company_size": "10001+", | |
| "description": "Created visual campaigns for major brands."} | |
| ], | |
| "education": [{"institution": "NID", "degree": "B.Des", "field_of_study": "Graphic Design", | |
| "start_year": 2014, "end_year": 2018, "grade": "8.5 CGPA", "tier": "tier_1"}], | |
| "skills": [{"name": "Adobe Creative Suite", "proficiency": "expert", "duration_months": 84}, | |
| {"name": "Figma", "proficiency": "advanced", "duration_months": 48}, | |
| {"name": "Machine Learning", "proficiency": "beginner", "duration_months": 6}, | |
| {"name": "Python", "proficiency": "beginner", "duration_months": 8}], | |
| "endorsements_count": 35, "github_profile": {"has_public_repos": False, "public_repo_count": 0, "stargazers_total": 0} | |
| }, | |
| ] | |
| def load_candidates_from_upload(file_obj) -> list[dict]: | |
| """Load candidates from uploaded file (JSONL, JSON array, or .jsonl.gz).""" | |
| if file_obj is None: | |
| return [] | |
| path = Path(file_obj.name if hasattr(file_obj, "name") else str(file_obj)) | |
| suffix = path.suffix.lower() | |
| # JSON array format | |
| if suffix == ".json": | |
| with open(file_obj.name, "r", encoding="utf-8") as f: | |
| data = json.load(f) | |
| if isinstance(data, list): | |
| return data | |
| elif isinstance(data, dict): | |
| return [data] | |
| return [] | |
| # JSONL format | |
| candidates = [] | |
| import gzip | |
| if suffix == ".gz": | |
| opener = gzip.open | |
| else: | |
| opener = open | |
| with opener(file_obj.name, "rt", encoding="utf-8") as f: | |
| for line in f: | |
| line = line.strip() | |
| if not line or line.startswith("#") or line.startswith("candidate_id,"): | |
| continue | |
| try: | |
| candidates.append(json.loads(line)) | |
| except json.JSONDecodeError: | |
| continue | |
| return candidates | |
| def run_ranking(candidates: list[dict]) -> tuple[str, str, str, str]: | |
| """Run the full V7 pipeline on candidates. Returns (csv_text, stats, logs, csv_path).""" | |
| t0 = time.time() | |
| logs = [] | |
| if not candidates: | |
| return "", "No candidates loaded.", "", "" | |
| n = len(candidates) | |
| log = f"[sandbox] Loaded {n} candidates" | |
| logs.append(log) | |
| print(log) | |
| if n > 100: | |
| log = f"[sandbox] WARNING: {n} > 100 limit. Truncating to first 100." | |
| logs.append(log) | |
| print(log) | |
| candidates = candidates[:100] | |
| # ββ Step 1: Feature Extraction βββββββββββββββββββββββββββββββββββββ | |
| t1 = time.time() | |
| log = "[sandbox] Step 1/3: Extracting V7 features..." | |
| logs.append(log) | |
| print(log) | |
| rows = [] | |
| texts = [] | |
| for c in candidates: | |
| row = extract_features_v7(c) | |
| rows.append(row) | |
| texts.append(schema.unified_text_blob(c)) | |
| log = f"[sandbox] Extracted features for {len(rows)} candidates in {time.time()-t1:.1f}s" | |
| logs.append(log) | |
| print(log) | |
| # ββ Step 2: TF-IDF + SVD Embeddings ββββββββββββββββββββββββββββββββ | |
| t2 = time.time() | |
| log = "[sandbox] Step 2/3: Computing TF-IDF+SVD embeddings..." | |
| logs.append(log) | |
| print(log) | |
| jd = get_jd() | |
| expanded_ideal = get_expanded_text(jd.ideal_text) | |
| all_texts = texts + [expanded_ideal] | |
| n_components = min(100, len(all_texts) - 1) | |
| embedder = emb_mod.TfidfSvdEmbedder(n_components=max(n_components, 2)) | |
| embedder.fit(all_texts) | |
| doc_emb = embedder.transform(all_texts)[:len(texts)] | |
| sims = embedder.similarity_to_query(doc_emb, expanded_ideal) | |
| for row, sim in zip(rows, sims): | |
| row["embedding_sim"] = float(sim) | |
| df = pd.DataFrame(rows) | |
| log = f"[sandbox] Embeddings computed in {time.time()-t2:.1f}s ({len(df.columns)} features)" | |
| logs.append(log) | |
| print(log) | |
| # ββ Step 3: Scoring + Ranking ββββββββββββββββββββββββββββββββββββββ | |
| t3 = time.time() | |
| log = "[sandbox] Step 3/3: Scoring and ranking..." | |
| logs.append(log) | |
| print(log) | |
| # Print hiring intent | |
| try: | |
| intent = get_intent() | |
| log = (f"[sandbox] Hiring Intent: {intent.philosophy} | " | |
| f"ownership={intent.ownership_expectation:.2f} | " | |
| f"need={intent.primary_need} | team={intent.team_context}") | |
| logs.append(log) | |
| print(log) | |
| except Exception as e: | |
| log = f"[sandbox] Warning: hiring intent failed: {e}" | |
| logs.append(log) | |
| # Compute scores | |
| elite = scoring.elite_score_vec(df) | |
| final = scoring.final_score_vec(df) | |
| df = df.assign(elite_score=elite.values, raw_score=final.values) | |
| top_n = min(TOP_N, len(df)) | |
| top = df.sort_values("raw_score", ascending=False).head(top_n).copy() | |
| # Sigmoid stretch | |
| raw = top["raw_score"].values.astype(float) | |
| raw_min, raw_max = raw.min(), raw.max() | |
| if raw_max > raw_min: | |
| norm = (raw - raw_min) / (raw_max - raw_min) | |
| stretched = 1.0 / (1.0 + np.exp(-10.0 * (norm - 0.5))) | |
| final_scores = 0.52 + 0.47 * stretched | |
| else: | |
| final_scores = np.full(top_n, 0.75) | |
| top["score"] = final_scores | |
| top["score"] = top["score"].round(6) | |
| top = top.sort_values(["score", "candidate_id"], ascending=[False, True]).reset_index(drop=True) | |
| top["rank"] = top.index + 1 | |
| honeypots_in_top = int(top["is_honeypot"].sum()) | |
| scores = top["score"].values | |
| # Generate reasoning | |
| log = f"[sandbox] Generating reasoning for {top_n} candidates..." | |
| logs.append(log) | |
| print(log) | |
| t_reason = time.time() | |
| out_rows = [] | |
| for _, row in top.iterrows(): | |
| cid = row["candidate_id"] | |
| candidate = json.loads(row["_candidate_json"]) | |
| disq_reasons = json.loads(row["_disq_reasons"]) | |
| beh_evidence = json.loads(row["_behaviour_evidence"]) | |
| narrative_suspicious = json.loads(row.get("narrative_suspicious", "[]")) | |
| feat = { | |
| "current_title": row["current_title"], | |
| "current_company": row["current_company"], | |
| "years_of_experience": row["years_of_experience"], | |
| "skill_coverage": float(row.get("skill_coverage", 0)), | |
| "impact_magnitude": float(row.get("impact_magnitude", 0)), | |
| "ownership_hierarchy": float(row.get("ownership_hierarchy", 0)), | |
| "evaluation_experience": float(row.get("evaluation_experience", 0)), | |
| "pre_llm_months": float(row.get("pre_llm_months", 0)), | |
| "evidence_strength": float(row.get("evidence_strength", 0)), | |
| "notice_period_days": beh_evidence.get("notice_period_days", 45), | |
| "days_since_active": beh_evidence.get("days_since_active", 90), | |
| "recruiter_response_rate": beh_evidence.get("recruiter_response_rate", 0.3), | |
| "disqualifier_reasons": disq_reasons, | |
| "tier5_signature": float(row.get("tier5_signature", 0)), | |
| "behavioral_twin_penalty": float(row.get("behavioral_twin_penalty", 1.0)), | |
| "langchain_only_penalty": float(row.get("langchain_only_penalty", 1.0)), | |
| "closed_source_penalty": float(row.get("closed_source_penalty", 1.0)), | |
| "pre_llm_x_ownership": float(row.get("pre_llm_x_ownership", 0)), | |
| "salary_compatibility": float(row.get("salary_compatibility", 0.7)), | |
| "is_honeypot": bool(row.get("is_honeypot", False)), | |
| "assessment_signal": float(row.get("assessment_signal", 0.5)), | |
| "endorsement_signal": float(row.get("endorsement_signal", 0.5)), | |
| "education_tier": float(row.get("education_tier", 0.5)), | |
| "cross_validation": float(row.get("cross_validation", 0.5)), | |
| "_candidate_json": row.get("_candidate_json", "{}"), | |
| "_beh_twin_evidence": row.get("_beh_twin_evidence", "{}"), | |
| "_langchain_evidence": row.get("_langchain_evidence", "{}"), | |
| "_closed_source_evidence": row.get("_closed_source_evidence", "{}"), | |
| "_salary_evidence": row.get("_salary_evidence", "{}"), | |
| "_assessment_evidence": row.get("_assessment_evidence", "{}"), | |
| "_endorsement_evidence": row.get("_endorsement_evidence", "{}"), | |
| "_education_evidence": row.get("_education_evidence", "{}"), | |
| } | |
| text = reasoning.generate(cid, candidate, feat, narrative_suspicious) | |
| out_rows.append({ | |
| "candidate_id": cid, | |
| "rank": int(row["rank"]), | |
| "score": f'{row["score"]:.6f}', | |
| "reasoning": text, | |
| }) | |
| log = f"[sandbox] Reasoning generated in {time.time()-t_reason:.1f}s" | |
| logs.append(log) | |
| print(log) | |
| # Build CSV string | |
| csv_buf = StringIO() | |
| writer = csv.DictWriter(csv_buf, fieldnames=["candidate_id", "rank", "score", "reasoning"]) | |
| writer.writeheader() | |
| writer.writerows(out_rows) | |
| csv_text = csv_buf.getvalue() | |
| # Write temp file for download | |
| tmp_path = Path(tempfile.gettempdir()) / "sandbox_submission.csv" | |
| with open(tmp_path, "w", encoding="utf-8") as f: | |
| f.write(csv_text) | |
| # Stats | |
| total_time = time.time() - t0 | |
| unique_scores = len(set(scores)) | |
| non_mono = sum(1 for i in range(len(scores) - 1) if scores[i] < scores[i + 1]) | |
| honeypots_total = int(df["is_honeypot"].sum()) | |
| stats = ( | |
| f"**Pipeline Stats**\n\n" | |
| f"| Metric | Value |\n|---|---|\n" | |
| f"| Candidates input | {n} |\n" | |
| f"| Candidates ranked | {top_n} |\n" | |
| f"| Honeypots detected | {honeypots_total} / {n} |\n" | |
| f"| Honeypots in top {top_n} | {honeypots_in_top} |\n" | |
| f"| Score range | {scores[0]:.6f} β {scores[-1]:.6f} |\n" | |
| f"| Unique scores | {unique_scores} / {top_n} |\n" | |
| f"| Monotonicity violations | {non_mono} |\n" | |
| f"| Total time | {total_time:.1f}s |\n" | |
| f"| Under 5-min budget | {'β Yes' if total_time < 300 else 'β No'} |\n" | |
| ) | |
| top5_table = "| Rank | Candidate ID | Score | Title | Company |\n|---|---|---|---|---|\n" | |
| for _, row in top.head(5).iterrows(): | |
| top5_table += f"| {int(row['rank'])} | {row['candidate_id']} | {row['score']:.6f} | {row['current_title']} | {row['current_company']} |\n" | |
| stats += f"\n\n**Top 5 Candidates**\n\n{top5_table}" | |
| log = f"[sandbox] Total time: {total_time:.1f}s β CSV ready for download" | |
| logs.append(log) | |
| print(log) | |
| # Return pandas DataFrame for Gradio Dataframe component | |
| result_df = pd.DataFrame(out_rows) | |
| return result_df, stats, "\n".join(logs), str(tmp_path) | |
| def on_upload_and_rank(file_obj): | |
| """Handle file upload + rank button.""" | |
| if file_obj is None: | |
| return pd.DataFrame(columns=["candidate_id", "rank", "score", "reasoning"]), "", "", None | |
| try: | |
| candidates = load_candidates_from_upload(file_obj) | |
| if not candidates: | |
| return pd.DataFrame(columns=["candidate_id", "rank", "score", "reasoning"]), "No valid candidates found in file. Use JSONL (one JSON per line) or JSON array format.", "", None | |
| return run_ranking(candidates) | |
| except Exception as e: | |
| tb = traceback.format_exc() | |
| return pd.DataFrame(columns=["candidate_id", "rank", "score", "reasoning"]), f"ERROR: {e}\n\n{tb}", "", None | |
| def on_demo_rank(): | |
| """Run with built-in 5-candidate demo set.""" | |
| return run_ranking(SAMPLE_CANDIDATES) | |
| # ββ Gradio UI βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| with gr.Blocks( | |
| title="V7 Elite Ranker β Redrob Hackathon Sandbox", | |
| theme=gr.themes.Soft(), | |
| ) as demo: | |
| gr.Markdown( | |
| """ | |
| # V7 Elite Ranker β Hackathon Sandbox | |
| **Redrob AI Hackathon:** India Runs Data & AI Challenge | |
| **Role:** Senior AI Engineer β Founding Team | |
| Upload a candidate file (β€100 candidates) or use the built-in demo to see the ranking pipeline in action. | |
| The sandbox runs the **exact same code** that runs at Stage 3 reproduction. | |
| """ | |
| ) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("### Input") | |
| file_input = gr.File( | |
| label="Upload Candidates (.jsonl, .json, .jsonl.gz)", | |
| file_types=[".json", ".jsonl", ".gz"], | |
| ) | |
| gr.Markdown( | |
| """ | |
| **Accepted formats:** | |
| - `.jsonl` β one JSON object per line | |
| - `.json` β JSON array of candidate objects | |
| - `.jsonl.gz` β gzipped JSONL | |
| - Max **100 candidates** (sandbox limit) | |
| **Or click "Run Demo" to use 5 built-in test candidates** (1 elite, 1 LangChain tourist, 1 HR trap, 1 pre-LLM veteran, 1 graphic designer). | |
| """ | |
| ) | |
| with gr.Row(): | |
| btn_demo = gr.Button("Run Demo (5 Candidates)", variant="secondary") | |
| btn_run = gr.Button("Rank Uploaded File", variant="primary") | |
| gr.Markdown("### Logs") | |
| log_output = gr.Textbox(label="Pipeline Logs", lines=12, interactive=False, max_lines=20) | |
| with gr.Column(scale=2): | |
| gr.Markdown("### Output") | |
| stats_output = gr.Markdown(label="Stats") | |
| csv_output = gr.Dataframe( | |
| label="Ranked Candidates (submission.csv)", | |
| headers=["candidate_id", "rank", "score", "reasoning"], | |
| interactive=False, | |
| ) | |
| download_btn = gr.File( | |
| label="Download submission.csv", | |
| interactive=False, | |
| ) | |
| gr.Markdown( | |
| """ | |
| --- | |
| ### Pipeline Architecture | |
| ``` | |
| candidates.jsonl β Feature Extraction (55 features) β TF-IDF+SVD Embeddings | |
| β Intent-Aware Scoring (Impact 42% + Ownership 33% + Search 15% + Behaviour 10%) | |
| β 4 Additive Boosts β 5 Multiplicative Penalties β Honeypot Γ0.01 | |
| β 13-term Tiebreaker β Sigmoid Stretch β Evidence-Graph Reasoning | |
| β submission.csv | |
| ``` | |
| **Constraints met:** CPU-only | No network | <5 min | β€16 GB RAM | Deterministic | |
| """ | |
| ) | |
| # Wire up events | |
| btn_demo.click(fn=on_demo_rank, outputs=[csv_output, stats_output, log_output, download_btn]) | |
| btn_run.click(fn=on_upload_and_rank, inputs=[file_input], outputs=[csv_output, stats_output, log_output, download_btn]) | |
| if __name__ == "__main__": | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| ) |