Spaces:
Sleeping
Sleeping
# app.py | |
import os | |
import io | |
import json | |
from datetime import datetime | |
import streamlit as st | |
from transformers import pipeline | |
from docx import Document | |
from PyPDF2 import PdfReader | |
# ------------------------------------------------------------------------------ | |
# Model Pipeline Setup | |
# ------------------------------------------------------------------------------ | |
# Use an instruction-tuned model (e.g., Flan-T5-xl) | |
model_name = "google/flan-t5-xl" | |
instruct_pipeline = pipeline( | |
"text2text-generation", model=model_name, max_length=1024, truncation=True | |
) | |
# ------------------------------------------------------------------------------ | |
# Helper Functions for File Reading | |
# ------------------------------------------------------------------------------ | |
def read_docx(file_bytes: bytes) -> str: | |
"""Extract text from a DOCX file.""" | |
document = Document(io.BytesIO(file_bytes)) | |
return "\n".join([para.text for para in document.paragraphs]) | |
def read_pdf(file_bytes: bytes) -> str: | |
"""Extract text from a PDF file.""" | |
reader = PdfReader(io.BytesIO(file_bytes)) | |
text = [] | |
for page in reader.pages: | |
extracted = page.extract_text() | |
if extracted: | |
text.append(extracted) | |
return "\n".join(text) | |
def read_plain(file_bytes: bytes) -> str: | |
"""Extract text from a plain text file.""" | |
return file_bytes.decode("utf-8", errors="ignore") | |
def extract_resume_text(file_obj) -> str: | |
""" | |
Determine file type and extract text accordingly. | |
Supports PDF, DOCX, and plain text. | |
""" | |
file_bytes = file_obj.read() | |
file_obj.seek(0) # Reset pointer for potential further use | |
filename = file_obj.name if hasattr(file_obj, "name") else "resume.txt" | |
ext = os.path.splitext(filename)[-1].lower() | |
if ext == ".pdf": | |
return read_pdf(file_bytes) | |
elif ext in [".docx", ".doc"]: | |
return read_docx(file_bytes) | |
else: | |
return read_plain(file_bytes) | |
# ------------------------------------------------------------------------------ | |
# Core AI Functions | |
# ------------------------------------------------------------------------------ | |
def parse_resume(resume_text: str) -> str: | |
""" | |
Extract candidate details from the resume text. | |
The model returns a JSON with keys: first_name, last_name, location, | |
work_experience, school_experience, and skills. | |
""" | |
prompt = ( | |
"You are an expert resume parser. Extract the following keys from the resume text: " | |
"first_name, last_name, location, work_experience, school_experience, and skills. " | |
"Return the answer strictly in JSON format with no extra text.\n\n" | |
f"Resume:\n{resume_text}" | |
) | |
result = instruct_pipeline(prompt, max_length=512)[0]["generated_text"] | |
return result.strip() | |
def generate_cover_letter(candidate_json: str, job_description: str, date_str: str) -> str: | |
""" | |
Generate a cover letter using the candidate's JSON profile, the job description, | |
and the current date. | |
""" | |
prompt = ( | |
"You are a seasoned career advisor and professional cover letter writer. " | |
"Using the candidate information provided in JSON format, craft a persuasive and personalized cover letter " | |
"tailored to the job description. Structure your answer with an introduction, body, and closing, " | |
"and include the date {date}.\n\n" | |
"Candidate JSON:\n{candidate_json}\n\n" | |
"Job Description:\n{job_description}\n\n" | |
"Cover Letter:".format( | |
candidate_json=candidate_json, job_description=job_description, date=date_str | |
) | |
) | |
result = instruct_pipeline(prompt, max_length=1024)[0]["generated_text"] | |
return result.strip() | |
def generate_resume(first_name: str, last_name: str, location: str, | |
work_experience: str, school_experience: str, skills: str) -> str: | |
""" | |
Generate a professional resume using candidate information provided in a form. | |
""" | |
candidate_info = { | |
"first_name": first_name, | |
"last_name": last_name, | |
"location": location, | |
"work_experience": work_experience, | |
"school_experience": school_experience, | |
"skills": skills, | |
} | |
candidate_str = json.dumps(candidate_info, indent=2) | |
prompt = ( | |
"You are a professional resume writer. Using the candidate information provided in JSON, " | |
"create a compelling, well-organized resume in plain text format. Include clear sections for " | |
"personal details, work experience, education, and skills. Ensure the resume is concise and professional.\n\n" | |
"Candidate Information:\n" + candidate_str + "\n\nResume:" | |
) | |
result = instruct_pipeline(prompt, max_length=1024)[0]["generated_text"] | |
return result.strip() | |
# ------------------------------------------------------------------------------ | |
# Streamlit UI | |
# ------------------------------------------------------------------------------ | |
st.set_page_config(page_title="AI-Powered Job Application Assistant", layout="wide") | |
st.title("AI-Powered Job Application Assistant") | |
st.markdown("Generate a **Cover Letter** from your resume or **Create a Resume** from scratch using AI.") | |
# Create tabs for the two functionalities | |
tabs = st.tabs(["Cover Letter Generator", "Resume Creator"]) | |
# ----- Tab 1: Cover Letter Generator ----- | |
with tabs[0]: | |
st.header("Cover Letter Generator") | |
st.markdown("Upload your resume (PDF, DOCX, or TXT) and paste the job description below.") | |
col1, col2 = st.columns(2) | |
with col1: | |
resume_file = st.file_uploader("Upload Your Resume", type=["pdf", "docx", "doc", "txt"]) | |
with col2: | |
job_description = st.text_area("Job Description", height=200, placeholder="Paste the job description here...") | |
if st.button("Generate Cover Letter"): | |
if resume_file is None or not job_description.strip(): | |
st.error("Please upload a resume and enter a job description.") | |
else: | |
with st.spinner("Processing resume..."): | |
resume_text = extract_resume_text(resume_file) | |
candidate_json = parse_resume(resume_text) | |
current_date = datetime.today().strftime("%d - %b - %Y") | |
cover_letter = generate_cover_letter(candidate_json, job_description, current_date) | |
st.subheader("Extracted Candidate Profile (JSON)") | |
st.code(candidate_json, language="json") | |
st.subheader("Generated Cover Letter") | |
st.text_area("", cover_letter, height=300) | |
# ----- Tab 2: Resume Creator ----- | |
with tabs[1]: | |
st.header("Resume Creator") | |
st.markdown("Fill in your details below to generate a professional resume from scratch.") | |
with st.form("resume_form"): | |
col1, col2 = st.columns(2) | |
with col1: | |
first_name = st.text_input("First Name", placeholder="John") | |
with col2: | |
last_name = st.text_input("Last Name", placeholder="Doe") | |
location = st.text_input("Location", placeholder="City, State, Country") | |
work_experience = st.text_area("Work Experience", height=150, placeholder="List your past roles and achievements...") | |
school_experience = st.text_area("Education", height=150, placeholder="List your academic qualifications...") | |
skills = st.text_area("Skills", height=100, placeholder="List your key skills...") | |
submit = st.form_submit_button("Generate Resume") | |
if submit: | |
with st.spinner("Generating resume..."): | |
resume_text = generate_resume(first_name, last_name, location, work_experience, school_experience, skills) | |
st.subheader("Generated Resume") | |
st.text_area("", resume_text, height=400) | |