File size: 6,292 Bytes
c505ce6 50afc78 c505ce6 |
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 |
import os
import gradio as gr
from pdfminer.high_level import extract_text
from docx import Document
from groq import Groq
key = "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"
client = Groq(api_key=key)
# Function to read PDF files
def read_pdf(file_path):
return extract_text(file_path)
# Function to read DOCX files
def read_docx(file_path):
doc = Document(file_path)
return "\n".join([paragraph.text for paragraph in doc.paragraphs])
# Function to optimize CV using Llama 3.1 and Groq API
def optimize_cv_with_llama(cv_text, job_description):
try:
# Compose the prompt
system_message = (
"You are an experienced Human Resource expert with 30 years of experience working for major international companies. "
"Your task is to optimize the following CV or Resume based on the provided job description. Tailor the CV content to align "
"with the job requirements and highlight relevant skills, experiences, and achievements. Present the optimized CV in Markdown format. "
"Ensure the formatting is professional and avoid adding extra comments."
)
# Send the job description and CV text to the Groq API
completion = client.chat.completions.create(
model="meta-llama/llama-4-maverick-17b-128e-instruct",
messages=[
{"role": "system", "content": system_message},
{"role": "user", "content": f"Job Description:\n{job_description}\n\nCV:\n{cv_text}"}
],
temperature=0.7,
max_tokens=2048,
top_p=0.9,
stream=False,
)
# Return the optimized Markdown text
return ''.join([chunk.message.content for chunk in completion.choices])
except Exception as e:
return f"Error optimizing CV: {e}"
# Function to save optimized Markdown as DOCX
from markdown2 import markdown
from bs4 import BeautifulSoup
def save_markdown_to_docx(markdown_text, output_docx_path="optimized_cv.docx"):
# Convert Markdown to HTML
html_content = markdown(markdown_text)
# Parse HTML with BeautifulSoup
soup = BeautifulSoup(html_content, "html.parser")
# Create a new DOCX document
doc = Document()
# Iterate through HTML elements and map them to DOCX formatting
for element in soup.descendants:
if element.name == "h1":
para = doc.add_paragraph(element.text, style="Heading 1")
elif element.name == "h2":
para = doc.add_paragraph(element.text, style="Heading 2")
elif element.name == "h3":
para = doc.add_paragraph(element.text, style="Heading 3")
elif element.name == "ul": # Unordered list
for li in element.find_all("li"):
doc.add_paragraph(li.text, style="List Bullet")
elif element.name == "ol": # Ordered list
for li in element.find_all("li"):
doc.add_paragraph(li.text, style="List Number")
elif element.name == "p": # Paragraph
doc.add_paragraph(element.text)
elif element.name == "strong": # Bold text
para = doc.add_paragraph()
run = para.add_run(element.text)
run.bold = True
elif element.name == "em": # Italics
para = doc.add_paragraph()
run = para.add_run(element.text)
run.italic = True
elif element.name == "a": # Hyperlink
para = doc.add_paragraph(element.text) # Add the text of the hyperlink
# Add the URL as well, optionally
para.add_run(f" ({element.get('href')})").italic = True
# Save the document
doc.save(output_docx_path)
return output_docx_path
# Function to process file upload and optimization
def process_inputs(cv_file, job_description):
try:
# Extract text from uploaded file
file_path = cv_file.name
file_extension = os.path.splitext(file_path)[1].lower()
if file_extension == ".pdf":
cv_text = read_pdf(file_path)
elif file_extension == ".docx":
cv_text = read_docx(file_path)
else:
return "Unsupported file format", None
# Optimize the CV based on the job description
optimized_markdown = optimize_cv_with_llama(cv_text, job_description)
# Save the optimized Markdown as DOCX
output_docx_path = "optimized_cv.docx"
save_markdown_to_docx(optimized_markdown, output_docx_path)
return optimized_markdown, output_docx_path
except Exception as e:
return f"Error processing inputs: {e}", None
# Gradio Interface
def main():
with gr.Blocks() as app:
# Title and Description
gr.Markdown(
"""
# **AI-Powered CV or Resume Optimizer**
Optimize your CV or Resume to match job descriptions using the power of AI.
This application processes your uploaded CV along with a job description and generates a tailored, professional CV ready for submission.
"""
)
# Input components
file_input = gr.File(label="Upload Your Resume (PDF or DOCX)", file_count="single",
file_types=[".pdf", ".docx"], # <-- Ensures you can select PDF/DOCX in the picker
type="filepath" # <-- Returns a string path your code can read
)
job_description = gr.Textbox(
label="Job Description",
placeholder="Paste the job description here...",
lines=5
)
# Output components
markdown_output = gr.Markdown(label="Optimized CV Preview")
download_button = gr.File(label="Download Optimized CV (DOCX)")
# Button to process inputs
run_button = gr.Button("Optimize CV")
# Define the interaction logic
def handle_inputs(cv_file, job_description):
markdown_text, docx_path = process_inputs(cv_file, job_description)
return markdown_text, docx_path
run_button.click(
handle_inputs,
inputs=[file_input, job_description],
outputs=[markdown_output, download_button]
)
app.launch()
if __name__ == "__main__":
main() |