diff --git a/src/ontogpt/cli.py b/src/ontogpt/cli.py index 4f38194b9..b5ca5b482 100644 --- a/src/ontogpt/cli.py +++ b/src/ontogpt/cli.py @@ -181,6 +181,12 @@ def get_model_by_name(modelname: str): default="AUTO", help="Prefix to use for auto-generated classes. Default is AUTO.", ) +show_prompt_option = click.option( + "--show-prompt/--no-show-prompt", + default=False, + show_default=True, + help="If set, show all prompts passed to model through an API. Use with verbose setting.", +) @click.group() @@ -226,6 +232,7 @@ def main(verbose: int, quiet: bool, cache_db: str, skip_annotator): @output_format_options @use_textract_options @auto_prefix_option +@show_prompt_option @click.option( "--set-slot-value", "-S", @@ -244,6 +251,7 @@ def extract( set_slot_value, use_textract, model, + show_prompt, **kwargs, ): """Extract knowledge from text guided by schema, using SPIRES engine. @@ -308,7 +316,7 @@ def extract( target_class_def = ke.schemaview.get_class(target_class) else: target_class_def = None - results = ke.extract_from_text(text, target_class_def) + results = ke.extract_from_text(text=text, cls=target_class_def, show_prompt=show_prompt) if set_slot_value: for slot_value in set_slot_value: slot, value = slot_value.split("=") @@ -324,8 +332,9 @@ def extract( @output_option_wb @output_format_options @auto_prefix_option +@show_prompt_option @click.argument("entity") -def generate_extract(model, entity, template, output, output_format, **kwargs): +def generate_extract(model, entity, template, output, output_format, show_prompt, **kwargs): """Generate text and then extract knowledge from it.""" logging.info(f"Creating for {template}") @@ -346,7 +355,7 @@ def generate_extract(model, entity, template, output, output_format, **kwargs): ke = GPT4AllEngine(template=template, model=model_name, **kwargs) logging.debug(f"Input entity: {entity}") - results = ke.generate_and_extract(entity) + results = ke.generate_and_extract(entity, show_prompt) write_extraction(results, output, output_format, ke) @@ -357,6 +366,7 @@ def generate_extract(model, entity, template, output, output_format, **kwargs): @output_option_wb @output_format_options @auto_prefix_option +@show_prompt_option @click.option("--ontology", "-r", help="Ontology to use; use oaklib selector path") @click.option("--max-iterations", "-M", default=10, type=click.INT) @click.option("--iteration-slot", "-I", multiple=True, help="Slots to iterate over") @@ -376,6 +386,7 @@ def iteratively_generate_extract( max_iterations, clear, ontology, + show_prompt, **kwargs, ): """Iterate through generate-extract.""" @@ -402,6 +413,7 @@ def iteratively_generate_extract( for results in ke.iteratively_generate_and_extract( entity, db, + show_prompt=show_prompt, iteration_slots=list(iteration_slot), max_iterations=max_iterations, adapter=adapter, @@ -416,13 +428,14 @@ def iteratively_generate_extract( @recurse_option @output_option_wb @output_format_options +@show_prompt_option @click.option( "--get-pmc/--no-get-pmc", default=False, help="Attempt to parse PubMed Central full text(s) instead of abstract(s) alone.", ) @click.argument("pmid") -def pubmed_extract(model, pmid, template, output, output_format, get_pmc, **kwargs): +def pubmed_extract(model, pmid, template, output, output_format, get_pmc, show_prompt, **kwargs): """Extract knowledge from a single PubMed ID.""" logging.info(f"Creating for {template}") @@ -450,7 +463,7 @@ def pubmed_extract(model, pmid, template, output, output_format, get_pmc, **kwar textlist = pmc.text(pmid) for text in textlist: logging.debug(f"Input text: {text}") - results = ke.extract_from_text(text) + results = ke.extract_from_text(text=text, show_prompt=show_prompt) write_extraction(results, output, output_format) @@ -460,6 +473,7 @@ def pubmed_extract(model, pmid, template, output, output_format, get_pmc, **kwar @recurse_option @output_option_wb @output_format_options +@show_prompt_option @click.option( "--limit", default=20, @@ -471,7 +485,7 @@ def pubmed_extract(model, pmid, template, output, output_format, get_pmc, **kwar help="Attempt to parse PubMed Central full text(s) instead of abstract(s) alone.", ) @click.argument("search") -def pubmed_annotate(model, search, template, output, output_format, limit, get_pmc, **kwargs): +def pubmed_annotate(model, search, template, output, output_format, limit, get_pmc, show_prompt, **kwargs): """Retrieve a collection of PubMed IDs for a search term; annotate them using a template. Example: @@ -506,7 +520,7 @@ def pubmed_annotate(model, search, template, output, output_format, limit, get_p textlist = pmc.text(pmids[: pubmed_annotate_limit + 1]) for text in textlist: logging.debug(f"Input text: {text}") - results = ke.extract_from_text(text) + results = ke.extract_from_text(text=text, show_prompt=show_prompt) write_extraction(results, output, output_format, ke) @@ -516,9 +530,10 @@ def pubmed_annotate(model, search, template, output, output_format, limit, get_p @recurse_option @output_option_wb @output_format_options +@show_prompt_option @click.option("--auto-prefix", default="AUTO", help="Prefix to use for auto-generated classes.") @click.argument("article") -def wikipedia_extract(model, article, template, output, output_format, **kwargs): +def wikipedia_extract(model, article, template, output, output_format, show_prompt, **kwargs): """Extract knowledge from a Wikipedia page.""" if not model: model = DEFAULT_MODEL @@ -541,7 +556,7 @@ def wikipedia_extract(model, article, template, output, output_format, **kwargs) text = client.text(article) logging.debug(f"Input text: {text}") - results = ke.extract_from_text(text) + results = ke.extract_from_text(text=text, show_prompt=show_prompt) write_extraction(results, output, output_format, ke) @@ -551,6 +566,7 @@ def wikipedia_extract(model, article, template, output, output_format, **kwargs) @recurse_option @output_option_wb @output_format_options +@show_prompt_option @click.option( "--keyword", "-k", @@ -558,7 +574,7 @@ def wikipedia_extract(model, article, template, output, output_format, **kwargs) help="Keyword to search for (e.g. --keyword therapy). Also obtained from schema", ) @click.argument("topic") -def wikipedia_search(model, topic, keyword, template, output, output_format, **kwargs): +def wikipedia_search(model, topic, keyword, template, output, output_format, show_prompt, **kwargs): """Extract knowledge from a Wikipedia page.""" if not model: model = DEFAULT_MODEL @@ -589,7 +605,7 @@ def wikipedia_search(model, topic, keyword, template, output, output_format, **k # TODO - expand this to fit context limits better # or add as cli option text = text[:4000] - results = ke.extract_from_text(text) + results = ke.extract_from_text(text=text, show_prompt=show_prompt) write_extraction(results, output, output_format) break @@ -600,6 +616,7 @@ def wikipedia_search(model, topic, keyword, template, output, output_format, **k @recurse_option @output_option_wb @output_format_options +@show_prompt_option @click.option( "--keyword", "-k", @@ -607,7 +624,7 @@ def wikipedia_search(model, topic, keyword, template, output, output_format, **k help="Keyword to search for (e.g. --keyword therapy). Also obtained from schema", ) @click.argument("term_tokens", nargs=-1) -def search_and_extract(model, term_tokens, keyword, template, output, output_format, **kwargs): +def search_and_extract(model, term_tokens, keyword, template, output, output_format, show_prompt, **kwargs): """Search for relevant literature and extract knowledge from it.""" if not model: model = DEFAULT_MODEL @@ -639,7 +656,7 @@ def search_and_extract(model, term_tokens, keyword, template, output, output_for logging.info(f"PMID={pmid}") text = pmc.text(pmid) logging.info(f"Input text: {text}") - results = ke.extract_from_text(text) + results = ke.extract_from_text(text=text, show_prompt=show_prompt) write_extraction(results, output, output_format) @@ -649,8 +666,9 @@ def search_and_extract(model, term_tokens, keyword, template, output, output_for @recurse_option @output_option_wb @output_format_options +@show_prompt_option @click.argument("url") -def web_extract(model, template, url, output, output_format, **kwargs): +def web_extract(model, template, url, output, output_format, show_prompt, **kwargs): """Extract knowledge from web page.""" logging.info(f"Creating for {template}") @@ -674,7 +692,7 @@ def web_extract(model, template, url, output, output_format, **kwargs): text = web_client.text(url) logging.debug(f"Input text: {text}") - results = ke.extract_from_text(text) + results = ke.extract_from_text(text=text, show_prompt=show_prompt) write_extraction(results, output, output_format) @@ -689,8 +707,9 @@ def web_extract(model, template, url, output, output_format, **kwargs): ) @click.option("--auto-prefix", default="AUTO", help="Prefix to use for auto-generated classes.") @model_option +@show_prompt_option @click.argument("url") -def recipe_extract(model, url, recipes_urls_file, dictionary, output, output_format, **kwargs): +def recipe_extract(model, url, recipes_urls_file, dictionary, output, output_format, show_prompt, **kwargs): """Extract from recipe on the web.""" try: from recipe_scrapers import scrape_me @@ -737,7 +756,7 @@ def recipe_extract(model, url, recipes_urls_file, dictionary, output, output_for Instructions:\n{instructions} """ logging.info(f"Input text: {text}") - results = ke.extract_from_text(text) + results = ke.extract_from_text(text=text, show_prompt=show_prompt) logging.debug(f"Results: {results}") results.extracted_object.url = url write_extraction(results, output, output_format, ke) @@ -839,6 +858,7 @@ def convert_geneset(input_file, output, output_format, fill, **kwargs): @output_option_txt @output_format_options @model_option +@show_prompt_option @click.option( "--resolver", "-r", help="OAK selector for the gene ID resolver. E.g. sqlite:obo:hgnc" ) @@ -853,12 +873,6 @@ def convert_geneset(input_file, output, output_format, fill, **kwargs): show_default=True, help="If set, there must be a unique mappings from labels to IDs", ) -@click.option( - "--show-prompt/--no-show-prompt", - default=True, - show_default=True, - help="If set, show prompt passed to model", -) @click.option( "--input-file", "-U", @@ -995,7 +1009,7 @@ def enrichment( @click.argument("text", nargs=-1) def embed(text, context, output, model, output_format, **kwargs): """Embed text. - + Not currently supported for open models. """ if model: @@ -1027,7 +1041,7 @@ def embed(text, context, output, model, output_format, **kwargs): @click.argument("text", nargs=-1) def text_similarity(text, context, output, model, output_format, **kwargs): """Embed text. - + Not currently supported for open models. """ if model: @@ -1067,7 +1081,7 @@ def text_similarity(text, context, output, model, output_format, **kwargs): @click.argument("text", nargs=-1) def text_distance(text, context, output, model, output_format, **kwargs): """Embed text and calculate euclidian distance between embeddings. - + Not currently supported for open models. """ if model: @@ -1440,8 +1454,9 @@ def eval(evaluator, num_tests, output, output_format, **kwargs): @recurse_option @output_option_wb @output_format_options +@show_prompt_option @click.argument("object") -def fill(model, template, object: str, examples, output, output_format, **kwargs): +def fill(model, template, object: str, examples, output, output_format, show_prompt, **kwargs): """Fill in missing values.""" logging.info(f"Creating for {template}") @@ -1463,7 +1478,7 @@ def fill(model, template, object: str, examples, output, output_format, **kwargs logging.info(f"Loading {examples}") examples = yaml.safe_load(examples) logging.debug(f"Input object: {object}") - results = ke.generalize(object, examples) + results = ke.generalize(object, examples, show_prompt) output.write(yaml.dump(results.dict())) @@ -1480,8 +1495,9 @@ def openai_models(**kwargs): @model_option @output_option_txt @output_format_options +@show_prompt_option @click.argument("input") -def complete(model, input, output, output_format, **kwargs): +def complete(model, input, output, output_format, show_prompt, **kwargs): """Prompt completion.""" if not model: model = DEFAULT_MODEL @@ -1493,7 +1509,7 @@ def complete(model, input, output, output_format, **kwargs): if model_source == "OpenAI": c = OpenAIClient(model=model_name) - results = c.complete(text) + results = c.complete(text, show_prompt) elif model_source == "GPT4All": c = set_up_gpt4all_model(modelname=model_name) @@ -1594,6 +1610,7 @@ def halo(model, input, context, terms, output, **kwargs): @model_option @output_option_wb @output_format_options +@show_prompt_option @click.option( "-d", "--description", @@ -1607,6 +1624,7 @@ def clinical_notes( sections, output, model, + show_prompt, output_format, **kwargs, ): @@ -1631,7 +1649,7 @@ def clinical_notes( if model_source == "OpenAI": c = OpenAIClient(model=model_name) - results = c.complete(prompt) + results = c.complete(prompt, show_prompt) elif model_source == "GPT4All": c = set_up_gpt4all_model(modelname=model_name) diff --git a/src/ontogpt/clients/openai_client.py b/src/ontogpt/clients/openai_client.py index 18dbf1035..2a3d18311 100644 --- a/src/ontogpt/clients/openai_client.py +++ b/src/ontogpt/clients/openai_client.py @@ -29,9 +29,11 @@ def __post_init__(self): self.api_key = get_apikey_value("openai") openai.api_key = self.api_key - def complete(self, prompt, max_tokens=3000, **kwargs) -> str: + def complete(self, prompt, show_prompt: bool = False, max_tokens=3000, **kwargs) -> str: engine = self.model logger.info(f"Complete: engine={engine}, prompt[{len(prompt)}]={prompt[0:100]}...") + if show_prompt: + logger.info(f" SENDING PROMPT:\n{prompt}") cur = self.db_connection() res = cur.execute("SELECT payload FROM cache WHERE prompt=? AND engine=?", (prompt, engine)) payload = res.fetchone() diff --git a/src/ontogpt/engines/gpt4all_engine.py b/src/ontogpt/engines/gpt4all_engine.py index 67c88970e..a09a7a941 100644 --- a/src/ontogpt/engines/gpt4all_engine.py +++ b/src/ontogpt/engines/gpt4all_engine.py @@ -62,7 +62,11 @@ def __post_init__(self): logging.info(f"Using template {self.template_class.name}") def extract_from_text( - self, text: str, cls: ClassDefinition = None, object: OBJECT = None + self, + text: str, + show_prompt: bool = False, + cls: ClassDefinition = None, + object: OBJECT = None, ) -> ExtractionResult: """ Extract annotations from the given text. @@ -78,6 +82,8 @@ def extract_from_text( for chunk in chunks: raw_text = self._raw_extract(chunk, cls, object=object) logging.info(f"RAW TEXT: {raw_text}") + if show_prompt: + logging.info(f" PROVIDED PROMPT:\n{self.last_prompt}") next_object = self.parse_completion_payload(raw_text, cls, object=object) if extracted_object is None: extracted_object = next_object @@ -93,6 +99,8 @@ def extract_from_text( else: raw_text = self._raw_extract(text, cls, object=object) logging.info(f"RAW TEXT: {raw_text}") + if show_prompt: + logging.info(f" PROVIDED PROMPT:\n{self.last_prompt}") extracted_object = self.parse_completion_payload(raw_text, cls, object=object) return ExtractionResult( input_text=text, diff --git a/src/ontogpt/engines/spires_engine.py b/src/ontogpt/engines/spires_engine.py index 257b0625c..028a263b6 100644 --- a/src/ontogpt/engines/spires_engine.py +++ b/src/ontogpt/engines/spires_engine.py @@ -57,7 +57,11 @@ class SPIRESEngine(KnowledgeEngine): The results are then merged together.""" def extract_from_text( - self, text: str, cls: ClassDefinition = None, object: OBJECT = None + self, + text: str, + show_prompt: bool = False, + cls: ClassDefinition = None, + object: OBJECT = None, ) -> ExtractionResult: """ Extract annotations from the given text. @@ -71,7 +75,7 @@ def extract_from_text( chunks = chunk_text(text, self.sentences_per_window) extracted_object = None for chunk in chunks: - raw_text = self._raw_extract(chunk, cls, object=object) + raw_text = self._raw_extract(chunk, cls, show_prompt=show_prompt, object=object) logging.info(f"RAW TEXT: {raw_text}") next_object = self.parse_completion_payload(raw_text, cls, object=object) if extracted_object is None: @@ -86,7 +90,7 @@ def extract_from_text( else: extracted_object[k] = v else: - raw_text = self._raw_extract(text, cls, object=object) + raw_text = self._raw_extract(text=text, cls=cls, show_prompt=show_prompt, object=object) logging.info(f"RAW TEXT: {raw_text}") extracted_object = self.parse_completion_payload(raw_text, cls, object=object) return ExtractionResult( @@ -98,11 +102,11 @@ def extract_from_text( ) def _extract_from_text_to_dict(self, text: str, cls: ClassDefinition = None) -> RESPONSE_DICT: - raw_text = self._raw_extract(text, cls) + raw_text = self._raw_extract(text, cls, ) return self._parse_response_to_dict(raw_text, cls) def generate_and_extract( - self, entity: str, prompt_template: str = None, **kwargs + self, entity: str, show_prompt: bool = False, prompt_template: str = None, **kwargs ) -> ExtractionResult: """ Generate a description using GPT and then extract from it using SPIRES. @@ -115,7 +119,7 @@ def generate_and_extract( prompt_template = "Generate a comprehensive description of {entity}.\n" # prompt = f"Generate a comprehensive description of {entity}.\n" prompt = prompt_template.format(entity=entity) - payload = self.client.complete(prompt) + payload = self.client.complete(prompt, show_prompt) return self.extract_from_text(payload, **kwargs) def iteratively_generate_and_extract( @@ -127,6 +131,7 @@ def iteratively_generate_and_extract( clear=False, max_iterations=10, prompt_template=None, + show_prompt: bool = False, **kwargs, ) -> Iterator[ExtractionResult]: def _remove_parenthetical_context(s: str): @@ -161,7 +166,7 @@ def _remove_parenthetical_context(s: str): else: curie = None result = self.generate_and_extract( - next_entity, prompt_template=prompt_template, **kwargs + next_entity, show_prompt=show_prompt, prompt_template=prompt_template, **kwargs ) if curie: if result.extracted_object: @@ -206,7 +211,10 @@ def _remove_parenthetical_context(s: str): f.write(dump_minimal_yaml(db)) def generalize( - self, object: Union[pydantic.v1.BaseModel, dict], examples: List[EXAMPLE] + self, + object: Union[pydantic.v1.BaseModel, dict], + examples: List[EXAMPLE], + show_prompt: bool = False, ) -> ExtractionResult: """ Generalize the given examples. @@ -228,7 +236,7 @@ def generalize( slot = sv.induced_slot(k, cls.name) prompt += f"{k}: {self._serialize_value(v, slot)}\n" logging.debug(f"PROMPT: {prompt}") - payload = self.client.complete(prompt) + payload = self.client.complete(prompt, show_prompt) prediction = self.parse_completion_payload(payload, object=object) return ExtractionResult( input_text=prompt, @@ -238,7 +246,9 @@ def generalize( named_entities=self.named_entities, ) - def map_terms(self, terms: List[str], ontology: str) -> Dict[str, List[str]]: + def map_terms( + self, terms: List[str], ontology: str, show_prompt: bool = False + ) -> Dict[str, List[str]]: """ Map the given terms to the given ontology. @@ -278,7 +288,7 @@ def map_terms(self, terms: List[str], ontology: str) -> Dict[str, List[str]]: prompt += "===\n\nTerms:" prompt += "; ".join(terms) prompt += "===\n\n" - payload = self.client.complete(prompt) + payload = self.client.complete(prompt, show_prompt) # outer parse best_results = [] for sep in ["\n", "; "]: @@ -346,7 +356,9 @@ def _serialize_value(self, val: Any, slot: SlotDefinition) -> str: return label return val - def _raw_extract(self, text, cls: ClassDefinition = None, object: OBJECT = None) -> str: + def _raw_extract( + self, text, show_prompt: bool = False, cls: ClassDefinition = None, object: OBJECT = None + ) -> str: """ Extract annotations from the given text. @@ -355,7 +367,7 @@ def _raw_extract(self, text, cls: ClassDefinition = None, object: OBJECT = None) """ prompt = self.get_completion_prompt(cls, text, object=object) self.last_prompt = prompt - payload = self.client.complete(prompt) + payload = self.client.complete(prompt, show_prompt) return payload def get_completion_prompt( diff --git a/src/ontogpt/templates/composite_disease.py b/src/ontogpt/templates/composite_disease.py new file mode 100644 index 000000000..3e7242122 --- /dev/null +++ b/src/ontogpt/templates/composite_disease.py @@ -0,0 +1,253 @@ +from __future__ import annotations +from datetime import datetime, date +from enum import Enum +from typing import List, Dict, Optional, Any, Union +from pydantic import BaseModel as BaseModel, Field +from linkml_runtime.linkml_model import Decimal +import sys +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal + + +metamodel_version = "None" +version = "None" + +class WeakRefShimBaseModel(BaseModel): + __slots__ = '__weakref__' + +class ConfiguredBaseModel(WeakRefShimBaseModel, + validate_assignment = True, + validate_all = True, + underscore_attrs_are_private = True, + extra = 'forbid', + arbitrary_types_allowed = True, + use_enum_values = True): + pass + + +class NCITDrugType(str, Enum): + + + dummy = "dummy" + + +class NCITTreatmentType(str, Enum): + + + dummy = "dummy" + + +class NCITTActivityType(str, Enum): + + + dummy = "dummy" + + +class MAXOActionType(str, Enum): + + + dummy = "dummy" + + +class MESHTherapeuticType(str, Enum): + + + dummy = "dummy" + + +class CHEBIDrugType(str, Enum): + + + dummy = "dummy" + + +class NullDataOptions(str, Enum): + + + UNSPECIFIED_METHOD_OF_ADMINISTRATION = "UNSPECIFIED_METHOD_OF_ADMINISTRATION" + + NOT_APPLICABLE = "NOT_APPLICABLE" + + NOT_MENTIONED = "NOT_MENTIONED" + + + +class CompositeDisease(ConfiguredBaseModel): + + main_disease: Optional[str] = Field(None, description="""the name of the disease that is treated.""") + drugs: Optional[List[str]] = Field(default_factory=list, description="""semicolon-separated list of named small molecule drugs""") + treatments: Optional[List[str]] = Field(default_factory=list, description="""semicolon-separated list of therapies and treatments are indicated for treating the disease.""") + contraindications: Optional[List[str]] = Field(default_factory=list, description="""semicolon-separated list of therapies and treatments that are contra-indicated for the disease, and should not be used, due to risk of adverse effects.""") + treatment_mechanisms: Optional[List[TreatmentMechanism]] = Field(default_factory=list, description="""semicolon-separated list of treatment to asterisk-separated mechanism associations""") + treatment_efficacies: Optional[List[TreatmentEfficacy]] = Field(default_factory=list, description="""semicolon-separated list of treatment to efficacy associations, e.g. Imatinib*effective""") + treatment_adverse_effects: Optional[List[TreatmentAdverseEffect]] = Field(default_factory=list, description="""semicolon-separated list of treatment to adverse effect associations, e.g. Imatinib*nausea""") + + + +class ExtractionResult(ConfiguredBaseModel): + """ + A result of extracting knowledge on text + """ + input_id: Optional[str] = Field(None) + input_title: Optional[str] = Field(None) + input_text: Optional[str] = Field(None) + raw_completion_output: Optional[str] = Field(None) + prompt: Optional[str] = Field(None) + extracted_object: Optional[Any] = Field(None, description="""The complex objects extracted from the text""") + named_entities: Optional[List[Any]] = Field(default_factory=list, description="""Named entities extracted from the text""") + + + +class NamedEntity(ConfiguredBaseModel): + + id: str = Field(..., description="""A unique identifier for the named entity""") + label: Optional[str] = Field(None, description="""The label (name) of the named thing""") + + + +class Gene(NamedEntity): + + id: str = Field(..., description="""A unique identifier for the named entity""") + label: Optional[str] = Field(None, description="""The label (name) of the named thing""") + + + +class Symptom(NamedEntity): + + id: str = Field(..., description="""A unique identifier for the named entity""") + label: Optional[str] = Field(None, description="""The label (name) of the named thing""") + + + +class Disease(NamedEntity): + + id: str = Field(..., description="""A unique identifier for the named entity""") + label: Optional[str] = Field(None, description="""The label (name) of the named thing""") + + + +class AdverseEffect(NamedEntity): + + id: str = Field(..., description="""A unique identifier for the named entity""") + label: Optional[str] = Field(None, description="""The label (name) of the named thing""") + + + +class Treatment(NamedEntity): + + id: str = Field(..., description="""A unique identifier for the named entity""") + label: Optional[str] = Field(None, description="""The label (name) of the named thing""") + + + +class Mechanism(NamedEntity): + + id: str = Field(..., description="""A unique identifier for the named entity""") + label: Optional[str] = Field(None, description="""The label (name) of the named thing""") + + + +class Drug(NamedEntity): + + id: str = Field(..., description="""A unique identifier for the named entity""") + label: Optional[str] = Field(None, description="""The label (name) of the named thing""") + + + +class CompoundExpression(ConfiguredBaseModel): + + None + + + +class TreatmentMechanism(CompoundExpression): + + treatment: Optional[str] = Field(None) + mechanism: Optional[str] = Field(None) + + + +class TreatmentAdverseEffect(CompoundExpression): + + treatment: Optional[str] = Field(None) + adverse_effects: Optional[List[str]] = Field(default_factory=list) + + + +class TreatmentEfficacy(CompoundExpression): + + treatment: Optional[str] = Field(None) + efficacy: Optional[str] = Field(None) + + + +class Triple(CompoundExpression): + """ + Abstract parent for Relation Extraction tasks + """ + subject: Optional[str] = Field(None) + predicate: Optional[str] = Field(None) + object: Optional[str] = Field(None) + qualifier: Optional[str] = Field(None, description="""A qualifier for the statements, e.g. \"NOT\" for negation""") + subject_qualifier: Optional[str] = Field(None, description="""An optional qualifier or modifier for the subject of the statement, e.g. \"high dose\" or \"intravenously administered\"""") + object_qualifier: Optional[str] = Field(None, description="""An optional qualifier or modifier for the object of the statement, e.g. \"severe\" or \"with additional complications\"""") + + + +class TextWithTriples(ConfiguredBaseModel): + + publication: Optional[Publication] = Field(None) + triples: Optional[List[Triple]] = Field(default_factory=list) + + + +class RelationshipType(NamedEntity): + + id: str = Field(..., description="""A unique identifier for the named entity""") + label: Optional[str] = Field(None, description="""The label (name) of the named thing""") + + + +class Publication(ConfiguredBaseModel): + + id: Optional[str] = Field(None, description="""The publication identifier""") + title: Optional[str] = Field(None, description="""The title of the publication""") + abstract: Optional[str] = Field(None, description="""The abstract of the publication""") + combined_text: Optional[str] = Field(None) + full_text: Optional[str] = Field(None, description="""The full text of the publication""") + + + +class AnnotatorResult(ConfiguredBaseModel): + + subject_text: Optional[str] = Field(None) + object_id: Optional[str] = Field(None) + object_text: Optional[str] = Field(None) + + + + +# Update forward refs +# see https://pydantic-docs.helpmanual.io/usage/postponed_annotations/ +CompositeDisease.update_forward_refs() +ExtractionResult.update_forward_refs() +NamedEntity.update_forward_refs() +Gene.update_forward_refs() +Symptom.update_forward_refs() +Disease.update_forward_refs() +AdverseEffect.update_forward_refs() +Treatment.update_forward_refs() +Mechanism.update_forward_refs() +Drug.update_forward_refs() +CompoundExpression.update_forward_refs() +TreatmentMechanism.update_forward_refs() +TreatmentAdverseEffect.update_forward_refs() +TreatmentEfficacy.update_forward_refs() +Triple.update_forward_refs() +TextWithTriples.update_forward_refs() +RelationshipType.update_forward_refs() +Publication.update_forward_refs() +AnnotatorResult.update_forward_refs() +