import os import gradio as gr from openai import OpenAI import PyPDF2 import pandas as pd import matplotlib.pyplot as plt import tempfile import json import re # Initialize OpenAI client client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) # --------------------------- # 🧠 Helper Functions # --------------------------- def extract_text_from_pdf(file_path): """Extract text safely from a PDF""" try: text = "" with open(file_path, "rb") as f: reader = PyPDF2.PdfReader(f) for page in reader.pages: page_text = page.extract_text() or "" text += page_text return text.strip() except Exception as e: return f"Error reading PDF: {e}" def analyze_resume(resume_text, job_desc): """Call GPT-4 model to analyze resume""" try: prompt = f""" You are an expert HR AI. Compare the following resume to the given job description. Rate how well the resume fits the job on a scale of 0–100. Then summarize the key strengths and weaknesses. Return output strictly in JSON format: {{ "score": , "summary": "" }} JOB DESCRIPTION: {job_desc} RESUME: {resume_text} """ response = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}], temperature=0.4, ) reply = response.choices[0].message.content match = re.search(r"\{.*\}", reply, re.S) if match: return json.loads(match.group()) else: return {"score": 50, "summary": reply.strip()} except Exception as e: return {"score": 0, "summary": f"Error: {e}"} def process_resumes(files, job_desc): """Main pipeline: extract text, analyze, chart results""" if not files or not job_desc: return "⚠️ Please upload resumes and enter a job description.", None, None results = [] for f in files: text = extract_text_from_pdf(f.name) result = analyze_resume(text, job_desc) results.append({ "Filename": os.path.basename(f.name), "Score": result.get("score", 0), "Summary": result.get("summary", "") }) df = pd.DataFrame(results) # Generate visualization fig, ax = plt.subplots(figsize=(6, 3)) ax.bar(df["Filename"], df["Score"], color="skyblue") ax.set_title("Resume Fit Scores") ax.set_ylabel("Score (0–100)") plt.xticks(rotation=15, ha="right") plt.tight_layout() tmp_chart = tempfile.NamedTemporaryFile(delete=False, suffix=".png") plt.savefig(tmp_chart.name) plt.close(fig) return df, tmp_chart.name, "✅ Analysis complete!" # --------------------------- # 🎨 Gradio UI # --------------------------- with gr.Blocks(theme=gr.themes.Soft(), title="AI Resume Screener Pro") as app: gr.Markdown("## 🤖 AI Resume Screener Pro\nUpload resumes and compare them with a job description using GPT-4.") with gr.Row(): job_desc = gr.Textbox(label="Job Description", lines=6, placeholder="Enter the job description here...") files = gr.File(label="Upload Resumes", file_count="multiple", type="filepath") analyze_btn = gr.Button("🚀 Analyze Resumes", variant="primary") output_table = gr.Dataframe(headers=["Filename", "Score", "Summary"], label="Results") output_plot = gr.Image(label="Visualization") output_status = gr.Textbox(label="Status", interactive=False) analyze_btn.click(fn=process_resumes, inputs=[files, job_desc], outputs=[output_table, output_plot, output_status]) gr.Markdown("---") gr.Markdown("Built with ❤️ using OpenAI GPT-4 and Gradio.") app.launch()