Spaces:
Sleeping
Sleeping
| import os | |
| import gradio as gr | |
| from pdfminer.high_level import extract_text | |
| from docx import Document | |
| from groq import Groq | |
| key = os.getenv("GroqCVs") | |
| 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="llama-3.3-70b-versatile", | |
| 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 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 CV (PDF or DOCX)") | |
| 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(debug=True) | |
| if __name__ == "__main__": | |
| main() | |