cv / app.py
saherPervaiz's picture
Update app.py
a69a9de verified
raw
history blame
3.76 kB
# app.py
import os
import gradio as gr
from text_extractor import extract_text_from_file
from embedder import get_embeddings
from vector_store import create_faiss_index, search_similar_cvs
from groq_api import summarize_match
# Global state
cv_texts = []
cv_names = []
cv_vectors = []
faiss_index = None
def upload_cvs(files):
global cv_texts, cv_names, cv_vectors, faiss_index
try:
cv_texts = [extract_text_from_file(f.name) for f in files]
cv_names = [f.name for f in files]
cv_vectors = get_embeddings(cv_texts)
import numpy as np
if cv_vectors is None or np.array(cv_vectors).size == 0:
return "❌ No valid CVs extracted or embedded."
faiss_index = create_faiss_index(cv_vectors)
return f"βœ… Uploaded and indexed {len(files)} CVs."
except Exception as e:
return f"❌ Error during upload: {e}"
def match_jd(jd_text):
global faiss_index
try:
if not faiss_index:
return "❌ Please upload CVs first."
if not jd_text.strip():
return "❌ Job description is empty."
jd_vector = get_embeddings([jd_text])[0]
top_k_indices = search_similar_cvs(jd_vector, faiss_index, k=3)
import os
matched_names = [os.path.basename(cv_names[i]) for i in top_k_indices]
matched_texts = [
cv_texts[i][:500] if cv_texts[i].strip() else "[No CV content]"
for i in top_k_indices
]
summary = summarize_match(jd_text, matched_names, matched_texts)
return f"""
βœ… <span style='color:#16a34a; font-weight:bold;'>Top Matches:</span><br>{matched_names}<br><br>
πŸ“ <span style='color:#3b82f6; font-weight:bold;'>Summary:</span><br>{summary}
"""
except Exception as e:
return f"<span style='color:red;'>❌ Error during matching: {e}</span>"
def clear_data():
global cv_texts, cv_names, cv_vectors, faiss_index
cv_texts, cv_names, cv_vectors, faiss_index = [], [], [], None
return "🧹 All data cleared. You can now start fresh."
# ======================
# TABBED PROFESSIONAL UI
# ======================
with gr.Blocks(css="""
.gr-button { background-color: #2563eb; color: white; font-weight: bold; }
.gr-button:hover { background-color: #1d4ed8; }
textarea, input[type='file'] { border: 2px solid #3b82f6 !important; }
.gr-textbox label { color: #111827; font-weight: 600; }
""") as upload_tab:
gr.Markdown("## πŸ“€ Upload CVs")
gr.Markdown("Upload candidate CVs in PDF or DOCX format.")
cv_upload = gr.File(label="Upload CVs", file_types=[".pdf", ".docx"], file_count="multiple")
upload_button = gr.Button("πŸ“ Upload & Index CVs")
upload_status = gr.Textbox(label="Status", interactive=False)
upload_button.click(upload_cvs, inputs=[cv_upload], outputs=[upload_status])
with gr.Blocks() as match_tab:
gr.Markdown("## πŸ“‹ Match Job Description to CVs")
jd_input = gr.Textbox(label="Paste Job Description", lines=8, placeholder="e.g. Looking for a Python Data Analyst...")
match_button = gr.Button("πŸ” Match CVs")
match_result = gr.HTML()
match_button.click(match_jd, inputs=[jd_input], outputs=[match_result])
with gr.Blocks() as reset_tab:
gr.Markdown("## 🧹 Clear All Data")
gr.Markdown("Click below to reset the app and upload new CVs.")
clear_button = gr.Button("Reset App")
clear_output = gr.Textbox(label="Reset Status", interactive=False)
clear_button.click(clear_data, inputs=[], outputs=[clear_output])
# Menu Bar Style Tabs
app = gr.TabbedInterface(
interface_list=[upload_tab, match_tab, reset_tab],
tab_names=["πŸ“€ Upload CVs", "πŸ“‹ Match JD", "🧹 Reset"]
)
if __name__ == "__main__":
app.launch()