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}")