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