Navya-Sree's picture
Update app.py
aa3140f verified
import gradio as gr
from datetime import datetime
from utils import generate_cover_letter
import os
# Custom CSS for modern UI
css = """
:root {
--primary: #4361ee;
--secondary: #3f37c9;
--accent: #4895ef;
--light: #f8f9fa;
--dark: #212529;
}
body {
font-family: 'Segoe UI', system-ui, sans-serif;
background: linear-gradient(135deg, #f5f7fa 0%, #e4edf5 100%);
min-height: 100vh;
margin: 0;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.header {
background: linear-gradient(rgba(0,0,0,0.7), rgba(0,0,0,0.7)), url('file/assets/header.jpg');
background-size: cover;
color: white;
padding: 2rem;
border-radius: 12px;
text-align: center;
margin-bottom: 2rem;
}
.step-card {
background: white;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.step-indicator {
display: flex;
justify-content: center;
margin-bottom: 2rem;
}
.step {
width: 36px;
height: 36px;
border-radius: 50%;
background: var(--accent);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
margin: 0 10px;
position: relative;
}
.step.active {
background: var(--secondary);
transform: scale(1.1);
}
.step:not(:last-child)::after {
content: '';
position: absolute;
width: 40px;
height: 2px;
background: #ddd;
left: 100%;
}
h2 {
color: var(--primary);
border-bottom: 2px solid var(--accent);
padding-bottom: 0.5rem;
margin-top: 0;
}
.btn-primary {
background: var(--primary) !important;
border: none !important;
padding: 12px 24px !important;
font-size: 16px !important;
border-radius: 8px !important;
transition: all 0.3s !important;
}
.btn-primary:hover {
background: var(--secondary) !important;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(67, 97, 238, 0.3) !important;
}
.output-card {
background: white;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
padding: 2rem;
margin-top: 2rem;
}
.tips {
background: #e3f2fd;
border-left: 4px solid var(--accent);
padding: 1rem;
border-radius: 4px;
font-size: 0.9rem;
}
.footer {
text-align: center;
margin-top: 2rem;
color: #6c757d;
font-size: 0.9rem;
}
"""
# Initialize steps
current_step = gr.State(1)
def next_step():
return current_step.value + 1
def generate_letter(job_desc, resume, name, email, phone, company, manager, tone):
# Generate cover letter body using NLP
letter_body = generate_cover_letter(job_desc, resume, tone)
# Format final letter
today = datetime.today().strftime("%B %d, %Y")
return f"""
{today}
{manager or "Hiring Manager"}
{company or "Company Name"}
Dear {manager.split()[0] + ',' if manager else "Hiring Manager,"}
{letter_body}
Sincerely,
{name}
{email} | {phone}
""", current_step.value + 1
def update_step(step):
return step
with gr.Blocks(css=css, title="AI Cover Letter Generator") as demo:
current_step = gr.Variable(1)
with gr.Column(elem_classes=["container"]):
# Header section
with gr.Column(elem_classes=["header"]):
gr.Markdown("# βœ‰οΈ AI Cover Letter Generator")
gr.Markdown("Create personalized cover letters in seconds")
# Step indicator
with gr.Column(elem_classes=["step-indicator"]):
gr.Markdown("### Create in 3 Steps")
with gr.Row():
step1 = gr.Markdown("1", elem_classes=["step", "active"])
step2 = gr.Markdown("2", elem_classes=["step"])
step3 = gr.Markdown("3", elem_classes=["step"])
# Step 1: Personal Details
with gr.Column(visible=True) as step1_section:
with gr.Column(elem_classes=["step-card"]):
gr.Markdown("### πŸ‘€ Your Information")
with gr.Row():
name = gr.Textbox(label="Full Name", placeholder="John Doe")
email = gr.Textbox(label="Email", placeholder="john@example.com")
with gr.Row():
phone = gr.Textbox(label="Phone", placeholder="(123) 456-7890")
tone = gr.Dropdown(
label="Writing Tone",
choices=["Professional", "Enthusiastic", "Formal", "Friendly"],
value="Professional"
)
# Step 2: Job & Resume Details
with gr.Column(visible=False) as step2_section:
with gr.Column(elem_classes=["step-card"]):
gr.Markdown("### πŸ’Ό Job & Company Details")
with gr.Row():
company = gr.Textbox(label="Company Name", placeholder="Acme Inc")
manager = gr.Textbox(label="Hiring Manager (Optional)", placeholder="Sarah Johnson")
job_desc = gr.Textbox(
label="Job Description",
lines=5,
placeholder="Paste the job description here...",
info="Copy-paste the full job posting for best results"
)
gr.Markdown("### πŸ“„ Your Resume")
resume = gr.Textbox(
label="Paste your resume content",
lines=8,
placeholder="Skills:\n- Python\n- Project Management\n\nExperience:\n- ABC Corp (2020-2023)...",
info="Include key skills and experiences"
)
with gr.Accordion("πŸ’‘ Resume Tips", open=False):
gr.Markdown("- Include specific skills mentioned in the job description\n- Add quantifiable achievements\n- Keep it concise (300-500 words)")
# Step 3: Generated Letter
with gr.Column(visible=False) as step3_section:
with gr.Column(elem_classes=["output-card"]):
gr.Markdown("### πŸ“œ Your Custom Cover Letter")
output = gr.Textbox(label="", lines=15, interactive=True)
with gr.Row():
download = gr.Button("πŸ“₯ Download as TXT")
new_letter = gr.Button("πŸ”„ Generate New Letter")
with gr.Column(elem_classes=["tips"]):
gr.Markdown("**Before using:**\n1. Review for accuracy\n2. Personalize company-specific details\n3. Check length (200-300 words)")
# Navigation buttons
with gr.Row():
back_btn = gr.Button("← Back", visible=False)
next_btn = gr.Button("Continue β†’", elem_classes=["btn-primary"])
submit_btn = gr.Button("✨ Generate Cover Letter", visible=False, elem_classes=["btn-primary"])
# Footer
gr.Markdown("---")
with gr.Column(elem_classes=["footer"]):
gr.Markdown("⚠️ Always review generated content before sending")
gr.Markdown("Made with ❀️ using Transformers | GPT-2 Model")
# Step navigation logic
next_btn.click(
next_step,
inputs=None,
outputs=current_step
).then(
update_step,
inputs=current_step,
outputs=[step1, step2, step3]
).then(
lambda step: {
step1_section: gr.update(visible=step == 1),
step2_section: gr.update(visible=step == 2),
step3_section: gr.update(visible=step == 3),
back_btn: gr.update(visible=step > 1),
next_btn: gr.update(visible=step < 2),
submit_btn: gr.update(visible=step == 2)
},
inputs=current_step,
outputs=[step1_section, step2_section, step3_section, back_btn, next_btn, submit_btn]
)
back_btn.click(
lambda step: step - 1,
inputs=current_step,
outputs=current_step
).then(
update_step,
inputs=current_step,
outputs=[step1, step2, step3]
).then(
lambda step: {
step1_section: gr.update(visible=step == 1),
step2_section: gr.update(visible=step == 2),
step3_section: gr.update(visible=step == 3),
back_btn: gr.update(visible=step > 1),
next_btn: gr.update(visible=step < 2),
submit_btn: gr.update(visible=step == 2)
},
inputs=current_step,
outputs=[step1_section, step2_section, step3_section, back_btn, next_btn, submit_btn]
)
submit_btn.click(
generate_letter,
inputs=[job_desc, resume, name, email, phone, company, manager, tone],
outputs=[output, current_step]
).then(
update_step,
inputs=current_step,
outputs=[step1, step2, step3]
).then(
lambda step: {
step1_section: gr.update(visible=step == 1),
step2_section: gr.update(visible=step == 2),
step3_section: gr.update(visible=step == 3),
back_btn: gr.update(visible=step > 1),
next_btn: gr.update(visible=step < 2),
submit_btn: gr.update(visible=step == 2)
},
inputs=current_step,
outputs=[step1_section, step2_section, step3_section, back_btn, next_btn, submit_btn]
)
download.click(
lambda text: {
"name": "cover_letter.txt",
"data": text
},
inputs=output,
outputs=gr.File()
)
new_letter.click(
lambda: 1,
inputs=None,
outputs=current_step
).then(
update_step,
inputs=current_step,
outputs=[step1, step2, step3]
).then(
lambda step: {
step1_section: gr.update(visible=step == 1),
step2_section: gr.update(visible=step == 2),
step3_section: gr.update(visible=step == 3),
back_btn: gr.update(visible=step > 1),
next_btn: gr.update(visible=step < 2),
submit_btn: gr.update(visible=step == 2)
},
inputs=current_step,
outputs=[step1_section, step2_section, step3_section, back_btn, next_btn, submit_btn]
)
if __name__ == "__main__":
demo.launch()