# -*- 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, convert_from_bytes from docx import Document import subprocess import shutil import tempfile from PIL import Image import io from docx2pdf import convert import docx import numpy as np # Create temporary directories temp_dir = tempfile.mkdtemp() import subprocess def check_poppler_installation(): """Check if poppler is installed and accessible""" try: # Try to execute pdftoppm (part of poppler-utils) result = subprocess.run(['pdftoppm', '-v'], capture_output=True, text=True) st.success("Poppler is installed and accessible") return True except FileNotFoundError: st.warning("Poppler not found in PATH. Using fallback display methods.") return False # Call this at startup check_poppler_installation() # Helper function to save uploaded files temporarily and return their paths def save_uploaded_file(content): if hasattr(content, 'name'): # Check if it's a file-like object file_path = os.path.join("/tmp", content.name) with open(file_path, "wb") as f: f.write(content.read()) else: # It's a string (the file contents) file_path = os.path.join("/tmp", "temp_upload") with open(file_path, "w") as f: f.write(str(content)) return file_path # 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(""" """, unsafe_allow_html=True) # Add ResumeMagic Logo # st.image("logo.jpeg", use_container_width=True) st.markdown('
', unsafe_allow_html=True) st.image("logo.jpeg", width=80) st.markdown('', 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('

Low chance, skills gap identified!

', unsafe_allow_html=True) pie_colors = ['#FF4B4B', '#E5E5E5'] elif 50 <= similarity_score < 70: st.markdown('

Good chance but you can improve further!

', unsafe_allow_html=True) pie_colors = ['#FFC107', '#E5E5E5'] else: st.markdown('

Excellent! You can submit your CV.

', 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_file(file_name): if hasattr(uploaded_file, 'name'): file_path = os.path.join("/tmp", uploaded_file.name) with open(file_path, "wb") as f: f.write(uploaded_file.read()) else: file_path = os.path.join("/tmp", "temp_upload") with open(file_path, "w") as f: f.write(uploaded_file) return file_path def save_docx_as_pdf(input_path, output_path='output.pdf'): if input_path.lower().endswith('.docx'): try: # Attempt to use unoconv subprocess.run(['unoconv', '-o', output_path, input_path]) if not os.path.exists(output_path): raise FileNotFoundError("unoconv failed to convert DOCX to PDF") except FileNotFoundError: # Fallback to text-based display with open(output_path, 'w') as f: f.write(input_path.read()) elif input_path.lower().endswith('.pdf'): shutil.copy(input_path, output_path) else: raise ValueError("Unsupported file format. Please upload a .docx or .pdf file.") # def save_docx_as_pdf(input_path, output_path='output.pdf'): # if input_path.lower().endswith('.docx'): # from docx2pdf import convert # convert(input_path, output_path) # elif input_path.lower().endswith('.pdf'): # shutil.copy(input_path, output_path) # else: # raise ValueError("Unsupported file format. Please upload a .docx or .pdf file.") def save_docx_as_pdf2(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) # subprocess.run(['libreoffice', '--headless', '--convert-to', 'pdf', temp_doc_path, '--outdir', os.path.dirname(output_path)]) def save_docx_as_pdf1(input_path, output_path='output.pdf'): if input_path.lower().endswith('.docx'): from docx2pdf import convert convert(input_path, output_path) elif input_path.lower().endswith('.pdf'): shutil.copy(input_path, output_path) else: raise ValueError("Unsupported file format. Please upload a .docx or .pdf file.") # if uploaded_resume.type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document": # save_docx_as_pdf(resume_path, 'uploaded_resume.pdf') # display_doc_as_image('uploaded_resume.pdf') def display_doc_as_image2(pdf_path): try: images = convert_from_path(pdf_path, size=800) display(Image(filename=images[0].filename)) except Exception as e: st.error(f"Failed to display image: {str(e)}") def display_doc_as_image3(pdf_path): try: images = convert_from_path(pdf_path, size=800) display(Image.fromarray(images[0])) except Exception as e: st.error(f"Failed to display image: {str(e)}") def display_doc_as_image1(pdf_path): try: img = Image.open(pdf_path) st.image(img) except Exception as e: st.error(f"Failed to display image: {str(e)}") def display_doc_as_image(file_path): """Display document with multiple fallback options""" try: # First attempt: Use pdf2image with explicit poppler path try: from pdf2image import convert_from_path # Try common poppler paths on Linux poppler_paths = [ '/usr/bin/pdftoppm', # Common Linux path '/opt/homebrew/bin/pdftoppm', # Mac Homebrew path 'poppler-utils' # Package name ] for poppler_path in poppler_paths: try: images = convert_from_path( file_path, size=800, poppler_path=os.path.dirname(poppler_path) if os.path.isfile(poppler_path) else None ) st.image(images[0]) return except Exception: continue # If no poppler path worked, try without specifying path images = convert_from_path(file_path, size=800) st.image(images[0]) except Exception as e: # Second attempt: Use Streamlit's native PDF display try: with open(file_path, "rb") as pdf_file: pdf_bytes = pdf_file.read() st.pdf(pdf_bytes) return except Exception as pdf_error: st.error(f"Error displaying PDF: {str(pdf_error)}") # Third attempt: If it's a DOCX file, try to extract text if file_path.lower().endswith('.docx'): try: doc = Document(file_path) text = '\n'.join([paragraph.text for paragraph in doc.paragraphs]) st.text(text) return except Exception as docx_error: st.error(f"Error displaying DOCX: {str(docx_error)}") except Exception as main_error: st.error(f"Error in display function: {str(main_error)}") st.info("Displaying file path for debugging: " + file_path) # Last resort: Try to read and display raw bytes try: with open(file_path, 'rb') as f: bytes_data = f.read() if file_path.lower().endswith('.pdf'): st.pdf(bytes_data) else: st.text("File content preview not available") except Exception as final_error: st.error(f"Final fallback failed: {str(final_error)}") # def display_doc_as_image1(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) # from IPython.display import display, Image # images = convert_from_bytes(open(pdf_path, 'rb').read(), size=800) # display(images[0]) # 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(""" """, 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) # resume_path = save_uploaded_file(generated_resume) # st.markdown("Generated Tailored Resume:") # st.write(generated_resume) #Autoscroll st.markdown(""" """, unsafe_allow_html=True) # 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) # 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 with tempfile.NamedTemporaryFile(delete=False, suffix=".docx") as temp_doc: temp_doc_path = temp_doc.name doc.save(temp_doc_path) # Now pass the path to any function that expects a file path pdf_path = '/tmp/generated_resume.pdf' save_docx_as_pdf(temp_doc_path, pdf_path) # Display the generated PDF or handle further processing display_doc_as_image(pdf_output_path) with tempfile.NamedTemporaryFile(suffix='.docx') as temp_doc: doc = Document() doc.add_paragraph(generated_resume) # doc.save(temp_doc.name) # resume_bytes = BytesIO() # doc.save(resume_bytes) # resume_bytes.seek(0) # Convert DOCX to PDF # pdf_path = f"temp_{os.path.basename(temp_doc.name)}.pdf" # convert(temp_doc.name, pdf_path) # save_docx_as_pdf(temp_doc.name, pdf_path) pdf_path = '/tmp/generated_resume.docx' doc.save(pdf_path) # pdf_path = save_uploaded_file(resume_bytes) save_docx_as_pdf(generated_resume, pdf_path) # Display resumes side by side col1, col2 = st.columns(2) with col1: st.write("Uploaded Resume:") if resume_path: display_doc_as_image(resume_path) else: st.warning("No resume file found") with col2: st.write("Generated Resume:") if pdf_path: display_doc_as_image(pdf_path) else: st.warning("No generated resume file found") # Allow users to download both PDFs # st.download_button( # label="Download Uploaded Resume", # data=resume_bytes, # file_name="uploaded_resume.pdf", # mime="application/pdf" # ) st.download_button( label="Download Generated Resume", data=open(pdf_path, 'rb').read(), file_name="generated_resume.pdf", mime="application/pdf" ) st.download_button( label="Generated Resume (Word)", data=resume_bytes, file_name="tailored_resume.docx", mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document" ) # doc = Document() # doc.add_paragraph(generated_resume) # resume_bytes = BytesIO() # doc.save(resume_bytes) # resume_bytes.seek(0) # gen_resume_path = save_uploaded_file(resume_bytes) # # uploaded_resume_path = save_uploaded_file(resume) # col1, col2 = st.columns(2) # with col1: # 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(gen_resume_path, 'tailored_resume.pdf') # display_doc_as_image('tailored_resume.pdf') # 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.")