@nahisaho/satori 0.12.0 → 0.14.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 (22) hide show
  1. package/README.md +150 -54
  2. package/package.json +1 -1
  3. package/src/.github/skills/scientific-biomedical-pubtator/SKILL.md +331 -0
  4. package/src/.github/skills/scientific-biothings-idmapping/SKILL.md +298 -0
  5. package/src/.github/skills/scientific-cell-line-resources/SKILL.md +258 -0
  6. package/src/.github/skills/scientific-compound-screening/SKILL.md +245 -0
  7. package/src/.github/skills/scientific-ebi-databases/SKILL.md +280 -0
  8. package/src/.github/skills/scientific-genome-sequence-tools/SKILL.md +304 -0
  9. package/src/.github/skills/scientific-healthcare-ai/SKILL.md +273 -0
  10. package/src/.github/skills/scientific-human-protein-atlas/SKILL.md +244 -0
  11. package/src/.github/skills/scientific-metabolic-modeling/SKILL.md +288 -0
  12. package/src/.github/skills/scientific-noncoding-rna/SKILL.md +262 -0
  13. package/src/.github/skills/scientific-ontology-enrichment/SKILL.md +340 -0
  14. package/src/.github/skills/scientific-pharmacology-targets/SKILL.md +323 -0
  15. package/src/.github/skills/scientific-phylogenetics/SKILL.md +297 -0
  16. package/src/.github/skills/scientific-preprint-archive/SKILL.md +476 -0
  17. package/src/.github/skills/scientific-public-health-data/SKILL.md +322 -0
  18. package/src/.github/skills/scientific-rare-disease-genetics/SKILL.md +327 -0
  19. package/src/.github/skills/scientific-regulatory-genomics/SKILL.md +274 -0
  20. package/src/.github/skills/scientific-reinforcement-learning/SKILL.md +280 -0
  21. package/src/.github/skills/scientific-structural-proteomics/SKILL.md +317 -0
  22. package/src/.github/skills/scientific-symbolic-mathematics/SKILL.md +277 -0
@@ -0,0 +1,274 @@
1
+ ---
2
+ name: scientific-regulatory-genomics
3
+ description: |
4
+ レギュラトリーゲノミクススキル。RegulomeDB バリアント制御機能スコア、
5
+ ReMap 転写因子結合マッピング、4D Nucleome (4DN) 三次元ゲノム構造
6
+ 解析の統合パイプライン。
7
+ ---
8
+
9
+ # Scientific Regulatory Genomics
10
+
11
+ RegulomeDB / ReMap / 4D Nucleome を統合した
12
+ レギュラトリーゲノミクス (制御領域バリアント解析) パイプラインを提供する。
13
+
14
+ ## When to Use
15
+
16
+ - 非コード領域バリアントの制御機能を評価するとき
17
+ - RegulomeDB で SNP の調節的影響をスコアリングするとき
18
+ - ReMap で転写因子結合部位のマッピングを確認するとき
19
+ - 4DN データから三次元ゲノム構造 (TAD/ループ) を解析するとき
20
+ - GWAS ヒットの制御メカニズムを解明するとき
21
+
22
+ ---
23
+
24
+ ## Quick Start
25
+
26
+ ## 1. RegulomeDB バリアント制御スコア
27
+
28
+ ```python
29
+ import requests
30
+ import pandas as pd
31
+
32
+ REGULOMEDB_API = "https://regulomedb.org/regulome-search"
33
+
34
+
35
+ def score_regulome_variants(variants):
36
+ """
37
+ RegulomeDB — 非コード領域バリアントの制御機能スコアリング。
38
+
39
+ Parameters:
40
+ variants: list — バリアントリスト (rsID or chr:pos 形式)
41
+ e.g., ["rs12345", "chr1:109274570"]
42
+
43
+ ToolUniverse:
44
+ RegulomeDB_score_variant(variant=variant)
45
+ """
46
+ results = []
47
+ for variant in variants:
48
+ params = {"regions": variant, "genome": "GRCh38", "format": "json"}
49
+ resp = requests.get(REGULOMEDB_API, params=params)
50
+ if resp.status_code != 200:
51
+ results.append({"variant": variant, "score": None, "error": True})
52
+ continue
53
+
54
+ data = resp.json()
55
+ for hit in data.get("@graph", []):
56
+ results.append({
57
+ "variant": variant,
58
+ "regulome_score": hit.get("regulome_score", {}).get("ranking", ""),
59
+ "probability": hit.get("regulome_score", {}).get("probability", ""),
60
+ "chrom": hit.get("chrom", ""),
61
+ "start": hit.get("start", ""),
62
+ "end": hit.get("end", ""),
63
+ "dnase": hit.get("dnase", ""),
64
+ "proteins_binding": hit.get("proteins_binding", []),
65
+ "motifs": hit.get("motifs", []),
66
+ "eqtls": hit.get("eqtls", []),
67
+ "chromatin_state": hit.get("chromatin_state", {}),
68
+ })
69
+
70
+ df = pd.DataFrame(results)
71
+ if not df.empty and "regulome_score" in df.columns:
72
+ high_func = (df["regulome_score"].astype(str).str.match(r"^[12]")).sum()
73
+ print(f"RegulomeDB: {len(variants)} variants scored, "
74
+ f"{high_func} with high regulatory function (score 1-2)")
75
+ return df
76
+ ```
77
+
78
+ ## 2. ReMap 転写因子結合マッピング
79
+
80
+ ```python
81
+ REMAP_API = "https://remap.univ-amu.fr/api/v1"
82
+
83
+
84
+ def search_remap_binding(chrom, start, end, genome="hg38"):
85
+ """
86
+ ReMap — ゲノム領域の転写因子/コレギュレーター結合マッピング。
87
+
88
+ Parameters:
89
+ chrom: str — 染色体 (e.g., "chr1")
90
+ start: int — 開始座標
91
+ end: int — 終了座標
92
+ genome: str — ゲノムアセンブリ ("hg38", "hg19", "mm10")
93
+
94
+ ToolUniverse:
95
+ ReMap_search_peaks(chrom=chrom, start=start, end=end)
96
+ ReMap_get_tf_targets(tf_name=tf_name)
97
+ """
98
+ params = {
99
+ "chrom": chrom,
100
+ "start": start,
101
+ "end": end,
102
+ "genome": genome,
103
+ }
104
+ resp = requests.get(f"{REMAP_API}/peaks/search", params=params)
105
+ resp.raise_for_status()
106
+ data = resp.json()
107
+
108
+ results = []
109
+ for peak in data.get("peaks", []):
110
+ results.append({
111
+ "tf_name": peak.get("tf_name", ""),
112
+ "biotype": peak.get("biotype", ""),
113
+ "cell_type": peak.get("cell_type", ""),
114
+ "experiment": peak.get("experiment_accession", ""),
115
+ "peak_start": peak.get("start", ""),
116
+ "peak_end": peak.get("end", ""),
117
+ "score": peak.get("score", ""),
118
+ })
119
+
120
+ df = pd.DataFrame(results)
121
+ unique_tfs = df["tf_name"].nunique() if not df.empty else 0
122
+ print(f"ReMap {chrom}:{start}-{end}: {len(df)} peaks, {unique_tfs} unique TFs")
123
+ return df
124
+
125
+
126
+ def get_remap_tf_targets(tf_name, genome="hg38"):
127
+ """
128
+ ReMap — 特定転写因子の全結合部位取得。
129
+
130
+ Parameters:
131
+ tf_name: str — 転写因子名 (e.g., "TP53", "CTCF", "STAT3")
132
+ """
133
+ params = {"tf": tf_name, "genome": genome}
134
+ resp = requests.get(f"{REMAP_API}/peaks/tf", params=params)
135
+ resp.raise_for_status()
136
+ data = resp.json()
137
+
138
+ results = []
139
+ for peak in data.get("peaks", [])[:1000]: # Limit for large TFs
140
+ results.append({
141
+ "chrom": peak.get("chrom", ""),
142
+ "start": peak.get("start", ""),
143
+ "end": peak.get("end", ""),
144
+ "cell_type": peak.get("cell_type", ""),
145
+ "score": peak.get("score", ""),
146
+ })
147
+
148
+ df = pd.DataFrame(results)
149
+ print(f"ReMap TF '{tf_name}': {len(df)} binding sites")
150
+ return df
151
+ ```
152
+
153
+ ## 3. 4D Nucleome (4DN) 三次元ゲノム構造
154
+
155
+ ```python
156
+ FOURDN_API = "https://data.4dnucleome.org"
157
+
158
+
159
+ def search_4dn_experiments(query, experiment_type=None):
160
+ """
161
+ 4D Nucleome ポータル — 三次元ゲノム実験データ検索。
162
+
163
+ Parameters:
164
+ query: str — 検索クエリ (細胞株名、タンパク質名等)
165
+ experiment_type: str — 実験タイプ ("in situ Hi-C", "SPRITE", "GAM")
166
+
167
+ ToolUniverse:
168
+ FourDN_search_experiments(query=query)
169
+ """
170
+ params = {
171
+ "searchTerm": query,
172
+ "type": "ExperimentSetReplicate",
173
+ "format": "json",
174
+ }
175
+ if experiment_type:
176
+ params["experiment_type.display_title"] = experiment_type
177
+
178
+ resp = requests.get(f"{FOURDN_API}/search/", params=params)
179
+ resp.raise_for_status()
180
+ data = resp.json()
181
+
182
+ results = []
183
+ for item in data.get("@graph", []):
184
+ results.append({
185
+ "accession": item.get("accession", ""),
186
+ "title": item.get("display_title", ""),
187
+ "experiment_type": item.get("experiment_type", {}).get("display_title", ""),
188
+ "biosource": item.get("biosource_summary", ""),
189
+ "lab": item.get("lab", {}).get("display_title", ""),
190
+ "status": item.get("status", ""),
191
+ })
192
+
193
+ df = pd.DataFrame(results)
194
+ print(f"4DN search '{query}': {len(df)} experiment sets")
195
+ return df
196
+ ```
197
+
198
+ ## 4. 制御バリアント統合解析パイプライン
199
+
200
+ ```python
201
+ def regulatory_variant_pipeline(variants, genome="hg38"):
202
+ """
203
+ 制御領域バリアント統合解析。
204
+
205
+ Parameters:
206
+ variants: list — バリアントリスト (rsID or chr:pos)
207
+ """
208
+ print("=" * 60)
209
+ print("Regulatory Variant Analysis Pipeline")
210
+ print("=" * 60)
211
+
212
+ # Step 1: RegulomeDB scoring
213
+ print("\n[1/3] RegulomeDB scoring...")
214
+ regulome_df = score_regulome_variants(variants)
215
+
216
+ # Step 2: ReMap TF binding for high-scoring variants
217
+ print("\n[2/3] ReMap TF binding analysis...")
218
+ remap_results = {}
219
+ for _, row in regulome_df.iterrows():
220
+ if row.get("chrom") and row.get("start"):
221
+ chrom = row["chrom"]
222
+ start = int(row["start"]) - 500
223
+ end = int(row["end"]) + 500
224
+ try:
225
+ remap_df = search_remap_binding(chrom, start, end, genome)
226
+ remap_results[row["variant"]] = remap_df
227
+ except Exception as e:
228
+ print(f" ReMap error for {row['variant']}: {e}")
229
+
230
+ # Step 3: Summary
231
+ print("\n[3/3] Summary")
232
+ summary = {
233
+ "total_variants": len(variants),
234
+ "regulome_scored": len(regulome_df),
235
+ "high_regulatory": (
236
+ regulome_df["regulome_score"].astype(str).str.match(r"^[12]")
237
+ ).sum() if "regulome_score" in regulome_df.columns else 0,
238
+ "remap_annotated": len(remap_results),
239
+ }
240
+ print(f" Total: {summary['total_variants']}, "
241
+ f"High regulatory: {summary['high_regulatory']}, "
242
+ f"ReMap annotated: {summary['remap_annotated']}")
243
+
244
+ return {"regulome": regulome_df, "remap": remap_results, "summary": summary}
245
+ ```
246
+
247
+ ---
248
+
249
+ ## 利用可能ツール
250
+
251
+ | ToolUniverse カテゴリ | 主なツール |
252
+ |---|---|
253
+ | `regulomedb` | `RegulomeDB_score_variant` |
254
+ | `remap` | `ReMap_search_peaks`, `ReMap_get_tf_targets` |
255
+ | `fourdn_portal` | `FourDN_search_experiments` |
256
+
257
+ ## パイプライン出力
258
+
259
+ | 出力ファイル | 説明 | 連携先スキル |
260
+ |---|---|---|
261
+ | `results/regulome_scores.csv` | バリアント制御スコア | → variant-interpretation, variant-effect-prediction |
262
+ | `results/remap_binding.csv` | TF 結合マッピング | → epigenomics-chromatin, disease-research |
263
+ | `results/4dn_contacts.json` | 3D ゲノム構造データ | → single-cell-genomics, epigenomics-chromatin |
264
+
265
+ ## パイプライン統合
266
+
267
+ ```
268
+ variant-interpretation ──→ regulatory-genomics ──→ epigenomics-chromatin
269
+ (ACMG/AMP) (RegulomeDB/ReMap/4DN) (ChIP-seq/ATAC)
270
+
271
+ ├──→ disease-research (GWAS enhancer)
272
+ ├──→ gene-expression (eQTL/制御)
273
+ └──→ noncoding-rna (ncRNA 制御)
274
+ ```
@@ -0,0 +1,280 @@
1
+ ---
2
+ name: scientific-reinforcement-learning
3
+ description: |
4
+ 強化学習スキル。Stable-Baselines3 による RL エージェント訓練、
5
+ Gymnasium 環境構築、PufferLib 大規模マルチエージェント、
6
+ 科学応用 (分子生成・実験最適化・ロボット制御) パイプライン。
7
+ ---
8
+
9
+ # Scientific Reinforcement Learning
10
+
11
+ Stable-Baselines3 / PufferLib / Gymnasium を活用した
12
+ 強化学習パイプラインを提供する。
13
+
14
+ ## When to Use
15
+
16
+ - RL エージェントを訓練・評価するとき
17
+ - カスタム Gymnasium 環境を構築するとき
18
+ - 分子設計・創薬に RL を適用するとき
19
+ - 実験パラメータの逐次最適化に RL を使うとき
20
+ - マルチエージェント強化学習を実行するとき
21
+ - ロボティクス・ラボオートメーションの制御方策を学習するとき
22
+
23
+ ---
24
+
25
+ ## Quick Start
26
+
27
+ ## 1. Stable-Baselines3 基本訓練
28
+
29
+ ```python
30
+ import numpy as np
31
+ import gymnasium as gym
32
+ from stable_baselines3 import PPO, SAC, A2C, DQN
33
+ from stable_baselines3.common.evaluation import evaluate_policy
34
+ from stable_baselines3.common.vec_env import DummyVecEnv, SubprocVecEnv
35
+ from stable_baselines3.common.callbacks import EvalCallback, CheckpointCallback
36
+
37
+
38
+ def train_rl_agent(env_id, algorithm="PPO", total_timesteps=100_000,
39
+ n_envs=4, hyperparams=None):
40
+ """
41
+ Stable-Baselines3 RL エージェント訓練。
42
+
43
+ Parameters:
44
+ env_id: str — Gymnasium 環境 ID (e.g., "CartPole-v1", "LunarLander-v3")
45
+ algorithm: str — "PPO", "SAC", "A2C", "DQN"
46
+ total_timesteps: int — 総訓練ステップ数
47
+ n_envs: int — 並列環境数
48
+ hyperparams: dict — ハイパーパラメータ override
49
+
50
+ K-Dense: stable-baselines3 — RL training framework
51
+ """
52
+ algo_map = {"PPO": PPO, "SAC": SAC, "A2C": A2C, "DQN": DQN}
53
+ AlgoClass = algo_map.get(algorithm, PPO)
54
+
55
+ # Vectorized environments
56
+ env = DummyVecEnv([lambda: gym.make(env_id) for _ in range(n_envs)])
57
+
58
+ # Default hyperparams per algorithm
59
+ default_params = {
60
+ "PPO": {"learning_rate": 3e-4, "n_steps": 2048, "batch_size": 64},
61
+ "SAC": {"learning_rate": 3e-4, "buffer_size": 1_000_000},
62
+ "A2C": {"learning_rate": 7e-4, "n_steps": 5},
63
+ "DQN": {"learning_rate": 1e-4, "buffer_size": 100_000},
64
+ }
65
+ params = default_params.get(algorithm, {})
66
+ if hyperparams:
67
+ params.update(hyperparams)
68
+
69
+ model = AlgoClass("MlpPolicy", env, verbose=1, **params)
70
+
71
+ # Callbacks
72
+ eval_env = gym.make(env_id)
73
+ eval_callback = EvalCallback(
74
+ eval_env, best_model_save_path="./models/best/",
75
+ log_path="./logs/", eval_freq=10_000,
76
+ )
77
+ checkpoint_callback = CheckpointCallback(
78
+ save_freq=25_000, save_path="./models/checkpoints/",
79
+ )
80
+
81
+ model.learn(
82
+ total_timesteps=total_timesteps,
83
+ callback=[eval_callback, checkpoint_callback],
84
+ )
85
+
86
+ # Evaluation
87
+ mean_reward, std_reward = evaluate_policy(model, eval_env, n_eval_episodes=20)
88
+ print(f"RL Training ({algorithm} on {env_id}): "
89
+ f"reward = {mean_reward:.2f} ± {std_reward:.2f}")
90
+
91
+ return model, {"mean_reward": mean_reward, "std_reward": std_reward}
92
+ ```
93
+
94
+ ## 2. カスタム Gymnasium 環境
95
+
96
+ ```python
97
+ class MoleculeDesignEnv(gym.Env):
98
+ """
99
+ 分子設計用カスタム RL 環境。
100
+
101
+ 状態: 分子フィンガープリント (Morgan FP)
102
+ 行動: 原子/結合の追加・削除・変更
103
+ 報酬: 薬物らしさスコア (QED) + 結合親和性予測
104
+ """
105
+ metadata = {"render_modes": ["human"]}
106
+
107
+ def __init__(self, max_atoms=50, target_property="qed"):
108
+ super().__init__()
109
+ self.max_atoms = max_atoms
110
+ self.target_property = target_property
111
+
112
+ # Action space: discrete (add atom types, add bonds, remove)
113
+ self.action_space = gym.spaces.Discrete(10)
114
+
115
+ # Observation space: molecular fingerprint
116
+ self.observation_space = gym.spaces.Box(
117
+ low=0, high=1, shape=(2048,), dtype=np.float32,
118
+ )
119
+
120
+ self.current_mol = None
121
+ self.step_count = 0
122
+
123
+ def reset(self, seed=None, options=None):
124
+ super().reset(seed=seed)
125
+ self.current_mol = None # Start from scratch
126
+ self.step_count = 0
127
+ obs = np.zeros(2048, dtype=np.float32)
128
+ return obs, {}
129
+
130
+ def step(self, action):
131
+ self.step_count += 1
132
+
133
+ # Apply action to modify molecule
134
+ reward = self._calculate_reward()
135
+ terminated = self.step_count >= self.max_atoms
136
+ truncated = False
137
+ obs = self._get_observation()
138
+
139
+ return obs, reward, terminated, truncated, {}
140
+
141
+ def _calculate_reward(self):
142
+ """Calculate reward based on molecular properties."""
143
+ if self.current_mol is None:
144
+ return 0.0
145
+ # Placeholder: QED score
146
+ return np.random.uniform(0, 1)
147
+
148
+ def _get_observation(self):
149
+ return np.zeros(2048, dtype=np.float32)
150
+
151
+
152
+ def train_molecule_designer(total_timesteps=50_000):
153
+ """分子設計 RL エージェント訓練。"""
154
+ env = MoleculeDesignEnv()
155
+ model = PPO("MlpPolicy", env, verbose=1, learning_rate=1e-4)
156
+ model.learn(total_timesteps=total_timesteps)
157
+
158
+ mean_reward, std_reward = evaluate_policy(model, env, n_eval_episodes=10)
159
+ print(f"Molecule Designer: reward = {mean_reward:.2f} ± {std_reward:.2f}")
160
+ return model
161
+ ```
162
+
163
+ ## 3. PufferLib 大規模マルチエージェント
164
+
165
+ ```python
166
+ def setup_pufferlib_training(env_name, num_agents=8, algorithm="PPO"):
167
+ """
168
+ PufferLib マルチエージェント RL 設定。
169
+
170
+ Parameters:
171
+ env_name: str — PufferLib 対応環境
172
+ num_agents: int — エージェント数
173
+ algorithm: str — "PPO", "IMPALA"
174
+
175
+ K-Dense: pufferlib — Scalable multi-agent RL
176
+ """
177
+ try:
178
+ import pufferlib
179
+ import pufferlib.environments
180
+
181
+ config = {
182
+ "env": env_name,
183
+ "num_agents": num_agents,
184
+ "algorithm": algorithm,
185
+ "total_timesteps": 1_000_000,
186
+ "batch_size": 256,
187
+ "learning_rate": 2.5e-4,
188
+ "num_envs": 16,
189
+ "num_steps": 128,
190
+ }
191
+ print(f"PufferLib config: {config}")
192
+ return config
193
+
194
+ except ImportError:
195
+ print("PufferLib not installed. Install with: pip install pufferlib")
196
+ return None
197
+ ```
198
+
199
+ ## 4. 実験パラメータ逐次最適化
200
+
201
+ ```python
202
+ def rl_experiment_optimizer(parameter_ranges, objective_fn,
203
+ total_episodes=100, algorithm="PPO"):
204
+ """
205
+ RL による実験パラメータ逐次最適化。
206
+
207
+ Parameters:
208
+ parameter_ranges: dict — {param_name: (min, max)}
209
+ objective_fn: callable — 目的関数 (params → score)
210
+ total_episodes: int — 最適化エピソード数
211
+ """
212
+ n_params = len(parameter_ranges)
213
+ param_names = list(parameter_ranges.keys())
214
+
215
+ class ExperimentEnv(gym.Env):
216
+ def __init__(self):
217
+ super().__init__()
218
+ self.action_space = gym.spaces.Box(
219
+ low=-1, high=1, shape=(n_params,), dtype=np.float32,
220
+ )
221
+ self.observation_space = gym.spaces.Box(
222
+ low=-np.inf, high=np.inf,
223
+ shape=(n_params + 1,), dtype=np.float32,
224
+ )
225
+ self.best_score = -np.inf
226
+ self.history = []
227
+
228
+ def reset(self, seed=None, options=None):
229
+ super().reset(seed=seed)
230
+ self.current_params = np.zeros(n_params, dtype=np.float32)
231
+ return np.zeros(n_params + 1, dtype=np.float32), {}
232
+
233
+ def step(self, action):
234
+ # Scale action to parameter ranges
235
+ params = {}
236
+ for i, name in enumerate(param_names):
237
+ lo, hi = parameter_ranges[name]
238
+ params[name] = lo + (action[i] + 1) / 2 * (hi - lo)
239
+
240
+ score = objective_fn(params)
241
+ self.history.append({"params": params, "score": score})
242
+
243
+ if score > self.best_score:
244
+ self.best_score = score
245
+
246
+ obs = np.append(action, [score]).astype(np.float32)
247
+ return obs, score, False, False, {}
248
+
249
+ env = ExperimentEnv()
250
+ model = SAC("MlpPolicy", env, verbose=0) if algorithm == "SAC" else PPO("MlpPolicy", env, verbose=0)
251
+ model.learn(total_timesteps=total_episodes)
252
+
253
+ best_idx = max(range(len(env.history)), key=lambda i: env.history[i]["score"])
254
+ best = env.history[best_idx]
255
+ print(f"RL Optimization: best score = {best['score']:.4f}")
256
+ print(f" Best params: {best['params']}")
257
+ return best, env.history
258
+ ```
259
+
260
+ ---
261
+
262
+ ## パイプライン出力
263
+
264
+ | 出力ファイル | 説明 | 連携先スキル |
265
+ |---|---|---|
266
+ | `models/rl_model.zip` | 訓練済み RL モデル | → deep-learning (モデル統合) |
267
+ | `results/rl_training_log.json` | 訓練曲線・メトリクス | → publication-figures |
268
+ | `results/rl_optimization.json` | 最適化パラメータ | → doe, process-optimization |
269
+ | `figures/rl_reward_curve.png` | 報酬曲線 | → presentation-design |
270
+
271
+ ## パイプライン統合
272
+
273
+ ```
274
+ doe ──→ reinforcement-learning ──→ lab-automation
275
+ (実験計画) (逐次最適化) (ロボット制御)
276
+
277
+ ├──→ drug-target-profiling (分子設計 RL)
278
+ ├──→ protein-design (構造最適化 RL)
279
+ └──→ deep-learning (DRL パイプライン)
280
+ ```