Spaces:
Build error
Build error
| import os | |
| import io | |
| import streamlit as st | |
| from langchain_google_genai import ChatGoogleGenerativeAI | |
| from fpdf import FPDF | |
| # === CONFIGURE YOUR GOOGLE GEMINI KEY === | |
| os.environ["GOOGLE_API_KEY"] = "AIzaSyCB5NLx39vOAlfRQBDmnEG3uLBgLraGvH4" | |
| # Initialize Gemini Model | |
| model = ChatGoogleGenerativeAI(model="gemini-2.5-flash", temperature=0.0) | |
| st.title("AI Resume Builder - Professional Format") | |
| # Session state | |
| for key in ("education_list", "project_list", "experience_list", "publication_list"): | |
| if key not in st.session_state: | |
| st.session_state[key] = [] | |
| # Basic Info Section | |
| st.subheader("Personal Information") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| name = st.text_input("Full Name") | |
| email = st.text_input("Email") | |
| phone = st.text_input("Phone Number") | |
| with col2: | |
| location = st.text_input("Location (City, State/Country)") | |
| website = st.text_input("Personal Website (optional)") | |
| linkedin = st.text_input("LinkedIn URL") | |
| github = st.text_input("GitHub URL (optional)") | |
| # Professional Summary | |
| st.subheader("Professional Summary") | |
| summary_manual = st.text_area("Professional Summary (optional - will be auto-generated if left blank)", | |
| placeholder="Brief overview of your career, skills, and goals...") | |
| # Skills Section | |
| st.subheader("Skills & Technologies") | |
| languages = st.text_input("Programming Languages", placeholder="e.g., Python, Java, C++, JavaScript") | |
| technologies = st.text_input("Technologies/Frameworks", placeholder="e.g., React, Django, AWS, Docker") | |
| databases = st.text_input("Databases (optional)", placeholder="e.g., MySQL, MongoDB, PostgreSQL") | |
| other_skills = st.text_input("Other Skills (optional)", placeholder="e.g., Git, Linux, Agile, Machine Learning") | |
| # Education Section | |
| st.subheader("Education Details") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| college = st.text_input("University/College Name") | |
| degree = st.text_input("Degree & Major", placeholder="e.g., BS in Computer Science") | |
| with col2: | |
| edu_start = st.text_input("Start Date", placeholder="e.g., Sept 2020") | |
| edu_end = st.text_input("End Date", placeholder="e.g., May 2024") | |
| gpa = st.text_input("GPA (optional)", placeholder="e.g., 3.9/4.0") | |
| coursework = st.text_input("Relevant Coursework (optional)", placeholder="e.g., Data Structures, Machine Learning, Database Systems") | |
| achievements = st.text_input("Academic Achievements (optional)", placeholder="e.g., Dean's List, Magna Cum Laude") | |
| if st.button("Add Education"): | |
| st.session_state.education_list.append({ | |
| "college": college, | |
| "degree": degree, | |
| "start": edu_start, | |
| "end": edu_end, | |
| "gpa": gpa, | |
| "coursework": coursework, | |
| "achievements": achievements | |
| }) | |
| for i, edu in enumerate(st.session_state.education_list, start=1): | |
| st.write(f"{i}. {edu['college']}, {edu['degree']} | {edu['start']} – {edu['end']}") | |
| if st.button(f"Remove Education {i}", key=f"remove_edu_{i}"): | |
| st.session_state.education_list.pop(i-1) | |
| st.rerun() | |
| # Experience Section | |
| exp_status = st.radio("Experience Level", ("Fresher", "Experienced")) | |
| if exp_status == "Experienced": | |
| st.subheader("Work Experience") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| job_title = st.text_input("Job Title") | |
| company = st.text_input("Company Name") | |
| with col2: | |
| work_location = st.text_input("Work Location", placeholder="e.g., New York, NY") | |
| work_start = st.text_input("Start Date", placeholder="e.g., June 2022") | |
| work_end = st.text_input("End Date", placeholder="e.g., Present or Aug 2024") | |
| # Job responsibilities | |
| st.write("Job Responsibilities (add multiple bullet points):") | |
| responsibility = st.text_area("Responsibility/Achievement", | |
| placeholder="Describe a specific achievement with metrics if possible...") | |
| if st.button("Add Experience"): | |
| st.session_state.experience_list.append({ | |
| "title": job_title, | |
| "company": company, | |
| "location": work_location, | |
| "start": work_start, | |
| "end": work_end, | |
| "responsibility": responsibility | |
| }) | |
| for i, exp in enumerate(st.session_state.experience_list, start=1): | |
| st.write(f"{i}. {exp['title']} at {exp['company']} – {exp['location']} | {exp['start']} – {exp['end']}") | |
| if st.button(f"Remove Experience {i}", key=f"remove_exp_{i}"): | |
| st.session_state.experience_list.pop(i-1) | |
| st.rerun() | |
| # Projects Section | |
| st.subheader("Projects") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| proj_title = st.text_input("Project Title") | |
| proj_tools = st.text_input("Technologies Used", placeholder="e.g., Python, Flask, MySQL") | |
| with col2: | |
| proj_github = st.text_input("GitHub/Demo Link (optional)") | |
| proj_date = st.text_input("Project Date (optional)", placeholder="e.g., Jan 2024") | |
| proj_desc = st.text_area("Project Description", | |
| placeholder="Describe what the project does, your role, and key achievements...") | |
| if st.button("Add Project"): | |
| st.session_state.project_list.append({ | |
| "title": proj_title, | |
| "tools": proj_tools, | |
| "github": proj_github, | |
| "date": proj_date, | |
| "desc": proj_desc | |
| }) | |
| for i, proj in enumerate(st.session_state.project_list, start=1): | |
| st.write(f"{i}. {proj['title']} | Tools: {proj['tools']}") | |
| if st.button(f"Remove Project {i}", key=f"remove_proj_{i}"): | |
| st.session_state.project_list.pop(i-1) | |
| st.rerun() | |
| # Publications Section (Optional) | |
| st.subheader("Publications (Optional)") | |
| pub_title = st.text_input("Publication Title") | |
| pub_authors = st.text_input("Authors", placeholder="e.g., John Doe, Jane Smith") | |
| pub_date = st.text_input("Publication Date", placeholder="e.g., Jan 2024") | |
| pub_doi = st.text_input("DOI/Link (optional)") | |
| if st.button("Add Publication"): | |
| st.session_state.publication_list.append({ | |
| "title": pub_title, | |
| "authors": pub_authors, | |
| "date": pub_date, | |
| "doi": pub_doi | |
| }) | |
| for i, pub in enumerate(st.session_state.publication_list, start=1): | |
| st.write(f"{i}. {pub['title']} | {pub['authors']} | {pub['date']}") | |
| if st.button(f"Remove Publication {i}", key=f"remove_pub_{i}"): | |
| st.session_state.publication_list.pop(i-1) | |
| st.rerun() | |
| # Generate Resume | |
| if st.button("Generate Professional Resume", type="primary"): | |
| # Prepare data for prompt | |
| contact_info = f"{name}\n{location} | {email} | {phone}" | |
| if website: | |
| contact_info += f" | {website}" | |
| if linkedin: | |
| contact_info += f"\nlinkedin.com/in/{linkedin.split('/')[-1] if '/' in linkedin else linkedin}" | |
| if github: | |
| contact_info += f" | github.com/{github.split('/')[-1] if '/' in github else github}" | |
| # Skills formatting | |
| skills_text = "" | |
| if languages: | |
| skills_text += f"Languages: {languages}\n" | |
| if technologies: | |
| skills_text += f"Technologies: {technologies}\n" | |
| if databases: | |
| skills_text += f"Databases: {databases}\n" | |
| if other_skills: | |
| skills_text += f"Other Skills: {other_skills}" | |
| # Education formatting | |
| education_text = "" | |
| for edu in st.session_state.education_list: | |
| education_text += f"• {edu['college']}, {edu['degree']}" | |
| if edu['start'] and edu['end']: | |
| education_text += f" | {edu['start']} – {edu['end']}\n" | |
| else: | |
| education_text += "\n" | |
| if edu['gpa']: | |
| education_text += f" - GPA: {edu['gpa']}\n" | |
| if edu['coursework']: | |
| education_text += f" - Coursework: {edu['coursework']}\n" | |
| if edu['achievements']: | |
| education_text += f" - {edu['achievements']}\n" | |
| # Experience formatting | |
| experience_text = "" | |
| if exp_status == "Experienced" and st.session_state.experience_list: | |
| for exp in st.session_state.experience_list: | |
| experience_text += f"• {exp['title']}, {exp['company']} – {exp['location']} | {exp['start']} – {exp['end']}\n" | |
| if exp['responsibility']: | |
| for resp in exp['responsibility'].split('\n'): | |
| if resp.strip(): | |
| experience_text += f" - {resp.strip()}\n" | |
| else: | |
| experience_text = "Recent graduate seeking entry-level opportunities to apply academic knowledge and skills." | |
| # Projects formatting | |
| project_text = "" | |
| for proj in st.session_state.project_list: | |
| project_text += f"• {proj['title']}" | |
| if proj['github']: | |
| project_text += f" | {proj['github']}" | |
| if proj['date']: | |
| project_text += f" | {proj['date']}" | |
| project_text += "\n" | |
| if proj['desc']: | |
| for desc_line in proj['desc'].split('\n'): | |
| if desc_line.strip(): | |
| project_text += f" - {desc_line.strip()}\n" | |
| if proj['tools']: | |
| project_text += f" - Tools Used: {proj['tools']}\n" | |
| # Publications formatting | |
| publications_text = "" | |
| for pub in st.session_state.publication_list: | |
| publications_text += f"• {pub['title']} | {pub['date']}\n" | |
| publications_text += f" {pub['authors']}\n" | |
| if pub['doi']: | |
| publications_text += f" {pub['doi']}\n" | |
| # Create comprehensive prompt | |
| prompt = [ | |
| ("system", """You are a professional resume writer specializing in creating clean, ATS-friendly resumes. | |
| Create resumes that follow this exact format and structure: | |
| HEADER: Name on first line, then contact info on subsequent lines | |
| SECTIONS: Use clear section headers in ALL CAPS | |
| FORMATTING: Use bullet points (•) for lists, maintain consistent spacing | |
| STYLE: Professional, concise, action-oriented language with quantifiable achievements when possible | |
| Always include these sections in this order: | |
| 1. Contact Information (header) | |
| 2. Professional Summary (if experience) or Objective (if fresher) | |
| 3. Education | |
| 4. Experience (if applicable) | |
| 5. Projects | |
| 6. Publications (if any) | |
| 7. Technologies/Skills | |
| Make it ATS-friendly with no fancy formatting, just clean structure."""), | |
| ("human", f"""Create a professional resume using this information: | |
| CONTACT INFORMATION: | |
| {contact_info} | |
| PROFESSIONAL SUMMARY: | |
| Status: {exp_status} | |
| Manual Summary: {summary_manual or '(Generate based on profile)'} | |
| EDUCATION: | |
| {education_text or '(No education provided)'} | |
| EXPERIENCE: | |
| {experience_text} | |
| PROJECTS: | |
| {project_text or '(No projects provided)'} | |
| PUBLICATIONS: | |
| {publications_text or '(No publications)'} | |
| SKILLS & TECHNOLOGIES: | |
| {skills_text or '(No skills provided)'} | |
| INSTRUCTIONS: | |
| 1. Format exactly like a professional resume with clear sections | |
| 2. Use bullet points for achievements and responsibilities | |
| 3. Keep it concise but comprehensive | |
| 4. Include quantifiable results where possible | |
| 5. Make it ATS-friendly | |
| 6. If manual summary is blank, generate a professional 3-4 line summary based on their profile | |
| 7. Don't include empty sections | |
| 8. Use action verbs for experience and project descriptions | |
| 9. Maintain professional tone throughout | |
| 10. Format contact info cleanly at the top | |
| Generate the complete resume now:""") | |
| ] | |
| try: | |
| response = model.invoke(prompt) | |
| resume_text = response.content | |
| resume_text = resume_text.replace("*", "-") | |
| st.subheader("Generated Professional Resume") | |
| st.text_area("Resume Output", value=resume_text, height=600) | |
| # Enhanced PDF generation | |
| def create_pdf_unicode(text: str): | |
| pdf = FPDF() | |
| pdf.add_page() | |
| pdf.set_font("Arial", size=12) | |
| lines = text.split("\n") | |
| for line in lines: | |
| if line.strip() == "": | |
| pdf.ln(3) | |
| elif line.isupper() and len(line.strip()) < 50: # Section headers | |
| pdf.set_font("Arial", "B", 12) | |
| pdf.ln(5) | |
| pdf.cell(0, 8, line.strip(), ln=True) | |
| pdf.ln(2) | |
| pdf.set_font("Arial", size=11) | |
| elif line.startswith(name.split()[0]) and len(line) < 100: # Name header | |
| pdf.set_font("Arial", "B", 16) | |
| pdf.cell(0, 10, line.strip(), ln=True, align='C') | |
| pdf.set_font("Arial", size=11) | |
| else: | |
| pdf.set_font("Arial", size=11) | |
| # Handle long lines | |
| if len(line) > 90: | |
| pdf.multi_cell(0, 6, line.strip()) | |
| else: | |
| pdf.cell(0, 6, line.strip(), ln=True) | |
| return io.BytesIO(pdf.output(dest="S").encode("latin-1")) | |
| pdf_buffer = create_pdf_unicode(resume_text) | |
| st.download_button( | |
| "📄 Download Professional Resume as PDF", | |
| data=pdf_buffer, | |
| file_name=f"{name.replace(' ', '_')}_Resume.pdf" if name else "Professional_Resume.pdf", | |
| mime="application/pdf" | |
| ) | |
| st.success("✅ Professional resume generated successfully! Click download to save as PDF.") | |
| except Exception as e: | |
| st.error(f"Error generating resume: {str(e)}") | |
| st.info("Please check your Google API key and try again.") | |