Spaces:
Running
Running
import streamlit as st | |
import os | |
from langchain_openai import ChatOpenAI | |
from crewai import Agent, Task, Crew | |
import PyPDF2 | |
from docx import Document | |
# Load environment variables | |
api_key = os.getenv("OPENAI_API_KEY") | |
os.environ["OPENAI_API_KEY"] = api_key | |
# Initialize LLM | |
llm = ChatOpenAI( | |
model_name="gpt-4o-mini", # Not "gpt-4o-mini", valid model names are "gpt-4o", "gpt-4-turbo", "gpt-3.5-turbo" | |
temperature=0, | |
openai_api_key=os.getenv("OPENAI_API_KEY") | |
) | |
# Function to extract text from resume files | |
def extract_text_from_file(file): | |
text = "" | |
if file.type == "application/pdf": | |
pdf_reader = PyPDF2.PdfReader(file) | |
for page in pdf_reader.pages: | |
text += page.extract_text() + "\n" | |
elif file.type in ["application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/msword"]: | |
doc = Document(file) | |
for para in doc.paragraphs: | |
text += para.text + "\n" | |
return text | |
# Define Agents | |
resume_agent = Agent( | |
role="Resume Keyword Extractor", | |
goal="Extract important skills and keywords from resumes", | |
backstory="An advanced ATS system that extracts relevant technical skills, tools, programming languages, and certifications from resumes for recruiters.", | |
verbose=True, | |
llm=llm # Make sure llm is initialized before this | |
) | |
jd_agent = Agent( | |
role="Job Description Analyzer", | |
goal="Extract key skills and responsibilities from job descriptions", | |
backstory="An AI hiring assistant that understands job requirements", | |
verbose=True, | |
llm=llm | |
) | |
match_agent = Agent( | |
role="Resume & JD Matcher", | |
goal="Compare resume with job description and provide a match score", | |
backstory="An AI that evaluates job fit based on ATS criteria", | |
verbose=True, | |
llm=llm | |
) | |
st.title("๐ AI-Powered ATS Scanner") | |
st.subheader("โ๏ธ Resume & JD Match Analysis") | |
resume_files = st.file_uploader("Upload Resumes (PDF/DOC)", type=["pdf", "docx"], accept_multiple_files=True, key="match_resume") | |
job_description = st.text_area("Paste Job Description", key="match_jd") | |
if st.button("Analyze Match"): | |
if resume_files and job_description: | |
results = [] | |
for resume_file in resume_files: | |
resume_text = extract_text_from_file(resume_file) | |
task_match = Task( | |
description=f"""Given the following resume text and job description:\n\nResume:\n{resume_text}\n\n | |
Job Description:\n{job_description}\n\n | |
Analyze and compare the skills, tools, technologies, and certifications mentioned in both. | |
Calculate a match score (in percentage) based on the overlap of technical and domain-specific skills. | |
Additionally, list the important technical skills or certifications mentioned in the Job Description but missing in the Resume. | |
Do NOT consider soft skills, personality traits, or general statements in the comparison. | |
Provide the output in this format: | |
- Match Score: XX% | |
- Missing Keywords: [List of missing keywords] | |
""", | |
agent=match_agent, | |
expected_output="Match score and missing keywords" | |
) | |
crew = Crew( | |
agents=[match_agent], | |
tasks=[task_match], | |
verbose=False | |
) | |
result = crew.kickoff(inputs={"resume_text": resume_text, "job_description": job_description}) | |
extracted_keywords = result.tasks_output[0].raw | |
# Parse result | |
match_score_line = next((line for line in extracted_keywords.split('\n') if "Match Score" in line), "") | |
missing_keywords_line = next((line for line in extracted_keywords.split('\n') if "Missing Keywords" in line), "") | |
try: | |
score = int(match_score_line.split(":")[1].strip().replace("%", "")) | |
except: | |
score = 0 | |
results.append({ | |
"Resume": resume_file.name, | |
"Match Score (%)": score, | |
"Missing Keywords": missing_keywords_line.split(":", 1)[-1].strip() | |
}) | |
# Sort by Match Score descending | |
results_sorted = sorted(results, key=lambda x: x["Match Score (%)"], reverse=True) | |
st.success("โ ATS Match Results Table") | |
st.dataframe(results_sorted) | |
else: | |
st.warning("Please upload at least one resume and paste the job description.") | |