# 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""" ✅ Top Matches:
{matched_names}

📝 Summary:
{summary} """ except Exception as e: return f"❌ Error during matching: {e}" 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()