"""Deterministic study, evidence-domain and population-level classification.""" from __future__ import annotations import re _PUBLICATION_TYPE_RULES: list[tuple[str, tuple[str, ...]]] = [ ("meta_analysis", ("meta-analysis", "meta analysis")), ("systematic_review", ("systematic review",)), ("randomized_controlled_trial", ("randomized controlled trial", "randomised controlled trial")), ("controlled_clinical_trial", ("controlled clinical trial", "clinical trial")), ("cohort", ("cohort studies", "cohort study")), ("case_control", ("case-control studies", "case control study")), ("cross_sectional", ("cross-sectional studies", "cross sectional study")), ("case_report", ("case reports", "case report")), ("narrative_review", ("review",)), ] _TEXT_RULES: list[tuple[str, re.Pattern[str]]] = [ ("meta_analysis", re.compile(r"\bmeta-analysis\b", re.I)), ("systematic_review", re.compile(r"\bsystematic review\b", re.I)), ("randomized_controlled_trial", re.compile(r"\brandomi[sz]ed\b.*\b(?:placebo|controlled|trial)\b|\bdouble-blind\b", re.I)), ("controlled_clinical_trial", re.compile(r"\bclinical trial\b|\bcontrolled trial\b", re.I)), ("cohort", re.compile(r"\bprospective cohort\b|\bretrospective cohort\b", re.I)), ("case_control", re.compile(r"\bcase-control\b", re.I)), ("cross_sectional", re.compile(r"\bcross-sectional\b", re.I)), ("case_report", re.compile(r"\bcase report\b", re.I)), ("pharmacokinetic_study", re.compile(r"\bpharmacokinetic\b|\bAUC\b|\bCmax\b|\bclearance\b", re.I)), ("animal_experiment", re.compile(r"\b(?:mice|mouse|rats?|murine|rodents?|rabbits?|dogs?|swine)\b", re.I)), ("in_vitro", re.compile(r"\bin vitro\b|\bcell lines?\b|\bcultured cells?\b", re.I)), ] def classify_study_type(publication_types: list[str], title: str, abstract: str) -> str: normalized = [value.casefold() for value in publication_types] for study_type, labels in _PUBLICATION_TYPE_RULES: if any(any(label in value for label in labels) for value in normalized): return study_type text = f"{title}\n{abstract}" for study_type, pattern in _TEXT_RULES: if pattern.search(text): return study_type return "unknown" def is_secondary_research(study_type: str) -> bool: return study_type in {"meta_analysis", "systematic_review", "narrative_review"} def classify_population_level(title: str, abstract: str, study_type: str) -> str: text = f"{title}\n{abstract}" animal = bool( re.search( r"\b(?:mice|mouse|rats?|murine|rodents?|" r"rabbits?|dogs?|swine|animals?|" r"animal models?|lab animal studies?|" r"laboratory animal studies?|" r"laboratory animals?)\b", text, re.I, ) ) invitro = bool(re.search(r"\bin vitro\b|\bcell lines?\b|\bcultured cells?\b", text, re.I)) human = bool(re.search(r"\b(?:participants?|patients?|subjects?|volunteers?|adults?|children|students?|women|men|elderly|humans?)\b", text, re.I)) levels = [name for name, present in (("human", human), ("animal", animal), ("in_vitro", invitro)) if present] if len(levels) > 1: return "mixed" if levels: return levels[0] if study_type in {"randomized_controlled_trial", "controlled_clinical_trial", "nonrandomized_intervention", "cohort", "case_control", "cross_sectional", "case_report", "pharmacokinetic_study"}: return "human" if study_type == "animal_experiment": return "animal" if study_type == "in_vitro": return "in_vitro" return "not_applicable" if is_secondary_research(study_type) else "mixed" def classify_evidence_domain(question: str | None, title: str, abstract: str) -> str: text = " ".join(filter(None, [question, title, abstract])) interaction = bool(re.search(r"\binteraction|herb[- ]drug|CYP\d|cytochrome|warfarin|pharmacokinetic\b", text, re.I)) safety = bool(re.search(r"\bsafety|adverse|toxicity|tolerability|harm|hepatotox|nephrotox\b", text, re.I)) mechanism = bool(re.search(r"\bmechanism|pathway|inhibit(?:s|ed|ion)?|activate(?:s|d|ion)?|enzyme|receptor\b", text, re.I)) efficacy = bool(re.search(r"\befficacy|effectiveness|improv|reduc|increase|decrease|benefit|outcome\b", text, re.I)) active = [name for name, present in (("interaction", interaction), ("safety", safety), ("mechanism", mechanism), ("efficacy", efficacy)) if present] if len(active) > 1: return "mixed" return active[0] if active else "mixed"