meesamraza's picture
Update app.py
7b7951a verified
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}")