- New Step 04.5 bm25_prefilter: cheap lexical BM25 pre-cut right after
hard_filter, before potion_broad's expensive embedding pass. Shrinks
potion's input from ~74K to 10K rows using JD-keyword overlap alone.
composite_narrow still runs its full potion+soft+bm25 blend later, once
those signals exist, so ranking quality is unchanged. Falls back to a
full passthrough on an empty/failed JD spec rather than an arbitrary cut.
- broad_retrieval/composite_narrow/precision all use fixed top_n counts
now (500/200/125) instead of a mix of top_pct and top_n.
- Moved the candidates Parquet cache down into load_candidates() itself
(was one layer up in run_preprocess, which Streamlit's per-phase
explorer bypasses). Now both the CLI and Streamlit share one cache —
verified Streamlit's eager warm-up dropped from 14.6s to 0.27s.
- Streamlit's _load_phase_input switched to st.cache_resource (avoids
copying the 100K-row frame on every cache hit; safe since every
downstream Polars st…
Add timing and error logging throughout
Hemprasad Badgujar
f1347ae
Instrument critical paths with performance metrics and error tracking. Add time.perf_counter() timing to model loading (_load_llama, _load_potion, load_onnx_session) and LLM generation. Wrap key operations in try-except blocks to log failures with context. Track progress of explanation polish with per-row and per-batch timing. Improves observability for debugging performance issues and troubleshooting failures in production.
Cache-first model loading for zero-network ranking
Hemprasad Badgujar
d68637e
Plain hf_hub_download fires a live network call on every load (even for fully-cached files) to validate etags, breaking the 'no network during ranking' contract. Add cached_hf_download() that checks local cache first via try_to_load_from_cache() and only calls the Hub on genuine cache-miss. Update all loaders (llm.py, onnx.py, potion.py) and prefetch to use this strategy. Also fix prefetch to pass cpu_threads to ONNX loaders so @lru_cache keys match the actual runtime. Update README and Dockerfile to clarify cache-first behavior replaces 'auto-download fallback' framing. Tests: 93→101.
Enhance JD extraction (Qwen3.5-2B + richer prompt) and Step-11 reasoning
Hemprasad Badgujar
eb18ae9
JD extraction:
- Switch JD parse to Qwen3.5-2B (standard-instruct GGUF); reasoning stays Qwen3-1.7B (separate handle)
- Gate Qwen's /no_think soft switch to Qwen models only (LlmClient._soft_no_think)
- Enrich the OBJECTIVE prompt with related skills (nice_to_have), target_industries,
exclude_companies, and all welcomed locations; guard out JD-rejected domains
- best-of-N now targets must_have recall only; _as_str_list dedups keywords case-insensitively
- City->country gazetteer fallback for acceptable_countries
Step-11 reasoning:
- Enrich grounded facts: industry / education / recency / title-fit + dominant-signal tail
- Revive the recent_days knob; LLM polish on Qwen3-1.7B
Config/cleanup: hard-filter graded checks off at funnel entry; doc fixes; remove stray files.
Tests: +dedup / related-field / explain coverage (93 pass, ruff + mypy clean).
Add retrieval & soft/composite ranking stages
Hemprasad Badgujar
08c3203
Introduce broad retrieval (potion Model2Vec) + soft_filter scoring + composite_narrow (BM25 + z-blend) pipeline steps. Adds retrieval implementations (potion static embedder, BM25 tokenizer/scorer), ranking modules (soft_filter, composite_narrow), and tests for bm25, potion, composite, soft_filter and hard_filter behavior. Update config/settings to expose new tuning blocks (broad_retrieval, soft_filter, composite_narrow) and default embedder, refine hard_filter inactive logic and integrity toggles, and export new rank/retrieve APIs. Streamlit explorer updated to include rank stages and show JD spec; pyproject dependencies added model2vec and numpy. These changes narrow the candidate pool deterministically before expensive embedding and blend semantic + lexical + quality signals for the top-N cut.