Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -66,41 +66,73 @@ def call_zephyr(prompt):
|
|
| 66 |
return f"Zephyr API error: {result['error']}"
|
| 67 |
return result[0].get("generated_text", "")
|
| 68 |
|
| 69 |
-
def
|
|
|
|
|
|
|
|
|
|
| 70 |
data = fetch_json_local(JSON_FILE)
|
| 71 |
-
|
| 72 |
for person in data:
|
| 73 |
work_exps = person.get("work_experiences", [])
|
| 74 |
if len(work_exps) == 0:
|
| 75 |
continue
|
| 76 |
-
|
|
|
|
|
|
|
|
|
|
| 77 |
continue
|
| 78 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
prompt = f"""
|
| 80 |
-
You are an HR assistant.
|
| 81 |
-
The category
|
| 82 |
|
| 83 |
Candidate JSON: {json.dumps(person)}
|
| 84 |
|
| 85 |
-
|
| 86 |
"""
|
| 87 |
-
|
| 88 |
-
if
|
| 89 |
-
|
|
|
|
|
|
|
| 90 |
"Name": person.get("name"),
|
| 91 |
"Email": person.get("email"),
|
| 92 |
"Phone": person.get("phone"),
|
| 93 |
"Location": person.get("location"),
|
| 94 |
-
"Roles": ", ".join(
|
| 95 |
"Skills": ", ".join(person.get("skills", [])),
|
| 96 |
"Salary": person.get("annual_salary_expectation", {}).get("full-time", "N/A")
|
| 97 |
})
|
| 98 |
|
| 99 |
-
if len(
|
| 100 |
return pd.DataFrame()
|
| 101 |
|
| 102 |
-
df = pd.DataFrame(
|
| 103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
|
| 105 |
# ----------------------------
|
| 106 |
# GRADIO INTERFACE
|
|
@@ -108,9 +140,7 @@ Respond only 'Yes' or 'No'.
|
|
| 108 |
def run_dashboard(category):
|
| 109 |
if category not in CATEGORIES:
|
| 110 |
return pd.DataFrame()
|
| 111 |
-
df =
|
| 112 |
-
if df.empty:
|
| 113 |
-
return pd.DataFrame()
|
| 114 |
return df
|
| 115 |
|
| 116 |
category_options = list(CATEGORIES.keys())
|
|
@@ -118,10 +148,10 @@ category_options = list(CATEGORIES.keys())
|
|
| 118 |
demo = gr.Interface(
|
| 119 |
fn=run_dashboard,
|
| 120 |
inputs=gr.Dropdown(category_options, label="Select Category"),
|
| 121 |
-
outputs=gr.Dataframe(label="
|
| 122 |
live=False,
|
| 123 |
title="Startup Candidate Dashboard - Zephyr-7B-Beta",
|
| 124 |
-
description="
|
| 125 |
)
|
| 126 |
|
| 127 |
if __name__ == "__main__":
|
|
|
|
| 66 |
return f"Zephyr API error: {result['error']}"
|
| 67 |
return result[0].get("generated_text", "")
|
| 68 |
|
| 69 |
+
def filter_candidates_by_category(category_name, job_titles):
|
| 70 |
+
"""
|
| 71 |
+
Step 1: Filter candidates based on actual work experience roles.
|
| 72 |
+
"""
|
| 73 |
data = fetch_json_local(JSON_FILE)
|
| 74 |
+
filtered = []
|
| 75 |
for person in data:
|
| 76 |
work_exps = person.get("work_experiences", [])
|
| 77 |
if len(work_exps) == 0:
|
| 78 |
continue
|
| 79 |
+
|
| 80 |
+
# Exclude candidates who ONLY have Full Stack roles
|
| 81 |
+
non_fullstack_roles = [exp.get("roleName") for exp in work_exps if "full stack developer" not in exp.get("roleName","").lower()]
|
| 82 |
+
if not non_fullstack_roles:
|
| 83 |
continue
|
| 84 |
|
| 85 |
+
# Include if any role matches the category
|
| 86 |
+
if any(role in job_titles for role in non_fullstack_roles):
|
| 87 |
+
filtered.append(person)
|
| 88 |
+
return filtered
|
| 89 |
+
|
| 90 |
+
def get_final_recommendations(category_name, job_titles, top_n=5):
|
| 91 |
+
"""
|
| 92 |
+
Step 2: Use Zephyr LLM for final recommendation and pick top N candidates.
|
| 93 |
+
"""
|
| 94 |
+
candidates = filter_candidates_by_category(category_name, job_titles)
|
| 95 |
+
recommended = []
|
| 96 |
+
|
| 97 |
+
for person in candidates:
|
| 98 |
prompt = f"""
|
| 99 |
+
You are an HR assistant. Review this candidate and determine if they are suitable for the category '{category_name}'.
|
| 100 |
+
The category includes the following job titles: {job_titles}
|
| 101 |
|
| 102 |
Candidate JSON: {json.dumps(person)}
|
| 103 |
|
| 104 |
+
Based on their work experience, skills, and education, respond only 'Yes' if suitable, otherwise 'No'.
|
| 105 |
"""
|
| 106 |
+
response = call_zephyr(prompt)
|
| 107 |
+
if response and "Yes" in response:
|
| 108 |
+
work_exps = person.get("work_experiences", [])
|
| 109 |
+
non_fullstack_roles = [exp.get("roleName") for exp in work_exps if "full stack developer" not in exp.get("roleName","").lower()]
|
| 110 |
+
recommended.append({
|
| 111 |
"Name": person.get("name"),
|
| 112 |
"Email": person.get("email"),
|
| 113 |
"Phone": person.get("phone"),
|
| 114 |
"Location": person.get("location"),
|
| 115 |
+
"Roles": ", ".join(non_fullstack_roles),
|
| 116 |
"Skills": ", ".join(person.get("skills", [])),
|
| 117 |
"Salary": person.get("annual_salary_expectation", {}).get("full-time", "N/A")
|
| 118 |
})
|
| 119 |
|
| 120 |
+
if len(recommended) == 0:
|
| 121 |
return pd.DataFrame()
|
| 122 |
|
| 123 |
+
df = pd.DataFrame(recommended)
|
| 124 |
+
|
| 125 |
+
# Optional: Sort by salary if available (ascending)
|
| 126 |
+
def parse_salary(s):
|
| 127 |
+
if isinstance(s, str) and s.startswith("$"):
|
| 128 |
+
return float(s.replace("$","").replace(",",""))
|
| 129 |
+
return float('inf')
|
| 130 |
+
if "Salary" in df.columns:
|
| 131 |
+
df["Salary_sort"] = df["Salary"].apply(parse_salary)
|
| 132 |
+
df = df.sort_values("Salary_sort")
|
| 133 |
+
df = df.drop(columns=["Salary_sort"])
|
| 134 |
+
|
| 135 |
+
return df.head(top_n) # return top N candidates
|
| 136 |
|
| 137 |
# ----------------------------
|
| 138 |
# GRADIO INTERFACE
|
|
|
|
| 140 |
def run_dashboard(category):
|
| 141 |
if category not in CATEGORIES:
|
| 142 |
return pd.DataFrame()
|
| 143 |
+
df = get_final_recommendations(category, CATEGORIES[category], top_n=5)
|
|
|
|
|
|
|
| 144 |
return df
|
| 145 |
|
| 146 |
category_options = list(CATEGORIES.keys())
|
|
|
|
| 148 |
demo = gr.Interface(
|
| 149 |
fn=run_dashboard,
|
| 150 |
inputs=gr.Dropdown(category_options, label="Select Category"),
|
| 151 |
+
outputs=gr.Dataframe(label="Top 5 Recommended Candidates"),
|
| 152 |
live=False,
|
| 153 |
title="Startup Candidate Dashboard - Zephyr-7B-Beta",
|
| 154 |
+
description="View top 5 final recommended candidates filtered by category using Zephyr LLM."
|
| 155 |
)
|
| 156 |
|
| 157 |
if __name__ == "__main__":
|