mgbam commited on
Commit
3333933
·
verified ·
1 Parent(s): f65e3d6

Update mcp/hpo.py

Browse files
Files changed (1) hide show
  1. mcp/hpo.py +59 -11
mcp/hpo.py CHANGED
@@ -1,16 +1,64 @@
1
- # mcp/hpo.py
2
- """
3
- Human Phenotype Ontology quick lookup.
 
 
 
 
 
 
 
 
4
  """
 
5
 
6
- import httpx
7
- from typing import Dict
 
8
 
9
- BASE = "https://hpo.jax.org/api/hpo/term/"
 
 
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  async def get_hpo(term_id: str) -> Dict:
12
- """Fetch HPO term details by ID (e.g., HP:0001250)."""
13
- async with httpx.AsyncClient(timeout=15) as client:
14
- r = await client.get(BASE + term_id)
15
- r.raise_for_status()
16
- return r.json()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """MedGenesis – Human Phenotype Ontology (HPO) async helper.
3
+
4
+ Adds reliability & caching over the minimal original version.
5
+
6
+ Capabilities
7
+ ~~~~~~~~~~~~
8
+ * `get_hpo(term_id)` – fetch full term JSON (`HP:XXXXXXX`), cached 24 h.
9
+ * `search_hpo(term)` – simple keyword search, returns top hit (id + name).
10
+
11
+ API docs: https://hpo.jax.org/api
12
  """
13
+ from __future__ import annotations
14
 
15
+ import httpx, asyncio
16
+ from functools import lru_cache
17
+ from typing import Dict, Optional, List
18
 
19
+ _BASE = "https://hpo.jax.org/api/hpo"
20
+ _TIMEOUT = 15
21
+ _HEADERS = {"User-Agent": "MedGenesis/1.0 (https://huggingface.co/spaces)"}
22
 
23
+ # ---------------------------------------------------------------------
24
+ # Internal helper with retry
25
+ # ---------------------------------------------------------------------
26
+ async def _get(url: str, *, retries: int = 3) -> Dict:
27
+ delay = 2
28
+ last: Optional[httpx.Response] = None
29
+ for _ in range(retries):
30
+ async with httpx.AsyncClient(timeout=_TIMEOUT, headers=_HEADERS) as cli:
31
+ last = await cli.get(url)
32
+ if last.status_code == 200:
33
+ return last.json()
34
+ await asyncio.sleep(delay)
35
+ delay *= 2
36
+ last.raise_for_status() # type: ignore
37
+
38
+ # ---------------------------------------------------------------------
39
+ # Public helpers (cached)
40
+ # ---------------------------------------------------------------------
41
+ @lru_cache(maxsize=512)
42
  async def get_hpo(term_id: str) -> Dict:
43
+ """Return JSON for `HP:NNNNNNN` (raises if not found)."""
44
+ return await _get(f"{_BASE}/term/{term_id}")
45
+
46
+
47
+ @lru_cache(maxsize=256)
48
+ async def search_hpo(term: str) -> Optional[Dict]:
49
+ """Return top search hit (`id`, `name`) for free‑text query or None."""
50
+ data = await _get(f"{_BASE}/search/{term}")
51
+ hits: List[Dict] = data.get("_embedded", {}).get("terms", [])
52
+ return hits[0] if hits else None
53
+
54
+ # ---------------------------------------------------------------------
55
+ # CLI test
56
+ # ---------------------------------------------------------------------
57
+ if __name__ == "__main__":
58
+ async def _demo():
59
+ hit = await search_hpo("microcephaly")
60
+ print("Top search hit:", hit)
61
+ if hit:
62
+ full = await get_hpo(hit["id"])
63
+ print("Definition:", full.get("definition"))
64
+ asyncio.run(_demo())