Spaces:
Running
Running
| # 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 | |
| from crewai import LLM | |
| API_KEY = os.getenv("groq_api") | |
| os.environ["MODEL_NAME"] = 'groq/deepseek-r1-distill-llama-70b' | |
| os.environ["SERPER_API_KEY"] = os.getenv("serper_key") | |
| #UPDATED | |
| llms = LLM( | |
| model="nvidia/llama3-chatqa-1.5-8b", #Crewai by defualts use Openai so we need to set another llm | |
| api_key=API_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.", | |
| llm = llms | |
| ) | |
| # 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.", | |
| llm = llms | |
| ) | |
| # 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.""", | |
| llm =llms | |
| ) | |
| 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 | |
| ) | |
| # Agent4: Resume Strategist | |
| resume_questioner = Agent( | |
| role="Professional AI/ML interviwer", | |
| goal="Based on the on the resume give top 10 possibilites questions.", | |
| verbose=True, | |
| backstory="With a strategic mind and an eye for detail, you excel at refining resumes based on the resume give me the what are the questions.", | |
| llm = llms | |
| ) | |
| # Task for Resume Strategist Agent: Align Resume with Job Requirements | |
| resume_question_task = Task( | |
| description=( | |
| """give me the interview question from the based on the rewrite resume. make sure what are the possibiliteis of question based on the resume: {resume}""" | |
| ), | |
| expected_output= "Resume in markdown format that effectively highlights the questions.", | |
| # output_file="improved_resume.md", | |
| context=[resume_advisor_task], | |
| agent=resume_questioner | |
| ) | |
| crew = Crew( | |
| agents=[resume_feedback, resume_advisor, job_researcher, resume_questioner], | |
| tasks=[resume_feedback_task, resume_advisor_task, research_task, resume_question_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() | |
| # job_questions = resume_question_task.output.raw.strip("```markdown").strip("```").strip() | |
| # return feedback, improved_resume, job_roles, job_questions | |
| def resume_agent(file_path, location): | |
| resume_text = extract_text_from_resume(file_path) | |
| result = crew.kickoff( | |
| inputs={"resume": resume_text, "location": location} | |
| ) | |
| # Always extract from CrewResult | |
| output_text = result.raw | |
| return ( | |
| output_text["feedback"], | |
| output_text["improved_resume"], | |
| output_text["job_roles"], | |
| output_text["job_questions"] | |
| ) | |
| # 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") | |
| job_questions_output = gr.Markdown(label="Relevant Resume questions") | |
| # Define the click event for the submit button | |
| def format_outputs(feedback, improved_resume, job_roles, job_questions): | |
| # 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}" | |
| job_Questions_with_heading = f"## Relevant resume questions:\n\n{job_questions}" | |
| return feedback_with_heading, improved_resume_with_heading, job_roles_with_heading, job_Questions_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, job_questions_output] | |
| ).then( | |
| format_outputs, | |
| inputs=[feedback_output, improved_resume_output, job_roles_output, job_questions_output], | |
| outputs=[feedback_output, improved_resume_output, job_roles_output, job_questions_output] | |
| ).then( | |
| lambda: gr.update(value="Submit"), | |
| inputs=[], | |
| outputs=submit_button | |
| ) | |
| demo.queue() | |
| demo.launch() |