| import gradio as gr |
| import pdfplumber |
| import spacy |
| import os |
|
|
| |
| try: |
| nlp = spacy.load("en_core_web_sm", disable=["ner", "lemmatizer"]) |
| except Exception as e: |
| raise RuntimeError(f"Failed to load spaCy model: {str(e)}") |
|
|
| def generate_portfolio(resume_file): |
| |
| if resume_file is None: |
| return "No file uploaded. Please upload a PDF resume." |
|
|
| |
| try: |
| with pdfplumber.open(resume_file) as pdf: |
| text = "".join(page.extract_text() or "" for page in pdf.pages) |
| except Exception as e: |
| return f"Error processing PDF: {str(e)}" |
|
|
| |
| doc = nlp(text) |
| data = { |
| "name": "", |
| "summary": "", |
| "experience": [], |
| "skills": [], |
| "contact": "" |
| } |
| for ent in doc.ents: |
| if ent.label_ == "PERSON" and not data["name"]: |
| data["name"] = ent.text |
| elif ent.label_ == "ORG": |
| data["experience"].append({"company": ent.text, "role": ""}) |
| elif ent.label_ == "EMAIL": |
| data["contact"] = ent.text |
|
|
| |
| skill_keywords = ["python", "javascript", "sql", "communication", "leadership"] |
| data["skills"] = [token.text for token in doc if token.text.lower() in skill_keywords] |
| data["summary"] = text[:200] + "..." |
|
|
| |
| os.remove(resume_file) |
|
|
| |
| portfolio_html = f""" |
| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>{data['name']}'s Portfolio</title> |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> |
| </head> |
| <body> |
| <header class="bg-primary text-white text-center py-5"> |
| <h1>{data['name']}</h1> |
| <p>Professional Portfolio</p> |
| </header> |
| <div class="container my-5"> |
| <section> |
| <h2>About Me</h2> |
| <p>{data['summary']}</p> |
| </section> |
| <section> |
| <h2>Experience</h2> |
| {''.join([f'<div class="card mb-3"><div class="card-body"><h5 class="card-title">{exp["company"]}</h5><p class="card-text">{exp["role"]}</p></div></div>' for exp in data['experience']])} |
| </section> |
| <section> |
| <h2>Skills</h2> |
| <ul class="list-group"> |
| {''.join([f'<li class="list-group-item">{skill}</li>' for skill in data['skills']])} |
| </ul> |
| </section> |
| <section> |
| <h2>Contact</h2> |
| <p>Email: {data['contact']}</p> |
| </section> |
| </div> |
| <footer class="bg-dark text-white text-center py-3"> |
| <p>© 2025 {data['name']}</p> |
| <p>Generated by Resume-to-Portfolio AI. Your data was processed securely and not retained.</p> |
| </footer> |
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> |
| </body> |
| </html> |
| """ |
| return portfolio_html |
|
|
| |
| interface = gr.Interface( |
| fn=generate_portfolio, |
| inputs=gr.inputs.File(label="Upload Resume (PDF)"), |
| outputs=gr.outputs.HTML(label="Your Portfolio"), |
| title="Resume to Portfolio Generator", |
| description="Upload your resume to generate a portfolio landing page. Your data is processed securely and not stored.", |
| allow_flagging="never" |
| ) |
|
|
| interface.launch() |