gapguide-api / apps /accounts /ner /__init__.py
arifRB's picture
Deploy GapGuide backend (Docker)
ffd36e0 verified
Raw
History Blame Contribute Delete
2.38 kB
"""NER layer package for Module 8 resume parsing.
Layers (merge-all semantics β€” see research/06-dataset-sourcing.md Β§5 and
the plan at ~/.claude/plans/okay-plan-for-7a-fluffy-marshmallow.md):
1. nucha β€” Nucha/Nucha_ITSkillNER_BERT (MIT, F1 0.90)
2. jobbert β€” jjzha/jobbert_skill_extraction (license unspecified, FYP-OK)
3. skillner β€” rule-based, EMSI taxonomy (Nov 2021 release, still works)
4. sbert β€” SentenceTransformer('all-MiniLM-L6-v2') + pgvector cosine
Each concrete layer implements ``NerLayer`` and exposes a module-level
lazy singleton so the HF models only load on first call. The dispatcher in
``resume_parser._predict_skills_from_text`` invokes the layers in order,
catches any import / timeout / model-download error per layer, and unions
the results into one {alias: max_confidence} dict.
The lexical floor (``ner.lexical``) is always run last even if the higher
layers succeed β€” it guarantees the endpoint returns at least the catalog
matches regardless of ML-layer availability.
"""
from __future__ import annotations
from abc import ABC, abstractmethod
class NerLayer(ABC):
"""Contract every NER layer must satisfy.
Implementations should:
* Keep the model as a module-level singleton, loaded on first call.
* Catch *internal* model errors and return an empty dict rather than
raising β€” the dispatcher already wraps calls in try/except, but
returning {} for recoverable failures keeps the log quieter.
* Never raise for an empty or non-English input β€” just return {}.
"""
#: Short stable identifier used in the response's ``parser_version`` list.
#: Keep lowercase, no spaces.
name: str = "abstract"
@abstractmethod
def predict(self, text: str) -> dict[str, float]:
"""Return {skill_or_alias_name: confidence_0_to_1}.
Keys are free-text β€” the dispatcher runs alias resolution against the
Skill catalog before they reach the user. Values are [0, 1] floats.
"""
raise NotImplementedError
def available(self) -> bool:
"""Cheap check the dispatcher calls before invoking predict().
Default: attempt a lazy-import of the layer's heavy deps. Override
for layers whose availability depends on external state (e.g. a
model being cached locally).
"""
return True