File size: 23,560 Bytes
7252d8a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
import os
import pdfplumber
import google.generativeai as genai
from dotenv import load_dotenv
import json 
import gradio as gr

# --- NEW: "Dark Mode" Custom CSS ---
custom_css = """
/* A modern, clean "Dark Mode" theme */
body {
    /* A dark gradient background */
    background: linear-gradient(135deg, #1e1e1e 0%, #121212 100%);
    font-family: 'Inter', 'Segoe UI', 'Roboto', sans-serif;
}

/* Style the main app container with a "dark glass" effect */
.gradio-container {
    border: none !important;
    border-radius: 12px !important;
    box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.3) !important;
    background-color: rgba(30, 30, 30, 0.85) !important;
    backdrop-filter: blur(10px) !important;
    border: 1px solid rgba(255, 255, 255, 0.1) !important;
}

/* Style the primary 'generate' buttons (Blue stands out well on dark) */
button[data-testid="button-primary"] {
    background: linear-gradient(90deg, #3A7BD5 0%, #00D2FF 100%);
    color: white;
    border-radius: 8px;
    font-weight: bold;
    box-shadow: 0 4px 14px 0 rgba(0, 118, 255, 0.39);
    border: none !important;
    transition: all 0.3s ease;
}
button[data-testid="button-primary"]:hover {
    box-shadow: 0 6px 20px 0 rgba(0, 118, 255, 0.5);
    transform: translateY(-2px);
}

/* --- FIX FOR TAB TITLES --- */
[data-testid="tab-button"] {
    color: #a0a0a0 !important; /* Light grey for unselected tabs */
    font-weight: 600 !important;
}
[data-testid="tab-button"].selected {
    color: #ffffff !important; /* White for selected tab */
    border-bottom: 2px solid #00D2FF !important; /* Accent color for the underline */
}

/* Style ALL markdown boxes (inputs and outputs) */
[data-testid="markdown"] {
    background-color: #2a2a2a !important; /* Dark grey for boxes */
    border-radius: 8px !important;
    border: 1px solid #444 !important;
    padding: 20px !important;
    box-shadow: 0 2px 4px 0 rgba(0,0,0,0.1);
}

/* Force all text within markdown components to be light */
[data-testid="markdown"] p, 
[data-testid="markdown"] h1, 
[data-testid="markdown"] h2, 
[data-testid="markdown"] h3, 
[data-testid="markdown"] li, 
[data-testid="markdown"] ol, 
[data-testid="markdown"] ul {
    color: #e0e0e0 !important; /* Light grey text */
}

/* Style the input textboxes and file upload */
[data-testid="textbox"] textarea, .gradio-file {
    background-color: #2a2a2a !important;
    border-radius: 8px !important;
    border: 1px solid #444 !important;
    color: #e0e0e0 !important; /* Make typed text light */
}
/* Style the labels for inputs (e.g., "Paste the Job Description Here") */
.gradio-form > * > label {
    color: #a0a0a0 !important;
    font-weight: 500 !important;
}
"""

# --- (All 6 Agents and Helper Functions) ---
# (No changes to the agent functions themselves)

def setup_api_key():
    """
    Loads the Google API key from the .env file and configures the SDK.
    """
    try:
        load_dotenv() # Loads environment variables from .env
        api_key = os.getenv("GOOGLE_API_KEY")
        
        if not api_key:
            print("Error: GOOGLE_API_KEY not found.")
            print("Please create a .env file in the project root and add:")
            print("GOOGLE_API_KEY=YOUR_API_KEY_HERE")
            return False
            
        genai.configure(api_key=api_key)
        print("API Key configured successfully.")
        return True
        
    except Exception as e:
        print(f"Error during API configuration: {e}")
        return False

def extract_text_from_file(file_path):
    """
    Extracts text from an uploaded file (.pdf or .txt).
    """
    text = ""
    try:
        file_extension = os.path.splitext(file_path)[1].lower()

        if file_extension == '.pdf':
            print(f"Extracting text from PDF: {file_path}")
            with pdfplumber.open(file_path) as pdf:
                for i, page in enumerate(pdf.pages):
                    page_text = page.extract_text()
                    if page_text:
                        text += page_text + "\n"
            print("PDF extraction complete.")
            
        elif file_extension == '.txt':
            print(f"Extracting text from TXT: {file_path}")
            with open(file_path, 'r', encoding='utf-8') as f:
                text = f.read()
            print("TXT extraction complete.")
            
        else:
            return "Unsupported file format. Please upload a .txt or .pdf file."
        
        if not text.strip():
            return "Error: File is empty or text could not be extracted."
            
        return text
    
    except Exception as e:
        print(f"Error reading file {file_path}: {e}")
        return f"Error reading file. It may be corrupted or in an unsupported format."

def analyze_job_description(jd_text):
    """
    Agent 1: Analyzes the job description (JD).
    """
    model = genai.GenerativeModel('models/gemini-flash-latest')
    prompt = f"""
    You are a Senior Technical Recruiter. Analyze the following job description (JD)
    and extract the most critical information.
    
    Return your analysis as a JSON object, and NOTHING ELSE. Do not add "```json".
    
    The JSON structure must be:
    {{
      "job_title": "string",
      "company": "string",
      "key_responsibilities": ["list", "of", "strings"],
      "hard_skills_keywords": ["list", "of", "tech", "skills"],
      "soft_skills_keywords": ["list", "of", "interpersonal", "skills"],
      "company_tone": "e.g., 'Formal & Corporate', 'Fast-paced & Startup'"
    }}
    
    Job Description Text:
    ---
    {jd_text}
    ---
    """
    try:
        print("\nSending JD to AI Recruiter Agent...")
        response = model.generate_content(prompt)
        cleaned_response_text = response.text.strip().replace("```json\n", "").replace("\n```", "").strip()
        print("AI analysis complete.")
        jd_analysis = json.loads(cleaned_response_text)
        return jd_analysis
    except Exception as e:
        print(f"Error during AI analysis (Recruiter Agent): {e}")
        return None

def analyze_resume(resume_text, jd_analysis_json):
    """
    Agent 2: Analyzes the resume against the JD's analysis.
    """
    model = genai.GenerativeModel('models/gemini-flash-latest')
    jd_analysis_string = json.dumps(jd_analysis_json, indent=2)
    prompt = f"""
    You are an expert Career Coach. You are given a user's resume and a JSON analysis
    of their target job. Your task is to find all relevant experiences and identify gaps.
    
    Return your analysis as a JSON object, and NOTHING ELSE. Do not add "```json".
    
    The JSON structure must be:
    {{
      "matching_experiences": ["list of text snippets from the resume that are highly relevant"],
      "quantifiable_achievements_found": ["list of bullet points from the resume that already have numbers"],
      "critical_gaps": ["list of key hard skills or responsibilities from the JD that are NOT mentioned in the resume"]
    }}
    
    ---
    Target Job Analysis (JSON):
    {jd_analysis_string}
    ---
    User's Resume Text:
    {resume_text}
    ---
    """
    try:
        print("\nSending Resume and JD to AI Career Coach Agent...")
        response = model.generate_content(prompt)
        cleaned_response_text = response.text.strip().replace("```json\n", "").replace("\n```", "").strip()
        print("AI career coach analysis complete.")
        resume_analysis = json.loads(cleaned_response_text)
        return resume_analysis
    except Exception as e:
        print(f"Error during AI analysis (Career Coach Agent): {e}")
        return None

def generate_tailored_resume(resume_text, jd_analysis_json, resume_analysis_json):
    """
    Agent 3: The "Master Rewrite Agent."
    """
    model = genai.GenerativeModel('models/gemini-flash-latest')
    jd_analysis_string = json.dumps(jd_analysis_json, indent=2)
    resume_analysis_string = json.dumps(resume_analysis_json, indent=2)
    prompt = f"""
    You are a world-class Professional Resume Writer. Your task is to rewrite the "Experience"
    section of the resume to align *perfectly* with a target job.
    
    **CRITICAL RULES:**
    1.  **Do NOT invent new experiences.** You must only rewrite and re-phrase the
        *existing* experience from the original resume.
    2.  Integrate the `hard_skills_keywords` from the Job Analysis naturally into the bullet points.
    3.  Rewrite weak bullet points to use the **STAR method** (Situation, Task, Action, Result)
        and quantify achievements where possible.
    4.  Reflect the `company_tone` from the Job Analysis in your writing style.
    5.  **Output *only* the new, fully rewritten 'Experience' section** in clean
        Markdown format. Do not add *any* other text, headings, or explanations.
    
    ---
    [Target Job Analysis (JSON)]
    {jd_analysis_string}
    ---
    [Career Coach's Gap Analysis (JSON)]
    {resume_analysis_string}
    ---
    [Original Resume Text]
    {resume_text}
    ---
    
    Provide the rewritten "Experience" section in Markdown:
    """
    try:
        print("\nSending all data to Master Rewrite Agent...")
        response = model.generate_content(prompt)
        print("Master rewrite complete.")
        return response.text.strip()
    except Exception as e:
        print(f"Error during AI analysis (Rewrite Agent): {e}")
        return None

def generate_ats_report(tailored_resume_text, jd_analysis_json):
    """
    Agent 4: The "ATS Scorecard Agent."
    """
    model = genai.GenerativeModel('models/gemini-flash-latest')
    jd_analysis_string = json.dumps(jd_analysis_json, indent=2)
    
    prompt = f"""
    You are an ATS (Applicant Tracking System) scanner. Your task is to generate a
    'Tailor Report' in Markdown format that scores the "New Resume Section" against
    the "Target Job Analysis."
    
    **Output Format (Must be Markdown):**
    
    ### Your 'Tailor' Report
    
    **ATS Match Score:** 85%
    
    **Keywords Hit:**
    - Python
    - Django
    
    **Keywords Missing:**
    - Flask
    - Data Analytics
    
    **Suggestion:** Great job! Consider adding a project or skill that mentions 'Flask'.
    
    ---
    [Target Job Analysis (JSON)]
    {jd_analysis_string}
    ---
    [New Resume Section]
    {tailored_resume_text}
    ---
    
    Now, generate the 'Tailor Report' in Markdown, and NOTHING ELSE.
    """
    
    try:
        print("\nSending data to ATS Scorecard Agent...")
        response = model.generate_content(prompt)
        print("ATS report complete.")
        return response.text.strip()
    except Exception as e:
        print(f"Error during AI analysis (ATS Agent): {e}")
        return None

def generate_cover_letter(resume_text, jd_analysis_json, resume_analysis_json):
    """
    Agent 5: The "Cover Letter Agent."
    """
    
    model = genai.GenerativeModel('models/gemini-flash-latest')
    
    jd_analysis_string = json.dumps(jd_analysis_json, indent=2)
    resume_analysis_string = json.dumps(resume_analysis_json, indent=2)

    prompt = f"""
    You are a world-class Professional Resume Writer and Career Coach.
    Your task is to write a compelling, professional cover letter for a job applicant
    based on their resume and a target job description.
    
    **CRITICAL RULES:**
    1.  **Tone:** The tone must be professional, confident, and aligned with the `company_tone`
        from the Job Analysis.
    2.  **Structure:** Follow a standard cover letter format (Salutation, Introduction, Body, Conclusion, Sign-off).
    3.  **Body Paragraphs:**
        * In the first body paragraph, highlight the applicant's skills that
            match the `hard_skills_keywords` and `key_responsibilities`.
        * In the second body paragraph, use the `matching_experiences` to provide a
            specific example or story that proves their qualification.
        * Address any `critical_gaps` by framing them positively, e.g., "While my
            direct experience with 'Flask' is developing, my proven ability to master
            'Django' and other Python frameworks demonstrates my capacity to learn quickly..."
    4.  **Do NOT invent new experiences.** You must only use information from the
        "Original Resume Text" and the analyses.
    5.  **Output *only* the cover letter** in clean Markdown format. Do not add
        any other text, headings, or explanations.
    
    ---
    [Target Job Analysis (JSON)]
    {jd_analysis_string}
    ---
    [Career Coach's Gap Analysis (JSON)]
    {resume_analysis_string}
    ---
    [Original Resume Text]
    {resume_text}
    ---
    
    Now, provide the complete, professional cover letter in Markdown:
    """

    try:
        print("\nSending all data to Cover Letter Agent...")
        response = model.generate_content(prompt)
        print("Cover letter generation complete.")
        return response.text.strip()
        
    except Exception as e:
        print(f"Error during AI analysis (Cover Letter Agent): {e}")
        return None

def generate_interview_prep(jd_analysis_json, resume_analysis_json):
    """
    Agent 6: The "Hiring Manager Agent."
    Generates custom interview questions based on the job and the candidate's gaps.
    """
    
    model = genai.GenerativeModel('models/gemini-flash-latest')
    
    jd_analysis_string = json.dumps(jd_analysis_json, indent=2)
    resume_analysis_string = json.dumps(resume_analysis_json, indent=2)

    prompt = f"""
    You are a senior Hiring Manager preparing to interview a candidate. You are given
    an analysis of the job and an analysis of the candidate's resume.
    
    Your task is to generate a custom "Interview Prep Sheet" in Markdown.
    
    **Instructions:**
    1.  Create 2-3 **Behavioral Questions** based on the `soft_skills_keywords`.
    2.  Create 2-3 **Technical Questions** based on the `hard_skills_keywords`.
    3.  Create 1-2 **Gap-Based Questions** based on the `critical_gaps`. These are the
        most important questions to ask. (e.g., "I see you have experience in X, but
        this role requires Y. Can you tell me how you'd bridge that gap?")
    4.  For *each* question, provide a brief **"Hint for a strong answer"** that tells
        the user what the interviewer is *really* looking for.
    
    **Output *only* the prep sheet** in clean Markdown.
    
    ---
    [Target Job Analysis (JSON)]
    {jd_analysis_string}
    ---
    [Career Coach's Gap Analysis (JSON)]
    {resume_analysis_string}
    ---
    
    Now, provide the complete "Interview Prep Sheet" in Markdown:
    """

    try:
        print("\nSending all data to Hiring Manager Agent...")
        response = model.generate_content(prompt)
        print("Interview prep generation complete.")
        return response.text.strip()
        
    except Exception as e:
        print(f"Error during AI analysis (Hiring Manager Agent): {e}")
        return None


# --- (Pipeline 1: Resume Tailor) ---
def tailor_resume_pipeline(resume_file, job_description):
    """
    Main controller for the "Resume Tailor" tab.
    Runs the full 4-agent pipeline (Agents 1, 2, 3, 4).
    """
    if not setup_api_key():
        return "Error: API Key is not configured. Please check your .env file.", ""
        
    print("--- RESUME TAILOR PIPELINE INITIATED ---")
    print("Step 1: Extracting text...")
    if resume_file is None:
        return "Error: Please upload a resume file.", ""
    resume_text = extract_text_from_file(resume_file.name)
    if "Error" in resume_text or not resume_text:
        return f"Could not process the resume file. Error: {resume_text}", ""
    
    if not job_description:
        return "Error: Please paste the job description.", ""
        
    print("Step 2: Analyzing job description...")
    jd_data = analyze_job_description(job_description)
    if not jd_data:
        return "The AI could not analyze the job description. Please try again.", ""
        
    print("Step 3: Analyzing resume...")
    resume_data = analyze_resume(resume_text, jd_data)
    if not resume_data:
        return "The AI could not analyze the resume. Please try again.", ""
        
    print("Step 4: Generating tailored resume...")
    tailored_resume = generate_tailored_resume(resume_text, jd_data, resume_data)
    if not tailored_resume:
        return "The AI failed to generate the final resume. Please try again.", ""

    print("Step 5: Generating ATS report...")
    ats_report = generate_ats_report(tailored_resume, jd_data)
    if not ats_report:
        ats_report = "Error: Could not generate ATS report."

    print("Resume pipeline complete! Returning 2 outputs.")
    return tailored_resume, ats_report


# --- (Pipeline 2: Cover Letter) ---
def generate_cover_letter_pipeline(resume_file, job_description):
    """
    Main controller for the "Cover Letter" tab.
    Runs a 3-agent pipeline (Agents 1, 2, 5).
    """
    if not setup_api_key():
        return "Error: API Key is not configured. Please check your .env file."
        
    print("--- COVER LETTER PIPELINE INITIATED ---")
    print("Step 1: Extracting text...")
    if resume_file is None:
        return "Error: Please upload a resume file."
    resume_text = extract_text_from_file(resume_file.name)
    if "Error" in resume_text or not resume_text:
        return f"Could not process the resume file. Error: {resume_text}"
    
    if not job_description:
        return "Error: Please paste the job description."
        
    print("Step 2: Analyzing job description...")
    jd_data = analyze_job_description(job_description)
    if not jd_data:
        return "The AI could not analyze the job description. Please try again."
        
    print("Step 3: Analyzing resume...")
    resume_data = analyze_resume(resume_text, jd_data)
    if not resume_data:
        return "The AI could not analyze the resume. Please try again."
        
    print("Step 4: Generating cover letter...")
    cover_letter = generate_cover_letter(resume_text, jd_data, resume_data)
    if not cover_letter:
        return "The AI failed to generate the cover letter. Please try again."

    print("Cover letter pipeline complete! Returning 1 output.")
    return cover_letter


# --- (Pipeline 3: Interview Prep) ---
def generate_interview_prep_pipeline(resume_file, job_description):
    """
    Main controller for the "Interview Prep" tab.
    Runs a 3-agent pipeline (Agents 1, 2, 6).
    """
    if not setup_api_key():
        return "Error: API Key is not configured. Please check your .env file."
        
    print("--- INTERVIEW PREP PIPELINE INITIATED ---")
    print("Step 1: Extracting text...")
    if resume_file is None:
        return "Error: Please upload a resume file."
    resume_text = extract_text_from_file(resume_file.name)
    if "Error" in resume_text or not resume_text:
        return f"Could not process the resume file. Error: {resume_text}"
    
    if not job_description:
        return "Error: Please paste the job description."
        
    print("Step 2: Analyzing job description...")
    jd_data = analyze_job_description(job_description)
    if not jd_data:
        return "The AI could not analyze the job description. Please try again."
        
    print("Step 3:Analyzing resume...")
    resume_data = analyze_resume(resume_text, jd_data)
    if not resume_data:
        return "The AI could not analyze the resume. Please. Please try again."
        
    print("Step 4: Generating interview prep...")
    interview_prep = generate_interview_prep(jd_data, resume_data) # Note: Doesn't need resume_text
    if not interview_prep:
        return "The AI failed to generate the interview prep. Please try again."

    print("Interview prep pipeline complete! Returning 1 output.")
    return interview_prep


# --- FINAL Gradio Web Interface (with 3 Tabs + Custom UI) ---
# We use gr.themes.Base() as our starting point and apply our CSS
with gr.Blocks(theme=gr.themes.Base(), css=custom_css) as demo:
    gr.Markdown(
        """
        <div style="text-align: center; padding: 20px 0;">
            <h1 style="font-size: 2.5em; font-weight: 700; color: #ffffff;">
                🤖 AI-Powered Job Application Suite
            </h1>
            <p style="font-size: 1.2em; color: #a0a0a0;">
                From Resume to Interview, get the AI-powered edge you need.
            </p>
        </div>
        """
    )
    
    with gr.Tabs():
        # --- Tab 1: Resume Tailor ---
        with gr.TabItem("1. Resume Tailor"):
            gr.Markdown("Upload your resume and paste a job description to get a tailored 'Experience' section and an ATS report.")
            with gr.Row():
                with gr.Column(scale=1):
                    resume_file_input_1 = gr.File(label="Upload Your Master Resume (.pdf or .txt)")
                    job_description_input_1 = gr.Textbox(lines=15, label="Paste the Job Description Here")
                    submit_button_1 = gr.Button("Tailor My Resume!", variant="primary")
                with gr.Column(scale=2):
                    tailored_resume_output = gr.Markdown(label="Your New, Tailored Resume Section")
                    ats_report_output = gr.Markdown(label="Your 'Tailor' Report")
            
            submit_button_1.click(
                fn=tailor_resume_pipeline,
                inputs=[resume_file_input_1, job_description_input_1],
                outputs=[tailored_resume_output, ats_report_output]
            )

        # --- Tab 2: Cover Letter Generator ---
        with gr.TabItem("2. Cover Letter Generator"):
            gr.Markdown("Upload your resume and paste a job description to generate a custom cover letter in seconds.")
            with gr.Row():
                with gr.Column(scale=1):
                    resume_file_input_2 = gr.File(label="Upload Your Master Resume (.pdf or .txt)")
                    job_description_input_2 = gr.Textbox(lines=15, label="Paste the Job Description Here")
                    submit_button_2 = gr.Button("Generate My Cover Letter!", variant="primary")
                with gr.Column(scale=2):
                    cover_letter_output = gr.Markdown(label="Your New, Generated Cover Letter")

            submit_button_2.click(
                fn=generate_cover_letter_pipeline,
                inputs=[resume_file_input_2, job_description_input_2],
                outputs=[cover_letter_output]
            )
            
        # --- Tab 3: Interview Prep ---
        with gr.TabItem("3. Interview Prep"):
            gr.Markdown("Upload your resume and paste a job description to get a custom list of interview questions and answer hints.")
            with gr.Row():
                with gr.Column(scale=1):
                    resume_file_input_3 = gr.File(label="Upload Your Master Resume (.pdf or .txt)")
                    job_description_input_3 = gr.Textbox(lines=15, label="Paste the Job Description Here")
                    submit_button_3 = gr.Button("Generate My Prep Sheet!", variant="primary")
                with gr.Column(scale=2):
                    interview_prep_output = gr.Markdown(label="Your Custom Interview Prep Sheet")

            submit_button_3.click(
                fn=generate_interview_prep_pipeline,
                inputs=[resume_file_input_3, job_description_input_3],
                outputs=[interview_prep_output]
            )

print("Launching the AI Job Application Suite (v6.0 DARK MODE)...")
# Added share=True so you can easily open it on your phone or share it
demo.launch(share=True)