File size: 6,586 Bytes
f8387c1 95242f6 f8387c1 e98268a f8387c1 28634dd f8387c1 c9135a2 28634dd c9135a2 f8387c1 888d73b ef396f3 95242f6 888d73b 95242f6 28634dd 888d73b f8387c1 888d73b 28634dd 888d73b ef396f3 888d73b f8387c1 888d73b c9135a2 888d73b c9135a2 28634dd f8387c1 888d73b c9135a2 888d73b f8387c1 888d73b 67ff76d 888d73b 93fba37 888d73b 93fba37 888d73b 93fba37 67ff76d 28634dd 93fba37 67ff76d f8387c1 28634dd f8387c1 28634dd f8387c1 28634dd f8387c1 c9135a2 28634dd 95242f6 c9135a2 28634dd 67ff76d 28634dd ef396f3 67ff76d ef396f3 28634dd f8387c1 d422d60 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 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 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
import os
from cerebras.cloud.sdk import Cerebras
from markitdown import MarkItDown
from weasyprint import HTML
import markdown
import gradio as gr
# Ensure you get the API key from environment variables
api_key = os.environ.get("CEREBRAS_API_KEY")
# Initialize MarkItDown instance
md_converter = MarkItDown()
# Functions for resume optimization
def create_prompt(resume_string: str, jd_string: str) -> str:
"""
Creates a detailed prompt for AI-powered resume optimization based on a job description.
"""
return 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.
"""
def get_resume_response(prompt: str, api_key: str, model: str = "llama-3.3-70b", temperature: float = 0.7) -> str:
client = Cerebras(api_key=api_key)
stream = client.chat.completions.create(
messages=[
{"role": "system", "content": "Expert resume writer"},
{"role": "user", "content": prompt}
],
model=model,
stream=True,
temperature=temperature,
max_completion_tokens=1024,
top_p=1
)
response_string = ""
for chunk in stream:
response_string += chunk.choices[0].delta.content or ""
return response_string
def process_resume(resume, jd_string):
"""
Process the uploaded resume and job description, optimize it, and return the result.
"""
try:
# Read file content from the resume path
with open(resume.name, "r", encoding="utf-8") as file:
resume_string = file.read()
# Create optimization prompt
prompt = create_prompt(resume_string, jd_string)
# Generate response using AI
response_string = get_resume_response(prompt, api_key)
response_list = response_string.split("## Additional Suggestions")
# Extract new resume and suggestions for improvement
new_resume = response_list[0].strip()
suggestions = "## Additional Suggestions \n\n" + response_list[1].strip() if len(response_list) > 1 else ""
# Save the optimized resume
optimized_file_path = "resumes/optimized_resume.md"
os.makedirs("resumes", exist_ok=True) # Ensure the directory exists
with open(optimized_file_path, "w", encoding="utf-8") as f:
f.write(new_resume)
# Return the results
return resume_string, new_resume, optimized_file_path, suggestions
except Exception as e:
return f"Error processing file: {str(e)}", "", None, ""
def export_resume(new_resume):
"""
Convert a markdown resume to PDF format and save it.
Args:
new_resume (str): The resume content in markdown format
Returns:
str: A message indicating success or failure of the PDF export
"""
try:
# Convert Markdown to HTML
html_content = markdown.markdown(new_resume)
# Convert HTML to PDF and save
output_pdf_file = "resumes/optimized_resume.pdf"
os.makedirs("resumes", exist_ok=True) # Ensure the directory exists
HTML(string=html_content).write_pdf(output_pdf_file, stylesheets=['resumes/style.css'])
return output_pdf_file # Return the file path for download
except Exception as e:
return f"Failed to export resume: {str(e)} π"
# Gradio App
with gr.Blocks() as app:
gr.Markdown("# Resume Optimizer π")
gr.Markdown("Upload your resume, paste the job description, and get actionable insights!")
with gr.Row():
resume_input = gr.File(label="Upload Your Resume")
jd_input = gr.Textbox(label="Paste the Job Description Here", lines=9, interactive=True, placeholder="Paste job description...")
run_button = gr.Button("Optimize Resume π€")
with gr.Row():
before_md = gr.Markdown(label="Original Resume (Before)")
after_md = gr.Markdown(label="Optimized Resume (After)")
output_suggestions = gr.Markdown(label="Suggestions")
with gr.Row():
download_before = gr.File(label="Download Original Resume")
download_after = gr.File(label="Download Optimized Resume")
export_button = gr.Button("Export Optimized Resume as PDF π")
export_result = gr.File(label="Download PDF")
# Bindings
run_button.click(
process_resume,
inputs=[resume_input, jd_input],
outputs=[before_md, after_md, download_before, download_after, output_suggestions]
)
export_button.click(export_resume, inputs=[after_md], outputs=[export_result])
app.launch()
|