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()