Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,136 +1,153 @@
|
|
|
|
1 |
import json
|
|
|
2 |
import pandas as pd
|
3 |
-
import gradio as gr
|
4 |
import google.generativeai as genai
|
5 |
-
import
|
6 |
-
from
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
text = ""
|
13 |
for page in reader.pages:
|
14 |
text += page.extract_text()
|
15 |
return text
|
16 |
|
17 |
-
# Function to extract
|
18 |
def extract_contact_info(resume_text):
|
19 |
-
|
20 |
-
name = "
|
21 |
-
|
22 |
-
|
|
|
|
|
23 |
return name, email, contact
|
24 |
|
25 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
input_prompt = """
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
{text}
|
42 |
-
|
43 |
-
Job Description (JD):
|
44 |
-
{jd}
|
45 |
"""
|
46 |
|
47 |
-
#
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
"Decision Making", "Problem Solving", "Team Motivation"
|
56 |
-
],
|
57 |
-
"Total_Experience_Years": 3.5,
|
58 |
-
"Direct_Management_Experience": [],
|
59 |
-
"Indirect_Management_Experience": [
|
60 |
-
"Guiding junior engineers on programming and software design tasks to enable timely delivery of products to customers.",
|
61 |
-
"Mentored sixteen pairs of students on research projects, with supervision through regular team-wise progress meetings."
|
62 |
-
],
|
63 |
-
"Mentoring_Guiding_Experience": [
|
64 |
-
"Guiding junior engineers on programming and software design tasks to enable timely delivery of products to customers.",
|
65 |
-
"Mentored sixteen pairs of students on research projects, with supervision through regular team-wise progress meetings.",
|
66 |
-
"Guided by Prof. Yulia Tsvetkov", "Guided by Prof. Veni Madhavan"
|
67 |
-
],
|
68 |
-
"Name": "Monisha Jegadeesan",
|
69 |
-
"Email": "Bmonishaj.65@gmail.com",
|
70 |
-
"Contact": "+91 9035212894",
|
71 |
-
"Profile_Summary": "Monisha Jegadeesan is a Software Engineer with 3.5 years of experience in Google. She has a strong background in Natural Language Processing, Machine Learning, and software development. She has experience guiding junior engineers and mentoring students on research projects. Monisha has a Master's degree in Computer Science and Engineering from the Indian Institute of Technology Madras."
|
72 |
-
}
|
73 |
-
# Simulating response as JSON string
|
74 |
-
return json.dumps(response)
|
75 |
-
|
76 |
-
# Main processing function for resume
|
77 |
-
def process_resume(job_desc, resume_file):
|
78 |
-
# Read the uploaded resume file
|
79 |
-
resume_text = input_pdf_text(resume_file)
|
80 |
-
|
81 |
# Extract contact info (name, email, contact)
|
82 |
name, email, contact = extract_contact_info(resume_text)
|
83 |
-
|
|
|
|
|
|
|
|
|
84 |
# Prepare the prompt with resume and job description text
|
85 |
-
prompt = input_prompt.format(text=resume_text, jd=
|
86 |
|
87 |
-
# Get the response from Gemini model
|
88 |
response_text = get_gemini_response(prompt)
|
|
|
|
|
|
|
|
|
89 |
|
90 |
-
#
|
91 |
-
|
92 |
|
93 |
-
#
|
94 |
-
|
|
|
95 |
|
|
|
96 |
try:
|
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 |
-
return result, gr.File.update(value=csv_file, visible=True)
|
124 |
-
|
125 |
-
# Define Gradio interface
|
126 |
-
resume_file_input = gr.File(label="Upload Resume (PDF)", type="file")
|
127 |
-
job_desc_input = gr.Textbox(label="Enter Job Description", placeholder="Paste job description here")
|
128 |
-
|
129 |
-
# Gradio interface layout
|
130 |
-
with gr.Blocks() as demo:
|
131 |
-
job_desc_input
|
132 |
-
resume_file_input
|
133 |
-
gr.Button("Process Resume").click(gradio_interface, inputs=[job_desc_input, resume_file_input], outputs=["json", "file"])
|
134 |
-
|
135 |
-
# Launch the Gradio interface
|
136 |
-
demo.launch()
|
|
|
1 |
+
import re
|
2 |
import json
|
3 |
+
import os
|
4 |
import pandas as pd
|
|
|
5 |
import google.generativeai as genai
|
6 |
+
import PyPDF2 as pdf
|
7 |
+
from dotenv import load_dotenv
|
8 |
+
import io
|
9 |
+
|
10 |
+
# Load environment variables from a .env file
|
11 |
+
load_dotenv()
|
12 |
+
|
13 |
+
# Get API Key from environment variable
|
14 |
+
api_key = os.getenv('GOOGLE_API_KEY')
|
15 |
+
if not api_key:
|
16 |
+
raise ValueError("API key not found. Please set GOOGLE_API_KEY in your environment variables.")
|
17 |
+
|
18 |
+
genai.configure(api_key=api_key)
|
19 |
+
|
20 |
+
# Function to get response from the Gemini model
|
21 |
+
def get_gemini_response(input_text):
|
22 |
+
model = genai.GenerativeModel('gemini-1.5-flash')
|
23 |
+
response = model.generate_content(input_text)
|
24 |
+
return response.text
|
25 |
+
|
26 |
+
# Function to extract text from uploaded PDF
|
27 |
+
def input_pdf_text(uploaded_file_path):
|
28 |
+
with open(uploaded_file_path, 'rb') as file:
|
29 |
+
reader = pdf.PdfReader(file)
|
30 |
text = ""
|
31 |
for page in reader.pages:
|
32 |
text += page.extract_text()
|
33 |
return text
|
34 |
|
35 |
+
# Function to extract name, email, and contact from the resume text
|
36 |
def extract_contact_info(resume_text):
|
37 |
+
name_match = re.search(r"^(?P<name>[A-Za-z\s]+)$", resume_text, re.MULTILINE)
|
38 |
+
name = name_match.group('name') if name_match else "Not Available"
|
39 |
+
email_match = re.search(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", resume_text)
|
40 |
+
email = email_match.group(0) if email_match else "Not Available"
|
41 |
+
contact_match = re.search(r"\+?\d{1,2}\s?\(?\d{1,4}\)?\s?\d{10}", resume_text)
|
42 |
+
contact = contact_match.group(0) if contact_match else "Not Available"
|
43 |
return name, email, contact
|
44 |
|
45 |
+
# Function to extract years of experience based on date mentions (for both direct and indirect experience)
|
46 |
+
def extract_years_from_text(text, role):
|
47 |
+
# Define regex patterns to match different formats for date ranges or years
|
48 |
+
patterns = [
|
49 |
+
r"from (\d{4}) to (\d{4})", # Matches: 'from 2019 to 2022'
|
50 |
+
r"for (\d+) years", # Matches: 'for 3 years'
|
51 |
+
r"since (\d{4})", # Matches: 'since 2018'
|
52 |
+
r"from (\d{4}) to present" # Matches: 'from 2019 to present'
|
53 |
+
]
|
54 |
+
|
55 |
+
total_years = 0
|
56 |
+
|
57 |
+
# Process each pattern to extract relevant years
|
58 |
+
for pattern in patterns:
|
59 |
+
matches = re.findall(pattern, text)
|
60 |
+
|
61 |
+
for match in matches:
|
62 |
+
if len(match) == 2: # Date range (e.g., "from 2019 to 2022")
|
63 |
+
start_year = int(match[0])
|
64 |
+
end_year = int(match[1])
|
65 |
+
total_years += end_year - start_year
|
66 |
+
elif len(match) == 1: # Single year or years
|
67 |
+
years = int(match[0])
|
68 |
+
total_years += years
|
69 |
+
|
70 |
+
# Apply different logic based on role: "Direct" or "Indirect"
|
71 |
+
if role.lower() == "direct":
|
72 |
+
return total_years # Direct management years
|
73 |
+
else:
|
74 |
+
return total_years # Indirect management years
|
75 |
+
|
76 |
+
# Refined Prompt Template for Gemini API (requesting simple text)
|
77 |
input_prompt = """
|
78 |
+
Act as a highly skilled Applicant Tracking System (ATS) with expertise in evaluating resumes for management and team leadership roles. Your task is to assess the resume against the provided job description, focusing on a detailed analysis.
|
79 |
+
|
80 |
+
Instructions:
|
81 |
+
1. **Direct Management/Team Leadership Experience**: Identify instances where the candidate has formal responsibility for managing a team, such as leading projects or directly managing team members.
|
82 |
+
2. **Indirect Management/Team Leadership Experience**: Identify instances where the candidate provides guidance or mentorship, such as mentoring junior engineers or organizing team activities without direct management responsibility.
|
83 |
+
3. **Match Percentage**: Calculate the match percentage by identifying and counting keywords and phrases relevant to management and team leadership from the job description. Include years of experience as a factor in the match.
|
84 |
+
|
85 |
+
Provide a simple text output with the following information:
|
86 |
+
- The candidate’s **Direct Management/Team Leadership Experience** in years.
|
87 |
+
- The candidate’s **Indirect Management/Team Leadership Experience** in years.
|
88 |
+
|
89 |
+
Input:
|
90 |
+
- Resume Text: "{text}"
|
91 |
+
- Job Description: "{jd}"
|
|
|
|
|
|
|
|
|
92 |
"""
|
93 |
|
94 |
+
# Manually specify the file path of the resume and the job description
|
95 |
+
uploaded_file_path = input("Enter the file path of the resume PDF: ")
|
96 |
+
jd = input("Paste the Job Description: ")
|
97 |
+
|
98 |
+
if os.path.exists(uploaded_file_path):
|
99 |
+
# Extract text from the PDF resume
|
100 |
+
resume_text = input_pdf_text(uploaded_file_path)
|
101 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
# Extract contact info (name, email, contact)
|
103 |
name, email, contact = extract_contact_info(resume_text)
|
104 |
+
|
105 |
+
# Extract years of experience based on date mentions
|
106 |
+
direct_management_years = extract_years_from_text(resume_text, role="direct")
|
107 |
+
indirect_management_years = extract_years_from_text(resume_text, role="indirect")
|
108 |
+
|
109 |
# Prepare the prompt with resume and job description text
|
110 |
+
prompt = input_prompt.format(text=resume_text, jd=jd)
|
111 |
|
112 |
+
# Get the response from Gemini model
|
113 |
response_text = get_gemini_response(prompt)
|
114 |
+
|
115 |
+
# Log the raw response for inspection (cleaned up)
|
116 |
+
print("Raw model response (before cleaning):")
|
117 |
+
print(repr(response_text)) # Use repr to show invisible characters
|
118 |
|
119 |
+
# Strip any leading/trailing whitespace or unwanted characters from the response
|
120 |
+
response_text_clean = response_text.strip()
|
121 |
|
122 |
+
# Log the cleaned response
|
123 |
+
print("\nCleaned model response (after stripping whitespace):")
|
124 |
+
print(repr(response_text_clean)) # Show cleaned response
|
125 |
|
126 |
+
# Now, process the plain text response
|
127 |
try:
|
128 |
+
# Create a DataFrame with the extracted data
|
129 |
+
data = {
|
130 |
+
'Name': [name],
|
131 |
+
'Email': [email],
|
132 |
+
'Contact': [contact],
|
133 |
+
'Direct_Management_Experience_Years': [direct_management_years],
|
134 |
+
'Indirect_Management_Experience_Years': [indirect_management_years],
|
135 |
+
'Model_Response': [response_text_clean]
|
136 |
+
}
|
137 |
+
|
138 |
+
df = pd.DataFrame(data)
|
139 |
+
|
140 |
+
# Display the DataFrame as a table
|
141 |
+
print("\nAnalysis Results Table:")
|
142 |
+
print(df)
|
143 |
+
|
144 |
+
# Save the DataFrame to a CSV file
|
145 |
+
csv_filename = "ATS_Analysis_Results.csv"
|
146 |
+
df.to_csv(csv_filename, index=False)
|
147 |
+
|
148 |
+
print(f"Results saved to {csv_filename}")
|
149 |
+
|
150 |
+
except Exception as e:
|
151 |
+
print(f"\nAn error occurred while processing the response: {str(e)}")
|
152 |
+
else:
|
153 |
+
print("The file path provided does not exist. Please check the path and try again.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|