File size: 6,914 Bytes
b8ea438
 
 
 
 
 
 
fb6e7b6
b8ea438
fb6e7b6
 
 
 
b8ea438
 
 
 
 
 
fb6e7b6
b8ea438
fb6e7b6
 
 
 
 
 
 
b8ea438
fb6e7b6
 
 
 
 
 
 
b8ea438
fb6e7b6
 
 
 
 
b8ea438
fb6e7b6
 
b8ea438
 
 
 
 
 
 
fb6e7b6
 
b8ea438
 
 
 
 
819317a
b8ea438
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fb6e7b6
b8ea438
 
 
 
 
 
 
 
fb6e7b6
 
b8ea438
 
819317a
b8ea438
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d1a04c5
 
 
fb6e7b6
b8ea438
d1a04c5
b01ebac
 
 
d1a04c5
b8ea438
 
fd22a75
fb6e7b6
b8ea438
fb6e7b6
b8ea438
 
fd22a75
 
 
d1a04c5
 
 
fd22a75
 
cc02251
b21a967
b8ea438
b21a967
 
 
 
b8ea438
 
b21a967
fd22a75
 
 
 
b21a967
 
 
 
fb6e7b6
 
b21a967
b8ea438
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# 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()