Spaces:
Sleeping
Sleeping
Commit ยท
53c490d
1
Parent(s): bce071b
feat(ui): merge legacy platform checkboxes into unified platform selector
Browse filesRemove the 6 separate legacy checkboxes (LinkedIn, Indeed, Glassdoor,
Remotive, WeWorkRemotely, Naukri) and combine everything into a single
"Job Platforms" grouped multiselect. Routing is preserved โ those 6
platforms still go through their dedicated high-quality scrapers while
all 160+ other platforms go through EverJobsScraper.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- HISTORY.md +12 -0
- README.md +1 -1
- ui.py +16 -31
HISTORY.md
CHANGED
|
@@ -4,6 +4,18 @@ A running log of everything built, fixed, and changed. Most recent first.
|
|
| 4 |
|
| 5 |
---
|
| 6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
## 2026-06-13 โ Phase 1: ever-jobs Integration (160+ Platforms)
|
| 8 |
|
| 9 |
### New Features
|
|
|
|
| 4 |
|
| 5 |
---
|
| 6 |
|
| 7 |
+
## 2026-06-13 โ Unified Platform Selector + ATS + HTML Rendering Fixes
|
| 8 |
+
|
| 9 |
+
### Changes
|
| 10 |
+
- **Unified platform selector**: Merged the 6 legacy checkboxes ("๐ Job Platforms") and the grouped ever-jobs selector ("๐ ever-jobs Platforms") into a single "๐ Job Platforms" section. One place to search all 170 platforms. Selecting LinkedIn/Indeed/Glassdoor/Remotive/WeWorkRemotely/Naukri still routes to their dedicated high-quality scrapers; everything else goes through EverJobsScraper.
|
| 11 |
+
- **ATS min_score default**: Changed slider default from 6 to 1 โ LLM resumes now generated for ALL jobs regardless of score.
|
| 12 |
+
- **HTML rendering fix**: Switched all 5 `st.markdown(..., unsafe_allow_html=True)` calls to `st.html()` โ fixes raw `<span>`/`<a>` tags showing as plain text in job cards (Streamlit 1.45+ regression).
|
| 13 |
+
|
| 14 |
+
### Modified Files
|
| 15 |
+
- `ui.py` โ removed 6 legacy checkboxes, renamed section label, updated platforms_cfg, updated pipeline routing to use unified `all_platforms` key
|
| 16 |
+
|
| 17 |
+
---
|
| 18 |
+
|
| 19 |
## 2026-06-13 โ Phase 1: ever-jobs Integration (160+ Platforms)
|
| 20 |
|
| 21 |
### New Features
|
README.md
CHANGED
|
@@ -92,7 +92,7 @@ The pipeline calls `ensure_running()` automatically before any ever-jobs platfor
|
|
| 92 |
|
| 93 |
### Platform Selection
|
| 94 |
|
| 95 |
-
The UI
|
| 96 |
|
| 97 |
| Group | Count | Description |
|
| 98 |
|-------|-------|-------------|
|
|
|
|
| 92 |
|
| 93 |
### Platform Selection
|
| 94 |
|
| 95 |
+
The UI has a single **"๐ Job Platforms"** section with three groups. Selecting LinkedIn, Indeed, Glassdoor, Remotive, WeWorkRemotely, or Naukri uses their dedicated high-quality scrapers; all other platforms go through the ever-jobs REST API.
|
| 96 |
|
| 97 |
| Group | Count | Description |
|
| 98 |
|-------|-------|-------------|
|
ui.py
CHANGED
|
@@ -489,23 +489,8 @@ with st.expander("โ๏ธ Configure Run", expanded=not (st.session_state.running
|
|
| 489 |
|
| 490 |
st.divider()
|
| 491 |
|
| 492 |
-
# โโ Row 3:
|
| 493 |
st.markdown('<p class="section-label">๐ Job Platforms</p>', unsafe_allow_html=True)
|
| 494 |
-
pc1, pc2, pc3, pc4, pc5, pc6 = st.columns(6)
|
| 495 |
-
use_linkedin = pc1.checkbox("๐ต LinkedIn", value=True)
|
| 496 |
-
use_indeed = pc2.checkbox("๐ Indeed", value=True)
|
| 497 |
-
use_glassdoor = pc3.checkbox("๐ข Glassdoor", value=True)
|
| 498 |
-
use_remotive = pc4.checkbox("๐ Remotive", value=True,
|
| 499 |
-
help="Remote/WFH PM jobs globally")
|
| 500 |
-
use_wwr = pc5.checkbox("๐ป WeWorkRemotely", value=False,
|
| 501 |
-
help="Remote jobs, worldwide")
|
| 502 |
-
use_naukri = pc6.checkbox("๐ฎ๐ณ Naukri", value=False,
|
| 503 |
-
help="Often blocked by Akamai anti-bot")
|
| 504 |
-
|
| 505 |
-
st.divider()
|
| 506 |
-
|
| 507 |
-
# โโ Row 3b: ever-jobs platform selector โโ
|
| 508 |
-
st.markdown('<p class="section-label">๐ ever-jobs Platforms (160+)</p>', unsafe_allow_html=True)
|
| 509 |
from src.ever_jobs_bridge.platforms import PLATFORM_GROUPS, INDIA_DEFAULT_PLATFORMS, EVER_JOBS_PLATFORMS
|
| 510 |
|
| 511 |
ej_col1, ej_col2, ej_col3 = st.columns(3)
|
|
@@ -560,7 +545,7 @@ with st.expander("โ๏ธ Configure Run", expanded=not (st.session_state.running
|
|
| 560 |
icon="โ ๏ธ",
|
| 561 |
)
|
| 562 |
elif use_ever_jobs:
|
| 563 |
-
st.caption(f"โ {len(ever_jobs_platforms)}
|
| 564 |
|
| 565 |
st.divider()
|
| 566 |
|
|
@@ -623,10 +608,7 @@ if start and not st.session_state.running:
|
|
| 623 |
for s in PIPELINE_STEPS}
|
| 624 |
|
| 625 |
platforms_cfg = {
|
| 626 |
-
"
|
| 627 |
-
"glassdoor": use_glassdoor, "naukri": use_naukri,
|
| 628 |
-
"remotive": use_remotive, "weworkremotely": use_wwr,
|
| 629 |
-
"ever_jobs_platforms": ever_jobs_platforms,
|
| 630 |
}
|
| 631 |
job_search_cfg = {
|
| 632 |
"roles": roles, "locations": locations,
|
|
@@ -741,45 +723,48 @@ if start and not st.session_state.running:
|
|
| 741 |
seen_tc: set = set()
|
| 742 |
skipped_dup: int = 0
|
| 743 |
|
| 744 |
-
|
| 745 |
-
|
|
|
|
|
|
|
|
|
|
| 746 |
from src.scrapers.linkedin import LinkedInScraper
|
| 747 |
scraper_map["linkedin"] = ("LinkedIn", LinkedInScraper())
|
| 748 |
else:
|
| 749 |
_step_skip("linkedin")
|
| 750 |
|
| 751 |
-
if
|
| 752 |
from src.scrapers.indeed import IndeedScraper
|
| 753 |
scraper_map["indeed"] = ("Indeed", IndeedScraper())
|
| 754 |
else:
|
| 755 |
_step_skip("indeed")
|
| 756 |
|
| 757 |
-
if
|
| 758 |
from src.scrapers.glassdoor import GlassdoorScraper
|
| 759 |
scraper_map["glassdoor"] = ("Glassdoor", GlassdoorScraper())
|
| 760 |
else:
|
| 761 |
_step_skip("glassdoor")
|
| 762 |
|
| 763 |
-
if
|
| 764 |
from src.scrapers.remotive import RemotiveScraper
|
| 765 |
scraper_map["remotive"] = ("Remotive", RemotiveScraper())
|
| 766 |
else:
|
| 767 |
_step_skip("remotive")
|
| 768 |
|
| 769 |
-
if
|
| 770 |
from src.scrapers.weworkremotely import WeWorkRemotelyScraper
|
| 771 |
scraper_map["weworkremotely"] = ("WeWorkRemotely", WeWorkRemotelyScraper())
|
| 772 |
else:
|
| 773 |
_step_skip("weworkremotely")
|
| 774 |
|
| 775 |
-
if
|
| 776 |
from src.scrapers.naukri import NaukriScraper
|
| 777 |
scraper_map["naukri"] = ("Naukri", NaukriScraper())
|
| 778 |
else:
|
| 779 |
_step_skip("naukri")
|
| 780 |
|
| 781 |
-
#
|
| 782 |
-
_ej_platforms =
|
| 783 |
if _ej_platforms:
|
| 784 |
from src.scrapers.ever_jobs import EverJobsScraper
|
| 785 |
scraper_map["ever_jobs"] = ("EverJobs", EverJobsScraper(_ej_platforms))
|
|
@@ -953,7 +938,7 @@ if start and not st.session_state.running:
|
|
| 953 |
save_run(assessed_jobs, {
|
| 954 |
"run_id": run_id,
|
| 955 |
"excel_path": excel_path,
|
| 956 |
-
"platforms":
|
| 957 |
"roles": _jscfg.get("roles", []),
|
| 958 |
})
|
| 959 |
_q_log("โ
Run saved to history")
|
|
|
|
| 489 |
|
| 490 |
st.divider()
|
| 491 |
|
| 492 |
+
# โโ Row 3: Unified platform selector โโ
|
| 493 |
st.markdown('<p class="section-label">๐ Job Platforms</p>', unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 494 |
from src.ever_jobs_bridge.platforms import PLATFORM_GROUPS, INDIA_DEFAULT_PLATFORMS, EVER_JOBS_PLATFORMS
|
| 495 |
|
| 496 |
ej_col1, ej_col2, ej_col3 = st.columns(3)
|
|
|
|
| 545 |
icon="โ ๏ธ",
|
| 546 |
)
|
| 547 |
elif use_ever_jobs:
|
| 548 |
+
st.caption(f"โ {len(ever_jobs_platforms)} platform(s) selected")
|
| 549 |
|
| 550 |
st.divider()
|
| 551 |
|
|
|
|
| 608 |
for s in PIPELINE_STEPS}
|
| 609 |
|
| 610 |
platforms_cfg = {
|
| 611 |
+
"all_platforms": ever_jobs_platforms,
|
|
|
|
|
|
|
|
|
|
| 612 |
}
|
| 613 |
job_search_cfg = {
|
| 614 |
"roles": roles, "locations": locations,
|
|
|
|
| 723 |
seen_tc: set = set()
|
| 724 |
skipped_dup: int = 0
|
| 725 |
|
| 726 |
+
_all_plats = set(_platforms.get("all_platforms", []))
|
| 727 |
+
_legacy_keys = {"linkedin", "indeed", "glassdoor", "remotive", "weworkremotely", "naukri"}
|
| 728 |
+
scraper_map = {}
|
| 729 |
+
|
| 730 |
+
if "linkedin" in _all_plats:
|
| 731 |
from src.scrapers.linkedin import LinkedInScraper
|
| 732 |
scraper_map["linkedin"] = ("LinkedIn", LinkedInScraper())
|
| 733 |
else:
|
| 734 |
_step_skip("linkedin")
|
| 735 |
|
| 736 |
+
if "indeed" in _all_plats:
|
| 737 |
from src.scrapers.indeed import IndeedScraper
|
| 738 |
scraper_map["indeed"] = ("Indeed", IndeedScraper())
|
| 739 |
else:
|
| 740 |
_step_skip("indeed")
|
| 741 |
|
| 742 |
+
if "glassdoor" in _all_plats:
|
| 743 |
from src.scrapers.glassdoor import GlassdoorScraper
|
| 744 |
scraper_map["glassdoor"] = ("Glassdoor", GlassdoorScraper())
|
| 745 |
else:
|
| 746 |
_step_skip("glassdoor")
|
| 747 |
|
| 748 |
+
if "remotive" in _all_plats:
|
| 749 |
from src.scrapers.remotive import RemotiveScraper
|
| 750 |
scraper_map["remotive"] = ("Remotive", RemotiveScraper())
|
| 751 |
else:
|
| 752 |
_step_skip("remotive")
|
| 753 |
|
| 754 |
+
if "weworkremotely" in _all_plats:
|
| 755 |
from src.scrapers.weworkremotely import WeWorkRemotelyScraper
|
| 756 |
scraper_map["weworkremotely"] = ("WeWorkRemotely", WeWorkRemotelyScraper())
|
| 757 |
else:
|
| 758 |
_step_skip("weworkremotely")
|
| 759 |
|
| 760 |
+
if "naukri" in _all_plats:
|
| 761 |
from src.scrapers.naukri import NaukriScraper
|
| 762 |
scraper_map["naukri"] = ("Naukri", NaukriScraper())
|
| 763 |
else:
|
| 764 |
_step_skip("naukri")
|
| 765 |
|
| 766 |
+
# All non-legacy platforms (150+) โ EverJobsScraper
|
| 767 |
+
_ej_platforms = [p for p in _all_plats if p not in _legacy_keys]
|
| 768 |
if _ej_platforms:
|
| 769 |
from src.scrapers.ever_jobs import EverJobsScraper
|
| 770 |
scraper_map["ever_jobs"] = ("EverJobs", EverJobsScraper(_ej_platforms))
|
|
|
|
| 938 |
save_run(assessed_jobs, {
|
| 939 |
"run_id": run_id,
|
| 940 |
"excel_path": excel_path,
|
| 941 |
+
"platforms": list(_platforms.get("all_platforms", [])),
|
| 942 |
"roles": _jscfg.get("roles", []),
|
| 943 |
})
|
| 944 |
_q_log("โ
Run saved to history")
|