Mohit0708's picture
Configure Hugging Face Space
f899b0a
Raw
History Blame Contribute Delete
29.1 kB
#!/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,
)