File size: 26,792 Bytes
38c327b
a6db53c
b82d535
1142c0d
 
38c327b
a6db53c
 
 
 
 
 
38c327b
 
a6db53c
 
38c327b
a6db53c
 
 
 
 
 
 
 
 
 
 
 
1142c0d
a6db53c
 
 
 
1142c0d
b82d535
a6db53c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b82d535
 
 
 
 
1142c0d
 
 
a6db53c
 
 
 
b82d535
a6db53c
1142c0d
a6db53c
 
 
 
 
 
1142c0d
a6db53c
 
 
 
 
 
 
 
 
 
 
1142c0d
a6db53c
 
38c327b
a6db53c
 
 
1142c0d
a6db53c
 
 
38c327b
a6db53c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
be3930a
1142c0d
be3930a
38c327b
be3930a
 
 
38c327b
 
a6db53c
1142c0d
 
 
a6db53c
 
 
 
 
be3930a
 
a6db53c
1142c0d
a6db53c
 
 
 
 
be3930a
a6db53c
1142c0d
a6db53c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1142c0d
 
a6db53c
38c327b
a6db53c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30543fe
a6db53c
 
 
 
 
 
30543fe
a6db53c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30543fe
 
a6db53c
30543fe
a6db53c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1142c0d
a6db53c
 
 
 
 
 
 
 
 
 
 
 
be3930a
a6db53c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
be3930a
 
 
 
 
a6db53c
be3930a
 
a6db53c
 
 
 
 
 
 
be3930a
a6db53c
 
be3930a
a6db53c
 
 
 
 
 
 
 
 
 
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
import json
import os
import requests
import streamlit as st
from datetime import datetime
from docx import Document
from io import BytesIO
from PyPDF2 import PdfReader, PdfWriter

# Consider using a more robust environment variable loading mechanism for production
from dotenv import load_dotenv
load_dotenv()

# ------------------------------------------------------------------------------
# 🌟 ULTIMATE AI-POWERED IMPORT OS - "ResumeForge Pro" 🌟
# Unleash the Power of AI for Career Advancement!
# ------------------------------------------------------------------------------
# This is not just an import statement, it's a portal to career empowerment.
# It combines cutting-edge AI, meticulous resume craftsmanship, and an intuitive UI.

# ==============================================================================
# πŸš€ CONFIGURATION - API KEYS, ENDPOINTS, & MODEL SELECTION πŸš€
# ==============================================================================
#  Ensure your GROQ_API key is securely stored. For development, use environment variables.
#  For production, consider secrets management solutions.
GROQ_API_KEY = os.getenv("GROQ_API_KEY") # Added correct env variable name

#  Define the API endpoint for the Groq service.  This provides flexibility
#  to switch to different Groq deployments if needed.
GROQ_ENDPOINT = "https://api.groq.com/openai/v1/chat/completions"

#  Choose the most appropriate Llama 3.3 model variant for your needs.
#  "llama-3.3-70b-versatile" offers a balance of capabilities, but other
#  variants might be better suited for specific tasks or resource constraints.
GROQ_MODEL = "llama-3.3-70b-versatile"

# ==============================================================================
# πŸ”₯ API HANDLER FOR GROQ AI - ROBUST AND RESILIENT πŸ›‘οΈ
# ==============================================================================
def call_groq_api(messages, temperature=0.7, max_tokens=1024, top_p=0.95, frequency_penalty=0.0, presence_penalty=0.0):
    """
    Handles API calls to Groq's Llama 3.3 model with comprehensive error handling,
    parameter tuning, and advanced logging.

    Args:
        messages (list): A list of message dictionaries, representing the conversation history.
                         Each dictionary should have 'role' (e.g., 'system', 'user', 'assistant')
                         and 'content' keys.
        temperature (float):  Controls the randomness of the output (0.0 - deterministic, 1.0 - very random).
                              Lower values are suitable for tasks requiring precision (e.g., resume formatting),
                              while higher values can be used for creative tasks (e.g., cover letter generation).
                              Defaults to 0.7.
        max_tokens (int):     The maximum number of tokens to generate in the response.  Adjust this
                              based on the expected length of the output to balance completeness and cost.
                              Defaults to 1024.
        top_p (float):       Nucleus sampling parameter.  Similar to temperature but controls the cumulative
                              probability of the tokens to sample from.  A higher value allows for more
                              diverse outputs. Defaults to 0.95.
        frequency_penalty (float):  Penalizes new tokens based on their existing frequency in the text so far.
                                     Encourages the model to use novel words and phrases. Defaults to 0.0.
        presence_penalty (float):   Penalizes new tokens that already appear in the text so far, regardless of frequency.
                                     Discourages the model from repeating the same topics or ideas. Defaults to 0.0.

    Returns:
        str: The generated text content from the API response, or None if the API call fails.
    """

    headers = {
        "Authorization": f"Bearer {GROQ_API_KEY}",
        "Content-Type": "application/json"
    }
    payload = {
        "model": GROQ_MODEL,
        "messages": messages,
        "temperature": temperature,
        "max_tokens": max_tokens,
        "top_p": top_p,
        "frequency_penalty": frequency_penalty,
        "presence_penalty": presence_penalty
    }

    try:
        st.sidebar.write(f"**API Request Payload:**\n\n{json.dumps(payload, indent=2)}")  # Log the API payload
        response = requests.post(GROQ_ENDPOINT, headers=headers, json=payload, timeout=25) # Increased timeout for potentially long requests
        response.raise_for_status()  # Raise HTTPError for bad responses (4xx or 5xx)
        response_json = response.json()
        st.sidebar.write(f"**API Response:**\n\n{json.dumps(response_json, indent=2)}")  # Log the entire response
        return response_json["choices"][0]["message"]["content"].strip()
    except requests.exceptions.RequestException as e:
        st.error(f"❌ API Request Failed: {e} - Please ensure your API key is valid and Groq's service is operational.")
        st.error(f"Detailed Error: {e}") # Provide a detailed error message
        return None
    except KeyError as e:
        st.error(f"❌ Error parsing API response: Missing key {e}. Check the API response format.")
        return None
    except json.JSONDecodeError as e:
        st.error(f"❌ Error decoding JSON response: {e}. The API might be returning invalid JSON.")
        return None
    except Exception as e:
        st.error(f"❌ An unexpected error occurred: {e}")
        return None
    finally:
        st.sidebar.write("--- API Request Complete ---") # Add a clear marker for request completion

# ==============================================================================
# πŸ“„ FILE PROCESSING - PDF, DOCX, TXT - WITH EXTENSIVE VALIDATION πŸ›‘οΈ
# ==============================================================================
def extract_resume_text(file_obj):
    """
    Extracts text from uploaded resumes (PDF, DOCX, TXT) with robust error handling,
    file type validation, and size limitations.

    Args:
        file_obj (streamlit.UploadedFile):  The uploaded file object.

    Returns:
        str: The extracted text from the resume, or None if extraction fails.
    """
    MAX_FILE_SIZE_MB = 5 # Set a reasonable file size limit
    try:
        file_bytes = file_obj.read()
        file_size_mb = len(file_bytes) / (1024 * 1024)
        if file_size_mb > MAX_FILE_SIZE_MB:
            st.error(f"❌ File size exceeds the limit of {MAX_FILE_SIZE_MB} MB. Please upload a smaller file.")
            return None

        file_obj.seek(0)  # Reset file pointer to the beginning
        ext = os.path.splitext(file_obj.name)[-1].lower()

        if ext == ".pdf":
            try:
                reader = PdfReader(BytesIO(file_bytes)) # Use BytesIO to handle in-memory file
                text = "\n".join(page.extract_text() for page in reader.pages if page.extract_text())
                return text
            except Exception as e:
                st.error(f"❌ Error extracting text from PDF: {e}")
                return None
        elif ext in [".docx", ".doc"]:
            try:
                document = Document(BytesIO(file_bytes))
                text = "\n".join([para.text for para in document.paragraphs])
                return text
            except Exception as e:
                st.error(f"❌ Error extracting text from DOCX: {e}")
                return None
        elif ext == ".txt":
            try:
                return file_bytes.decode("utf-8", errors="ignore") # Handle encoding issues
            except Exception as e:
                st.error(f"❌ Error decoding text file: {e}")
                return None
        else:
            st.warning(f"⚠️ Unsupported file type: {ext}. Please upload a PDF, DOCX, or TXT file.")
            return None

    except Exception as e:
        st.error(f"❌ An unexpected error occurred during file processing: {e}")
        return None

# ==============================================================================
# 🎯 AI-POWERED RESUME GENERATION - ATS OPTIMIZED & STRUCTURED πŸš€
# ==============================================================================
def generate_resume(first_name, last_name, location, work_experience, school_experience, skills, contact_number, email_address, linkedin_profile):
    """
    Generates a structured, ATS-friendly resume with enhanced formatting,
    detailed instructions to the AI, and incorporates contact information.

    Args:
        first_name (str): The candidate's first name.
        last_name (str): The candidate's last name.
        location (str): The candidate's location.
        work_experience (str): A detailed description of work experience.
        school_experience (str): Details of educational background.
        skills (str): A comma-separated list of skills.
        contact_number (str): Candidate's phone number.
        email_address (str): Candidate's email address.
        linkedin_profile (str): Candidate's LinkedIn profile URL.

    Returns:
        str: The generated resume text.
    """

    candidate_data = json.dumps({
        "full_name": f"{first_name} {last_name}",  # Added full_name
        "location": location,
        "contact_number": contact_number,  # Include contact_number
        "email_address": email_address,  # Include email_address
        "linkedin_profile": linkedin_profile,  # Include linkedin_profile
        "work_experience": work_experience,
        "school_experience": school_experience,
        "skills": skills,
    }, indent=2)

    messages = [
        {"role": "system", "content": """
        You are an expert resume writer with extensive experience in Applicant Tracking Systems (ATS) optimization and modern resume design principles.
        Your goal is to create a compelling and highly effective resume that showcases the candidate's strengths and experiences in a clear, concise, and ATS-friendly format.

        You are an expert in using bullet points to quantify experience with metrics and achievements.

        You will focus on extracting information given in work experience, education, and skills to accurately tailor the resume
        """},
        {"role": "user", "content": f"""
        Generate a **highly professional**, **ATS-optimized resume** using the following structured information. Focus on:
        *   **Quantifiable Achievements:** Emphasize results and use numbers/metrics wherever possible.
        *   **Keywords:** Incorporate industry-specific keywords naturally.
        *   **Action Verbs:** Start each bullet point with strong action verbs.
        *   **Conciseness:** Keep sentences short and to the point.
        *   **Use the info provided and do not make things up.**

        {candidate_data}

        **Resume Structure Requirements:**

        1.  **Contact Information:**
            *   Full Name (prominently displayed)
            *   Phone Number
            *   Email Address
            *   LinkedIn Profile URL (if provided, ensure it's valid)
            *   Location (City, State - no full address)

        2.  **Summary/Profile:**
            *   A brief (3-4 sentence) summary highlighting key skills, experience, and career goals. Tailor this to be generic enough to apply to several positions.

        3.  **Work Experience:**
            *   Job Title
            *   Company Name
            *   Dates of Employment (Month Year - Month Year)
            *   **Responsibilities and Achievements:** Use bullet points to describe responsibilities and, most importantly, **quantifiable achievements**.
                *   Example: "Increased sales by 25% in Q3 by implementing a new marketing strategy."
                *   Example: "Reduced customer support tickets by 15% by improving the onboarding process."
            *   Order experiences from most recent to oldest.

        4.  **Education:**
            *   Degree Name
            *   Major (if applicable)
            *   University Name
            *   Graduation Date (Month Year) or Expected Graduation Date
            *   Include relevant coursework or academic achievements (optional).

        5.  **Skills:**
            *   List both technical and soft skills relevant to the candidate's field.
            *   Categorize skills (e.g., "Technical Skills," "Soft Skills," "Programming Languages").

        6.  **Certifications/Awards (Optional):**
            *   List any relevant certifications or awards.

        **Formatting Guidelines:**

        *   Use a clean and professional font (e.g., Arial, Calibri, Times New Roman) – Size 10-12.
        *   Use clear headings and subheadings.
        *   Use white space effectively to improve readability.
        *   Maintain consistent formatting throughout the document.
        *   Adhere to a one-page or two-page limit, depending on the candidate's experience level.
        *   Make sure to include enough information so the bot can create a great resume.

        **IMPORTANT:** The resume MUST be ATS-compatible. Avoid using tables, columns, or graphics that can confuse ATS systems.

        **Tone:** Professional, confident, and results-oriented.
        """}
    ]
    return call_groq_api(messages, temperature=0.4, max_tokens=2048)  # Lower temperature for more precision

# ==============================================================================
# ✍️ AI-POWERED COVER LETTER GENERATION - PERSUASIVE & TAILORED πŸš€
# ==============================================================================
def generate_cover_letter(candidate_json, job_description, hiring_manager_name="Hiring Manager"):
    """
    Generates a compelling cover letter using structured candidate details and
    a provided job description.

    Args:
        candidate_json (str): A JSON string containing candidate information (name, skills, experience).
        job_description (str): The text of the job description.
        hiring_manager_name (str, optional): The name of the hiring manager. Defaults to "Hiring Manager".

    Returns:
        str: The generated cover letter text.
    """
    date_str = datetime.today().strftime("%d %B %Y")
    messages = [
        {"role": "system", "content": """
        You are a world-class career advisor, adept at crafting highly persuasive and tailored cover letters.
        Your cover letters are known for their ability to capture the attention of hiring managers and showcase the candidate's
        unique qualifications and enthusiasm for the role. You are familiar with best practices in cover letter writing,
        including the importance of tailoring the content to the specific job description and highlighting measurable achievements.
        """},
        {"role": "user", "content": f"""
        Generate a **compelling and professional cover letter** using the following information:

        **Candidate Profile:** {candidate_json}

        **Job Description:** {job_description}

        **Date:** {date_str}

        **Hiring Manager Name (Salutation):** {hiring_manager_name}

        **Cover Letter Requirements:**

        1.  **Opening Paragraph (Introduction):**
            *   Start with a strong opening that grabs the reader's attention.
            *   Clearly state the position you are applying for and where you saw the job posting.
            *   Express your enthusiasm for the opportunity.

        2.  **Body Paragraphs (Skills and Experience Alignment):**
            *   Highlight 2-3 key skills or experiences that directly align with the requirements outlined in the job description.
            *   Provide specific examples of how you have demonstrated these skills and achieved measurable results in previous roles.
            *   Quantify your achievements whenever possible (e.g., "Increased sales by 20%," "Reduced costs by 15%").
            *   Showcase your understanding of the company and the role.

        3.  **Closing Paragraph (Call to Action):**
            *   Reiterate your interest in the position and your enthusiasm for the opportunity.
            *   Express your confidence in your ability to contribute to the company's success.
            *   Thank the hiring manager for their time and consideration.
            *   Include a call to action, such as requesting an interview.

        **Formatting Guidelines:**

        *   Use a professional and easy-to-read font (e.g., Arial, Calibri, Times New Roman).
        *   Keep the cover letter concise and focused (ideally, no more than one page).
        *   Use proper grammar and spelling.
        *   Address the cover letter to the hiring manager by name, if possible.
        *   If the hiring manager's name is not available, use "Dear Hiring Manager."

        **Tone:** Enthusiastic, confident, professional, and tailored.
        """}
    ]
    return call_groq_api(messages, temperature=0.5, max_tokens=1536)  # Adjusted temperature for persuasion

# ==============================================================================
# πŸ’Ύ SAVE FUNCTION
# ==============================================================================

def save_text_as_file(text, filename, file_format):
    """Saves the generated text as a downloadable file in specified format."""
    try:
        if file_format == "txt":
            # UTF-8 encoding to support special characters.
            data = text.encode('utf-8')
            st.download_button(
                label=f"Download {filename}.txt",
                data=data,
                file_name=f"{filename}.txt",
                mime="text/plain",
                help="Click to download the generated text as a plain text file.",
            )
        elif file_format == "docx":
            document = Document()
            document.add_paragraph(text)
            # Write docx to a BytesIO object for downloading.
            buffer = BytesIO()
            document.save(buffer)
            buffer.seek(0)  # Go to the beginning of the buffer so it can be read.
            st.download_button(
                label=f"Download {filename}.docx",
                data=buffer,
                file_name=f"{filename}.docx",
                mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                help="Click to download the generated text as a Word document (.docx).",
            )
        elif file_format == "pdf":
            # Creating PDF from the given text.
            from reportlab.lib.pagesizes import letter
            from reportlab.pdfgen import canvas
            # Buffer to hold the PDF in memory
            buffer = BytesIO()
            # Create the PDF object, using the buffer as its "file."
            c = canvas.Canvas(buffer, pagesize=letter)
            # Set font and size
            c.setFont('Helvetica', 12)
            textobject = c.beginText()
            textobject.setTextOrigin(50, 750)
            # Split the text into lines
            lines = text.splitlines()
            # Setting line height
            line_height = 14
            # Write each line of text
            for line in lines:
                textobject.textLine(line.strip())
                textobject.moveCursor(0, -line_height)  # Adjust line height to move down a bit

            # Finish up
            c.drawText(textobject)
            c.showPage()
            c.save()

            # Move the buffer position to the beginning
            buffer.seek(0)
            st.download_button(
                label=f"Download {filename}.pdf",
                data=buffer,
                file_name=f"{filename}.pdf",
                mime="application/pdf",
                help="Click to download the generated text as a PDF document.",
            )
        else:
            st.error("Unsupported file format. Please choose txt, docx, or pdf.")

    except Exception as e:
        st.error(f"Error generating download: {e}")


# ==============================================================================
# 🎨 STREAMLIT UI DESIGN - USER-FRIENDLY & RESPONSIVE πŸ“±
# ==============================================================================
def main():
    st.set_page_config(page_title="AI Resume & Cover Letter Generator", layout="wide")
    st.title("πŸš€ AI-Powered Resume & Cover Letter Generator")
    st.markdown("### Create a **perfect ATS-friendly Resume** and **tailored Cover Letter** using **Groq AI (Llama 3.3-70B)**")

    # Sidebar for API key and advanced settings
    with st.sidebar:
        st.header("βš™οΈ Advanced Settings")
        api_key_input = st.text_input("Groq API Key", type="password", value=GROQ_API_KEY if GROQ_API_KEY else "", help="Enter your Groq API key. Keep it safe!", key="api_key_input")

        if api_key_input:
             os.environ["GROQ_API_KEY"] = api_key_input  # Correct way to set/update env var

        model_temperature = st.slider("Model Temperature", min_value=0.0, max_value=1.0, value=0.5, step=0.05, help="Adjust the randomness of the AI's output. Lower values for more precise output.")
        model_max_tokens = st.slider("Max Tokens", min_value=256, max_value=4096, value=1024, step=128, help="The maximum number of tokens in the generated output.")
        top_p = st.slider("Top P", min_value=0.0, max_value=1.0, value=0.95, step=0.05, help="Nucleus sampling parameter. Controls the cumulative probability of the tokens to sample from.")
        frequency_penalty = st.slider("Frequency Penalty", min_value=-2.0, max_value=2.0, value=0.0, step=0.1, help="Penalizes new tokens based on their existing frequency.")
        presence_penalty = st.slider("Presence Penalty", min_value=-2.0, max_value=2.0, value=0.0, step=0.1, help="Penalizes new tokens that already appear in the text.")
        st.markdown("---")
        st.markdown("πŸ’‘ **Tip:** Adjust these settings to fine-tune the AI's performance. Lower temperature for resumes, higher for cover letters.")

    tabs = st.tabs(["πŸ“„ Cover Letter Generator", "πŸ“‘ Resume Creator"])

    # ----- COVER LETTER GENERATOR -----
    with tabs[0]:
        st.header("πŸ“„ Cover Letter Generator")

        resume_file = st.file_uploader("Upload Your Resume", type=["pdf", "docx", "txt"], help="Upload your resume in PDF, DOCX, or TXT format.")
        job_description = st.text_area("Paste Job Description", height=200, help="Paste the job description from the job posting.")
        hiring_manager_name = st.text_input("Hiring Manager Name (Optional)", value="Hiring Manager", help="Enter the name of the hiring manager if known.")

        if st.button("πŸ”Ή Generate Cover Letter"):
            if not os.getenv("GROQ_API_KEY"):
                st.error("Please enter your Groq API key in the sidebar.")
                return
            if resume_file and job_description.strip():
                with st.spinner("✨ Processing resume..."):
                    resume_text = extract_resume_text(resume_file)
                    if resume_text:
                        # Dummy data, consider extracting dynamically from resume.
                        candidate_json = json.dumps({
                            "first_name": "Jane",
                            "last_name": "Doe",
                            "location": "San Francisco, CA",
                            "work_experience": "Experienced Software Engineer with a proven track record of success.",
                            "school_experience": "Master's Degree in Computer Science from Stanford University",
                            "skills": "Python, Java, Machine Learning, Cloud Computing"
                        })
                        cover_letter = generate_cover_letter(candidate_json, job_description, hiring_manager_name)
                        if cover_letter:
                            st.success("βœ… Cover Letter Generated!")
                            st.text_area("πŸ“œ Your Cover Letter:", cover_letter, height=300)
                            filename = "cover_letter"
                            file_format = st.selectbox("Select download format:", ["txt", "docx", "pdf"])
                            save_text_as_file(cover_letter, filename, file_format)

            else:
                st.warning("⚠️ Please upload a resume and paste the job description.")

    # ----- RESUME CREATOR -----
    with tabs[1]:
        st.header("πŸ“‘ Resume Creator")

        with st.form("resume_form"):
            col1, col2 = st.columns(2)
            first_name = col1.text_input("First Name", help="Enter your first name.", value="Oluwafemi")  # Pre-filled value
            last_name = col2.text_input("Last Name", help="Enter your last name.", value="Idiakhoa")  # Pre-filled value
            location = st.text_input("Location", help="Enter your city and state.", value="Houston, Texas")  # Pre-filled value
            contact_number = st.text_input("Contact Number", help="Enter your phone number.", value="404-922-0516")  # Pre-filled value
            email_address = st.text_input("Email Address", help="Enter your email address.", value="[email protected]")  # Pre-filled value
            linkedin_profile = st.text_input("LinkedIn Profile URL", help="Enter your LinkedIn profile URL (optional).")
            work_experience = st.text_area("Work Experience", height=150, help="Describe your work experience, including job titles, company names, dates of employment, and responsibilities/achievements.", value="Verizon feb-2023")  # Pre-filled value
            school_experience = st.text_area("Education", height=150, help="Describe your educational background, including degree names, university names, and graduation dates.", value="Master in Engineering")  # Pre-filled value
            skills = st.text_area("Skills", height=100, help="List your skills, separated by commas.")
            submit = st.form_submit_button("πŸ“‘ Generate Resume")

        if submit:
            if not os.getenv("GROQ_API_KEY"):
                st.error("Please enter your Groq API key in the sidebar.")
                return

            with st.spinner("πŸ“ Creating Resume..."):
                resume_text = generate_resume(first_name, last_name, location, work_experience, school_experience, skills, contact_number, email_address, linkedin_profile)

                if resume_text:
                    st.success("βœ… Resume Generated!")
                    st.text_area("πŸ“œ Your Resume:", resume_text, height=400)

                    filename = f"{first_name}_{last_name}_resume"
                    file_format = st.selectbox("Select download format:", ["txt", "docx", "pdf"])
                    save_text_as_file(resume_text, filename, file_format)

if __name__ == "__main__":
    main()