Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import google.generativeai as genai | |
| from github import Github | |
| from pypdf import PdfReader | |
| import os | |
| from dotenv import load_dotenv | |
| # --- CONFIG --- | |
| st.set_page_config(page_title="DevResume Pro", layout="wide", page_icon="β‘") | |
| # Load Keys | |
| api_key = os.getenv("GEMINI_API_KEY") | |
| github_token = os.getenv("GITHUB_TOKEN") | |
| if not api_key: | |
| load_dotenv() | |
| api_key = os.getenv("GEMINI_API_KEY") | |
| github_token = os.getenv("GITHUB_TOKEN") | |
| # --- FUNC 1: PDF PARSER --- | |
| def extract_pdf_text(file): | |
| try: | |
| reader = PdfReader(file) | |
| text = "" | |
| for page in reader.pages: | |
| text += page.extract_text() | |
| return text | |
| except: | |
| return None | |
| # --- FUNC 2: GITHUB CRAWLER --- | |
| def fetch_github_data(username): | |
| try: | |
| g = Github(github_token) if github_token else Github() | |
| user = g.get_user(username) | |
| repos = sorted(user.get_repos(), key=lambda x: x.stargazers_count, reverse=True)[:4] | |
| repo_data = "" | |
| for repo in repos: | |
| readme = "No README" | |
| try: | |
| if repo.get_readme().decoded_content: | |
| readme = repo.get_readme().decoded_content.decode("utf-8")[:1000] | |
| except: pass | |
| repo_data += f"Project: {repo.name} ({repo.stargazers_count} Stars, {repo.language})\nDesc: {repo.description}\nContext: {readme}\n\n" | |
| return repo_data | |
| except Exception as e: | |
| return f"Error fetching GitHub: {str(e)}" | |
| # --- FUNC 3: THE RESUME ARCHITECT --- | |
| def generate_full_resume(old_resume_text, github_data, target_role): | |
| genai.configure(api_key=api_key) | |
| try: | |
| model = genai.GenerativeModel('gemini-2.5-flash') | |
| except: | |
| model = genai.GenerativeModel('gemini-1.5-flash') | |
| prompt = f""" | |
| You are an Elite Tech Resume Writer. | |
| SOURCE MATERIAL: | |
| 1. OLD RESUME TEXT: | |
| {old_resume_text[:4000]} | |
| 2. GITHUB PORTFOLIO ANALYSIS: | |
| {github_data} | |
| TARGET ROLE: {target_role} | |
| TASK: | |
| Write a complete, SOTA Resume (Markdown Format). | |
| STRUCTURE: | |
| 1. **Header:** Name, Title (Target Role), Links (GitHub/LinkedIn). | |
| 2. **Professional Summary:** Synthesize the old resume + new GitHub achievements into a killer 3-line bio. | |
| 3. **Technical Skills:** Grouped by category (Languages, Frameworks, Tools). | |
| 4. **Featured Projects:** Use the GitHub Data. Write "XYZ Style" impact bullets. | |
| 5. **Experience:** Polish the old resume's experience section. Make it punchy. | |
| 6. **Education:** Keep it simple. | |
| TONE: Senior, High-Impact, Quantified. | |
| """ | |
| try: | |
| response = model.generate_content(prompt) | |
| return response.text | |
| except Exception as e: | |
| return f"AI Error: {e}" | |
| # --- UI --- | |
| st.title("β‘ DevResume Pro: The Hybrid Architect") | |
| st.markdown("Combines your **Old Resume** + **Real GitHub Code** to build the ultimate portfolio.") | |
| col1, col2 = st.columns([1, 2]) | |
| with col1: | |
| st.subheader("1. Your Inputs") | |
| gh_user = st.text_input("GitHub Username", placeholder="eatosin") | |
| role = st.text_input("Target Role", value="Senior AI Engineer") | |
| uploaded_file = st.file_uploader("Upload Old Resume (PDF)", type="pdf") | |
| if st.button("π Build Resume", type="primary"): | |
| if not gh_user or not uploaded_file: | |
| st.error("Please provide both GitHub User and PDF Resume.") | |
| else: | |
| with st.spinner("π΅οΈββοΈ Reading PDF & Scraping GitHub..."): | |
| # 1. Read PDF | |
| pdf_text = extract_pdf_text(uploaded_file) | |
| # 2. Scrape GitHub | |
| gh_data = fetch_github_data(gh_user) | |
| # 3. Generate | |
| if pdf_text and gh_data: | |
| st.session_state['resume'] = generate_full_resume(pdf_text, gh_data, role) | |
| else: | |
| st.error("Failed to read inputs.") | |
| with col2: | |
| if 'resume' in st.session_state: | |
| st.subheader("π Your New Resume") | |
| st.markdown(st.session_state['resume']) | |
| st.download_button("π₯ Download Markdown", st.session_state['resume'], file_name="SOTA_Resume.md") |