Spaces:
Runtime error
Runtime error
import streamlit as st | |
import tempfile | |
import os | |
import random | |
import json | |
from pathlib import Path | |
from PyPDF2 import PdfReader | |
from openai import OpenAI | |
# Import our CrewAI resume optimization module | |
from crewai_resume_optimization import optimize_resume, generate_interview_questions, extract_job_description | |
# --------------------------- | |
# Helper Function: Extract text from PDF (for resume) | |
# --------------------------- | |
def extract_pdf_text(uploaded_file): | |
# Ensure file size is less than 10MB | |
uploaded_file.seek(0, os.SEEK_END) | |
if uploaded_file.tell() > 10 * 1024 * 1024: | |
st.error("File exceeds 10MB limit.") | |
return "" | |
uploaded_file.seek(0) | |
reader = PdfReader(uploaded_file) | |
text = "" | |
for page in reader.pages: | |
page_text = page.extract_text() | |
if page_text: | |
text += page_text + "\n" | |
return text | |
# --------------------------- | |
# OpenAI Helper for Keyword Extraction | |
# --------------------------- | |
def extract_keywords_from_text(text): | |
prompt = f"Extract the most important keywords from the following job input, separated by commas:\n\n{text}" | |
messages = [ | |
{"role": "system", "content": "You are a job analysis assistant."}, | |
{"role": "user", "content": prompt} | |
] | |
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) | |
completion = client.chat.completions.create(model="gpt-4o-mini", messages=messages) | |
return completion.choices[0].message.content.strip() | |
# --------------------------- | |
# Sidebar: File Upload & Input Mode | |
# --------------------------- | |
st.sidebar.title("Job & Resume Setup") | |
# Resume upload (PDF only) | |
uploaded_resume = st.sidebar.file_uploader("Upload your resume (PDF, max 10MB)", type="pdf") | |
# Job input mode selection: "Job Description" vs "Job URL" | |
mode = st.sidebar.radio("Select Job Input Mode", ("Job Description", "Job URL")) | |
job_input = "" | |
if mode == "Job Description": | |
job_input = st.sidebar.text_area("Paste the job description here:") | |
elif mode == "Job URL": | |
job_input = st.sidebar.text_input("Enter the job URL:") | |
# Button to extract keywords from job input. | |
if st.sidebar.button("Extract Keywords"): | |
if job_input: | |
# For simplicity, we use the same function regardless of mode. | |
st.session_state.job_keywords = extract_keywords_from_text(job_input) | |
st.sidebar.success("Keywords extracted!") | |
else: | |
st.sidebar.error("Please provide job input.") | |
# Button to trigger optimization. | |
if st.sidebar.button("Optimize Resume"): | |
st.session_state.optimize_trigger = True | |
# --------------------------- | |
# Session State Initialization | |
# --------------------------- | |
if "resume_text" not in st.session_state: | |
st.session_state.resume_text = None | |
if "job_keywords" not in st.session_state: | |
st.session_state.job_keywords = None | |
if "optimized_resume" not in st.session_state: | |
st.session_state.optimized_resume = None | |
if "interview_questions" not in st.session_state: | |
st.session_state.interview_questions = None | |
# --------------------------- | |
# Process Resume Upload | |
# --------------------------- | |
if uploaded_resume is not None: | |
st.session_state.resume_text = extract_pdf_text(uploaded_resume) | |
if st.session_state.resume_text: | |
st.sidebar.success("Resume uploaded and processed successfully!") | |
else: | |
st.sidebar.error("Failed to extract text from the resume.") | |
# --------------------------- | |
# Main Area: Display Results | |
# --------------------------- | |
st.title("Optimized Resume & Interview Preparation") | |
if st.session_state.resume_text is None: | |
st.info("Please upload your resume from the sidebar to begin.") | |
else: | |
# Display job keywords if available. | |
if st.session_state.job_keywords: | |
st.subheader("Extracted Job Keywords") | |
st.write(st.session_state.job_keywords) | |
else: | |
st.info("Please provide job input and extract keywords from the sidebar.") | |
# Trigger optimization if requested. | |
if st.session_state.get("optimize_trigger", False): | |
if st.session_state.resume_text and st.session_state.job_keywords: | |
with st.spinner("Optimizing resume..."): | |
st.session_state.optimized_resume = optimize_resume(st.session_state.resume_text, st.session_state.job_keywords) | |
with st.spinner("Generating interview questions..."): | |
st.session_state.interview_questions = generate_interview_questions(st.session_state.optimized_resume, st.session_state.job_keywords) | |
st.success("Resume optimized and interview questions generated!") | |
st.session_state.optimize_trigger = False | |
else: | |
st.error("Please ensure you have uploaded your resume and extracted job keywords.") | |
# Display the optimized resume and interview questions if available. | |
if st.session_state.optimized_resume: | |
st.header("Optimized Resume") | |
st.markdown(st.session_state.optimized_resume) | |
st.download_button("Download Optimized Resume (md)", | |
st.session_state.optimized_resume, | |
file_name="tailored_resume.md", | |
mime="text/markdown") | |
if st.session_state.interview_questions: | |
st.header("Interview Questions") | |
st.markdown(st.session_state.interview_questions) | |
st.download_button("Download Interview Questions (md)", | |
st.session_state.interview_questions, | |
file_name="interview_materials.md", | |
mime="text/markdown") | |
st.info("You can open the downloaded markdown (.md) files with Notepad or any text editor.") | |