@nahisaho/satori 0.11.0 → 0.12.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.
Files changed (27) hide show
  1. package/README.md +111 -45
  2. package/package.json +1 -1
  3. package/src/.github/skills/scientific-admet-pharmacokinetics/SKILL.md +1 -0
  4. package/src/.github/skills/scientific-cancer-genomics/SKILL.md +287 -0
  5. package/src/.github/skills/scientific-clinical-decision-support/SKILL.md +2 -0
  6. package/src/.github/skills/scientific-clinical-reporting/SKILL.md +324 -0
  7. package/src/.github/skills/scientific-computational-materials/SKILL.md +4 -4
  8. package/src/.github/skills/scientific-deep-learning/SKILL.md +1 -0
  9. package/src/.github/skills/scientific-epidemiology-public-health/SKILL.md +1 -0
  10. package/src/.github/skills/scientific-grant-writing/SKILL.md +2 -0
  11. package/src/.github/skills/scientific-lab-data-management/SKILL.md +2 -2
  12. package/src/.github/skills/scientific-literature-search/SKILL.md +443 -0
  13. package/src/.github/skills/scientific-meta-analysis/SKILL.md +10 -0
  14. package/src/.github/skills/scientific-metabolomics-databases/SKILL.md +288 -0
  15. package/src/.github/skills/scientific-molecular-docking/SKILL.md +303 -0
  16. package/src/.github/skills/scientific-pathway-enrichment/SKILL.md +449 -0
  17. package/src/.github/skills/scientific-pharmacovigilance/SKILL.md +3 -0
  18. package/src/.github/skills/scientific-population-genetics/SKILL.md +2 -0
  19. package/src/.github/skills/scientific-precision-oncology/SKILL.md +1 -0
  20. package/src/.github/skills/scientific-protein-domain-family/SKILL.md +369 -0
  21. package/src/.github/skills/scientific-protein-interaction-network/SKILL.md +352 -0
  22. package/src/.github/skills/scientific-scientific-schematics/SKILL.md +2 -2
  23. package/src/.github/skills/scientific-single-cell-genomics/SKILL.md +2 -0
  24. package/src/.github/skills/scientific-survival-clinical/SKILL.md +11 -0
  25. package/src/.github/skills/scientific-systematic-review/SKILL.md +361 -0
  26. package/src/.github/skills/scientific-variant-effect-prediction/SKILL.md +325 -0
  27. package/src/.github/skills/scientific-variant-interpretation/SKILL.md +1 -0
@@ -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)
@@ -355,6 +355,16 @@ def cumulative_meta_analysis(studies_df, sort_by="year", model="random"):
355
355
  | EuropePMC | `EuropePMC_search_articles` | ヨーロッパ文献検索 |
356
356
  | Crossref | `Crossref_search_works` | 出版情報検索 |
357
357
 
358
+ ### 参照スキル
359
+
360
+ | スキル | 連携 |
361
+ |---|---|
362
+ | `scientific-survival-clinical` | ← 生存解析・値引 HR |
363
+ | `scientific-statistical-testing` | ← 仮説検定・効果量算出 |
364
+ | `scientific-deep-research` | ← 系統的文献検索 |
365
+ | `scientific-clinical-trials-analytics` | ← 臨床試験結果の統合 |
366
+ | `scientific-academic-writing` | → メタアナリシス論文化 |
367
+
358
368
  #### 依存パッケージ
359
369
 
360
370
  ```