@nahisaho/satori 0.11.1 → 0.13.0
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.
- package/README.md +125 -56
- package/package.json +1 -1
- package/src/.github/skills/scientific-biothings-idmapping/SKILL.md +298 -0
- package/src/.github/skills/scientific-cancer-genomics/SKILL.md +287 -0
- package/src/.github/skills/scientific-clinical-reporting/SKILL.md +324 -0
- package/src/.github/skills/scientific-compound-screening/SKILL.md +245 -0
- package/src/.github/skills/scientific-genome-sequence-tools/SKILL.md +304 -0
- package/src/.github/skills/scientific-healthcare-ai/SKILL.md +273 -0
- package/src/.github/skills/scientific-human-protein-atlas/SKILL.md +244 -0
- package/src/.github/skills/scientific-literature-search/SKILL.md +443 -0
- package/src/.github/skills/scientific-metabolic-modeling/SKILL.md +288 -0
- package/src/.github/skills/scientific-metabolomics-databases/SKILL.md +288 -0
- package/src/.github/skills/scientific-molecular-docking/SKILL.md +303 -0
- package/src/.github/skills/scientific-noncoding-rna/SKILL.md +262 -0
- package/src/.github/skills/scientific-pathway-enrichment/SKILL.md +449 -0
- package/src/.github/skills/scientific-pharmacology-targets/SKILL.md +323 -0
- package/src/.github/skills/scientific-protein-domain-family/SKILL.md +369 -0
- package/src/.github/skills/scientific-protein-interaction-network/SKILL.md +352 -0
- package/src/.github/skills/scientific-rare-disease-genetics/SKILL.md +327 -0
- package/src/.github/skills/scientific-structural-proteomics/SKILL.md +317 -0
- package/src/.github/skills/scientific-systematic-review/SKILL.md +361 -0
- package/src/.github/skills/scientific-variant-effect-prediction/SKILL.md +325 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scientific-human-protein-atlas
|
|
3
|
+
description: |
|
|
4
|
+
Human Protein Atlas (HPA) 統合スキル。組織/細胞タンパク質発現、
|
|
5
|
+
がん予後バイオマーカー、RNA 発現プロファイル、細胞内局在、
|
|
6
|
+
タンパク質相互作用の包括的検索・解析パイプライン。
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Scientific Human Protein Atlas
|
|
10
|
+
|
|
11
|
+
HPA REST API を活用した組織・細胞レベルの
|
|
12
|
+
タンパク質発現プロファイリングパイプラインを提供する。
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
- 遺伝子/タンパク質の組織発現パターンを調べるとき
|
|
17
|
+
- がん予後バイオマーカー候補を評価するとき
|
|
18
|
+
- 細胞内局在 (subcellular localization) を確認するとき
|
|
19
|
+
- 細胞株間の発現比較を行うとき
|
|
20
|
+
- RNA 発現データ (HPA/GTEx/FANTOM5) を統合するとき
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
## 1. HPA 遺伝子基本情報取得
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import requests
|
|
30
|
+
import pandas as pd
|
|
31
|
+
|
|
32
|
+
HPA_API = "https://www.proteinatlas.org/api"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_hpa_gene_info(ensembl_id):
|
|
36
|
+
"""
|
|
37
|
+
HPA 遺伝子基本情報取得。
|
|
38
|
+
|
|
39
|
+
Parameters:
|
|
40
|
+
ensembl_id: str — Ensembl gene ID (e.g., "ENSG00000141510")
|
|
41
|
+
|
|
42
|
+
ToolUniverse:
|
|
43
|
+
HPA_get_gene_basic_info_by_ensembl_id(ensembl_id=ensembl_id)
|
|
44
|
+
HPA_get_comprehensive_gene_details_by_ensembl_id(ensembl_id=ensembl_id)
|
|
45
|
+
"""
|
|
46
|
+
url = f"https://www.proteinatlas.org/{ensembl_id}.json"
|
|
47
|
+
resp = requests.get(url)
|
|
48
|
+
resp.raise_for_status()
|
|
49
|
+
data = resp.json()
|
|
50
|
+
|
|
51
|
+
info = {
|
|
52
|
+
"ensembl_id": ensembl_id,
|
|
53
|
+
"gene_name": data.get("Gene", ""),
|
|
54
|
+
"gene_description": data.get("Gene description", ""),
|
|
55
|
+
"uniprot_id": data.get("Uniprot", []),
|
|
56
|
+
"chromosome": data.get("Chromosome", ""),
|
|
57
|
+
"protein_class": data.get("Protein class", []),
|
|
58
|
+
"evidence": data.get("Evidence", ""),
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
print(f"HPA gene: {info['gene_name']} ({ensembl_id})")
|
|
62
|
+
return info, data
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 2. 組織 RNA 発現プロファイル
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
def get_tissue_rna_expression(gene_name):
|
|
69
|
+
"""
|
|
70
|
+
HPA 組織別 RNA 発現データ取得。
|
|
71
|
+
|
|
72
|
+
ToolUniverse:
|
|
73
|
+
HPA_get_rna_expression_by_source(gene=gene_name, source="HPA")
|
|
74
|
+
HPA_get_rna_expression_in_specific_tissues(gene=gene_name, tissues=tissues)
|
|
75
|
+
"""
|
|
76
|
+
url = f"https://www.proteinatlas.org/{gene_name}.json"
|
|
77
|
+
resp = requests.get(url)
|
|
78
|
+
resp.raise_for_status()
|
|
79
|
+
data = resp.json()
|
|
80
|
+
|
|
81
|
+
rna_data = data.get("RNA tissue specific nTPM", [])
|
|
82
|
+
results = []
|
|
83
|
+
for entry in rna_data:
|
|
84
|
+
results.append({
|
|
85
|
+
"tissue": entry.get("Tissue", ""),
|
|
86
|
+
"cell_type": entry.get("Cell type", ""),
|
|
87
|
+
"ntpm": float(entry.get("nTPM", 0)),
|
|
88
|
+
"detection": entry.get("Detection", ""),
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
df = pd.DataFrame(results)
|
|
92
|
+
if not df.empty:
|
|
93
|
+
df = df.sort_values("ntpm", ascending=False)
|
|
94
|
+
|
|
95
|
+
print(f"HPA RNA expression '{gene_name}': {len(df)} tissue entries")
|
|
96
|
+
return df
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## 3. がん予後バイオマーカー解析
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
def get_cancer_prognostics(gene_name):
|
|
103
|
+
"""
|
|
104
|
+
HPA がん予後データ取得。
|
|
105
|
+
|
|
106
|
+
ToolUniverse:
|
|
107
|
+
HPA_get_cancer_prognostics_by_gene(gene=gene_name)
|
|
108
|
+
"""
|
|
109
|
+
url = f"https://www.proteinatlas.org/{gene_name}.json"
|
|
110
|
+
resp = requests.get(url)
|
|
111
|
+
resp.raise_for_status()
|
|
112
|
+
data = resp.json()
|
|
113
|
+
|
|
114
|
+
prognostics = data.get("Pathology prognostics", [])
|
|
115
|
+
results = []
|
|
116
|
+
for entry in prognostics:
|
|
117
|
+
results.append({
|
|
118
|
+
"cancer_type": entry.get("Cancer type", ""),
|
|
119
|
+
"prognostic_type": entry.get("Prognostic type", ""),
|
|
120
|
+
"is_prognostic": entry.get("Is prognostic", False),
|
|
121
|
+
"p_value": float(entry.get("p-value", 1.0)),
|
|
122
|
+
"high_expression_favorable": entry.get(
|
|
123
|
+
"High expression is favorable", None
|
|
124
|
+
),
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
df = pd.DataFrame(results)
|
|
128
|
+
if not df.empty:
|
|
129
|
+
df = df.sort_values("p_value")
|
|
130
|
+
significant = df[df["p_value"] < 0.05]
|
|
131
|
+
print(f"HPA cancer prognostics '{gene_name}': "
|
|
132
|
+
f"{len(significant)}/{len(df)} significant")
|
|
133
|
+
else:
|
|
134
|
+
print(f"HPA cancer prognostics '{gene_name}': no data")
|
|
135
|
+
return df
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## 4. 細胞内局在
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
def get_subcellular_location(gene_name):
|
|
142
|
+
"""
|
|
143
|
+
HPA 細胞内局在データ取得。
|
|
144
|
+
|
|
145
|
+
ToolUniverse:
|
|
146
|
+
HPA_get_subcellular_location(gene=gene_name)
|
|
147
|
+
"""
|
|
148
|
+
url = f"https://www.proteinatlas.org/{gene_name}.json"
|
|
149
|
+
resp = requests.get(url)
|
|
150
|
+
resp.raise_for_status()
|
|
151
|
+
data = resp.json()
|
|
152
|
+
|
|
153
|
+
sc = data.get("Subcellular location", [])
|
|
154
|
+
results = []
|
|
155
|
+
for entry in sc:
|
|
156
|
+
results.append({
|
|
157
|
+
"location": entry.get("Location", ""),
|
|
158
|
+
"reliability": entry.get("Reliability", ""),
|
|
159
|
+
"enhanced": entry.get("Enhanced", False),
|
|
160
|
+
"supported": entry.get("Supported", False),
|
|
161
|
+
"cell_lines": entry.get("Cell lines", []),
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
df = pd.DataFrame(results)
|
|
165
|
+
print(f"HPA subcellular '{gene_name}': {len(df)} locations")
|
|
166
|
+
return df
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## 5. タンパク質相互作用ネットワーク (HPA)
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
def get_hpa_protein_interactions(gene_name):
|
|
173
|
+
"""
|
|
174
|
+
HPA タンパク質相互作用データ取得。
|
|
175
|
+
|
|
176
|
+
ToolUniverse:
|
|
177
|
+
HPA_get_protein_interactions_by_gene(gene=gene_name)
|
|
178
|
+
HPA_get_biological_processes_by_gene(gene=gene_name)
|
|
179
|
+
HPA_get_contextual_biological_process_analysis(gene=gene_name)
|
|
180
|
+
"""
|
|
181
|
+
url = f"https://www.proteinatlas.org/{gene_name}.json"
|
|
182
|
+
resp = requests.get(url)
|
|
183
|
+
resp.raise_for_status()
|
|
184
|
+
data = resp.json()
|
|
185
|
+
|
|
186
|
+
interactions = data.get("Protein interaction partners", [])
|
|
187
|
+
results = []
|
|
188
|
+
for partner in interactions:
|
|
189
|
+
results.append({
|
|
190
|
+
"partner_gene": partner.get("Gene", ""),
|
|
191
|
+
"partner_ensembl": partner.get("Ensembl", ""),
|
|
192
|
+
"confidence": partner.get("Confidence", ""),
|
|
193
|
+
"source": partner.get("Source", ""),
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
df = pd.DataFrame(results)
|
|
197
|
+
print(f"HPA interactions '{gene_name}': {len(df)} partners")
|
|
198
|
+
return df
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## References
|
|
202
|
+
|
|
203
|
+
### Output Files
|
|
204
|
+
|
|
205
|
+
| ファイル | 形式 |
|
|
206
|
+
|---|---|
|
|
207
|
+
| `results/hpa_gene_info.json` | JSON |
|
|
208
|
+
| `results/hpa_tissue_expression.csv` | CSV |
|
|
209
|
+
| `results/hpa_cancer_prognostics.csv` | CSV |
|
|
210
|
+
| `results/hpa_subcellular.csv` | CSV |
|
|
211
|
+
| `results/hpa_interactions.csv` | CSV |
|
|
212
|
+
|
|
213
|
+
### 利用可能ツール
|
|
214
|
+
|
|
215
|
+
| カテゴリ | 主要ツール | 用途 |
|
|
216
|
+
|---|---|---|
|
|
217
|
+
| HPA | `HPA_generic_search` | 汎用検索 |
|
|
218
|
+
| HPA | `HPA_get_gene_basic_info_by_ensembl_id` | 遺伝子基本情報 |
|
|
219
|
+
| HPA | `HPA_get_comprehensive_gene_details_by_ensembl_id` | 包括的詳細 |
|
|
220
|
+
| HPA | `HPA_get_rna_expression_by_source` | RNA 発現 |
|
|
221
|
+
| HPA | `HPA_get_rna_expression_in_specific_tissues` | 組織別発現 |
|
|
222
|
+
| HPA | `HPA_get_cancer_prognostics_by_gene` | がん予後 |
|
|
223
|
+
| HPA | `HPA_get_subcellular_location` | 細胞内局在 |
|
|
224
|
+
| HPA | `HPA_get_protein_interactions_by_gene` | PPI |
|
|
225
|
+
| HPA | `HPA_get_biological_processes_by_gene` | 生物学的プロセス |
|
|
226
|
+
| HPA | `HPA_get_contextual_biological_process_analysis` | プロセス解析 |
|
|
227
|
+
| HPA | `HPA_get_disease_expression_by_gene_tissue_disease` | 疾患発現 |
|
|
228
|
+
| HPA | `HPA_get_comparative_expression_by_gene_and_cellline` | 細胞株比較 |
|
|
229
|
+
| HPA | `HPA_get_gene_tsv_data_by_ensembl_id` | TSV データ |
|
|
230
|
+
| HPA | `HPA_search_genes_by_query` | 遺伝子検索 |
|
|
231
|
+
|
|
232
|
+
### 参照スキル
|
|
233
|
+
|
|
234
|
+
| スキル | 関連 |
|
|
235
|
+
|---|---|
|
|
236
|
+
| `scientific-gene-expression-transcriptomics` | GEO/GTEx 発現解析 |
|
|
237
|
+
| `scientific-proteomics-mass-spectrometry` | プロテオミクス |
|
|
238
|
+
| `scientific-cancer-genomics` | がんゲノミクス |
|
|
239
|
+
| `scientific-protein-interaction-network` | PPI ネットワーク |
|
|
240
|
+
| `scientific-pathway-enrichment` | パスウェイ濃縮 |
|
|
241
|
+
|
|
242
|
+
### 依存パッケージ
|
|
243
|
+
|
|
244
|
+
`requests`, `pandas`
|
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scientific-literature-search
|
|
3
|
+
description: |
|
|
4
|
+
学術文献検索・取得スキル。PubMed E-utilities、Semantic Scholar、
|
|
5
|
+
OpenAlex、EuropePMC、CrossRef の 5 大学術データベース API を統合した
|
|
6
|
+
文献検索パイプライン。MeSH 構造化検索、引用ネットワーク分析、
|
|
7
|
+
著者/機関メトリクス、全文取得、PICO ベース検索戦略対応。
|
|
8
|
+
29 の ToolUniverse SMCP ツールと連携。
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Scientific Literature Search
|
|
12
|
+
|
|
13
|
+
PubMed / Semantic Scholar / OpenAlex / EuropePMC / CrossRef の
|
|
14
|
+
5 大学術 DB を統合した文献検索・メタデータ取得パイプラインを提供する。
|
|
15
|
+
|
|
16
|
+
## When to Use
|
|
17
|
+
|
|
18
|
+
- PubMed で MeSH 用語を用いた構造化検索が必要なとき
|
|
19
|
+
- Semantic Scholar でセマンティック類似論文を発見するとき
|
|
20
|
+
- OpenAlex で著者・機関・ジャーナルメトリクスを分析するとき
|
|
21
|
+
- 特定論文の引用/被引用ネットワークを構築するとき
|
|
22
|
+
- 系統的レビューのためのマルチ DB 横断検索が必要なとき
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
## 1. PubMed E-utilities 検索
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import requests
|
|
32
|
+
import xml.etree.ElementTree as ET
|
|
33
|
+
import pandas as pd
|
|
34
|
+
import time
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def pubmed_search(query, max_results=100, sort="relevance",
|
|
38
|
+
date_from=None, date_to=None, rettype="xml"):
|
|
39
|
+
"""
|
|
40
|
+
PubMed E-utilities による構造化検索。
|
|
41
|
+
|
|
42
|
+
Parameters:
|
|
43
|
+
query: str — PubMed クエリ (MeSH 構文対応)
|
|
44
|
+
max_results: int — 最大取得件数
|
|
45
|
+
sort: "relevance" or "date"
|
|
46
|
+
date_from/to: "YYYY/MM/DD" フォーマット
|
|
47
|
+
"""
|
|
48
|
+
base = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils"
|
|
49
|
+
|
|
50
|
+
# Step 1: esearch — PMID 取得
|
|
51
|
+
params = {
|
|
52
|
+
"db": "pubmed",
|
|
53
|
+
"term": query,
|
|
54
|
+
"retmax": max_results,
|
|
55
|
+
"sort": sort,
|
|
56
|
+
"retmode": "json",
|
|
57
|
+
}
|
|
58
|
+
if date_from:
|
|
59
|
+
params["mindate"] = date_from
|
|
60
|
+
params["datetype"] = "pdat"
|
|
61
|
+
if date_to:
|
|
62
|
+
params["maxdate"] = date_to
|
|
63
|
+
|
|
64
|
+
resp = requests.get(f"{base}/esearch.fcgi", params=params)
|
|
65
|
+
data = resp.json()
|
|
66
|
+
pmids = data["esearchresult"]["idlist"]
|
|
67
|
+
total = int(data["esearchresult"]["count"])
|
|
68
|
+
print(f"PubMed search: {total} total results, fetching {len(pmids)}")
|
|
69
|
+
|
|
70
|
+
if not pmids:
|
|
71
|
+
return pd.DataFrame()
|
|
72
|
+
|
|
73
|
+
# Step 2: efetch — 詳細取得
|
|
74
|
+
time.sleep(0.4)
|
|
75
|
+
fetch_params = {
|
|
76
|
+
"db": "pubmed",
|
|
77
|
+
"id": ",".join(pmids),
|
|
78
|
+
"rettype": "xml",
|
|
79
|
+
"retmode": "xml",
|
|
80
|
+
}
|
|
81
|
+
resp = requests.get(f"{base}/efetch.fcgi", params=fetch_params)
|
|
82
|
+
root = ET.fromstring(resp.text)
|
|
83
|
+
|
|
84
|
+
articles = []
|
|
85
|
+
for article in root.findall(".//PubmedArticle"):
|
|
86
|
+
medline = article.find(".//MedlineCitation")
|
|
87
|
+
pmid = medline.findtext("PMID", "")
|
|
88
|
+
title = medline.findtext(".//ArticleTitle", "")
|
|
89
|
+
abstract = medline.findtext(".//AbstractText", "")
|
|
90
|
+
journal = medline.findtext(".//Journal/Title", "")
|
|
91
|
+
year = medline.findtext(".//PubDate/Year", "")
|
|
92
|
+
|
|
93
|
+
authors = []
|
|
94
|
+
for author in medline.findall(".//Author"):
|
|
95
|
+
last = author.findtext("LastName", "")
|
|
96
|
+
fore = author.findtext("ForeName", "")
|
|
97
|
+
if last:
|
|
98
|
+
authors.append(f"{last} {fore}")
|
|
99
|
+
|
|
100
|
+
mesh_terms = [m.findtext("DescriptorName", "")
|
|
101
|
+
for m in medline.findall(".//MeshHeading")]
|
|
102
|
+
|
|
103
|
+
articles.append({
|
|
104
|
+
"pmid": pmid,
|
|
105
|
+
"title": title,
|
|
106
|
+
"abstract": abstract[:500],
|
|
107
|
+
"journal": journal,
|
|
108
|
+
"year": year,
|
|
109
|
+
"authors": "; ".join(authors[:5]),
|
|
110
|
+
"mesh_terms": "; ".join(mesh_terms[:10]),
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
return pd.DataFrame(articles)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## 2. Semantic Scholar API 検索
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
def semantic_scholar_search(query, max_results=50, year_from=None,
|
|
120
|
+
fields=None):
|
|
121
|
+
"""
|
|
122
|
+
Semantic Scholar Academic Graph API 検索。
|
|
123
|
+
|
|
124
|
+
Parameters:
|
|
125
|
+
query: str — 検索クエリ
|
|
126
|
+
fields: list — 取得フィールド
|
|
127
|
+
"""
|
|
128
|
+
url = "https://api.semanticscholar.org/graph/v1/paper/search"
|
|
129
|
+
|
|
130
|
+
if fields is None:
|
|
131
|
+
fields = ["title", "abstract", "year", "citationCount",
|
|
132
|
+
"influentialCitationCount", "authors", "url",
|
|
133
|
+
"openAccessPdf"]
|
|
134
|
+
|
|
135
|
+
params = {
|
|
136
|
+
"query": query,
|
|
137
|
+
"limit": min(max_results, 100),
|
|
138
|
+
"fields": ",".join(fields),
|
|
139
|
+
}
|
|
140
|
+
if year_from:
|
|
141
|
+
params["year"] = f"{year_from}-"
|
|
142
|
+
|
|
143
|
+
resp = requests.get(url, params=params)
|
|
144
|
+
data = resp.json()
|
|
145
|
+
papers = data.get("data", [])
|
|
146
|
+
|
|
147
|
+
results = []
|
|
148
|
+
for p in papers:
|
|
149
|
+
results.append({
|
|
150
|
+
"paper_id": p.get("paperId", ""),
|
|
151
|
+
"title": p.get("title", ""),
|
|
152
|
+
"abstract": (p.get("abstract") or "")[:300],
|
|
153
|
+
"year": p.get("year"),
|
|
154
|
+
"citations": p.get("citationCount", 0),
|
|
155
|
+
"influential_citations": p.get("influentialCitationCount", 0),
|
|
156
|
+
"authors": "; ".join([a.get("name", "")
|
|
157
|
+
for a in (p.get("authors") or [])[:5]]),
|
|
158
|
+
"url": p.get("url", ""),
|
|
159
|
+
"open_access": bool(p.get("openAccessPdf")),
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
df = pd.DataFrame(results)
|
|
163
|
+
print(f"Semantic Scholar: {data.get('total', 0)} total, "
|
|
164
|
+
f"{len(df)} fetched")
|
|
165
|
+
return df
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## 3. OpenAlex 著者・機関メトリクス
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
def openalex_search(query, entity_type="works", max_results=50,
|
|
172
|
+
filters=None):
|
|
173
|
+
"""
|
|
174
|
+
OpenAlex API 検索 (250M+ works, 90M+ authors)。
|
|
175
|
+
|
|
176
|
+
Parameters:
|
|
177
|
+
query: str — 検索クエリ
|
|
178
|
+
entity_type: "works", "authors", "institutions", "concepts"
|
|
179
|
+
filters: dict — OpenAlex フィルタ (e.g., {"from_publication_date": "2020-01-01"})
|
|
180
|
+
"""
|
|
181
|
+
base = "https://api.openalex.org"
|
|
182
|
+
url = f"{base}/{entity_type}"
|
|
183
|
+
|
|
184
|
+
params = {
|
|
185
|
+
"search": query,
|
|
186
|
+
"per-page": min(max_results, 200),
|
|
187
|
+
"mailto": "research@example.com",
|
|
188
|
+
}
|
|
189
|
+
if filters:
|
|
190
|
+
filter_parts = [f"{k}:{v}" for k, v in filters.items()]
|
|
191
|
+
params["filter"] = ",".join(filter_parts)
|
|
192
|
+
|
|
193
|
+
resp = requests.get(url, params=params)
|
|
194
|
+
data = resp.json()
|
|
195
|
+
|
|
196
|
+
results = data.get("results", [])
|
|
197
|
+
total = data.get("meta", {}).get("count", 0)
|
|
198
|
+
print(f"OpenAlex {entity_type}: {total} total, {len(results)} fetched")
|
|
199
|
+
|
|
200
|
+
if entity_type == "works":
|
|
201
|
+
return pd.DataFrame([{
|
|
202
|
+
"id": r.get("id", ""),
|
|
203
|
+
"title": r.get("title", ""),
|
|
204
|
+
"year": r.get("publication_year"),
|
|
205
|
+
"citations": r.get("cited_by_count", 0),
|
|
206
|
+
"doi": r.get("doi", ""),
|
|
207
|
+
"type": r.get("type", ""),
|
|
208
|
+
"open_access": r.get("open_access", {}).get("is_oa", False),
|
|
209
|
+
} for r in results])
|
|
210
|
+
elif entity_type == "authors":
|
|
211
|
+
return pd.DataFrame([{
|
|
212
|
+
"id": r.get("id", ""),
|
|
213
|
+
"name": r.get("display_name", ""),
|
|
214
|
+
"works_count": r.get("works_count", 0),
|
|
215
|
+
"citations": r.get("cited_by_count", 0),
|
|
216
|
+
"h_index": r.get("summary_stats", {}).get("h_index", 0),
|
|
217
|
+
"institution": (r.get("last_known_institutions") or [{}])[0].get(
|
|
218
|
+
"display_name", "") if r.get("last_known_institutions") else "",
|
|
219
|
+
} for r in results])
|
|
220
|
+
|
|
221
|
+
return results
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## 4. EuropePMC 全文検索
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
def europepmc_search(query, max_results=50, source="MED",
|
|
228
|
+
open_access_only=False):
|
|
229
|
+
"""
|
|
230
|
+
EuropePMC REST API 検索 (39M+ records)。
|
|
231
|
+
|
|
232
|
+
Parameters:
|
|
233
|
+
query: str — 検索クエリ
|
|
234
|
+
source: "MED" (PubMed), "PMC" (PubMed Central), "AGR", "CBA"
|
|
235
|
+
open_access_only: True でオープンアクセスのみ
|
|
236
|
+
"""
|
|
237
|
+
url = "https://www.ebi.ac.uk/europepmc/webservices/rest/search"
|
|
238
|
+
|
|
239
|
+
q = query
|
|
240
|
+
if open_access_only:
|
|
241
|
+
q += " AND OPEN_ACCESS:y"
|
|
242
|
+
|
|
243
|
+
params = {
|
|
244
|
+
"query": q,
|
|
245
|
+
"resultType": "core",
|
|
246
|
+
"pageSize": min(max_results, 100),
|
|
247
|
+
"format": "json",
|
|
248
|
+
"src": source,
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
resp = requests.get(url, params=params)
|
|
252
|
+
data = resp.json()
|
|
253
|
+
results = data.get("resultList", {}).get("result", [])
|
|
254
|
+
total = data.get("hitCount", 0)
|
|
255
|
+
|
|
256
|
+
articles = []
|
|
257
|
+
for r in results:
|
|
258
|
+
articles.append({
|
|
259
|
+
"pmid": r.get("pmid", ""),
|
|
260
|
+
"pmcid": r.get("pmcid", ""),
|
|
261
|
+
"title": r.get("title", ""),
|
|
262
|
+
"journal": r.get("journalTitle", ""),
|
|
263
|
+
"year": r.get("pubYear", ""),
|
|
264
|
+
"citations": r.get("citedByCount", 0),
|
|
265
|
+
"has_fulltext": r.get("hasTextMinedTerms", "N") == "Y",
|
|
266
|
+
"is_open_access": r.get("isOpenAccess", "N") == "Y",
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
df = pd.DataFrame(articles)
|
|
270
|
+
print(f"EuropePMC: {total} total, {len(df)} fetched")
|
|
271
|
+
return df
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## 5. CrossRef メタデータ取得
|
|
275
|
+
|
|
276
|
+
```python
|
|
277
|
+
def crossref_search(query, max_results=50, filter_type=None,
|
|
278
|
+
from_date=None, sort="relevance"):
|
|
279
|
+
"""
|
|
280
|
+
CrossRef REST API 検索 (DOI メタデータ)。
|
|
281
|
+
|
|
282
|
+
Parameters:
|
|
283
|
+
query: str — 検索クエリ
|
|
284
|
+
filter_type: str — DOI タイプフィルタ ("journal-article", "book-chapter")
|
|
285
|
+
from_date: str — "YYYY-MM-DD"
|
|
286
|
+
sort: "relevance", "published", "is-referenced-by-count"
|
|
287
|
+
"""
|
|
288
|
+
url = "https://api.crossref.org/works"
|
|
289
|
+
params = {
|
|
290
|
+
"query": query,
|
|
291
|
+
"rows": min(max_results, 100),
|
|
292
|
+
"sort": sort,
|
|
293
|
+
"mailto": "research@example.com",
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
filters = []
|
|
297
|
+
if filter_type:
|
|
298
|
+
filters.append(f"type:{filter_type}")
|
|
299
|
+
if from_date:
|
|
300
|
+
filters.append(f"from-pub-date:{from_date}")
|
|
301
|
+
if filters:
|
|
302
|
+
params["filter"] = ",".join(filters)
|
|
303
|
+
|
|
304
|
+
resp = requests.get(url, params=params)
|
|
305
|
+
data = resp.json()
|
|
306
|
+
items = data.get("message", {}).get("items", [])
|
|
307
|
+
total = data.get("message", {}).get("total-results", 0)
|
|
308
|
+
|
|
309
|
+
results = []
|
|
310
|
+
for item in items:
|
|
311
|
+
title = item.get("title", [""])[0] if item.get("title") else ""
|
|
312
|
+
results.append({
|
|
313
|
+
"doi": item.get("DOI", ""),
|
|
314
|
+
"title": title,
|
|
315
|
+
"journal": item.get("container-title", [""])[0] if item.get("container-title") else "",
|
|
316
|
+
"year": item.get("published", {}).get("date-parts", [[None]])[0][0],
|
|
317
|
+
"citations": item.get("is-referenced-by-count", 0),
|
|
318
|
+
"type": item.get("type", ""),
|
|
319
|
+
"publisher": item.get("publisher", ""),
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
df = pd.DataFrame(results)
|
|
323
|
+
print(f"CrossRef: {total} total, {len(df)} fetched")
|
|
324
|
+
return df
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## 6. 引用ネットワーク構築
|
|
328
|
+
|
|
329
|
+
```python
|
|
330
|
+
def build_citation_network(seed_pmids, depth=1, max_per_level=20):
|
|
331
|
+
"""
|
|
332
|
+
PubMed 論文の引用/被引用ネットワーク構築。
|
|
333
|
+
|
|
334
|
+
Parameters:
|
|
335
|
+
seed_pmids: list — 起点となる PMID リスト
|
|
336
|
+
depth: int — 探索深度 (1=直接引用のみ)
|
|
337
|
+
max_per_level: int — 各レベルの最大ノード数
|
|
338
|
+
"""
|
|
339
|
+
import networkx as nx
|
|
340
|
+
|
|
341
|
+
G = nx.DiGraph()
|
|
342
|
+
visited = set()
|
|
343
|
+
current_level = set(seed_pmids)
|
|
344
|
+
|
|
345
|
+
for level in range(depth + 1):
|
|
346
|
+
next_level = set()
|
|
347
|
+
for pmid in list(current_level)[:max_per_level]:
|
|
348
|
+
if pmid in visited:
|
|
349
|
+
continue
|
|
350
|
+
visited.add(pmid)
|
|
351
|
+
G.add_node(pmid, level=level, is_seed=(level == 0))
|
|
352
|
+
|
|
353
|
+
# elink で引用関係取得
|
|
354
|
+
time.sleep(0.4)
|
|
355
|
+
url = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/elink.fcgi"
|
|
356
|
+
params = {
|
|
357
|
+
"dbfrom": "pubmed", "db": "pubmed",
|
|
358
|
+
"id": pmid, "linkname": "pubmed_pubmed_citedin",
|
|
359
|
+
"retmode": "json",
|
|
360
|
+
}
|
|
361
|
+
try:
|
|
362
|
+
resp = requests.get(url, params=params)
|
|
363
|
+
data = resp.json()
|
|
364
|
+
links = data.get("linksets", [{}])[0].get("linksetdbs", [])
|
|
365
|
+
if links:
|
|
366
|
+
cited_by = [l["id"] for l in links[0].get("links", [])[:max_per_level]]
|
|
367
|
+
for citing in cited_by:
|
|
368
|
+
G.add_edge(citing, pmid)
|
|
369
|
+
next_level.add(citing)
|
|
370
|
+
except Exception:
|
|
371
|
+
continue
|
|
372
|
+
|
|
373
|
+
current_level = next_level - visited
|
|
374
|
+
|
|
375
|
+
print(f"Citation network: {G.number_of_nodes()} nodes, "
|
|
376
|
+
f"{G.number_of_edges()} edges, depth={depth}")
|
|
377
|
+
return G
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## References
|
|
381
|
+
|
|
382
|
+
### Output Files
|
|
383
|
+
|
|
384
|
+
| ファイル | 形式 |
|
|
385
|
+
|---|---|
|
|
386
|
+
| `results/pubmed_search.csv` | CSV |
|
|
387
|
+
| `results/semantic_scholar_results.csv` | CSV |
|
|
388
|
+
| `results/openalex_results.csv` | CSV |
|
|
389
|
+
| `results/europepmc_results.csv` | CSV |
|
|
390
|
+
| `results/crossref_results.csv` | CSV |
|
|
391
|
+
| `results/citation_network.graphml` | GraphML |
|
|
392
|
+
| `figures/citation_network.png` | PNG |
|
|
393
|
+
|
|
394
|
+
### 利用可能ツール
|
|
395
|
+
|
|
396
|
+
> [ToolUniverse](https://github.com/mims-harvard/ToolUniverse) SMCP 経由で利用可能な外部ツール。
|
|
397
|
+
|
|
398
|
+
| カテゴリ | 主要ツール | 用途 |
|
|
399
|
+
|---|---|---|
|
|
400
|
+
| PubMed | `PubMed_search_articles` | PubMed 論文検索 |
|
|
401
|
+
| PubMed | `PubMed_get_article` | 論文詳細取得 |
|
|
402
|
+
| PubMed | `PubMed_get_cited_by` | 被引用論文取得 |
|
|
403
|
+
| PubMed | `PubMed_get_related` | 関連論文検索 |
|
|
404
|
+
| PubMed | `PubMed_get_links` | 関連リンク取得 |
|
|
405
|
+
| PubMed | `PubMed_Guidelines_Search` | ガイドライン検索 |
|
|
406
|
+
| EuropePMC | `EuropePMC_search_articles` | EuropePMC 検索 |
|
|
407
|
+
| EuropePMC | `EuropePMC_get_article` | 記事詳細取得 |
|
|
408
|
+
| EuropePMC | `EuropePMC_get_references` | 参考文献取得 |
|
|
409
|
+
| EuropePMC | `EuropePMC_get_citations` | 引用取得 |
|
|
410
|
+
| EuropePMC | `EuropePMC_get_fulltext` | 全文取得 |
|
|
411
|
+
| EuropePMC | `EuropePMC_get_fulltext_snippets` | 全文スニペット |
|
|
412
|
+
| EuropePMC | `EuropePMC_Guidelines_Search` | ガイドライン検索 |
|
|
413
|
+
| Semantic Scholar | `SemanticScholar_search_papers` | セマンティック論文検索 |
|
|
414
|
+
| Semantic Scholar | `SemanticScholar_get_pdf_snippets` | PDF スニペット |
|
|
415
|
+
| OpenAlex | `openalex_literature_search` | 文献検索 |
|
|
416
|
+
| OpenAlex | `openalex_get_work` | 論文詳細 |
|
|
417
|
+
| OpenAlex | `openalex_get_work_by_doi` | DOI → 論文 |
|
|
418
|
+
| OpenAlex | `openalex_search_works` | 論文検索 (REST) |
|
|
419
|
+
| OpenAlex | `openalex_get_author` | 著者詳細 |
|
|
420
|
+
| OpenAlex | `openalex_search_authors` | 著者検索 |
|
|
421
|
+
| OpenAlex | `openalex_get_institution` | 機関詳細 |
|
|
422
|
+
| OpenAlex | `openalex_search_institutions` | 機関検索 |
|
|
423
|
+
| CrossRef | `Crossref_search_works` | DOI メタデータ検索 |
|
|
424
|
+
| CrossRef | `Crossref_get_work` | 論文メタデータ取得 |
|
|
425
|
+
| CrossRef | `Crossref_get_funder` | 助成機関情報 |
|
|
426
|
+
| CrossRef | `Crossref_get_journal` | ジャーナル情報 |
|
|
427
|
+
| CrossRef | `Crossref_list_funders` | 助成機関一覧 |
|
|
428
|
+
| CrossRef | `Crossref_list_types` | 出版タイプ一覧 |
|
|
429
|
+
|
|
430
|
+
### 参照スキル
|
|
431
|
+
|
|
432
|
+
| スキル | 関連 |
|
|
433
|
+
|---|---|
|
|
434
|
+
| `scientific-deep-research` | 文献検索 → 深層リサーチ |
|
|
435
|
+
| `scientific-citation-checker` | 引用検証連携 |
|
|
436
|
+
| `scientific-systematic-review` | 系統的検索戦略 |
|
|
437
|
+
| `scientific-meta-analysis` | メタアナリシス文献収集 |
|
|
438
|
+
| `scientific-academic-writing` | 関連文献の自動発見 |
|
|
439
|
+
| `scientific-text-mining-nlp` | 抽出テキストの NLP 解析 |
|
|
440
|
+
|
|
441
|
+
### 依存パッケージ
|
|
442
|
+
|
|
443
|
+
`requests`, `pandas`, `networkx`, `xml.etree.ElementTree` (stdlib)
|