resume-agent / app.py
AV-AV's picture
Update app.py
b01ebac verified
# Warning control
import warnings
warnings.filterwarnings('ignore')
import fitz # PyMuPDF for PDF processing
import docx # python-docx for DOCX processing
import gradio as gr
import os
from crewai import Agent, Task, Crew
from crewai_tools import SerperDevTool
os.environ['OPENAI_API_KEY'] = os.getenv("openaikey")
os.environ["OPENAI_MODEL_NAME"] = 'gpt-4o-mini'
os.environ["SERPER_API_KEY"] = os.getenv("serper_key")
def extract_text_from_pdf(file_path):
"""Extracts text from a PDF file using PyMuPDF."""
doc = fitz.open(file_path)
text = ""
for page in doc:
text += page.get_text()
return text
def extract_text_from_docx(file_path):
"""Extracts text from a DOCX file using python-docx."""
doc = docx.Document(file_path)
fullText = []
for para in doc.paragraphs:
fullText.append(para.text)
return "\n".join(fullText)
def extract_text_from_resume(file_path):
"""Determines file type and extracts text."""
if file_path.endswith(".pdf"):
return extract_text_from_pdf(file_path)
elif file_path.endswith(".docx"):
return extract_text_from_docx(file_path)
else:
return "Unsupported file format."
# Agent 1: Resume Strategist
resume_feedback = Agent(
role="Professional Resume Advisor",
goal="Give feedback on the resume to make it stand out in the job market.",
verbose=True,
backstory="With a strategic mind and an eye for detail, you excel at providing feedback on resumes to highlight the most relevant skills and experiences."
)
# Task for Resume Strategist Agent: Align Resume with Job Requirements
resume_feedback_task = Task(
description=(
"""Give feedback on the resume to make it stand out for recruiters.
Review every section, inlcuding the summary, work experience, skills, and education. Suggest to add relevant sections if they are missing.
Also give an overall score to the resume out of 10. This is the resume: {resume}"""
),
expected_output="The overall score of the resume followed by the feedback in bullet points.",
agent=resume_feedback
)
# Agent 2: Resume Strategist
resume_advisor = Agent(
role="Professional Resume Writer",
goal="Based on the feedback recieved from Resume Advisor, make changes to the resume to make it stand out in the job market.",
verbose=True,
backstory="With a strategic mind and an eye for detail, you excel at refining resumes based on the feedback to highlight the most relevant skills and experiences."
)
# Task for Resume Strategist Agent: Align Resume with Job Requirements
resume_advisor_task = Task(
description=(
"""Rewrite the resume based on the feedback to make it stand out for recruiters. You can adjust and enhance the resume but don't make up facts.
Review and update every section, including the summary, work experience, skills, and education to better reflect the candidates abilities. This is the resume: {resume}"""
),
expected_output= "Resume in markdown format that effectively highlights the candidate's qualifications and experiences",
# output_file="improved_resume.md",
context=[resume_feedback_task],
agent=resume_advisor
)
search_tool = SerperDevTool()
# Agent 3: Researcher
job_researcher = Agent(
role = "Senior Recruitment Consultant",
goal = "Find the 5 most relevant, recently posted jobs based on the improved resume recieved from resume advisor and the location preference",
tools = [search_tool],
verbose = True,
backstory = """As a senior recruitment consultant your prowess in finding the most relevant jobs based on the resume and location preference is unmatched.
You can scan the resume efficiently, identify the most suitable job roles and search for the best suited recently posted open job positions at the preffered location."""
)
research_task = Task(
description = """Find the 5 most relevant recent job postings based on the resume recieved from resume advisor and location preference. This is the preferred location: {location} .
Use the tools to gather relevant content and shortlist the 5 most relevant, recent, job openings""",
expected_output=(
"A bullet point list of the 5 job openings, with the appropriate links and detailed description about each job, in markdown format"
),
# output_file="relevant_jobs.md",
agent=job_researcher
)
crew = Crew(
agents=[resume_feedback, resume_advisor, job_researcher],
tasks=[resume_feedback_task, resume_advisor_task, research_task],
verbose=True
)
def resume_agent(file_path, location):
resume_text = extract_text_from_resume(file_path)
result = crew.kickoff(inputs={"resume": resume_text, "location": location})
# Extract outputs
feedback = resume_feedback_task.output.raw.strip("```markdown").strip("```").strip()
improved_resume = resume_advisor_task.output.raw.strip("```markdown").strip("```").strip()
job_roles = research_task.output.raw.strip("```markdown").strip("```").strip()
return feedback, improved_resume, job_roles
# Gradio Interface
with gr.Blocks() as demo:
gr.Markdown("# Resume Feedback and Job Matching Tool")
gr.Markdown("*Expected Runtime: 1 Min*")
with gr.Column():
with gr.Row():
resume_upload = gr.File(label="Upload Your Resume (PDF or DOCX)", height=120)
location_input = gr.Textbox(label="Preferred Location", placeholder="e.g., San Francisco")
submit_button = gr.Button("Submit")
with gr.Column():
feedback_output = gr.Markdown(label="Resume Feedback")
improved_resume_output = gr.Markdown(label="Improved Resume")
job_roles_output = gr.Markdown(label="Relevant Job Roles")
# Define the click event for the submit button
def format_outputs(feedback, improved_resume, job_roles):
# Add bold headings to each section
feedback_with_heading = f"## Resume Feedback:**\n\n{feedback}"
improved_resume_with_heading = f"## Improved Resume:\n\n{improved_resume}"
job_roles_with_heading = f"## Relevant Job Roles:\n\n{job_roles}"
return feedback_with_heading, improved_resume_with_heading, job_roles_with_heading
submit_button.click(
lambda: gr.update(value="Processing..."),
inputs=[],
outputs=submit_button
).then(
resume_agent,
inputs=[resume_upload, location_input],
outputs=[feedback_output, improved_resume_output, job_roles_output]
).then(
format_outputs,
inputs=[feedback_output, improved_resume_output, job_roles_output],
outputs=[feedback_output, improved_resume_output, job_roles_output]
).then(
lambda: gr.update(value="Submit"),
inputs=[],
outputs=submit_button
)
demo.queue()
demo.launch()