Spaces:
Sleeping
Sleeping
Update resume_generation_gemini_pro.py (#2)
Browse files- Update resume_generation_gemini_pro.py (a0bde6d779ea1929b6ff69e97c08b7ab9cf56148)
Co-authored-by: Anushka Bhat <[email protected]>
- resume_generation_gemini_pro.py +88 -46
resume_generation_gemini_pro.py
CHANGED
@@ -31,6 +31,7 @@ Original file is located at
|
|
31 |
|
32 |
import docx2txt
|
33 |
import PyPDF2
|
|
|
34 |
def extract_text(file_path):
|
35 |
if file_path.endswith(".docx"):
|
36 |
# Extract text from DOCX file
|
@@ -68,6 +69,7 @@ from langchain_community.vectorstores.faiss import FAISS
|
|
68 |
from docx import Document
|
69 |
import google.generativeai as genai
|
70 |
from datetime import datetime
|
|
|
71 |
|
72 |
api_key_google = os.environ.get('GOOGLE_GEMINI_KEY')
|
73 |
genai.configure(api_key=api_key_google)
|
@@ -88,61 +90,107 @@ def read_docx(file_path):
|
|
88 |
doc = Document(file_path)
|
89 |
return "\n".join([para.text for para in doc.paragraphs])
|
90 |
|
91 |
-
def generate_resume_text(resume_text):
|
92 |
-
|
93 |
-
Given the following resume content:
|
94 |
-
|
95 |
-
[Resume Start]
|
96 |
-
{resume_text}
|
97 |
-
[Resume End]
|
98 |
-
|
99 |
-
Format this resume content with appropriate section titles. Only use the information provided and avoid placeholders like "[Your Name]". Ensure it retains the structure and details exactly as shown.
|
100 |
-
"""
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
|
110 |
def tailor_resume(resume_text, job_description):
|
111 |
# Use the generate_resume_text function to get the formatted resume content
|
112 |
-
formatted_resume = generate_resume_text(resume_text)
|
113 |
-
print("formatted resume:",
|
114 |
-
if formatted_resume:
|
115 |
prompt = f"""
|
116 |
-
Below is the candidate's original
|
117 |
-
|
118 |
[Resume Start]
|
119 |
-
{
|
120 |
[Resume End]
|
121 |
-
|
122 |
Using the candidate's resume above and the job description below, create a tailored resume.
|
123 |
-
|
124 |
[Job Description Start]
|
125 |
{job_description}
|
126 |
[Job Description End]
|
127 |
|
|
|
128 |
Please generate a resume that:
|
129 |
1. Uses real data from the candidate's resume, including name, and education.
|
130 |
-
2. Avoids placeholders like "[Your Name]" and includes actual details.
|
131 |
3. In the experience section, emphasizes professional experiences and skills that are directly relevant to the job description.
|
132 |
4. Keeps only a maximum of the top three accomplishments/ responsibilities for each job position held so as to make the candidate standout in the new job role
|
133 |
-
5. Removes special characters from the section titles
|
134 |
-
6. Only includes publications if the job description is research based
|
135 |
-
7. Summarizes the skills and technical skills section into a brief profile
|
136 |
-
8. Does not include courses, certification, references, skills and a technical skills sections
|
|
|
|
|
137 |
"""
|
|
|
|
|
138 |
try:
|
139 |
response = model.generate_content(prompt)
|
|
|
140 |
return response.candidates[0].content.parts[0].text
|
141 |
except Exception as e:
|
142 |
print("Error in tailoring resume:", e)
|
143 |
return None
|
144 |
-
|
145 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
|
147 |
#Entry function for the model
|
148 |
def generate_gemini(current_resume,job_description):
|
@@ -154,19 +202,13 @@ def generate_gemini(current_resume,job_description):
|
|
154 |
|
155 |
# Tailor resume based on job description
|
156 |
tailored_resume = tailor_resume(resume_text, job_description)
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
file_path = f"Tailored_Resume_{datetime.now().strftime('%Y%m%d_%H%M%S')}.docx"
|
165 |
-
save_resume_to_docx(tailored_resume, file_path)
|
166 |
-
# st.success(f"Download tailored resume")
|
167 |
-
# st.success(f"Tailored resume saved to {file_path}")
|
168 |
-
|
169 |
-
return tailored_resume, file_path
|
170 |
|
171 |
# Main function for Streamlit app
|
172 |
# def Gemini_pro_main(current_resume,job_description):
|
|
|
31 |
|
32 |
import docx2txt
|
33 |
import PyPDF2
|
34 |
+
|
35 |
def extract_text(file_path):
|
36 |
if file_path.endswith(".docx"):
|
37 |
# Extract text from DOCX file
|
|
|
69 |
from docx import Document
|
70 |
import google.generativeai as genai
|
71 |
from datetime import datetime
|
72 |
+
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
|
73 |
|
74 |
api_key_google = os.environ.get('GOOGLE_GEMINI_KEY')
|
75 |
genai.configure(api_key=api_key_google)
|
|
|
90 |
doc = Document(file_path)
|
91 |
return "\n".join([para.text for para in doc.paragraphs])
|
92 |
|
93 |
+
# def generate_resume_text(resume_text):
|
94 |
+
# prompt = f"""
|
95 |
+
# Given the following resume content:
|
96 |
+
|
97 |
+
# [Resume Start]
|
98 |
+
# {resume_text}
|
99 |
+
# [Resume End]
|
100 |
+
|
101 |
+
# Format this resume content with appropriate section titles. Only use the information provided and avoid placeholders like "[Your Name]". Ensure it retains the structure and details exactly as shown.
|
102 |
+
# """
|
103 |
+
# try:
|
104 |
+
# response = model.generate_content(prompt)
|
105 |
+
# print(response)
|
106 |
+
# # Accessing the generated text content
|
107 |
+
# return response.candidates[0].content.parts[0].text
|
108 |
+
# except Exception as e:
|
109 |
+
# print("Error in generating resume text:", e)
|
110 |
+
# return None
|
111 |
|
112 |
def tailor_resume(resume_text, job_description):
|
113 |
# Use the generate_resume_text function to get the formatted resume content
|
114 |
+
# formatted_resume = generate_resume_text(resume_text)
|
115 |
+
# print("formatted resume:",resume_text)
|
|
|
116 |
prompt = f"""
|
117 |
+
Below is the candidate's original resume content:
|
|
|
118 |
[Resume Start]
|
119 |
+
{resume_text}
|
120 |
[Resume End]
|
|
|
121 |
Using the candidate's resume above and the job description below, create a tailored resume.
|
|
|
122 |
[Job Description Start]
|
123 |
{job_description}
|
124 |
[Job Description End]
|
125 |
|
126 |
+
|
127 |
Please generate a resume that:
|
128 |
1. Uses real data from the candidate's resume, including name, and education.
|
129 |
+
2. Avoids placeholders like "[Your Name]" and includes actual details. This is important.
|
130 |
3. In the experience section, emphasizes professional experiences and skills that are directly relevant to the job description.
|
131 |
4. Keeps only a maximum of the top three accomplishments/ responsibilities for each job position held so as to make the candidate standout in the new job role
|
132 |
+
5. Removes special characters from the section titles.
|
133 |
+
6. Only includes publications if the job description is research based.
|
134 |
+
7. Summarizes the skills and technical skills section into a brief profile.
|
135 |
+
8. Does not include courses, certification, references, skills and a technical skills sections if they are not relevant.
|
136 |
+
9. Only includes true information about the candidate.
|
137 |
+
10.Provide the text in markdown format that clearly identifies the headings and subheadings.
|
138 |
"""
|
139 |
+
|
140 |
+
|
141 |
try:
|
142 |
response = model.generate_content(prompt)
|
143 |
+
print(response.candidates[0].content.parts[0].text)
|
144 |
return response.candidates[0].content.parts[0].text
|
145 |
except Exception as e:
|
146 |
print("Error in tailoring resume:", e)
|
147 |
return None
|
148 |
+
|
149 |
+
def add_bold_and_normal_text(paragraph, text):
|
150 |
+
"""Adds text to the paragraph, handling bold formatting."""
|
151 |
+
while "**" in text:
|
152 |
+
before, bold_part, after = text.partition("**")
|
153 |
+
if before:
|
154 |
+
paragraph.add_run(before)
|
155 |
+
if bold_part == "**":
|
156 |
+
bold_text, _, text = after.partition("**")
|
157 |
+
paragraph.add_run(bold_text).bold = True
|
158 |
+
else:
|
159 |
+
text = after
|
160 |
+
if text:
|
161 |
+
paragraph.add_run(text)
|
162 |
+
|
163 |
+
def convert_resume_to_word(markdown_text,output_file):
|
164 |
+
# Create a new Word document
|
165 |
+
doc = Document()
|
166 |
+
|
167 |
+
# Split the text into lines for processing
|
168 |
+
lines = markdown_text.splitlines()
|
169 |
+
|
170 |
+
for line in lines:
|
171 |
+
if line.startswith("## "): # Main heading (Level 1)
|
172 |
+
paragraph = doc.add_heading(line[3:].strip(), level=1)
|
173 |
+
paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.JUSTIFY
|
174 |
+
elif line.startswith("### "): # Subheading (Level 2)
|
175 |
+
paragraph = doc.add_heading(line[4:].strip(), level=2)
|
176 |
+
paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.JUSTIFY
|
177 |
+
elif line.startswith("- "): # Bullet points
|
178 |
+
paragraph = doc.add_paragraph()
|
179 |
+
add_bold_and_normal_text(paragraph, line[2:].strip())
|
180 |
+
paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.JUSTIFY
|
181 |
+
elif line.startswith("* "): # Sub-bullet points or normal list items
|
182 |
+
paragraph = doc.add_paragraph(style="List Bullet")
|
183 |
+
add_bold_and_normal_text(paragraph, line[2:].strip())
|
184 |
+
paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.JUSTIFY
|
185 |
+
elif line.strip(): # Normal text (ignores blank lines)
|
186 |
+
paragraph = doc.add_paragraph()
|
187 |
+
add_bold_and_normal_text(paragraph, line.strip())
|
188 |
+
paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.JUSTIFY
|
189 |
+
|
190 |
+
# Save the Word document
|
191 |
+
|
192 |
+
doc.save(output_file)
|
193 |
+
print(f"Markdown converted and saved as {output_file}")
|
194 |
|
195 |
#Entry function for the model
|
196 |
def generate_gemini(current_resume,job_description):
|
|
|
202 |
|
203 |
# Tailor resume based on job description
|
204 |
tailored_resume = tailor_resume(resume_text, job_description)
|
205 |
+
output_file = f"Tailored_Resume_{datetime.now().strftime('%Y%m%d_%H%M%S')}.docx"
|
206 |
+
convert_resume_to_word(tailored_resume,output_file)
|
207 |
+
|
208 |
+
st.success(f"Tailored resume saved to {output_file}")
|
209 |
+
|
210 |
+
return tailored_resume, output_file
|
211 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
212 |
|
213 |
# Main function for Streamlit app
|
214 |
# def Gemini_pro_main(current_resume,job_description):
|