resumeMagic / app.py
pktpaulie's picture
Add Poppler Path
799a461 verified
raw
history blame
9.06 kB
# -*- coding: utf-8 -*-
import streamlit as st
import os
import pandas as pd
import matplotlib.pyplot as plt
from resume_generation_gemini_pro import generate_gemini
from similarity_score_refined import similarity_main
from pdf2image import convert_from_path
# Helper function to save uploaded files temporarily and return their paths
def save_uploaded_file(uploaded_file):
file_path = os.path.join("/tmp", uploaded_file.name)
with open(file_path, "wb") as f:
f.write(uploaded_file.getbuffer())
return file_path
# Custom CSS for styling
st.markdown("""
<style>
.main {
background-color: #f5f5f5;
font-family: Arial, sans-serif;
}
h1, h2 {
color: #4B7BE5;
text-align: center;
}
.stContainer {
# background-color: #000000;
display: flex;
justify-content: center;
align-items: center;
# max-width: 100%;
height: 30%;
width: 45%;
}
.logo-container {
# background-color: black;
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
# max-width: 100%;
}
.logo-container img {
max-width: 60%;
height: 40%;
}
.stButton>button {
# background-color: #4B7BE5;
# color: white;
# font-size: 18px;
appearance: none;
background-color: transparent;
border: 0.125em solid #1A1A1A;
border-radius: 0.9375em;
box-sizing: border-box;
color: #3B3B3B;
cursor: pointer;
display: inline-block;
font-family: Roobert,-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";
font-size: 16px;
font-weight: 600;
line-height: normal;
margin: 0;
min-height: 3.75em;
min-width: 0;
outline: none;
padding: 1em 2.3em;
text-align: center;
text-decoration: none;
transition: all 300ms cubic-bezier(.23, 1, 0.32, 1);
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
will-change: transform;
}
.stButton>button:hover {
color: #fff;
background-color: #1A1A1A;
box-shadow: rgba(0, 0, 0, 0.25) 0 8px 15px;
transform: translateY(-2px);
border: none !important;
}
/* From Uiverse.io by e-coders */
# .stButton>btn:disabled {
# pointer-events: none;
# }
.stButton>:active {
box-shadow: none;
transform: translateY(0);
}
</style>
""", unsafe_allow_html=True)
# Add ResumeMagic Logo
# st.image("logo.jpeg", use_container_width=True)
st.markdown('<div class="logo-container"></div>', unsafe_allow_html=True)
st.image("logo.jpeg", width=80)
st.markdown('</div>', unsafe_allow_html=True)
# Title and Description
st.title("Resume Tailoring with Google Generative AI")
st.markdown("### Upload your resume and job description to check similarity and generate a tailored resume.")
# Two columns for file uploaders
col1, col2 = st.columns(2)
with col1:
uploaded_resume = st.file_uploader("Upload Current Resume (.docx or .pdf)", type=["docx", "pdf"], key="resume")
with col2:
uploaded_job_description = st.file_uploader("Upload Job Description (.docx or .pdf)", type=["docx", "pdf"], key="job_description")
def get_score(resume_path, job_description_path):
similarity_score = similarity_main(resume_path, job_description_path)
if isinstance(similarity_score, str) and '%' in similarity_score:
similarity_score = float(similarity_score.replace('%', ''))
# Display messages based on score range
if similarity_score < 50:
st.markdown('<p style="color: red; font-weight: bold;">Low chance, skills gap identified!</p>', unsafe_allow_html=True)
pie_colors = ['#FF4B4B', '#E5E5E5']
elif 50 <= similarity_score < 70:
st.markdown('<p style="color: red; font-weight: bold;">Good chance but you can improve further!</p>', unsafe_allow_html=True)
pie_colors = ['#FFC107', '#E5E5E5']
else:
st.markdown('<p style="color: green; font-weight: bold;">Excellent! You can submit your CV.</p>', unsafe_allow_html=True)
pie_colors = ['#4CAF50', '#E5E5E5']
return similarity_score, pie_colors
def display_score(similarity, colors):
# Display Score as a Pie Chart
st.markdown(f"### Resume - Job Match: {int(similarity_score)}%")
# Pie chart to show similarity
fig, ax = plt.subplots()
# ax.pie([similarity_score, 100 - similarity_score], labels=['Match', 'Difference'], autopct='%1.1f%%', startangle=140, colors=['#4B7BE5', '#E5E5E5'])
ax.pie([similarity_score, 100 - similarity_score], labels=['Match', 'Difference'], autopct='%1.1f%%', startangle=140, colors=pie_colors)
ax.axis('equal')
st.pyplot(fig)
def save_docx_as_pdf(doc_content, output_path='output.pdf'):
# Save document content as a .docx file
temp_doc_path = 'temp.docx'
doc = Document()
doc.add_paragraph(doc_content)
doc.save(temp_doc_path)
# Convert .docx to PDF
from docx2pdf import convert
convert(temp_doc_path, output_path)
os.remove(temp_doc_path)
def display_doc_as_image(pdf_path):
poppler_path = 'usr/bin'
images = convert_from_path(pdf_path, poppler_path=poppler_path)
for img in images:
buf = BytesIO()
img.save(buf, format="PNG")
st.image(buf)
# Process if files are uploaded
if uploaded_resume and uploaded_job_description:
# Save files
resume_path = save_uploaded_file(uploaded_resume)
job_description_path = save_uploaded_file(uploaded_job_description)
# Similarity Score Section
st.markdown("---")
# st.subheader("Check Job Match")
if st.button("Resume-JD Matching"):
with st.spinner("Computing Match"):
similarity_score, pie_colors = get_score(resume_path, job_description_path)
display_score(similarity_score, pie_colors)
#Autoscroll
st.markdown("""
<script>
window.scrollTo(0, document.body.scrollHeight);
</script>
""", unsafe_allow_html=True)
# Generate Tailored Resume Section
st.markdown("---")
# st.subheader("Tailor Resume")
if st.button("Tailor Resume"):
with st.spinner("Generating resume..."):
generated_resume, new_resume_path = generate_gemini(resume_path, job_description_path)
# st.markdown("Generated Tailored Resume:")
# st.write(generated_resume)
#Autoscroll
st.markdown("""
<script>
window.scrollTo(0, document.body.scrollHeight);
</script>
""", unsafe_allow_html=True)
col1, col2 = st.columns(2)
with col1:
st.markdown("### Uploaded Resume:")
# if resume_path.endswith('.docx'):
# save_docx_as_pdf(uploaded_resume.getvalue().decode('utf-8'), 'uploaded_resume.pdf')
if uploaded_resume.type == "application/pdf":
display_doc_as_image(resume_path)
else:
save_docx_as_pdf(resume_path, 'uploaded_resume.pdf')
display_doc_as_image('uploaded_resume.pdf')
with col2:
st.markdown("### Tailored Resume:")
save_docx_as_pdf(generated_resume, 'tailored_resume.pdf')
display_doc_as_image('tailored_resume.pdf')
with st.spinner("Computing Match"):
similarity_score, pie_colors = get_score(resume_path, job_description_path)
display_score(similarity_score, pie_colors)
if generated_resume is not None:
from io import BytesIO
from docx import Document
doc = Document()
doc.add_paragraph(generated_resume)
resume_bytes = BytesIO()
doc.save(resume_bytes)
resume_bytes.seek(0)
st.download_button(
label="Download Resume",
data=resume_bytes,
file_name="tailored_resume.docx",
mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document"
)
else:
st.warning("Please upload both the resume and job description files.")