biomedical-knowledge-lookup 2.2.0__tar.gz → 2.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/PKG-INFO +1 -1
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/pyproject.toml +1 -1
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/__init__.py +1 -1
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/__main__.py +51 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/ols_adapter.py +76 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/nodes/expand.py +12 -1
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/runners.py +6 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/state.py +3 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/core/term_expansion.py +384 -31
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/LICENSE +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/README.md +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/__init__.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/biolinker_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/bioontology_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/bioportal_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/chembl_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/clinvar_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/cosmic_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/dbpedia_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/disgenet_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/drugbank_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/ebiols_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/ensembl_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/europepmc_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/eutils_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/geneontology_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/hgnc_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/hpo_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/interpro_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/kegg_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/mondo_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/obofoundry_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/omim_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/opentargets_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/oxo_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/pdb_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/pfam_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/pubchem_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/quickgo_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/reactome_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/string_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/tyto_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/umls_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/unichem_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/uniprot_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/wikidata_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/adapters/zooma_adapter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/__init__.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/config.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/graph.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/nodes/__init__.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/nodes/_limits.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/nodes/aggregate.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/nodes/approval.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/nodes/detail_gather.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/nodes/enrichment.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/nodes/export.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/nodes/filter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/nodes/lookup.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/nodes/preprocess.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/nodes/prune.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/nodes/quality_gate.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/nodes/refine.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/nodes/review.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/agents/routing.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/base.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/benchmarking/__init__.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/benchmarking/benchmarking.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/benchmarks/__init__.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/benchmarks/run_benchmark.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/cache/__init__.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/cache/cache.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/core/__init__.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/core/central_lookup.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/core/expansion_store.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/core/factory.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/core/multi_source_annotator.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/core/source_routing.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/curie_utils/__init__.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/curie_utils/normalization.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/curie_utils/reference.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/curie_utils/validation.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/export/__init__.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/export/exports.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/helpers/__init__.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/helpers/helpers.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/mcp_server/__init__.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/mcp_server/__main__.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/mcp_server/isolation.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/mcp_server/schemas.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/mcp_server/server.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/mcp_server/sources.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/models/__init__.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/models/biomedical_knowledge_models.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/models/extensions.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/models/models.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/models/validation_models.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/py.typed +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/services/__init__.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/services/ontology_concept_loader.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/services/rdf_converter.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/umls/__init__.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/umls/batch.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/umls/cache.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/umls/embeddings.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/umls/llm.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/umls/rdf.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/utils/redaction.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/utils/retry_utils.py +0 -0
- {biomedical_knowledge_lookup-2.2.0 → biomedical_knowledge_lookup-2.3.0}/src/knowledge_lookup/utils/timing_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: biomedical-knowledge-lookup
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Unified biological concept lookup across 36 biomedical knowledge sources including BioPortal, OLS, UMLS, ChEMBL, DisGeNET, and more
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -16,7 +16,7 @@ urls = { Documentation = "https://jonasheinickeBio.github.io/biomedical-knowledg
|
|
|
16
16
|
# Optional feature groups. The core install pulls none of these; each dependency
|
|
17
17
|
# guards its own import so `import knowledge_lookup` works without them and the
|
|
18
18
|
# matching adapter/feature is simply disabled when absent.
|
|
19
|
-
version = "2.
|
|
19
|
+
version = "2.3.0"
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
[project.optional-dependencies]
|
|
@@ -114,7 +114,7 @@ __all__ = [
|
|
|
114
114
|
# poetry-dynamic-versioning rewrites the next line with the real version at build time
|
|
115
115
|
# ([tool.poetry-dynamic-versioning.substitution] in pyproject.toml). Keep it the only line
|
|
116
116
|
# that starts with `__version__ = "`, or the substitution would hit more than one line.
|
|
117
|
-
__version__ = "2.
|
|
117
|
+
__version__ = "2.3.0"
|
|
118
118
|
__author__ = "AID-PAIS Knowledge Graph Team"
|
|
119
119
|
__description__ = "Unified biological concept lookup across multiple knowledge sources"
|
|
120
120
|
|
|
@@ -72,6 +72,26 @@ def search(
|
|
|
72
72
|
partial: bool = typer.Option(
|
|
73
73
|
False, "--partial", "-p", help="Enable partial/fuzzy matching (UMLS adapter)"
|
|
74
74
|
),
|
|
75
|
+
expand: bool = typer.Option(
|
|
76
|
+
False,
|
|
77
|
+
"--expand",
|
|
78
|
+
"-e",
|
|
79
|
+
help="Iteratively expand the query with synonyms/long-forms discovered from results "
|
|
80
|
+
"and search each new term (uses search_concepts_expanded)",
|
|
81
|
+
),
|
|
82
|
+
relationships: bool = typer.Option(
|
|
83
|
+
False,
|
|
84
|
+
"--relationships",
|
|
85
|
+
help="With --expand, also traverse relationship edges (STRING interactions, KEGG "
|
|
86
|
+
"pathways, DisGeNET/Open Targets associations) and search their named targets "
|
|
87
|
+
"(implies --expand)",
|
|
88
|
+
),
|
|
89
|
+
expand_hierarchy: bool = typer.Option(
|
|
90
|
+
False,
|
|
91
|
+
"--expand-hierarchy",
|
|
92
|
+
help="With --expand, traverse only taxonomic class<->member edges (OLS narrower/"
|
|
93
|
+
"broader, UMLS parent/child) so a class term surfaces its members (implies --expand)",
|
|
94
|
+
),
|
|
75
95
|
):
|
|
76
96
|
"""
|
|
77
97
|
Search for biological concepts across knowledge sources.
|
|
@@ -119,6 +139,31 @@ def search(
|
|
|
119
139
|
result = LookupResult(query=query)
|
|
120
140
|
result.add_concepts(umls_concepts, KnowledgeSource.UMLS)
|
|
121
141
|
return result
|
|
142
|
+
if expand or relationships or expand_hierarchy:
|
|
143
|
+
if expand_hierarchy:
|
|
144
|
+
from knowledge_lookup.core.term_expansion import (
|
|
145
|
+
hierarchy_relationship_sources,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
return await lkp.search_concepts_expanded(
|
|
149
|
+
query=query,
|
|
150
|
+
sources=source_enums,
|
|
151
|
+
max_results=limit,
|
|
152
|
+
relationships=True,
|
|
153
|
+
relationship_sources=hierarchy_relationship_sources(lkp),
|
|
154
|
+
)
|
|
155
|
+
if relationships:
|
|
156
|
+
return await lkp.search_concepts_expanded(
|
|
157
|
+
query=query,
|
|
158
|
+
sources=source_enums,
|
|
159
|
+
max_results=limit,
|
|
160
|
+
relationships=True,
|
|
161
|
+
)
|
|
162
|
+
return await lkp.search_concepts_expanded(
|
|
163
|
+
query=query,
|
|
164
|
+
sources=source_enums,
|
|
165
|
+
max_results=limit,
|
|
166
|
+
)
|
|
122
167
|
return await lkp.search_concepts(
|
|
123
168
|
query=query,
|
|
124
169
|
sources=source_enums,
|
|
@@ -249,6 +294,11 @@ def workflow(
|
|
|
249
294
|
concept_types: list[str] | None = typer.Option(
|
|
250
295
|
None, "--type", "-t", help="Filter by concept types"
|
|
251
296
|
),
|
|
297
|
+
relationships: bool = typer.Option(
|
|
298
|
+
False,
|
|
299
|
+
"--relationships",
|
|
300
|
+
help="Expand the search with relationship edges (interactions, pathways, class members)",
|
|
301
|
+
),
|
|
252
302
|
):
|
|
253
303
|
"""
|
|
254
304
|
Run the intelligent agent workflow with review and approval.
|
|
@@ -284,6 +334,7 @@ def workflow(
|
|
|
284
334
|
export_path=export_path,
|
|
285
335
|
max_iterations=max_iterations,
|
|
286
336
|
auto_approve_threshold=auto_approve,
|
|
337
|
+
include_relationships=relationships,
|
|
287
338
|
)
|
|
288
339
|
|
|
289
340
|
result = asyncio.run(_run())
|
|
@@ -65,6 +65,26 @@ class OLSAdapter(KnowledgeSourceAdapter):
|
|
|
65
65
|
# Get the first match
|
|
66
66
|
term_data = data["_embedded"]["terms"][0]
|
|
67
67
|
concept = self._convert_ols_concept_to_unified(term_data)
|
|
68
|
+
if concept is not None:
|
|
69
|
+
links = term_data.get("_links", {}) or {}
|
|
70
|
+
child_labels = [
|
|
71
|
+
label
|
|
72
|
+
for _iri, label in await self._fetch_linked_terms(
|
|
73
|
+
(links.get("children") or {}).get("href")
|
|
74
|
+
)
|
|
75
|
+
if label
|
|
76
|
+
]
|
|
77
|
+
parent_labels = [
|
|
78
|
+
label
|
|
79
|
+
for _iri, label in await self._fetch_linked_terms(
|
|
80
|
+
(links.get("parents") or {}).get("href")
|
|
81
|
+
)
|
|
82
|
+
if label
|
|
83
|
+
]
|
|
84
|
+
if child_labels:
|
|
85
|
+
concept.children = child_labels
|
|
86
|
+
if parent_labels:
|
|
87
|
+
concept.parents = parent_labels
|
|
68
88
|
return concept
|
|
69
89
|
|
|
70
90
|
return None
|
|
@@ -73,6 +93,62 @@ class OLSAdapter(KnowledgeSourceAdapter):
|
|
|
73
93
|
logger.error(f"Failed to get OLS concept details for '{concept_id}': {e}")
|
|
74
94
|
return None
|
|
75
95
|
|
|
96
|
+
async def _fetch_linked_terms(
|
|
97
|
+
self, href: str | None, limit: int = 20
|
|
98
|
+
) -> list[tuple[str, str]]:
|
|
99
|
+
"""Follow an OLS ``_links`` hierarchy href (children/parents/...) and
|
|
100
|
+
return ``(iri, label)`` pairs. Any failure degrades to ``[]``."""
|
|
101
|
+
if not href:
|
|
102
|
+
return []
|
|
103
|
+
try:
|
|
104
|
+
base = href.split("?", 1)[0]
|
|
105
|
+
data = await self._make_request(base, {"size": max(1, min(limit, 200)), "page": 0})
|
|
106
|
+
except Exception as e:
|
|
107
|
+
logger.debug(f"OLS linked-terms request failed for {href}: {e}")
|
|
108
|
+
return []
|
|
109
|
+
terms = (data.get("_embedded") or {}).get("terms") or []
|
|
110
|
+
return [(t.get("iri", ""), t.get("label", "")) for t in terms if t.get("iri")]
|
|
111
|
+
|
|
112
|
+
async def get_relationships(self, concept_id: str, limit: int = 10) -> list[dict[str, Any]]:
|
|
113
|
+
"""Return direct hierarchy neighbours of an OLS term as relationship
|
|
114
|
+
edges.
|
|
115
|
+
|
|
116
|
+
Resolves the term's ``_links.children``/``_links.parents`` (the API
|
|
117
|
+
supplies ready-to-follow hrefs, so no endpoint guessing) and returns
|
|
118
|
+
them in the adapter relationship shape. Narrower terms become
|
|
119
|
+
``has_narrower`` (a class->member edge for class terms), broader terms
|
|
120
|
+
``has_broader``. Non-IRI ids and any failure return ``[]``.
|
|
121
|
+
"""
|
|
122
|
+
if not concept_id or "http" not in concept_id:
|
|
123
|
+
return []
|
|
124
|
+
try:
|
|
125
|
+
data = await self._make_request(f"{self.base_url}/terms", {"iri": concept_id})
|
|
126
|
+
terms = (data.get("_embedded") or {}).get("terms") or []
|
|
127
|
+
if not terms:
|
|
128
|
+
return []
|
|
129
|
+
links = terms[0].get("_links", {}) or {}
|
|
130
|
+
except Exception as e:
|
|
131
|
+
logger.error(f"OLS get_relationships failed for '{concept_id}': {e}")
|
|
132
|
+
return []
|
|
133
|
+
|
|
134
|
+
rels: list[dict[str, Any]] = []
|
|
135
|
+
for key, label in (("children", "has_narrower"), ("parents", "has_broader")):
|
|
136
|
+
href = (links.get(key) or {}).get("href")
|
|
137
|
+
for iri, name in await self._fetch_linked_terms(href, limit=limit):
|
|
138
|
+
if not name:
|
|
139
|
+
continue
|
|
140
|
+
rels.append(
|
|
141
|
+
{
|
|
142
|
+
"relation_label": label,
|
|
143
|
+
"related_id": iri,
|
|
144
|
+
"related_name": name,
|
|
145
|
+
"source": "OLS",
|
|
146
|
+
}
|
|
147
|
+
)
|
|
148
|
+
if len(rels) >= limit:
|
|
149
|
+
return rels
|
|
150
|
+
return rels
|
|
151
|
+
|
|
76
152
|
def _convert_ols_result_to_concept(self, result: dict[str, Any]) -> UnifiedConcept | None:
|
|
77
153
|
"""Convert OLS search result to unified concept."""
|
|
78
154
|
try:
|
|
@@ -34,7 +34,11 @@ from __future__ import annotations
|
|
|
34
34
|
import asyncio
|
|
35
35
|
|
|
36
36
|
from ...core.central_lookup import CentralKnowledgeLookup
|
|
37
|
-
from ...core.term_expansion import
|
|
37
|
+
from ...core.term_expansion import (
|
|
38
|
+
AbbreviationSource,
|
|
39
|
+
default_relationship_sources,
|
|
40
|
+
expand_and_search,
|
|
41
|
+
)
|
|
38
42
|
from ...models import KnowledgeSource, LookupConfig
|
|
39
43
|
from ..state import LookupWorkflowState, make_step
|
|
40
44
|
from . import _limits
|
|
@@ -66,6 +70,12 @@ async def expand_node(state: LookupWorkflowState) -> dict:
|
|
|
66
70
|
None if source_filter is None or KnowledgeSource.UMLS in source_filter else []
|
|
67
71
|
)
|
|
68
72
|
lookup = CentralKnowledgeLookup(config=config, auto_initialize=True)
|
|
73
|
+
# Relationship-edge expansion (interactions, pathways, associations, class
|
|
74
|
+
# members) is opt-in via the workflow state; off by default so the bounded
|
|
75
|
+
# quality pass stays cheap unless a caller asks for a relationship network.
|
|
76
|
+
relationship_sources = (
|
|
77
|
+
default_relationship_sources(lookup) if state.get("include_relationships") else None
|
|
78
|
+
)
|
|
69
79
|
try:
|
|
70
80
|
_, trace = await asyncio.wait_for(
|
|
71
81
|
expand_and_search(
|
|
@@ -75,6 +85,7 @@ async def expand_node(state: LookupWorkflowState) -> dict:
|
|
|
75
85
|
max_rounds=_MAX_ROUNDS,
|
|
76
86
|
max_terms_per_round=_MAX_TERMS_PER_ROUND,
|
|
77
87
|
abbreviation_sources=abbreviation_sources,
|
|
88
|
+
relationship_sources=relationship_sources,
|
|
78
89
|
),
|
|
79
90
|
timeout=_limits.EXPAND_TIMEOUT,
|
|
80
91
|
)
|
|
@@ -41,6 +41,7 @@ def _initial_state(
|
|
|
41
41
|
export_path: str | None,
|
|
42
42
|
max_iterations: int,
|
|
43
43
|
auto_approve_threshold: float,
|
|
44
|
+
include_relationships: bool = False,
|
|
44
45
|
) -> LookupWorkflowState:
|
|
45
46
|
return {
|
|
46
47
|
"query": query,
|
|
@@ -68,6 +69,7 @@ def _initial_state(
|
|
|
68
69
|
"normalized_query": "",
|
|
69
70
|
"original_query": query,
|
|
70
71
|
"expanded_search_terms": [],
|
|
72
|
+
"include_relationships": include_relationships,
|
|
71
73
|
"is_german": False,
|
|
72
74
|
"quality_score": None,
|
|
73
75
|
"quality_details": None,
|
|
@@ -125,6 +127,7 @@ async def run_workflow(
|
|
|
125
127
|
export_path: str | None = None,
|
|
126
128
|
max_iterations: int = 3,
|
|
127
129
|
auto_approve_threshold: float = 0.8,
|
|
130
|
+
include_relationships: bool = False,
|
|
128
131
|
checkpointer: BaseCheckpointSaver | None = None,
|
|
129
132
|
) -> dict:
|
|
130
133
|
"""Run the full lookup-review-approval-export workflow.
|
|
@@ -138,6 +141,8 @@ async def run_workflow(
|
|
|
138
141
|
export_path: Directory for export files.
|
|
139
142
|
max_iterations: Maximum lookup passes (initial search + refinements).
|
|
140
143
|
auto_approve_threshold: Score above which auto-approval triggers.
|
|
144
|
+
include_relationships: Enable relationship-edge expansion (interactions,
|
|
145
|
+
pathways, class members) during the search step.
|
|
141
146
|
checkpointer: Checkpointer holding paused runs. Defaults to a
|
|
142
147
|
process-wide in-memory saver; pass the same one to
|
|
143
148
|
:func:`resume_workflow`.
|
|
@@ -162,6 +167,7 @@ async def run_workflow(
|
|
|
162
167
|
export_path=export_path,
|
|
163
168
|
max_iterations=max_iterations,
|
|
164
169
|
auto_approve_threshold=auto_approve_threshold,
|
|
170
|
+
include_relationships=include_relationships,
|
|
165
171
|
)
|
|
166
172
|
|
|
167
173
|
# Run the graph to completion (or interrupt)
|
|
@@ -44,6 +44,9 @@ class LookupWorkflowState(TypedDict):
|
|
|
44
44
|
normalized_query: str # Cleaned/normalized version of the query
|
|
45
45
|
original_query: str # Original query as provided
|
|
46
46
|
expanded_search_terms: list[str] # Flat list of ALL search variants (searched in parallel)
|
|
47
|
+
include_relationships: (
|
|
48
|
+
bool # Opt-in relationship-edge expansion (interactions, pathways, class members)
|
|
49
|
+
)
|
|
47
50
|
is_german: bool # Whether the query appears to be German
|
|
48
51
|
quality_score: float | None # Quality gate score (0-1)
|
|
49
52
|
quality_details: dict | None # Quality breakdown
|