Untitled
unknown
plain_text
a month ago
6.8 kB
2
Indexable
import os import json import openai import spacy import streamlit as st import pdfkit from docx import Document from zipfile import ZipFile import tempfile from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity from dotenv import load_dotenv # Initialize load_dotenv() openai.api_key = os.getenv("OPENAI_API_KEY") nlp = spacy.load("en_core_web_sm") # ====================== # Core Functions # ====================== def parse_linkedin_data(zip_path): """Extract LinkedIn profile data from ZIP export""" with ZipFile(zip_path, 'r') as zip_ref: with zip_ref.open('Profile.json') as file: data = json.load(file) profile = data['profile'] return { 'name': f"{profile['firstName']} {profile['lastName']}", 'contact': f"{profile['email']} | {profile['phone']}", 'summary': profile['summary'], 'experience': "\n".join([ f"- {exp['title']} at {exp['companyName']} ({exp['dates']})" for exp in profile['positionGroups'] ]), 'skills': [skill['name'] for skill in profile['skills']], 'education': "\n".join([ f"- {edu['degreeName']} at {edu['schoolName']}" for edu in profile['education'] ]) } def create_ats_docx(resume_data): """Generate ATS-friendly Word document""" doc = Document() # Header doc.add_heading(resume_data['name'], 0) doc.add_paragraph(resume_data['contact'] + "\n") # Sections sections = [ ('Professional Summary', resume_data['summary']), ('Work Experience', resume_data['experience']), ('Skills', ', '.join(resume_data['skills'])), ('Education', resume_data['education']) ] for title, content in sections: doc.add_heading(title, level=1) doc.add_paragraph(content) # Formatting for paragraph in doc.paragraphs: paragraph.style.font.name = 'Arial' paragraph.style.font.size = Pt(11) return doc def create_ats_pdf(resume_data): """Generate ATS-friendly PDF""" html_content = f""" <!DOCTYPE html> <html> <head> <style> body {{ font-family: Arial; font-size: 11pt; line-height: 1.6; }} h1 {{ color: #2B3467; border-bottom: 2px solid #2B3467; }} h2 {{ color: #2B3467; margin-top: 1.5em; }} </style> </head> <body> <h1>{resume_data['name']}</h1> <p>{resume_data['contact']}</p> <h2>Professional Summary</h2> <p>{resume_data['summary']}</p> <h2>Work Experience</h2> <p>{resume_data['experience']}</p> <h2>Skills</h2> <p>{', '.join(resume_data['skills'])}</p> <h2>Education</h2> <p>{resume_data['education']}</p> </body> </html> """ config = pdfkit.configuration(wkhtmltopdf='/usr/local/bin/wkhtmltopdf') pdfkit.from_string(html_content, "resume.pdf", configuration=config) def calculate_ats_score(resume_text, job_desc): """Calculate ATS compatibility score""" def extract_keywords(text): doc = nlp(text) return [token.lemma_.lower() for token in doc if not token.is_stop and token.pos_ in ['NOUN', 'VERB']] vectorizer = TfidfVectorizer(tokenizer=extract_keywords) tfidf_matrix = vectorizer.fit_transform([resume_text, job_desc]) return round(cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[1:2])[0][0] * 100, 1) def enhance_with_ai(resume_data, job_desc): """Improve resume using GPT-3.5""" prompt = f""" Optimize this resume for the following job description: {job_desc} Current resume data: {json.dumps(resume_data, indent=2)} Return ONLY valid JSON with these keys: - summary (improved professional summary) - experience (bullet points) - skills (prioritized list) - education (formatted) """ response = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=[{"role": "user", "content": prompt}], max_tokens=700 ) return json.loads(response.choices[0].message.content) # ====================== # Streamlit UI # ====================== st.set_page_config(page_title="AI Resume Builder", layout="wide") st.title("🚀 AI-Powered Resume Builder") # Input Section col1, col2 = st.columns(2) with col1: linkedin_zip = st.file_uploader("Upload LinkedIn Export (ZIP):", type='zip') with col2: job_desc = st.text_area("Paste Job Description:", height=150) # Manual Inputs if not linkedin_zip: name = st.text_input("Full Name:") contact = st.text_input("Contact Info (Email/Phone):") experience = st.text_area("Work Experience (Bullet Points):") skills = st.text_input("Skills (comma-separated):") education = st.text_area("Education:") if st.button("Generate Resume"): resume_data = {} # Process Inputs if linkedin_zip: with tempfile.NamedTemporaryFile(delete=False) as tmp: tmp.write(linkedin_zip.getvalue()) resume_data = parse_linkedin_data(tmp.name) else: resume_data = { 'name': name, 'contact': contact, 'summary': "", 'experience': experience, 'skills': [s.strip() for s in skills.split(',')], 'education': education } # AI Enhancement with st.spinner("Optimizing with AI..."): ai_enhanced = enhance_with_ai(resume_data, job_desc) resume_data.update(ai_enhanced) # Generate Documents with st.spinner("Creating files..."): # DOCX doc = create_ats_docx(resume_data) doc.save("resume.docx") # PDF create_ats_pdf(resume_data) # ATS Score resume_text = " ".join([ resume_data['summary'], resume_data['experience'], " ".join(resume_data['skills']), resume_data['education'] ]) score = calculate_ats_score(resume_text, job_desc) # Display Results st.success("Resume Generated!") st.subheader(f"ATS Compatibility Score: {score}/100") if score < 70: st.warning("Improvement needed! Add more keywords from the job description.") # Download Buttons col1, col2 = st.columns(2) with col1: st.download_button("Download DOCX", open("resume.docx", 'rb'), file_name="resume.docx") with col2: st.download_button("Download PDF", open("resume.pdf", 'rb'), file_name="resume.pdf")
Editor is loading...
Leave a Comment