# ============================================================ # app.py — TalentMatch AI on Hugging Face Spaces # This file runs the web interface using Gradio. # Hugging Face automatically runs this file when your Space loads. # ============================================================ import gradio as gr import pandas as pd from preprocess import full_preprocess from skill_extractor import extract_skills, skill_match_percentage from matcher import rank_candidates # ── Load and preprocess data when the app FIRST starts ────── # This runs ONCE when someone opens the Space — then it's ready. print("Loading dataset...") df = pd.read_csv("data/ats_resume_dataset_elite_v3.csv") print("Preprocessing all resumes (this takes ~30 seconds)...") df['cleaned_resume'] = df['resume_text'].apply(full_preprocess) print("TalentMatch AI is ready!") # ── The main function that Gradio calls ────────────────────── def screen_candidates(job_description, num_results): """ Takes a job description and returns the top matching candidates. This function is called every time someone clicks 'Submit'. """ # Handle empty input if not job_description.strip(): return pd.DataFrame({"Message": ["Please paste a job description in the box above."]}) # Extract skills from the job description job_skills = extract_skills(job_description) # Rank all candidates using TF-IDF + Cosine Similarity top_candidates = rank_candidates(df, job_description, top_n=int(num_results)) # Build a clean results table results = [] for rank, (_, row) in enumerate(top_candidates.iterrows(), start=1): resume_skills = extract_skills(str(row['resume_text'])) match_pct = skill_match_percentage(resume_skills, job_skills) results.append({ 'Rank' : rank, 'Resume ID' : row['resume_id'], 'Job Role' : row['job_role'], 'Experience' : f"{row['experience_years']} yrs", 'Education' : row['education_level'], 'ATS Score' : round(row['computed_similarity'], 3), 'Skill Match' : f"{int(match_pct * 100)}%", 'Shortlisted' : 'YES ✅' if row['shortlisted'] == 1 else 'NO', }) return pd.DataFrame(results) # ── Build the Gradio web interface ─────────────────────────── demo = gr.Interface( fn=screen_candidates, inputs=[ gr.Textbox( label="Paste Job Description Here", placeholder=( "Example:\n" "We are looking for a Data Scientist.\n" "Required skills: Python, Machine Learning, SQL, pandas, scikit-learn.\n" "Minimum 2 years experience required." ), lines=7 ), gr.Slider( minimum=5, maximum=20, value=10, step=1, label="Number of Top Candidates to Show" ), ], outputs=gr.Dataframe( label="Top Matching Candidates — Ranked by AI", wrap=True ), title="TalentMatch AI — ATS Resume Screening System", description=( "Built using NLP, TF-IDF Vectorization, and Cosine Similarity. " "Paste any job description → AI ranks 6,000 resumes in seconds. " "Built by an Undergraduate CS Student." ), examples=[ [ "We need a Data Scientist with Python, Machine Learning, TensorFlow, SQL, and pandas. " "2+ years experience required. Knowledge of NLP and deep learning is a plus.", 10 ], [ "Looking for a Frontend Developer skilled in React, JavaScript, HTML, CSS, and Node.js. " "Must know REST APIs and Git. Fresh graduates welcome.", 8 ], [ "Hiring ML Engineer with PyTorch, scikit-learn, Docker, AWS, and Python. " "Must have experience with model deployment and feature engineering.", 10 ], ], theme=gr.themes.Soft(), ) # ── Launch the app ──────────────────────────────────────────── # On Hugging Face, demo.launch() with no arguments is correct. # Locally, use demo.launch(share=True) to get a public link. demo.launch()