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