Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -16,6 +16,7 @@ import math
|
|
| 16 |
kw_extractor = yake.KeywordExtractor(n=2, top=30)
|
| 17 |
embedder = SentenceTransformer("all-MiniLM-L6-v2")
|
| 18 |
genai_client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))
|
|
|
|
| 19 |
|
| 20 |
SYSTEM_PROMPT = """
|
| 21 |
You are a job-matching assistant. Given a resume and job listings,
|
|
@@ -118,13 +119,9 @@ def format_posted(job):
|
|
| 118 |
# 6️⃣ Main pipeline
|
| 119 |
def find_jobs(file, added_kw, use_ai):
|
| 120 |
resume = extract_text(file) or ""
|
| 121 |
-
|
| 122 |
-
base_kws = added_kw.split(",") if added_kw.strip() else extract_keywords(resume)[:5]
|
| 123 |
-
print("Base_kws", base_kws)
|
| 124 |
keywords = [kw.strip() for kw in base_kws if kw.strip()]
|
| 125 |
-
|
| 126 |
-
jobs = fetch_arbeitnow(keywords) + fetch_remotive(keywords) + fetch_remoteok(keywords)
|
| 127 |
-
print("Jobs", jobs)
|
| 128 |
ranked = rank_jobs(resume, jobs)
|
| 129 |
print("Rank_jobs", ranked)
|
| 130 |
|
|
@@ -149,10 +146,10 @@ def find_jobs(file, added_kw, use_ai):
|
|
| 149 |
explanation = refine_with_ai(ranked, resume) if use_ai else ""
|
| 150 |
return table, explanation
|
| 151 |
|
| 152 |
-
def paginate(table, page):
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
|
| 157 |
# 7️⃣ Jobs in Markdown
|
| 158 |
def jobs_to_markdown(table, explanation, page, per_page=10):
|
|
@@ -174,14 +171,20 @@ def jobs_to_markdown(table, explanation, page, per_page=10):
|
|
| 174 |
f"| {row['Role']} | {row['Company']} | {row['Location']} "
|
| 175 |
f"| {row['Posted']} | {row['Score']} | {link} |\n"
|
| 176 |
)
|
| 177 |
-
# Append explanation *only* on page 1
|
| 178 |
-
if page == 1 and explanation:
|
| 179 |
-
|
| 180 |
return md
|
| 181 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 182 |
# 7️⃣ Gradio UI
|
| 183 |
with gr.Blocks(theme=gr.themes.Base()) as demo:
|
| 184 |
-
gr.Markdown("## 🌍 Global Job Finder
|
| 185 |
with gr.Row():
|
| 186 |
resume = gr.File(label="Upload Resume (PDF/DOCX)")
|
| 187 |
added = gr.Textbox(label="Add keywords (comma-separated)", placeholder="e.g. Python, ML")
|
|
@@ -195,28 +198,34 @@ with gr.Blocks(theme=gr.themes.Base()) as demo:
|
|
| 195 |
expl_state = gr.State("")
|
| 196 |
|
| 197 |
# outputs
|
| 198 |
-
|
| 199 |
-
|
|
|
|
| 200 |
|
| 201 |
-
# 1)
|
| 202 |
-
# - run find_jobs → (full_table, explanation)
|
| 203 |
-
# - store in state, reset page to 1
|
| 204 |
find_btn.click(
|
| 205 |
-
fn=
|
| 206 |
inputs=[resume, added, use_ai],
|
| 207 |
outputs=[jobs_state, expl_state, page_sel]
|
| 208 |
).then(
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
outputs=md_out
|
| 213 |
)
|
| 214 |
|
| 215 |
-
# 2)
|
| 216 |
page_sel.change(
|
| 217 |
-
fn=lambda tbl,
|
| 218 |
-
inputs=[jobs_state,
|
| 219 |
-
outputs=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
)
|
| 221 |
|
| 222 |
if __name__ == "__main__":
|
|
|
|
| 16 |
kw_extractor = yake.KeywordExtractor(n=2, top=30)
|
| 17 |
embedder = SentenceTransformer("all-MiniLM-L6-v2")
|
| 18 |
genai_client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))
|
| 19 |
+
PER_PAGE = 10
|
| 20 |
|
| 21 |
SYSTEM_PROMPT = """
|
| 22 |
You are a job-matching assistant. Given a resume and job listings,
|
|
|
|
| 119 |
# 6️⃣ Main pipeline
|
| 120 |
def find_jobs(file, added_kw, use_ai):
|
| 121 |
resume = extract_text(file) or ""
|
| 122 |
+
base_kws = added_kw.split(",") if added_kw.strip() else extract_keywords(resume)
|
|
|
|
|
|
|
| 123 |
keywords = [kw.strip() for kw in base_kws if kw.strip()]
|
| 124 |
+
jobs = fetch_arbeitnow(keywords) + fetch_remotive(keywords) + fetch_remoteok(keywords)
|
|
|
|
|
|
|
| 125 |
ranked = rank_jobs(resume, jobs)
|
| 126 |
print("Rank_jobs", ranked)
|
| 127 |
|
|
|
|
| 146 |
explanation = refine_with_ai(ranked, resume) if use_ai else ""
|
| 147 |
return table, explanation
|
| 148 |
|
| 149 |
+
# def paginate(table, page):
|
| 150 |
+
# per_page = 10
|
| 151 |
+
# start = (page-1)*per_page
|
| 152 |
+
# return table[start:start+per_page]
|
| 153 |
|
| 154 |
# 7️⃣ Jobs in Markdown
|
| 155 |
def jobs_to_markdown(table, explanation, page, per_page=10):
|
|
|
|
| 171 |
f"| {row['Role']} | {row['Company']} | {row['Location']} "
|
| 172 |
f"| {row['Posted']} | {row['Score']} | {link} |\n"
|
| 173 |
)
|
| 174 |
+
# # Append explanation *only* on page 1
|
| 175 |
+
# if page == 1 and explanation:
|
| 176 |
+
# md += "\n---\n**AI Explanation:**\n\n" + explanation
|
| 177 |
return md
|
| 178 |
|
| 179 |
+
def load_jobs_and_pages(resume, added_kw, use_ai):
|
| 180 |
+
full_table, explanation = find_jobs(resume, added_kw, use_ai) # your existing pipeline
|
| 181 |
+
total_pages = max(1, math.ceil(len(full_table) / PER_PAGE))
|
| 182 |
+
# Return: table-state, explanation-state, slider update
|
| 183 |
+
return full_table, explanation, gr.update(value=1, maximum=total_pages)
|
| 184 |
+
|
| 185 |
# 7️⃣ Gradio UI
|
| 186 |
with gr.Blocks(theme=gr.themes.Base()) as demo:
|
| 187 |
+
gr.Markdown("## 🌍 Global Job Finder")
|
| 188 |
with gr.Row():
|
| 189 |
resume = gr.File(label="Upload Resume (PDF/DOCX)")
|
| 190 |
added = gr.Textbox(label="Add keywords (comma-separated)", placeholder="e.g. Python, ML")
|
|
|
|
| 198 |
expl_state = gr.State("")
|
| 199 |
|
| 200 |
# outputs
|
| 201 |
+
jobs_md = gr.Markdown()
|
| 202 |
+
expl_md = gr.Markdown()
|
| 203 |
+
page_sel = gr.Slider(minimum=1, maximum=1, step=1, value=1, label="Page")
|
| 204 |
|
| 205 |
+
# 1) On search: populate states & slider
|
|
|
|
|
|
|
| 206 |
find_btn.click(
|
| 207 |
+
fn=load_jobs_and_pages,
|
| 208 |
inputs=[resume, added, use_ai],
|
| 209 |
outputs=[jobs_state, expl_state, page_sel]
|
| 210 |
).then(
|
| 211 |
+
fn=lambda tbl, pg: jobs_to_markdown(tbl, pg),
|
| 212 |
+
inputs=[jobs_state, page_sel],
|
| 213 |
+
outputs=[jobs_md]
|
|
|
|
| 214 |
)
|
| 215 |
|
| 216 |
+
# 2) On page change: re-render table only
|
| 217 |
page_sel.change(
|
| 218 |
+
fn=lambda tbl, pg: jobs_to_markdown(tbl, pg),
|
| 219 |
+
inputs=[jobs_state, page_sel],
|
| 220 |
+
outputs=[jobs_md]
|
| 221 |
+
)
|
| 222 |
+
|
| 223 |
+
# 3) Always render explanation from state
|
| 224 |
+
expl_state.change(
|
| 225 |
+
fn=lambda expl: expl,
|
| 226 |
+
inputs=[expl_state],
|
| 227 |
+
outputs=[expl_md],
|
| 228 |
+
queue=False
|
| 229 |
)
|
| 230 |
|
| 231 |
if __name__ == "__main__":
|