THIS IS MY main.py:
from scripts.embed_jobs import generate_embeddings
from scripts.parse_jobs import clean_job_dataset
import pandas as pd

# Step 1: Clean raw jobs.csv (if not done yet)
clean_job_dataset()

# Step 2: Generate embeddings from cleaned job data
generate_embeddings()

# Step 3: Preview final job data
df = pd.read_csv("data/cleaned_jobs.csv", low_memory=False)
print("📄 Columns in cleaned_jobs.csv:\n", df.columns.tolist())
print("\n🔍 Sample Cleaned Job Posting:")
print(df[["job_id", "title", "description"]].head(3))

from scripts.resume_matcher import match_resume_to_jobs

resume_input = """
Highly motivated Computer Science student with experience in Python, Streamlit, and backend APIs.
Built ML-based salary predictor using Scikit-learn. Familiar with LLMs, prompt engineering, and Gen AI tools.
Interned as full stack developer with exposure to cloud (AWS), version control, and agile workflows.
"""

print("\n🧠 Matching Resume to Jobs...\n")
matches = match_resume_to_jobs(resume_input)

for idx, job in enumerate(matches, 1):
    print(f"{idx}. {job['title']} @ {job['company']} ({job['location']})")
    print(f"   Type: {job['work_type']} | Exp: {job['experience']} | Similarity: {job['score']}\n")


main_ui.py:
import sys
import os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

import streamlit as st
from scripts.resume_matcher import match_resume_to_jobs
from scripts.explain_match import explain_match
import PyPDF2
import time

st.set_page_config(page_title="AI Resume Matcher", layout="centered")

st.title("AI Resume Matcher")
st.subheader("Match your resume with real job postings using Gen AI + FAISS")

resume_file = st.file_uploader("📎 Upload your Resume (PDF)", type=["pdf"])

location_filter = st.text_input("Location (optional)")
work_type_filter = st.selectbox("Work Type", ["All", "Full-time", "Part-time", "Remote"])
min_salary = st.number_input("Minimum Expected Salary (not used yet)", min_value=0, step=1000)

if resume_file and st.button("Match Jobs"):
    reader = PyPDF2.PdfReader(resume_file)
    resume_text = "".join([page.extract_text() for page in reader.pages])

    status = st.empty()
    status.info("📄 Matching resume to jobs...")

    with st.spinner("Processing..."):
        matches, logs = match_resume_to_jobs(resume_text, return_logs=True)

    for line in logs:
        status.info(line)

    st.subheader("Top Job Matches")

    if not matches:
        st.warning("No matches found. Try different filters or a better resume.")
    else:
        shown_any = False
        for i, job in enumerate(matches):
            if (
                (location_filter.lower() in job["location"].lower() if location_filter else True)
                and (job["work_type"] == work_type_filter or work_type_filter == "All")
            ):
                shown_any = True

                explanation = explain_match(
                    resume_text,
                    job,
                    job_description="",
                    job_skills=", ".join(job.get("skills_matched", []) + job.get("skills_missing", []))
                )
                time.sleep(1.2)

                matched = ", ".join(job["skills_matched"]) if job["skills_matched"] else "None"
                missing = ", ".join(job["skills_missing"]) if job["skills_missing"] else "None"

                st.markdown(f"""
                    <div style="padding: 14px 18px; border: 1px solid #ddd; border-radius: 12px; margin-bottom: 20px;">
                        <h4 style="margin-bottom: 6px;">{i+1}. {job['title']}</h4>
                        <p style="margin: 0;"><strong>Company:</strong> {job['company']}</p>
                        <p style="margin: 0;"><strong>Location:</strong> {job['location']}</p>
                        <p style="margin: 0;"><strong>Work Type:</strong> {job['work_type']}</p>
                        <p style="margin: 0;"><strong>Experience:</strong> {job['experience'] or "Not specified"}</p>
                        <p style="margin: 0;"><strong>Match Score:</strong> {job['score']}</p>
                        <p style="margin-top: 10px;"><strong>❌ Skills Missing:</strong> {missing}</p>
                        <p style="margin-top: 10px; color: #555;"><em>{explanation}</em></p>
                    </div>
                """, unsafe_allow_html=True)

        if not shown_any:
            st.warning("Matches found but none passed your filters.")


resume_matcher.py:
import numpy as np
import pandas as pd
from sentence_transformers import SentenceTransformer
import faiss
import re

# Load skill mapping dictionary (abr -> full name)
def load_skill_mapping():
    mapping_df = pd.read_csv("data/skill_mapping.csv")
    return dict(zip(mapping_df["skill_abr"], mapping_df["skill_name"]))

# Load job_id -> set(skill_abr)
def load_job_skills():
    df = pd.read_csv("data/job_skills.csv")
    return df.groupby("job_id")["skill_abr"].apply(set).to_dict()

# Helper: extract keywords from title (simple fallback)
def extract_keywords(text):
    if not text: return set()
    return set(re.findall(r'\b\w{3,}\b', text.lower()))

def load_faiss_index(embedding_file="data/job_embeddings.npy", logs=None):
    embeddings = np.load(embedding_file)
    index = faiss.IndexFlatL2(embeddings.shape[1])
    index.add(embeddings)
    if logs is not None:
        logs.append("📦 Loaded job embeddings and built FAISS index.")
    return index, embeddings

def match_resume_to_jobs(resume_text, top_k=5, return_logs=False):
    logs = [] if return_logs else None
    if not resume_text.strip():
        if logs: logs.append("❌ Empty resume text.")
        return ([], logs) if return_logs else []

    try:
        jobs_df = pd.read_csv("data/job_metadata.csv")
    except Exception as e:
        if logs: logs.append(f"❌ Metadata load failed: {e}")
        return ([], logs) if return_logs else []

    model = SentenceTransformer("all-MiniLM-L6-v2")
    resume_embedding = model.encode([resume_text])

    index, _ = load_faiss_index(logs=logs)
    distances, indices = index.search(resume_embedding, top_k)

    job_skills_map = load_job_skills()
    skill_names_map = load_skill_mapping()

    resume_text_lower = resume_text.lower()

    results = []
    for i in indices[0]:
        if i >= len(jobs_df): continue
        job = jobs_df.iloc[i]
        job_id = job.get("job_id")

        matched_skills = []
        missing_skills = []

        # Primary logic: use skill mapping
        if job_id in job_skills_map:
            for abr in job_skills_map[job_id]:
                skill = skill_names_map.get(abr, abr)
                if skill.lower() in resume_text_lower:
                    matched_skills.append(skill)
                else:
                    missing_skills.append(skill)
        else:
            # Fallback: extract keywords from job title (e.g. Java, Python)
            keywords = extract_keywords(job.get("title", ""))
            for kw in keywords:
                if kw in resume_text_lower:
                    matched_skills.append(kw)

        results.append({
            "title": job.get("title", ""),
            "company": job.get("company_name", ""),
            "location": job.get("location", ""),
            "work_type": job.get("formatted_work_type", ""),
            "experience": job.get("formatted_experience_level", ""),
            "score": round(float(1 - distances[0][list(indices[0]).index(i)]), 4),
            "skills_matched": matched_skills or [],
            "skills_missing": missing_skills or []
        })

    return (results, logs) if return_logs else results


check if everything is correct or not

IM using streamlit for frontend 
i actually merged some data into a preexisting data and cleaned it and combinded it. the new data set which i combined had indian cities instead of global soo that the filters are avalable for India, but the filters are not working in the frontend. check all the code and give the full and final codes