import gradio as gr
from huggingface_hub import InferenceClient
import io
from docx import Document
import os
import pymupdf
# For PDF generation
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet
# Initialize Hugging Face Inference Client
client = InferenceClient(
model="meta-llama/Meta-Llama-3-8B-Instruct",
token=os.getenv("HF_TOKEN"))
# Function to extract text from PDF
def extract_text_from_pdf(pdf_file):
try:
pdf_document = pymupdf.open(pdf_file)
text = "".join(page.get_text() for page in pdf_document)
return text.strip() or "No text could be extracted from the PDF."
except Exception as e:
return f"Error reading PDF: {e}"
# Function to extract text from DOCX
def extract_text_from_docx(docx_file):
try:
doc = Document(docx_file)
text = "\n".join(para.text for para in doc.paragraphs)
return text.strip() or "No text could be extracted from the DOCX file."
except Exception as e:
return f"Error reading DOCX: {e}"
# Function to analyze CV and generate report
def parse_cv(file, job_description):
if file is None:
return "Please upload a CV file.", "", None
try:
file_path = file.name
file_ext = os.path.splitext(file_path)[1].lower()
if file_ext == ".pdf":
extracted_text = extract_text_from_pdf(file_path)
elif file_ext == ".docx":
extracted_text = extract_text_from_docx(file_path)
else:
return "Unsupported file format. Please upload a PDF or DOCX file.", "", None
except Exception as e:
return f"Error reading file: {e}", "", None
if extracted_text.startswith("Error"):
return extracted_text, "Error during text extraction. Please check the file.", None
prompt = (
f"Analyze the CV against the job description. Provide a summary, assessment, "
f"and a score 0-10.\n\n"
f"Job Description:\n{job_description}\n\n"
f"Candidate CV:\n{extracted_text}\n"
)
try:
analysis = client.text_generation(prompt, max_new_tokens=512)
report_text = f"--- Analysis Report ---\n{analysis}"
pdf_path = create_pdf_report(report_text) # Generate PDF in the backend
return extracted_text, report_text, pdf_path
except Exception as e:
return extracted_text, f"Analysis Error: {e}", None
# Function to create PDF report
def create_pdf_report(report_text):
if not report_text.strip():
report_text = "No analysis report to convert."
pdf_path = "analysis_report.pdf"
doc = SimpleDocTemplate(pdf_path, pagesize=letter)
styles = getSampleStyleSheet()
Story = []
title = Paragraph("Analysis Report", styles['Title'])
Story.append(title)
Story.append(Spacer(1, 12))
report_paragraph = Paragraph(report_text.replace("\n", "
"), styles['BodyText'])
Story.append(report_paragraph)
doc.build(Story)
return pdf_path
# Function to process and optimize resume
def process_resume(resume_file, job_title):
if resume_file is None:
return "Please upload a resume file."
try:
file_path = resume_file.name
file_ext = os.path.splitext(file_path)[1].lower()
if file_ext == ".pdf":
resume_text = extract_text_from_pdf(file_path)
elif file_ext == ".docx":
resume_text = extract_text_from_docx(file_path)
else:
return "Unsupported file format. Please upload a PDF or DOCX file."
if resume_text.startswith("Error"):
return resume_text
prompt = (
f"Optimize the following resume for the job title: {job_title}.\n"
f"Include relevant skills, experience, and keywords related to the job title.\n\n"
f"Resume:\n{resume_text}\n"
)
optimized_resume = client.text_generation(prompt, max_new_tokens=1024)
return optimized_resume
except Exception as e:
return f"Error processing resume: {e}"
# Build the Gradio UI
demo = gr.Blocks()
with demo:
gr.Markdown("## AI-powered CV Analyzer and Optimizer")
with gr.Tab("CV Analyzer"):
gr.Markdown("### Upload your CV and provide the job description")
file_input = gr.File(label="Upload CV", file_types=[".pdf", ".docx"])
job_desc_input = gr.Textbox(label="Job Description", lines=5)
extracted_text = gr.Textbox(label="Extracted CV Content", lines=10, interactive=False)
analysis_output = gr.Textbox(label="Analysis Report", lines=10, interactive=False)
analyze_button = gr.Button("Analyze CV")
download_pdf_button = gr.File(label="Download Analysis Report PDF", interactive=False)
analyze_button.click(parse_cv, [file_input, job_desc_input], [extracted_text, analysis_output, download_pdf_button])
with gr.Tab("CV Optimizer"):
gr.Markdown("### Upload your Resume and Enter Job Title")
resume_file = gr.File(label="Upload Resume (PDF or Word)", file_types=[".pdf", ".docx"])
job_title_input = gr.Textbox(label="Job Title", lines=1)
optimized_resume_output = gr.Textbox(label="Optimized Resume", lines=20)
optimize_button = gr.Button("Optimize Resume")
optimize_button.click(process_resume, [resume_file, job_title_input], [optimized_resume_output])
if __name__ == "__main__":
demo.queue().launch()