Source code for medkit.text.spacy.doc_pipeline

__all__ = ["SpacyDocPipeline"]

from typing import Callable, Dict, List, Optional

from spacy import Language
from spacy.tokens import Span as SpacySpan

from medkit.core import DocOperation, Attribute
from medkit.core.text import TextDocument
from medkit.text.spacy import spacy_utils


[docs]class SpacyDocPipeline(DocOperation): """DocPipeline to obtain annotations created using spacy""" def __init__( self, nlp: Language, medkit_labels_anns: Optional[List[str]] = None, medkit_attrs: Optional[List[str]] = None, spacy_entities: Optional[List[str]] = None, spacy_span_groups: Optional[List[str]] = None, spacy_attrs: Optional[List[str]] = None, medkit_attribute_factories: Optional[ Dict[str, Callable[[SpacySpan, str], Attribute]] ] = None, name: Optional[str] = None, uid: Optional[str] = None, ): """Initialize the pipeline Parameters ---------- nlp: Language object with the loaded pipeline from Spacy medkit_labels_anns: Labels of medkit annotations to include in the spacy document. If `None` (default) all the annotations will be included. medkit_attrs: Labels of medkit attributes to add in the annotations that will be included. If `None` (default) all the attributes will be added as `custom attributes` in each annotation included. spacy_entities: Labels of new spacy entities (`doc.ents`) to convert into medkit entities. If `None` (default) all the new spacy entities will be converted and added into its origin medkit document. spacy_span_groups: Name of new spacy span groups (`doc.spans`) to convert into medkit segments. If `None` (default) new spacy span groups will be converted and added into its origin medkit document. spacy_attrs: Name of span extensions to convert into medkit attributes. If `None` (default) all non-None extensions will be added for each annotation with a medkit ID. medkit_attribute_factories: Mapping of factories in charge of converting spacy attributes to medkit attributes. Factories will receive a spacy span and an an attribute label when called. The key in the mapping is the attribute label. name: Name describing the pipeline (defaults to the class name). uid: Identifier of the pipeline """ # Pass all arguments to super (remove self) init_args = locals() init_args.pop("self") super().__init__(**init_args) self.nlp = nlp self.medkit_labels_anns = medkit_labels_anns self.medkit_attrs = medkit_attrs self.spacy_entities = spacy_entities self.spacy_span_groups = spacy_span_groups self.spacy_attrs = spacy_attrs self.medkit_attribute_factories = medkit_attribute_factories
[docs] def run(self, medkit_docs: List[TextDocument]) -> None: """Run a spacy pipeline on a list of medkit documents. Each medkit document is converted to spacy document (Doc object), with the selected annotations and attributes. Then, the spacy pipeline is executed and finally, the new annotations and attributes are converted into medkit annotations. Parameters ---------- medkit_docs: List of TextDocuments on which to run the pipeline """ for medkit_doc in medkit_docs: # build spacy doc spacy_doc = spacy_utils.build_spacy_doc_from_medkit_doc( nlp=self.nlp, medkit_doc=medkit_doc, labels_anns=self.medkit_labels_anns, attrs=self.medkit_attrs, include_medkit_info=True, ) # apply nlp spacy spacy_doc = self.nlp(spacy_doc) # get new annotations and attributes raw_segment = medkit_doc.raw_segment anns, attrs_by_ann_id = spacy_utils.extract_anns_and_attrs_from_spacy_doc( spacy_doc=spacy_doc, medkit_source_ann=raw_segment, entities=self.spacy_entities, span_groups=self.spacy_span_groups, attrs=self.spacy_attrs, attribute_factories=self.medkit_attribute_factories, rebuild_medkit_anns_and_attrs=False, ) # annotate # add new annotations for ann in anns: medkit_doc.anns.add(ann) if self._prov_tracer is not None: self._prov_tracer.add_prov( ann, self.description, source_data_items=[raw_segment], ) # add new attributes in each annotation for ann_id, attrs in attrs_by_ann_id.items(): ann = medkit_doc.anns.get_by_id(ann_id) for attr in attrs: ann.attrs.add(attr) if self._prov_tracer is not None: # if ann is an existing annotation, in terms # of provenance, the annotation was used to # generate the attribute, else, it was regenerate using # raw_text_segment source_data_item = raw_segment if ann in anns else ann self._prov_tracer.add_prov( attr, self.description, source_data_items=[source_data_item] )