In today’s digital age, your résumé isn’t just a static document—it’s a dynamic showcase of your professional potential. At ResumeBurger, we’re all about transforming your résumé into a polished, recruiter-approved PDF with minimal effort. In this tutorial, we’ll build an API endpoint using FastAPI that takes your résumé text, enhances it using OpenAI, formats it with HTML templates, and converts it into a high-quality PDF using WeasyPrint.
What You’ll Need
- Python 3.x installed on your system
- Basic knowledge of Python scripting
- An OpenAI API key (store it securely in a
.env
file) - The following Python packages:
- FastAPI
- uvicorn for serving the app
- openai
- python-dotenv
- Jinja2 for templating
- WeasyPrint for PDF generation
Install the dependencies with:
pip install fastapi uvicorn openai python-dotenv jinja2 WeasyPrint
Step 1: Secure Your Credentials and Create a Template
Create a .env
File
Store your OpenAI API key in a .env
file in your project directory:
OPENAI_API_KEY=your_openai_api_key_here
Create an HTML Template
Create a file named resume_template.html
with the following content (feel free to style it with Tailwind CSS or custom CSS):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Optimized Résumé</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
h1 { font-size: 2em; border-bottom: 2px solid #333; padding-bottom: 0.5em; }
p { line-height: 1.6; }
</style>
</head>
<body>
<h1>{{ name }}</h1>
<h2>Professional Summary</h2>
<p>{{ summary }}</p>
<h2>Experience</h2>
<p>{{ experience }}</p>
<h2>Education</h2>
<p>{{ education }}</p>
<!-- Add more sections as needed -->
</body>
</html>
This template will be used to generate a styled HTML résumé before converting it into a PDF.
Step 2: Build the FastAPI Endpoint
We’ll create a FastAPI application that enhances the résumé text with OpenAI, renders the HTML template, and generates a PDF with WeasyPrint.
import os
import openai
from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException, Response
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
from jinja2 import Environment, FileSystemLoader
from weasyprint import HTML
import io
# Load environment variables
load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")
app = FastAPI(title="ResumeBurger PDF Generator")
# Define request model
class ResumeData(BaseModel):
name: str
summary: str
experience: str
education: str
job_description: str # This could be used to tailor the résumé further
def enhance_resume_section(text: str, job_description: str) -> str:
prompt = (
f"Enhance the following résumé section to better align with the job description provided.\n\n"
f"Section text:\n{text}\n\nJob description:\n{job_description}\n\n"
"Provide a refined, professional version."
)
try:
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": prompt}],
max_tokens=150,
temperature=0.7,
)
return response.choices[0].message.content.strip()
except Exception as e:
raise Exception(f"OpenAI API error: {e}")
@app.post("/generate-resume-pdf")
async def generate_resume_pdf(data: ResumeData):
try:
# Enhance résumé sections using OpenAI
enhanced_summary = enhance_resume_section(data.summary, data.job_description)
enhanced_experience = enhance_resume_section(data.experience, data.job_description)
enhanced_education = enhance_resume_section(data.education, data.job_description)
except Exception as error:
raise HTTPException(status_code=500, detail=str(error))
# Set up Jinja2 environment to load HTML template
env = Environment(loader=FileSystemLoader('.'))
template = env.get_template("resume_template.html")
html_content = template.render(
name=data.name,
summary=enhanced_summary,
experience=enhanced_experience,
education=enhanced_education
)
# Generate PDF using WeasyPrint
pdf_file = HTML(string=html_content).write_pdf()
pdf_stream = io.BytesIO(pdf_file)
pdf_stream.seek(0)
headers = {
"Content-Disposition": f"attachment; filename={data.name.replace(' ', '_')}_Resume.pdf"
}
return StreamingResponse(pdf_stream, media_type="application/pdf", headers=headers)
if __name__ == "__main__":
import uvicorn
uvicorn.run("your_script_name:app", host="0.0.0.0", port=8000, reload=True)
Replace "your_script_name"
with your file name (without the .py
extension).
How It Works
Enhancing Text:
Theenhance_resume_section
function sends each résumé section (summary, experience, education) along with the job description to OpenAI. It refines the text for clarity and impact.Template Rendering:
The enhanced sections are injected into theresume_template.html
file using Jinja2, producing a well-formatted HTML document.PDF Generation:
WeasyPrint converts the HTML into a PDF, which is then returned as a downloadable file via FastAPI.
Step 3: Testing and Deployment
- Local Testing: Run the application with:
uvicorn your_script_name:app --reload
Send a POST request to http://localhost:8000/generate-resume-pdf
with a JSON body:
{
"name": "Jane Doe",
"summary": "Experienced software developer with a background in AI.",
"experience": "5 years of experience at tech companies.",
"education": "Bachelor's degree in Computer Science.",
"job_description": "Looking for a candidate with strong AI, machine learning, and cloud computing skills."
}
The API will return a PDF file that you can download and review.
- Docker Deployment (Optional): Containerize your application using a Dockerfile for scalable deployment.
Conclusion
With this tutorial, you’ve built a powerful tool that automates the entire résumé PDF generation process—from AI-enhanced text refinement to PDF conversion. By leveraging FastAPI, OpenAI, Jinja2, and WeasyPrint, you can provide job seekers with professional, recruiter-approved résumés in minutes.
Customize the templates and enhancement prompts to best suit your audience, integrate with ResumeBurger’s platform, and empower users to stand out in today’s competitive job market.
Happy coding, and here’s to landing your dream job with a standout résumé!
Top comments (0)