Spaces:
Sleeping
Sleeping
Commit ·
583aa92
1
Parent(s): 3b931a0
minimal pdf
Browse files- .env.example +11 -0
- .gitignore +39 -0
- README.md +44 -0
- app.py +20 -0
- app/__init__.py +5 -0
- app/app.py +136 -0
- milestones.md +46 -0
- purpose.md +1 -0
- requirements.txt +8 -0
- templates/minimal_resume.tex +31 -0
- templates/resume_template.tex +159 -0
.env.example
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Hugging Face API Token (used for accessing LLM models)
|
| 2 |
+
HF_API_TOKEN=your_huggingface_token_here
|
| 3 |
+
|
| 4 |
+
# Model to use for job description analysis
|
| 5 |
+
LLM_MODEL=google/flan-t5-large
|
| 6 |
+
|
| 7 |
+
# Default template location (relative to app root)
|
| 8 |
+
DEFAULT_TEMPLATE_PATH=templates/resume_template.tex
|
| 9 |
+
|
| 10 |
+
# Output directory for generated files
|
| 11 |
+
OUTPUT_DIR=outputs
|
.gitignore
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Python
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.py[cod]
|
| 4 |
+
*$py.class
|
| 5 |
+
*.so
|
| 6 |
+
.Python
|
| 7 |
+
env/
|
| 8 |
+
build/
|
| 9 |
+
develop-eggs/
|
| 10 |
+
dist/
|
| 11 |
+
downloads/
|
| 12 |
+
eggs/
|
| 13 |
+
.eggs/
|
| 14 |
+
lib/
|
| 15 |
+
lib64/
|
| 16 |
+
parts/
|
| 17 |
+
sdist/
|
| 18 |
+
var/
|
| 19 |
+
*.egg-info/
|
| 20 |
+
.installed.cfg
|
| 21 |
+
*.egg
|
| 22 |
+
|
| 23 |
+
# Virtual Environment
|
| 24 |
+
venv/
|
| 25 |
+
ENV/
|
| 26 |
+
env/
|
| 27 |
+
|
| 28 |
+
# IDE
|
| 29 |
+
.idea/
|
| 30 |
+
.vscode/
|
| 31 |
+
*.swp
|
| 32 |
+
*.swo
|
| 33 |
+
|
| 34 |
+
# Project specific
|
| 35 |
+
outputs/
|
| 36 |
+
*.pdf
|
| 37 |
+
*.aux
|
| 38 |
+
*.log
|
| 39 |
+
*.out
|
README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Resume Customizer
|
| 2 |
+
|
| 3 |
+
A Hugging Face Spaces application that customizes your resume for specific job applications by analyzing job descriptions and generating tailored "Why Hire Me" sections.
|
| 4 |
+
|
| 5 |
+
## Features
|
| 6 |
+
|
| 7 |
+
- Upload your base LaTeX resume template
|
| 8 |
+
- Input job descriptions to analyze
|
| 9 |
+
- Automatically generate a customized "Why Hire Me" section highlighting relevant skills and experience
|
| 10 |
+
- Convert the customized LaTeX resume to PDF
|
| 11 |
+
- Preview and download the final resume
|
| 12 |
+
|
| 13 |
+
## How It Works
|
| 14 |
+
|
| 15 |
+
1. The application takes your LaTeX resume template and a job description as input
|
| 16 |
+
2. It uses a language model to analyze the job description and identify key requirements
|
| 17 |
+
3. Based on the analysis, it generates a tailored "Why Hire Me" section that emphasizes your qualifications
|
| 18 |
+
4. The new section is injected into your LaTeX resume
|
| 19 |
+
5. The modified LaTeX is converted to PDF for download
|
| 20 |
+
|
| 21 |
+
## Getting Started
|
| 22 |
+
|
| 23 |
+
### Local Development
|
| 24 |
+
|
| 25 |
+
1. Clone this repository
|
| 26 |
+
2. Install dependencies: `pip install -r requirements.txt`
|
| 27 |
+
3. Run the application: `python app/app.py`
|
| 28 |
+
|
| 29 |
+
### Using Hugging Face Space
|
| 30 |
+
|
| 31 |
+
Simply visit the Hugging Face Space at [URL to be added] and use the interface directly in your browser.
|
| 32 |
+
|
| 33 |
+
## Project Structure
|
| 34 |
+
|
| 35 |
+
- `app/` - Contains the main application code
|
| 36 |
+
- `app/app.py` - Main Gradio application
|
| 37 |
+
- `app/resume_processor.py` - LaTeX processing utilities
|
| 38 |
+
- `app/llm_utils.py` - LLM integration for job description analysis
|
| 39 |
+
- `templates/` - Default LaTeX resume template
|
| 40 |
+
- `assets/` - Static assets for the application
|
| 41 |
+
|
| 42 |
+
## License
|
| 43 |
+
|
| 44 |
+
MIT
|
app.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Main entry point for the Resume Customizer application.
|
| 3 |
+
For Hugging Face Spaces deployment.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import os
|
| 7 |
+
import sys
|
| 8 |
+
|
| 9 |
+
# Add the current directory to Python's path to allow imports
|
| 10 |
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
| 11 |
+
|
| 12 |
+
# Import the create_interface function from the app module
|
| 13 |
+
from app.app import create_interface
|
| 14 |
+
|
| 15 |
+
# Create and launch the application
|
| 16 |
+
app = create_interface()
|
| 17 |
+
|
| 18 |
+
# For Hugging Face Spaces, we need to export the app
|
| 19 |
+
if __name__ == "__main__":
|
| 20 |
+
app.launch()
|
app/__init__.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Resume Customizer application package.
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
__version__ = "0.1.0"
|
app/app.py
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import gradio as gr
|
| 3 |
+
from huggingface_hub import InferenceClient
|
| 4 |
+
import tempfile
|
| 5 |
+
import shutil
|
| 6 |
+
import subprocess
|
| 7 |
+
|
| 8 |
+
# Constants
|
| 9 |
+
# Use the minimal template for testing
|
| 10 |
+
DEFAULT_TEMPLATE_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "templates", "minimal_resume.tex")
|
| 11 |
+
OUTPUT_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "outputs")
|
| 12 |
+
|
| 13 |
+
# Ensure output directory exists
|
| 14 |
+
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
| 15 |
+
|
| 16 |
+
def customize_resume(job_description):
|
| 17 |
+
"""
|
| 18 |
+
Main function to customize resume based on job description.
|
| 19 |
+
|
| 20 |
+
Args:
|
| 21 |
+
job_description (str): The job description text
|
| 22 |
+
|
| 23 |
+
Returns:
|
| 24 |
+
tuple: (PDF path, Status message)
|
| 25 |
+
"""
|
| 26 |
+
# This is a placeholder for future implementation of LLM integration
|
| 27 |
+
# For now, we'll just add a simple "Why Hire Me" section
|
| 28 |
+
why_hire_me_section = "\\section{Why Hire Me?}\nThis is a placeholder for the Why Hire Me section that will be generated by an LLM in future milestones."
|
| 29 |
+
|
| 30 |
+
# Read the template
|
| 31 |
+
with open(DEFAULT_TEMPLATE_PATH, "r") as f:
|
| 32 |
+
template_content = f.read()
|
| 33 |
+
|
| 34 |
+
# Replace the placeholder with the generated section
|
| 35 |
+
modified_content = template_content.replace("% WHY_HIRE_ME_SECTION", why_hire_me_section)
|
| 36 |
+
|
| 37 |
+
# Save the modified content to a new file
|
| 38 |
+
output_tex_path = os.path.join(OUTPUT_DIR, "customized_resume.tex")
|
| 39 |
+
with open(output_tex_path, "w") as f:
|
| 40 |
+
f.write(modified_content)
|
| 41 |
+
|
| 42 |
+
# Convert to PDF using pdflatex
|
| 43 |
+
try:
|
| 44 |
+
pdf_path = convert_to_pdf(output_tex_path)
|
| 45 |
+
return pdf_path, f"Resume successfully generated! Click to download."
|
| 46 |
+
except Exception as e:
|
| 47 |
+
return None, f"Error converting to PDF: {str(e)}"
|
| 48 |
+
|
| 49 |
+
def convert_to_pdf(tex_path):
|
| 50 |
+
"""
|
| 51 |
+
Convert a LaTeX file to PDF using pdflatex.
|
| 52 |
+
|
| 53 |
+
Args:
|
| 54 |
+
tex_path (str): Path to the LaTeX file
|
| 55 |
+
|
| 56 |
+
Returns:
|
| 57 |
+
str: Path to the generated PDF file
|
| 58 |
+
"""
|
| 59 |
+
# Get the directory and filename
|
| 60 |
+
tex_dir = os.path.dirname(tex_path)
|
| 61 |
+
tex_filename = os.path.basename(tex_path)
|
| 62 |
+
|
| 63 |
+
# Change to the directory containing the tex file
|
| 64 |
+
original_dir = os.getcwd()
|
| 65 |
+
os.chdir(tex_dir)
|
| 66 |
+
|
| 67 |
+
try:
|
| 68 |
+
# Create a log file to capture output
|
| 69 |
+
log_path = os.path.join(tex_dir, "pdflatex_log.txt")
|
| 70 |
+
with open(log_path, 'w') as log_file:
|
| 71 |
+
# Run pdflatex and capture output to the log file
|
| 72 |
+
log_file.write("Running pdflatex - First pass\n")
|
| 73 |
+
result = subprocess.run(['pdflatex', '-interaction=nonstopmode', tex_filename],
|
| 74 |
+
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
| 75 |
+
log_file.write(f"Return code: {result.returncode}\n")
|
| 76 |
+
log_file.write(f"STDOUT:\n{result.stdout}\n")
|
| 77 |
+
log_file.write(f"STDERR:\n{result.stderr}\n\n")
|
| 78 |
+
|
| 79 |
+
# Run a second time to resolve references
|
| 80 |
+
log_file.write("Running pdflatex - Second pass\n")
|
| 81 |
+
result = subprocess.run(['pdflatex', '-interaction=nonstopmode', tex_filename],
|
| 82 |
+
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
| 83 |
+
log_file.write(f"Return code: {result.returncode}\n")
|
| 84 |
+
log_file.write(f"STDOUT:\n{result.stdout}\n")
|
| 85 |
+
log_file.write(f"STDERR:\n{result.stderr}\n")
|
| 86 |
+
|
| 87 |
+
# Get the PDF path
|
| 88 |
+
pdf_filename = tex_filename.replace('.tex', '.pdf')
|
| 89 |
+
pdf_path = os.path.join(tex_dir, pdf_filename)
|
| 90 |
+
|
| 91 |
+
# Check if the PDF was actually created
|
| 92 |
+
if not os.path.exists(pdf_path):
|
| 93 |
+
raise Exception(f"PDF file not created. See log at: {log_path}")
|
| 94 |
+
|
| 95 |
+
# Return the absolute path to the PDF
|
| 96 |
+
return os.path.abspath(pdf_path)
|
| 97 |
+
except subprocess.CalledProcessError as e:
|
| 98 |
+
raise Exception(f"PDF conversion failed: {e}\nSee log at: {os.path.abspath(log_path)}")
|
| 99 |
+
except Exception as e:
|
| 100 |
+
raise Exception(f"Error in PDF conversion: {str(e)}")
|
| 101 |
+
finally:
|
| 102 |
+
# Change back to the original directory
|
| 103 |
+
os.chdir(original_dir)
|
| 104 |
+
|
| 105 |
+
# Define the Gradio interface
|
| 106 |
+
def create_interface():
|
| 107 |
+
with gr.Blocks(title="Resume Customizer") as app:
|
| 108 |
+
gr.Markdown("# Resume Customizer")
|
| 109 |
+
gr.Markdown("Enter a job description to generate a customized resume.")
|
| 110 |
+
|
| 111 |
+
with gr.Row():
|
| 112 |
+
with gr.Column():
|
| 113 |
+
job_description = gr.Textbox(
|
| 114 |
+
label="Job Description",
|
| 115 |
+
placeholder="Paste the job description here...",
|
| 116 |
+
lines=10
|
| 117 |
+
)
|
| 118 |
+
|
| 119 |
+
customize_btn = gr.Button("Customize Resume")
|
| 120 |
+
|
| 121 |
+
with gr.Column():
|
| 122 |
+
pdf_output = gr.File(label="Download Resume")
|
| 123 |
+
status_text = gr.Textbox(label="Status", interactive=False)
|
| 124 |
+
|
| 125 |
+
customize_btn.click(
|
| 126 |
+
fn=customize_resume,
|
| 127 |
+
inputs=[job_description],
|
| 128 |
+
outputs=[pdf_output, status_text]
|
| 129 |
+
)
|
| 130 |
+
|
| 131 |
+
return app
|
| 132 |
+
|
| 133 |
+
# Main entry point
|
| 134 |
+
if __name__ == "__main__":
|
| 135 |
+
app = create_interface()
|
| 136 |
+
app.launch()
|
milestones.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Resume Customization Project Milestones
|
| 2 |
+
Note (when something is implemented write [done] in front of it)
|
| 3 |
+
## Milestone 1: Project Setup [done]
|
| 4 |
+
- Set up project structure and repository [done]
|
| 5 |
+
- Create basic README with project overview [done]
|
| 6 |
+
- Set up Python environment with requirements.txt [done]
|
| 7 |
+
- Initialize Gradio application [done]
|
| 8 |
+
|
| 9 |
+
## Milestone 2: LaTeX Resume Setup [done]
|
| 10 |
+
- Create or import base LaTeX resume template [done]
|
| 11 |
+
- Test LaTeX to PDF conversion pipeline [done]
|
| 12 |
+
- Set up file storage structure for template and customized resumes [done]
|
| 13 |
+
|
| 14 |
+
## Milestone 3: Job Description Analysis with LLM
|
| 15 |
+
- Set up LLM integration (Hugging Face models)
|
| 16 |
+
- Develop prompt engineering for job description analysis
|
| 17 |
+
- Create function to extract key skills and requirements from job descriptions
|
| 18 |
+
|
| 19 |
+
## Milestone 4: Resume Customization Logic
|
| 20 |
+
- Develop logic to generate "Why Hire Me" section based on job description
|
| 21 |
+
- Create function to inject new section into LaTeX resume
|
| 22 |
+
- Implement resume customization pipeline (job desc → analysis → LaTeX modification → PDF)
|
| 23 |
+
|
| 24 |
+
## Milestone 5: Gradio UI Development
|
| 25 |
+
- Design simple UI with job description input
|
| 26 |
+
- Add file upload option for custom base resume (optional)
|
| 27 |
+
- Implement PDF preview and download functionality
|
| 28 |
+
- Style the interface for better user experience
|
| 29 |
+
|
| 30 |
+
## Milestone 6: Testing and Refinement
|
| 31 |
+
- Test with various job descriptions
|
| 32 |
+
- Refine LLM prompts for better customization
|
| 33 |
+
- Optimize performance and resource usage
|
| 34 |
+
- Fix bugs and edge cases
|
| 35 |
+
|
| 36 |
+
## Milestone 7: Hugging Face Deployment
|
| 37 |
+
- Prepare application for Hugging Face Spaces
|
| 38 |
+
- Configure deployment settings
|
| 39 |
+
- Create deployment documentation
|
| 40 |
+
- Deploy application to Hugging Face Spaces
|
| 41 |
+
|
| 42 |
+
## Milestone 8: Documentation and Maintenance
|
| 43 |
+
- Complete user documentation
|
| 44 |
+
- Document code for future maintenance
|
| 45 |
+
- Create examples and usage instructions
|
| 46 |
+
- Plan for future enhancements
|
purpose.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
the purpose is the customize my resume for each job applied. so the input will be job description and output will be the pdf. essentially at backend there will be a a latex resume .tex file and it'll be converted to another tex file via LLM (it'll just add a why hire me section) on top of the resume using LLMs. essentiallyl that tex will be converted to pdf as well. it'll be a gradio, huggingface, python app.
|
requirements.txt
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio>=4.0.0
|
| 2 |
+
huggingface_hub>=0.20.0
|
| 3 |
+
transformers>=4.36.0
|
| 4 |
+
torch>=2.0.0
|
| 5 |
+
PyPDF2>=3.0.0
|
| 6 |
+
python-dotenv>=1.0.0
|
| 7 |
+
latex>=0.7.0
|
| 8 |
+
pdflatex>=0.1.3
|
templates/minimal_resume.tex
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
\documentclass[letterpaper,11pt]{article}
|
| 2 |
+
|
| 3 |
+
\usepackage[margin=1in]{geometry}
|
| 4 |
+
\usepackage{enumitem}
|
| 5 |
+
|
| 6 |
+
% WHY HIRE ME SECTION PLACEHOLDER - this will be modified by the app
|
| 7 |
+
% WHY_HIRE_ME_SECTION
|
| 8 |
+
|
| 9 |
+
\begin{document}
|
| 10 |
+
|
| 11 |
+
\centerline{\Huge\textbf{John Doe}}
|
| 12 |
+
\vspace{0.25em}
|
| 13 |
+
\centerline{123-456-7890 $\vert$ john.doe@email.com $\vert$ linkedin.com/in/johndoe}
|
| 14 |
+
|
| 15 |
+
\section*{Education}
|
| 16 |
+
\textbf{University of Technology} \hfill City, State\\
|
| 17 |
+
Master of Science in Computer Science \hfill 2018-2020
|
| 18 |
+
|
| 19 |
+
\section*{Experience}
|
| 20 |
+
\textbf{Senior Software Engineer} \hfill Jan 2021 - Present\\
|
| 21 |
+
Tech Company Inc. \hfill City, State
|
| 22 |
+
\begin{itemize}
|
| 23 |
+
\item Led development of cloud-based microservices architecture
|
| 24 |
+
\item Implemented CI/CD pipeline reducing deployment time by 40\%
|
| 25 |
+
\end{itemize}
|
| 26 |
+
|
| 27 |
+
\section*{Skills}
|
| 28 |
+
Languages: Python, JavaScript, Java, C++, SQL\\
|
| 29 |
+
Tools: Docker, Kubernetes, AWS, Git, Jenkins
|
| 30 |
+
|
| 31 |
+
\end{document}
|
templates/resume_template.tex
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
\documentclass[letterpaper,11pt]{article}
|
| 2 |
+
|
| 3 |
+
\usepackage{latexsym}
|
| 4 |
+
\usepackage[empty]{fullpage}
|
| 5 |
+
\usepackage{titlesec}
|
| 6 |
+
\usepackage[usenames,dvipsnames]{color}
|
| 7 |
+
\usepackage{verbatim}
|
| 8 |
+
\usepackage{enumitem}
|
| 9 |
+
\usepackage[hidelinks]{hyperref}
|
| 10 |
+
\usepackage{fancyhdr}
|
| 11 |
+
\usepackage[english]{babel}
|
| 12 |
+
\usepackage{tabularx}
|
| 13 |
+
\usepackage{multicol}
|
| 14 |
+
\setlength{\multicolsep}{-3.0pt}
|
| 15 |
+
\setlength{\columnsep}{-1pt}
|
| 16 |
+
|
| 17 |
+
% FONT SETTINGS
|
| 18 |
+
\usepackage[T1]{fontenc}
|
| 19 |
+
|
| 20 |
+
% PAGE SETTINGS
|
| 21 |
+
\pagestyle{fancy}
|
| 22 |
+
\fancyhf{} % clear all header and footer fields
|
| 23 |
+
\fancyfoot{}
|
| 24 |
+
\renewcommand{\headrulewidth}{0pt}
|
| 25 |
+
\renewcommand{\footrulewidth}{0pt}
|
| 26 |
+
|
| 27 |
+
% Adjust margins
|
| 28 |
+
\addtolength{\oddsidemargin}{-0.6in}
|
| 29 |
+
\addtolength{\evensidemargin}{-0.5in}
|
| 30 |
+
\addtolength{\textwidth}{1.19in}
|
| 31 |
+
\addtolength{\topmargin}{-.7in}
|
| 32 |
+
\addtolength{\textheight}{1.4in}
|
| 33 |
+
|
| 34 |
+
\urlstyle{same}
|
| 35 |
+
|
| 36 |
+
\raggedbottom
|
| 37 |
+
\raggedright
|
| 38 |
+
\setlength{\tabcolsep}{0in}
|
| 39 |
+
|
| 40 |
+
% SECTION FORMATTING
|
| 41 |
+
\titleformat{\section}{
|
| 42 |
+
\vspace{-4pt}\scshape\raggedright\large\bfseries
|
| 43 |
+
}{}{0em}{}[\color{black}\titlerule \vspace{-5pt}]
|
| 44 |
+
|
| 45 |
+
% CUSTOM COMMANDS
|
| 46 |
+
\newcommand{\resumeItem}[1]{
|
| 47 |
+
\item\small{
|
| 48 |
+
{#1 \vspace{-2pt}}
|
| 49 |
+
}
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
\newcommand{\resumeSubheading}[4]{
|
| 53 |
+
\vspace{-2pt}\item
|
| 54 |
+
\begin{tabular*}{1.0\textwidth}[t]{l@{\extracolsep{\fill}}r}
|
| 55 |
+
\textbf{#1} & #2 \\
|
| 56 |
+
\textit{\small#3} & \textit{\small #4} \\
|
| 57 |
+
\end{tabular*}\vspace{-7pt}
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
\newcommand{\resumeSubItem}[1]{\resumeItem{#1}\vspace{-4pt}}
|
| 61 |
+
|
| 62 |
+
\renewcommand\labelitemii{$\vcenter{\hbox{\tiny$\bullet$}}$}
|
| 63 |
+
|
| 64 |
+
\newcommand{\resumeSubHeadingListStart}{\begin{itemize}[leftmargin=0.15in, label={}]}
|
| 65 |
+
\newcommand{\resumeSubHeadingListEnd}{\end{itemize}}
|
| 66 |
+
\newcommand{\resumeItemListStart}{\begin{itemize}}
|
| 67 |
+
\newcommand{\resumeItemListEnd}{\end{itemize}\vspace{-5pt}}
|
| 68 |
+
|
| 69 |
+
% WHY HIRE ME SECTION PLACEHOLDER - this will be modified by the app
|
| 70 |
+
% WHY_HIRE_ME_SECTION
|
| 71 |
+
|
| 72 |
+
\begin{document}
|
| 73 |
+
|
| 74 |
+
\begin{center}
|
| 75 |
+
\textbf{\Huge John Doe} \\ \vspace{1pt}
|
| 76 |
+
\small +1-123-456-7890 $|$ \href{mailto:john.doe@email.com}{john.doe@email.com} $|$
|
| 77 |
+
\href{https://linkedin.com/in/johndoe}{linkedin.com/in/johndoe} $|$
|
| 78 |
+
\href{https://github.com/johndoe}{github.com/johndoe}
|
| 79 |
+
\end{center}
|
| 80 |
+
|
| 81 |
+
%----------------------------------------------------------------------------------------
|
| 82 |
+
% EDUCATION
|
| 83 |
+
%----------------------------------------------------------------------------------------
|
| 84 |
+
|
| 85 |
+
\section{Education}
|
| 86 |
+
\resumeSubHeadingListStart
|
| 87 |
+
\resumeSubheading
|
| 88 |
+
{University of Technology}{City, State}
|
| 89 |
+
{Master of Science in Computer Science}{Jan 2018 -- Dec 2020}
|
| 90 |
+
\resumeSubheading
|
| 91 |
+
{University of Science}{City, State}
|
| 92 |
+
{Bachelor of Science in Computer Engineering}{Aug 2014 -- Dec 2017}
|
| 93 |
+
\resumeSubHeadingListEnd
|
| 94 |
+
|
| 95 |
+
%----------------------------------------------------------------------------------------
|
| 96 |
+
% EXPERIENCE
|
| 97 |
+
%----------------------------------------------------------------------------------------
|
| 98 |
+
|
| 99 |
+
\section{Experience}
|
| 100 |
+
\resumeSubHeadingListStart
|
| 101 |
+
|
| 102 |
+
\resumeSubheading
|
| 103 |
+
{Senior Software Engineer}{Jan 2021 -- Present}
|
| 104 |
+
{Tech Company Inc.}{City, State}
|
| 105 |
+
\resumeItemListStart
|
| 106 |
+
\resumeItem{Led development of cloud-based microservices architecture serving 100k+ users}
|
| 107 |
+
\resumeItem{Implemented CI/CD pipeline reducing deployment time by 40\%}
|
| 108 |
+
\resumeItem{Mentored junior developers and conducted code reviews}
|
| 109 |
+
\resumeItemListEnd
|
| 110 |
+
|
| 111 |
+
\resumeSubheading
|
| 112 |
+
{Software Engineer}{Jan 2018 -- Dec 2020}
|
| 113 |
+
{Software Solutions LLC}{City, State}
|
| 114 |
+
\resumeItemListStart
|
| 115 |
+
\resumeItem{Developed RESTful APIs for client applications with Python and Django}
|
| 116 |
+
\resumeItem{Optimized database queries resulting in 30\% performance improvement}
|
| 117 |
+
\resumeItem{Collaborated with cross-functional teams to design new product features}
|
| 118 |
+
\resumeItemListEnd
|
| 119 |
+
|
| 120 |
+
\resumeSubHeadingListEnd
|
| 121 |
+
|
| 122 |
+
%----------------------------------------------------------------------------------------
|
| 123 |
+
% SKILLS
|
| 124 |
+
%----------------------------------------------------------------------------------------
|
| 125 |
+
|
| 126 |
+
\section{Skills}
|
| 127 |
+
\begin{itemize}[leftmargin=0.15in, label={}]
|
| 128 |
+
\small{\item{
|
| 129 |
+
\textbf{Languages}{: Python, JavaScript, TypeScript, Java, C++, SQL} \\
|
| 130 |
+
\textbf{Frameworks}{: React, Django, Flask, Express.js, Spring Boot} \\
|
| 131 |
+
\textbf{Tools}{: Docker, Kubernetes, AWS, Git, Jenkins, Jira} \\
|
| 132 |
+
\textbf{Databases}{: PostgreSQL, MongoDB, Redis, Elasticsearch} \\
|
| 133 |
+
}}
|
| 134 |
+
\end{itemize}
|
| 135 |
+
|
| 136 |
+
%----------------------------------------------------------------------------------------
|
| 137 |
+
% PROJECTS
|
| 138 |
+
%----------------------------------------------------------------------------------------
|
| 139 |
+
|
| 140 |
+
\section{Projects}
|
| 141 |
+
\resumeSubHeadingListStart
|
| 142 |
+
\resumeSubheading
|
| 143 |
+
{Personal Website}{https://github.com/johndoe/personal-website}
|
| 144 |
+
{Full-stack web application}{Jan 2021 -- Present}
|
| 145 |
+
\resumeItemListStart
|
| 146 |
+
\resumeItem{Designed and developed a personal portfolio website using React and Node.js}
|
| 147 |
+
\resumeItem{Implemented responsive design principles for optimal display across devices}
|
| 148 |
+
\resumeItemListEnd
|
| 149 |
+
|
| 150 |
+
\resumeSubheading
|
| 151 |
+
{Task Management App}{https://github.com/johndoe/task-manager}
|
| 152 |
+
{Mobile application}{Mar 2020 -- Nov 2020}
|
| 153 |
+
\resumeItemListStart
|
| 154 |
+
\resumeItem{Built a task management application using React Native and Firebase}
|
| 155 |
+
\resumeItem{Implemented user authentication, real-time database, and push notifications}
|
| 156 |
+
\resumeItemListEnd
|
| 157 |
+
\resumeSubHeadingListEnd
|
| 158 |
+
|
| 159 |
+
\end{document}
|