Imports
We start by importing some manual Python libraries. The keys are open to access GPT-4o-mini, as well as reduction and easy printing to create a PDF version of the final resume. Note: An OpenAI API key is required for this project, which I imported from a separate Python script.
from IPython.display import display, Markdown
from openai import OpenAI
from top_secret import my_skfrom markdown import markdown
from weasyprint import HTML
Step 1: Enter Resume and JD
Next, we will load our input resume into Python as a string and use Python. input() feature that allows us to copy and paste it into any job description when we run the script.
# open and read the markdown file
with open("resumes/resume.md", "r", encoding="utf-8") as file:
resume_string = file.read()# input job description
jd_string = input()
A detail here is that the The resume is saved in Markdown format.. This is important because it will encourage GPT-4o-mini to generate a new resume in Markdown, which we can easily design in a PDF. Note: ChatGPT (or similar) can convert your resume to PDF on markdown.
Step 2: build message
With our resume and JD imported, we can now create a message to tell the model to optimize the resume. A pro tip here is use ChatGPT to write an initial version of this message because 1) it's quite long and 2) LLMs tend to write instructions more aligned with the expectations of other LLMs.
After some experimenting, I ended up with the following template, which rewrites the resume and makes additional suggestions for improvement if there are skill gaps.
prompt_template = lambda resume_string, jd_string : f"""
You are a professional resume optimization expert specializing in tailoring \
resumes to specific job descriptions. Your goal is to optimize my resume and \
provide actionable suggestions for improvement to align with the target role.### Guidelines:
1. **Relevance**:
- Prioritize experiences, skills, and achievements **most relevant to the \
job description**.
- Remove or de-emphasize irrelevant details to ensure a **concise** and \
**targeted** resume.
- Limit work experience section to 2-3 most relevant roles
- Limit bullet points under each role to 2-3 most relevant impacts
2. **Action-Driven Results**:
- Use **strong action verbs** and **quantifiable results** (e.g., \
percentages, revenue, efficiency improvements) to highlight impact.
3. **Keyword Optimization**:
- Integrate **keywords** and phrases from the job description naturally to \
optimize for ATS (Applicant Tracking Systems).
4. **Additional Suggestions** *(If Gaps Exist)*:
- If the resume does not fully align with the job description, suggest:
1. **Additional technical or soft skills** that I could add to make my \
profile stronger.
2. **Certifications or courses** I could pursue to bridge the gap.
3. **Project ideas or experiences** that would better align with the role.
5. **Formatting**:
- Output the tailored resume in **clean Markdown format**.
- Include an **"Additional Suggestions"** section at the end with \
actionable improvement recommendations.
---
### Input:
- **My resume**:
{resume_string}
- **The job description**:
{jd_string}
---
### Output:
1. **Tailored Resume**:
- A resume in **Markdown format** that emphasizes relevant experience, \
skills, and achievements.
- Incorporates job description **keywords** to optimize for ATS.
- Uses strong language and is no longer than **one page**.
2. **Additional Suggestions** *(if applicable)*:
- List **skills** that could strengthen alignment with the role.
- Recommend **certifications or courses** to pursue.
- Suggest **specific projects or experiences** to develop.
"""
Step 3: Make an API call
Using the above message template, we can dynamically construct a message using the input resume and JD and then send it to OpenAI via its API.
# create prompt
prompt = prompt_template(resume_string, jd_string)# setup api client
client = OpenAI(api_key=my_sk)
# make api call
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=(
{"role": "system", "content": "Expert resume writer"},
{"role": "user", "content": prompt}
),
temperature = 0.7
)
# extract response
response_string = response.choices(0).message.content
Step 4: Save the new resume
Finally we will be able to extract the optimized resume and suggestions for improvement.
# separate new resume from improvement suggestions
response_list = response_string.split("## Additional Suggestions")
For the resume, we can convert the Markdown output to HTML using the Markdown library. Then convert the HTML to PDF using weasyprint.
# save as PDF
output_pdf_file = "resumes/resume_new.pdf"# Convert Markdown to HTML
html_content = markdown(response_list(0))
# Convert HTML to PDF and save
HTML(string=html_content).write_pdf(output_pdf_file,
stylesheets=('resumes/style.css'))
This is what the final result looks like.
For improvement suggestions, we can print them directly.
display(Markdown(response_list(1)))
Bonus: Create a GUI
While the code above simplifies this process to some extent, we can do better. To improve the usability of this tool, we can create a simple web interface using Gradio.
The final product is shown below. A user can upload a markdown file of their resume and paste it into any job description more easily. I also added an area where users can edit the new resume before exporting it as a PDF.
He Example code is available on GitHub. repository <a target="_blank" class="af oe" href="https://github.com/ShawhinT/ai-Builders-Bootcamp-2/blob/main/lightning-lesson/resume_optimizer_UI.ipynb” rel=”noopener ugc nofollow” target=”_blank”>here. look at the youtube video to see me talk through the code.
While tailoring your resume to specific job descriptions is an effective way to make an application stand out, it can be quite tedious. Here, we look at implementing an ai-powered resume optimization tool using Python and the OpenAI API.
If you have any questions or want to delve deeper into any of the topics covered, let me know in the comments 🙂
—
y2b.io It helped me write this article.