Spaces:
Runtime error
Runtime error
| # 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() | |