Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import os | |
| import io | |
| import pdfplumber | |
| import pandas as pd | |
| from dotenv import load_dotenv | |
| from groq import Groq | |
| import gspread | |
| from oauth2client.service_account import ServiceAccountCredentials | |
| from docx import Document | |
| # Page config | |
| st.set_page_config(page_title="π AI ResumeSync Analyzer", layout="centered") | |
| # Load env vars | |
| load_dotenv() | |
| GROQ_API_KEY = os.getenv("GROQ_API_KEY") | |
| if not GROQ_API_KEY: | |
| st.error("β GROQ API Key is missing. Please add it in the .env file or Hugging Face Secrets.") | |
| st.stop() | |
| # Load Google Sheet | |
| df = pd.DataFrame() | |
| sheet_loaded = False | |
| scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"] | |
| if os.path.exists("credentials.json"): | |
| try: | |
| creds = ServiceAccountCredentials.from_json_keyfile_name("credentials.json", scope) | |
| client = gspread.authorize(creds) | |
| sheet = client.open("Job_Listings").sheet1 | |
| data = sheet.get_all_records() | |
| df = pd.DataFrame(data) | |
| sheet_loaded = True | |
| except Exception as e: | |
| st.warning(f"β οΈ Could not load job listings from Google Sheet: {e}") | |
| # Fallback job listing | |
| if not sheet_loaded: | |
| df = pd.DataFrame([{ | |
| "Title": "Software Engineer", | |
| "Skills": "Python, Django, SQL", | |
| "Experience": "2+ years", | |
| "Education": "BS in Computer Science" | |
| }]) | |
| # Groq client | |
| groq_client = Groq(api_key=GROQ_API_KEY) | |
| # UI: Title | |
| st.title("π AI ResumeSync Analyzer") | |
| st.markdown("Upload your resume below to receive tailored job match analysis, skill suggestions, and a personalized cover letter.") | |
| # File uploader | |
| uploaded_file = st.file_uploader("π€ Upload your resume (PDF, DOCX, or TXT)", type=["pdf", "docx", "txt"]) | |
| # Resume text extractor | |
| def extract_resume_text(uploaded_file): | |
| try: | |
| filename = uploaded_file.name.lower() | |
| buffer = io.BytesIO(uploaded_file.getvalue()) # Use getvalue() instead of read() | |
| buffer.seek(0) | |
| if filename.endswith(".pdf"): | |
| text = "" | |
| with pdfplumber.open(buffer) as pdf: | |
| for page in pdf.pages: | |
| page_text = page.extract_text() | |
| if page_text: | |
| text += page_text + "\n" | |
| return text.strip() | |
| elif filename.endswith(".docx"): | |
| doc = Document(buffer) | |
| return "\n".join(para.text for para in doc.paragraphs if para.text.strip()) | |
| elif filename.endswith(".txt"): | |
| return buffer.getvalue().decode("utf-8", errors="ignore") | |
| else: | |
| return None | |
| except Exception as e: | |
| st.error(f"β Error reading resume file: {e}") | |
| return None | |
| # Main logic | |
| if uploaded_file: | |
| with st.spinner("π Analyzing your resume..."): | |
| resume_text = extract_resume_text(uploaded_file) | |
| if not resume_text or resume_text.strip() == "": | |
| st.error("β No readable content in the uploaded resume.") | |
| st.stop() | |
| # AI Prompt | |
| prompt = f""" | |
| You are an expert AI Resume Analyzer. Based on the resume and job listings provided, return a detailed, formatted response covering: | |
| 1. β Match Score (as percentage) | |
| 2. π― Recommended Jobs (top 3 that match well) | |
| 3. π Qualification Ranking (1 to 10) | |
| 4. π§© Skill Gaps & Suggestions | |
| 5. π οΈ Keyword Optimization Suggestions | |
| 6. π Education & Experience Alignment | |
| 7. π° Estimated Salary Range | |
| 8. π Job Market Trends (optional) | |
| 9. βοΈ Personalized Cover Letter | |
| Return the output with clear headings and markdown formatting. | |
| Resume: | |
| {resume_text} | |
| Available Jobs: | |
| {df.to_string(index=False)} | |
| """ | |
| try: | |
| response = groq_client.chat.completions.create( | |
| model="llama3-8b-8192", | |
| messages=[{"role": "user", "content": prompt}] | |
| ) | |
| message = response.choices[0].message.content.strip() | |
| if not message: | |
| st.error("β Groq returned an empty response.") | |
| else: | |
| st.success("β Analysis Complete!") | |
| # Output full analysis | |
| st.markdown(message, unsafe_allow_html=True) | |
| # Job recommendations | |
| st.markdown("---") | |
| st.subheader("π Job Listing Overview") | |
| st.dataframe(df) | |
| # Call-to-action | |
| st.markdown("### π Unlock More Features or Take Action") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| if st.button("β Apply Now"): | |
| st.info("π Redirecting to application portal... (hook this into your system)") | |
| with col2: | |
| if st.button("π Upgrade to Pro Templates"): | |
| st.warning("Premium templates coming soon! Contact support to activate.") | |
| except Exception as e: | |
| st.error(f"β Failed to generate analysis: {e}") |