chore: track worktree checkout, lightweight extension staging and wgs manifests

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
sj
2026-08-21 11:49:48 +08:00
co-authored by Claude Opus 5
parent c59f346037
commit 8985f5cbdd
499 changed files with 515945 additions and 0 deletions
+53
View File
@@ -0,0 +1,53 @@
# LLM API Keys
ZHIPUAI_API_KEY=
MINIMAX_API_KEY=
MOONSHOT_API_KEY=
DEEPSEEK_API_KEY=
DASHSCOPE_API_KEY=
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/genefamily
REDIS_URL=redis://localhost:6379/0
# Vector DB
VECTOR_DB_TYPE=qdrant
QDRANT_URL=http://localhost:6333
# Log Level
LOG_LEVEL=INFO
ENVIRONMENT=development
# Project runtime
BBAV5_PROJECT_ROOT=/home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev
BBAV5_CONDA_BASE=/home/xzq/miniconda3
BBAV5_DEFAULT_ENV=test4py311
BBAV5_GFPY_ENV=gfpy312
BBAV5_RNASEQ_ENV=rnaseq
BBAV5_RNAR_ENV=rnaR
BBAV5_QUEUE_PREFIX=plantai_dev_7880
BBAV5_REDIS_URL=redis://localhost:6379/8
BBAV5_INTERPROSCAN_TMP_ROOT=/tmp/interproscan
PLANTAI_MAIN_AGENT_MAX_TOOL_CALLS=10
PLANTAI_AGENT_STATE_DB=workspace/.agent_state/agent-state.sqlite3
WGS_BCFTOOLS=
WGS_BEAGLE_JAR=
# gene-family-mas-v2 RAG/QA integration
# QA: /api/v1/kb-qa/chat; graph subgraph: /api/v1/v15-graph-qa/chat.
GENE_FAMILY_MAS_API=http://127.0.0.1:8000
DUAL_KB_QA_ROUTE=kb-qa
DUAL_KB_GRAPH_QA_ROUTE=v15-graph-qa
METHODOLOGY_RAG_API=http://127.0.0.1:8000/api/v1
# PlantCARE promoter stage
PLANTCARE_IMAP_SERVER=imap.qq.com
PLANTCARE_IMAP_PORT=993
PLANTCARE_EMAIL_ACCOUNT=
PLANTCARE_EMAIL_PASSWORD=
# Optional external integrations
# GF_MAS_ROOT=/home/xzq/gene-family-mas-v2
# PLANTAI_RAG_ROOT=/home/xzq/PlantAI-rag
ATH_REF_DATA_DIR=/home/xzq/wutx/data/raw_genome/ath
ATH_FAMILY_ROOT=/home/xzq/wutx/data/raw_genome/ath_family
PLANTAI_REF_DATA_ROOT=/home/xzq/wutx/data/raw_genome
+216
View File
@@ -0,0 +1,216 @@
# BBAV20311 Open Source .gitignore
# Strategy: Only Agent system is open-sourced
# ============================================================================
# CLOSED-SOURCE COMPONENTS - DO NOT COMMIT
# ============================================================================
# Analysis scripts (based on course materials)
apps/cli/
scripts/
gfa_core/tools/
# Local data directories
input/
workspace/
output/
logs/
*.log
# Bioinformatics data files
*.fa
*.fasta
*.fna
*.faa
*.gff
*.gff3
*.gtf
*.bed
*.vcf
*.bam
*.sam
*.cram
# HMM and BLAST databases
*.hmm
*.h3f
*.h3i
*.h3m
*.h3p
*.phr
*.pin
*.pog
*.psd
*.psi
*.psq
*.ptf
*.pto
# ============================================================================
# PYTHON
# ============================================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
# Distribution / packaging
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# ============================================================================
# IDE
# ============================================================================
# PyCharm
.idea/
*.iml
*.iws
*.ipr
# VSCode
.vscode/
*.code-workspace
# Sublime Text
*.sublime-project
*.sublime-workspace
# Vim
*.swp
*.swo
*~
# Emacs
*~
\#*\#
.\#*
# ============================================================================
# OS
# ============================================================================
# macOS
.DS_Store
.AppleDouble
.LSOverride
# Windows
Thumbs.db
ehthumbs.db
Desktop.ini
$RECYCLE.BIN/
# Linux
*~
.nfs*
# ============================================================================
# PROJECT SPECIFIC
# ============================================================================
# Configuration with sensitive data
config/api_keys.yaml
config/secrets.yaml
# Database
*.db
*.sqlite
*.sqlite3
# Temporary files
tmp/
temp/
*.tmp
# Large files
*.tar.gz
*.zip
*.rar
*.7z
# Model files
*.pkl
*.pth
*.h5
*.onnx
*.pb
# Documentation builds
docs/_build/
docs/_static/
docs/_templates/
+41
View File
@@ -0,0 +1,41 @@
{
"project": "bbav20311",
"revision_start": "2026-04-12T02:39:00",
"current_status": "completed",
"revision_phase": "multi_stage_testing_complete",
"last_action": "completed_motif_stage",
"job_id": "job_1775900738746",
"completed_stages": ["identify", "phylogeny", "motif"],
"running_stages": [],
"pending_stages": ["domain", "structure", "promoter", "synteny"],
"test_results": {
"identify": {
"status": "completed",
"members": 24,
"elapsed": 37,
"verified": true
},
"phylogeny": {
"status": "completed",
"elapsed": 172,
"files_generated": ["Ft.SPL.tree.nwk", "Ft.SPL.phylogeny_report.md"],
"verified": true
},
"motif": {
"status": "completed",
"elapsed": 47,
"images_generated": ["Ft.SPL.motif.png", "Ft.SPL.motif.tree_motif.png"],
"verified": true
}
},
"verification": {
"multi_stage_workflow": "verified",
"identify_stage": "verified",
"phylogeny_stage": "verified",
"motif_stage": "verified",
"same_job_reuse": "verified",
"stage_dependency_check": "verified"
},
"final_status": "All core stages tested successfully. Multi-stage workflow verified.",
"next_phase": "documentation_and_summary"
}
Binary file not shown.
@@ -0,0 +1,8 @@
>seq1
MKTAYIAKQRQISFVKSHFSRQDILDLWIYHTQGYFPDWQNY
>seq2
MKTAYIAKQRQISFVKSHFSRQDILDLWIYHTQGYFPDWQNY
>seq3
MKTAYIAKQRQISFVKSHFSRQDILDLWIYHTQGYFPDWQNY
>seq4
MKTAYIAKQRQISFVKSHFSRQDILDLWIYHTQGYFPDWQNY
View File
+96
View File
@@ -0,0 +1,96 @@
# AGENTS.md - bbav5 基因家族分析执行系统
## 项目定位
**执行型 Agent** - 运行基因家族分析流程,调用 run_*.py 脚本
## 分析阶段速查
### 核心阶段 (13个)
| 阶段 | 脚本 | 功能 | 环境 |
|------|------|------|------|
| identify | run_identify.py | 基因鉴定 | test4py311 |
| phylogeny | run_phylogeny.py | 系统发育树 | test4py311 |
| motif | run_motif.py | MEME motif | test4py311 |
| domain | run_domain.py | Pfam结构域 | test4py311 |
| structure | run_structure.py | 基因结构 | test4py311 |
| promoter | run_promoter.py | 启动子分析 | test4py311 |
| synteny | run_synteny.py | 种内共线性 | test4py311 |
| interspecies_synteny | run_interspecies_synteny.py | 种间共线性 | test4py311 |
| karyotype | run_karyotype.py | 核型图 | test4py311 |
| combo | run_combo.py | 组合图 | test4py311 |
| ppi | run_ppi.py | 蛋白互作 | test4py311 |
| expression | run_expression.py | 表达分析 | **rnaR** |
| pep | run_pep.py | PEP分析 | test4py311 |
### RNA-seq 流水线 (5个)
| 阶段 | 脚本 | 功能 | 环境 |
|------|------|------|------|
| rnaseq_qc | run_rnaseq_qc.py | 质控 | **rnaseq** |
| rnaseq_align | run_rnaseq_align.py | 比对 | **rnaseq** |
| rnaseq_quant | run_rnaseq_quant.py | 定量 | **rnaseq** |
| rnaseq_de | run_rnaseq_de.py | 差异表达 | **rnaseq** |
| rnaseq_enrich | run_rnaseq_enrich_v2.py | 富集分析 | **rnaseq** |
### 辅助阶段 (9个,无契约)
genome_prepare_v2, kaks_v2, ortholog, cis_element_http, fetch_expression, tree_plot, ppi_v2, ppi_v2_with_repro, summary
## 执行流程
1. **识别意图** → 确定目标阶段
2. **检查输入** → 验证契约文件存在 (input/ 或 final/)
3. **执行脚本** → `python apps/cli/run_*.py` 或调用 Skills
4. **验证输出** → 检查 final/ 目录产物 + Manifest
5. **报告结果** → artifacts 列表 + metrics 摘要
## Conda 环境 [关键]
| 环境名 | 用途 | 激活命令 |
|--------|------|----------|
| test4py311 | 标准分析 | `conda activate test4py311` |
| rnaseq | RNA-seq流程 | `conda activate rnaseq` |
| rnaR | 表达绘图 | `conda activate rnaR` |
**注意**: expression阶段用rnaR,其他绘图用test4py311
## 关键目录
| 目录 | 内容 |
|------|------|
| `apps/cli/` | 27个 run_*.py 脚本 |
| `gfa_core/schemas/stages/` | 18个契约文件 *_contract_v1.md |
| `skills/` | 技能封装 |
| `scripts/` | R绘图脚本 |
## Manifest 结构
```json
{
"manifest_version": "1.0",
"stage": "identify",
"status": "success",
"prefix": "Ft.SPL",
"artifacts": { "key": {"path": "final/...", "type": "fasta"} },
"metrics": { ... }
}
```
## 工作原则
- **契约优先**: 有契约的阶段执行前检查输入,执行后验证输出
- **Manifest记录**: 每次执行生成完整 Manifest
- **可复现性**: reproducibility_v2.py 确保分析可追溯
- **错误诊断**: 失败时读错误日志,给具体修复建议
## 常用命令
```bash
# 运行鉴定阶段
python apps/cli/run_identify.py --prefix Ft.SPL --workspace ~/test_workspace
# 启动前端服务
python apps/web/vue3/main.py
```
+240
View File
@@ -0,0 +1,240 @@
# bbav5 分析流程代码依赖分析
## 以"进化树分析"为例,串完整流程
### 阶段1: 前端调用
```
用户点击"进化树分析"按钮
↓
Vue3 前端 → POST /api/execute (stage="phylogeny")
↓
apps/web/vue3/main.py → execute_stage()
```
**必须保留:**
- `apps/web/vue3/main.py` - FastAPI 主入口
- `apps/web/vue3/index.html` - Vue3 前端页面
---
### 阶段2: API 层处理
```
apps/web/vue3/main.py
↓
检查 stage 是否在 ASYNC_STAGES 中
↓
调用 run_stage_sync() 或同步执行
↓
from apps.web.pipeline_backend import run_stage, JobInfo
```
**必须保留:**
- `apps/web/vue3/main.py` - API 端点定义
- `apps/web/pipeline_backend.py` - 后端 pipeline 核心
---
### 阶段3: Pipeline 后端
```
apps/web/pipeline_backend.py → run_stage()
↓
stage == "phylogeny"
↓
导入 apps/cli/run_phylogeny.py
↓
构建命令行参数
↓
subprocess 执行
```
**必须保留:**
- `apps/web/pipeline_backend.py` - stage 路由和参数处理
- `apps/cli/run_phylogeny.py` - 进化树分析脚本
---
### 阶段4: 分析脚本执行
```
apps/cli/run_phylogeny.py
↓
1. 读取 input/{job_id}/Ft.SPL.final_members.pep.fa
2. 运行 MAFFT 多序列比对
3. 运行 IQ-TREE 建树
4. 生成输出到 workspace/{job_id}/final/
- Ft.SPL.pep.msa.fa
- Ft.SPL.tree.nwk
- Ft.SPL.phylogeny_report.md
- Ft.SPL.phylogeny.manifest.json
```
**必须保留:**
- `apps/cli/run_phylogeny.py` - 进化树分析
- `apps/cli/run_identify.py` - 基因家族鉴定(前置依赖)
- `apps/cli/run_motif.py` - Motif分析
- `apps/cli/run_domain.py` - 结构域分析
- `apps/cli/run_structure.py` - 基因结构
- `apps/cli/run_promoter.py` - 启动子分析
- `apps/cli/run_synteny.py` - 共线性分析
- `apps/cli/run_karyotype.py` - 核型分析
- `apps/cli/run_expression.py` - 表达分析
- `apps/cli/run_pep.py` - 蛋白特征
- `apps/cli/run_*.py` - 其他分析脚本
---
### 阶段5: 依赖的 gfa_core 模块
```
apps/cli/run_phylogeny.py
↓
from gfa_core.api_clients import ...
from gfa_core.reproducibility_v2 import ReproducibilityManager
```
**必须保留:**
- `gfa_core/api_clients.py` - API客户端(PlantCARE等)
- `gfa_core/reproducibility_v2.py` - 可复现性管理
- `gfa_core/pipelines/*.py` - pipeline 工具函数
---
### 阶段6: Agent 系统(LangGraph 迁移目标)
```
用户自然语言输入
↓
Orchestrator (LangGraph)
↓
RouterAgent → PlanningAgent → ExecutionAgent
↓
调用 apps/cli/run_*.py
```
**必须保留(迁移到 LangGraph):**
- `gfa_core/mas/agents/*.py` - 9个Agent
- `base.py` - Agent 基类
- `router.py` - 意图路由
- `planning.py` - 任务规划
- `execution.py` - 任务执行
- `knowledge.py` - 知识检索
- `diagnosis.py` - 错误诊断
- `validator.py` - 结果验证
- `result_parser.py` - 结果解析
- `learning.py` - 学习优化
- `discovery.py` - 科学发现
- `gfa_core/mas/core/orchestrator.py` - 编排器(参考代码)
- `gfa_core/mas/llm/` - LLM管理
- `gfa_core/mas/tools/` - 工具注册
- `gfa_core/mas/cost_tracker.py` - 成本追踪
---
### 阶段7: Skills 系统
```
apps/cli/run_*.py
↓
skills/{stage}/run.py
```
**必须保留:**
- `skills/*/run.py` - 各阶段技能实现
- `skills/*/templates/` - 报告模板
---
### 阶段8: 配置文件
```
加载配置
↓
config/
prompts/
```
**必须保留:**
- `config/` - 配置文件
- `prompts/` - Agent 提示词
- `.env` - 环境变量
---
## 必须保留的文件类型总结
### 1. 前端层
- `apps/web/vue3/main.py` - FastAPI
- `apps/web/vue3/index.html` - Vue3
- `apps/web/pipeline_backend.py` - Pipeline后端
### 2. CLI 分析脚本(11个阶段)
- `apps/cli/run_identify.py`
- `apps/cli/run_phylogeny.py`
- `apps/cli/run_motif.py`
- `apps/cli/run_domain.py`
- `apps/cli/run_structure.py`
- `apps/cli/run_promoter.py`
- `apps/cli/run_synteny.py`
- `apps/cli/run_karyotype.py`
- `apps/cli/run_pep.py`
- `apps/cli/run_expression.py`
- `apps/cli/run_*.py` (其他)
### 3. Agent 系统(LangGraph 迁移)
- `gfa_core/mas/agents/*.py` (9个Agent)
- `gfa_core/mas/core/*.py`
- `gfa_core/mas/llm/*.py`
- `gfa_core/mas/tools/*.py`
### 4. 核心模块
- `gfa_core/api_clients.py`
- `gfa_core/reproducibility_v2.py`
- `gfa_core/pipelines/*.py`
### 5. Skills
- `skills/*/` - 所有技能目录
### 6. 配置
- `config/`
- `prompts/`
- `.env`
### 7. 微信集成(确认保留)
- `wechat_*.py`
---
## 可以删除的文件类型(待确认)
### 1. 测试文件
- `test_*.py` (26个)
### 2. Demo 文件
- `demo_*.py`
### 3. 旧 RAG 实现
- `kb/` 目录
- `langchain_agent.py`
### 4. 备份文件
- `backup/` 目录
- `*.backup.*`
- `*.bak`
### 5. 日志和临时文件
- `*.log` (非必要)
- `__pycache__/`
- `*.pyc`
### 6. 文档和报告
- `REVISION_*.md`
- `e2e_test_report.md`
- `EXECUTION_LOG.md`
- `项目记录/` (确认是否保留)
---
## 待确认问题
1. **test_*.py** - 是否全部删除?还是保留部分核心测试?
2. **kb/** - 旧 RAG 实现,是否删除?(gene-family-mas-v2 已替代)
3. **langchain_agent.py** - 实验性代码,是否删除?
4. **项目记录/** - 历史文档,是否保留?
5. **REVISION_*.md** - 修订记录,是否保留?
6. **codeMiaoshu/** - 代码描述,是否保留?
7. **paper/** - 文献 PDF,是否保留?
@@ -0,0 +1,49 @@
locus_id short_name subfamily planttfdb_common_name planttfdb_description
AT1G05230 HDG2 HD-ZIP IV HDG2, HDGL2-2, YUP8H12.16 homeodomain GLABROUS 2
AT1G17920 HDG12 HD-ZIP IV F2H15.14, HDG12, HDGL2-12 homeodomain GLABROUS 12
AT1G26960 AtHB23 HD-ZIP I AtHB23, ATHB-23, HB23, T2P11.15 homeobox protein 23
AT1G27045 AtHB54 HD-ZIP I ATHB54, ATHB-54, HB54, T7N9.11 HD-ZIP family protein
AT1G30490 PHV/AtHB9 HD-ZIP III ATHB9, ATHB-9, F26G16.11, HB9, PHV HD-ZIP family protein
AT1G34650 HDG10 HD-ZIP IV F12K21.1, F21H2.11, HDG10, HDGL2-10 homeodomain GLABROUS 10
AT1G52150 CNA/AtHB15 HD-ZIP III ATHB15, ATHB-15, CNA, F5F19.21, F9I5.18, ICU4 HD-ZIP family protein
AT1G69780 AtHB13 HD-ZIP I ATHB13, ATHB-13, T6C23.2 HD-ZIP family protein
AT1G70920 AtHB18 HD-ZIP II ATHB18, ATHB-X, F15H11_25, HB18 homeobox-leucine zipper protein 18
AT1G73360 HDG11 HD-ZIP IV AtEDT1, ATHDG11, EDT1, HDG11, HDGL2-11, T9L24.43 homeodomain GLABROUS 11
AT1G79840 GL2 HD-ZIP IV ATHB10, F19K16.20, GL2 HD-ZIP family protein
AT2G01430 AtHB17 HD-ZIP II ATHB17, ATHB-17, F2I9.5, HB17 homeobox-leucine zipper protein 17
AT2G18550 AtHB21 HD-ZIP I ATHB21, ATHB-21, F24H14.10, HB-2, HB21 homeobox protein 21
AT2G22430 AtHB6 HD-ZIP I ATHB6, ATHB-6, F14M13.17, HB6 homeobox protein 6
AT2G22800 HAT9 HD-ZIP II HAT9, T20K9.1, T30L20.6 HD-ZIP family protein
AT2G32370 HDG3 HD-ZIP IV HDG3, HDGL2-3, T32F6.11, UCL1 homeodomain GLABROUS 3
AT2G34710 PHB/AtHB14 HD-ZIP III ATHB14, ATHB-14, PHB, PHB-1D, T29F13.8 HD-ZIP family protein
AT2G36610 AtHB22 HD-ZIP I ATHB22, ATHB-22, F13K3.1, F1O11.24, HB22 homeobox protein 22
AT2G44910 AtHB4 HD-ZIP II ATHB4, ATHB-4, HB4, T13E15.8 homeobox-leucine zipper protein 4
AT2G46680 AtHB7 HD-ZIP I ATHB7, ATHB-7, HB-7, T3A4.6 homeobox 7
AT3G01220 AtHB20 HD-ZIP I ATHB20, ATHB-20, HB20, T4P13.9 homeobox protein 20
AT3G01470 AtHB1/HAT5 HD-ZIP I ATHB1, ATHB-1, F4P13.2, HAT5, HB-1, HD-ZIP-1 homeobox 1
AT3G03260 HDG8 HD-ZIP IV HDG8, HDGL2-8, T17B22.5 homeodomain GLABROUS 8
AT3G60390 HAT3 HD-ZIP II HAT3, T8B10_50 homeobox-leucine zipper protein 3
AT3G61150 HDG1 HD-ZIP IV HDG1, HD-GL2-1, HDGL2-1, T20K12.50 homeodomain GLABROUS 1
AT3G61890 AtHB12 HD-ZIP I ATHB12, ATHB-12, F21F14.60, HB-12 homeobox 12
AT4G00730 ANL2 HD-ZIP IV AHDP, ANL2, F6N23.10 HD-ZIP family protein
AT4G04890 PDF2 HD-ZIP IV PDF2, T1J1.3 protodermal factor 2
AT4G16780 AtHB2/HAT4 HD-ZIP II ATHB2, ATHB-2, dl4415w, FCAALL.101, HAT4, HB-2 homeobox protein 2
AT4G17460 HAT1 HD-ZIP II dl4765w, FCAALL.65, HAT1, JAB Homeobox-leucine zipper protein 4 (HB-4) / HD-ZIP protein
AT4G17710 HDG4 HD-ZIP IV dl4890c, FCAALL.102, HDG4, HDGL2-4 homeodomain GLABROUS 4
AT4G21750 ATML1 HD-ZIP IV ATML1, F17L22.210 HD-ZIP family protein
AT4G25530 FWA/HDG6 HD-ZIP IV FWA, HDG6, HDGL2-6, M7J2.100 FLOWERING WAGENINGEN
AT4G32880 AtHB8 HD-ZIP III ATHB8, ATHB-8, HB8, HB-8, T16I18.90 homeobox gene 8
AT4G36740 AtHB40 HD-ZIP I ATHB40, ATHB-40, C7A10.620, HB40, HB-5 homeobox protein 40
AT4G37790 HAT22 HD-ZIP II HAT22, T28I19.70 HD-ZIP family protein
AT4G40060 AtHB16 HD-ZIP I ATHB16, ATHB-16, HB16, T5J17.230 homeobox protein 16
AT5G03790 AtHB51 HD-ZIP I ATHB51, ATHB-51, F17C15_210, HB51, LMI1, MED24.8 homeobox 51
AT5G06710 HAT14 HD-ZIP II HAT14, MPH15.6 homeobox from Arabidopsis thaliana
AT5G15150 AtHB3/HAT7 HD-ZIP I ATHB3, ATHB-3, F8M21_40, HAT7, HB-3 homeobox 3
AT5G17320 HDG9 HD-ZIP IV HDG9, HDGL2-9, MKP11.28 homeodomain GLABROUS 9
AT5G46880 HDG5 HD-ZIP IV HB-7, HDG5, HDGL2-5, MQD22.1 homeobox-7
AT5G47370 HAT2 HD-ZIP II HAT2, MQL5.23 Homeobox-leucine zipper protein 4 (HB-4) / HD-ZIP protein
AT5G52170 HDG7 HD-ZIP IV F17P19.7, HDG7, HDGL2-7 homeodomain GLABROUS 7
AT5G53980 AtHB52 HD-ZIP I ATHB52, ATHB-52, HB52, K19P17.15 homeobox protein 52
AT5G60690 REV/IFL1 HD-ZIP III AVB1, IFL, IFL1, MUP24.16, REV HD-ZIP family protein
AT5G65310 AtHB5 HD-ZIP I ATHB5, ATHB-5, HB5, MNA5.4 homeobox protein 5
AT5G66700 AtHB53 HD-ZIP I ATHB53, ATHB-53, HB53, HB-8, MSN2.9 homeobox 53
1 locus_id short_name subfamily planttfdb_common_name planttfdb_description
2 AT1G05230 HDG2 HD-ZIP IV HDG2, HDGL2-2, YUP8H12.16 homeodomain GLABROUS 2
3 AT1G17920 HDG12 HD-ZIP IV F2H15.14, HDG12, HDGL2-12 homeodomain GLABROUS 12
4 AT1G26960 AtHB23 HD-ZIP I AtHB23, ATHB-23, HB23, T2P11.15 homeobox protein 23
5 AT1G27045 AtHB54 HD-ZIP I ATHB54, ATHB-54, HB54, T7N9.11 HD-ZIP family protein
6 AT1G30490 PHV/AtHB9 HD-ZIP III ATHB9, ATHB-9, F26G16.11, HB9, PHV HD-ZIP family protein
7 AT1G34650 HDG10 HD-ZIP IV F12K21.1, F21H2.11, HDG10, HDGL2-10 homeodomain GLABROUS 10
8 AT1G52150 CNA/AtHB15 HD-ZIP III ATHB15, ATHB-15, CNA, F5F19.21, F9I5.18, ICU4 HD-ZIP family protein
9 AT1G69780 AtHB13 HD-ZIP I ATHB13, ATHB-13, T6C23.2 HD-ZIP family protein
10 AT1G70920 AtHB18 HD-ZIP II ATHB18, ATHB-X, F15H11_25, HB18 homeobox-leucine zipper protein 18
11 AT1G73360 HDG11 HD-ZIP IV AtEDT1, ATHDG11, EDT1, HDG11, HDGL2-11, T9L24.43 homeodomain GLABROUS 11
12 AT1G79840 GL2 HD-ZIP IV ATHB10, F19K16.20, GL2 HD-ZIP family protein
13 AT2G01430 AtHB17 HD-ZIP II ATHB17, ATHB-17, F2I9.5, HB17 homeobox-leucine zipper protein 17
14 AT2G18550 AtHB21 HD-ZIP I ATHB21, ATHB-21, F24H14.10, HB-2, HB21 homeobox protein 21
15 AT2G22430 AtHB6 HD-ZIP I ATHB6, ATHB-6, F14M13.17, HB6 homeobox protein 6
16 AT2G22800 HAT9 HD-ZIP II HAT9, T20K9.1, T30L20.6 HD-ZIP family protein
17 AT2G32370 HDG3 HD-ZIP IV HDG3, HDGL2-3, T32F6.11, UCL1 homeodomain GLABROUS 3
18 AT2G34710 PHB/AtHB14 HD-ZIP III ATHB14, ATHB-14, PHB, PHB-1D, T29F13.8 HD-ZIP family protein
19 AT2G36610 AtHB22 HD-ZIP I ATHB22, ATHB-22, F13K3.1, F1O11.24, HB22 homeobox protein 22
20 AT2G44910 AtHB4 HD-ZIP II ATHB4, ATHB-4, HB4, T13E15.8 homeobox-leucine zipper protein 4
21 AT2G46680 AtHB7 HD-ZIP I ATHB7, ATHB-7, HB-7, T3A4.6 homeobox 7
22 AT3G01220 AtHB20 HD-ZIP I ATHB20, ATHB-20, HB20, T4P13.9 homeobox protein 20
23 AT3G01470 AtHB1/HAT5 HD-ZIP I ATHB1, ATHB-1, F4P13.2, HAT5, HB-1, HD-ZIP-1 homeobox 1
24 AT3G03260 HDG8 HD-ZIP IV HDG8, HDGL2-8, T17B22.5 homeodomain GLABROUS 8
25 AT3G60390 HAT3 HD-ZIP II HAT3, T8B10_50 homeobox-leucine zipper protein 3
26 AT3G61150 HDG1 HD-ZIP IV HDG1, HD-GL2-1, HDGL2-1, T20K12.50 homeodomain GLABROUS 1
27 AT3G61890 AtHB12 HD-ZIP I ATHB12, ATHB-12, F21F14.60, HB-12 homeobox 12
28 AT4G00730 ANL2 HD-ZIP IV AHDP, ANL2, F6N23.10 HD-ZIP family protein
29 AT4G04890 PDF2 HD-ZIP IV PDF2, T1J1.3 protodermal factor 2
30 AT4G16780 AtHB2/HAT4 HD-ZIP II ATHB2, ATHB-2, dl4415w, FCAALL.101, HAT4, HB-2 homeobox protein 2
31 AT4G17460 HAT1 HD-ZIP II dl4765w, FCAALL.65, HAT1, JAB Homeobox-leucine zipper protein 4 (HB-4) / HD-ZIP protein
32 AT4G17710 HDG4 HD-ZIP IV dl4890c, FCAALL.102, HDG4, HDGL2-4 homeodomain GLABROUS 4
33 AT4G21750 ATML1 HD-ZIP IV ATML1, F17L22.210 HD-ZIP family protein
34 AT4G25530 FWA/HDG6 HD-ZIP IV FWA, HDG6, HDGL2-6, M7J2.100 FLOWERING WAGENINGEN
35 AT4G32880 AtHB8 HD-ZIP III ATHB8, ATHB-8, HB8, HB-8, T16I18.90 homeobox gene 8
36 AT4G36740 AtHB40 HD-ZIP I ATHB40, ATHB-40, C7A10.620, HB40, HB-5 homeobox protein 40
37 AT4G37790 HAT22 HD-ZIP II HAT22, T28I19.70 HD-ZIP family protein
38 AT4G40060 AtHB16 HD-ZIP I ATHB16, ATHB-16, HB16, T5J17.230 homeobox protein 16
39 AT5G03790 AtHB51 HD-ZIP I ATHB51, ATHB-51, F17C15_210, HB51, LMI1, MED24.8 homeobox 51
40 AT5G06710 HAT14 HD-ZIP II HAT14, MPH15.6 homeobox from Arabidopsis thaliana
41 AT5G15150 AtHB3/HAT7 HD-ZIP I ATHB3, ATHB-3, F8M21_40, HAT7, HB-3 homeobox 3
42 AT5G17320 HDG9 HD-ZIP IV HDG9, HDGL2-9, MKP11.28 homeodomain GLABROUS 9
43 AT5G46880 HDG5 HD-ZIP IV HB-7, HDG5, HDGL2-5, MQD22.1 homeobox-7
44 AT5G47370 HAT2 HD-ZIP II HAT2, MQL5.23 Homeobox-leucine zipper protein 4 (HB-4) / HD-ZIP protein
45 AT5G52170 HDG7 HD-ZIP IV F17P19.7, HDG7, HDGL2-7 homeodomain GLABROUS 7
46 AT5G53980 AtHB52 HD-ZIP I ATHB52, ATHB-52, HB52, K19P17.15 homeobox protein 52
47 AT5G60690 REV/IFL1 HD-ZIP III AVB1, IFL, IFL1, MUP24.16, REV HD-ZIP family protein
48 AT5G65310 AtHB5 HD-ZIP I ATHB5, ATHB-5, HB5, MNA5.4 homeobox protein 5
49 AT5G66700 AtHB53 HD-ZIP I ATHB53, ATHB-53, HB53, HB-8, MSN2.9 homeobox 53
@@ -0,0 +1,59 @@
input_id locus_id short_name subfamily planttfdb_common_name planttfdb_description
AT1G05230.1 AT1G05230 HDG2 HD-ZIP IV HDG2, HDGL2-2, YUP8H12.16 homeodomain GLABROUS 2
AT1G05230.2 AT1G05230 HDG2 HD-ZIP IV HDG2, HDGL2-2, YUP8H12.16 homeodomain GLABROUS 2
AT1G05230.3 AT1G05230 HDG2 HD-ZIP IV HDG2 homeodomain GLABROUS 2
AT1G05230.4 AT1G05230 HDG2 HD-ZIP IV HDG2, HDGL2-2, YUP8H12.16 homeodomain GLABROUS 2
AT1G17920.1 AT1G17920 HDG12 HD-ZIP IV F2H15.14, HDG12, HDGL2-12 homeodomain GLABROUS 12
AT1G26960.1 AT1G26960 AtHB23 HD-ZIP I AtHB23, ATHB-23, HB23, T2P11.15 homeobox protein 23
AT1G27045.1 AT1G27045 AtHB54 HD-ZIP I ATHB54, ATHB-54, HB54, T7N9.11 HD-ZIP family protein
AT1G30490.1 AT1G30490 PHV/AtHB9 HD-ZIP III ATHB9, ATHB-9, F26G16.11, HB9, PHV HD-ZIP family protein
AT1G34650.1 AT1G34650 HDG10 HD-ZIP IV F12K21.1, F21H2.11, HDG10, HDGL2-10 homeodomain GLABROUS 10
AT1G52150.1 AT1G52150 CNA/AtHB15 HD-ZIP III ATHB15, ATHB-15, CNA, F5F19.21, F9I5.18, ICU4 HD-ZIP family protein
AT1G52150.2 AT1G52150 CNA/AtHB15 HD-ZIP III ATHB15, ATHB-15, CNA, ICU4 HD-ZIP family protein
AT1G52150.3 AT1G52150 CNA/AtHB15 HD-ZIP III ATHB15, ATHB-15, CNA, ICU4 HD-ZIP family protein
AT1G69780.1 AT1G69780 AtHB13 HD-ZIP I ATHB13, ATHB-13, T6C23.2 HD-ZIP family protein
AT1G70920.1 AT1G70920 AtHB18 HD-ZIP II ATHB18, ATHB-X, F15H11_25, HB18 homeobox-leucine zipper protein 18
AT1G73360.1 AT1G73360 HDG11 HD-ZIP IV AtEDT1, ATHDG11, EDT1, HDG11, HDGL2-11, T9L24.43 homeodomain GLABROUS 11
AT1G79840.1 AT1G79840 GL2 HD-ZIP IV ATHB10, F19K16.20, GL2 HD-ZIP family protein
AT1G79840.2 AT1G79840 GL2 HD-ZIP IV GL2 HD-ZIP family protein
AT2G01430.1 AT2G01430 AtHB17 HD-ZIP II ATHB17, ATHB-17, F2I9.5, HB17 homeobox-leucine zipper protein 17
AT2G18550.1 AT2G18550 AtHB21 HD-ZIP I ATHB21, ATHB-21, F24H14.10, HB-2, HB21 homeobox protein 21
AT2G22430.1 AT2G22430 AtHB6 HD-ZIP I ATHB6, ATHB-6, F14M13.17, HB6 homeobox protein 6
AT2G22800.1 AT2G22800 HAT9 HD-ZIP II HAT9, T20K9.1, T30L20.6 HD-ZIP family protein
AT2G32370.1 AT2G32370 HDG3 HD-ZIP IV HDG3, HDGL2-3, T32F6.11, UCL1 homeodomain GLABROUS 3
AT2G34710.1 AT2G34710 PHB/AtHB14 HD-ZIP III ATHB14, ATHB-14, PHB, PHB-1D, T29F13.8 HD-ZIP family protein
AT2G36610.1 AT2G36610 AtHB22 HD-ZIP I ATHB22, ATHB-22, F13K3.1, F1O11.24, HB22 homeobox protein 22
AT2G44910.1 AT2G44910 AtHB4 HD-ZIP II ATHB4, ATHB-4, HB4, T13E15.8 homeobox-leucine zipper protein 4
AT2G46680.1 AT2G46680 AtHB7 HD-ZIP I ATHB7, ATHB-7, HB-7, T3A4.6 homeobox 7
AT2G46680.2 AT2G46680 AtHB7 HD-ZIP I ATHB7, ATHB-7, HB-7 homeobox 7
AT3G01220.1 AT3G01220 AtHB20 HD-ZIP I ATHB20, ATHB-20, HB20, T4P13.9 homeobox protein 20
AT3G01470.1 AT3G01470 AtHB1/HAT5 HD-ZIP I ATHB1, ATHB-1, F4P13.2, HAT5, HB-1, HD-ZIP-1 homeobox 1
AT3G03260.1 AT3G03260 HDG8 HD-ZIP IV HDG8, HDGL2-8, T17B22.5 homeodomain GLABROUS 8
AT3G60390.1 AT3G60390 HAT3 HD-ZIP II HAT3, T8B10_50 homeobox-leucine zipper protein 3
AT3G61150.1 AT3G61150 HDG1 HD-ZIP IV HDG1, HD-GL2-1, HDGL2-1, T20K12.50 homeodomain GLABROUS 1
AT3G61890.1 AT3G61890 AtHB12 HD-ZIP I ATHB12, ATHB-12, F21F14.60, HB-12 homeobox 12
AT4G00730.1 AT4G00730 ANL2 HD-ZIP IV AHDP, ANL2, F6N23.10 HD-ZIP family protein
AT4G00730.2 AT4G00730 ANL2 HD-ZIP IV AHDP, ANL2 HD-ZIP family protein
AT4G04890.1 AT4G04890 PDF2 HD-ZIP IV PDF2, T1J1.3 protodermal factor 2
AT4G16780.1 AT4G16780 AtHB2/HAT4 HD-ZIP II ATHB2, ATHB-2, dl4415w, FCAALL.101, HAT4, HB-2 homeobox protein 2
AT4G17460.1 AT4G17460 HAT1 HD-ZIP II dl4765w, FCAALL.65, HAT1, JAB Homeobox-leucine zipper protein 4 (HB-4) / HD-ZIP protein
AT4G17710.1 AT4G17710 HDG4 HD-ZIP IV dl4890c, FCAALL.102, HDG4, HDGL2-4 homeodomain GLABROUS 4
AT4G21750.1 AT4G21750 ATML1 HD-ZIP IV ATML1, F17L22.210 HD-ZIP family protein
AT4G21750.2 AT4G21750 ATML1 HD-ZIP IV ATML1, F17L22.210 HD-ZIP family protein
AT4G25530.1 AT4G25530 FWA/HDG6 HD-ZIP IV FWA, HDG6, HDGL2-6, M7J2.100 FLOWERING WAGENINGEN
AT4G32880.1 AT4G32880 AtHB8 HD-ZIP III ATHB8, ATHB-8, HB8, HB-8, T16I18.90 homeobox gene 8
AT4G36740.1 AT4G36740 AtHB40 HD-ZIP I ATHB40, ATHB-40, C7A10.620, HB40, HB-5 homeobox protein 40
AT4G37790.1 AT4G37790 HAT22 HD-ZIP II HAT22, T28I19.70 HD-ZIP family protein
AT4G40060.1 AT4G40060 AtHB16 HD-ZIP I ATHB16, ATHB-16, HB16, T5J17.230 homeobox protein 16
AT5G03790.1 AT5G03790 AtHB51 HD-ZIP I ATHB51, ATHB-51, F17C15_210, HB51, LMI1, MED24.8 homeobox 51
AT5G06710.1 AT5G06710 HAT14 HD-ZIP II HAT14, MPH15.6 homeobox from Arabidopsis thaliana
AT5G15150.1 AT5G15150 AtHB3/HAT7 HD-ZIP I ATHB3, ATHB-3, F8M21_40, HAT7, HB-3 homeobox 3
AT5G17320.1 AT5G17320 HDG9 HD-ZIP IV HDG9, HDGL2-9, MKP11.28 homeodomain GLABROUS 9
AT5G46880.1 AT5G46880 HDG5 HD-ZIP IV HB-7, HDG5, HDGL2-5, MQD22.1 homeobox-7
AT5G47370.1 AT5G47370 HAT2 HD-ZIP II HAT2, MQL5.23 Homeobox-leucine zipper protein 4 (HB-4) / HD-ZIP protein
AT5G52170.1 AT5G52170 HDG7 HD-ZIP IV F17P19.7, HDG7, HDGL2-7 homeodomain GLABROUS 7
AT5G53980.1 AT5G53980 AtHB52 HD-ZIP I ATHB52, ATHB-52, HB52, K19P17.15 homeobox protein 52
AT5G60690.1 AT5G60690 REV/IFL1 HD-ZIP III AVB1, IFL, IFL1, MUP24.16, REV HD-ZIP family protein
AT5G65310.1 AT5G65310 AtHB5 HD-ZIP I ATHB5, ATHB-5, HB5, MNA5.4 homeobox protein 5
AT5G65310.2 AT5G65310 AtHB5 HD-ZIP I ATHB5, ATHB-5, HB5 homeobox protein 5
AT5G66700.1 AT5G66700 AtHB53 HD-ZIP I ATHB53, ATHB-53, HB53, HB-8, MSN2.9 homeobox 53
1 input_id locus_id short_name subfamily planttfdb_common_name planttfdb_description
2 AT1G05230.1 AT1G05230 HDG2 HD-ZIP IV HDG2, HDGL2-2, YUP8H12.16 homeodomain GLABROUS 2
3 AT1G05230.2 AT1G05230 HDG2 HD-ZIP IV HDG2, HDGL2-2, YUP8H12.16 homeodomain GLABROUS 2
4 AT1G05230.3 AT1G05230 HDG2 HD-ZIP IV HDG2 homeodomain GLABROUS 2
5 AT1G05230.4 AT1G05230 HDG2 HD-ZIP IV HDG2, HDGL2-2, YUP8H12.16 homeodomain GLABROUS 2
6 AT1G17920.1 AT1G17920 HDG12 HD-ZIP IV F2H15.14, HDG12, HDGL2-12 homeodomain GLABROUS 12
7 AT1G26960.1 AT1G26960 AtHB23 HD-ZIP I AtHB23, ATHB-23, HB23, T2P11.15 homeobox protein 23
8 AT1G27045.1 AT1G27045 AtHB54 HD-ZIP I ATHB54, ATHB-54, HB54, T7N9.11 HD-ZIP family protein
9 AT1G30490.1 AT1G30490 PHV/AtHB9 HD-ZIP III ATHB9, ATHB-9, F26G16.11, HB9, PHV HD-ZIP family protein
10 AT1G34650.1 AT1G34650 HDG10 HD-ZIP IV F12K21.1, F21H2.11, HDG10, HDGL2-10 homeodomain GLABROUS 10
11 AT1G52150.1 AT1G52150 CNA/AtHB15 HD-ZIP III ATHB15, ATHB-15, CNA, F5F19.21, F9I5.18, ICU4 HD-ZIP family protein
12 AT1G52150.2 AT1G52150 CNA/AtHB15 HD-ZIP III ATHB15, ATHB-15, CNA, ICU4 HD-ZIP family protein
13 AT1G52150.3 AT1G52150 CNA/AtHB15 HD-ZIP III ATHB15, ATHB-15, CNA, ICU4 HD-ZIP family protein
14 AT1G69780.1 AT1G69780 AtHB13 HD-ZIP I ATHB13, ATHB-13, T6C23.2 HD-ZIP family protein
15 AT1G70920.1 AT1G70920 AtHB18 HD-ZIP II ATHB18, ATHB-X, F15H11_25, HB18 homeobox-leucine zipper protein 18
16 AT1G73360.1 AT1G73360 HDG11 HD-ZIP IV AtEDT1, ATHDG11, EDT1, HDG11, HDGL2-11, T9L24.43 homeodomain GLABROUS 11
17 AT1G79840.1 AT1G79840 GL2 HD-ZIP IV ATHB10, F19K16.20, GL2 HD-ZIP family protein
18 AT1G79840.2 AT1G79840 GL2 HD-ZIP IV GL2 HD-ZIP family protein
19 AT2G01430.1 AT2G01430 AtHB17 HD-ZIP II ATHB17, ATHB-17, F2I9.5, HB17 homeobox-leucine zipper protein 17
20 AT2G18550.1 AT2G18550 AtHB21 HD-ZIP I ATHB21, ATHB-21, F24H14.10, HB-2, HB21 homeobox protein 21
21 AT2G22430.1 AT2G22430 AtHB6 HD-ZIP I ATHB6, ATHB-6, F14M13.17, HB6 homeobox protein 6
22 AT2G22800.1 AT2G22800 HAT9 HD-ZIP II HAT9, T20K9.1, T30L20.6 HD-ZIP family protein
23 AT2G32370.1 AT2G32370 HDG3 HD-ZIP IV HDG3, HDGL2-3, T32F6.11, UCL1 homeodomain GLABROUS 3
24 AT2G34710.1 AT2G34710 PHB/AtHB14 HD-ZIP III ATHB14, ATHB-14, PHB, PHB-1D, T29F13.8 HD-ZIP family protein
25 AT2G36610.1 AT2G36610 AtHB22 HD-ZIP I ATHB22, ATHB-22, F13K3.1, F1O11.24, HB22 homeobox protein 22
26 AT2G44910.1 AT2G44910 AtHB4 HD-ZIP II ATHB4, ATHB-4, HB4, T13E15.8 homeobox-leucine zipper protein 4
27 AT2G46680.1 AT2G46680 AtHB7 HD-ZIP I ATHB7, ATHB-7, HB-7, T3A4.6 homeobox 7
28 AT2G46680.2 AT2G46680 AtHB7 HD-ZIP I ATHB7, ATHB-7, HB-7 homeobox 7
29 AT3G01220.1 AT3G01220 AtHB20 HD-ZIP I ATHB20, ATHB-20, HB20, T4P13.9 homeobox protein 20
30 AT3G01470.1 AT3G01470 AtHB1/HAT5 HD-ZIP I ATHB1, ATHB-1, F4P13.2, HAT5, HB-1, HD-ZIP-1 homeobox 1
31 AT3G03260.1 AT3G03260 HDG8 HD-ZIP IV HDG8, HDGL2-8, T17B22.5 homeodomain GLABROUS 8
32 AT3G60390.1 AT3G60390 HAT3 HD-ZIP II HAT3, T8B10_50 homeobox-leucine zipper protein 3
33 AT3G61150.1 AT3G61150 HDG1 HD-ZIP IV HDG1, HD-GL2-1, HDGL2-1, T20K12.50 homeodomain GLABROUS 1
34 AT3G61890.1 AT3G61890 AtHB12 HD-ZIP I ATHB12, ATHB-12, F21F14.60, HB-12 homeobox 12
35 AT4G00730.1 AT4G00730 ANL2 HD-ZIP IV AHDP, ANL2, F6N23.10 HD-ZIP family protein
36 AT4G00730.2 AT4G00730 ANL2 HD-ZIP IV AHDP, ANL2 HD-ZIP family protein
37 AT4G04890.1 AT4G04890 PDF2 HD-ZIP IV PDF2, T1J1.3 protodermal factor 2
38 AT4G16780.1 AT4G16780 AtHB2/HAT4 HD-ZIP II ATHB2, ATHB-2, dl4415w, FCAALL.101, HAT4, HB-2 homeobox protein 2
39 AT4G17460.1 AT4G17460 HAT1 HD-ZIP II dl4765w, FCAALL.65, HAT1, JAB Homeobox-leucine zipper protein 4 (HB-4) / HD-ZIP protein
40 AT4G17710.1 AT4G17710 HDG4 HD-ZIP IV dl4890c, FCAALL.102, HDG4, HDGL2-4 homeodomain GLABROUS 4
41 AT4G21750.1 AT4G21750 ATML1 HD-ZIP IV ATML1, F17L22.210 HD-ZIP family protein
42 AT4G21750.2 AT4G21750 ATML1 HD-ZIP IV ATML1, F17L22.210 HD-ZIP family protein
43 AT4G25530.1 AT4G25530 FWA/HDG6 HD-ZIP IV FWA, HDG6, HDGL2-6, M7J2.100 FLOWERING WAGENINGEN
44 AT4G32880.1 AT4G32880 AtHB8 HD-ZIP III ATHB8, ATHB-8, HB8, HB-8, T16I18.90 homeobox gene 8
45 AT4G36740.1 AT4G36740 AtHB40 HD-ZIP I ATHB40, ATHB-40, C7A10.620, HB40, HB-5 homeobox protein 40
46 AT4G37790.1 AT4G37790 HAT22 HD-ZIP II HAT22, T28I19.70 HD-ZIP family protein
47 AT4G40060.1 AT4G40060 AtHB16 HD-ZIP I ATHB16, ATHB-16, HB16, T5J17.230 homeobox protein 16
48 AT5G03790.1 AT5G03790 AtHB51 HD-ZIP I ATHB51, ATHB-51, F17C15_210, HB51, LMI1, MED24.8 homeobox 51
49 AT5G06710.1 AT5G06710 HAT14 HD-ZIP II HAT14, MPH15.6 homeobox from Arabidopsis thaliana
50 AT5G15150.1 AT5G15150 AtHB3/HAT7 HD-ZIP I ATHB3, ATHB-3, F8M21_40, HAT7, HB-3 homeobox 3
51 AT5G17320.1 AT5G17320 HDG9 HD-ZIP IV HDG9, HDGL2-9, MKP11.28 homeodomain GLABROUS 9
52 AT5G46880.1 AT5G46880 HDG5 HD-ZIP IV HB-7, HDG5, HDGL2-5, MQD22.1 homeobox-7
53 AT5G47370.1 AT5G47370 HAT2 HD-ZIP II HAT2, MQL5.23 Homeobox-leucine zipper protein 4 (HB-4) / HD-ZIP protein
54 AT5G52170.1 AT5G52170 HDG7 HD-ZIP IV F17P19.7, HDG7, HDGL2-7 homeodomain GLABROUS 7
55 AT5G53980.1 AT5G53980 AtHB52 HD-ZIP I ATHB52, ATHB-52, HB52, K19P17.15 homeobox protein 52
56 AT5G60690.1 AT5G60690 REV/IFL1 HD-ZIP III AVB1, IFL, IFL1, MUP24.16, REV HD-ZIP family protein
57 AT5G65310.1 AT5G65310 AtHB5 HD-ZIP I ATHB5, ATHB-5, HB5, MNA5.4 homeobox protein 5
58 AT5G65310.2 AT5G65310 AtHB5 HD-ZIP I ATHB5, ATHB-5, HB5 homeobox protein 5
59 AT5G66700.1 AT5G66700 AtHB53 HD-ZIP I ATHB53, ATHB-53, HB53, HB-8, MSN2.9 homeobox 53
+275
View File
@@ -0,0 +1,275 @@
# bbav5 修订记录 - 2026-04-14
## 今日修订概览
### 1. 修复 completed_stages 追踪问题
**问题**: 系统重复执行已完成的阶段(identify/phylogeny),不识别已完成的 pep 分析
**修复文件**: `gfa_core/mas/core/langgraph_orchestrator.py`
- 添加 `import json` 修复 manifest 解析
- 在 `_router_node` 中设置 `state["next_node"]` 确保正确路由
- 修改 `_route_decision` 优先使用 `next_node`
- 添加 `_query_completed_stages_from_manifest()` 方法从 manifest 文件查询已完成阶段
### 2. 统一 MAS 与 Pipeline 执行层
**问题**: MAS 的 Stage Registry 缺少 pep 阶段,导致多智能体无法执行 pep 分析
**修复文件**: `gfa_core/mas/tools/stage_tools.py`
- 重写 `StageToolExecutor.execute()` 调用 `pipeline_backend.run_stage()`
- 添加 `pep` stage 到 Stage Registry
- 处理异步执行(`asyncio.to_thread`)
- 添加工作目录切换(`os.chdir(self.project_root)`)
### 3. 修复 LangGraph 工作流循环问题
**问题**: Validator 反复验证导致无限循环
**修复文件**: `gfa_core/mas/agents/execution.py`
- 当 `stages_to_run` 为空时直接返回成功,跳过执行
**修复文件**: `gfa_core/mas/core/langgraph_orchestrator.py`
- `_validator_node`: 当 `execution_result` 为空列表时跳过验证
- `_to_agent_state`: 处理 `execution_result` 列表类型
### 4. 修复前端 API 响应
**修复文件**: `apps/web/vue3/main.py`
- 处理 `final_output.get("execution")` 返回列表的情况
- `/api/execute` 端点检查 manifest,返回 `already_completed: true`
### 5. 完善 Validator 支持
**修复文件**: `gfa_core/mas/agents/validator.py`
- 在 `EXPECTED_OUTPUTS` 中添加 `pep` 阶段预期输出文件
### 6. 修复 PlanningAgentV2 和 IntentAgentV2
**修复文件**: `gfa_core/mas/agents/planning_v2.py`
- 添加 `_check_stage_status_from_manifest()` 方法
- 修改 `_generate_plan_with_llm` 基于 manifest 状态过滤阶段
- 接收 `job_id` 和 `workspace` 参数
**修复文件**: `gfa_core/mas/agents/intent_v2.py`
- 添加 pep 强制规则匹配
- 修改 LLM 提示词,不过滤 completed stages
- 传递 `job_id` 和 `workspace` 到 intent 结果
## 验证结果
```bash
# 测试命令
curl -s http://localhost:7868/api/agent/chat \
-X POST \
-H "Content-Type: application/json" \
-d '{"message":"帮我执行pep分析","session_id":"test_pep","job_id":"job_1776101584377"}'
# 返回结果
{"success": true, ...}
```
**PEP 分析成功执行,生成文件**:
- `Ft.SPL.pep.manifest.json`
- `Ft.SPL.pep_properties.tsv`
- `Ft.SPL.pep_report.md`
- `Ft.SPL.pep_properties.pdf`
- `Ft.SPL.pep_properties.png`
## 关键架构改进
### 执行路径统一
```
旧路径: MAS → StageToolExecutor → 直接运行脚本 ❌ 缺少 pep 支持
新路径: MAS → StageToolExecutor → pipeline_backend.run_stage() ✅ 统一调用
```
### 状态管理优化
- `completed_stages` 从 manifest 文件实时查询
- 空阶段列表时跳过执行和验证
- 正确处理列表/字典类型转换
## 多智能体架构设计与功能增强(讨论记录)
### 当前架构问题分析
**12个 Agent 架构存在的问题:**
1. **Validator vs SelfCritique** - 功能高度冗余,都在检查执行结果
2. **Knowledge Agent 功能浪费** - 只用于 FAQ,未充分利用 RAG 能力
3. **缺少 Pre-flight 验证** - 执行前不验证输入文件和依赖
4. **缺少迭代机制** - 单次执行,失败时直接报错
### 优化后的 9个 Agent 架构
```
Router → IntentV2 → PlanningV2 → PreFlight → Execution → QualityValidator
│
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
ResultParser Diagnosis(+迭代) Discovery
│ │ │
└─────────────────────┴─────────────────────┘
│
▼
Learning → Knowledge
```
**合并优化:**
- **Validator + SelfCritique** → **QualityValidator**(质量验证器)
- 删除冗余 Agent,保留核心功能
### Knowledge Agent 完整功能定位(4个)
| 功能 | 描述 | 当前状态 | 计划 |
|------|------|----------|------|
| **1. 知识检索与事实回答** | RAG 问答 | ✅ 已实现 | 保持 |
| **2. 文献存在性判断** | 判断是否有相关文献 | ⚠️ 部分实现 | 增强 |
| **3. 分析方案生成** | 生成完整分析方案(数据来源、比对物种等) | ❌ 未实现 | **新增** |
| **4. 报告增强** | 为 Discovery 提供生物学背景支撑 | ❌ 未实现 | **新增** |
### 新增 Agent 设计
#### 1. PreFlight Agent(执行前验证)
**职责:**
- 输入文件存在性检查
- 依赖阶段状态检查(manifest)
- 资源可用性检查(CPU/内存/磁盘)
- 参数合法性检查
**输出:**
```python
{
"valid": True/False,
"issues": ["输入文件不存在: xxx.fa"],
"suggested_fix": "请先运行 identify 阶段",
"stage_status": {...}
}
```
#### 2. QualityValidator Agent(质量验证器)
**合并:** Validator + SelfCritique
**职责:**
- 原 Validator:检查输出文件存在性、manifest 完整性
- 新增 SelfCritique:检查结果合理性、质量评分
**输出:**
```python
{
"passed": True/False,
"score": 85,
"completeness": {...}, # 原 Validator
"quality": {...}, # 原 SelfCritique
"issues": [...]
}
```
#### 3. 增强 Diagnosis Agent
**新增功能:**
- 分析失败根因(输入/代码/资源)
- 建议具体修复方案
- 记录修复历史,避免重复错误
- 支持迭代重试(max_iterations)
### 迭代执行机制
```python
max_iterations = 3 # 最大迭代次数
current_iteration = 0
while current_iteration < max_iterations:
result = await execute()
# QualityValidator 检查
quality = await quality_validate(result)
if quality["passed"]:
break # 成功,退出
# Diagnosis 诊断
diagnosis = await diagnose(quality["issues"])
if not diagnosis["fixable"]:
break # 不可修复,退出
# 修复并重试
await apply_fix(diagnosis["fix"])
current_iteration += 1
```
### State 扩展字段
```python
{
# 新增字段
"pre_flight_result": {...}, # PreFlight 输出
"quality_validation_result": {...}, # QualityValidator 输出
"iteration_count": 0, # 当前迭代次数
"max_iterations": 3, # 最大迭代次数
"fix_history": [...], # 修复历史
}
```
### 架构债务(紧急)
| 步骤 | 任务 | 文件 | 优先级 | 说明 |
|------|------|------|--------|------|
| 0 | **复用 `_parse_intent_from_query`** | `intent_v2.py` / 公共模块 | **P0** | 替代当前重复实现的强制规则 |
**问题:**
- `intent_v2.py` 重新实现了 pep/karyotype/synteny 等强制规则
- `orchestrator.py` 已有成熟的 `_parse_intent_from_query`
- 重复代码,维护困难
**方案:**
```python
# 推荐:提取到公共模块
from gfa_core.mas.utils.intent_parser import parse_intent_from_query
# IntentAgentV2 使用:
base_intent = parse_intent_from_query(query) # 硬编码规则
refined_intent = await llm_refine(base_intent) # LLM 细化
```
### 实施计划
| 步骤 | 任务 | 文件 | 优先级 |
|------|------|------|--------|
| 1 | **复用 `_parse_intent_from_query`** | 公共模块 / `intent_v2.py` | **P0** |
| 2 | 创建 PreFlight Agent | `agents/preflight.py` | P1 |
| 3 | 创建 QualityValidator | `agents/quality_validator.py` | P1 |
| 4 | 增强 Diagnosis Agent | `agents/diagnosis.py` | P1 |
| 5 | 修改 LangGraph 工作流 | `langgraph_orchestrator.py` | P1 |
| 6 | 增强 Knowledge Agent(功能3、4) | `agents/knowledge.py` | P2 |
| 7 | 添加迭代状态管理 | `core/state.py` | P2 |
| 8 | 测试验证 | - | P1 |
## 待办事项
### 明日计划
1. [ ] 测试其他分析阶段(structure/promoter/synteny)
2. [ ] 验证多阶段串联执行(identify → phylogeny → motif)
3. [ ] 检查前端状态显示是否与后端一致
### 中期计划(功能增强)
1. [ ] 创建 PreFlight Agent
2. [ ] 创建 QualityValidator(合并 Validator + SelfCritique)
3. [ ] 增强 Diagnosis Agent(添加迭代支持)
4. [ ] 增强 Knowledge Agent(功能3:分析方案生成)
5. [ ] 增强 Knowledge Agent(功能4:报告增强)
### 总体计划
1. **Phase 1**: 修复核心执行流程 ✅(今日完成)
2. **Phase 2**: 完善所有分析阶段支持 ⏳
3. **Phase 3**: 优化前端状态同步 ⏳
4. **Phase 4**: Agent 架构增强(PreFlight/QualityValidator/迭代机制)⏳
5. **Phase 5**: Knowledge Agent 功能完善(方案生成/报告增强)⏳
6. **Phase 6**: 集成测试和性能优化 ⏳
## 今日任务完成度
| 任务 | 状态 | 备注 |
|------|------|------|
| 修复 completed_stages 追踪 | ✅ | 核心问题已解决 |
| 统一 MAS 与 Pipeline 执行 | ✅ | 现在支持 pep 分析 |
| 修复 LangGraph 循环问题 | ✅ | 无无限循环 |
| 修复前端 API 响应 | ✅ | Success: true |
| 真实数据测试 | ✅ | PEP 分析成功执行 |
**完成度: 5/5 (100%)**
---
记录时间: 2026-04-14 19:50
记录者: xialab的幸运星
+65
View File
@@ -0,0 +1,65 @@
# CLAUDE.md
Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed.
**Tradeoff:** These guidelines bias toward caution over speed. For trivial tasks, use judgment.
## 1. Think Before Coding
**Don't assume. Don't hide confusion. Surface tradeoffs.**
Before implementing:
- State your assumptions explicitly. If uncertain, ask.
- If multiple interpretations exist, present them - don't pick silently.
- If a simpler approach exists, say so. Push back when warranted.
- If something is unclear, stop. Name what's confusing. Ask.
## 2. Simplicity First
**Minimum code that solves the problem. Nothing speculative.**
- No features beyond what was asked.
- No abstractions for single-use code.
- No "flexibility" or "configurability" that wasn't requested.
- No error handling for impossible scenarios.
- If you write 200 lines and it could be 50, rewrite it.
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
## 3. Surgical Changes
**Touch only what you must. Clean up only your own mess.**
When editing existing code:
- Don't "improve" adjacent code, comments, or formatting.
- Don't refactor things that aren't broken.
- Match existing style, even if you'd do it differently.
- If you notice unrelated dead code, mention it - don't delete it.
When your changes create orphans:
- Remove imports/variables/functions that YOUR changes made unused.
- Don't remove pre-existing dead code unless asked.
The test: Every changed line should trace directly to the user's request.
## 4. Goal-Driven Execution
**Define success criteria. Loop until verified.**
Transform tasks into verifiable goals:
- "Add validation" → "Write tests for invalid inputs, then make them pass"
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
- "Refactor X" → "Ensure tests pass before and after"
For multi-step tasks, state a brief plan:
```
1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]
```
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
---
**These guidelines are working if:** fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes.
@@ -0,0 +1,252 @@
# bbav5 ConversationManager 实施报告
**实施时间**: 2026-04-13 00:22
**实施人**: xialab的幸运星
**状态**: ✅ 已完成
---
## 1. 实施概述
成功为bbav5添加类似 **DeepSeek/ChatGPT** 的多会话管理功能,解决了之前"一个job_id一个记录"的局限。
---
## 2. 核心改进
### 2.1 架构改进
| 维度 | 之前 | 现在 |
|:---|:---|:---|
| **会话模型** | 1个job = 1个session | 1个用户 = N个独立会话 |
| **数据隔离** | 按job隔离 | 按用户+会话双重隔离 |
| **持久化** | 内存级 | 文件系统持久化 |
| **查询能力** | 只能查单个session | 可列出用户所有会话 |
| **生命周期** | 随job结束 | 支持active/archived/deleted |
### 2.2 新增组件
```
gfa_core/mas/memory/
├── conversation.py # 核心:ConversationManager
└── persistent.py # 已有:持久化基类
gfa_core/mas/api/
└── conversation_routes.py # 新增:REST API路由
memory_storage/
├── conversations/ # 会话数据存储
│ ├── 202604/
│ │ ├── conv_xxx.json # 单个会话文件
│ │ └── ...
│ └── user_index.json # 用户-会话索引
├── sessions/ # 已有:session存储
├── cases/ # 已有:case存储
└── knowledge/ # 已有:knowledge存储
```
---
## 3. 功能清单
### 3.1 ConversationManager 核心功能
| 功能 | 方法 | 状态 |
|:---|:---|:---:|
| 创建会话 | `create_conversation()` | ✅ |
| 添加消息 | `add_message()` | ✅ |
| 列出用户会话 | `list_user_conversations()` | ✅ |
| 获取消息历史 | `get_messages()` | ✅ |
| 更新标题 | `update_title()` | ✅ |
| 删除会话 | `delete_conversation()` | ✅ |
| 归档会话 | `archive_conversation()` | ✅ |
| 关联Job | `link_to_job()` | ✅ |
### 3.2 REST API 端点
| 端点 | 方法 | 功能 |
|:---|:---:|:---|
| `/conversations/create` | POST | 创建新会话 |
| `/conversations/message` | POST | 添加消息 |
| `/conversations/list/{user_id}` | GET | 列出用户会话 |
| `/conversations/{id}/messages` | GET | 获取消息历史 |
| `/conversations/update-title` | POST | 更新标题 |
| `/conversations/delete` | POST | 删除会话 |
| `/conversations/archive` | POST | 归档会话 |
| `/conversations/link-to-job` | POST | 关联分析任务 |
---
## 4. 测试报告
### 4.1 测试环境
- **Python**: 3.12
- **存储**: 本地文件系统
- **测试数据**: 真实基因家族分析场景
### 4.2 测试用例
| 用例ID | 描述 | 结果 |
|:---|:---|:---:|
| TC-001 | 创建SPL基因家族分析会话 | ✅ 通过 |
| TC-002 | 创建TCP进化分析会话 | ✅ 通过 |
| TC-003 | 创建通用咨询会话 | ✅ 通过 |
| TC-004 | 添加用户消息 | ✅ 通过 |
| TC-005 | 添加AI回复 | ✅ 通过 |
| TC-006 | 列出用户所有会话 | ✅ 通过 |
| TC-007 | 获取消息历史 | ✅ 通过 |
| TC-008 | 更新会话标题 | ✅ 通过 |
| TC-009 | 关联到Job | ✅ 通过 |
| TC-010 | 归档会话 | ✅ 通过 |
### 4.3 性能指标
| 指标 | 数值 |
|:---|:---|
| 创建会话耗时 | < 10ms |
| 添加消息耗时 | < 5ms |
| 列出会话耗时 | < 20ms (100个会话) |
| 获取历史耗时 | < 10ms (100条消息) |
| 存储格式 | JSON文件 |
---
## 5. 使用示例
### 5.1 Python SDK
```python
from gfa_core.mas.memory.conversation import ConversationManager
manager = ConversationManager()
# 创建新会话
conv = await manager.create_conversation(
user_id='xia-lab',
title='SPL基因家族分析',
gene_family='SPL',
species='Ft'
)
# 添加消息
await manager.add_message(conv.conversation_id, 'user', '帮我分析...')
await manager.add_message(conv.conversation_id, 'assistant', '好的...')
# 列出所有会话(类似ChatGPT侧边栏)
conversations = await manager.list_user_conversations('xia-lab')
for c in conversations:
print(f"{c.title} ({c.message_count}条消息)")
```
### 5.2 REST API
```bash
# 创建会话
curl -X POST http://localhost:8000/api/conversations/create \
-H "Content-Type: application/json" \
-d '{
"user_id": "xia-lab",
"title": "SPL分析",
"gene_family": "SPL",
"species": "Ft"
}'
# 列出会话
curl http://localhost:8000/api/conversations/list/xia-lab
# 获取消息历史
curl http://localhost:8000/api/conversations/{conv_id}/messages
```
---
## 6. 前端集成建议
### 6.1 Vue3组件设计
```vue
<!-- ConversationSidebar.vue -->
<template>
<div class="conversation-sidebar">
<button @click="createNewConversation">+ New Chat</button>
<div v-for="conv in conversations" :key="conv.conversation_id"
@click="selectConversation(conv)"
:class="{ active: currentConv?.id === conv.conversation_id }">
<div class="title">{{ conv.title }}</div>
<div class="meta">{{ conv.message_count }}条消息 · {{ conv.gene_family || '通用' }}</div>
<div class="last-message">{{ conv.last_message }}</div>
</div>
</div>
</template>
```
### 6.2 界面效果
类似ChatGPT的左侧边栏:
```
┌─────────────────────────────────────────┐
│ + New Chat │
├─────────────────────────────────────────┤
│ 📁 Ft.SPL分析 🧬 SPL │
│ 5条消息 · 最后: 生成系统发育树 │
├─────────────────────────────────────────┤
│ 📁 Os.TCP进化 🧬 TCP │
│ 2条消息 · 最后: 开始分析... │
├─────────────────────────────────────────┤
│ 📁 HMMER参数配置 📝 通用 │
│ 3条消息 · 最后: bit score设置 │
└─────────────────────────────────────────┘
```
---
## 7. 后续优化建议
### 7.1 短期(1-2周)
- [ ] Vue3前端集成会话侧边栏
- [ ] 添加会话搜索功能
- [ ] 实现会话置顶功能
### 7.2 中期(1个月)
- [ ] 从内存缓存改为Redis缓存
- [ ] 添加会话分享功能
- [ ] 实现会话模板(快速创建常见分析)
### 7.3 长期(持续)
- [ ] 会话数据分析(用户行为洞察)
- [ ] 智能会话推荐
- [ ] 多设备同步
---
## 8. 文件清单
| 文件 | 路径 | 说明 |
|:---|:---|:---|
| ConversationManager | `gfa_core/mas/memory/conversation.py` | 核心实现 |
| API Routes | `gfa_core/mas/api/conversation_routes.py` | REST API |
| 测试报告 | `CONVERSATION_MANAGER_REPORT.md` | 本文档 |
---
## 9. 总结
✅ **bbav5现在支持类似DeepSeek/ChatGPT的多会话管理!**
- 一个用户可以拥有多个独立会话
- 每个会话有自己的标题、消息历史和元数据
- 支持列出、归档、删除会话
- 会话可关联到具体的基因家族分析任务
- 完整REST API支持前端集成
**下一步**: 前端Vue3集成,添加类似ChatGPT的侧边栏UI。
---
*报告生成时间: 2026-04-13 00:25*
*实施状态: ✅ 全部完成*
@@ -0,0 +1,24 @@
FtPinG0006588500.01 FtPinG0008190500.01 FtPinG0003310800.01 FtPinG0006144300.01 FtPinG0000212200.01 FtPinG0006382900.01 FtPinG0002293500.01 FtPinG0007448200.01 FtPinG0001287900.01 FtPinG0003446200.01 FtPinG0007295700.01 FtPinG0005035600.01 FtPinG0006337300.01 FtPinG0000377600.01 FtPinG0000286400.01 FtPinG0009145900.01 FtPinG0001782200.01 FtPinG0005349100.01 FtPinG0006650700.01 FtPinG0000496000.01 FtPinG0000493400.01 FtPinG0007464600.01 FtPinG0009904300.01
1 0.763977297045498 0.362306253992531 -0.297364177336134 0.886574867158801 0.766666635857025 0.167066965657706 0.84071827222532 0.7321881775191 0.552170563500791 0.828518859328645 0.926599607704093 0.0283339387298275 0.802010771833353 0.925425061568231 0.773759821441228 0.732336801726691 0.8514792131362 0.868277358073888 0.721857640371706 0.932111740618097 0.901548795053261 0.592167113441814
0.763977297045498 1 0.420618145955125 -0.327837996847146 0.957869319800842 0.825570414424048 0.47090456046584 0.953571198223258 0.915976236226215 0.696829840353352 0.743496827746765 0.917383878157675 0.303203106969891 0.892497501940861 0.88508186575069 0.908671703158221 0.647485276552536 0.968070730328125 0.850757523409126 0.973440261975927 0.931396455682474 0.890350037218093 0.739567327420683
0.362306253992531 0.420618145955125 1 -0.250601718210098 0.401434134903414 0.46195854773325 0.352470613641699 0.296662672793622 0.153292157937659 0.0150327191885208 0.108935975986506 0.317090797853271 0.464339394787339 0.343920097826525 0.20166489405544 0.320342195260115 -0.0160685163078603 0.388962551035708 0.351952666550627 0.288706024035277 0.461678202479768 0.168276952591961 0.11762159535573
-0.297364177336134 -0.327837996847146 -0.250601718210098 1 -0.301957485054484 0.0116933964791182 0.283206871574742 -0.296801773623735 -0.366822729736472 -0.422792876284152 -0.242747080393473 -0.313917432808282 0.152905985415759 -0.258989866206239 -0.286836914037064 -0.195515629227989 -0.527929705453189 -0.297002505921361 -0.228166615478739 -0.223446834202493 -0.282914811658729 -0.366969406551725 -0.138204466648141
0.886574867158801 0.957869319800842 0.401434134903414 -0.301957485054484 1 0.895505590036444 0.412105325553714 0.978818698823108 0.915372097538663 0.743637101730958 0.824849405429816 0.987904444568084 0.104687595341454 0.940576062944407 0.95738396215094 0.946067319595474 0.72901281818197 0.98469410647373 0.940017426918904 0.939670775470103 0.986770519958042 0.950469528183235 0.804070776797611
0.766666635857025 0.825570414424048 0.46195854773325 0.0116933964791182 0.895505590036444 1 0.693726776743482 0.862185343315214 0.718255667840392 0.654816770404525 0.759155961628757 0.854038770620457 0.0702432985887324 0.917486608236047 0.786130272196786 0.941910336813492 0.508110462177498 0.893624773106316 0.944235720407398 0.844436364594235 0.895992491807012 0.757329708716226 0.69844151012325
0.167066965657706 0.47090456046584 0.352470613641699 0.283206871574742 0.412105325553714 0.693726776743482 1 0.379975414491467 0.241011359493029 0.263709409174582 0.333929237252667 0.296798124184329 0.276697396732026 0.509376199317314 0.203245159664083 0.578225048908408 -0.0354602464426738 0.456523781985529 0.518934657712666 0.536207998424169 0.401053085803689 0.177383078252203 0.176556278239889
0.84071827222532 0.953571198223258 0.296662672793622 -0.296801773623735 0.978818698823108 0.862185343315214 0.379975414491467 1 0.946138487193425 0.824661165740299 0.84614299688998 0.971311764358583 0.0686043539197794 0.958075593478404 0.947497041344641 0.961431226345709 0.767135983221901 0.990999408139853 0.929972560314232 0.946124374746584 0.952621287253545 0.960404195531399 0.826422968020944
0.7321881775191 0.915976236226215 0.153292157937659 -0.366822729736472 0.915372097538663 0.718255667840392 0.241011359493029 0.946138487193425 1 0.817573866494127 0.812588035110717 0.917772098399363 0.0140113041660117 0.836172089179638 0.915909623764224 0.867581874032557 0.840177712348188 0.910374892326512 0.799925768550058 0.93822559672528 0.849901104277338 0.935954860219547 0.863011193697999
0.552170563500791 0.696829840353352 0.0150327191885208 -0.422792876284152 0.743637101730958 0.654816770404525 0.263709409174582 0.824661165740299 0.817573866494127 1 0.734439906239105 0.747444143478084 -0.39047816169276 0.851297590089451 0.708237480003319 0.845158861772077 0.781822501067767 0.781481353028796 0.796735202730265 0.730403262843855 0.669520498108427 0.775899112380969 0.776950362198008
0.828518859328645 0.743496827746765 0.108935975986506 -0.242747080393473 0.824849405429816 0.759155961628757 0.333929237252667 0.84614299688998 0.812588035110717 0.734439906239105 1 0.852212444842583 -0.136607388735739 0.801999744213109 0.844754316190782 0.837208447632659 0.89006483651264 0.837291806640169 0.865086174078125 0.808938213166151 0.810834689733497 0.853421771872407 0.577771612126922
0.926599607704093 0.917383878157675 0.317090797853271 -0.313917432808282 0.987904444568084 0.854038770620457 0.296798124184329 0.971311764358583 0.917772098399363 0.747444143478084 0.852212444842583 1 0.0228416226853041 0.918783663016859 0.987170399730814 0.916903433893905 0.787479133150597 0.964027740137067 0.930341023406304 0.902333139763514 0.978646992276125 0.980403450961637 0.811960952436426
0.0283339387298275 0.303203106969891 0.464339394787339 0.152905985415759 0.104687595341454 0.0702432985887324 0.276697396732026 0.0686043539197794 0.0140113041660117 -0.39047816169276 -0.136607388735739 0.0228416226853041 1 -0.0195847646948573 0.0208107930534155 -0.00440252491335805 -0.325250126216899 0.142526367853256 -0.0783872911500918 0.212998832025682 0.156873791072314 -0.0197329725088677 -0.183687544929775
0.802010771833353 0.892497501940861 0.343920097826525 -0.258989866206239 0.940576062944407 0.917486608236047 0.509376199317314 0.958075593478404 0.836172089179638 0.851297590089451 0.801999744213109 0.918783663016859 -0.0195847646948573 1 0.866408842436724 0.986016458084539 0.665453623879053 0.966132911295697 0.975627133132557 0.879286308680141 0.927547250804721 0.884314628271863 0.765757273531754
0.925425061568231 0.88508186575069 0.20166489405544 -0.286836914037064 0.95738396215094 0.786130272196786 0.203245159664083 0.947497041344641 0.915909623764224 0.708237480003319 0.844754316190782 0.987170399730814 0.0208107930534155 0.866408842436724 1 0.864550907687836 0.801400040039978 0.927965210935964 0.880092835823746 0.876509653043875 0.948182579407145 0.990986311756845 0.800257932645277
0.773759821441228 0.908671703158221 0.320342195260115 -0.195515629227989 0.946067319595474 0.941910336813492 0.578225048908408 0.961431226345709 0.867581874032557 0.845158861772077 0.837208447632659 0.916903433893905 -0.00440252491335805 0.986016458084539 0.864550907687836 1 0.683151378230202 0.967841534812107 0.970737758757276 0.926219446208721 0.918151139082027 0.875110612934003 0.783983996307267
0.732336801726691 0.647485276552536 -0.0160685163078603 -0.527929705453189 0.72901281818197 0.508110462177498 -0.0354602464426738 0.767135983221901 0.840177712348188 0.781822501067767 0.89006483651264 0.787479133150597 -0.325250126216899 0.665453623879053 0.801400040039978 0.683151378230202 1 0.718889435660118 0.700917360427673 0.692761328596212 0.682159322234159 0.839611977396654 0.629662710406678
0.8514792131362 0.968070730328125 0.388962551035708 -0.297002505921361 0.98469410647373 0.893624773106316 0.456523781985529 0.990999408139853 0.910374892326512 0.781481353028796 0.837291806640169 0.964027740137067 0.142526367853256 0.966132911295697 0.927965210935964 0.967841534812107 0.718889435660118 1 0.94520110413051 0.949439851970342 0.971388836398859 0.935808167194227 0.767474825785344
0.868277358073888 0.850757523409126 0.351952666550627 -0.228166615478739 0.940017426918904 0.944235720407398 0.518934657712666 0.929972560314232 0.799925768550058 0.796735202730265 0.865086174078125 0.930341023406304 -0.0783872911500918 0.975627133132557 0.880092835823746 0.970737758757276 0.700917360427673 0.94520110413051 1 0.853923145211992 0.941065657293308 0.881123519782033 0.713564094081412
0.721857640371706 0.973440261975927 0.288706024035277 -0.223446834202493 0.939670775470103 0.844436364594235 0.536207998424169 0.946124374746584 0.93822559672528 0.730403262843855 0.808938213166151 0.902333139763514 0.212998832025682 0.879286308680141 0.876509653043875 0.926219446208721 0.692761328596212 0.949439851970342 0.853923145211992 1 0.892682232267606 0.878564473204782 0.761739058823704
0.932111740618097 0.931396455682474 0.461678202479768 -0.282914811658729 0.986770519958042 0.895992491807012 0.401053085803689 0.952621287253545 0.849901104277338 0.669520498108427 0.810834689733497 0.978646992276125 0.156873791072314 0.927547250804721 0.948182579407145 0.918151139082027 0.682159322234159 0.971388836398859 0.941065657293308 0.892682232267606 1 0.933094113452704 0.728330495742318
0.901548795053261 0.890350037218093 0.168276952591961 -0.366969406551725 0.950469528183235 0.757329708716226 0.177383078252203 0.960404195531399 0.935954860219547 0.775899112380969 0.853421771872407 0.980403450961637 -0.0197329725088677 0.884314628271863 0.990986311756845 0.875110612934003 0.839611977396654 0.935808167194227 0.881123519782033 0.878564473204782 0.933094113452704 1 0.801240030825883
0.592167113441814 0.739567327420683 0.11762159535573 -0.138204466648141 0.804070776797611 0.69844151012325 0.176556278239889 0.826422968020944 0.863011193697999 0.776950362198008 0.577771612126922 0.811960952436426 -0.183687544929775 0.765757273531754 0.800257932645277 0.783983996307267 0.629662710406678 0.767474825785344 0.713564094081412 0.761739058823704 0.728330495742318 0.801240030825883 1
Binary file not shown.
@@ -0,0 +1,24 @@
geneID X2_1 X2_2 X2_3 X3_1 X3_2 X3_3 X4_1 X4_2 X4_3
FtPinG0006588500.01 9.792287231 3.778525168 5.52607575 3.142950512 1.772584057 1.68827488 2.84671249 1.871446651 0.960648855
FtPinG0008190500.01 5.33346899 4.154910643 6.35909238 2.871351534 2.182118437 2.861615999 0.856712248 0.691432923 1.049345127
FtPinG0003310800.01 1.447293654 1.351481792 0.73987976 2.759284629 0.704453302 0.728787785 0.103897575 0.393746231 0.098171292
FtPinG0006144300.01 0.107763856 0.201259626 0 0 0.337196571 0.116281539 0 0.329826388 0.109645858
FtPinG0000212200.01 4.354539506 2.682605987 4.107703959 1.377258741 0.536188426 0.685230498 0.065125302 0.185106646 0.246143763
FtPinG0006382900.01 3.654336603 3.797275994 3.040016839 2.008044517 1.805453165 1.304509451 1.005948706 1.737959357 1.14619859
FtPinG0002293500.01 4.187865361 17.09761942 5.227788917 3.816746518 8.634395774 3.047613575 0 0.397443379 0
FtPinG0007448200.01 37.78823858 28.51363167 40.60919491 15.92844796 10.63765317 17.70969226 10.70250408 13.36000226 9.684457336
FtPinG0001287900.01 11.64082234 6.340945149 19.61860002 2.13397912 0.778301439 2.174004672 0.642819529 1.065805895 0.759238406
FtPinG0003446200.01 9.154592955 10.24730325 11.57136663 6.774984052 4.733364413 7.471952357 7.835670011 7.603423506 7.543128425
FtPinG0007295700.01 3.426827058 2.819020035 3.485822048 1.641964778 1.829658879 1.496681756 2.591820528 1.956148311 1.037700476
FtPinG0005035600.01 3.611879084 1.597627961 3.123694619 0.604043472 0 0.153843273 0 0.048485361 0
FtPinG0006337300.01 0.938195384 0.584057458 0.79936758 1.324949627 1.739640603 1.687250974 0.112251149 0.319053165 0.106064461
FtPinG0000377600.01 17.47106863 16.93519446 16.6520874 10.2952618 7.351795864 10.88083059 8.548936195 9.302373736 8.537163075
FtPinG0000286400.01 16.08935551 4.687559392 13.58322615 0.499881891 0.313252244 0.648146324 0 0 0.043654245
FtPinG0009145900.01 47.00797708 49.01317568 50.03029556 18.80177474 12.46061822 18.60795783 12.12333488 16.29517853 10.7284783
FtPinG0001782200.01 6.682312764 4.639954598 8.151460789 4.018492746 3.063614867 3.301503873 6.088581783 4.295202248 3.511578412
FtPinG0005349100.01 16.85614975 12.92218805 16.98184879 6.843651063 3.779878881 6.888515478 3.138565849 3.486740987 1.928942288
FtPinG0006650700.01 19.33510456 17.31362416 15.72257134 7.842666342 4.720752 6.126201081 6.861714007 6.359284223 4.847501097
FtPinG0000496000.01 37.4695409 33.73788178 53.90199431 12.38070506 16.81789804 13.2111626 2.985030551 2.215370637 1.551281323
FtPinG0000493400.01 9.347343202 5.257543135 7.006088978 3.242257057 1.453854783 1.916960154 0.618046839 0.641329088 0.417130982
FtPinG0007464600.01 24.33761622 12.56813403 23.34102338 7.260949357 5.562757473 8.910837935 7.99464498 6.642819189 7.02887659
FtPinG0009904300.01 1.199106495 0.895779839 1.663863926 0.508025001 0.250136185 0.34503578 0 0.815563003 0.813365229
+489
View File
@@ -0,0 +1,489 @@
# identify 阶段多智能体数据流转详解
## 概述
本文档详细分析 identify 阶段从用户输入到最终输出的 10 个 Agent 数据流转,包括每个 Agent 的输入、输出、数据类型,以及错误处理机制。
---
## 1. 用户输入 -> Router Agent
### 输入数据
```json
{
"query": "鉴定Ft.SPL基因家族",
"user_input": {
"prefix": "Ft.SPL",
"stage": "identify",
"species_name": "Fagopyrum tataricum"
},
"job_id": "job_xxx"
}
```
### Router Agent 处理
1. 调用 `RouterAgent.classify()` 判断模式: `analysis`
2. 如果是单 stage 模式(`user_input.stage` 存在),直接设置 intent:
- `stages = ["identify"]`
- `prefix = "Ft.SPL"`
3. 否则调用 `IntentAgentV2` 解析意图
### 输出数据(设置到 state)
```python
state["mode"] = "analysis"
state["intent_result"] = {
"mode": "analysis",
"stages": ["identify"],
"prefix": "Ft.SPL",
"single_stage_mode": True,
"job_id": "job_xxx",
"workspace": "/path/to/workspace/job_xxx"
}
state["next_node"] = "learning_recommend"
```
---
## 2. Router -> Learning Recommend Agent
### 输入数据(从 state 获取)
```python
intent = state.get("intent_result", {})
target_stages = intent.get("stages", ["identify"]) # ["identify"]
```
### Learning Recommend Agent 处理
- 查询历史执行记录,获取参数推荐
- 如果有高置信度历史记录,返回推荐参数
- 否则返回默认参数
### 输出数据(设置到 state)
```python
state["learning_recommendations"] = {
"confidence": "high", # 或 "medium" / "low"
"params": {
"evalue": "1e-5",
"coverage": 0.5
},
"message": "基于历史执行推荐参数"
}
```
---
## 3. Learning Recommend -> Planning Agent
### 输入数据(从 state 获取)
```python
state["intent_result"] # 包含 stages, prefix 等
state["learning_recommendations"] # 参数推荐
state["completed_stages"] # 已完成的阶段(从 manifest 查询)
```
### Planning Agent 处理
1. 重新查询 `completed_stages`(从文件系统 manifest)
2. 根据 intent 和 learning_recommendations 制定执行计划
3. 设置 stages_to_run = ["identify"](排除已完成的)
### 输出数据(设置到 state)
```python
state["plan_result"] = {
"stages": [
{
"id": "identify",
"name": "基因鉴定",
"params": {
"evalue": "1e-5",
"coverage": 0.5
}
}
],
"prefix": "Ft.SPL",
"workspace": "/path/to/workspace/job_xxx",
"job_id": "job_xxx"
}
```
---
## 4. Planning -> PreFlight Agent
### 输入数据(从 state 获取)
```python
plan = state.get("plan_result", {})
job_id = state.get("job_id", "")
prefix = intent.get("prefix", "Ft.SPL")
```
### PreFlight Agent 处理
1. 检查输入文件是否存在:
- `input/{prefix}.pep.fa`(参考序列)
- `input/{species_prefix}.pep.fa`(物种序列)
2. 检查契约文件是否存在
3. 检查环境配置
### 输出数据(设置到 state)
```python
state["preflight_result"] = {
"valid": True, # 或 False
"issues": [], # 如果 valid=False,列出问题
"checked_files": [
"input/Ft.SPL.pep.fa: EXISTS",
"input/Ft.pep.fa: EXISTS"
]
}
```
### 错误处理
- 如果 `preflight_result.valid = False`:
- 记录 `state["errors"]`
- Planning Agent 可能重新规划(目前未实现)
---
## 5. PreFlight -> Execution Agent 【关键】
### 输入数据(从 state 获取)
```python
plan = state.get("plan_result", {})
# plan 包含:
# - stages: [{"id": "identify", "params": {...}}]
# - prefix: "Ft.SPL"
# - workspace: "/path/to/workspace/job_xxx"
# - job_id: "job_xxx"
```
### Execution Agent 处理
1. 解析 plan,获取 `stages_to_run = ["identify"]`
2. 调用 `stage_registry.execute("identify", job_id, prefix, params)`
3. 执行 `python apps/cli/run_identify.py --prefix Ft.SPL --workspace ...`
4. 等待执行完成,读取 manifest
### 执行结果结构(关键)
```python
result = {
"status": "success", # 或 "error"
"manifest": {...}, # manifest.json 内容
"manifest_path": "/path/to/manifest.json",
"elapsed_sec": 45.2,
"metrics": {
"final_members": 15,
"initial_candidates": 120
}
}
```
### 输出数据(设置到 state)【问题点】
```python
execution_results = [
{
"stage": "identify",
"result": {
"status": "success",
"manifest": {...},
"manifest_path": "...",
"message": "✅ Identify completed successfully"
}
}
]
state["execution_results"] = execution_results # LIST 类型
```
### **LangGraph State 传递问题**
- `_execution_node` 设置 `state["execution_results"] = execution_results`(list)
- LangGraph 调用 `return state` 返回给下一个节点
- **TypedDict 类型定义必须匹配**: `execution_results: list[dict[str, Any]]`
- 如果类型不匹配,LangGraph 可能无法正确传递
---
## 6. Execution -> ResultParser Agent
### 输入数据(从 state 获取)
```python
execution_results = state.get("execution_results", []) # LIST
```
### **Fallback 机制(关键)**
如果 `execution_results` 为空(LangGraph state 传递失败):
```python
if not execution_results:
# 从文件系统重新加载 manifest
workspace = Path(f"/path/to/workspace/{job_id}/final")
for manifest_file in workspace.glob(f"{prefix}.*.manifest.json"):
manifest = json.load(manifest_file)
execution_results.append({
"stage": manifest.get("stage"),
"result": {
"status": manifest.get("status", "success"),
"manifest": manifest
}
})
```
### ResultParser Agent 处理
- 解析 execution_results,生成结构化报告
- 提取关键指标:final_members, initial_candidates 等
### 输出数据(设置到 state)
```python
state["parse_result"] = {
"stage": "identify",
"status": "success",
"summary": "鉴定到 15 个 Ft.SPL 基因家族成员",
"metrics": {
"final_members": 15,
"initial_candidates": 120
},
"files": [
"final/Ft.SPL.identify.pep.fa",
"final/Ft.SPL.identify.manifest.json"
]
}
```
---
## 7. ResultParser -> Validator Agent 【关键决策点】
### 输入数据(从 state 获取)
```python
execution_results_list = state.get("execution_results", []) # LIST
parse_result = state.get("parse_result", {})
```
### **Fallback 机制(再次确认)**
如果 `execution_results_list` 为空:
```python
# 再次从 manifest 加载(双重保险)
```
### Validator Agent 处理
1. 检查 `execution_result.status == "success"`
2. 检查输出文件是否存在
3. 检查数据合理性(final_members > 0)
4. 检查 manifest 完整性
### 输出数据(设置到 state)
```python
state["validation_result"] = {
"overall_passed": True, # 或 False
"stage": "identify",
"score": 95.0,
"errors": [], # 如果 overall_passed=False
"warnings": [], # 可能有警告但不影响通过
"summary": "✅ 验证通过,所有检查项正常"
}
```
---
## 8. Validator -> Decision: _validate_decision
### 决策逻辑
```python
def _validate_decision(state: GraphState) -> str:
validation = state.get("validation_result", {})
if validation.get("overall_passed", False):
return "success" # -> Discovery Agent
else:
return "failure" # -> Diagnosis Agent
```
### **关键问题根因**
如果 `validation_result` 为空 `{}`(LangGraph state 传递失败):
- `validation.get("overall_passed", False)` 返回 `False`
- 决策走 `"failure"` -> Diagnosis Agent
- 触发错误诊断 -> retry
---
## 9. Validator(success) -> Discovery Agent
### 输入数据(从 state 获取)
```python
execution_results = state.get("execution_results", [])
parse_result = state.get("parse_result", {})
```
### Discovery Agent 处理
- 分析鉴定结果,生成科学发现报告
- 例如:发现新的 SPL 基因亚家族
### 输出数据(设置到 state)
```python
state["discovery_result"] = {
"findings": ["发现 15 个 SPL 基因,分为 3 个亚家族"],
"should_continue": False, # 是否继续迭代
"updated_plan": None # 如果继续迭代,新的计划
}
```
---
## 10. Discovery -> Decision: _discovery_decision
### 决策逻辑
```python
def _discovery_decision(state: GraphState) -> str:
discovery = state.get("discovery_result", {})
iteration_count = state.get("iteration_count", 0)
max_iterations = state.get("max_iterations", 3)
if iteration_count >= max_iterations:
return "learning"
if discovery.get("should_continue", False):
return "replan" # -> Planning(循环迭代)
else:
return "learning" # -> Learning Agent
```
---
## 11. Discovery -> Learning Agent
### 输入数据(从 state 获取)
```python
execution_results = state.get("execution_results", [])
discovery_result = state.get("discovery_result", {})
```
### Learning Agent 处理
- 记录本次执行的参数、结果
- 更新知识库
- 生成学习总结
### 输出数据(设置到 state)
```python
state["final_output"] = {
"response": "鉴定完成,发现 15 个 SPL 基因",
"artifacts": [
"final/Ft.SPL.identify.pep.fa",
"final/Ft.SPL.identify.manifest.json"
],
"metrics": {...}
}
state["status"] = "completed"
```
---
## 错误处理路径
### Validator 验证失败 -> Diagnosis Agent
### Diagnosis Agent 处理
```python
state["diagnosis_result"] = {
"error_type": "missing_output_file",
"suggested_fix": "检查输入文件路径",
"retry_params": {...}
}
state["retry_count"] += 1
```
### Diagnosis -> Decision: _diagnosis_decision
```python
if retry_count < max_retries:
return "retry" # -> Execution Agent(重新执行)
else:
return "fail" # -> END(失败结束)
```
---
## LangGraph State 传递问题详解
### TypedDict 类型定义(state.py)
```python
class GraphState(TypedDict):
execution_results: list[dict[str, Any]] # LIST 类型(已修复)
validation_result: dict[str, Any] # DICT 类型
...
```
### LangGraph 内部机制
LangGraph 使用 TypedDict 进行类型检查:
1. 节点函数返回 `state`(dict)
2. LangGraph 检查返回值是否符合 TypedDict 定义
3. 如果类型不匹配,可能导致:
- 数据丢失(字段被忽略)
- 类型转换错误
- 默认值覆盖
### 已修复的问题
之前 `execution_results` 定义为 `dict[str, Any]`,但实际使用 `list[dict]`,导致:
- `_execution_node` 设置 list
- `_validator_node` 获取空 `{}` 或 `[]`
- fallback 机制从 manifest 加载(但可能加载失败)
- `_validate_decision` 判断 failure
---
## 数据流转图(简化版)
```
用户输入
↓
[Router] → state["intent_result"] = {stages, prefix, mode}
↓
[Learning Recommend] → state["learning_recommendations"] = {params}
↓
[Planning] → state["plan_result"] = {stages, prefix, workspace}
↓
[PreFlight] → state["preflight_result"] = {valid, issues}
↓
[Execution] → state["execution_results"] = [{stage, result}] ← 关键
↓
[ResultParser] → state["parse_result"] = {summary, metrics} ← 有 fallback
↓
[Validator] → state["validation_result"] = {overall_passed} ← 有 fallback
↓
[_validate_decision] → "success" / "failure"
↓
[Discovery] (success) → state["discovery_result"]
↓
[Learning] → state["final_output"]
↓
END
OR (failure):
[Validator] → "failure"
↓
[Diagnosis] → state["diagnosis_result"] + retry_count++
↓
[_diagnosis_decision] → "retry" (if retry < max) / "fail" (if max reached)
↓
[Execution] (retry) → 重新执行
```
---
## 关键数据类型总结
| 字段名 | 类型 | 设置节点 | 使用节点 |
|--------|------|----------|----------|
| `intent_result` | `dict[str, Any]` | Router | Planning |
| `learning_recommendations` | `dict[str, Any]` | Learning Recommend | Planning |
| `plan_result` | `dict[str, Any]` | Planning | PreFlight, Execution |
| `preflight_result` | `dict[str, Any]` | PreFlight | (记录 errors) |
| `execution_results` | `list[dict[str, Any]]` | Execution | ResultParser, Validator, Diagnosis |
| `parse_result` | `dict[str, Any]` | ResultParser | Validator |
| `validation_result` | `dict[str, Any]` | Validator | _validate_decision |
| `diagnosis_result` | `dict[str, Any]` | Diagnosis | _diagnosis_decision |
| `discovery_result` | `dict[str, Any]` | Discovery | _discovery_decision |
---
## 测试验证步骤
1. 启动 Celery 服务
2. 前端触发 identify 任务
3. 观察 Celery 日志:
- `[Execution] DEBUG: state['execution_results'] set: 1 items`
- `[Validator] ✅ 使用execution_results进行验证`
- `[Validator] overall_passed: True`
4. 检查 `workspace/job_xxx/logs/` 只有 1 个日志文件
5. 前端显示 "执行成功"
+127
View File
@@ -0,0 +1,127 @@
# bbav5 项目记忆 - 决策与踩坑
> 创建时间:2026-03-18 | 最后更新:2026-04-15
>
> 本文件记录**设计决策**和**踩坑经验**,运行时配置见 AGENTS.md
---
## 1. 架构设计决策
### 1.1 三层架构
```
Frontend (Vue3 + FastAPI)
↓
Core Framework (Contracts + Reproducibility + API)
↓
Analysis Execution (CLI Scripts + Skills)
```
**决策理由**: 解耦前端展示与后端执行,契约层保证阶段间数据流转可靠
### 1.2 目录结构规范
```
workspace/{job_id}/
├── final/ # 最终产物(只读,下游依赖)
├── {stage}/analysis/ # 中间文件(可追溯)
├── logs/ # 执行日志
└── input/ # 输入文件(只读)
```
**踩坑**: 早期版本输出到 `{stage}/final/`,下游阶段找不到文件 → 统一为 `final/`
### 1.3 契约化设计
每个阶段契约文件 (`*_contract_v1.md`) 定义:
- **输入契约**: 文件类型、来源
- **输出契约**: final/ 必须产物
- **Manifest 契约**: artifacts 字段最小集
---
## 2. 重大踩坑记录
### 2.1 RNA-seq 环境问题 (2026-03-19)
**问题**: RNA-seq 阶段执行失败,工具找不到
**原因**: 用错了 conda 环境,应该用 `rnaseq` 而非 `test4py311`
**修复**:
- rnaseq_qc/align/quant/de/enrich → `conda activate rnaseq`
- expression 绘图 → `conda activate rnaR`
### 2.2 Manifest 路径问题 (2026-03-27)
**问题**: 前端读取 manifest 失败
**原因**: 返回路径是相对路径,前端无法解析
**修复**: Manifest 必须包含 `full_path` 绝对路径
### 2.3 Agent 意图识别慢 (2026-04-05)
**问题**: RNA-seq 意图识别耗时 16 分钟
**原因**: LLM 调用过多
**修复**: 添加 `fast_intent` 关键词匹配,降至 <5 秒
### 2.4 循环迭代未实现 (2026-04-15)
**问题**: Discovery → Learning 是固定边,无法循环
**原因**: Orchestrator 没有条件边设计
**修复**:
- `langgraph_orchestrator.py` 新增 `iteration_count`, `max_iterations`
- `_discovery_decision()` 决策函数
- 循环逻辑: should_continue → replan → Planning
---
## 3. 关键修复索引
| 日期 | 文件 | 详情 |
|------|------|------|
| 2026-03-27 | memory/2026-03-27.md | RNASEQ_QC 修复 |
| 2026-03-28 | memory/2026-03-28.md | RNASEQ_ALIGN 修复 |
| 2026-03-29 | memory/2026-03-29.md | RNASEQ_QUANT 修复 |
| 2026-03-30 | memory/2026-03-30.md | RNASEQ_DE 修复 |
| 2026-04-03 | memory/2026-04-03.md | Celery 集成 |
| 2026-04-05 | memory/2026-04-05.md | 意图识别优化 |
| 2026-04-06 | memory/2026-04-06.md | PEP/PPI 技能化 |
| 2026-04-07 | memory/2026-04-07.md | 其他修复 |
| 2026-04-15 | 全局 MEMORY | 循环迭代修复 |
---
## 4. 已知问题
| 问题 | 状态 | 备注 |
|------|------|------|
| RouterAgent 第74行 `prompt` 变量 | 待修复 | 应为 `full_prompt` |
| 两个 Orchestrator 并存 | 待重构 | orchestrator.py (2656行) + langgraph_orchestrator.py (638行) |
| _route_query 关键词过多 | 待优化 | 约100个关键词,维护困难 |
---
## 5. 技能化状态
全部 16 个核心阶段已技能化,见 `skills/` 目录
---
## 6. 修订检查清单
- [ ] 是否遵循契约文档 (`*_contract_v1.md`)
- [ ] 输出是否在 `final/` 目录
- [ ] Manifest 是否包含 `full_path`, `size`, `sha256`
- [ ] 是否使用正确的 Conda 环境
- [ ] 是否更新 MEMORY.md 或 memory/*.md
---
*详细日志见 `memory/` 目录*
+22
View File
@@ -0,0 +1,22 @@
# Open Source Exclusion List
This working copy intentionally keeps some local data and history so the project can still be tested before release.
Do not publish these paths without a separate curation pass:
- `.env`
- `.codex/`, `.agents/`, `.cursor/`, `.idea/`
- `input` and `workspace` symlinks
- `data/`
- `项目记录/`
- `paper/`
- `memory/`, `memory_storage/`
- `logs/`, `cost_logs/`, `.runtime/`, `temp/`, `tmp/`, `outputs/`, `final/`
- `backup/`, `backups/`
- generated benchmark, extension golden data, and local report outputs unless explicitly selected
Current release direction:
- Keep runtime compatibility first.
- Move secrets to environment variables and `.env.example`.
- Defer broad `bbav5` to `PlantAI` code renaming until startup and one representative stage have been validated in the copied project.
@@ -0,0 +1,39 @@
"gene","TATA-box","CAAT-box","AT~TATA-box","ABRE","MYC","MYB","G-box","STRE","TGACG-motif","CGTCA-motif","as-1","Box 4","GT1-motif","Myb","ARE","AAGAA-motif","Myb-binding site","G-Box","MYB-like sequence","W box"
"Os01t0104200-01",1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0,1
"Os01t0104500-01",1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0
"Os01t0191300-01",1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,0
"Os01t0261200-01",1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0
"Os01t0393100-02",1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,1,0
"Os01t0672100-02",1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0
"Os01t0675800-01",1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,0,1,1,1
"Os01t0816100-01",1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1
"Os01t0862800-01",1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,0,0,1
"Os01t0884300-01",1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1
"Os01t0888300-01",1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0
"Os01t0925400-01",1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1
"Os01t0946200-01",1,1,0,1,1,1,1,1,1,1,1,0,0,0,0,1,1,0,1,1
"Os02t0214500-01",1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0
"Os02t0252200-01",1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,0,1,0,1,1
"Os02t0285900-00",1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1
"Os02t0555300-01",1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1
"Os02t0579000-02",1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1
"Os02t0594800-01",1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0
"Os02t0643600-00",1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,0,1,1,1,0
"Os02t0745250-00",1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
"Os02t0810900-01",1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,0
"Os02t0822400-01",1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1
"Os03t0109000-01",1,1,1,1,1,1,1,1,0,0,0,1,1,0,1,0,1,0,0,1
"Os03t0119966-01",1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1
"Os03t0133000-01",1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,0
"Os03t0327100-01",1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1
"Os03t0327800-01",1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0
"Os03t0624600-01",1,1,1,1,1,1,1,0,0,0,0,1,0,1,0,0,0,1,0,1
"Os03t0777000-01",1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0
"Os03t0815100-01",1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,0,1,1,0,0
"Os04t0437000-01",1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0
"Os07t0225300-01",1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1
"Os07t0272700-00",1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1
"Os07t0456900-01",1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,0,0,0
"Os07t0566500-01",1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,0,1,0,0,1
"Os07t0683200-01",1,1,1,1,1,0,1,1,1,1,1,1,0,1,0,0,0,1,0,0
"Os07t0684800-02",1,1,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0
1 gene TATA-box CAAT-box AT~TATA-box ABRE MYC MYB G-box STRE TGACG-motif CGTCA-motif as-1 Box 4 GT1-motif Myb ARE AAGAA-motif Myb-binding site G-Box MYB-like sequence W box
2 Os01t0104200-01 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 0 1
3 Os01t0104500-01 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 0
4 Os01t0191300-01 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 1 0
5 Os01t0261200-01 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
6 Os01t0393100-02 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 0 1 1 0
7 Os01t0672100-02 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0
8 Os01t0675800-01 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 0 1 1 1
9 Os01t0816100-01 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1
10 Os01t0862800-01 1 1 1 1 1 0 1 0 1 1 1 1 0 1 1 0 0 0 0 1
11 Os01t0884300-01 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 0 1 1 1
12 Os01t0888300-01 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 0 0
13 Os01t0925400-01 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 1
14 Os01t0946200-01 1 1 0 1 1 1 1 1 1 1 1 0 0 0 0 1 1 0 1 1
15 Os02t0214500-01 1 1 1 1 1 1 1 0 1 1 1 1 0 0 1 1 1 1 0 0
16 Os02t0252200-01 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 0 1 1
17 Os02t0285900-00 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 0 1 1 1
18 Os02t0555300-01 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1
19 Os02t0579000-02 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 1 1 1
20 Os02t0594800-01 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 0
21 Os02t0643600-00 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 0
22 Os02t0745250-00 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
23 Os02t0810900-01 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0
24 Os02t0822400-01 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 0 1 1
25 Os03t0109000-01 1 1 1 1 1 1 1 1 0 0 0 1 1 0 1 0 1 0 0 1
26 Os03t0119966-01 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1
27 Os03t0133000-01 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 0
28 Os03t0327100-01 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1
29 Os03t0327800-01 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 0
30 Os03t0624600-01 1 1 1 1 1 1 1 0 0 0 0 1 0 1 0 0 0 1 0 1
31 Os03t0777000-01 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 1 0 1 0
32 Os03t0815100-01 1 1 1 1 0 1 1 1 1 1 1 0 0 1 1 0 1 1 0 0
33 Os04t0437000-01 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0
34 Os07t0225300-01 1 1 1 0 1 1 1 1 1 1 1 0 1 1 0 1 1 0 1 1
35 Os07t0272700-00 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 0 1 1
36 Os07t0456900-01 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 0 1 0 0 0
37 Os07t0566500-01 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 0 1 0 0 1
38 Os07t0683200-01 1 1 1 1 1 0 1 1 1 1 1 1 0 1 0 0 0 1 0 0
39 Os07t0684800-02 1 1 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0
+105
View File
@@ -0,0 +1,105 @@
# Plan Review Log: PPI stage-local STRING ID resolution
Act 1 discussion complete — plan locked with the user. MAX_ROUNDS=5.
## Phase 0 evidence consolidation
### Local code inventory
- `skills/ppi/run.py` currently strips versions in both Ortholog and direct paths, has no `get_string_ids`, writes `probe_status=not_run`, and conflates network API errors with `[]`.
- `apps/web/pipeline_backend.py` creates `pep_cds_idmap.tsv`, but stores `LOC...` in `gene_id`; numeric NCBI GeneID exists only inside `cds_header`.
- PPI main and PPI Reset are separate backend entry points and both must pass the same ID evidence.
- Existing AlphaFold link generation already prefers `string_id`, so a populated resolution report can be reused.
- Existing frontend can preview the TSV; direct metric labels are an enhancement required by the approved acceptance criteria.
### Official STRING API evidence
- Official docs: https://string-db.org/help/api/ and fixed v12 docs: https://version-12-0.string-db.org/help/api/.
- `get_string_ids` returns one best STRING match per input; `limit` is not a supported parameter.
- Use `queryIndex` rather than response order; unresolved inputs are omitted.
- All-unresolved `get_string_ids` has been observed/documented as HTTP 200 with `[]` or HTTP 404; network can also return 404 for unusable inputs. Endpoint, response shape, and request state—not status alone—must drive classification.
- `network` should explicitly set `add_nodes=0` for input-only family networks.
- Validate score, network type, taxon, and non-empty identifiers client-side.
- Version response currently uses `stable_address`; client should also tolerate documented `string_stable_address`.
- Official guidance recommends POST for lists, `caller_identity`, stable-version URLs, and at least one second between requests.
## Round 1 — Codex
The biological direction is sound—canonical IDs remain immutable, Ortholog remains a relationship, GeneID is a valid job-local bridge, partial mapping is distinguishable from an empty network, and the scope excludes unrelated Ortholog/KaKs redesign. However, the plan is not implementation-ready.
Blocking changes:
1. Close the PPI Reset identity and scope path.
- Reset currently reloads Ft canonical IDs but does not carry the Ft→soe Ortholog relationship; the soe alias map alone is insufficient.
- Carry the exact scoped Ortholog file and verified ID map into Reset, select the exact scoped source manifest, constrain client-supplied paths, declare Reset input namespace, and test real Ft→soe Reset wiring.
2. Make provenance cardinality explicit before deduplication.
- The real job has 24 Ft canonical members, 12 unique soe reference queries, and many-to-one relationships. Preserve every canonical→reference path and deduplicate only final STRING network queries.
- Cover conflicting references, versionless collisions, conflicting GeneIDs, and mixed-species ID-map rows.
3. Define metric denominators and exact manifest locations.
- Distinguish canonical members, Ortholog relationships, unique reference queries, resolved STRING queries, returned network nodes, and edges.
- Main, scoped, and Reset manifests must expose the same scientific metrics; frontend tests must assert values, not label presence only.
4. Reconcile partial mapping with `evaluate_string_mapping_quality()`.
- Partial nonzero resolution must be nonterminal; zero resolution must fail; ambiguous entries must be excluded.
5. Lock the STRING HTTP state machine.
- Handle all-unresolved `404` and `200 []`, validate `queryIndex` and taxon, test throttling, always send `add_nodes=0`, and distinguish stable scientific endpoints from optional visualization endpoints.
6. Specify header-only empty-network artifacts and persisted failure manifests, including CLI exit codes.
7. Expand validation to scoped Reset, exact manifest selection, cross-job/species rejection, Reset APIs, stage status, 24→12 provenance, and manifest equivalence.
VERDICT: REVISE
### Codex's response
Accepted all seven blockers because each is supported by current code or real-job evidence and remains inside the approved PPI-first boundary. The revised plan will:
- make Reset canonical-target-only, scope-bound, and dependent on both the exact Ortholog relationship and species-matched alias map;
- introduce an explicit per-canonical relationship record and retain 24 provenance rows before 12-query deduplication;
- replace ambiguous metrics with nested, denominator-defined ID-resolution and network metrics shared by main/scoped/Reset manifests;
- retire the old terminal low-rate threshold in favor of complete/partial/failed resolution states;
- define the STRING response validator, request pacing, empty-network TSV schema, failure manifests, exit codes, and expanded API/real-data validation.
The optional STRING image/link endpoint will remain explicitly non-authoritative visualization evidence if it cannot use the same stable version endpoint; it will not determine scientific stage status.
## Round 2 — Codex
The revision closes the original seven blocker groups in substance. Four material issues remain:
1. `query_mapping_rate` uses the wrong numerator when multiple reference queries converge on one STRING entity. Add `resolved_reference_query_count`; keep `selected_string_query_count` as the deduplicated network-query count and test two references converging on one STRING ID.
2. Reset needs race-safe evidence snapshots and a separate direct-target policy. Snapshot and re-hash canonical input, Ortholog mapping, and ID map inside the isolated Reset directory before launch; validate direct-target IDs against the recorded canonical member set.
3. Cross-process STRING pacing is not yet testably specified. PPI uses a light queue with concurrency four, so choose a shared interprocess gate or a dedicated single-concurrency queue and test it.
4. Contract/failure validation is incomplete. Explicitly test persisted failed manifests and backend/status exposure for CLI exits 2/3/4; synchronize `skills/ppi/config.yaml`; decide whether `network_type` is fixed or configurable; replace the stale flat metric schema in the project record.
VERDICT: REVISE
### Codex's response
Accepted all four findings.
- Add `resolved_reference_query_count` and use it for query mapping rate/status; network-query deduplication remains a separate count.
- Record the canonical input hash and make Reset execute from verified snapshots copied into its isolated directory. Projected Reset validates against Ortholog sources; direct-target Reset validates against the recorded canonical member set.
- Use a host-shared `fcntl.flock` + timestamp file gate for all stable STRING version/mapping/network requests across main and Reset processes; production interval remains one second and a short-interval multiprocessing test proves serialization.
- Add backend/status failure-manifest tests, synchronize `skills/ppi/config.yaml`, and keep this phase's PPI analysis fixed to `network_type=functional` to avoid unrelated request/UI expansion. Update the original project-record metric section to the nested schema.
## Round 3 — Codex
Round 2 is almost fully closed. Two material blockers remain:
1. The shared STRING rate gate excludes automatic image requests; route every fallback attempt through the same interprocess gate or disable retrieval, and test a scientific request concurrent with an image request.
2. The direct-target Reset rule conflicts with a following blanket rule requiring all added IDs to be Ortholog sources; qualify that rule as projected-only.
VERDICT: REVISE
### Codex's response
Accepted both findings. The detailed plan now places the host-shared gate in `gfa_core.string_rate_gate` and requires every active PPI-path STRING HTTP call—including each optional image/SVG fallback—to use it with the same caller identity. The multiprocessing suite combines scientific and image callers. The Ortholog-source requirement is explicitly projected-Reset-only; direct-target Reset accepts only IDs present in the recorded canonical snapshot.
## Round 4 — Codex
All prior blockers are closed.
- `gfa_core.string_rate_gate` is the single host-shared gate for version, mapping, network, and every image/SVG fallback in main and Reset, with aligned caller identity and mixed scientific-plus-image multiprocessing coverage.
- Projected Reset additions must be Ortholog sources; direct-target Reset accepts only IDs from its recorded canonical snapshot. The rules and tests no longer conflict.
- The earlier metric, snapshot, failure-manifest, configuration, network-type, and validation findings remain closed.
Non-blocking caution: the `fcntl` gate is intentionally host-local; a future multi-host worker deployment would require a distributed gate.
VERDICT: APPROVED
+44
View File
@@ -0,0 +1,44 @@
# Plan: PPI stage-local STRING ID resolution on a reusable job-local alias core
_Locked via discussion — Codex + user_
## Goal
Preserve canonical family-member IDs while making PPI resolve target/reference protein IDs through job-local PEP/CDS evidence and the official STRING `get_string_ids` API before network lookup, with explicit provenance and a correct distinction between ID failure, external API failure, and a successful empty network.
## Approach
1. Add a small reusable `gfa_core.id_resolution` module that reads job-local alias evidence and extracts RefSeq protein accession, LOC symbol, and numeric NCBI GeneID without performing network calls.
2. Extend future reference-bundle ID maps with an explicit `ncbi_gene_id` column while remaining compatible with existing maps by parsing `cds_header`.
3. Add typed STRING API methods for `get_string_ids`, `network`, and `version`; use the returned stable version address, POST identifier lists, include `caller_identity`, respect STRING's request interval, and raise structured errors instead of returning an empty list.
4. Replace lossy query lists with explicit relationship records that retain every `canonical target -> versioned Ortholog reference` path; probe raw and GeneID candidates, then deduplicate only the final STRING network query set.
5. Pass the canonical input, exact scope-matched Ortholog relationship, and species-matched job-local ID map through main PPI and PPI Reset. Reset accepts canonical target IDs only, is bound to an exact source `scope_id`, snapshots verified evidence before launch, and rejects undeclared/mixed namespaces or paths outside the job; direct-target Reset validates against its canonical member snapshot without requiring Ortholog.
6. Replace the old terminal mapping-rate threshold with `complete`, nonterminal `partial`, and terminal `failed` resolution states; exclude ambiguous members from network queries.
7. Synchronize the PPI contract, skill docs, persisted success/failure manifests, diagnosis, status, and frontend labels using denominator-defined nested metrics shared by main, scoped, and Reset outputs.
8. Validate with unit/contract/API tests and the full real `Ft.SPL -> soe` job: 24 canonical provenance paths, 12 unique STRING queries, 12/12 query resolution, and `success + empty_network` for zero edges; repeat the scoped Reset path.
## Key decisions & tradeoffs
- Canonical `final_members` IDs are immutable; all external IDs are stage-local aliases.
- Ortholog relationships are not aliases.
- The first release uses the existing job-local `pep_cds_idmap.tsv` plus a reusable parser, not a global database or SQLite registry.
- STRING-specific HTTP probing remains in the PPI adapter; generic local alias extraction lives in `gfa_core`.
- STRING returns one best match per submitted candidate. If different local candidates for one biological query resolve to different STRING IDs, the query is conflicting/ambiguous and is not silently selected.
- Resolution evidence has one summary row per canonical-to-reference relationship. Many canonical members may share one network query; deduplication never removes their provenance rows.
- Query resolution and network deduplication are separate metrics: every reference query may resolve even when several converge on one submitted STRING ID.
- Partial nonzero ID resolution proceeds with a warning; zero resolved IDs block PPI. The old minimum-count/rate failure threshold is retired for execution decisions.
- A normal zero-edge response is success with `network_status=empty_network`; API failure is a separate failure.
- Empty networks still emit a header-only `protein1/protein2/score` TSV and a success manifest. Zero resolution and API failures emit failed manifests and nonzero CLI exits.
- STRING mapping/network calls use one stable version and validated `queryIndex`/taxon responses. Optional public web/image links are labeled non-authoritative if they are not version-pinned.
## Risks / open questions
- STRING mapping aliases and database versions change; every probe must record taxon, version, and evidence.
- Existing ID maps lack `ncbi_gene_id`; legacy header parsing must be covered by tests.
- Existing PPI code strips protein versions before resolution; exact versions remain primary and versionless forms are lookup aliases only.
- PPI Reset currently selects a generic manifest first, accepts a client path, and loses the Ortholog relationship. Its scope/namespace contract must be corrected with the main path.
- Direct-target PPI jobs may not have a reference-bundle ID map and must still work through raw-ID probing.
- Every active PPI-path STRING HTTP request—including optional image fallbacks—uses one shared interprocess lock/timestamp gate because the light queue can run multiple workers; unit and multiprocessing tests cover the one-second production rule.
- The repository has no usable Git metadata, so commit checkpoints cannot be executed in this workspace.
## Out of scope
- Ortholog/KaKs reference-state fixes and immutable scoped Ortholog artifacts.
- Migration of expression, enrichment, synteny, or other consumers.
- Global cross-job ID databases.
- Rewriting `final_members`, Ortholog, or KaKs algorithms.
- Treating a valid empty PPI network as failure.
+132
View File
@@ -0,0 +1,132 @@
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848643/SRR8848643_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848643/SRR8848643_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848644/SRR8848644_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848644/SRR8848644_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848646/SRR8848646_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848646/SRR8848646_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848647/SRR8848647_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848647/SRR8848647_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848650/SRR8848650_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848650/SRR8848650_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848651/SRR8848651_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848651/SRR8848651_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848654/SRR8848654_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848654/SRR8848654_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848660/SRR8848660_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848660/SRR8848660_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848661/SRR8848661_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848661/SRR8848661_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848663/SRR8848663_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848663/SRR8848663_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848666/SRR8848666_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848666/SRR8848666_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848669/SRR8848669_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848669/SRR8848669_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848671/SRR8848671_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848671/SRR8848671_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848673/SRR8848673_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848673/SRR8848673_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848674/SRR8848674_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848674/SRR8848674_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848677/SRR8848677_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848677/SRR8848677_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848682/SRR8848682_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848682/SRR8848682_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848683/SRR8848683_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848683/SRR8848683_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848685/SRR8848685_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848685/SRR8848685_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848700/SRR8848700_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848700/SRR8848700_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848701/SRR8848701_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848701/SRR8848701_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848707/SRR8848707_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848707/SRR8848707_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848648/SRR8848648_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848648/SRR8848648_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848652/SRR8848652_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848652/SRR8848652_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848653/SRR8848653_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848653/SRR8848653_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848656/SRR8848656_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848656/SRR8848656_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848658/SRR8848658_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848658/SRR8848658_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848659/SRR8848659_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848659/SRR8848659_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848664/SRR8848664_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848664/SRR8848664_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848665/SRR8848665_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848665/SRR8848665_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848667/SRR8848667_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848667/SRR8848667_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848668/SRR8848668_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848668/SRR8848668_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848670/SRR8848670_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848670/SRR8848670_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848675/SRR8848675_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848675/SRR8848675_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848676/SRR8848676_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848676/SRR8848676_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848679/SRR8848679_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848679/SRR8848679_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848680/SRR8848680_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848680/SRR8848680_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848681/SRR8848681_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848681/SRR8848681_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848684/SRR8848684_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848684/SRR8848684_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848687/SRR8848687_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848687/SRR8848687_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848688/SRR8848688_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848688/SRR8848688_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848696/SRR8848696_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848696/SRR8848696_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848703/SRR8848703_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848703/SRR8848703_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848704/SRR8848704_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848704/SRR8848704_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848705/SRR8848705_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848705/SRR8848705_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848708/SRR8848708_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848708/SRR8848708_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848645/SRR8848645_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848645/SRR8848645_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848649/SRR8848649_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848649/SRR8848649_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848655/SRR8848655_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848655/SRR8848655_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848657/SRR8848657_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848657/SRR8848657_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848662/SRR8848662_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848662/SRR8848662_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848672/SRR8848672_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848672/SRR8848672_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848678/SRR8848678_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848678/SRR8848678_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848686/SRR8848686_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848686/SRR8848686_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848689/SRR8848689_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848689/SRR8848689_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848690/SRR8848690_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848690/SRR8848690_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848691/SRR8848691_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848691/SRR8848691_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848692/SRR8848692_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848692/SRR8848692_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848693/SRR8848693_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848693/SRR8848693_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848694/SRR8848694_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848694/SRR8848694_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848695/SRR8848695_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848695/SRR8848695_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848697/SRR8848697_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848697/SRR8848697_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848698/SRR8848698_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848698/SRR8848698_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848699/SRR8848699_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848699/SRR8848699_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848702/SRR8848702_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848702/SRR8848702_2.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848706/SRR8848706_1.fastq.gz
https://ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848706/SRR8848706_2.fastq.gz
+67
View File
@@ -0,0 +1,67 @@
run_accession sample_accession experiment_accession scientific_name fastq_ftp fastq_aspera fastq_bytes fastq_md5
SRR8848643 SAMN11337804 SRX5636394 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848643/SRR8848643_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848643/SRR8848643_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848643/SRR8848643_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848643/SRR8848643_2.fastq.gz 1782934223;1830571017 b26072fcc2e333fe0d533c929b1c9102;054e112c5b9973fdf0f946660848e201
SRR8848644 SAMN11337803 SRX5636393 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848644/SRR8848644_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848644/SRR8848644_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848644/SRR8848644_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848644/SRR8848644_2.fastq.gz 2001541510;2070167348 2bea98a03b238eb0be650d54688a263f;050bbfd7a60c05b0f8e350aef11a492d
SRR8848646 SAMN11337801 SRX5636391 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848646/SRR8848646_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848646/SRR8848646_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848646/SRR8848646_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848646/SRR8848646_2.fastq.gz 1984198211;2061538651 dc935c4ffc93dbec97fc3ec221fa18f4;0eb3dcbeeb55f95becc2db070cd1b982
SRR8848647 SAMN11337800 SRX5636390 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848647/SRR8848647_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848647/SRR8848647_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848647/SRR8848647_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848647/SRR8848647_2.fastq.gz 2204461915;2273561396 4619d5d79c772207d7049220e7ab00c2;da22c00d6a052a42c654cef7331cfae6
SRR8848650 SAMN11337797 SRX5636387 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848650/SRR8848650_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848650/SRR8848650_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848650/SRR8848650_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848650/SRR8848650_2.fastq.gz 2115902642;2208045149 1b24550c7233ef5a463a277015407f73;a157b359e7cf7de58c2792bdc73c61d4
SRR8848651 SAMN11337806 SRX5636386 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848651/SRR8848651_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848651/SRR8848651_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848651/SRR8848651_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848651/SRR8848651_2.fastq.gz 2311801550;2387651849 2c5d795003281ae686f6eca00307316e;37995ab807fcd1b806b0b9f81987ce90
SRR8848654 SAMN11337748 SRX5636383 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848654/SRR8848654_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848654/SRR8848654_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848654/SRR8848654_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848654/SRR8848654_2.fastq.gz 1476361305;1498189478 dacc1de38b9fcbda988442469569e25e;cf84b840bd68d68cf9a9a77a4d3522d2
SRR8848660 SAMN11337754 SRX5636377 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848660/SRR8848660_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848660/SRR8848660_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848660/SRR8848660_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848660/SRR8848660_2.fastq.gz 1809304913;1858544862 bea59c4c919bf27cc96e20c4048fee38;459da78b70f5fb8d77009c792a0e59e3
SRR8848661 SAMN11337753 SRX5636376 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848661/SRR8848661_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848661/SRR8848661_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848661/SRR8848661_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848661/SRR8848661_2.fastq.gz 1666930682;1690513285 59c7a8bf3f744c9e1b48a011946ab8d6;96f5b3066238416f331b2401ccf4ac48
SRR8848663 SAMN11337755 SRX5636374 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848663/SRR8848663_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848663/SRR8848663_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848663/SRR8848663_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848663/SRR8848663_2.fastq.gz 1539461717;1578574622 5d6b4cbdf01b3f682a6730750442f359;a9279b71b57f6535190263045bbffeee
SRR8848666 SAMN11337767 SRX5636371 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848666/SRR8848666_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848666/SRR8848666_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848666/SRR8848666_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848666/SRR8848666_2.fastq.gz 1912731347;1968907180 4d4167490d1504f1760f28d14efb2c80;1ccae37fb0c5e358c83848dbd4830c0f
SRR8848669 SAMN11337774 SRX5636368 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848669/SRR8848669_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848669/SRR8848669_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848669/SRR8848669_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848669/SRR8848669_2.fastq.gz 1145867352;1172095259 dfd95e68619664390e96878a79964e1e;ee8bad036e4be9233e3baf2bbff408a1
SRR8848671 SAMN11337772 SRX5636366 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848671/SRR8848671_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848671/SRR8848671_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848671/SRR8848671_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848671/SRR8848671_2.fastq.gz 1548725431;1570182025 90a471fab4860a1c8699963d7dc0d126;c708bfefd591fc6a6f6a4b7085afcc88
SRR8848673 SAMN11337776 SRX5636364 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848673/SRR8848673_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848673/SRR8848673_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848673/SRR8848673_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848673/SRR8848673_2.fastq.gz 1690871660;1718015156 13fb80274c68d5ed80c3a9ded6d90496;f58848cdeb0b8ad3d242acdf65470636
SRR8848674 SAMN11337809 SRX5636363 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848674/SRR8848674_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848674/SRR8848674_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848674/SRR8848674_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848674/SRR8848674_2.fastq.gz 2320915229;2388088536 4c8339d47128e73d08b997a8ac044e00;ede054b96fbd56f44098cdfb282c61ce
SRR8848677 SAMN11337808 SRX5636360 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848677/SRR8848677_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848677/SRR8848677_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848677/SRR8848677_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848677/SRR8848677_2.fastq.gz 2087541740;2172309980 14d5977ff638a5b4db03c602f4f3ab77;654f95ef28ed5a4c9d37685d16126d99
SRR8848682 SAMN11337791 SRX5636355 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848682/SRR8848682_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848682/SRR8848682_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848682/SRR8848682_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848682/SRR8848682_2.fastq.gz 1187095863;1199975571 cec23987cc0d4024a910912c7a169d9e;d8981aec73376759ba39f70b5e0e786f
SRR8848683 SAMN11337792 SRX5636354 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848683/SRR8848683_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848683/SRR8848683_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848683/SRR8848683_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848683/SRR8848683_2.fastq.gz 2079870389;2160198814 da8e96ef76e7b24dd672112840ba1c26;d565429dc2a008168f4294af31da2620
SRR8848685 SAMN11337794 SRX5636352 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848685/SRR8848685_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848685/SRR8848685_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848685/SRR8848685_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848685/SRR8848685_2.fastq.gz 2774481031;2886218941 97dcc3519cfdb97909f7588b2e612a52;216964ff90a4d35505756acdd806ff61
SRR8848700 SAMN11337783 SRX5636337 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848700/SRR8848700_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848700/SRR8848700_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848700/SRR8848700_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848700/SRR8848700_2.fastq.gz 1372886855;1394968651 b5a3c3c9a9e8bd3510c129a27c66a8f2;37a84cccd50e1340d50942c5fa674c6f
SRR8848701 SAMN11337760 SRX5636336 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848701/SRR8848701_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848701/SRR8848701_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848701/SRR8848701_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848701/SRR8848701_2.fastq.gz 2124530505;2191298837 de89cf7f50b9cea74f81f0b657ca6525;0d280315f0fabd212aa430f51a6cc9d5
SRR8848707 SAMN11337762 SRX5636330 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848707/SRR8848707_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848707/SRR8848707_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848707/SRR8848707_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848707/SRR8848707_2.fastq.gz 1687339155;1763483173 b078557d3c771844bc7770f621c88c28;3eac660d66a5451abcc6c96babc7772e
SRR8848648 SAMN11337799 SRX5636389 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848648/SRR8848648_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848648/SRR8848648_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848648/SRR8848648_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848648/SRR8848648_2.fastq.gz 2264781136;2318739364 2711bcb8ce95199851da26d857786041;8820e70e2d2f4743c612de6996d4d8ed
SRR8848652 SAMN11337805 SRX5636385 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848652/SRR8848652_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848652/SRR8848652_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848652/SRR8848652_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848652/SRR8848652_2.fastq.gz 2263622227;2391628166 49cb8a119a22bece66f5e8d2d454ef0e;6d574b7fcaf217fa08bddd6908004980
SRR8848653 SAMN11337779 SRX5636384 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848653/SRR8848653_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848653/SRR8848653_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848653/SRR8848653_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848653/SRR8848653_2.fastq.gz 1488132126;1551329597 02eb2ce858918e726d55914666698f01;b35c3bf49aef36c9e62f84e729f6f1a0
SRR8848656 SAMN11337750 SRX5636381 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848656/SRR8848656_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848656/SRR8848656_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848656/SRR8848656_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848656/SRR8848656_2.fastq.gz 1879123849;1933796633 7c303624010c50bdd6d25c1157b60349;fdc66249343ad7bfbf67e5259ae83289
SRR8848658 SAMN11337752 SRX5636379 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848658/SRR8848658_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848658/SRR8848658_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848658/SRR8848658_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848658/SRR8848658_2.fastq.gz 1667996507;1689627600 8d1aae2d46a4bf729ab770952d81db77;7d46fabad583afac562d7ec9aef9c053
SRR8848659 SAMN11337751 SRX5636378 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848659/SRR8848659_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848659/SRR8848659_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848659/SRR8848659_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848659/SRR8848659_2.fastq.gz 1559089847;1594535543 4fe4ef76062633930d42ea03d0bdc6ab;3c1c157f791d027fbcd0ab4c4e1e5858
SRR8848664 SAMN11337769 SRX5636373 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848664/SRR8848664_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848664/SRR8848664_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848664/SRR8848664_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848664/SRR8848664_2.fastq.gz 1956539508;2033420631 e02d80e0006f7778e3f402ed3779870f;22878b54f5851270678e3aca687da556
SRR8848665 SAMN11337770 SRX5636372 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848665/SRR8848665_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848665/SRR8848665_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848665/SRR8848665_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848665/SRR8848665_2.fastq.gz 1878427472;1923206394 304e45abeeba16a1739128cc3c1156ab;8428ccc1c85e4006d524946369bc4c60
SRR8848667 SAMN11337768 SRX5636370 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848667/SRR8848667_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848667/SRR8848667_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848667/SRR8848667_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848667/SRR8848667_2.fastq.gz 2149895254;2222572883 0a39c17507c169dc379211d1b3868e28;3f96774f5208e9c47b28bf555e1e2a8a
SRR8848668 SAMN11337773 SRX5636369 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848668/SRR8848668_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848668/SRR8848668_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848668/SRR8848668_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848668/SRR8848668_2.fastq.gz 1418696788;1467067643 2721de0a3b2c7c2e8f3017859c03683a;a0d20fe7de22b291227fe31df492111f
SRR8848670 SAMN11337771 SRX5636367 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848670/SRR8848670_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848670/SRR8848670_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848670/SRR8848670_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848670/SRR8848670_2.fastq.gz 1686570635;1709827942 cf30740a4fd0235a38940e4d5cb0d1bf;53d8994de45fe89f54d86bf31c6b5234
SRR8848675 SAMN11337810 SRX5636362 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848675/SRR8848675_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848675/SRR8848675_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848675/SRR8848675_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848675/SRR8848675_2.fastq.gz 1995941748;2057871919 a440c5a07fe954d7cd1af86b255ef30b;9fb3bd1ac55e7946aacf5b24161ad7f8
SRR8848676 SAMN11337807 SRX5636361 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848676/SRR8848676_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848676/SRR8848676_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848676/SRR8848676_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848676/SRR8848676_2.fastq.gz 1821584546;1895162039 c1d2c314075ff3f87fed83d2cf416469;c8d13ecc6b93761572cf06123b74034f
SRR8848679 SAMN11337788 SRX5636358 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848679/SRR8848679_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848679/SRR8848679_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848679/SRR8848679_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848679/SRR8848679_2.fastq.gz 1679278498;1737494099 884f39f1ddc821b39aa8783ddf441870;f348b5a2b23263b2531cfd55a1c26b44
SRR8848680 SAMN11337789 SRX5636357 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848680/SRR8848680_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848680/SRR8848680_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848680/SRR8848680_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848680/SRR8848680_2.fastq.gz 1379856238;1418109883 60c96db9eb9b6986544b06ae5aaec432;12a5a1653c1e006a25352bf96cf3e99e
SRR8848681 SAMN11337790 SRX5636356 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848681/SRR8848681_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848681/SRR8848681_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848681/SRR8848681_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848681/SRR8848681_2.fastq.gz 1127276562;1156220721 fdc36451b647696e92f85aa7653090ce;870dc23aa93f60f8a4d210141a8a14c4
SRR8848684 SAMN11337793 SRX5636353 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848684/SRR8848684_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848684/SRR8848684_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848684/SRR8848684_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848684/SRR8848684_2.fastq.gz 2231324712;2333517319 c500975019671e6113927cb53d60ae07;58b69b13c5e137a4b95b2cc2a4c3f4e1
SRR8848687 SAMN11337796 SRX5636350 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848687/SRR8848687_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848687/SRR8848687_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848687/SRR8848687_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848687/SRR8848687_2.fastq.gz 2058947935;2119565084 43fc01ed05a259e8ec6d0cf4dbef09e6;8a7e6a9ee1392fbdc2d12e6f9eaaa363
SRR8848688 SAMN11337780 SRX5636349 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848688/SRR8848688_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848688/SRR8848688_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848688/SRR8848688_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848688/SRR8848688_2.fastq.gz 1565579800;1617577226 fe17c6acc80740f815ceb3801595f91e;b311f3d120502a072d0cd93db1c0e273
SRR8848696 SAMN11337765 SRX5636341 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848696/SRR8848696_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848696/SRR8848696_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848696/SRR8848696_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848696/SRR8848696_2.fastq.gz 1931122606;2035132065 e60772cb7e3b3a8e80656969c569a7ad;1b1616db0bb1eb249b14d8977716f6f1
SRR8848703 SAMN11337758 SRX5636334 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848703/SRR8848703_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848703/SRR8848703_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848703/SRR8848703_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848703/SRR8848703_2.fastq.gz 2071230622;2132208247 462a1cd5ca4d3cf29357918c0483abe3;d943ef2aa067607fd3a449c6a61bc83f
SRR8848704 SAMN11337757 SRX5636333 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848704/SRR8848704_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848704/SRR8848704_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848704/SRR8848704_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848704/SRR8848704_2.fastq.gz 1666632491;1711740253 ad18df5652381aaeb402fae07bef1328;c69078be2456c61fafc057c769f14fc3
SRR8848705 SAMN11337764 SRX5636332 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848705/SRR8848705_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848705/SRR8848705_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848705/SRR8848705_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848705/SRR8848705_2.fastq.gz 1883984821;2069941891 44b22e866f409e1481a0f70c949d75a6;eb72c15d35fbfd4faeeb0430e7ac7fd5
SRR8848708 SAMN11337761 SRX5636329 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848708/SRR8848708_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848708/SRR8848708_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848708/SRR8848708_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848708/SRR8848708_2.fastq.gz 1013578999;1042446524 c33b60961d1b7835e7bccd5ea4e2f5ab;882f5f9cb464731f425b372bbdf4772f
SRR8848645 SAMN11337802 SRX5636392 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848645/SRR8848645_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848645/SRR8848645_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848645/SRR8848645_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848645/SRR8848645_2.fastq.gz 1922835863;2015905496 5786510d6ba4ae5599901a69a9894f77;b072062a9b7a68546c2b3ef88311bb3e
SRR8848649 SAMN11337798 SRX5636388 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848649/SRR8848649_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848649/SRR8848649_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848649/SRR8848649_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848649/SRR8848649_2.fastq.gz 2073317600;2127749911 96a017c7e578f7310a2fb67729f89ec5;15183c01449e35823fa055978fc75d9a
SRR8848655 SAMN11337747 SRX5636382 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848655/SRR8848655_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848655/SRR8848655_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848655/SRR8848655_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848655/SRR8848655_2.fastq.gz 1327800889;1387848758 6caa0fd729a96c39772d259235b00d11;6c26d13e91684dd082aed2a56a874ce5
SRR8848657 SAMN11337749 SRX5636380 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848657/SRR8848657_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848657/SRR8848657_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848657/SRR8848657_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848657/SRR8848657_2.fastq.gz 1653315959;1703251646 5fd16ccd6a9d57ca853ddd6f97a22831;df4d10dc916d0b3234fa5c881c91daf5
SRR8848662 SAMN11337756 SRX5636375 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848662/SRR8848662_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848662/SRR8848662_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848662/SRR8848662_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848662/SRR8848662_2.fastq.gz 6568578209;6874588835 3ad1f0966ed5e9565e0463fc82ec0936;6d3243f8f1fd5627db1b54364a2a2ab8
SRR8848672 SAMN11337775 SRX5636365 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848672/SRR8848672_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848672/SRR8848672_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848672/SRR8848672_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848672/SRR8848672_2.fastq.gz 1739872275;1787985299 8c3a8695e92c5f7ccafa5d5e9aec350d;29501db7a5831f53dd517419a3c73208
SRR8848678 SAMN11337787 SRX5636359 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848678/SRR8848678_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848678/SRR8848678_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848678/SRR8848678_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848678/SRR8848678_2.fastq.gz 1475469990;1502409453 a17597c6e22a24bc1025bd6caeceb2b5;fd3fa32d3202deea680ac78d5773dee9
SRR8848686 SAMN11337795 SRX5636351 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848686/SRR8848686_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848686/SRR8848686_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848686/SRR8848686_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848686/SRR8848686_2.fastq.gz 2507215057;2581073697 103dc4b16778b22693fc65b82f169d28;5de80031628795e7064b18d6044befa0
SRR8848689 SAMN11337786 SRX5636348 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848689/SRR8848689_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848689/SRR8848689_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848689/SRR8848689_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848689/SRR8848689_2.fastq.gz 1565094637;1593673954 bd12862bc8c1bdee2e6a77922afe09b6;72aef58ba433713e69bdbd407f344f2b
SRR8848690 SAMN11337785 SRX5636347 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848690/SRR8848690_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848690/SRR8848690_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848690/SRR8848690_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848690/SRR8848690_2.fastq.gz 1467572786;1537289083 88adffd0fb2e53f6cf69258e4e2e9328;46818cfd20f9f564ef38c510e02e3513
SRR8848691 SAMN11337811 SRX5636346 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848691/SRR8848691_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848691/SRR8848691_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848691/SRR8848691_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848691/SRR8848691_2.fastq.gz 2111851212;2172065805 cbea0510290d2350cea59e256bec612c;12805ee27eb93aa431bb96fcd9c73c7d
SRR8848692 SAMN11337812 SRX5636345 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848692/SRR8848692_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848692/SRR8848692_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848692/SRR8848692_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848692/SRR8848692_2.fastq.gz 1765294051;1850059854 fb5c9485f8f74ed1ab303f2acd2e1e13;97510b52930d3f14020b2d5f40f717da
SRR8848693 SAMN11337778 SRX5636344 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848693/SRR8848693_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848693/SRR8848693_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848693/SRR8848693_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848693/SRR8848693_2.fastq.gz 1171490338;1213579721 b502285fed0fd82681967ee1d035ce1c;a557e6f2600a8ac1c0c1b8e5c85f973b
SRR8848694 SAMN11337777 SRX5636343 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848694/SRR8848694_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848694/SRR8848694_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848694/SRR8848694_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848694/SRR8848694_2.fastq.gz 1009608079;1070369379 498e297c4a85c64ddc5e53d4f9731255;545c308314100306e0a4e1c74247f82b
SRR8848695 SAMN11337766 SRX5636342 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848695/SRR8848695_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848695/SRR8848695_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848695/SRR8848695_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848695/SRR8848695_2.fastq.gz 1833673017;1922284899 7d2790e77bf250817ce73a82ddb9aa5b;5a63e79f03ab420636f034819fc4ee0e
SRR8848697 SAMN11337782 SRX5636340 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848697/SRR8848697_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848697/SRR8848697_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848697/SRR8848697_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848697/SRR8848697_2.fastq.gz 1194816937;1254364136 daa6ee64ba1a5e9cf12ea326565a8d3d;742c4e62549c5e7fc153da83f0762fb3
SRR8848698 SAMN11337781 SRX5636339 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848698/SRR8848698_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848698/SRR8848698_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848698/SRR8848698_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848698/SRR8848698_2.fastq.gz 1500999084;1533027030 7d8040be1425d0dc039c7ad12a3ead08;47487eeca7e4b0056c79063583abfba7
SRR8848699 SAMN11337784 SRX5636338 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848699/SRR8848699_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848699/SRR8848699_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848699/SRR8848699_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848699/SRR8848699_2.fastq.gz 1693235920;1777496534 8b0164aef43362b19e34a0d40f666b4b;6e7ca7a2c598b4d14e1741e76d8b830f
SRR8848702 SAMN11337759 SRX5636335 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848702/SRR8848702_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848702/SRR8848702_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848702/SRR8848702_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848702/SRR8848702_2.fastq.gz 1968631957;2052166772 462085df28e00db500ff2da065d0f648;31ef866a2447e67501873aa29ac052ac
SRR8848706 SAMN11337763 SRX5636331 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848706/SRR8848706_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848706/SRR8848706_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848706/SRR8848706_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848706/SRR8848706_2.fastq.gz 2195043047;2288528261 23304a986e5429073ab0ff3b81129936;288954d15006675508892f5d12720ffc
1 run_accession sample_accession experiment_accession scientific_name fastq_ftp fastq_aspera fastq_bytes fastq_md5
2 SRR8848643 SAMN11337804 SRX5636394 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848643/SRR8848643_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848643/SRR8848643_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848643/SRR8848643_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848643/SRR8848643_2.fastq.gz 1782934223;1830571017 b26072fcc2e333fe0d533c929b1c9102;054e112c5b9973fdf0f946660848e201
3 SRR8848644 SAMN11337803 SRX5636393 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848644/SRR8848644_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848644/SRR8848644_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848644/SRR8848644_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848644/SRR8848644_2.fastq.gz 2001541510;2070167348 2bea98a03b238eb0be650d54688a263f;050bbfd7a60c05b0f8e350aef11a492d
4 SRR8848646 SAMN11337801 SRX5636391 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848646/SRR8848646_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848646/SRR8848646_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848646/SRR8848646_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848646/SRR8848646_2.fastq.gz 1984198211;2061538651 dc935c4ffc93dbec97fc3ec221fa18f4;0eb3dcbeeb55f95becc2db070cd1b982
5 SRR8848647 SAMN11337800 SRX5636390 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848647/SRR8848647_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848647/SRR8848647_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848647/SRR8848647_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848647/SRR8848647_2.fastq.gz 2204461915;2273561396 4619d5d79c772207d7049220e7ab00c2;da22c00d6a052a42c654cef7331cfae6
6 SRR8848650 SAMN11337797 SRX5636387 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848650/SRR8848650_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848650/SRR8848650_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848650/SRR8848650_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848650/SRR8848650_2.fastq.gz 2115902642;2208045149 1b24550c7233ef5a463a277015407f73;a157b359e7cf7de58c2792bdc73c61d4
7 SRR8848651 SAMN11337806 SRX5636386 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848651/SRR8848651_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848651/SRR8848651_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848651/SRR8848651_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848651/SRR8848651_2.fastq.gz 2311801550;2387651849 2c5d795003281ae686f6eca00307316e;37995ab807fcd1b806b0b9f81987ce90
8 SRR8848654 SAMN11337748 SRX5636383 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848654/SRR8848654_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848654/SRR8848654_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848654/SRR8848654_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848654/SRR8848654_2.fastq.gz 1476361305;1498189478 dacc1de38b9fcbda988442469569e25e;cf84b840bd68d68cf9a9a77a4d3522d2
9 SRR8848660 SAMN11337754 SRX5636377 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848660/SRR8848660_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848660/SRR8848660_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848660/SRR8848660_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848660/SRR8848660_2.fastq.gz 1809304913;1858544862 bea59c4c919bf27cc96e20c4048fee38;459da78b70f5fb8d77009c792a0e59e3
10 SRR8848661 SAMN11337753 SRX5636376 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848661/SRR8848661_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848661/SRR8848661_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848661/SRR8848661_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848661/SRR8848661_2.fastq.gz 1666930682;1690513285 59c7a8bf3f744c9e1b48a011946ab8d6;96f5b3066238416f331b2401ccf4ac48
11 SRR8848663 SAMN11337755 SRX5636374 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848663/SRR8848663_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848663/SRR8848663_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848663/SRR8848663_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848663/SRR8848663_2.fastq.gz 1539461717;1578574622 5d6b4cbdf01b3f682a6730750442f359;a9279b71b57f6535190263045bbffeee
12 SRR8848666 SAMN11337767 SRX5636371 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848666/SRR8848666_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848666/SRR8848666_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848666/SRR8848666_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848666/SRR8848666_2.fastq.gz 1912731347;1968907180 4d4167490d1504f1760f28d14efb2c80;1ccae37fb0c5e358c83848dbd4830c0f
13 SRR8848669 SAMN11337774 SRX5636368 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848669/SRR8848669_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848669/SRR8848669_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848669/SRR8848669_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848669/SRR8848669_2.fastq.gz 1145867352;1172095259 dfd95e68619664390e96878a79964e1e;ee8bad036e4be9233e3baf2bbff408a1
14 SRR8848671 SAMN11337772 SRX5636366 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848671/SRR8848671_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848671/SRR8848671_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848671/SRR8848671_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848671/SRR8848671_2.fastq.gz 1548725431;1570182025 90a471fab4860a1c8699963d7dc0d126;c708bfefd591fc6a6f6a4b7085afcc88
15 SRR8848673 SAMN11337776 SRX5636364 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848673/SRR8848673_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848673/SRR8848673_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848673/SRR8848673_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848673/SRR8848673_2.fastq.gz 1690871660;1718015156 13fb80274c68d5ed80c3a9ded6d90496;f58848cdeb0b8ad3d242acdf65470636
16 SRR8848674 SAMN11337809 SRX5636363 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848674/SRR8848674_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848674/SRR8848674_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848674/SRR8848674_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848674/SRR8848674_2.fastq.gz 2320915229;2388088536 4c8339d47128e73d08b997a8ac044e00;ede054b96fbd56f44098cdfb282c61ce
17 SRR8848677 SAMN11337808 SRX5636360 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848677/SRR8848677_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848677/SRR8848677_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848677/SRR8848677_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848677/SRR8848677_2.fastq.gz 2087541740;2172309980 14d5977ff638a5b4db03c602f4f3ab77;654f95ef28ed5a4c9d37685d16126d99
18 SRR8848682 SAMN11337791 SRX5636355 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848682/SRR8848682_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848682/SRR8848682_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848682/SRR8848682_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848682/SRR8848682_2.fastq.gz 1187095863;1199975571 cec23987cc0d4024a910912c7a169d9e;d8981aec73376759ba39f70b5e0e786f
19 SRR8848683 SAMN11337792 SRX5636354 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848683/SRR8848683_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848683/SRR8848683_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848683/SRR8848683_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848683/SRR8848683_2.fastq.gz 2079870389;2160198814 da8e96ef76e7b24dd672112840ba1c26;d565429dc2a008168f4294af31da2620
20 SRR8848685 SAMN11337794 SRX5636352 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848685/SRR8848685_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848685/SRR8848685_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848685/SRR8848685_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848685/SRR8848685_2.fastq.gz 2774481031;2886218941 97dcc3519cfdb97909f7588b2e612a52;216964ff90a4d35505756acdd806ff61
21 SRR8848700 SAMN11337783 SRX5636337 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848700/SRR8848700_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848700/SRR8848700_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848700/SRR8848700_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848700/SRR8848700_2.fastq.gz 1372886855;1394968651 b5a3c3c9a9e8bd3510c129a27c66a8f2;37a84cccd50e1340d50942c5fa674c6f
22 SRR8848701 SAMN11337760 SRX5636336 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848701/SRR8848701_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848701/SRR8848701_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848701/SRR8848701_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848701/SRR8848701_2.fastq.gz 2124530505;2191298837 de89cf7f50b9cea74f81f0b657ca6525;0d280315f0fabd212aa430f51a6cc9d5
23 SRR8848707 SAMN11337762 SRX5636330 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848707/SRR8848707_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848707/SRR8848707_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848707/SRR8848707_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848707/SRR8848707_2.fastq.gz 1687339155;1763483173 b078557d3c771844bc7770f621c88c28;3eac660d66a5451abcc6c96babc7772e
24 SRR8848648 SAMN11337799 SRX5636389 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848648/SRR8848648_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848648/SRR8848648_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848648/SRR8848648_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848648/SRR8848648_2.fastq.gz 2264781136;2318739364 2711bcb8ce95199851da26d857786041;8820e70e2d2f4743c612de6996d4d8ed
25 SRR8848652 SAMN11337805 SRX5636385 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848652/SRR8848652_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848652/SRR8848652_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848652/SRR8848652_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848652/SRR8848652_2.fastq.gz 2263622227;2391628166 49cb8a119a22bece66f5e8d2d454ef0e;6d574b7fcaf217fa08bddd6908004980
26 SRR8848653 SAMN11337779 SRX5636384 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848653/SRR8848653_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848653/SRR8848653_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848653/SRR8848653_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848653/SRR8848653_2.fastq.gz 1488132126;1551329597 02eb2ce858918e726d55914666698f01;b35c3bf49aef36c9e62f84e729f6f1a0
27 SRR8848656 SAMN11337750 SRX5636381 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848656/SRR8848656_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848656/SRR8848656_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848656/SRR8848656_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848656/SRR8848656_2.fastq.gz 1879123849;1933796633 7c303624010c50bdd6d25c1157b60349;fdc66249343ad7bfbf67e5259ae83289
28 SRR8848658 SAMN11337752 SRX5636379 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848658/SRR8848658_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848658/SRR8848658_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848658/SRR8848658_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848658/SRR8848658_2.fastq.gz 1667996507;1689627600 8d1aae2d46a4bf729ab770952d81db77;7d46fabad583afac562d7ec9aef9c053
29 SRR8848659 SAMN11337751 SRX5636378 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848659/SRR8848659_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848659/SRR8848659_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848659/SRR8848659_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848659/SRR8848659_2.fastq.gz 1559089847;1594535543 4fe4ef76062633930d42ea03d0bdc6ab;3c1c157f791d027fbcd0ab4c4e1e5858
30 SRR8848664 SAMN11337769 SRX5636373 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848664/SRR8848664_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848664/SRR8848664_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848664/SRR8848664_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848664/SRR8848664_2.fastq.gz 1956539508;2033420631 e02d80e0006f7778e3f402ed3779870f;22878b54f5851270678e3aca687da556
31 SRR8848665 SAMN11337770 SRX5636372 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848665/SRR8848665_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848665/SRR8848665_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848665/SRR8848665_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848665/SRR8848665_2.fastq.gz 1878427472;1923206394 304e45abeeba16a1739128cc3c1156ab;8428ccc1c85e4006d524946369bc4c60
32 SRR8848667 SAMN11337768 SRX5636370 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848667/SRR8848667_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848667/SRR8848667_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848667/SRR8848667_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848667/SRR8848667_2.fastq.gz 2149895254;2222572883 0a39c17507c169dc379211d1b3868e28;3f96774f5208e9c47b28bf555e1e2a8a
33 SRR8848668 SAMN11337773 SRX5636369 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848668/SRR8848668_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848668/SRR8848668_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848668/SRR8848668_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848668/SRR8848668_2.fastq.gz 1418696788;1467067643 2721de0a3b2c7c2e8f3017859c03683a;a0d20fe7de22b291227fe31df492111f
34 SRR8848670 SAMN11337771 SRX5636367 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848670/SRR8848670_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848670/SRR8848670_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848670/SRR8848670_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848670/SRR8848670_2.fastq.gz 1686570635;1709827942 cf30740a4fd0235a38940e4d5cb0d1bf;53d8994de45fe89f54d86bf31c6b5234
35 SRR8848675 SAMN11337810 SRX5636362 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848675/SRR8848675_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848675/SRR8848675_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848675/SRR8848675_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848675/SRR8848675_2.fastq.gz 1995941748;2057871919 a440c5a07fe954d7cd1af86b255ef30b;9fb3bd1ac55e7946aacf5b24161ad7f8
36 SRR8848676 SAMN11337807 SRX5636361 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848676/SRR8848676_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848676/SRR8848676_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848676/SRR8848676_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848676/SRR8848676_2.fastq.gz 1821584546;1895162039 c1d2c314075ff3f87fed83d2cf416469;c8d13ecc6b93761572cf06123b74034f
37 SRR8848679 SAMN11337788 SRX5636358 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848679/SRR8848679_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848679/SRR8848679_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848679/SRR8848679_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848679/SRR8848679_2.fastq.gz 1679278498;1737494099 884f39f1ddc821b39aa8783ddf441870;f348b5a2b23263b2531cfd55a1c26b44
38 SRR8848680 SAMN11337789 SRX5636357 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848680/SRR8848680_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848680/SRR8848680_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848680/SRR8848680_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848680/SRR8848680_2.fastq.gz 1379856238;1418109883 60c96db9eb9b6986544b06ae5aaec432;12a5a1653c1e006a25352bf96cf3e99e
39 SRR8848681 SAMN11337790 SRX5636356 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848681/SRR8848681_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848681/SRR8848681_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848681/SRR8848681_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848681/SRR8848681_2.fastq.gz 1127276562;1156220721 fdc36451b647696e92f85aa7653090ce;870dc23aa93f60f8a4d210141a8a14c4
40 SRR8848684 SAMN11337793 SRX5636353 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848684/SRR8848684_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848684/SRR8848684_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848684/SRR8848684_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848684/SRR8848684_2.fastq.gz 2231324712;2333517319 c500975019671e6113927cb53d60ae07;58b69b13c5e137a4b95b2cc2a4c3f4e1
41 SRR8848687 SAMN11337796 SRX5636350 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848687/SRR8848687_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848687/SRR8848687_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848687/SRR8848687_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848687/SRR8848687_2.fastq.gz 2058947935;2119565084 43fc01ed05a259e8ec6d0cf4dbef09e6;8a7e6a9ee1392fbdc2d12e6f9eaaa363
42 SRR8848688 SAMN11337780 SRX5636349 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848688/SRR8848688_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848688/SRR8848688_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848688/SRR8848688_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848688/SRR8848688_2.fastq.gz 1565579800;1617577226 fe17c6acc80740f815ceb3801595f91e;b311f3d120502a072d0cd93db1c0e273
43 SRR8848696 SAMN11337765 SRX5636341 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848696/SRR8848696_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848696/SRR8848696_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848696/SRR8848696_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848696/SRR8848696_2.fastq.gz 1931122606;2035132065 e60772cb7e3b3a8e80656969c569a7ad;1b1616db0bb1eb249b14d8977716f6f1
44 SRR8848703 SAMN11337758 SRX5636334 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848703/SRR8848703_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848703/SRR8848703_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848703/SRR8848703_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848703/SRR8848703_2.fastq.gz 2071230622;2132208247 462a1cd5ca4d3cf29357918c0483abe3;d943ef2aa067607fd3a449c6a61bc83f
45 SRR8848704 SAMN11337757 SRX5636333 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848704/SRR8848704_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848704/SRR8848704_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848704/SRR8848704_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848704/SRR8848704_2.fastq.gz 1666632491;1711740253 ad18df5652381aaeb402fae07bef1328;c69078be2456c61fafc057c769f14fc3
46 SRR8848705 SAMN11337764 SRX5636332 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848705/SRR8848705_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848705/SRR8848705_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848705/SRR8848705_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848705/SRR8848705_2.fastq.gz 1883984821;2069941891 44b22e866f409e1481a0f70c949d75a6;eb72c15d35fbfd4faeeb0430e7ac7fd5
47 SRR8848708 SAMN11337761 SRX5636329 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848708/SRR8848708_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848708/SRR8848708_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848708/SRR8848708_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848708/SRR8848708_2.fastq.gz 1013578999;1042446524 c33b60961d1b7835e7bccd5ea4e2f5ab;882f5f9cb464731f425b372bbdf4772f
48 SRR8848645 SAMN11337802 SRX5636392 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848645/SRR8848645_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848645/SRR8848645_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848645/SRR8848645_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848645/SRR8848645_2.fastq.gz 1922835863;2015905496 5786510d6ba4ae5599901a69a9894f77;b072062a9b7a68546c2b3ef88311bb3e
49 SRR8848649 SAMN11337798 SRX5636388 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848649/SRR8848649_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848649/SRR8848649_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848649/SRR8848649_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848649/SRR8848649_2.fastq.gz 2073317600;2127749911 96a017c7e578f7310a2fb67729f89ec5;15183c01449e35823fa055978fc75d9a
50 SRR8848655 SAMN11337747 SRX5636382 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848655/SRR8848655_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848655/SRR8848655_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848655/SRR8848655_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848655/SRR8848655_2.fastq.gz 1327800889;1387848758 6caa0fd729a96c39772d259235b00d11;6c26d13e91684dd082aed2a56a874ce5
51 SRR8848657 SAMN11337749 SRX5636380 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848657/SRR8848657_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848657/SRR8848657_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848657/SRR8848657_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848657/SRR8848657_2.fastq.gz 1653315959;1703251646 5fd16ccd6a9d57ca853ddd6f97a22831;df4d10dc916d0b3234fa5c881c91daf5
52 SRR8848662 SAMN11337756 SRX5636375 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848662/SRR8848662_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848662/SRR8848662_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848662/SRR8848662_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848662/SRR8848662_2.fastq.gz 6568578209;6874588835 3ad1f0966ed5e9565e0463fc82ec0936;6d3243f8f1fd5627db1b54364a2a2ab8
53 SRR8848672 SAMN11337775 SRX5636365 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848672/SRR8848672_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848672/SRR8848672_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848672/SRR8848672_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848672/SRR8848672_2.fastq.gz 1739872275;1787985299 8c3a8695e92c5f7ccafa5d5e9aec350d;29501db7a5831f53dd517419a3c73208
54 SRR8848678 SAMN11337787 SRX5636359 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848678/SRR8848678_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848678/SRR8848678_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848678/SRR8848678_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848678/SRR8848678_2.fastq.gz 1475469990;1502409453 a17597c6e22a24bc1025bd6caeceb2b5;fd3fa32d3202deea680ac78d5773dee9
55 SRR8848686 SAMN11337795 SRX5636351 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848686/SRR8848686_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848686/SRR8848686_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848686/SRR8848686_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848686/SRR8848686_2.fastq.gz 2507215057;2581073697 103dc4b16778b22693fc65b82f169d28;5de80031628795e7064b18d6044befa0
56 SRR8848689 SAMN11337786 SRX5636348 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848689/SRR8848689_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848689/SRR8848689_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848689/SRR8848689_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848689/SRR8848689_2.fastq.gz 1565094637;1593673954 bd12862bc8c1bdee2e6a77922afe09b6;72aef58ba433713e69bdbd407f344f2b
57 SRR8848690 SAMN11337785 SRX5636347 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848690/SRR8848690_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/000/SRR8848690/SRR8848690_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848690/SRR8848690_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/000/SRR8848690/SRR8848690_2.fastq.gz 1467572786;1537289083 88adffd0fb2e53f6cf69258e4e2e9328;46818cfd20f9f564ef38c510e02e3513
58 SRR8848691 SAMN11337811 SRX5636346 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848691/SRR8848691_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/001/SRR8848691/SRR8848691_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848691/SRR8848691_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/001/SRR8848691/SRR8848691_2.fastq.gz 2111851212;2172065805 cbea0510290d2350cea59e256bec612c;12805ee27eb93aa431bb96fcd9c73c7d
59 SRR8848692 SAMN11337812 SRX5636345 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848692/SRR8848692_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848692/SRR8848692_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848692/SRR8848692_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848692/SRR8848692_2.fastq.gz 1765294051;1850059854 fb5c9485f8f74ed1ab303f2acd2e1e13;97510b52930d3f14020b2d5f40f717da
60 SRR8848693 SAMN11337778 SRX5636344 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848693/SRR8848693_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/003/SRR8848693/SRR8848693_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848693/SRR8848693_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/003/SRR8848693/SRR8848693_2.fastq.gz 1171490338;1213579721 b502285fed0fd82681967ee1d035ce1c;a557e6f2600a8ac1c0c1b8e5c85f973b
61 SRR8848694 SAMN11337777 SRX5636343 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848694/SRR8848694_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/004/SRR8848694/SRR8848694_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848694/SRR8848694_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/004/SRR8848694/SRR8848694_2.fastq.gz 1009608079;1070369379 498e297c4a85c64ddc5e53d4f9731255;545c308314100306e0a4e1c74247f82b
62 SRR8848695 SAMN11337766 SRX5636342 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848695/SRR8848695_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/005/SRR8848695/SRR8848695_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848695/SRR8848695_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/005/SRR8848695/SRR8848695_2.fastq.gz 1833673017;1922284899 7d2790e77bf250817ce73a82ddb9aa5b;5a63e79f03ab420636f034819fc4ee0e
63 SRR8848697 SAMN11337782 SRX5636340 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848697/SRR8848697_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/007/SRR8848697/SRR8848697_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848697/SRR8848697_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/007/SRR8848697/SRR8848697_2.fastq.gz 1194816937;1254364136 daa6ee64ba1a5e9cf12ea326565a8d3d;742c4e62549c5e7fc153da83f0762fb3
64 SRR8848698 SAMN11337781 SRX5636339 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848698/SRR8848698_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/008/SRR8848698/SRR8848698_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848698/SRR8848698_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/008/SRR8848698/SRR8848698_2.fastq.gz 1500999084;1533027030 7d8040be1425d0dc039c7ad12a3ead08;47487eeca7e4b0056c79063583abfba7
65 SRR8848699 SAMN11337784 SRX5636338 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848699/SRR8848699_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/009/SRR8848699/SRR8848699_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848699/SRR8848699_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/009/SRR8848699/SRR8848699_2.fastq.gz 1693235920;1777496534 8b0164aef43362b19e34a0d40f666b4b;6e7ca7a2c598b4d14e1741e76d8b830f
66 SRR8848702 SAMN11337759 SRX5636335 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848702/SRR8848702_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/002/SRR8848702/SRR8848702_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848702/SRR8848702_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/002/SRR8848702/SRR8848702_2.fastq.gz 1968631957;2052166772 462085df28e00db500ff2da065d0f648;31ef866a2447e67501873aa29ac052ac
67 SRR8848706 SAMN11337763 SRX5636331 Oryza sativa Japonica Group ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848706/SRR8848706_1.fastq.gz;ftp.sra.ebi.ac.uk/vol1/fastq/SRR884/006/SRR8848706/SRR8848706_2.fastq.gz fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848706/SRR8848706_1.fastq.gz;fasp.sra.ebi.ac.uk:/vol1/fastq/SRR884/006/SRR8848706/SRR8848706_2.fastq.gz 2195043047;2288528261 23304a986e5429073ab0ff3b81129936;288954d15006675508892f5d12720ffc
+132
View File
@@ -0,0 +1,132 @@
b26072fcc2e333fe0d533c929b1c9102 SRR8848643_1.fastq.gz
054e112c5b9973fdf0f946660848e201 SRR8848643_2.fastq.gz
2bea98a03b238eb0be650d54688a263f SRR8848644_1.fastq.gz
050bbfd7a60c05b0f8e350aef11a492d SRR8848644_2.fastq.gz
dc935c4ffc93dbec97fc3ec221fa18f4 SRR8848646_1.fastq.gz
0eb3dcbeeb55f95becc2db070cd1b982 SRR8848646_2.fastq.gz
4619d5d79c772207d7049220e7ab00c2 SRR8848647_1.fastq.gz
da22c00d6a052a42c654cef7331cfae6 SRR8848647_2.fastq.gz
1b24550c7233ef5a463a277015407f73 SRR8848650_1.fastq.gz
a157b359e7cf7de58c2792bdc73c61d4 SRR8848650_2.fastq.gz
2c5d795003281ae686f6eca00307316e SRR8848651_1.fastq.gz
37995ab807fcd1b806b0b9f81987ce90 SRR8848651_2.fastq.gz
dacc1de38b9fcbda988442469569e25e SRR8848654_1.fastq.gz
cf84b840bd68d68cf9a9a77a4d3522d2 SRR8848654_2.fastq.gz
bea59c4c919bf27cc96e20c4048fee38 SRR8848660_1.fastq.gz
459da78b70f5fb8d77009c792a0e59e3 SRR8848660_2.fastq.gz
59c7a8bf3f744c9e1b48a011946ab8d6 SRR8848661_1.fastq.gz
96f5b3066238416f331b2401ccf4ac48 SRR8848661_2.fastq.gz
5d6b4cbdf01b3f682a6730750442f359 SRR8848663_1.fastq.gz
a9279b71b57f6535190263045bbffeee SRR8848663_2.fastq.gz
4d4167490d1504f1760f28d14efb2c80 SRR8848666_1.fastq.gz
1ccae37fb0c5e358c83848dbd4830c0f SRR8848666_2.fastq.gz
dfd95e68619664390e96878a79964e1e SRR8848669_1.fastq.gz
ee8bad036e4be9233e3baf2bbff408a1 SRR8848669_2.fastq.gz
90a471fab4860a1c8699963d7dc0d126 SRR8848671_1.fastq.gz
c708bfefd591fc6a6f6a4b7085afcc88 SRR8848671_2.fastq.gz
13fb80274c68d5ed80c3a9ded6d90496 SRR8848673_1.fastq.gz
f58848cdeb0b8ad3d242acdf65470636 SRR8848673_2.fastq.gz
4c8339d47128e73d08b997a8ac044e00 SRR8848674_1.fastq.gz
ede054b96fbd56f44098cdfb282c61ce SRR8848674_2.fastq.gz
14d5977ff638a5b4db03c602f4f3ab77 SRR8848677_1.fastq.gz
654f95ef28ed5a4c9d37685d16126d99 SRR8848677_2.fastq.gz
cec23987cc0d4024a910912c7a169d9e SRR8848682_1.fastq.gz
d8981aec73376759ba39f70b5e0e786f SRR8848682_2.fastq.gz
da8e96ef76e7b24dd672112840ba1c26 SRR8848683_1.fastq.gz
d565429dc2a008168f4294af31da2620 SRR8848683_2.fastq.gz
97dcc3519cfdb97909f7588b2e612a52 SRR8848685_1.fastq.gz
216964ff90a4d35505756acdd806ff61 SRR8848685_2.fastq.gz
b5a3c3c9a9e8bd3510c129a27c66a8f2 SRR8848700_1.fastq.gz
37a84cccd50e1340d50942c5fa674c6f SRR8848700_2.fastq.gz
de89cf7f50b9cea74f81f0b657ca6525 SRR8848701_1.fastq.gz
0d280315f0fabd212aa430f51a6cc9d5 SRR8848701_2.fastq.gz
b078557d3c771844bc7770f621c88c28 SRR8848707_1.fastq.gz
3eac660d66a5451abcc6c96babc7772e SRR8848707_2.fastq.gz
2711bcb8ce95199851da26d857786041 SRR8848648_1.fastq.gz
8820e70e2d2f4743c612de6996d4d8ed SRR8848648_2.fastq.gz
49cb8a119a22bece66f5e8d2d454ef0e SRR8848652_1.fastq.gz
6d574b7fcaf217fa08bddd6908004980 SRR8848652_2.fastq.gz
02eb2ce858918e726d55914666698f01 SRR8848653_1.fastq.gz
b35c3bf49aef36c9e62f84e729f6f1a0 SRR8848653_2.fastq.gz
7c303624010c50bdd6d25c1157b60349 SRR8848656_1.fastq.gz
fdc66249343ad7bfbf67e5259ae83289 SRR8848656_2.fastq.gz
8d1aae2d46a4bf729ab770952d81db77 SRR8848658_1.fastq.gz
7d46fabad583afac562d7ec9aef9c053 SRR8848658_2.fastq.gz
4fe4ef76062633930d42ea03d0bdc6ab SRR8848659_1.fastq.gz
3c1c157f791d027fbcd0ab4c4e1e5858 SRR8848659_2.fastq.gz
e02d80e0006f7778e3f402ed3779870f SRR8848664_1.fastq.gz
22878b54f5851270678e3aca687da556 SRR8848664_2.fastq.gz
304e45abeeba16a1739128cc3c1156ab SRR8848665_1.fastq.gz
8428ccc1c85e4006d524946369bc4c60 SRR8848665_2.fastq.gz
0a39c17507c169dc379211d1b3868e28 SRR8848667_1.fastq.gz
3f96774f5208e9c47b28bf555e1e2a8a SRR8848667_2.fastq.gz
2721de0a3b2c7c2e8f3017859c03683a SRR8848668_1.fastq.gz
a0d20fe7de22b291227fe31df492111f SRR8848668_2.fastq.gz
cf30740a4fd0235a38940e4d5cb0d1bf SRR8848670_1.fastq.gz
53d8994de45fe89f54d86bf31c6b5234 SRR8848670_2.fastq.gz
a440c5a07fe954d7cd1af86b255ef30b SRR8848675_1.fastq.gz
9fb3bd1ac55e7946aacf5b24161ad7f8 SRR8848675_2.fastq.gz
c1d2c314075ff3f87fed83d2cf416469 SRR8848676_1.fastq.gz
c8d13ecc6b93761572cf06123b74034f SRR8848676_2.fastq.gz
884f39f1ddc821b39aa8783ddf441870 SRR8848679_1.fastq.gz
f348b5a2b23263b2531cfd55a1c26b44 SRR8848679_2.fastq.gz
60c96db9eb9b6986544b06ae5aaec432 SRR8848680_1.fastq.gz
12a5a1653c1e006a25352bf96cf3e99e SRR8848680_2.fastq.gz
fdc36451b647696e92f85aa7653090ce SRR8848681_1.fastq.gz
870dc23aa93f60f8a4d210141a8a14c4 SRR8848681_2.fastq.gz
c500975019671e6113927cb53d60ae07 SRR8848684_1.fastq.gz
58b69b13c5e137a4b95b2cc2a4c3f4e1 SRR8848684_2.fastq.gz
43fc01ed05a259e8ec6d0cf4dbef09e6 SRR8848687_1.fastq.gz
8a7e6a9ee1392fbdc2d12e6f9eaaa363 SRR8848687_2.fastq.gz
fe17c6acc80740f815ceb3801595f91e SRR8848688_1.fastq.gz
b311f3d120502a072d0cd93db1c0e273 SRR8848688_2.fastq.gz
e60772cb7e3b3a8e80656969c569a7ad SRR8848696_1.fastq.gz
1b1616db0bb1eb249b14d8977716f6f1 SRR8848696_2.fastq.gz
462a1cd5ca4d3cf29357918c0483abe3 SRR8848703_1.fastq.gz
d943ef2aa067607fd3a449c6a61bc83f SRR8848703_2.fastq.gz
ad18df5652381aaeb402fae07bef1328 SRR8848704_1.fastq.gz
c69078be2456c61fafc057c769f14fc3 SRR8848704_2.fastq.gz
44b22e866f409e1481a0f70c949d75a6 SRR8848705_1.fastq.gz
eb72c15d35fbfd4faeeb0430e7ac7fd5 SRR8848705_2.fastq.gz
c33b60961d1b7835e7bccd5ea4e2f5ab SRR8848708_1.fastq.gz
882f5f9cb464731f425b372bbdf4772f SRR8848708_2.fastq.gz
5786510d6ba4ae5599901a69a9894f77 SRR8848645_1.fastq.gz
b072062a9b7a68546c2b3ef88311bb3e SRR8848645_2.fastq.gz
96a017c7e578f7310a2fb67729f89ec5 SRR8848649_1.fastq.gz
15183c01449e35823fa055978fc75d9a SRR8848649_2.fastq.gz
6caa0fd729a96c39772d259235b00d11 SRR8848655_1.fastq.gz
6c26d13e91684dd082aed2a56a874ce5 SRR8848655_2.fastq.gz
5fd16ccd6a9d57ca853ddd6f97a22831 SRR8848657_1.fastq.gz
df4d10dc916d0b3234fa5c881c91daf5 SRR8848657_2.fastq.gz
3ad1f0966ed5e9565e0463fc82ec0936 SRR8848662_1.fastq.gz
6d3243f8f1fd5627db1b54364a2a2ab8 SRR8848662_2.fastq.gz
8c3a8695e92c5f7ccafa5d5e9aec350d SRR8848672_1.fastq.gz
29501db7a5831f53dd517419a3c73208 SRR8848672_2.fastq.gz
a17597c6e22a24bc1025bd6caeceb2b5 SRR8848678_1.fastq.gz
fd3fa32d3202deea680ac78d5773dee9 SRR8848678_2.fastq.gz
103dc4b16778b22693fc65b82f169d28 SRR8848686_1.fastq.gz
5de80031628795e7064b18d6044befa0 SRR8848686_2.fastq.gz
bd12862bc8c1bdee2e6a77922afe09b6 SRR8848689_1.fastq.gz
72aef58ba433713e69bdbd407f344f2b SRR8848689_2.fastq.gz
88adffd0fb2e53f6cf69258e4e2e9328 SRR8848690_1.fastq.gz
46818cfd20f9f564ef38c510e02e3513 SRR8848690_2.fastq.gz
cbea0510290d2350cea59e256bec612c SRR8848691_1.fastq.gz
12805ee27eb93aa431bb96fcd9c73c7d SRR8848691_2.fastq.gz
fb5c9485f8f74ed1ab303f2acd2e1e13 SRR8848692_1.fastq.gz
97510b52930d3f14020b2d5f40f717da SRR8848692_2.fastq.gz
b502285fed0fd82681967ee1d035ce1c SRR8848693_1.fastq.gz
a557e6f2600a8ac1c0c1b8e5c85f973b SRR8848693_2.fastq.gz
498e297c4a85c64ddc5e53d4f9731255 SRR8848694_1.fastq.gz
545c308314100306e0a4e1c74247f82b SRR8848694_2.fastq.gz
7d2790e77bf250817ce73a82ddb9aa5b SRR8848695_1.fastq.gz
5a63e79f03ab420636f034819fc4ee0e SRR8848695_2.fastq.gz
daa6ee64ba1a5e9cf12ea326565a8d3d SRR8848697_1.fastq.gz
742c4e62549c5e7fc153da83f0762fb3 SRR8848697_2.fastq.gz
7d8040be1425d0dc039c7ad12a3ead08 SRR8848698_1.fastq.gz
47487eeca7e4b0056c79063583abfba7 SRR8848698_2.fastq.gz
8b0164aef43362b19e34a0d40f666b4b SRR8848699_1.fastq.gz
6e7ca7a2c598b4d14e1741e76d8b830f SRR8848699_2.fastq.gz
462085df28e00db500ff2da065d0f648 SRR8848702_1.fastq.gz
31ef866a2447e67501873aa29ac052ac SRR8848702_2.fastq.gz
23304a986e5429073ab0ff3b81129936 SRR8848706_1.fastq.gz
288954d15006675508892f5d12720ffc SRR8848706_2.fastq.gz
+145
View File
@@ -0,0 +1,145 @@
# bbav5 项目总规划
## 项目目标
将 bbav20311 迁移到 LangGraph 框架,实现 9 个 Agent 的图结构编排
## 当前状态
- 项目路径: `/home/xia-lab/wutx/00test/bbav5`
- 端口: 7867 ✅ 服务运行中
- RAG端口: 8001 ✅ 服务运行中
---
## 任务清单
### Phase 1: 项目初始化 ✅
- [x] 复制项目(排除 input/workspace)
- [x] 修改端口 7865 → 7867
- [x] 修改 RAG 端口 8000 → 8001
- [x] 更新项目路径 bbav20311 → bbav5
- [x] 添加 DiscoveryAgent(9个Agent)
### Phase 2: 代码清理 ✅
- [x] 删除测试文件(test_*.py)
- [x] 删除 demo 文件
- [x] 保留微信集成文件(wechat_*.py)
- [x] 删除旧 RAG 实现(kb/)
- [x] 删除备份文件(backup/, *.bak, *.backup.*)
- [x] 删除实验性代码(langchain_agent.py)
- [x] 删除日志文件(logs/, *.log)
- [x] 删除修订记录(REVISION_*.md)
- [x] 保留文档(项目记录/, codeMiaoshu/)
### Phase 3: LangGraph 迁移 ✅
- [x] 安装 langgraph 依赖 (0.2.0)
- [x] 设计 StateGraph 结构
- [x] 创建 LangGraphOrchestrator 类
- [x] 实现 9 个 Agent 节点
- [x] 构建条件边和路由
- [x] 更新 apps/web/vue3/main.py 使用新的 LangGraphOrchestrator
- [x] 保留原 orchestrator.py 作为参考
- [x] 调整 RAG 集成(gene-family-mas-v2 端口 8001)
### Phase 4: 测试验证 ✅
- [x] RAG 服务启动(gene-family-mas-v2 端口 8001)
- [x] KnowledgeAgent 单测通过
- [x] LangGraph Orchestrator FAQ 流程测试通过
- [x] bbav5 服务启动(端口 7867)
- [x] API 测试通过(/api/agent/chat)
- [ ] 前端页面测试
- [ ] 完整分析流程测试(ANALYSIS 模式)
---
## 9 个 Agent 清单
1. RouterAgent - 意图路由 ✅
2. PlanningAgent - 任务规划 ✅
3. ExecutionAgent - 任务执行 ✅
4. KnowledgeAgent - 知识检索(RAG)✅
5. DiagnosisAgent - 错误诊断 ✅
6. ValidatorAgent - 结果验证 ✅
7. ResultParserAgent - 结果解析 ✅
8. LearningAgent - 学习优化 ✅
9. DiscoveryAgent - 科学发现(新增)✅
---
## LangGraph 工作流图
```
Router -> [条件分支]
├── FAQ/CONSULTATION/INTERPRETATION -> Knowledge -> END ✅ 已测试
└── ANALYSIS -> Planning -> Execution -> Validator
├── 失败 -> Diagnosis -> [重试/结束]
└── 成功 -> ResultParser -> Discovery -> Learning -> END
```
---
## 测试结果
### ✅ API 测试 (FAQ 模式)
```bash
curl http://localhost:7867/api/agent/chat \
-X POST \
-H "Content-Type: application/json" \
-d '{"message": "什么是SPL基因家族", "model": "kimi"}'
```
**响应:**
```json
{
"success": true,
"intent": {
"stage": "identify",
"taskType": "faq",
"params": {},
"confidence": 0.9,
"message": "处理完成"
},
"model_used": "kimi",
"session_id": "test_api_007",
"mode": "langgraph",
"current_agent": "knowledge"
}
```
### ✅ RAG 集成测试
```
查询: "什么是SPL基因家族的功能?"
回答: 找到 5 条相关文献。涉及物种: Arabidopsis。涉及基因家族: NAC, SPL。
来源: Arabidopsis_SPL_2010, Arabidopsis_SPL_2025_Hortic_Res 等
```
---
## 服务状态
| 服务 | 端口 | 状态 |
|------|------|------|
| bbav5 | 7867 | ✅ 运行中 |
| gene-family-mas-v2 | 8001 | ✅ 运行中 |
---
## 下一步任务
**Phase 4 完成: 最终验证**
可选执行:
1. 前端页面测试(浏览器访问 http://localhost:7867)
2. 完整分析流程测试(ANALYSIS 模式,需要配置 LLM API Key)
3. 微信集成测试
---
## 修订记录
| 时间 | 任务 | 状态 |
|------|------|------|
| 2026-04-12 11:37 | Phase 1 完成 | ✅ |
| 2026-04-12 11:47 | 添加 DiscoveryAgent | ✅ |
| 2026-04-12 12:07 | Phase 2 代码清理完成 | ✅ |
| 2026-04-12 12:15 | LangGraph 编排器创建完成 | ✅ |
| 2026-04-12 12:25 | 更新 main.py 使用 LangGraphOrchestrator | ✅ |
| 2026-04-12 12:35 | RAG 服务启动,KnowledgeAgent 测试通过 | ✅ |
| 2026-04-12 12:40 | LangGraph Orchestrator FAQ 流程测试通过 | ✅ |
| 2026-04-12 12:50 | bbav5 服务启动,API 测试通过 | ✅ |
+88
View File
@@ -0,0 +1,88 @@
# 修订记录 - 2026-04-13
## 今日任务
修复"/api/agent/execute"执行核型分析时返回错误阶段的问题
## 问题描述
用户说"帮我执行核型分析",但系统执行了identify阶段,而不是synteny+karyotype阶段。
## 根本原因
1. `/api/agent/plan` 直接调用 `orchestrator.plan()` → PlanningAgentV2,正确返回['synteny', 'karyotype']
2. `/api/agent/execute` 调用 `orchestrator.run()` → LangGraph → `_planning_node` → PlanningAgentV2
3. `completed_stages` 在传递过程中丢失,PlanningAgentV2收到空列表
## 已完成的修复
### 1. IntentAgentV2 依赖定义统一
**文件**: `gfa_core/mas/agents/intent_v2.py`
- 将 `synteny` 依赖从 `["identify", "phylogeny"]` 改为 `["identify"]`
- 添加 karyotype 关键词检查到 fallback 方法
- 修改 LLM prompt,明确指示不要过度推断
### 2. PlanningAgentV2 使用 completed_stages
**文件**: `gfa_core/mas/agents/planning_v2.py`
- 在 `_generate_plan_with_llm` 中添加逻辑,检查依赖阶段是否已完成
- 添加调试日志 `print(f"[PlanningAgentV2] completed_stages: {completed_stages}")`
### 3. 接受 partial_success 作为已完成状态
**文件**: `apps/web/vue3/main.py`
- `/api/agent/plan` 现在接受 `partial_success` 作为已完成状态
### 4. LangGraphOrchestrator 使用 PlanningAgentV2
**文件**: `gfa_core/mas/core/langgraph_orchestrator.py`
- 将 `PlanningAgent` 改为 `PlanningAgentV2`
- 修复 `state.get("user_input")` 可能为 None 的错误
- 在 `_to_agent_state` 中添加 `completed_stages` 传递
### 5. tasks.py 使用 LangGraphOrchestrator
**文件**: `tasks.py`
- 将 `Orchestrator` 改为 `LangGraphOrchestrator`
- 添加 `messages` 字段到 initial_state
- 添加 `completed_stages` 查询逻辑
- 添加调试日志
### 6. GraphState 添加 completed_stages 字段
**文件**: `gfa_core/mas/core/state.py`
- 添加 `completed_stages: list[str]` 字段
## 当前状态
### 验证结果
**`/api/agent/plan` 测试**:
```bash
curl -s "http://localhost:7867/api/agent/plan" \
-X POST -H "Content-Type: application/json" \
-d '{"message":"帮我执行核型分析","session_id":"job_1776004000991"}'
# 返回: ['synteny', 'karyotype'] ✅ 正确
```
**`/api/agent/execute` 调试日志**:
```
[tasks.py] Completed stages: ['identify', 'phylogeny'] ✅ 正确查询
[PlanningAgentV2] completed_stages: [] ❌ 收到空列表
```
### 待解决问题
`completed_stages` 在从 `tasks.py` 传递到 `PlanningAgentV2` 的过程中丢失
可能原因:
1. LangGraph 工作流中 state 被修改导致 `completed_stages` 丢失
2. `_to_agent_state` 方法没有正确读取 `completed_stages`
3. RouterAgent 或其他节点修改了 state
## 明日计划
1. 修复 `completed_stages` 传递丢失问题
2. 验证 `/api/agent/execute` 正确返回 ['synteny', 'karyotype']
3. 测试完整执行流程
## 总体计划
1. 修复阶段依赖识别问题 ✅
2. 修复 completed_stages 传递问题 ⏳
3. 测试核型分析完整流程 ⏳
4. 修复其他潜在问题 ⏳
## 今日完成任务数
**已完成**: 6 项修复
**进行中**: 1 项(completed_stages 传递)
**剩余**: 3 项
+16
View File
@@ -0,0 +1,16 @@
# Secret Audit
Scope: PlantAI-dev working copy created from bbav5_0502_Yang_Tihuan.7880.
## Current Actions
- Moved PlantCARE email account and IMAP authorization code out of `apps/cli/run_promoter.py`.
- Kept private values in `.env` for local runtime compatibility.
- Added `.env.example` with placeholders for future open-source setup.
## Still To Review Before Open Source
- `.env` contains private LLM API keys and must not be published.
- `memory/` and `memory_storage/` include historical conversation/config records and should be removed or sanitized before publishing.
- `data/`, `项目记录/`, generated extension fixtures, benchmark outputs, and local reports should be separated from the public source release unless explicitly curated.
- Search again for `API_KEY`, `PASSWORD`, `TOKEN`, `SECRET`, email addresses, and `sk-` before any public commit.
@@ -0,0 +1,233 @@
# bbav5 Vue3 会话侧边栏集成报告
**实施时间**: 2026-04-13 00:30
**实施人**: xialab的幸运星
**状态**: ✅ 已完成
---
## 1. 实施概述
成功为bbav5的Vue3前端添加类似 **ChatGPT** 的会话侧边栏UI,实现了多会话管理功能。
---
## 2. 文件清单
| 文件 | 路径 | 说明 |
|:---|:---|:---|
| **主应用** | `apps/web/vue3/index.html` | 修改后的主应用文件 |
| **侧边栏组件** | `apps/web/vue3/conversation-sidebar.js` | Vue3组件 |
| **样式文件** | `apps/web/vue3/conversation-sidebar.css` | ChatGPT风格样式 |
| **后端API** | `gfa_core/mas/api/conversation_routes.py` | REST API |
| **ConversationManager** | `gfa_core/mas/memory/conversation.py` | 后端逻辑 |
---
## 3. 功能特性
### 3.1 侧边栏功能
| 功能 | 说明 | 状态 |
|:---|:---|:---:|
| **New Chat** | 创建新会话 | ✅ |
| **会话列表** | 按时间分组(今天/昨天/更早) | ✅ |
| **搜索会话** | 按标题/基因家族/内容搜索 | ✅ |
| **选择会话** | 点击切换当前会话 | ✅ |
| **重命名** | 修改会话标题 | ✅ |
| **归档** | 归档旧会话 | ✅ |
| **删除** | 删除会话 | ✅ |
| **折叠/展开** | 侧边栏宽度调整 | ✅ |
### 3.2 会话信息展示
```
┌─────────────────────────────────┐
│ + New Chat [<<] │
├─────────────────────────────────┤
│ 🔍 搜索会话... │
├─────────────────────────────────┤
│ 今天 │
│ 💬 Ft.SPL分析 [🧬SPL] │
│ 12条消息 │
│ 系统发育树已生成... │
├─────────────────────────────────┤
│ 昨天 │
│ 💬 Os.TCP进化 [🧬TCP] │
│ 5条消息 │
│ 正在构建进化树... │
├─────────────────────────────────┤
│ 过去7天 │
│ 💬 HMMER参数配置 [📝通用]│
│ 8条消息 │
│ E-value建议设置... │
├─────────────────────────────────┤
│ 👤 xia-lab │
└─────────────────────────────────┘
```
---
## 4. 技术实现
### 4.1 组件架构
```
Vue3 App
├── ConversationSidebar (新)
│ ├── 头部:New Chat + 折叠按钮
│ ├── 搜索框
│ ├── 会话列表(分组)
│ │ ├── 今天
│ │ ├── 昨天
│ │ └── 更早
│ └── 底部:用户信息
├── LeftPanel (原有)
│ └── 分析控制
├── MiddlePanel (原有)
│ └── 对话区域
└── RightPanel (原有)
└── 结果展示
```
### 4.2 数据流
```
用户操作 → ConversationSidebar → API调用 → ConversationManager
↓
事件通知 → Vue App → 更新UI
```
### 4.3 API接口
| 端点 | 方法 | 功能 |
|:---|:---:|:---|
| `/conversations/create` | POST | 创建会话 |
| `/conversations/list/{user_id}` | GET | 列表 |
| `/conversations/{id}/messages` | GET | 消息历史 |
| `/conversations/update-title` | POST | 重命名 |
| `/conversations/archive` | POST | 归档 |
| `/conversations/delete` | POST | 删除 |
---
## 5. 样式设计
### 5.1 ChatGPT风格配色
| 元素 | 颜色 | 说明 |
|:---|:---|:---|
| 背景 | `#202123` | 深色侧边栏 |
| 文字 | `#ececf1` | 主文字 |
| 次要文字 | `#8e8ea0` | 预览/时间 |
| 高亮 | `#343541` | 选中项 |
| 强调 | `#10a37f` | 基因家族标签 |
| 边框 | `#4d4d4f` | 分隔线 |
### 5.2 响应式设计
- **展开状态**: 260px宽度,完整信息
- **折叠状态**: 60px宽度,仅图标
---
## 6. 使用方法
### 6.1 启动前端
```bash
cd /home/xia-lab/wutx/00test/bbav5/apps/web/vue3
python3 -m http.server 8080
```
访问: http://localhost:8080
### 6.2 使用流程
1. **创建会话**: 点击 "+ New Chat"
2. **切换会话**: 点击侧边栏中的会话项
3. **搜索会话**: 在搜索框输入关键词
4. **管理会话**: 点击右侧"..."菜单
---
## 7. 与后端集成
### 7.1 启动后端API
确保bbav5后端运行在 `localhost:8000`
### 7.2 数据持久化
会话数据存储在:
```
memory_storage/
└── conversations/
├── 202604/
│ ├── conv_xxx.json
│ └── ...
└── user_index.json
```
---
## 8. 测试报告
### 8.1 功能测试
| 测试项 | 结果 |
|:---|:---:|
| 组件加载 | ✅ 通过 |
| 创建会话 | ✅ 通过 |
| 列表显示 | ✅ 通过 |
| 消息加载 | ✅ 通过 |
| 搜索过滤 | ✅ 通过 |
| 折叠展开 | ✅ 通过 |
### 8.2 性能测试
| 指标 | 数值 |
|:---|:---|
| 组件加载时间 | < 100ms |
| 会话列表渲染 | < 50ms (50个会话) |
| 切换会话响应 | < 200ms |
---
## 9. 后续优化
### 9.1 短期(1周内)
- [ ] 添加拖拽排序功能
- [ ] 实现会话置顶
- [ ] 添加标签分类
### 9.2 中期(1月内)
- [ ] WebSocket实时同步
- [ ] 会话分享功能
- [ ] 多设备同步
### 9.3 长期(持续)
- [ ] AI智能会话总结
- [ ] 会话推荐
- [ ] 语音输入支持
---
## 10. 总结
✅ **bbav5前端已成功集成类似ChatGPT的会话侧边栏!**
- 深色主题UI,专业美观
- 完整的多会话管理功能
- 与后端API无缝集成
- 响应式设计,支持折叠
**访问地址**: http://localhost:8080
---
*报告生成时间: 2026-04-13 00:35*
*实施状态: ✅ 全部完成*
+138
View File
@@ -0,0 +1,138 @@
# WeChat 集成指南 - bbav20311
> 基于 mcp-wechat-server 的微信集成方案
## 📋 功能概览
| 功能 | 状态 | 说明 |
|------|------|------|
| 任务完成通知 | ✅ | 自动发送微信通知 |
| 接收用户指令 | ✅ | 支持自然语言分析请求 |
| 任务状态查询 | ✅ | 查询任务进度和详情 |
| 多用户支持 | ✅ | 区分不同微信用户 |
## 🚀 快速开始
### 1. 安装依赖
```bash
# 安装 Bun (mcp-wechat-server 需要)
curl -fsSL https://bun.sh/install | bash
# 验证安装
bun --version # >= 1.0.0
```
### 2. 测试基础功能
```bash
cd /home/xia-lab/wutx/00test/bbav20311
# 运行基础测试
python wechat_integration.py
```
### 3. 启动完整服务
```bash
# 启动微信任务桥接服务
python wechat_task_bridge.py
```
## 📱 用户交互流程
```
用户微信 → 发送分析请求 → bbav20311 处理 → 微信通知结果
↓
支持命令:
• "帮助" - 显示帮助信息
• "状态" - 查询系统状态
• "Ft.SPL 基因家族鉴定" - 创建分析任务
• "任务列表" - 查看进行中的任务
• "详情 <任务ID>" - 查看任务详情
```
## 🔧 集成到现有系统
### 在 pipeline_backend.py 中添加通知
```python
from wechat_integration import WeChatTaskNotifier
async def run_stage_with_notification(job_id: str, stage: str, user_wechat_id: str):
"""运行 stage 并发送微信通知"""
notifier = WeChatTaskNotifier(user_wechat_id=user_wechat_id)
# 通知开始
await notifier.notify_task_started(task_id=job_id, task_type=stage)
try:
# 执行实际任务
result = await run_stage(job_id, stage)
# 通知完成
await notifier.notify_task_completed(
task_id=job_id,
task_type=stage,
output_files=result.get("output_files", [])
)
except Exception as e:
# 通知失败
await notifier.notify_task_failed(
task_id=job_id,
task_type=stage,
error=str(e)
)
```
### 在 API 中添加微信通知参数
```python
@app.post("/api/pipeline/run")
async def run_pipeline(
request: PipelineRequest,
wechat_user_id: Optional[str] = None # 新增参数
):
job = new_job()
if wechat_user_id:
# 后台运行并发送微信通知
asyncio.create_task(
run_with_wechat_notification(job.job_id, request, wechat_user_id)
)
return {"job_id": job.job_id, "message": "任务已提交,将通过微信通知结果"}
else:
# 原有逻辑
result = await run_stage(job.job_id, request.stage)
return result
```
## ⚠️ 注意事项
1. **登录状态**: 首次使用需要扫码登录,Cookie 会保存在 `~/.mcp-wechat-server/`
2. **封号风险**: 个人微信机器人存在封号风险,建议使用企业微信或测试号
3. **网络要求**: 扫码时如果页面加载慢,尝试切换到移动数据网络
4. **依赖 Bun**: mcp-wechat-server 需要 Bun 运行时
## 📁 文件说明
| 文件 | 说明 |
|------|------|
| `wechat_integration.py` | 核心集成模块,提供 WeChatIntegration 类 |
| `wechat_task_bridge.py` | 任务桥接服务,连接微信和 bbav20311 |
| `WECHAT_INTEGRATION.md` | 本文档 |
## 🔮 后续优化
- [ ] 接入真实的 MCP 协议(当前为模拟实现)
- [ ] 支持图片/文件发送
- [ ] 支持群聊 @机器人
- [ ] 添加任务队列管理
- [ ] 集成飞书作为备选通道
## 📚 参考
- [mcp-wechat-server](https://github.com/Howardzhangdqs/mcp-wechat-server)
- [MCP Protocol](https://modelcontextprotocol.io/)
+72
View File
@@ -0,0 +1,72 @@
# WORKLINE
last_updated: 2026-07-02
## Identity
- type: `bioagent`
- copy_role: `PlantAI-dev 9000 profile / active bioagent development line`
- canonical_path: `/home/xia-lab/PlantAI-dev`
- resolved_path_policy: use `readlink -f /home/xia-lab/PlantAI-dev` before path-sensitive edits because this path is a symlink into project roots.
- source_project: same family as bbav5, but current runtime profile and feature work differ from 7880.
## Current Workline
Current workline: RNA-seq quant/expression evidence-chain revision plus PlantAI 9000 runtime profile.
Evidence:
- `项目记录/PlantAI-dev_9000启动说明_20260626.md`
- `项目记录/rnaseqUpdate/2026-06-30_rnaseq_quant_expression_evidence_revision.md`
- `logs/celery_plantai_dev_9000/`
- `logs/plantai_dev_9000_web.log`
## Runtime Profile
- web_port: `9000`
- celery_queue_prefix: `plantai_dev_9000`
- redis_db: `10`
- start_scripts:
- `start_celery_port9000.sh`
- `start_plantai_9000.sh`
- historical_scripts:
- `start_celery_7880.sh` is retained for compatibility and is not the current default.
## External Dependencies
- Redis local service.
- Conda/Python environment used by PlantAI-dev startup scripts.
- Bioinformatics toolchain used by bbav5 stages and RNA-seq bridge logic.
## Active Evidence
- Project startup record: `项目记录/PlantAI-dev_9000启动说明_20260626.md`
- RNA-seq feature record: `项目记录/rnaseqUpdate/2026-06-30_rnaseq_quant_expression_evidence_revision.md`
- Runtime logs: `logs/celery_plantai_dev_9000/`, `logs/plantai_dev_9000_web.log`
## Verification Commands
Use these only after user-approved service startup:
```bash
curl -s http://127.0.0.1:9000/api/info
curl -s http://127.0.0.1:9000/api/celery/health
```
For read-only governance checks:
```bash
sed -n '1,140p' 项目记录/PlantAI-dev_9000启动说明_20260626.md
find logs/celery_plantai_dev_9000 -maxdepth 1 -type f
```
## Do Not Assume Duplicate Of
- Do not treat this as a disposable copy of `/home/xia-lab/wutx/00test/bbav5_0502_Yang_Tihuan.7880`.
- Do not use stale `.env` 7880-style values as the only runtime source; prefer the 9000 startup record and 9000 scripts.
- Do not copy 7880 or 7881 changes into this workline without first listing differences and risks.
## Update Policy
Update this file when the default port, queue prefix, Redis DB, startup scripts, current feature line, or active evidence record changes.
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,84 @@
#!/usr/bin/env python3
"""
测试修订后的run_stage函数
"""
import sys
from pathlib import Path
# 添加项目路径
sys.path.insert(0, str(Path(__file__).parent / "apps" / "backend"))
# 假设JobInfo定义在pipeline_backend中
from pipeline_backend import run_stage, JobInfo
def test_phylogeny_stage():
"""测试phylogeny阶段"""
print("🧪 测试Phylogeny阶段集成")
print("=" * 60)
# 创建测试job信息
job = JobInfo(
workspace_dir="workspace/20260128_072702_3148145_fb521a",
input_dir="input/20260128_072702_3148145_fb521a",
logs_dir="workspace/20260128_072702_3148145_fb521a/logs"
)
prefix = "Ft.SPL"
cpu = 4
print(f"🔧 测试参数:")
print(f" 工作空间: {job.workspace_dir}")
print(f" 分析前缀: {prefix}")
print(f" CPU核心: {cpu}")
# 运行phylogeny阶段
msg, manifest_path = run_stage(
stage="phylogeny",
job=job,
prefix=prefix,
cpu=cpu
)
print(f"\n📊 运行结果:")
print(f" 消息: {msg}")
print(f" Manifest路径: {manifest_path}")
# 检查输出
ws = Path(job.workspace_dir)
expected_files = [
ws / "final" / f"{prefix}.pep.msa.fa",
ws / "final" / f"{prefix}.tree.nwk",
ws / "final" / f"{prefix}.phylogeny_report.md",
ws / "final" / f"{prefix}.phylogeny.manifest.json"
]
print(f"\n📁 检查输出文件:")
all_exist = True
for file_path in expected_files:
exists = file_path.exists()
status = "✅" if exists else "❌"
print(f" {status} {file_path.name}: {exists}")
if not exists:
all_exist = False
# 总结
print("\n" + "=" * 60)
success = "✅" in msg and all_exist
if success:
print("🎉 Phylogeny阶段集成测试通过!")
else:
print("⚠️ Phylogeny阶段集成测试失败")
return success
if __name__ == "__main__":
try:
success = test_phylogeny_stage()
sys.exit(0 if success else 1)
except Exception as e:
print(f"❌ 测试异常: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
@@ -0,0 +1,411 @@
<!-- Agent状态显示组件 - 可嵌入index.html -->
<template id="agent-status-component">
<div class="agent-status-panel">
<div class="agent-header">
<h3>🤖 Agent 智能助手</h3>
<span class="agent-mode">{{ currentMode }}</span>
</div>
<div class="agent-messages" ref="messageContainer">
<div v-for="(msg, index) in messages" :key="index"
:class="['message', msg.role]">
<div class="message-role">{{ getRoleLabel(msg.role) }}</div>
<div class="message-content" v-html="formatMessage(msg.content)"></div>
<div class="message-time">{{ formatTime(msg.timestamp) }}</div>
</div>
</div>
<div class="agent-input">
<textarea v-model="userInput"
placeholder="输入您的问题,例如:分析SPL基因家族"
@keydown.enter.prevent="sendMessage"
rows="3"></textarea>
<button @click="sendMessage" :disabled="isProcessing">
{{ isProcessing ? '处理中...' : '发送' }}
</button>
</div>
<div class="agent-tasks" v-if="tasks.length > 0">
<h4>📋 任务列表</h4>
<div v-for="task in tasks" :key="task.task_id"
:class="['task-item', task.status]"
@click="selectTask(task)">
<span class="task-status">{{ getStatusIcon(task.status) }}</span>
<span class="task-message">{{ task.message }}</span>
<span class="task-progress">{{ task.progress }}%</span>
</div>
</div>
</div>
</template>
<script>
// Agent状态组件
const AgentStatusComponent = {
template: '#agent-status-component',
data() {
return {
messages: [],
userInput: '',
isProcessing: false,
currentMode: '待机',
sessionId: '',
tasks: [],
currentTask: null,
pollingInterval: null
};
},
mounted() {
this.sessionId = 'session_' + Date.now();
this.loadTasks();
this.startPolling();
},
beforeUnmount() {
this.stopPolling();
},
methods: {
async sendMessage() {
if (!this.userInput.trim() || this.isProcessing) return;
const message = this.userInput.trim();
this.userInput = '';
this.isProcessing = true;
// 添加用户消息
this.addMessage('user', message);
try {
// 调用Agent执行API
const response = await fetch('/api/agent/execute', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: message,
session_id: this.sessionId,
model: 'kimi'
})
});
const data = await response.json();
if (data.success) {
this.currentTask = data.task_id;
this.addMessage('system', `任务已提交: ${data.task_id}`);
this.loadTasks();
} else {
this.addMessage('error', data.message || '提交失败');
}
} catch (error) {
this.addMessage('error', `请求失败: ${error.message}`);
}
this.isProcessing = false;
},
async loadTasks() {
try {
const response = await fetch('/api/agent/tasks');
const data = await response.json();
if (data.success) {
this.tasks = data.tasks;
}
} catch (error) {
console.error('加载任务失败:', error);
}
},
async checkTaskStatus(taskId) {
try {
const response = await fetch(`/api/agent/status/${taskId}`);
const data = await response.json();
if (data.success && data.task) {
const task = data.task;
// 更新任务状态
const taskIndex = this.tasks.findIndex(t => t.task_id === taskId);
if (taskIndex >= 0) {
this.tasks[taskIndex] = { ...this.tasks[taskIndex], ...task };
}
// 如果任务完成,显示结果
if (task.status === 'completed' && task.result) {
this.addMessage('assistant', task.result.response || '任务完成');
// 显示执行结果摘要
if (task.result.execution_result) {
const execResult = task.result.execution_result;
if (execResult.status === 'success') {
const manifest = execResult.manifest || {};
const metrics = manifest.metrics || {};
this.addMessage('system',
`✅ 分析完成! 找到 ${metrics.final_members || 0} 个基因成员`);
}
}
} else if (task.status === 'failed') {
this.addMessage('error', task.result?.response || '任务失败');
}
}
} catch (error) {
console.error('检查任务状态失败:', error);
}
},
selectTask(task) {
this.currentTask = task.task_id;
this.checkTaskStatus(task.task_id);
},
startPolling() {
this.pollingInterval = setInterval(() => {
if (this.currentTask) {
this.checkTaskStatus(this.currentTask);
}
this.loadTasks();
}, 3000); // 每3秒轮询一次
},
stopPolling() {
if (this.pollingInterval) {
clearInterval(this.pollingInterval);
}
},
addMessage(role, content) {
this.messages.push({
role: role,
content: content,
timestamp: new Date().toISOString()
});
// 滚动到底部
setTimeout(() => {
const container = this.$refs.messageContainer;
if (container) {
container.scrollTop = container.scrollHeight;
}
}, 100);
},
getRoleLabel(role) {
const labels = {
'user': '👤 用户',
'assistant': '🤖 Agent',
'system': '💬 系统',
'error': '❌ 错误',
'execution': '⚙️ 执行',
'planning': '📋 规划',
'diagnosis': '🔍 诊断'
};
return labels[role] || role;
},
getStatusIcon(status) {
const icons = {
'pending': '⏳',
'running': '🔄',
'completed': '✅',
'failed': '❌',
'cancelled': '🚫'
};
return icons[status] || '❓';
},
formatMessage(content) {
// 简单的Markdown格式化
return content
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
.replace(/\n/g, '<br>');
},
formatTime(timestamp) {
if (!timestamp) return '';
const date = new Date(timestamp);
return date.toLocaleTimeString('zh-CN', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
}
}
};
</script>
<style>
.agent-status-panel {
border: 1px solid #ddd;
border-radius: 8px;
padding: 16px;
background: #f9f9f9;
height: 100%;
display: flex;
flex-direction: column;
}
.agent-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #eee;
}
.agent-header h3 {
margin: 0;
font-size: 16px;
}
.agent-mode {
font-size: 12px;
color: #666;
background: #e0e0e0;
padding: 2px 8px;
border-radius: 4px;
}
.agent-messages {
flex: 1;
overflow-y: auto;
max-height: 400px;
margin-bottom: 12px;
}
.message {
margin-bottom: 12px;
padding: 8px 12px;
border-radius: 8px;
background: white;
border-left: 3px solid #ddd;
}
.message.user {
border-left-color: #4CAF50;
background: #E8F5E9;
}
.message.assistant {
border-left-color: #2196F3;
background: #E3F2FD;
}
.message.error {
border-left-color: #f44336;
background: #FFEBEE;
}
.message.system {
border-left-color: #9E9E9E;
background: #F5F5F5;
font-size: 12px;
}
.message-role {
font-size: 12px;
color: #666;
margin-bottom: 4px;
}
.message-content {
font-size: 14px;
line-height: 1.5;
}
.message-time {
font-size: 11px;
color: #999;
text-align: right;
margin-top: 4px;
}
.agent-input {
display: flex;
gap: 8px;
margin-bottom: 12px;
}
.agent-input textarea {
flex: 1;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
resize: none;
font-family: inherit;
}
.agent-input button {
padding: 8px 16px;
background: #2196F3;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.agent-input button:disabled {
background: #ccc;
cursor: not-allowed;
}
.agent-tasks {
border-top: 1px solid #eee;
padding-top: 12px;
}
.agent-tasks h4 {
margin: 0 0 8px 0;
font-size: 14px;
}
.task-item {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 8px;
border-radius: 4px;
cursor: pointer;
margin-bottom: 4px;
background: white;
}
.task-item:hover {
background: #f0f0f0;
}
.task-item.pending {
border-left: 3px solid #FFC107;
}
.task-item.running {
border-left: 3px solid #2196F3;
}
.task-item.completed {
border-left: 3px solid #4CAF50;
}
.task-item.failed {
border-left: 3px solid #f44336;
}
.task-status {
font-size: 14px;
}
.task-message {
flex: 1;
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.task-progress {
font-size: 11px;
color: #666;
}
</style>
@@ -0,0 +1,416 @@
<!-- Agent状态显示组件 - 可嵌入index.html -->
<template id="agent-status-component">
<div class="agent-status-panel">
<div class="agent-header">
<h3>{{ t('agent-assistant') }}</h3>
<span class="agent-mode">{{ currentMode }}</span>
</div>
<div class="agent-messages" ref="messageContainer">
<div v-for="(msg, index) in messages" :key="index"
:class="['message', msg.role]">
<div class="message-role">{{ getRoleLabel(msg.role) }}</div>
<div class="message-content" v-html="formatMessage(msg.content)"></div>
<div class="message-time">{{ formatTime(msg.timestamp) }}</div>
</div>
</div>
<div class="agent-input">
<textarea v-model="userInput"
:placeholder="t('enter-question')"
@keydown.enter.prevent="sendMessage"
rows="3"></textarea>
<button @click="sendMessage" :disabled="isProcessing">
{{ isProcessing ? t('processing') : t('send') }}
</button>
</div>
<div class="agent-tasks" v-if="tasks.length > 0">
<h4>{{ t('task-list') }}</h4>
<div v-for="task in tasks" :key="task.task_id"
:class="['task-item', task.status]"
@click="selectTask(task)">
<span class="task-status">{{ getStatusIcon(task.status) }}</span>
<span class="task-message">{{ task.message }}</span>
<span class="task-progress">{{ task.progress }}%</span>
</div>
</div>
</div>
</template>
<script src="/static/i18n.js"></script>
// Agent状态组件
const AgentStatusComponent = {
template: '#agent-status-component',
data() {
return {
messages: [],
userInput: '',
isProcessing: false,
currentMode: '',
sessionId: '',
tasks: [],
currentTask: null,
pollingInterval: null
};
},
mounted() {
this.sessionId = 'session_' + Date.now();
this.currentMode = t('standby');
this.loadTasks();
this.startPolling();
},
beforeUnmount() {
this.stopPolling();
},
methods: {
async sendMessage() {
if (!this.userInput.trim() || this.isProcessing) return;
const message = this.userInput.trim();
this.userInput = '';
this.isProcessing = true;
// 添加用户消息
this.addMessage('user', message);
try {
// 调用Agent执行API
const response = await fetch('/api/agent/execute', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: message,
session_id: this.sessionId,
model: 'kimi'
})
});
const data = await response.json();
if (data.success) {
this.currentTask = data.task_id;
this.addMessage('system', t('msg-task-submitted') + data.task_id);
this.loadTasks();
} else {
this.addMessage('error', data.message || t('msg-submit-failed'));
}
} catch (error) {
this.addMessage('error', t('msg-request-failed') + error.message);
}
this.isProcessing = false;
},
async loadTasks() {
try {
const response = await fetch('/api/agent/tasks');
const data = await response.json();
if (data.success) {
this.tasks = data.tasks;
}
} catch (error) {
console.error(t('msg-load-task-failed'), error);
}
},
async checkTaskStatus(taskId) {
try {
const response = await fetch(`/api/agent/status/${taskId}`);
const data = await response.json();
if (data.success && data.task) {
const task = data.task;
// 更新任务状态
const taskIndex = this.tasks.findIndex(t => t.task_id === taskId);
if (taskIndex >= 0) {
this.tasks[taskIndex] = { ...this.tasks[taskIndex], ...task };
}
// 如果任务完成,显示结果
if (task.status === 'completed' && task.result) {
this.addMessage('assistant', task.result.response || t('msg-task-completed'));
// 显示执行结果摘要
if (task.result.execution_result) {
const execResult = task.result.execution_result;
if (execResult.status === 'success') {
const manifest = execResult.manifest || {};
const metrics = manifest.metrics || {};
this.addMessage('system',
t('msg-analysis-complete') + (metrics.final_members || 0) + t('msg-gene-members'));
}
}
} else if (task.status === 'failed') {
this.addMessage('error', task.result?.response || t('msg-task-failed'));
}
}
} catch (error) {
console.error(t('msg-check-task-status-failed'), error);
}
},
selectTask(task) {
this.currentTask = task.task_id;
this.checkTaskStatus(task.task_id);
},
startPolling() {
this.pollingInterval = setInterval(() => {
if (this.currentTask) {
this.checkTaskStatus(this.currentTask);
}
this.loadTasks();
}, 3000); // 每3秒轮询一次
},
stopPolling() {
if (this.pollingInterval) {
clearInterval(this.pollingInterval);
}
},
addMessage(role, content) {
this.messages.push({
role: role,
content: content,
timestamp: new Date().toISOString()
});
// 滚动到底部
setTimeout(() => {
const container = this.$refs.messageContainer;
if (container) {
container.scrollTop = container.scrollHeight;
}
}, 100);
},
getRoleLabel(role) {
const keys = {
'user': 'user-role',
'assistant': 'agent-role',
'system': 'system-role',
'error': 'error-role',
'execution': 'execution-role',
'planning': 'planning-role',
'diagnosis': 'diagnosis-role'
};
return keys[role] ? t(keys[role]) : role;
},
getStatusIcon(status) {
const icons = {
'pending': '⏳',
'running': '🔄',
'completed': '✅',
'failed': '❌',
'cancelled': '🚫'
};
return icons[status] || '❓';
},
formatMessage(content) {
// 简单的Markdown格式化
return content
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
.replace(/\n/g, '<br>');
},
formatTime(timestamp) {
if (!timestamp) return '';
const date = new Date(timestamp);
return date.toLocaleTimeString('zh-CN', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
},
t(key) {
return window.t ? window.t(key) : key;
}
}
};
</script>
<style>
.agent-status-panel {
border: 1px solid #ddd;
border-radius: 8px;
padding: 16px;
background: #f9f9f9;
height: 100%;
display: flex;
flex-direction: column;
}
.agent-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #eee;
}
.agent-header h3 {
margin: 0;
font-size: 16px;
}
.agent-mode {
font-size: 12px;
color: #666;
background: #e0e0e0;
padding: 2px 8px;
border-radius: 4px;
}
.agent-messages {
flex: 1;
overflow-y: auto;
max-height: 400px;
margin-bottom: 12px;
}
.message {
margin-bottom: 12px;
padding: 8px 12px;
border-radius: 8px;
background: white;
border-left: 3px solid #ddd;
}
.message.user {
border-left-color: #4CAF50;
background: #E8F5E9;
}
.message.assistant {
border-left-color: #2196F3;
background: #E3F2FD;
}
.message.error {
border-left-color: #f44336;
background: #FFEBEE;
}
.message.system {
border-left-color: #9E9E9E;
background: #F5F5F5;
font-size: 12px;
}
.message-role {
font-size: 12px;
color: #666;
margin-bottom: 4px;
}
.message-content {
font-size: 14px;
line-height: 1.5;
}
.message-time {
font-size: 11px;
color: #999;
text-align: right;
margin-top: 4px;
}
.agent-input {
display: flex;
gap: 8px;
margin-bottom: 12px;
}
.agent-input textarea {
flex: 1;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
resize: none;
font-family: inherit;
}
.agent-input button {
padding: 8px 16px;
background: #2196F3;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.agent-input button:disabled {
background: #ccc;
cursor: not-allowed;
}
.agent-tasks {
border-top: 1px solid #eee;
padding-top: 12px;
}
.agent-tasks h4 {
margin: 0 0 8px 0;
font-size: 14px;
}
.task-item {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 8px;
border-radius: 4px;
cursor: pointer;
margin-bottom: 4px;
background: white;
}
.task-item:hover {
background: #f0f0f0;
}
.task-item.pending {
border-left: 3px solid #FFC107;
}
.task-item.running {
border-left: 3px solid #2196F3;
}
.task-item.completed {
border-left: 3px solid #4CAF50;
}
.task-item.failed {
border-left: 3px solid #f44336;
}
.task-status {
font-size: 14px;
}
.task-message {
flex: 1;
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.task-progress {
font-size: 11px;
color: #666;
}
</style>
Binary file not shown.
@@ -0,0 +1,385 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BotanicalBaseAgent - 基因家族分析</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-plus@2.3.14/dist/index.css">
<script src="https://cdn.jsdelivr.net/npm/vue@3.3.4/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/element-plus@2.3.14/dist/index.full.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@element-plus/icons-vue@2.1.0/dist/index.iife.js"></script>
<link rel="stylesheet" href="conversation-sidebar.css">
<style>
* { box-sizing: border-box; }
body {
margin: 0;
font-family: 'Helvetica Neue', Arial, sans-serif;
background: #f5f7fa;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 15px 20px;
}
.header h1 { margin: 0; font-size: 22px; }
.main-container {
display: flex;
height: calc(100vh - 60px);
overflow: hidden;
}
/* 左侧控制面板 */
.left-panel {
width: 280px;
background: white;
border-right: 1px solid #e4e7ed;
display: flex;
flex-direction: column;
padding: 15px;
gap: 15px;
overflow-y: auto;
}
/* 中间内容区 */
.center-panel {
flex: 1;
display: flex;
flex-direction: column;
padding: 15px;
gap: 15px;
overflow: hidden;
}
/* 右侧结果区 */
.right-panel {
width: 350px;
background: white;
border-left: 1px solid #e4e7ed;
padding: 15px;
overflow-y: auto;
}
.panel-section {
background: white;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
.panel-title {
font-size: 14px;
font-weight: bold;
color: #409EFF;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 2px solid #409EFF;
}
.chat-area {
flex: 1;
background: white;
border-radius: 8px;
padding: 15px;
overflow-y: auto;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
.chat-message {
margin-bottom: 15px;
padding: 12px 16px;
border-radius: 8px;
max-width: 80%;
}
.chat-message.user {
background: #ecf5ff;
margin-left: auto;
text-align: right;
}
.chat-message.assistant {
background: #f0f9eb;
}
.input-area {
display: flex;
gap: 10px;
}
.stage-tag {
display: inline-block;
padding: 4px 12px;
border-radius: 4px;
font-size: 12px;
margin: 4px;
}
.stage-tag.success { background: #67C23A; color: white; }
.stage-tag.running { background: #E6A23C; color: white; }
.stage-tag.pending { background: #909399; color: white; }
</style>
</head>
<body>
<div id="app">
<!-- Header -->
<div class="header">
<h1>🌱 BotanicalBaseAgent - 基因家族分析系统</h1>
</div>
<div class="main-container">
<!-- 左侧:会话侧边栏 + 控制面板 -->
<div class="left-panel">
<!-- 会话侧边栏 -->
<div class="conversation-sidebar" style="width: 100%; margin: -15px; margin-bottom: 0;">
<div class="sidebar-header">
<button class="new-chat-btn" @click="createNewConversation" style="flex: 1;">
<el-icon><plus /></el-icon>
<span>New Chat</span>
</button>
</div>
<div class="search-box" style="padding: 12px;">
<el-input
v-model="searchQuery"
placeholder="搜索会话..."
prefix-icon="search"
clearable
size="small">
</el-input>
</div>
<div class="conversation-list" style="max-height: 300px;">
<div class="list-section">
<div class="section-title">会话列表</div>
<div v-for="conv in filteredConversations"
:key="conv.id"
class="conversation-item"
:class="{ active: currentConv?.id === conv.id }"
@click="selectConversation(conv)">
<div class="item-icon">
<el-icon><chat-dot-round /></el-icon>
</div>
<div class="item-content">
<div class="item-title">{{ conv.title }}</div>
<div class="item-meta">
<span class="gene-family" v-if="conv.gene_family">{{ conv.gene_family }}</span>
<span class="message-count">{{ conv.message_count }}条消息</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 分析控制 -->
<div class="panel-section">
<div class="panel-title">▶ Analysis Stage</div>
<el-select v-model="selectedStage" placeholder="选择分析阶段" style="width: 100%;">
<el-option label="Identify - 基因家族鉴定" value="identify"></el-option>
<el-option label="Phylogeny - 系统发育分析" value="phylogeny"></el-option>
<el-option label="Motif - Motif分析" value="motif"></el-option>
<el-option label="Domain - 结构域分析" value="domain"></el-option>
<el-option label="Expression - 表达分析" value="expression"></el-option>
</el-select>
<el-button type="primary" style="width: 100%; margin-top: 10px;" @click="executeAnalysis">
🚀 执行分析
</el-button>
</div>
<!-- 参数设置 -->
<div class="panel-section">
<div class="panel-title">⚙️ 参数设置</div>
<el-form :model="params" label-width="80px" size="small">
<el-form-item label="前缀">
<el-input v-model="params.prefix" placeholder="如: Ft.SPL"></el-input>
</el-form-item>
<el-form-item label="CPU">
<el-input-number v-model="params.cpu" :min="1" :max="32" style="width: 100%;"></el-input-number>
</el-form-item>
</el-form>
</div>
</div>
<!-- 中间:对话区 -->
<div class="center-panel">
<div class="chat-area">
<div v-for="(msg, index) in messages" :key="index"
class="chat-message" :class="msg.role">
<div style="font-size: 12px; color: #666; margin-bottom: 4px;">
{{ msg.role === 'user' ? '用户' : 'AI助手' }} · {{ msg.time }}
</div>
<div>{{ msg.content }}</div>
</div>
<div v-if="messages.length === 0" style="text-align: center; color: #999; padding: 40px;">
<el-icon :size="48" style="display: block; margin-bottom: 10px;"><chat-line-round /></el-icon>
<p>开始一个新的对话</p>
<p style="font-size: 12px;">或点击左侧会话继续之前的对话</p>
</div>
</div>
<div class="input-area">
<el-input
v-model="userInput"
type="textarea"
:rows="3"
placeholder="描述您的需求,如:帮我分析拟南芥SPL基因家族"
@keyup.enter.ctrl="sendMessage">
</el-input>
<el-button type="primary" size="large" @click="sendMessage" :disabled="!userInput.trim()">
发送
</el-button>
</div>
</div>
<!-- 右侧:结果展示 -->
<div class="right-panel">
<div class="panel-title">📊 Analysis Results</div>
<div v-for="stage in stages" :key="stage.name" style="margin-bottom: 15px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
<span style="font-weight: 500;">{{ stage.label }}</span>
<span class="stage-tag" :class="stage.status">{{ stage.statusText }}</span>
</div>
<el-progress :percentage="stage.progress" :status="stage.status"></el-progress>
</div>
<el-divider></el-divider>
<div style="text-align: center; color: #999; padding: 20px;">
<el-icon :size="48" style="display: block; margin-bottom: 10px;"><picture /></el-icon>
<p>分析结果将在此显示</p>
</div>
</div>
</div>
</div>
<script>
const { createApp, ref, reactive, computed } = Vue;
const app = createApp({
setup() {
// 会话管理
const conversations = ref([
{ id: 1, title: 'Ft.SPL基因家族分析', gene_family: 'SPL', message_count: 12 },
{ id: 2, title: 'Os.TCP进化分析', gene_family: 'TCP', message_count: 5 },
{ id: 3, title: 'HMMER参数配置咨询', gene_family: null, message_count: 8 },
]);
const currentConv = ref(null);
const searchQuery = ref('');
const filteredConversations = computed(() => {
if (!searchQuery.value) return conversations.value;
const query = searchQuery.value.toLowerCase();
return conversations.value.filter(conv =>
conv.title.toLowerCase().includes(query) ||
(conv.gene_family && conv.gene_family.toLowerCase().includes(query))
);
});
const createNewConversation = () => {
const newConv = {
id: Date.now(),
title: '新会话 ' + new Date().toLocaleTimeString(),
gene_family: null,
message_count: 0
};
conversations.value.unshift(newConv);
selectConversation(newConv);
};
const selectConversation = (conv) => {
currentConv.value = conv;
// 清空消息并添加欢迎语
messages.value = [{
role: 'assistant',
content: `欢迎来到 "${conv.title}"!我是BotanicalBaseAgent,专注于基因家族分析。请告诉我您想分析哪个基因家族?`,
time: new Date().toLocaleTimeString()
}];
};
// 分析参数
const selectedStage = ref('');
const params = reactive({
prefix: 'Ft.SPL',
cpu: 8
});
// 消息
const messages = ref([]);
const userInput = ref('');
const sendMessage = () => {
if (!userInput.value.trim()) return;
// 添加用户消息
messages.value.push({
role: 'user',
content: userInput.value,
time: new Date().toLocaleTimeString()
});
// 更新当前会话消息数
if (currentConv.value) {
currentConv.value.message_count++;
}
// 模拟AI回复
setTimeout(() => {
messages.value.push({
role: 'assistant',
content: `收到您的请求:"${userInput.value}"。我将帮您分析基因家族。请确认分析参数后点击"执行分析"。`,
time: new Date().toLocaleTimeString()
});
if (currentConv.value) {
currentConv.value.message_count++;
}
}, 500);
userInput.value = '';
};
// 分析阶段
const stages = ref([
{ name: 'identify', label: 'Identify', status: 'success', statusText: '已完成', progress: 100 },
{ name: 'phylogeny', label: 'Phylogeny', status: 'running', statusText: '运行中', progress: 60 },
{ name: 'motif', label: 'Motif', status: 'pending', statusText: '等待中', progress: 0 },
{ name: 'domain', label: 'Domain', status: 'pending', statusText: '等待中', progress: 0 },
]);
const executeAnalysis = () => {
if (!selectedStage.value) {
ElementPlus.ElMessage.warning('请先选择分析阶段');
return;
}
ElementPlus.ElMessage.success(`开始执行 ${selectedStage.value} 分析`);
};
return {
conversations,
currentConv,
searchQuery,
filteredConversations,
createNewConversation,
selectConversation,
selectedStage,
params,
messages,
userInput,
sendMessage,
stages,
executeAnalysis
};
}
});
app.use(ElementPlus);
// 注册图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component);
}
app.mount('#app');
</script>
</body>
</html>
@@ -0,0 +1,391 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<script src="/static/i18n.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BotanicalBaseAgent</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-plus@2.3.14/dist/index.css">
<script src="https://cdn.jsdelivr.net/npm/vue@3.3.4/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/element-plus@2.3.14/dist/index.full.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@element-plus/icons-vue@2.1.0/dist/index.iife.js"></script>
<link rel="stylesheet" href="conversation-sidebar.css">
<style>
* { box-sizing: border-box; }
body {
margin: 0;
font-family: 'Helvetica Neue', Arial, sans-serif;
background: #f5f7fa;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 15px 20px;
}
.header h1 { margin: 0; font-size: 22px; }
.main-container {
display: flex;
height: calc(100vh - 60px);
overflow: hidden;
}
/* 左侧控制面板 */
.left-panel {
width: 280px;
background: white;
border-right: 1px solid #e4e7ed;
display: flex;
flex-direction: column;
padding: 15px;
gap: 15px;
overflow-y: auto;
}
/* 中间内容区 */
.center-panel {
flex: 1;
display: flex;
flex-direction: column;
padding: 15px;
gap: 15px;
overflow: hidden;
}
/* 右侧结果区 */
.right-panel {
width: 350px;
background: white;
border-left: 1px solid #e4e7ed;
padding: 15px;
overflow-y: auto;
}
.panel-section {
background: white;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
.panel-title {
font-size: 14px;
font-weight: bold;
color: #409EFF;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 2px solid #409EFF;
}
.chat-area {
flex: 1;
background: white;
border-radius: 8px;
padding: 15px;
overflow-y: auto;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
.chat-message {
margin-bottom: 15px;
padding: 12px 16px;
border-radius: 8px;
max-width: 80%;
}
.chat-message.user {
background: #ecf5ff;
margin-left: auto;
text-align: right;
}
.chat-message.assistant {
background: #f0f9eb;
}
.input-area {
display: flex;
gap: 10px;
}
.stage-tag {
display: inline-block;
padding: 4px 12px;
border-radius: 4px;
font-size: 12px;
margin: 4px;
}
.stage-tag.success { background: #67C23A; color: white; }
.stage-tag.running { background: #E6A23C; color: white; }
.stage-tag.pending { background: #909399; color: white; }
</style>
</head>
<body>
<div id="app">
<!-- Header -->
<div class="header">
<h1>{{ t('gf-analysis-system') }}</h1>
</div>
<div class="main-container">
<!-- 左侧:会话侧边栏 + 控制面板 -->
<div class="left-panel">
<!-- 会话侧边栏 -->
<div class="conversation-sidebar" style="width: 100%; margin: -15px; margin-bottom: 0;">
<div class="sidebar-header">
<button class="new-chat-btn" @click="createNewConversation" style="flex: 1;">
<el-icon><plus /></el-icon>
<span>New Chat</span>
</button>
</div>
<div class="search-box" style="padding: 12px;">
<el-input
v-model="searchQuery"
:placeholder="t('search-conv')"
prefix-icon="search"
clearable
size="small">
</el-input>
</div>
<div class="conversation-list" style="max-height: 300px;">
<div class="list-section">
<div class="section-title">{{ t('conv-list') }}</div>
<div v-for="conv in filteredConversations"
:key="conv.id"
class="conversation-item"
:class="{ active: currentConv?.id === conv.id }"
@click="selectConversation(conv)">
<div class="item-icon">
<el-icon><chat-dot-round /></el-icon>
</div>
<div class="item-content">
<div class="item-title">{{ conv.title }}</div>
<div class="item-meta">
<span class="gene-family" v-if="conv.gene_family">{{ conv.gene_family }}</span>
<span class="message-count">{{ conv.message_count }}{{ t('msg-count') }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 分析控制 -->
<div class="panel-section">
<div class="panel-title">{{ t('analysis-stage') }}</div>
<el-select v-model="selectedStage" :placeholder="t('select-stage')" style="width: 100%;">
<el-option :label="t('identify-label')" value="identify"></el-option>
<el-option :label="t('phylogeny-label')" value="phylogeny"></el-option>
<el-option :label="t('motif-label')" value="motif"></el-option>
<el-option :label="t('domain-label')" value="domain"></el-option>
<el-option :label="t('expression-label')" value="expression"></el-option>
</el-select>
<el-button type="primary" style="width: 100%; margin-top: 10px;" @click="executeAnalysis">
{{ t('execute-analysis') }}
</el-button>
</div>
<!-- 参数设置 -->
<div class="panel-section">
<div class="panel-title">{{ t('param-settings') }}</div>
<el-form :model="params" label-width="80px" size="small">
<el-form-item :label="t('prefix')">
<el-input v-model="params.prefix" :placeholder="t('prefix-placeholder')"></el-input>
</el-form-item>
<el-form-item label="CPU">
<el-input-number v-model="params.cpu" :min="1" :max="32" style="width: 100%;"></el-input-number>
</el-form-item>
</el-form>
</div>
</div>
<!-- 中间:对话区 -->
<div class="center-panel">
<div class="chat-area">
<div v-for="(msg, index) in messages" :key="index"
class="chat-message" :class="msg.role">
<div style="font-size: 12px; color: #666; margin-bottom: 4px;">
{{ msg.role === 'user' ? t('user') : t('ai-assistant') }} · {{ msg.time }}
</div>
<div>{{ msg.content }}</div>
</div>
<div v-if="messages.length === 0" style="text-align: center; color: #999; padding: 40px;">
<el-icon :size="48" style="display: block; margin-bottom: 10px;"><chat-line-round /></el-icon>
<p>{{ t('start-new-chat') }}</p>
<p style="font-size: 12px;">{{ t('or-continue') }}</p>
</div>
</div>
<div class="input-area">
<el-input
v-model="userInput"
type="textarea"
:rows="3"
:placeholder="t('describe-need')"
@keyup.enter.ctrl="sendMessage">
</el-input>
<el-button type="primary" size="large" @click="sendMessage" :disabled="!userInput.trim()">
{{ t('send') }}
</el-button>
</div>
</div>
<!-- 右侧:结果展示 -->
<div class="right-panel">
<div class="panel-title">📊 Analysis Results</div>
<div v-for="stage in stages" :key="stage.name" style="margin-bottom: 15px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
<span style="font-weight: 500;">{{ stage.label }}</span>
<span class="stage-tag" :class="stage.status">{{ stage.statusText }}</span>
</div>
<el-progress :percentage="stage.progress" :status="stage.status"></el-progress>
</div>
<el-divider></el-divider>
<div style="text-align: center; color: #999; padding: 20px;">
<el-icon :size="48" style="display: block; margin-bottom: 10px;"><picture /></el-icon>
<p>{{ t('results-here') }}</p>
</div>
</div>
</div>
</div>
<script>
const { createApp, ref, reactive, computed } = Vue;
const app = createApp({
setup() {
const t = window.t;
document.title = 'BotanicalBaseAgent - ' + t('gf-analysis');
// 会话管理
const conversations = ref([
{ id: 1, title: 'Ft.SPL基因家族分析', gene_family: 'SPL', message_count: 12 },
{ id: 2, title: 'Os.TCP进化分析', gene_family: 'TCP', message_count: 5 },
{ id: 3, title: 'HMMER参数配置咨询', gene_family: null, message_count: 8 },
]);
const currentConv = ref(null);
const searchQuery = ref('');
const filteredConversations = computed(() => {
if (!searchQuery.value) return conversations.value;
const query = searchQuery.value.toLowerCase();
return conversations.value.filter(conv =>
conv.title.toLowerCase().includes(query) ||
(conv.gene_family && conv.gene_family.toLowerCase().includes(query))
);
});
const createNewConversation = () => {
const newConv = {
id: Date.now(),
title: t('new-chat') + ' ' + new Date().toLocaleTimeString(),
gene_family: null,
message_count: 0
};
conversations.value.unshift(newConv);
selectConversation(newConv);
};
const selectConversation = (conv) => {
currentConv.value = conv;
// 清空消息并添加欢迎语
messages.value = [{
role: 'assistant',
content: t('initial-welcome').replace('{title}', conv.title),
time: new Date().toLocaleTimeString()
}];
};
// 分析参数
const selectedStage = ref('');
const params = reactive({
prefix: 'Ft.SPL',
cpu: 8
});
// 消息
const messages = ref([]);
const userInput = ref('');
const sendMessage = () => {
if (!userInput.value.trim()) return;
// 添加用户消息
messages.value.push({
role: 'user',
content: userInput.value,
time: new Date().toLocaleTimeString()
});
// 更新当前会话消息数
if (currentConv.value) {
currentConv.value.message_count++;
}
// 模拟AI回复
setTimeout(() => {
messages.value.push({
role: 'assistant',
content: `Received: "${userInput.value}". I will help analyze the gene family. Confirm parameters and click "${t('execute-analysis')}".`,
time: new Date().toLocaleTimeString()
});
if (currentConv.value) {
currentConv.value.message_count++;
}
}, 500);
userInput.value = '';
};
// 分析阶段
const stages = ref([
{ name: 'identify', label: 'Identify', status: 'success', statusText: t('completed'), progress: 100 },
{ name: 'phylogeny', label: 'Phylogeny', status: 'running', statusText: t('running'), progress: 60 },
{ name: 'motif', label: 'Motif', status: 'pending', statusText: t('pending'), progress: 0 },
{ name: 'domain', label: 'Domain', status: 'pending', statusText: t('pending'), progress: 0 },
]);
const executeAnalysis = () => {
if (!selectedStage.value) {
ElementPlus.ElMessage.warning(t('msg-select-stage-first'));
return;
}
ElementPlus.ElMessage.success(t('msg-executing') + selectedStage.value + t('msg-analysis-text'));
};
return {
t,
conversations,
currentConv,
searchQuery,
filteredConversations,
createNewConversation,
selectConversation,
selectedStage,
params,
messages,
userInput,
sendMessage,
stages,
executeAnalysis
};
}
});
app.use(ElementPlus);
// 注册 i18n 翻译函数到 Vue 模板作用域
app.config.globalProperties.t = window.t || ((key) => key);
// 注册图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component);
}
app.mount('#app');
</script>
</body>
</html>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+702
View File
@@ -0,0 +1,702 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>知识图谱 - V13.1 基因家族分析</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-plus@2.7.1/dist/index.css">
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/element-plus@2.7.1/dist/index.full.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@element-plus/icons-vue"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<style>
body { margin: 0; font-family: 'Helvetica Neue', Arial, sans-serif; background: #f5f7fa; }
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 15px 20px; display: flex; align-items: center; justify-content: space-between; }
.header h1 { margin: 0; font-size: 22px; }
.header .subtitle { font-size: 12px; opacity: 0.8; margin-top: 4px; }
.main-container { display: flex; padding: 15px; gap: 15px; height: calc(100vh - 70px); }
.left-panel { width: 300px; display: flex; flex-direction: column; gap: 10px; }
.control-section { background: white; border-radius: 8px; padding: 15px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); }
.control-section h4 { margin: 0 0 10px 0; color: #409EFF; font-size: 14px; border-bottom: 2px solid #409EFF; padding-bottom: 8px; }
.stat-item { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #eee; }
.stat-item:last-child { border-bottom: none; }
.stat-label { color: #666; }
.stat-value { font-weight: bold; color: #409EFF; }
.filter-section { margin-top: 10px; }
.filter-tag { margin: 4px; cursor: pointer; }
.filter-tag.active { background: #409EFF; color: white; }
.main-panel { flex: 1; display: flex; flex-direction: column; background: white; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); overflow: hidden; }
.toolbar { padding: 10px 15px; border-bottom: 1px solid #eee; display: flex; align-items: center; gap: 10px; }
#graph-container { flex: 1; position: relative; }
.right-panel { width: 350px; background: white; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); padding: 15px; overflow-y: auto; }
.right-panel h4 { margin: 0 0 10px 0; color: #67C23A; border-bottom: 2px solid #67C23A; padding-bottom: 8px; }
.node-detail { padding: 10px; background: #f5f7fa; border-radius: 6px; margin-top: 10px; }
.node-detail .label { color: #666; font-size: 12px; margin-bottom: 4px; }
.node-detail .value { font-weight: 500; color: #333; }
.relation-list { margin-top: 10px; }
.relation-item { padding: 8px; background: #f0f9eb; border-radius: 4px; margin-bottom: 8px; font-size: 13px; }
.relation-item .source { color: #409EFF; font-weight: 500; }
.relation-item .rel { color: #67C23A; margin: 0 4px; }
.relation-item .target { color: #E6A23C; font-weight: 500; }
.search-box { margin-bottom: 10px; }
.legend { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.legend-item { display: flex; align-items: center; gap: 4px; font-size: 12px; }
.legend-color { width: 12px; height: 12px; border-radius: 50%; }
.legend-symbol { width: 12px; height: 12px; border-radius: 2px; }
.legend-line { width: 20px; height: 2px; }
/* PC语义分类样式 */
.pc-category-header {
font-size: 11px;
color: #666;
font-weight: bold;
margin: 8px 0 4px 0;
padding-left: 4px;
border-left: 3px solid #409EFF;
}
</style>
</head>
<body>
<div id="app">
<div class="header">
<div>
<h1>🧬 知识图谱可视化</h1>
<div class="subtitle">V13.1 基因家族分析系统 - Pecan SPL</div>
</div>
<el-button type="primary" @click="goBack">
<el-icon><arrow-left /></el-icon> 返回主界面
</el-button>
</div>
<div class="main-container">
<!-- 左侧面板 -->
<div class="left-panel">
<div class="control-section">
<h4>📊 图谱统计</h4>
<div class="stat-item">
<span class="stat-label">节点总数</span>
<span class="stat-value">{{ stats.nodes }}</span>
</div>
<div class="stat-item">
<span class="stat-label">关系总数</span>
<span class="stat-value">{{ stats.edges }}</span>
</div>
<div class="stat-item">
<span class="stat-label">节点类型</span>
<span class="stat-value">{{ stats.nodeTypes }}</span>
</div>
<div class="stat-item">
<span class="stat-label">关系类型</span>
<span class="stat-value">{{ stats.edgeTypes }}</span>
</div>
</div>
<div class="control-section">
<h4>🔍 节点搜索</h4>
<el-input
v-model="searchQuery"
placeholder="输入基因名或实体..."
clearable
@keyup.enter="searchNode"
>
<template #append>
<el-button @click="searchNode">
<el-icon><search /></el-icon>
</el-button>
</template>
</el-input>
</div>
<div class="control-section">
<h4>🏷️ 关系过滤 (PC语义)</h4>
<div class="filter-section">
<div v-for="(types, category) in relationTypesByCategory" :key="category" style="margin-bottom: 10px;">
<div style="font-size: 12px; color: #666; margin-bottom: 5px; font-weight: bold;">
{{ category === 'activation' ? '激活/诱导' :
category === 'repression' ? '抑制/下调' :
category === 'regulation' ? '调控' :
category === 'expression' ? '表达' :
category === 'association' ? '关联' :
category === 'localization' ? '定位' :
category === 'containment' ? '包含' :
category === 'participation' ? '参与' : '其他' }}
</div>
<el-tag
v-for="type in types"
:key="type"
class="filter-tag"
:class="{ active: selectedRelations.includes(type) }"
@click="toggleRelationFilter(type)"
size="small"
:style="{ borderColor: relationEdgeStyles[category].color, color: selectedRelations.includes(type) ? '#fff' : relationEdgeStyles[category].color }"
>
{{ type }} ({{ relationCounts[type] }})
</el-tag>
</div>
</div>
</div>
<div class="control-section">
<h4>🎨 节点图例 (PC语义)</h4>
<div class="pc-category-header">Gene/Protein</div>
<div class="legend">
<div class="legend-item" v-for="type in ['gene', 'gene_id', 'gene_group', 'gene_family']" :key="type">
<div class="legend-symbol" :style="{ background: nodeColors[type] }"></div>
<span>{{ nodeTypeLabels[type] }}</span>
</div>
</div>
<div class="pc-category-header">Phenotype</div>
<div class="legend">
<div class="legend-item" v-for="type in ['phenotype', 'attribute']" :key="type">
<div class="legend-symbol" :style="{ background: nodeColors[type] }"></div>
<span>{{ nodeTypeLabels[type] }}</span>
</div>
</div>
<div class="pc-category-header">Cell/Organ/Organism</div>
<div class="legend">
<div class="legend-item" v-for="type in ['tissue', 'species']" :key="type">
<div class="legend-symbol" :style="{ background: nodeColors[type] }"></div>
<span>{{ nodeTypeLabels[type] }}</span>
</div>
</div>
<div class="pc-category-header">Biological Process</div>
<div class="legend">
<div class="legend-item" v-for="type in ['process', 'time', 'condition', 'stress']" :key="type">
<div class="legend-symbol" :style="{ background: nodeColors[type] }"></div>
<span>{{ nodeTypeLabels[type] }}</span>
</div>
</div>
<div class="pc-category-header">Genomic</div>
<div class="legend">
<div class="legend-item" v-for="type in ['location', 'sra_dataset', 'data_type', 'count']" :key="type">
<div class="legend-symbol" :style="{ background: nodeColors[type] }"></div>
<span>{{ nodeTypeLabels[type] }}</span>
</div>
</div>
<h4 style="margin-top: 15px;">🔗 关系图例 (PC语义)</h4>
<div class="legend">
<div class="legend-item" v-for="(style, cat) in relationEdgeStyles" :key="cat">
<div class="legend-line" :style="{ background: style.color, height: style.width + 'px', borderTop: style.type === 'dashed' ? '2px dashed ' + style.color : 'none' }"></div>
<span>{{ cat === 'activation' ? 'Activation/Induction' :
cat === 'repression' ? 'Repression/Inhibition' :
cat === 'regulation' ? 'Regulation/Control' :
cat === 'expression' ? 'Expression/Detection' :
cat === 'association' ? 'Association/Interaction' :
cat === 'localization' ? 'Localization' :
cat === 'containment' ? 'Containment/Composition' :
cat === 'participation' ? 'Participation/Function' : 'Other' }}</span>
</div>
</div>
</div>
</div>
<!-- 主面板 -->
<div class="main-panel">
<div class="toolbar">
<el-button-group>
<el-button @click="fitGraph">
<el-icon><full-screen /></el-icon> 适应视图
</el-button>
<el-button @click="resetFilters">
<el-icon><refresh /></el-icon> 重置过滤
</el-button>
</el-button-group>
<el-divider direction="vertical"></el-divider>
<span style="color: #666; font-size: 13px;">
💡 点击节点查看详情,拖拽调整布局
</span>
</div>
<div id="graph-container"></div>
</div>
<!-- 右侧面板 -->
<div class="right-panel">
<h4>📋 节点详情</h4>
<div v-if="selectedNode" class="node-detail">
<div style="margin-bottom: 15px;">
<div class="label">节点名称</div>
<div class="value" style="font-size: 18px; color: #409EFF;">{{ selectedNode.name }}</div>
</div>
<div style="margin-bottom: 15px;">
<div class="label">节点类型 (PC)</div>
<div class="value">
<el-tag :type="getNodeTypeTag(selectedNode.category)" :style="{ backgroundColor: nodeColors[selectedNode.category] + '20', borderColor: nodeColors[selectedNode.category], color: nodeColors[selectedNode.category] }">
{{ nodeTypeLabels[selectedNode.category] || selectedNode.category }}
</el-tag>
</div>
</div>
<div>
<div class="label">连接关系数</div>
<div class="value">{{ selectedNode.degree }} 个</div>
</div>
</div>
<div v-else style="color: #999; text-align: center; padding: 40px;">
点击图谱中的节点查看详情
</div>
<template v-if="selectedNodeRelations.length > 0">
<h4 style="margin-top: 20px;">🔗 相关关系 ({{ selectedNodeRelations.length }})</h4>
<div class="relation-list">
<div
v-for="rel in selectedNodeRelations.slice(0, 10)"
:key="rel.id"
class="relation-item"
:style="{ borderLeft: '3px solid ' + relationEdgeStyles[rel.category || relationCategories[rel.name] || 'other'].color }"
>
<span class="source">{{ rel.source }}</span>
<span class="rel" :style="{ color: relationEdgeStyles[rel.category || relationCategories[rel.name] || 'other'].color }">--{{ rel.name }}--></span>
<span class="target">{{ rel.target }}</span>
</div>
<div v-if="selectedNodeRelations.length > 10" style="text-align: center; color: #999; padding: 10px;">
还有 {{ selectedNodeRelations.length - 10 }} 个关系...
</div>
</div>
</template>
</div>
</div>
</div>
<script>
const { createApp, ref, onMounted, computed } = Vue;
const { ElMessage } = ElementPlus;
createApp({
setup() {
const graphData = ref({ nodes: [], edges: [] });
const chart = ref(null);
const searchQuery = ref('');
const selectedNode = ref(null);
const selectedRelations = ref([]);
// PC (Pathway Commons) 语义分类颜色映射
const nodeColors = {
// Gene/Protein - 蓝色
'gene': '#5DADE2',
'gene_id': '#85C1E9',
'gene_group': '#AED6F1',
'gene_family': '#5DADE2',
// Phenotype - 绿色
'phenotype': '#58D68D',
'attribute': '#82E0AA',
// Cell/Organ/Organism - 粉色
'tissue': '#F5B7B1',
'species': '#F1948A',
// Process - 紫色菱形
'process': '#AF7AC5',
'time': '#C39BD3',
'condition': '#D7BDE2',
'stress': '#E8DAEF',
// Location - 浅绿色
'location': '#82E0AA',
// Data - 橙色(更显眼)
'sra_dataset': '#E67E22',
'data_type': '#F39C12',
'count': '#EAEDED',
'unknown': '#95A5A6'
,
'article': '#2ecc71',
'paper_title': '#9b59b6'
};
// PC 语义分类显示名称
const nodeTypeLabels = {
'gene': 'Gene/Protein',
'gene_id': 'Gene Identifier',
'gene_group': 'Gene Group',
'gene_family': 'Gene Family',
'phenotype': 'Phenotype',
'attribute': 'Attribute',
'tissue': 'Cell/Organ/Tissue',
'species': 'Organism',
'process': 'Biological Process',
'time': 'Time/Stage',
'condition': 'Condition',
'stress': 'Stress',
'location': 'Genomic Location',
'sra_dataset': 'SRA Dataset',
'geo_dataset': 'GEO Dataset',
'data_type': 'Data Type',
'count': 'Count/Statistic',
'article': 'Article (PMID)',
'paper_title': 'Paper Title',
'unknown': 'Other'
};
// PC 关系类型分类
const relationCategories = {
// Activation/Induction - 绿色箭头
'induces': 'activation',
'promote': 'activation',
'overexpression_increases': 'activation',
'enhanced_tolerance_to': 'activation',
// Repression/Inhibition - 红色T型
'down_regulated_during': 'repression',
'down_regulation_improves': 'repression',
// Regulation - 蓝色
'regulate': 'regulation',
'regulates': 'regulation',
'regulating': 'regulation',
// Expression - 橙色
'expressed_in': 'expression',
'expressed_during': 'expression',
'was_expressed_during': 'expression',
'expression_reached_peak_at': 'expression',
// Association - 紫色
'collinear_with': 'association',
'was_highly_orthologous_to': 'association',
'related_to': 'association',
'affect': 'association',
// Localization - 深绿
'located_on': 'localization',
'identified_in': 'localization',
// Containment - 青色
'contain': 'containment',
'had': 'containment',
'has_gene_id': 'containment',
'has_data_type': 'containment',
// Participation - 深红
'involved_in': 'participation',
'participate_in': 'participation',
'default': 'other'
};
const relationEdgeStyles = {
'activation': { color: '#27AE60', width: 2, type: 'solid' },
'repression': { color: '#E74C3C', width: 2, type: 'solid' },
'regulation': { color: '#3498DB', width: 2, type: 'solid' },
'expression': { color: '#E67E22', width: 1.5, type: 'solid' },
'association': { color: '#9B59B6', width: 1.5, type: 'dashed' },
'localization': { color: '#16A085', width: 1.5, type: 'solid' },
'containment': { color: '#1ABC9C', width: 1.5, type: 'solid' },
'participation': { color: '#C0392B', width: 2, type: 'solid' },
'other': { color: '#95A5A6', width: 1, type: 'solid' }
};
const stats = computed(() => ({
nodes: graphData.value.nodes.length,
edges: graphData.value.edges.length,
nodeTypes: Object.keys(nodeColors).length,
edgeTypes: relationTypes.value.length
}));
// 按 PC 语义分类的关系类型
const relationTypesByCategory = computed(() => {
const cats = {};
graphData.value.edges.forEach(e => {
const cat = relationCategories[e.relation] || 'other';
if (!cats[cat]) cats[cat] = [];
cats[cat].push(e.relation);
});
// 去重并排序
for (const cat in cats) {
cats[cat] = [...new Set(cats[cat])].sort();
}
return cats;
});
const relationTypes = computed(() => {
const types = new Set();
graphData.value.edges.forEach(e => types.add(e.relation));
return Array.from(types).sort();
});
const relationCounts = computed(() => {
const counts = {};
graphData.value.edges.forEach(e => {
counts[e.relation] = (counts[e.relation] || 0) + 1;
});
return counts;
});
const selectedNodeRelations = computed(() => {
if (!selectedNode.value) return [];
return graphData.value.edges.filter(e =>
e.source === selectedNode.value.id || e.target === selectedNode.value.id
);
});
const loadData = async () => {
try {
// 优先加载包含多组学数据的知识图谱
let response = await fetch('knowledge_graph_with_omics.json');
if (!response.ok) {
// 回退到标准知识图谱
response = await fetch('knowledge_graph.json');
}
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
// 验证数据结构
if (!data.nodes || !Array.isArray(data.nodes)) {
throw new Error('数据格式错误: nodes 未定义或不是数组');
}
if (!data.edges || !Array.isArray(data.edges)) {
console.warn('数据警告: edges 未定义,使用空数组');
data.edges = [];
}
// 计算节点度数
const nodeDegrees = {};
data.edges.forEach(e => {
nodeDegrees[e.source] = (nodeDegrees[e.source] || 0) + 1;
nodeDegrees[e.target] = (nodeDegrees[e.target] || 0) + 1;
});
// 根据 PC 语义分类设置节点形状
const getNodeSymbol = (type) => {
const symbolMap = {
'gene': 'circle',
'gene_id': 'circle',
'gene_group': 'circle',
'gene_family': 'circle',
'phenotype': 'rect',
'attribute': 'rect',
'tissue': 'roundRect',
'species': 'roundRect',
'process': 'diamond',
'time': 'diamond',
'condition': 'diamond',
'stress': 'diamond',
'location': 'triangle',
'sra_dataset': 'pin',
'data_type': 'pin',
'count': 'pin'
};
return symbolMap[type] || 'circle';
};
graphData.value = {
nodes: data.nodes.map(n => ({
id: n.id,
name: n.id,
category: n.type || 'unknown',
degree: nodeDegrees[n.id] || 0,
symbol: getNodeSymbol(n.type),
symbolSize: (n.type === 'gene' ? 20 : n.type === 'sra_dataset' ? 18 : 12) + Math.min((nodeDegrees[n.id] || 0) * 0.3, 15),
itemStyle: {
color: nodeColors[n.type] || nodeColors.unknown,
borderColor: '#fff',
borderWidth: 1
}
})),
edges: data.edges.map((e, i) => {
const cat = relationCategories[e.relation] || 'other';
const style = relationEdgeStyles[cat];
return {
id: i,
source: e.source,
target: e.target,
name: e.relation,
relation: e.relation,
category: cat,
lineStyle: {
color: style.color,
width: style.width,
type: style.type,
curveness: 0.1
}
};
})
};
initChart();
ElMessage.success('知识图谱加载完成 (PC语义规范)');
} catch (error) {
ElMessage.error('加载数据失败: ' + error.message);
}
};
const initChart = () => {
const container = document.getElementById('graph-container');
chart.value = echarts.init(container);
const option = {
tooltip: {
formatter: params => {
if (params.dataType === 'node') {
const pcType = nodeTypeLabels[params.data.category] || params.data.category;
return `<b>${params.name}</b><br/>PC类型: ${pcType}<br/>关系数: ${params.data.degree}`;
}
const cat = params.data.category || relationCategories[params.name] || 'other';
const catName = cat === 'activation' ? 'Activation' :
cat === 'repression' ? 'Repression' :
cat === 'regulation' ? 'Regulation' :
cat === 'expression' ? 'Expression' :
cat === 'association' ? 'Association' :
cat === 'localization' ? 'Localization' :
cat === 'containment' ? 'Containment' :
cat === 'participation' ? 'Participation' : 'Other';
return `<b>${params.data.source}</b> <span style="color:${relationEdgeStyles[cat].color}">--${params.name}--></span> <b>${params.data.target}</b><br/><small>PC: ${catName}</small>`;
}
},
series: [{
type: 'graph',
layout: 'force',
data: graphData.value.nodes,
links: graphData.value.edges,
roam: true,
draggable: true,
label: {
show: true,
position: 'right',
formatter: '{b}'
},
force: {
repulsion: 300,
gravity: 0.1,
edgeLength: 100,
layoutAnimation: true
},
emphasis: {
focus: 'adjacency',
lineStyle: { width: 4 }
}
}]
};
chart.value.setOption(option);
chart.value.on('click', params => {
if (params.dataType === 'node') {
selectedNode.value = params.data;
} else {
selectedNode.value = null;
}
});
window.addEventListener('resize', () => chart.value.resize());
};
const searchNode = () => {
if (!searchQuery.value || !chart.value) return;
const node = graphData.value.nodes.find(n =>
n.id.toLowerCase().includes(searchQuery.value.toLowerCase())
);
if (node) {
chart.value.dispatchAction({
type: 'highlight',
seriesIndex: 0,
name: node.id
});
selectedNode.value = node;
ElMessage.success(`找到节点: ${node.name}`);
} else {
ElMessage.warning('未找到匹配的节点');
}
};
const toggleRelationFilter = (type) => {
const index = selectedRelations.value.indexOf(type);
if (index > -1) {
selectedRelations.value.splice(index, 1);
} else {
selectedRelations.value.push(type);
}
if (selectedRelations.value.length === 0) {
chart.value.setOption({
series: [{ data: graphData.value.nodes, links: graphData.value.edges }]
});
} else {
const filteredEdges = graphData.value.edges.filter(e =>
selectedRelations.value.includes(e.relation)
);
const connectedNodes = new Set();
filteredEdges.forEach(e => {
connectedNodes.add(e.source);
connectedNodes.add(e.target);
});
const filteredNodes = graphData.value.nodes.filter(n =>
connectedNodes.has(n.id)
);
chart.value.setOption({
series: [{ data: filteredNodes, links: filteredEdges }]
});
}
};
const fitGraph = () => {
if (chart.value) {
chart.value.dispatchAction({ type: 'restore' });
}
};
const resetFilters = () => {
selectedRelations.value = [];
selectedNode.value = null;
searchQuery.value = '';
if (chart.value) {
chart.value.setOption({
series: [{ data: graphData.value.nodes, links: graphData.value.edges }]
});
chart.value.dispatchAction({ type: 'restore' });
}
};
const getNodeTypeTag = (type) => {
const typeMap = { 'gene': '', 'gene_id': 'success', 'tissue': 'warning', 'location': 'info' };
return typeMap[type] || '';
};
const goBack = () => {
window.location.href = '/';
};
onMounted(() => {
loadData().then(() => {
// 检查URL参数,如果有highlight则自动搜索高亮
const urlParams = new URLSearchParams(window.location.search);
const highlightEntity = urlParams.get('highlight');
if (highlightEntity) {
searchQuery.value = highlightEntity;
setTimeout(() => {
searchNode();
}, 500); // 等待图表初始化完成
}
});
});
return {
stats,
searchQuery,
selectedNode,
selectedRelations,
relationTypes,
relationTypesByCategory,
relationCounts,
relationEdgeStyles,
relationCategories,
nodeTypeLabels,
selectedNodeRelations,
nodeColors,
searchNode,
toggleRelationFilter,
fitGraph,
resetFilters,
getNodeTypeTag,
goBack
};
}
}).use(ElementPlus).mount('#app');
</script>
</body>
</html>
+712
View File
@@ -0,0 +1,712 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Knowledge Graph</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-plus@2.7.1/dist/index.css">
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/element-plus@2.7.1/dist/index.full.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@element-plus/icons-vue"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<script src="/static/i18n.js"></script>
<style>
body { margin: 0; font-family: 'Helvetica Neue', Arial, sans-serif; background: #f5f7fa; }
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 15px 20px; display: flex; align-items: center; justify-content: space-between; }
.header h1 { margin: 0; font-size: 22px; }
.header .subtitle { font-size: 12px; opacity: 0.8; margin-top: 4px; }
.main-container { display: flex; padding: 15px; gap: 15px; height: calc(100vh - 70px); }
.left-panel { width: 300px; display: flex; flex-direction: column; gap: 10px; }
.control-section { background: white; border-radius: 8px; padding: 15px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); }
.control-section h4 { margin: 0 0 10px 0; color: #409EFF; font-size: 14px; border-bottom: 2px solid #409EFF; padding-bottom: 8px; }
.stat-item { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #eee; }
.stat-item:last-child { border-bottom: none; }
.stat-label { color: #666; }
.stat-value { font-weight: bold; color: #409EFF; }
.filter-section { margin-top: 10px; }
.filter-tag { margin: 4px; cursor: pointer; }
.filter-tag.active { background: #409EFF; color: white; }
.main-panel { flex: 1; display: flex; flex-direction: column; background: white; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); overflow: hidden; }
.toolbar { padding: 10px 15px; border-bottom: 1px solid #eee; display: flex; align-items: center; gap: 10px; }
#graph-container { flex: 1; position: relative; }
.right-panel { width: 350px; background: white; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); padding: 15px; overflow-y: auto; }
.right-panel h4 { margin: 0 0 10px 0; color: #67C23A; border-bottom: 2px solid #67C23A; padding-bottom: 8px; }
.node-detail { padding: 10px; background: #f5f7fa; border-radius: 6px; margin-top: 10px; }
.node-detail .label { color: #666; font-size: 12px; margin-bottom: 4px; }
.node-detail .value { font-weight: 500; color: #333; }
.relation-list { margin-top: 10px; }
.relation-item { padding: 8px; background: #f0f9eb; border-radius: 4px; margin-bottom: 8px; font-size: 13px; }
.relation-item .source { color: #409EFF; font-weight: 500; }
.relation-item .rel { color: #67C23A; margin: 0 4px; }
.relation-item .target { color: #E6A23C; font-weight: 500; }
.search-box { margin-bottom: 10px; }
.legend { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.legend-item { display: flex; align-items: center; gap: 4px; font-size: 12px; }
.legend-color { width: 12px; height: 12px; border-radius: 50%; }
.legend-symbol { width: 12px; height: 12px; border-radius: 2px; }
.legend-line { width: 20px; height: 2px; }
/* PC语义分类样式 */
.pc-category-header {
font-size: 11px;
color: #666;
font-weight: bold;
margin: 8px 0 4px 0;
padding-left: 4px;
border-left: 3px solid #409EFF;
}
</style>
</head>
<body>
<div id="app">
<div class="header">
<div>
<h1>{{ t('kg-visualization') }}</h1>
<div class="subtitle">{{ t('kg-subtitle') }}</div>
</div>
<el-button type="primary" @click="goBack">
<el-icon><arrow-left /></el-icon> {{ t('back-to-main') }}
</el-button>
</div>
<div class="main-container">
<!-- 左侧面板 -->
<div class="left-panel">
<div class="control-section">
<h4>{{ t('kg-stats') }}</h4>
<div class="stat-item">
<span class="stat-label">{{ t('node-count') }}</span>
<span class="stat-value">{{ stats.nodes }}</span>
</div>
<div class="stat-item">
<span class="stat-label">{{ t('edge-count') }}</span>
<span class="stat-value">{{ stats.edges }}</span>
</div>
<div class="stat-item">
<span class="stat-label">{{ t('node-types') }}</span>
<span class="stat-value">{{ stats.nodeTypes }}</span>
</div>
<div class="stat-item">
<span class="stat-label">{{ t('edge-types') }}</span>
<span class="stat-value">{{ stats.edgeTypes }}</span>
</div>
</div>
<div class="control-section">
<h4>{{ t('node-search') }}</h4>
<el-input
v-model="searchQuery"
:placeholder="t('enter-gene-name')"
clearable
@keyup.enter="searchNode"
>
<template #append>
<el-button @click="searchNode">
<el-icon><search /></el-icon>
</el-button>
</template>
</el-input>
</div>
<div class="control-section">
<h4>{{ t('relation-filter-pc') }}</h4>
<div class="filter-section">
<div v-for="(types, category) in relationTypesByCategory" :key="category" style="margin-bottom: 10px;">
<div style="font-size: 12px; color: #666; margin-bottom: 5px; font-weight: bold;">
{{ category === 'activation' ? t('activation-induction') :
category === 'repression' ? t('repression-inhibition') :
category === 'regulation' ? t('regulation-control') :
category === 'expression' ? t('expression-detection') :
category === 'association' ? t('association-interaction') :
category === 'localization' ? t('localization') :
category === 'containment' ? t('containment-composition') :
category === 'participation' ? t('participation-function') : t('other-rel') }}
</div>
<el-tag
v-for="type in types"
:key="type"
class="filter-tag"
:class="{ active: selectedRelations.includes(type) }"
@click="toggleRelationFilter(type)"
size="small"
:style="{ borderColor: relationEdgeStyles[category].color, color: selectedRelations.includes(type) ? '#fff' : relationEdgeStyles[category].color }"
>
{{ type }} ({{ relationCounts[type] }})
</el-tag>
</div>
</div>
</div>
<div class="control-section">
<h4>{{ t('node-legend-pc') }}</h4>
<div class="pc-category-header">Gene/Protein</div>
<div class="legend">
<div class="legend-item" v-for="type in ['gene', 'gene_id', 'gene_group', 'gene_family']" :key="type">
<div class="legend-symbol" :style="{ background: nodeColors[type] }"></div>
<span>{{ nodeTypeLabels[type] }}</span>
</div>
</div>
<div class="pc-category-header">Phenotype</div>
<div class="legend">
<div class="legend-item" v-for="type in ['phenotype', 'attribute']" :key="type">
<div class="legend-symbol" :style="{ background: nodeColors[type] }"></div>
<span>{{ nodeTypeLabels[type] }}</span>
</div>
</div>
<div class="pc-category-header">Cell/Organ/Organism</div>
<div class="legend">
<div class="legend-item" v-for="type in ['tissue', 'species']" :key="type">
<div class="legend-symbol" :style="{ background: nodeColors[type] }"></div>
<span>{{ nodeTypeLabels[type] }}</span>
</div>
</div>
<div class="pc-category-header">Biological Process</div>
<div class="legend">
<div class="legend-item" v-for="type in ['process', 'time', 'condition', 'stress']" :key="type">
<div class="legend-symbol" :style="{ background: nodeColors[type] }"></div>
<span>{{ nodeTypeLabels[type] }}</span>
</div>
</div>
<div class="pc-category-header">Genomic</div>
<div class="legend">
<div class="legend-item" v-for="type in ['location', 'sra_dataset', 'data_type', 'count']" :key="type">
<div class="legend-symbol" :style="{ background: nodeColors[type] }"></div>
<span>{{ nodeTypeLabels[type] }}</span>
</div>
</div>
<h4 style="margin-top: 15px;">🔗 {{ t('edge-legend-pc') }}</h4>
<div class="legend">
<div class="legend-item" v-for="(style, cat) in relationEdgeStyles" :key="cat">
<div class="legend-line" :style="{ background: style.color, height: style.width + 'px', borderTop: style.type === 'dashed' ? '2px dashed ' + style.color : 'none' }"></div>
<span>{{ cat === 'activation' ? 'Activation/Induction' :
cat === 'repression' ? 'Repression/Inhibition' :
cat === 'regulation' ? 'Regulation/Control' :
cat === 'expression' ? 'Expression/Detection' :
cat === 'association' ? 'Association/Interaction' :
cat === 'localization' ? 'Localization' :
cat === 'containment' ? 'Containment/Composition' :
cat === 'participation' ? 'Participation/Function' : 'Other' }}</span>
</div>
</div>
</div>
</div>
<!-- 主面板 -->
<div class="main-panel">
<div class="toolbar">
<el-button-group>
<el-button @click="fitGraph">
<el-icon><full-screen /></el-icon> {{ t('fit-view') }}
</el-button>
<el-button @click="resetFilters">
<el-icon><refresh /></el-icon> {{ t('reset-filters') }}
</el-button>
</el-button-group>
<el-divider direction="vertical"></el-divider>
<span style="color: #666; font-size: 13px;">
{{ t('click-drag-hint') }}
</span>
</div>
<div id="graph-container"></div>
</div>
<!-- 右侧面板 -->
<div class="right-panel">
<h4>{{ t('node-detail') }}</h4>
<div v-if="selectedNode" class="node-detail">
<div style="margin-bottom: 15px;">
<div class="label">{{ t('node-name') }}</div>
<div class="value" style="font-size: 18px; color: #409EFF;">{{ selectedNode.name }}</div>
</div>
<div style="margin-bottom: 15px;">
<div class="label">{{ t('node-type-pc') }}</div>
<div class="value">
<el-tag :type="getNodeTypeTag(selectedNode.category)" :style="{ backgroundColor: nodeColors[selectedNode.category] + '20', borderColor: nodeColors[selectedNode.category], color: nodeColors[selectedNode.category] }">
{{ nodeTypeLabels[selectedNode.category] || selectedNode.category }}
</el-tag>
</div>
</div>
<div>
<div class="label">{{ t('connection-count') }}</div>
<div class="value">{{ selectedNode.degree }}{{ t('num-connections') }}</div>
</div>
</div>
<div v-else style="color: #999; text-align: center; padding: 40px;">
{{ t('click-node-detail') }}
</div>
<template v-if="selectedNodeRelations.length > 0">
<h4 style="margin-top: 20px;">🔗 {{ t('related-relations') }} ({{ selectedNodeRelations.length }})</h4>
<div class="relation-list">
<div
v-for="rel in selectedNodeRelations.slice(0, 10)"
:key="rel.id"
class="relation-item"
:style="{ borderLeft: '3px solid ' + relationEdgeStyles[rel.category || relationCategories[rel.name] || 'other'].color }"
>
<span class="source">{{ rel.source }}</span>
<span class="rel" :style="{ color: relationEdgeStyles[rel.category || relationCategories[rel.name] || 'other'].color }">--{{ rel.name }}--></span>
<span class="target">{{ rel.target }}</span>
</div>
<div v-if="selectedNodeRelations.length > 10" style="text-align: center; color: #999; padding: 10px;">
{{ tp('more-relations', { count: selectedNodeRelations.length - 10 }) }}
</div>
</div>
</template>
</div>
</div>
</div>
<script>
const { createApp, ref, onMounted, computed } = Vue;
const { ElMessage } = ElementPlus;
createApp({
setup() {
const t = window.t || ((key) => key);
const tp = window.tp || ((key, params) => {
let s = t(key);
if (params) Object.keys(params).forEach(k => { s = s.replace('{' + k + '}', params[k]); });
return s;
});
document.title = t('kg-title');
const graphData = ref({ nodes: [], edges: [] });
const chart = ref(null);
const searchQuery = ref('');
const selectedNode = ref(null);
const selectedRelations = ref([]);
// PC (Pathway Commons) 语义分类颜色映射
const nodeColors = {
// Gene/Protein - 蓝色
'gene': '#5DADE2',
'gene_id': '#85C1E9',
'gene_group': '#AED6F1',
'gene_family': '#5DADE2',
// Phenotype - 绿色
'phenotype': '#58D68D',
'attribute': '#82E0AA',
// Cell/Organ/Organism - 粉色
'tissue': '#F5B7B1',
'species': '#F1948A',
// Process - 紫色菱形
'process': '#AF7AC5',
'time': '#C39BD3',
'condition': '#D7BDE2',
'stress': '#E8DAEF',
// Location - 浅绿色
'location': '#82E0AA',
// Data - 橙色(更显眼)
'sra_dataset': '#E67E22',
'data_type': '#F39C12',
'count': '#EAEDED',
'unknown': '#95A5A6'
,
'article': '#2ecc71',
'paper_title': '#9b59b6'
};
// PC 语义分类显示名称
const nodeTypeLabels = {
'gene': 'Gene/Protein',
'gene_id': 'Gene Identifier',
'gene_group': 'Gene Group',
'gene_family': 'Gene Family',
'phenotype': 'Phenotype',
'attribute': 'Attribute',
'tissue': 'Cell/Organ/Tissue',
'species': 'Organism',
'process': 'Biological Process',
'time': 'Time/Stage',
'condition': 'Condition',
'stress': 'Stress',
'location': 'Genomic Location',
'sra_dataset': 'SRA Dataset',
'geo_dataset': 'GEO Dataset',
'data_type': 'Data Type',
'count': 'Count/Statistic',
'article': 'Article (PMID)',
'paper_title': 'Paper Title',
'unknown': 'Other'
};
// PC 关系类型分类
const relationCategories = {
// Activation/Induction - 绿色箭头
'induces': 'activation',
'promote': 'activation',
'overexpression_increases': 'activation',
'enhanced_tolerance_to': 'activation',
// Repression/Inhibition - 红色T型
'down_regulated_during': 'repression',
'down_regulation_improves': 'repression',
// Regulation - 蓝色
'regulate': 'regulation',
'regulates': 'regulation',
'regulating': 'regulation',
// Expression - 橙色
'expressed_in': 'expression',
'expressed_during': 'expression',
'was_expressed_during': 'expression',
'expression_reached_peak_at': 'expression',
// Association - 紫色
'collinear_with': 'association',
'was_highly_orthologous_to': 'association',
'related_to': 'association',
'affect': 'association',
// Localization - 深绿
'located_on': 'localization',
'identified_in': 'localization',
// Containment - 青色
'contain': 'containment',
'had': 'containment',
'has_gene_id': 'containment',
'has_data_type': 'containment',
// Participation - 深红
'involved_in': 'participation',
'participate_in': 'participation',
'default': 'other'
};
const relationEdgeStyles = {
'activation': { color: '#27AE60', width: 2, type: 'solid' },
'repression': { color: '#E74C3C', width: 2, type: 'solid' },
'regulation': { color: '#3498DB', width: 2, type: 'solid' },
'expression': { color: '#E67E22', width: 1.5, type: 'solid' },
'association': { color: '#9B59B6', width: 1.5, type: 'dashed' },
'localization': { color: '#16A085', width: 1.5, type: 'solid' },
'containment': { color: '#1ABC9C', width: 1.5, type: 'solid' },
'participation': { color: '#C0392B', width: 2, type: 'solid' },
'other': { color: '#95A5A6', width: 1, type: 'solid' }
};
const stats = computed(() => ({
nodes: graphData.value.nodes.length,
edges: graphData.value.edges.length,
nodeTypes: Object.keys(nodeColors).length,
edgeTypes: relationTypes.value.length
}));
// 按 PC 语义分类的关系类型
const relationTypesByCategory = computed(() => {
const cats = {};
graphData.value.edges.forEach(e => {
const cat = relationCategories[e.relation] || 'other';
if (!cats[cat]) cats[cat] = [];
cats[cat].push(e.relation);
});
// 去重并排序
for (const cat in cats) {
cats[cat] = [...new Set(cats[cat])].sort();
}
return cats;
});
const relationTypes = computed(() => {
const types = new Set();
graphData.value.edges.forEach(e => types.add(e.relation));
return Array.from(types).sort();
});
const relationCounts = computed(() => {
const counts = {};
graphData.value.edges.forEach(e => {
counts[e.relation] = (counts[e.relation] || 0) + 1;
});
return counts;
});
const selectedNodeRelations = computed(() => {
if (!selectedNode.value) return [];
return graphData.value.edges.filter(e =>
e.source === selectedNode.value.id || e.target === selectedNode.value.id
);
});
const loadData = async () => {
try {
// 优先加载包含多组学数据的知识图谱
let response = await fetch('knowledge_graph_with_omics.json');
if (!response.ok) {
// 回退到标准知识图谱
response = await fetch('knowledge_graph.json');
}
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
// 验证数据结构
if (!data.nodes || !Array.isArray(data.nodes)) {
throw new Error(t('err-data-format'));
}
if (!data.edges || !Array.isArray(data.edges)) {
console.warn(t('warn-edges-undefined'));
data.edges = [];
}
// 计算节点度数
const nodeDegrees = {};
data.edges.forEach(e => {
nodeDegrees[e.source] = (nodeDegrees[e.source] || 0) + 1;
nodeDegrees[e.target] = (nodeDegrees[e.target] || 0) + 1;
});
// 根据 PC 语义分类设置节点形状
const getNodeSymbol = (type) => {
const symbolMap = {
'gene': 'circle',
'gene_id': 'circle',
'gene_group': 'circle',
'gene_family': 'circle',
'phenotype': 'rect',
'attribute': 'rect',
'tissue': 'roundRect',
'species': 'roundRect',
'process': 'diamond',
'time': 'diamond',
'condition': 'diamond',
'stress': 'diamond',
'location': 'triangle',
'sra_dataset': 'pin',
'data_type': 'pin',
'count': 'pin'
};
return symbolMap[type] || 'circle';
};
graphData.value = {
nodes: data.nodes.map(n => ({
id: n.id,
name: n.id,
category: n.type || 'unknown',
degree: nodeDegrees[n.id] || 0,
symbol: getNodeSymbol(n.type),
symbolSize: (n.type === 'gene' ? 20 : n.type === 'sra_dataset' ? 18 : 12) + Math.min((nodeDegrees[n.id] || 0) * 0.3, 15),
itemStyle: {
color: nodeColors[n.type] || nodeColors.unknown,
borderColor: '#fff',
borderWidth: 1
}
})),
edges: data.edges.map((e, i) => {
const cat = relationCategories[e.relation] || 'other';
const style = relationEdgeStyles[cat];
return {
id: i,
source: e.source,
target: e.target,
name: e.relation,
relation: e.relation,
category: cat,
lineStyle: {
color: style.color,
width: style.width,
type: style.type,
curveness: 0.1
}
};
})
};
initChart();
ElMessage.success(t('msg-kg-loaded'));
} catch (error) {
ElMessage.error(t('msg-load-data-failed') + error.message);
}
};
const initChart = () => {
const container = document.getElementById('graph-container');
chart.value = echarts.init(container);
const option = {
tooltip: {
formatter: params => {
if (params.dataType === 'node') {
const pcType = nodeTypeLabels[params.data.category] || params.data.category;
return `<b>${params.name}</b><br/>PC: ${pcType}<br/>${t('connection-count').replace('Connections', 'Deg')}: ${params.data.degree}`;
}
const cat = params.data.category || relationCategories[params.name] || 'other';
const catName = cat === 'activation' ? 'Activation' :
cat === 'repression' ? 'Repression' :
cat === 'regulation' ? 'Regulation' :
cat === 'expression' ? 'Expression' :
cat === 'association' ? 'Association' :
cat === 'localization' ? 'Localization' :
cat === 'containment' ? 'Containment' :
cat === 'participation' ? 'Participation' : 'Other';
return `<b>${params.data.source}</b> <span style="color:${relationEdgeStyles[cat].color}">--${params.name}--></span> <b>${params.data.target}</b><br/><small>PC: ${catName}</small>`;
}
},
series: [{
type: 'graph',
layout: 'force',
data: graphData.value.nodes,
links: graphData.value.edges,
roam: true,
draggable: true,
label: {
show: true,
position: 'right',
formatter: '{b}'
},
force: {
repulsion: 300,
gravity: 0.1,
edgeLength: 100,
layoutAnimation: true
},
emphasis: {
focus: 'adjacency',
lineStyle: { width: 4 }
}
}]
};
chart.value.setOption(option);
chart.value.on('click', params => {
if (params.dataType === 'node') {
selectedNode.value = params.data;
} else {
selectedNode.value = null;
}
});
window.addEventListener('resize', () => chart.value.resize());
};
const searchNode = () => {
if (!searchQuery.value || !chart.value) return;
const node = graphData.value.nodes.find(n =>
n.id.toLowerCase().includes(searchQuery.value.toLowerCase())
);
if (node) {
chart.value.dispatchAction({
type: 'highlight',
seriesIndex: 0,
name: node.id
});
selectedNode.value = node;
ElMessage.success(t('msg-node-found') + node.name);
} else {
ElMessage.warning(t('msg-node-not-found'));
}
};
const toggleRelationFilter = (type) => {
const index = selectedRelations.value.indexOf(type);
if (index > -1) {
selectedRelations.value.splice(index, 1);
} else {
selectedRelations.value.push(type);
}
if (selectedRelations.value.length === 0) {
chart.value.setOption({
series: [{ data: graphData.value.nodes, links: graphData.value.edges }]
});
} else {
const filteredEdges = graphData.value.edges.filter(e =>
selectedRelations.value.includes(e.relation)
);
const connectedNodes = new Set();
filteredEdges.forEach(e => {
connectedNodes.add(e.source);
connectedNodes.add(e.target);
});
const filteredNodes = graphData.value.nodes.filter(n =>
connectedNodes.has(n.id)
);
chart.value.setOption({
series: [{ data: filteredNodes, links: filteredEdges }]
});
}
};
const fitGraph = () => {
if (chart.value) {
chart.value.dispatchAction({ type: 'restore' });
}
};
const resetFilters = () => {
selectedRelations.value = [];
selectedNode.value = null;
searchQuery.value = '';
if (chart.value) {
chart.value.setOption({
series: [{ data: graphData.value.nodes, links: graphData.value.edges }]
});
chart.value.dispatchAction({ type: 'restore' });
}
};
const getNodeTypeTag = (type) => {
const typeMap = { 'gene': '', 'gene_id': 'success', 'tissue': 'warning', 'location': 'info' };
return typeMap[type] || '';
};
const goBack = () => {
window.location.href = '/';
};
onMounted(() => {
loadData().then(() => {
// 检查URL参数,如果有highlight则自动搜索高亮
const urlParams = new URLSearchParams(window.location.search);
const highlightEntity = urlParams.get('highlight');
if (highlightEntity) {
searchQuery.value = highlightEntity;
setTimeout(() => {
searchNode();
}, 500); // 等待图表初始化完成
}
});
});
return {
t,
tp,
stats,
searchQuery,
selectedNode,
selectedRelations,
relationTypes,
relationTypesByCategory,
relationCounts,
relationEdgeStyles,
relationCategories,
nodeTypeLabels,
selectedNodeRelations,
nodeColors,
searchNode,
toggleRelationFilter,
fitGraph,
resetFilters,
getNodeTypeTag,
goBack
};
}
}).use(ElementPlus).mount('#app');
</script>
</body>
</html>
@@ -0,0 +1,304 @@
(function () {
const PY_EXTENSIONS = new Set(['.py']);
const R_EXTENSIONS = new Set(['.r']);
function normalizedRelativePath(file) {
const relative = String(file.webkitRelativePath || file.relativePath || file.name || '').replace(/^\/+/, '');
return relative.split('\\').join('/');
}
function parsePythonImports(content) {
const imports = new Set();
const lines = String(content || '').split(/\r?\n/);
for (const line of lines) {
let match = line.match(/^\s*import\s+([A-Za-z0-9_.,\s]+)/);
if (match) {
match[1].split(',').forEach((item) => {
const token = item.trim().split(/\s+as\s+/i)[0].split('.')[0].trim();
if (token) imports.add(token);
});
}
match = line.match(/^\s*from\s+([A-Za-z0-9_.]+)\s+import\s+/);
if (match) {
const token = match[1].split('.')[0].trim();
if (token) imports.add(token);
}
}
return Array.from(imports);
}
function parseRPackages(content) {
const packages = new Set();
const pattern = /(?:library|require)\(\s*["']?([A-Za-z0-9_.-]+)["']?\s*\)/g;
let match;
const text = String(content || '');
while ((match = pattern.exec(text)) !== null) {
if (match[1]) packages.add(match[1]);
}
return Array.from(packages);
}
function commonPathPrefix(files) {
const paths = files.map((f) => normalizedRelativePath(f).split('/')).filter((parts) => parts.length > 0);
if (!paths.length) return '';
const first = paths[0];
let prefixLen = 0;
for (let i = 0; i < first.length; i++) {
if (!paths.every((parts) => parts[i] === first[i])) break;
prefixLen = i + 1;
}
return first.slice(0, prefixLen).join('/');
}
function sanitizeDisplayName(raw) {
return String(raw || '').replace(/[^A-Za-z0-9_-]+/g, '_').replace(/^_+|_+$/g, '') || 'lightweight_extension';
}
function extractRootName(files) {
const prefix = commonPathPrefix(files);
const base = (prefix && prefix !== 'raw_code' && prefix !== 'raw_test_data')
? sanitizeDisplayName(prefix.split('/')[0])
: 'lightweight_extension_drop';
const ts = Date.now();
return base + '_' + ts;
}
function splitFixedStructure(files) {
const codeFiles = [];
const dataFiles = [];
let hasRunScript = false;
let prefix = commonPathPrefix(files);
if (prefix && !prefix.endsWith('/')) prefix += '/';
const sampled = [];
for (const file of files) {
let relativePath = normalizedRelativePath(file);
if (prefix && relativePath.startsWith(prefix)) {
relativePath = relativePath.slice(prefix.length);
}
if (sampled.length < 10) sampled.push(relativePath);
if (relativePath.startsWith('raw_code/')) {
file.lightweightRelativePath = relativePath.slice('raw_code/'.length) || file.name;
codeFiles.push(file);
if (relativePath === 'raw_code/run.sh') {
hasRunScript = true;
}
} else if (relativePath.startsWith('raw_test_data/')) {
file.lightweightRelativePath = relativePath.slice('raw_test_data/'.length) || file.name;
dataFiles.push(file);
}
}
if (!codeFiles.length) {
const preview = sampled.length ? sampled.slice(0, 10).join(', ') : '(无)';
throw new Error('缺少 raw_code/ 目录(检测到的路径样例: ' + preview + ')');
}
if (!dataFiles.length) {
throw new Error('缺少 raw_test_data/ 目录');
}
if (!hasRunScript) {
throw new Error('缺少 raw_code/run.sh');
}
return { codeFiles, dataFiles };
}
async function extractDependencies(files) {
const pythonImports = new Set();
const rPackages = new Set();
for (const file of files) {
const path = normalizedRelativePath(file);
const lower = path.toLowerCase();
const extension = lower.includes('.') ? lower.slice(lower.lastIndexOf('.')) : '';
if (!PY_EXTENSIONS.has(extension) && !R_EXTENSIONS.has(extension)) {
continue;
}
const content = await file.text();
if (PY_EXTENSIONS.has(extension)) {
parsePythonImports(content).forEach((name) => pythonImports.add(name));
} else {
parseRPackages(content).forEach((name) => rPackages.add(name));
}
}
return {
python_imports: Array.from(pythonImports),
r_packages: Array.from(rPackages),
};
}
async function encodeBase64(file) {
const buffer = await file.arrayBuffer();
const bytes = new Uint8Array(buffer);
let binary = '';
const chunkSize = 0x8000;
for (let index = 0; index < bytes.length; index += chunkSize) {
binary += String.fromCharCode(...bytes.subarray(index, index + chunkSize));
}
return btoa(binary);
}
async function importFolderToJob(hooks, rootName, files) {
const payload = {
job_id: String(hooks.jobInfo.job_id || '').trim(),
root_name: rootName,
files: [],
relative_paths: [],
};
for (const file of files) {
payload.files.push(await encodeBase64(file));
payload.relative_paths.push(normalizedRelativePath(file));
}
const response = await fetch('/api/job/import-folder', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
const data = await response.json();
if (!response.ok || !data.success) {
throw new Error(data.detail || data.error || data.message || 'Job 导入失败');
}
return data;
}
async function resolveRuntimeEnv(files) {
const dependencies = await extractDependencies(files);
console.log('[lightWeightExtensionTest] 提取的依赖:', JSON.stringify(dependencies), '| 扫描文件数:', files.length);
try {
const response = await fetch('/api/extension-stages/envs/resolve', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(dependencies),
});
const data = await response.json();
console.log('[lightWeightExtensionTest] 后端 env/resolve 原始响应:', response.status, JSON.stringify(data).slice(0, 500));
if (!response.ok || !data.success) {
throw new Error(data.detail || data.error || data.message || '运行环境解析失败');
}
return data;
} catch (e) {
console.error('[lightWeightExtensionTest] env/resolve 调用失败:', e);
throw e;
}
}
function notifyError(message) {
if (window.ElementPlus && window.ElementPlus.ElMessage) {
window.ElementPlus.ElMessage.error(message);
}
}
async function ensureJob(hooks) {
if (String(hooks.jobInfo.job_id || '').trim() && String(hooks.jobInfo.job_id) !== 'default_job') {
return;
}
await hooks.createNewJob();
if (!String(hooks.jobInfo.job_id || '').trim() || String(hooks.jobInfo.job_id) === 'default_job') {
throw new Error('自动创建 Job 失败');
}
}
async function processFolderFiles(hooks, inputFiles) {
const files = Array.from(inputFiles || []).filter((file) => normalizedRelativePath(file));
if (!files.length) {
throw new Error('未读取到任何文件');
}
hooks.lightweightExtensionTestStatus.value = '正在校验目录结构...';
const rootName = extractRootName(files);
const fixed = splitFixedStructure(files);
hooks.lightweightExtensionTestStatus.value = '正在确保 Job 可用...';
await ensureJob(hooks);
hooks.lightweightExtensionTestStatus.value = '正在解析运行环境...';
const envResult = await resolveRuntimeEnv(files);
hooks.extensionBuild.runtimeEnv = envResult.runtime_env || 'test4py311';
console.log(
'[lightWeightExtensionTest] ✓ 选定环境: ' + hooks.extensionBuild.runtimeEnv,
'| 原因: ' + (envResult.reason || 'unknown'),
'| 兜底: ' + (envResult.fallback ? '是' : '否'),
envResult.matches ? '| 候选: ' + JSON.stringify(envResult.matches.map(m => m.env + '(py:' + (m.python_hits || []).join(',') + ' r:' + (m.r_hits || []).join(',') + ')')) : '',
);
hooks.lightweightExtensionTestStatus.value = '正在镜像导入当前 Job...';
await importFolderToJob(hooks, rootName, files);
hooks.extensionBuild.displayName = rootName;
hooks.extensionBuild.command = 'bash run.sh';
hooks.extensionBuild.codeFiles = hooks.appendExtensionFiles([], fixed.codeFiles);
hooks.extensionBuild.dataFiles = hooks.appendExtensionFiles([], fixed.dataFiles);
hooks.extensionBuild.dataPaths = '';
hooks.lightweightExtensionTestStatus.value = `运行环境 ${hooks.extensionBuild.runtimeEnv} 已确定,正在触发 upload...`;
await hooks.buildLightweightExtensionStage();
hooks.lightweightExtensionTestStatus.value = '已开始 upload,系统正在自动轮询并等待候选卡。';
}
async function readEntry(entry, basePath) {
if (entry.isFile) {
return new Promise((resolve) => {
entry.file((file) => {
Object.defineProperty(file, 'webkitRelativePath', {
value: basePath ? basePath + '/' + entry.name : entry.name,
writable: false,
});
resolve([file]);
});
});
}
if (entry.isDirectory) {
const reader = entry.createReader();
const entries = await new Promise((resolve) => {
reader.readEntries(resolve);
});
const subPath = basePath ? basePath + '/' + entry.name : entry.name;
const nested = await Promise.all(entries.map((e) => readEntry(e, subPath)));
return nested.flat();
}
return [];
}
async function readDroppedFiles(dataTransfer) {
if (!dataTransfer || !dataTransfer.items) {
return Array.from(dataTransfer?.files || []);
}
const items = Array.from(dataTransfer.items);
const entries = items
.map((item) => item.webkitGetAsEntry && item.webkitGetAsEntry())
.filter(Boolean);
if (!entries.length) {
return Array.from(dataTransfer.files || []);
}
const results = await Promise.all(entries.map((entry) => readEntry(entry, '')));
return results.flat();
}
function mountApi() {
window.LightWeightExtensionTest = {
async handleDrop(hooks, event) {
try {
const files = await readDroppedFiles(event?.dataTransfer);
await processFolderFiles(hooks, files);
} catch (error) {
const message = `失败:${error.message || '目录处理失败'}`;
hooks.lightweightExtensionTestStatus.value = message;
notifyError(message);
}
},
async handlePick(hooks, event) {
const files = event?.target?.files || [];
try {
await processFolderFiles(hooks, files);
} catch (error) {
const message = `失败:${error.message || '目录处理失败'}`;
hooks.lightweightExtensionTestStatus.value = message;
notifyError(message);
} finally {
if (event?.target) {
event.target.value = '';
}
}
},
openPicker() {
const input = document.getElementById('lightweight-extension-test-folder-input');
if (input) {
input.click();
}
},
};
}
mountApi();
})();
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,109 @@
def generate_stage_connection(from_stage: str, to_stage: str, from_metrics: dict, to_metrics: dict, prefix: str) -> dict:
"""基于真实metrics生成阶段间关联分析"""
# 获取关键数值
from_count = from_metrics.get("final_members") or from_metrics.get("gene_count") or from_metrics.get("sequences_count") or from_metrics.get("sequence_count")
to_count = to_metrics.get("final_members") or to_metrics.get("gene_count") or to_metrics.get("sequences_count") or to_metrics.get("sequence_count")
# 阶段名称映射
stage_names = {
"identify": "基因家族鉴定",
"phylogeny": "系统发育分析",
"motif": "Motif分析",
"domain": "结构域分析",
"structure": "基因结构分析",
"promoter": "启动子分析",
"pep": "蛋白属性分析",
"synteny": "共线性分析",
"expression": "表达分析"
}
from_name = stage_names.get(from_stage, from_stage)
to_name = stage_names.get(to_stage, to_stage)
# 提取from阶段的详细信息
from_details = []
to_details = []
if from_stage == "identify":
candidates = from_metrics.get("candidates", 0)
final = from_metrics.get("final_members", 0)
from_details.append(f"从{candidates}个候选基因筛选出{final}个成员")
elif from_stage == "pep":
avg_len = from_metrics.get("avg_length", 0)
avg_pi = from_metrics.get("avg_pi", 0)
from_details.append(f"平均长度{avg_len:.0f}aa,等电点{avg_pi:.1f}")
elif from_stage == "structure":
genes = from_metrics.get("genes_with_structure", 0) or from_count
from_details.append(f"{genes}个基因的结构信息")
elif from_stage == "promoter":
total_elem = from_metrics.get("total_elements", 0)
unique_elem = from_metrics.get("unique_elements", 0)
from_details.append(f"识别出{total_elem}个顺式作用元件({unique_elem}种类型)")
# 提取to阶段的详细信息
if to_stage == "promoter":
genes_with_elem = to_metrics.get("genes_with_elements", 0)
total_elem = to_metrics.get("total_elements", 0)
unique_elem = to_metrics.get("unique_elements", 0)
enriched = to_metrics.get("enriched_pairs", 0)
to_details.append(f"{genes_with_elem}个基因含有顺式作用元件")
to_details.append(f"共发现{total_elem}个元件({unique_elem}种类型)")
if enriched > 0:
to_details.append(f"{enriched}对显著富集的元件组合")
elif to_stage == "phylogeny":
msa_len = to_metrics.get("msa_length", 0)
model = to_metrics.get("tree_model", "").split()[0] if to_metrics.get("tree_model") else ""
to_details.append(f"MSA长度{msa_len}bp" if msa_len else f"{to_count}条序列")
if model:
to_details.append(f"使用{model}模型")
elif to_stage == "motif":
motif_count = to_metrics.get("motif_count", 0)
to_details.append(f"识别出{motif_count}个保守Motif")
elif to_stage == "domain":
domain_count = to_metrics.get("domain_count", 0)
to_details.append(f"发现{domain_count}类功能结构域")
# 生成具体描述
if from_details and to_details:
description = f"{from_name}提供了{'; '.join(from_details)},基于此进行{to_name},获得{'; '.join(to_details)}。"
elif from_details:
description = f"{from_name}提供了{'; '.join(from_details)},为{to_name}奠定基础。"
elif to_details:
description = f"基于{from_name}的结果进行{to_name},获得{'; '.join(to_details)}。"
else:
description = f"{from_name}的结果为{to_name}提供了必要的数据基础。"
# 生成洞察(基于数据关系)
insights = []
# 检查数据一致性
if from_count and to_count:
if abs(from_count - to_count) <= 1:
insights.append(f"两阶段数据高度一致({from_count} vs {to_count}),表明分析质量良好")
elif to_count < from_count:
ratio = to_count / from_count * 100
insights.append(f"{to_name}覆盖了{ratio:.0f}%的{from_name}数据,部分基因可能因不符合条件被过滤")
else:
insights.append(f"{to_name}涉及更多数据点,可能包含了参考序列或外群")
# 阶段特定洞察
if from_stage == "identify" and to_stage == "promoter":
genes_with_elem = to_metrics.get("genes_with_elements", 0)
final = from_metrics.get("final_members", 0) or from_count
if genes_with_elem and final:
coverage = genes_with_elem / final * 100
insights.append(f"{coverage:.0f}%的家族成员具有可识别的启动子元件")
if from_stage == "structure" and to_stage == "promoter":
insights.append("基因结构与启动子元件的联合分析可揭示调控机制与基因组织的关联")
if not insights:
insights.append("连续的分析流程确保了数据的完整性和一致性")
return {
"from": from_stage,
"to": to_stage,
"description": description,
"insight": ";".join(insights)
}
@@ -0,0 +1,48 @@
#!/bin/bash
# BBAV20311 服务启动脚本 - 带自动重启
PROJECT_DIR="/home/xzq/5090/PlantAI-dev4090-7/PlantAI-dev"
LOG_FILE="/tmp/bbav5_vue3.log"
PID_FILE="/tmp/bbav5_vue3.pid"
cd "$PROJECT_DIR/apps/web/vue3"
# 如果服务已在运行,先停止
if [ -f "$PID_FILE" ]; then
OLD_PID=$(cat "$PID_FILE")
if ps -p "$OLD_PID" > /dev/null 2>&1; then
echo "停止旧服务 (PID: $OLD_PID)..."
kill "$OLD_PID" 2>/dev/null
sleep 2
fi
fi
# 清理日志
echo "=== 服务启动 $(date) ===" > "$LOG_FILE"
# 启动服务并监控
while true; do
echo "启动服务..."
python3 main.py >> "$LOG_FILE" 2>&1 &
PID=$!
echo $PID > "$PID_FILE"
echo "服务已启动,PID: $PID"
# 等待服务退出
wait $PID
EXIT_CODE=$?
echo "服务退出,退出码: $EXIT_CODE,$(date)" >> "$LOG_FILE"
# 检查是否是正常停止(SIGTERM = 143, SIGINT = 130)
if [ $EXIT_CODE -eq 0 ] || [ $EXIT_CODE -eq 130 ] || [ $EXIT_CODE -eq 143 ]; then
echo "服务正常停止,不重启"
break
fi
echo "服务异常退出,5秒后重启..."
sleep 5
done
rm -f "$PID_FILE"
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,165 @@
// global wrapper
/*! Element Plus v2.3.14 */
window.en = {
name: "en",
el: {
colorpicker: {
confirm: "OK",
clear: "Clear",
defaultLabel: "color picker",
description: "current color is {color}. press enter to select a new color."
},
datepicker: {
now: "Now",
today: "Today",
cancel: "Cancel",
clear: "Clear",
confirm: "OK",
dateTablePrompt: "Use the arrow keys and enter to select the day of the month",
monthTablePrompt: "Use the arrow keys and enter to select the month",
yearTablePrompt: "Use the arrow keys and enter to select the year",
selectedDate: "Selected date",
selectDate: "Select date",
selectTime: "Select time",
startDate: "Start Date",
startTime: "Start Time",
endDate: "End Date",
endTime: "End Time",
prevYear: "Previous Year",
nextYear: "Next Year",
prevMonth: "Previous Month",
nextMonth: "Next Month",
year: "",
month1: "January",
month2: "February",
month3: "March",
month4: "April",
month5: "May",
month6: "June",
month7: "July",
month8: "August",
month9: "September",
month10: "October",
month11: "November",
month12: "December",
week: "week",
weeks: {
sun: "Sun",
mon: "Mon",
tue: "Tue",
wed: "Wed",
thu: "Thu",
fri: "Fri",
sat: "Sat"
},
weeksFull: {
sun: "Sunday",
mon: "Monday",
tue: "Tuesday",
wed: "Wednesday",
thu: "Thursday",
fri: "Friday",
sat: "Saturday"
},
months: {
jan: "Jan",
feb: "Feb",
mar: "Mar",
apr: "Apr",
may: "May",
jun: "Jun",
jul: "Jul",
aug: "Aug",
sep: "Sep",
oct: "Oct",
nov: "Nov",
dec: "Dec"
}
},
inputNumber: {
decrease: "decrease number",
increase: "increase number"
},
select: {
loading: "Loading",
noMatch: "No matching data",
noData: "No data",
placeholder: "Select"
},
dropdown: {
toggleDropdown: "Toggle Dropdown"
},
cascader: {
noMatch: "No matching data",
loading: "Loading",
placeholder: "Select",
noData: "No data"
},
pagination: {
goto: "Go to",
pagesize: "/page",
total: "Total {total}",
pageClassifier: "",
page: "Page",
prev: "Go to previous page",
next: "Go to next page",
currentPage: "page {pager}",
prevPages: "Previous {pager} pages",
nextPages: "Next {pager} pages",
deprecationWarning: "Deprecated usages detected, please refer to the el-pagination documentation for more details"
},
dialog: {
close: "Close this dialog"
},
drawer: {
close: "Close this dialog"
},
messagebox: {
title: "Message",
confirm: "OK",
cancel: "Cancel",
error: "Illegal input",
close: "Close this dialog"
},
upload: {
deleteTip: "press delete to remove",
delete: "Delete",
preview: "Preview",
continue: "Continue"
},
slider: {
defaultLabel: "slider between {min} and {max}",
defaultRangeStartLabel: "pick start value",
defaultRangeEndLabel: "pick end value"
},
table: {
emptyText: "No Data",
confirmFilter: "Confirm",
resetFilter: "Reset",
clearFilter: "All",
sumText: "Sum"
},
tree: {
emptyText: "No Data"
},
transfer: {
noMatch: "No matching data",
noData: "No data",
titles: ["List 1", "List 2"],
filterPlaceholder: "Enter keyword",
noCheckedFormat: "{total} items",
hasCheckedFormat: "{checked}/{total} checked"
},
image: {
error: "FAILED"
},
pageHeader: {
title: "Back"
},
popconfirm: {
confirmButtonText: "Yes",
cancelButtonText: "No"
}
}
};
@@ -0,0 +1,165 @@
/*! Element Plus v2.3.14 */
var en = {
name: "en",
el: {
colorpicker: {
confirm: "OK",
clear: "Clear",
defaultLabel: "color picker",
description: "current color is {color}. press enter to select a new color."
},
datepicker: {
now: "Now",
today: "Today",
cancel: "Cancel",
clear: "Clear",
confirm: "OK",
dateTablePrompt: "Use the arrow keys and enter to select the day of the month",
monthTablePrompt: "Use the arrow keys and enter to select the month",
yearTablePrompt: "Use the arrow keys and enter to select the year",
selectedDate: "Selected date",
selectDate: "Select date",
selectTime: "Select time",
startDate: "Start Date",
startTime: "Start Time",
endDate: "End Date",
endTime: "End Time",
prevYear: "Previous Year",
nextYear: "Next Year",
prevMonth: "Previous Month",
nextMonth: "Next Month",
year: "",
month1: "January",
month2: "February",
month3: "March",
month4: "April",
month5: "May",
month6: "June",
month7: "July",
month8: "August",
month9: "September",
month10: "October",
month11: "November",
month12: "December",
week: "week",
weeks: {
sun: "Sun",
mon: "Mon",
tue: "Tue",
wed: "Wed",
thu: "Thu",
fri: "Fri",
sat: "Sat"
},
weeksFull: {
sun: "Sunday",
mon: "Monday",
tue: "Tuesday",
wed: "Wednesday",
thu: "Thursday",
fri: "Friday",
sat: "Saturday"
},
months: {
jan: "Jan",
feb: "Feb",
mar: "Mar",
apr: "Apr",
may: "May",
jun: "Jun",
jul: "Jul",
aug: "Aug",
sep: "Sep",
oct: "Oct",
nov: "Nov",
dec: "Dec"
}
},
inputNumber: {
decrease: "decrease number",
increase: "increase number"
},
select: {
loading: "Loading",
noMatch: "No matching data",
noData: "No data",
placeholder: "Select"
},
dropdown: {
toggleDropdown: "Toggle Dropdown"
},
cascader: {
noMatch: "No matching data",
loading: "Loading",
placeholder: "Select",
noData: "No data"
},
pagination: {
goto: "Go to",
pagesize: "/page",
total: "Total {total}",
pageClassifier: "",
page: "Page",
prev: "Go to previous page",
next: "Go to next page",
currentPage: "page {pager}",
prevPages: "Previous {pager} pages",
nextPages: "Next {pager} pages",
deprecationWarning: "Deprecated usages detected, please refer to the el-pagination documentation for more details"
},
dialog: {
close: "Close this dialog"
},
drawer: {
close: "Close this dialog"
},
messagebox: {
title: "Message",
confirm: "OK",
cancel: "Cancel",
error: "Illegal input",
close: "Close this dialog"
},
upload: {
deleteTip: "press delete to remove",
delete: "Delete",
preview: "Preview",
continue: "Continue"
},
slider: {
defaultLabel: "slider between {min} and {max}",
defaultRangeStartLabel: "pick start value",
defaultRangeEndLabel: "pick end value"
},
table: {
emptyText: "No Data",
confirmFilter: "Confirm",
resetFilter: "Reset",
clearFilter: "All",
sumText: "Sum"
},
tree: {
emptyText: "No Data"
},
transfer: {
noMatch: "No matching data",
noData: "No data",
titles: ["List 1", "List 2"],
filterPlaceholder: "Enter keyword",
noCheckedFormat: "{total} items",
hasCheckedFormat: "{checked}/{total} checked"
},
image: {
error: "FAILED"
},
pageHeader: {
title: "Back"
},
popconfirm: {
confirmButtonText: "Yes",
cancelButtonText: "No"
}
}
};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,130 @@
// global wrapper
/*! Element Plus v2.3.14 */
window.zhCn = {
name: "zh-cn",
el: {
colorpicker: {
confirm: "\u786E\u5B9A",
clear: "\u6E05\u7A7A"
},
datepicker: {
now: "\u6B64\u523B",
today: "\u4ECA\u5929",
cancel: "\u53D6\u6D88",
clear: "\u6E05\u7A7A",
confirm: "\u786E\u5B9A",
selectDate: "\u9009\u62E9\u65E5\u671F",
selectTime: "\u9009\u62E9\u65F6\u95F4",
startDate: "\u5F00\u59CB\u65E5\u671F",
startTime: "\u5F00\u59CB\u65F6\u95F4",
endDate: "\u7ED3\u675F\u65E5\u671F",
endTime: "\u7ED3\u675F\u65F6\u95F4",
prevYear: "\u524D\u4E00\u5E74",
nextYear: "\u540E\u4E00\u5E74",
prevMonth: "\u4E0A\u4E2A\u6708",
nextMonth: "\u4E0B\u4E2A\u6708",
year: "\u5E74",
month1: "1 \u6708",
month2: "2 \u6708",
month3: "3 \u6708",
month4: "4 \u6708",
month5: "5 \u6708",
month6: "6 \u6708",
month7: "7 \u6708",
month8: "8 \u6708",
month9: "9 \u6708",
month10: "10 \u6708",
month11: "11 \u6708",
month12: "12 \u6708",
weeks: {
sun: "\u65E5",
mon: "\u4E00",
tue: "\u4E8C",
wed: "\u4E09",
thu: "\u56DB",
fri: "\u4E94",
sat: "\u516D"
},
months: {
jan: "\u4E00\u6708",
feb: "\u4E8C\u6708",
mar: "\u4E09\u6708",
apr: "\u56DB\u6708",
may: "\u4E94\u6708",
jun: "\u516D\u6708",
jul: "\u4E03\u6708",
aug: "\u516B\u6708",
sep: "\u4E5D\u6708",
oct: "\u5341\u6708",
nov: "\u5341\u4E00\u6708",
dec: "\u5341\u4E8C\u6708"
}
},
select: {
loading: "\u52A0\u8F7D\u4E2D",
noMatch: "\u65E0\u5339\u914D\u6570\u636E",
noData: "\u65E0\u6570\u636E",
placeholder: "\u8BF7\u9009\u62E9"
},
cascader: {
noMatch: "\u65E0\u5339\u914D\u6570\u636E",
loading: "\u52A0\u8F7D\u4E2D",
placeholder: "\u8BF7\u9009\u62E9",
noData: "\u6682\u65E0\u6570\u636E"
},
pagination: {
goto: "\u524D\u5F80",
pagesize: "\u6761/\u9875",
total: "\u5171 {total} \u6761",
pageClassifier: "\u9875",
page: "\u9875",
prev: "\u4E0A\u4E00\u9875",
next: "\u4E0B\u4E00\u9875",
currentPage: "\u7B2C {pager} \u9875",
prevPages: "\u5411\u524D {pager} \u9875",
nextPages: "\u5411\u540E {pager} \u9875",
deprecationWarning: "\u4F60\u4F7F\u7528\u4E86\u4E00\u4E9B\u5DF2\u88AB\u5E9F\u5F03\u7684\u7528\u6CD5\uFF0C\u8BF7\u53C2\u8003 el-pagination \u7684\u5B98\u65B9\u6587\u6863"
},
messagebox: {
title: "\u63D0\u793A",
confirm: "\u786E\u5B9A",
cancel: "\u53D6\u6D88",
error: "\u8F93\u5165\u7684\u6570\u636E\u4E0D\u5408\u6CD5!"
},
upload: {
deleteTip: "\u6309 delete \u952E\u53EF\u5220\u9664",
delete: "\u5220\u9664",
preview: "\u67E5\u770B\u56FE\u7247",
continue: "\u7EE7\u7EED\u4E0A\u4F20"
},
table: {
emptyText: "\u6682\u65E0\u6570\u636E",
confirmFilter: "\u7B5B\u9009",
resetFilter: "\u91CD\u7F6E",
clearFilter: "\u5168\u90E8",
sumText: "\u5408\u8BA1"
},
tree: {
emptyText: "\u6682\u65E0\u6570\u636E"
},
transfer: {
noMatch: "\u65E0\u5339\u914D\u6570\u636E",
noData: "\u65E0\u6570\u636E",
titles: ["\u5217\u8868 1", "\u5217\u8868 2"],
filterPlaceholder: "\u8BF7\u8F93\u5165\u641C\u7D22\u5185\u5BB9",
noCheckedFormat: "\u5171 {total} \u9879",
hasCheckedFormat: "\u5DF2\u9009 {checked}/{total} \u9879"
},
image: {
error: "\u52A0\u8F7D\u5931\u8D25"
},
pageHeader: {
title: "\u8FD4\u56DE"
},
popconfirm: {
confirmButtonText: "\u786E\u5B9A",
cancelButtonText: "\u53D6\u6D88"
}
}
};
@@ -0,0 +1,130 @@
/*! Element Plus v2.3.14 */
var zhCn = {
name: "zh-cn",
el: {
colorpicker: {
confirm: "\u786E\u5B9A",
clear: "\u6E05\u7A7A"
},
datepicker: {
now: "\u6B64\u523B",
today: "\u4ECA\u5929",
cancel: "\u53D6\u6D88",
clear: "\u6E05\u7A7A",
confirm: "\u786E\u5B9A",
selectDate: "\u9009\u62E9\u65E5\u671F",
selectTime: "\u9009\u62E9\u65F6\u95F4",
startDate: "\u5F00\u59CB\u65E5\u671F",
startTime: "\u5F00\u59CB\u65F6\u95F4",
endDate: "\u7ED3\u675F\u65E5\u671F",
endTime: "\u7ED3\u675F\u65F6\u95F4",
prevYear: "\u524D\u4E00\u5E74",
nextYear: "\u540E\u4E00\u5E74",
prevMonth: "\u4E0A\u4E2A\u6708",
nextMonth: "\u4E0B\u4E2A\u6708",
year: "\u5E74",
month1: "1 \u6708",
month2: "2 \u6708",
month3: "3 \u6708",
month4: "4 \u6708",
month5: "5 \u6708",
month6: "6 \u6708",
month7: "7 \u6708",
month8: "8 \u6708",
month9: "9 \u6708",
month10: "10 \u6708",
month11: "11 \u6708",
month12: "12 \u6708",
weeks: {
sun: "\u65E5",
mon: "\u4E00",
tue: "\u4E8C",
wed: "\u4E09",
thu: "\u56DB",
fri: "\u4E94",
sat: "\u516D"
},
months: {
jan: "\u4E00\u6708",
feb: "\u4E8C\u6708",
mar: "\u4E09\u6708",
apr: "\u56DB\u6708",
may: "\u4E94\u6708",
jun: "\u516D\u6708",
jul: "\u4E03\u6708",
aug: "\u516B\u6708",
sep: "\u4E5D\u6708",
oct: "\u5341\u6708",
nov: "\u5341\u4E00\u6708",
dec: "\u5341\u4E8C\u6708"
}
},
select: {
loading: "\u52A0\u8F7D\u4E2D",
noMatch: "\u65E0\u5339\u914D\u6570\u636E",
noData: "\u65E0\u6570\u636E",
placeholder: "\u8BF7\u9009\u62E9"
},
cascader: {
noMatch: "\u65E0\u5339\u914D\u6570\u636E",
loading: "\u52A0\u8F7D\u4E2D",
placeholder: "\u8BF7\u9009\u62E9",
noData: "\u6682\u65E0\u6570\u636E"
},
pagination: {
goto: "\u524D\u5F80",
pagesize: "\u6761/\u9875",
total: "\u5171 {total} \u6761",
pageClassifier: "\u9875",
page: "\u9875",
prev: "\u4E0A\u4E00\u9875",
next: "\u4E0B\u4E00\u9875",
currentPage: "\u7B2C {pager} \u9875",
prevPages: "\u5411\u524D {pager} \u9875",
nextPages: "\u5411\u540E {pager} \u9875",
deprecationWarning: "\u4F60\u4F7F\u7528\u4E86\u4E00\u4E9B\u5DF2\u88AB\u5E9F\u5F03\u7684\u7528\u6CD5\uFF0C\u8BF7\u53C2\u8003 el-pagination \u7684\u5B98\u65B9\u6587\u6863"
},
messagebox: {
title: "\u63D0\u793A",
confirm: "\u786E\u5B9A",
cancel: "\u53D6\u6D88",
error: "\u8F93\u5165\u7684\u6570\u636E\u4E0D\u5408\u6CD5!"
},
upload: {
deleteTip: "\u6309 delete \u952E\u53EF\u5220\u9664",
delete: "\u5220\u9664",
preview: "\u67E5\u770B\u56FE\u7247",
continue: "\u7EE7\u7EED\u4E0A\u4F20"
},
table: {
emptyText: "\u6682\u65E0\u6570\u636E",
confirmFilter: "\u7B5B\u9009",
resetFilter: "\u91CD\u7F6E",
clearFilter: "\u5168\u90E8",
sumText: "\u5408\u8BA1"
},
tree: {
emptyText: "\u6682\u65E0\u6570\u636E"
},
transfer: {
noMatch: "\u65E0\u5339\u914D\u6570\u636E",
noData: "\u65E0\u6570\u636E",
titles: ["\u5217\u8868 1", "\u5217\u8868 2"],
filterPlaceholder: "\u8BF7\u8F93\u5165\u641C\u7D22\u5185\u5BB9",
noCheckedFormat: "\u5171 {total} \u9879",
hasCheckedFormat: "\u5DF2\u9009 {checked}/{total} \u9879"
},
image: {
error: "\u52A0\u8F7D\u5931\u8D25"
},
pageHeader: {
title: "\u8FD4\u56DE"
},
popconfirm: {
confirmButtonText: "\u786E\u5B9A",
cancelButtonText: "\u53D6\u6D88"
}
}
};
@@ -0,0 +1,307 @@
/**
* Conversation Sidebar Styles
* 类似ChatGPT的会话侧边栏样式
*/
/* 侧边栏容器 */
.conversation-sidebar {
width: 260px;
min-width: 260px;
height: 100%;
background: #202123;
color: #ececf1;
display: flex;
flex-direction: column;
transition: width 0.3s ease;
overflow: hidden;
}
.conversation-sidebar.collapsed {
width: 60px;
min-width: 60px;
}
/* 头部 */
.sidebar-header {
padding: 12px;
display: flex;
gap: 8px;
align-items: center;
border-bottom: 1px solid #2d2d2d;
}
.new-chat-btn {
flex: 1;
display: flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
background: transparent;
border: 1px solid #4d4d4f;
border-radius: 6px;
color: #ececf1;
font-size: 14px;
cursor: pointer;
transition: all 0.2s;
}
.new-chat-btn:hover {
background: #2d2d2d;
border-color: #ececf1;
}
.new-chat-btn .el-icon {
font-size: 16px;
}
.toggle-btn {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: none;
color: #8e8ea0;
cursor: pointer;
border-radius: 6px;
transition: all 0.2s;
}
.toggle-btn:hover {
background: #2d2d2d;
color: #ececf1;
}
/* 搜索框 */
.search-box {
padding: 12px;
border-bottom: 1px solid #2d2d2d;
}
.search-box .el-input__wrapper {
background: #2d2d2d !important;
border: 1px solid #4d4d4f !important;
border-radius: 6px !important;
}
.search-box .el-input__inner {
color: #ececf1 !important;
}
.search-box .el-input__inner::placeholder {
color: #8e8ea0 !important;
}
/* 会话列表 */
.conversation-list {
flex: 1;
overflow-y: auto;
padding: 8px;
}
/* 分组标题 */
.list-section {
margin-bottom: 16px;
}
.section-title {
padding: 8px 12px;
font-size: 12px;
color: #8e8ea0;
text-transform: uppercase;
letter-spacing: 0.5px;
}
/* 会话项 */
.conversation-item {
display: flex;
align-items: flex-start;
gap: 10px;
padding: 10px 12px;
margin-bottom: 2px;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s;
position: relative;
}
.conversation-item:hover {
background: #2d2d2d;
}
.conversation-item.active {
background: #343541;
}
.item-icon {
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
color: #8e8ea0;
flex-shrink: 0;
margin-top: 2px;
}
.item-content {
flex: 1;
min-width: 0;
overflow: hidden;
}
.item-title {
font-size: 14px;
color: #ececf1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-bottom: 4px;
}
.item-meta {
display: flex;
gap: 8px;
align-items: center;
margin-bottom: 4px;
}
.gene-family {
font-size: 11px;
color: #10a37f;
background: rgba(16, 163, 127, 0.1);
padding: 2px 6px;
border-radius: 4px;
}
.message-count {
font-size: 11px;
color: #8e8ea0;
}
.item-preview {
font-size: 12px;
color: #8e8ea0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* 操作按钮 */
.item-actions {
opacity: 0;
transition: opacity 0.2s;
flex-shrink: 0;
}
.conversation-item:hover .item-actions {
opacity: 1;
}
.item-actions .el-icon {
color: #8e8ea0;
cursor: pointer;
padding: 4px;
border-radius: 4px;
}
.item-actions .el-icon:hover {
color: #ececf1;
background: #4d4d4f;
}
/* 空状态 */
.empty-state {
padding: 40px 20px;
text-align: center;
color: #8e8ea0;
}
.empty-state .el-icon {
font-size: 48px;
margin-bottom: 16px;
color: #4d4d4f;
}
.empty-state p {
margin: 0;
font-size: 14px;
}
.empty-state .hint {
font-size: 12px;
margin-top: 8px;
color: #6e6e80;
}
/* 底部用户信息 */
.sidebar-footer {
padding: 12px;
border-top: 1px solid #2d2d2d;
}
.user-info {
display: flex;
align-items: center;
gap: 10px;
padding: 8px;
border-radius: 6px;
cursor: pointer;
transition: background 0.2s;
}
.user-info:hover {
background: #2d2d2d;
}
.username {
font-size: 14px;
color: #ececf1;
}
/* 滚动条样式 */
.conversation-list::-webkit-scrollbar {
width: 6px;
}
.conversation-list::-webkit-scrollbar-track {
background: transparent;
}
.conversation-list::-webkit-scrollbar-thumb {
background: #4d4d4f;
border-radius: 3px;
}
.conversation-list::-webkit-scrollbar-thumb:hover {
background: #6e6e80;
}
/* 下拉菜单样式 */
.el-dropdown-menu {
background: #202123 !important;
border: 1px solid #4d4d4f !important;
}
.el-dropdown-menu__item {
color: #ececf1 !important;
}
.el-dropdown-menu__item:hover {
background: #2d2d2d !important;
}
.el-dropdown-menu__item.is-divided {
border-top: 1px solid #4d4d4f !important;
}
/* 深色主题覆盖 */
.conversation-sidebar .el-input__wrapper {
background: #2d2d2d !important;
box-shadow: 0 0 0 1px #4d4d4f inset !important;
}
.conversation-sidebar .el-input__inner {
color: #ececf1 !important;
}
@@ -0,0 +1,373 @@
/**
* Conversation Sidebar Component
* Conversation Sidebar component
*/
const ConversationSidebar = {
template: `
<div class="conversation-sidebar" :class="{ collapsed: isCollapsed }">
<!-- Header: New Chat button -->
<div class="sidebar-header">
<button class="new-chat-btn" @click="createNewConversation">
<el-icon><plus /></el-icon>
<span v-if="!isCollapsed">New Chat</span>
</button>
<button class="toggle-btn" @click="toggleSidebar">
<el-icon><arrow-left v-if="!isCollapsed" /><arrow-right v-else /></el-icon>
</button>
</div>
<!-- Search box -->
<div class="search-box" v-if="!isCollapsed">
<el-input
v-model="searchQuery"
placeholder="Search conversations..."
prefix-icon="search"
clearable
size="small"
/>
</div>
<!-- Conversation list -->
<div class="conversation-list" v-if="!isCollapsed">
<!-- Todays conversations -->
<div class="list-section" v-if="todayConversations.length > 0">
<div class="section-title">Today</div>
<div
v-for="conv in todayConversations"
:key="conv.conversation_id"
class="conversation-item"
:class="{ active: currentConversationId === conv.conversation_id }"
@click="selectConversation(conv)"
>
<div class="item-icon">
<el-icon><chat-dot-round /></el-icon>
</div>
<div class="item-content">
<div class="item-title">{{ conv.title }}</div>
<div class="item-meta">
<span class="gene-family" v-if="conv.gene_family">{{ conv.gene_family }}</span>
<span class="message-count">{{ conv.message_count }} messages</span>
</div>
<div class="item-preview">{{ conv.last_message }}</div>
</div>
<div class="item-actions" @click.stop>
<el-dropdown trigger="click">
<el-icon><more /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="renameConversation(conv)">
<el-icon><edit /></el-icon>Rename
</el-dropdown-item>
<el-dropdown-item @click="archiveConversation(conv)">
<el-icon><folder /></el-icon>Archive
</el-dropdown-item>
<el-dropdown-item divided @click="deleteConversation(conv)" type="danger">
<el-icon><delete /></el-icon>Delete
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</div>
<!-- Yesterdays conversations -->
<div class="list-section" v-if="yesterdayConversations.length > 0">
<div class="section-title">Yesterday</div>
<div
v-for="conv in yesterdayConversations"
:key="conv.conversation_id"
class="conversation-item"
:class="{ active: currentConversationId === conv.conversation_id }"
@click="selectConversation(conv)"
>
<div class="item-icon">
<el-icon><chat-dot-round /></el-icon>
</div>
<div class="item-content">
<div class="item-title">{{ conv.title }}</div>
<div class="item-meta">
<span class="gene-family" v-if="conv.gene_family">{{ conv.gene_family }}</span>
<span class="message-count">{{ conv.message_count }}</span>
</div>
</div>
</div>
</div>
<!-- Older conversations -->
<div class="list-section" v-if="olderConversations.length > 0">
<div class="section-title">Past 7 days</div>
<div
v-for="conv in olderConversations"
:key="conv.conversation_id"
class="conversation-item"
:class="{ active: currentConversationId === conv.conversation_id }"
@click="selectConversation(conv)"
>
<div class="item-icon">
<el-icon><chat-dot-round /></el-icon>
</div>
<div class="item-content">
<div class="item-title">{{ conv.title }}</div>
<div class="item-meta">
<span class="gene-family" v-if="conv.gene_family">{{ conv.gene_family }}</span>
</div>
</div>
</div>
</div>
<!-- Empty state -->
<div v-if="filteredConversations.length === 0" class="empty-state">
<el-icon><chat-line-round /></el-icon>
<p>No conversations yet</p>
<p class="hint">Click "New Chat" to start gene family analysis</p>
</div>
</div>
<!-- footer: user info -->
<div class="sidebar-footer" v-if="!isCollapsed">
<div class="user-info">
<el-avatar :size="32" :icon="UserFilled" />
<span class="username">{{ userId }}</span>
</div>
</div>
</div>
`,
props: {
userId: {
type: String,
default: 'xia-lab'
},
apiBaseUrl: {
type: String,
default: 'http://localhost:8000/api'
}
},
data() {
return {
isCollapsed: false,
searchQuery: '',
conversations: [],
currentConversationId: null,
loading: false,
// Icons
Plus: ElementPlusIconsVue.Plus,
ArrowLeft: ElementPlusIconsVue.ArrowLeft,
ArrowRight: ElementPlusIconsVue.ArrowRight,
ChatDotRound: ElementPlusIconsVue.ChatDotRound,
ChatLineRound: ElementPlusIconsVue.ChatLineRound,
More: ElementPlusIconsVue.More,
Edit: ElementPlusIconsVue.Edit,
Folder: ElementPlusIconsVue.Folder,
Delete: ElementPlusIconsVue.Delete,
UserFilled: ElementPlusIconsVue.UserFilled,
}
},
computed: {
filteredConversations() {
if (!this.searchQuery) return this.conversations;
const query = this.searchQuery.toLowerCase();
return this.conversations.filter(conv =>
conv.title.toLowerCase().includes(query) ||
(conv.gene_family && conv.gene_family.toLowerCase().includes(query)) ||
conv.last_message.toLowerCase().includes(query)
);
},
todayConversations() {
const today = new Date().toDateString();
return this.filteredConversations.filter(conv => {
const convDate = new Date(conv.updated_at).toDateString();
return convDate === today;
});
},
yesterdayConversations() {
const yesterday = new Date(Date.now() - 86400000).toDateString();
return this.filteredConversations.filter(conv => {
const convDate = new Date(conv.updated_at).toDateString();
return convDate === yesterday;
});
},
olderConversations() {
const yesterday = new Date(Date.now() - 86400000).toDateString();
return this.filteredConversations.filter(conv => {
const convDate = new Date(conv.updated_at).toDateString();
return convDate < yesterday;
});
}
},
mounted() {
this.loadConversations();
// Auto-refresh
this.refreshInterval = setInterval(() => {
this.loadConversations();
}, 30000); // 30 seconds refresh interval
},
beforeUnmount() {
if (this.refreshInterval) {
clearInterval(this.refreshInterval);
}
},
methods: {
async loadConversations() {
try {
this.loading = true;
const response = await fetch(`${this.apiBaseUrl}/conversations/list/${this.userId}`);
if (response.ok) {
const data = await response.json();
this.conversations = data.conversations || [];
}
} catch (error) {
console.error('Failed to load conversations:', error);
// Use mock data
this.conversations = this.getMockConversations();
} finally {
this.loading = false;
}
},
getMockConversations() {
// Mock data for testing
return [
{
conversation_id: 'conv_001',
title: 'At.WRKY gene family analysis',
gene_family: 'WRKY',
species: 'At',
message_count: 12,
last_message: 'Phylogenetic tree done',
updated_at: new Date().toISOString()
},
{
conversation_id: 'conv_002',
title: 'Os.TCP evolution analysis',
gene_family: 'TCP',
species: 'Os',
message_count: 5,
last_message: 'Building tree...',
updated_at: new Date(Date.now() - 3600000).toISOString()
},
{
conversation_id: 'conv_003',
title: 'HMMER config consultation',
message_count: 8,
last_message: 'E-value 1e-5 recommended',
updated_at: new Date(Date.now() - 86400000).toISOString()
}
];
},
toggleSidebar() {
this.isCollapsed = !this.isCollapsed;
this.$emit('toggle', this.isCollapsed);
},
async createNewConversation() {
try {
const response = await fetch(`${this.apiBaseUrl}/conversations/create`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
user_id: this.userId,
title: 'New Chat ' + new Date().toLocaleTimeString()
})
});
if (response.ok) {
const data = await response.json();
this.currentConversationId = data.conversation_id;
this.$emit('new-conversation', data);
await this.loadConversations();
}
} catch (error) {
console.error('Failed to create conversation:', error);
// Create local conversation
const newConv = {
conversation_id: 'conv_' + Date.now(),
title: 'New Chat',
message_count: 0,
last_message: '',
updated_at: new Date().toISOString()
};
this.conversations.unshift(newConv);
this.currentConversationId = newConv.conversation_id;
this.$emit('new-conversation', newConv);
}
},
selectConversation(conv) {
this.currentConversationId = conv.conversation_id;
this.$emit('select-conversation', conv);
},
async renameConversation(conv) {
const newTitle = prompt('Enter new title:', conv.title);
if (newTitle && newTitle !== conv.title) {
try {
await fetch(`${this.apiBaseUrl}/conversations/update-title`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
conversation_id: conv.conversation_id,
title: newTitle
})
});
conv.title = newTitle;
} catch (error) {
console.error('Failed to rename:', error);
conv.title = newTitle; // local update
}
}
},
async archiveConversation(conv) {
try {
await fetch(`${this.apiBaseUrl}/conversations/archive`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
conversation_id: conv.conversation_id
})
});
await this.loadConversations();
} catch (error) {
console.error('Failed to archive:', error);
}
},
async deleteConversation(conv) {
if (confirm(`Delete conversation "${conv.title}"?`)) {
try {
await fetch(`${this.apiBaseUrl}/conversations/delete`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
conversation_id: conv.conversation_id
})
});
await this.loadConversations();
if (this.currentConversationId === conv.conversation_id) {
this.currentConversationId = null;
this.$emit('select-conversation', null);
}
} catch (error) {
console.error('Failed to delete:', error);
}
}
}
}
};
// Export component
if (typeof module !== 'undefined' && module.exports) {
module.exports = { ConversationSidebar };
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,716 @@
// ===== Agent 多语言:卡片 + Agent 消息英文翻译 =====
// key 为中文原文,value 为英文翻译
// 使用 t(key) 获取翻译,tp(key, params) 处理动态占位符
window.__I18N_EN__ = {
"Agent状态": "AgentStatus",
"Self-RAG反思": "Self-RAG Reflection",
"三角形": "Triangle",
"下一步": "Next Step",
"下载": "Download",
"不受支持标记处理策略": "Unsupported Marker Handling Policy",
"中性替换率": "Neutral Substitution Rate",
"中性速率": "Neutral Rate",
"中文": "Chinese",
"丰度引擎": "Abundance Engine",
"主参考": "Primary Reference",
"主参考物种": "Primary reference species",
"主要结果": "Main Results",
"亚家族分类确认": "Subfamily Classification Confirmation",
"亚家族名称距离": "Subfamily Name Distance",
"亚家族外圈弧线": "Subfamily Outer Arc",
"亚家族确认参数": "Subfamily Confirmation Parameters",
"交集": "Intersection",
"仅圈图": "Circle Plot Only",
"仅比较物种": "Comparative Species Only",
"仅目标": "Target Only",
"仅目标物种": "Target Species Only",
"仅矩形图": "Rectangular Only",
"任务列表": "Task List",
"位置分布图": "Position Distribution Map",
"使用拟南芥作为显式兜底": "Use Arabidopsis as Explicit Fallback",
"使用推荐区间": "Use Recommended Range",
"保存方法学方案": "Save Methodology Plan",
"保留": "Retain",
"修订": "Revision",
"倒计时已暂停": "Countdown paused",
"全屏": "Full Screen",
"全屏展示": "Full Screen Display",
"全部": "All",
"全部行": "All Rows",
"关系总数": "Total Edges",
"关闭": "Close",
"内容": "Content",
"内置物种代码": "Built-in Species Code",
"分析家族": "Analysis Family",
"分组角色": "Group Role",
"分组角色不改": "Group Role (Unchanged)",
"删除": "Deleted",
"删除会话": "Delete Session",
"刷新": "Refresh",
"刷新结果": "Refresh Results",
"前景基因": "Foreground Genes",
"功能类别": "Feature Category",
"加入正式列表": "Add to Formal List",
"包含关键词": "Contains Keyword",
"匹配方式": "Match Mode",
"匹配行": "Matched Rows",
"原因": "Reason",
"原始代码": "Original Code",
"原始命令": "Original Command",
"原始文件名": "Original Filename",
"原始证据": "Original Evidence",
"原推荐参考": "Original Recommended Reference",
"参数": "Parameters",
"参考分类": "Reference Classification",
"参考前缀": "Reference Prefix",
"参考基因": "Reference Gene",
"参考基因编号": "Reference Gene ID",
"参考文献": "References",
"参考物种": "Reference Species",
"发送": "Send",
"取消": "Cancel",
"取消预览": "Cancel Preview",
"只会执行已勾选且可执行的阶段": "Only checked and executable stages will run",
"可改": "Editable",
"同时处理的样本数": "Number of Samples Processed Simultaneously",
"名称": "Name",
"后续主参考物种": "Downstream Primary Reference Species",
"启动子元件": "Promoter Elements",
"启动子自定义绘图": "Promoter Custom Plot",
"图例颜色": "Legend Color",
"图类型": "Plot Type",
"图表标题清单": "Chart Title List",
"图表标题驱动复现规划预览": "Chart Title-Driven Reproduction Plan Preview",
"圆形": "Circle",
"基因注释": "Gene Annotation",
"基本参数": "Basic Parameters",
"基础参数": "Basic Parameters",
"处理中...": "Processing...",
"处理方式": "Processing Method",
"多物种处理方式": "Multi-species Processing",
"大小": "Size",
"定量模式": "Quantification Mode",
"实验设计": "Experimental Design",
"实验设计模块": "Experimental Design Module",
"审核备注": "Review Notes",
"富集类型": "Enrichment Type",
"差异表达范围": "Differential Expression Scope",
"已写阶段": "Registered Stages",
"已完成": "Completed",
"已完成阶段": "Completed Stages",
"已应用": "Applied",
"建议参数": "Suggested Parameters",
"开始验证": "Start Validation",
"弧线避让距离": "Arc Avoidance Distance",
"当前参数": "Current Parameters",
"当前参考物种": "Current Reference Species",
"当前选择": "Current Selection",
"待补数据": "Awaiting Data",
"必填": "Required",
"我知道了": "Got It",
"手动区间": "Manual Range",
"执行": "Execute",
"扫描双链": "Scan Both Strands",
"批量执行确认": "Batch Execution Confirmation",
"拉丁名": "Latin Name",
"拓展分析运行参数确认": "Extension Analysis Run Parameter Confirmation",
"拓展分析阶段": "Extension Analysis Stage",
"拓展分析阶段状态": "Extension Analysis Stage Status",
"拓展分析阶段确认": "Extension Analysis Stage Confirmation",
"拓展分析阶段运行结果": "Extension Analysis Stage Run Result",
"按元件": "By Element",
"按单个物种分别分析与确认": "Per-Species Analysis & Confirmation",
"按当前筛选重建成员蛋白": "Rebuild Member Proteins by Current Filter",
"按类别": "By Category",
"授权发布": "Authorize Publish",
"推荐参考数据下载失败": "Recommended Ref Data Download Failed",
"提出修订意见": "Submit Revision Suggestions",
"操作": "Operation",
"数据准备": "Data Preparation",
"数据路径": "Data Path",
"数据需求": "Data Needs",
"文件": "File",
"文件类型": "File Type",
"文件范围": "File Scope",
"文献参数": "Literature Parameters",
"文献工具": "Literature Tools",
"文章涉及物种与下载入口": "Article Species & Download Entry",
"新增": "Added",
"方形": "Square",
"方法参考": "Method Reference",
"方法学文献": "Methodology Papers",
"无": "None",
"明确指定": "Explicitly Specify",
"显示": "Show",
"暂停倒计时": "Pause Countdown",
"暂无已上传文件": "No Uploaded Files Yet",
"暂无拓展分析阶段结果": "No Extension Analysis Stage Results Yet",
"暂无状态记录": "No Status Record Yet",
"最大宽度": "Max Width",
"最小宽度": "Min Width",
"最小非缺口比例": "Min Non-gap Ratio",
"最近到属": "Closest to Genus",
"最近到目": "Closest to Order",
"最近到科": "Closest to Family",
"最近到纲": "Closest to Class",
"有损转换警告": "Lossy Conversion Warning",
"服务器测试数据路径": "Server Test Data Path",
"未从图表标题推断出额外阶段": "No Additional Stages Inferred from Chart Titles",
"未提取到图表标题": "No Chart Title Extracted",
"未识别到内置下载链接": "No Built-in DL Link Identified",
"未识别到参数": "No Parameters Identified",
"未识别到文献工具": "No Literature Tool Identified",
"本次成员鉴定物种": "Current Member Identification Species",
"来源": "Sources",
"染色体标注位置": "Chromosome Annotation Position",
"染色体标注大小": "Chromosome Annotation Size",
"染色体策略": "Chromosome Strategy",
"染色体色块粗细": "Chromosome Block Width",
"查看本次知识检索过程": "View knowledge retrieval process",
"标记大小": "Mark Size",
"标记模式": "Mark Mode",
"标题推断的候选阶段": "Candidate Stages Inferred from Titles",
"树枝粗细": "Branch Width",
"树枝颜色": "Branch Color",
"样本并行数量": "Sample Parallel Count",
"检索结果": "Retrieval Results",
"检索表格内容": "Search Table Content",
"正则匹配": "Regex Match",
"此拓展阶段没有可配置参数": "No Configurable Parameters",
"测试数据": "Test Data",
"涉及阶段": "Involved Stages",
"添加行": "Add Row",
"灰色": "Gray",
"物种": "Species",
"物种代码": "Species Code",
"物种代码不改": "Species Code (Unchanged)",
"物种名": "Species Name",
"物种角色": "Species Role",
"物种角色不改": "Species Role (Unchanged)",
"环境": "Environment",
"留空则自动发现": "Leave empty for auto-discovery",
"目标前缀": "Target Prefix",
"目标物种": "Target Species",
"知识图谱": "Knowledge Graph",
"确定": "Confirm",
"确认亚家族标签": "Confirm Subfamily Labels",
"确认保存": "Confirm Save",
"确认并写入正式配置": "Confirm & Write to Official Config",
"确认并执行": "Confirm & Execute",
"确认执行": "Confirm Execution",
"确认自动注释": "Confirm Auto-Annotation",
"确认重绘": "Confirm Replot",
"种间共线性比较物种": "Interspecies Synteny Comparative Species",
"种间共线性绘图设置": "Interspecies Synteny Plot Settings",
"移除": "Remove",
"窗口长度": "Window Length",
"类型": "Types",
"精确匹配": "Exact Match",
"红色": "Red",
"终止位点": "End Site",
"终止残基": "End Residue",
"绘图模式": "Plot Mode",
"绿色": "Green",
"置信度": "Confidence",
"置信度阈值": "Confidence Threshold",
"群体遗传输入": "Population Genetic Input",
"背景来源": "Background Source",
"背景知识": "Background knowledge",
"自动": "Auto",
"自动从注释提取": "Auto-extract from Annotation",
"自动保守窗口": "Auto Conserved Window",
"自动判断": "Auto-detect",
"节点名称": "Node Name",
"节点总数": "Total Nodes",
"节点类型": "Node Types",
"菱形": "Diamond",
"蓝色": "Blue",
"蛋白": "Protein",
"蛋白文件": "Protein Files",
"表达矩阵": "Expression Matrix",
"诊断动作": "Diagnostic Actions",
"说明": "Description",
"请先试运行以记录真实输出": "Please Run a Trial First to Record Actual Output",
"请选择共线性分析类型": "Please select synteny analysis type",
"请选择模式物种": "Select Model Species",
"起始位点": "Start Site",
"起始残基": "Start Residue",
"跳数": "Hops",
"输出": "Output",
"输出前缀": "Output Prefix",
"输出标签": "Output Label",
"运行值": "Run Value",
"运行结果": "Run Result",
"进化树图修订参数": "Phylogenetic Tree Revision Parameters",
"连接关系数": "Connections",
"迭代": "Iteration",
"选择其他提取结果": "Select Other Extraction Result",
"选择工具": "Select Tool",
"选择已完成撰写的拓展阶段": "Select Completed Extension Stage",
"通常留空": "Usually leave empty",
"重写查询": "Rewrite Query",
"重新生成说明": "Regenerate Description",
"重置": "Reset",
"重置视图": "Reset View",
"链接": "Link",
"链特异性": "Library Strandedness",
"隐藏": "Hide",
"需检查": "Needs Review",
"需要补充": "Need to Supplement",
"非时间实验留空": "Leave empty for non-time experiments",
"项目": "Project",
"预览": "Preview",
"预览到表格": "Preview to Table",
"预览命令": "Preview Commands",
"黑色": "Black",
"默认值": "Default Value",
"提取方法学": "Extract",
"刷新记录": "Refresh",
"打开最新提取结果": "Open Latest Extraction",
"查看最新提取状态": "View Latest Status",
"打开所选提取结果": "Open Selected Extraction",
"查看所选提取状态": "View Selected Status",
"生成并发布": "Generate & Publish",
"运行已发布": "Run Published",
"当前会话": "Current Session",
"更多会话": "More Sessions",
"新建": "New",
"新建会话": "New Session",
"使用小Tip": "Tips",
"一、分析模块快速指令": "1. Analysis Module Quick Commands",
"选择输入框上方\"Analysis\"": "Select \"Analysis\" above input box",
"粘贴数据位置": "Paste data location",
"核对配置文件": "Review config files",
"执行数据准备": "Run data preparation",
"执行XX物种的亚家族分类": "Run subfamily classification for XX species",
"执行XX物种的基因家族分析": "Run gene family analysis for XX species",
"执行rnaseq分析": "Run RNA-seq analysis",
"二、文章复现步骤": "2. Article Reproduction Steps",
"点击\"浏览\"上传文献": "Click \"Browse\" to upload paper",
"点击提取方法学": "Click Extract Methodology",
"核对分析步骤": "Review analysis steps",
"点击保存方案": "Click Save Plan",
"上传数据": "Upload data",
"发送\"按已保存的方法学方案继续执行\"": "Send \"Continue with saved methodology plan\"",
"三、RAG快速指令": "3. RAG Quick Commands",
"选择输入框上方\"RAG\"": "Select \"RAG\" above input box",
"输入问题": "Enter question",
"点击\"知识图谱\"查看关系": "Click \"Knowledge Graph\" to view relations",
"知识图谱": "Knowledge Graph",
"重新加载": "Reload",
"重置视图": "Reset View",
"2.2 MSA Replot / 区间重绘": "2.2 MSA Replot",
"2.3 Tree Replot / 进化树重绘": "2.3 Tree Replot",
"2.5 亚家族确认": "2.5 Subfamily Confirmation",
"6.1 启动子自定义绘图": "6.1 Promoter Custom Plot",
"7️⃣ 种内Synteny": "7️⃣ Intraspecies Synteny",
"7.1 种内共线性 Circos 重绘": "7.1 Intraspecies Synteny Circos Replot",
"8️⃣ Karyotype": "8️⃣ Karyotype",
"9️⃣ 种间Synteny": "9️⃣ Interspecies Synteny",
"基因家族": "Gene Family",
"WGS2GWAS(遗传变异与群体分析)": "WGS2GWAS",
"基因家族 promoter 扫描": "Gene family promoter scanning",
"新会话": "New Session",
"新会话已创建,请选择或创建 Working Directory": "New session created. Please select or create a Working Directory",
"创建会话失败": "Failed to create session",
"会话已删除": "Session deleted",
"删除会话失败": "Failed to delete session",
"对话历史已清空": "Chat history cleared",
"错误日志已清空": "Error logs cleared",
"重启 Celery": "Restart Celery",
"重启项目": "Restart Project",
"提交配置好的项目重启脚本": "Submit configured project restart script",
"未配置 PLANTAI_RESTART_SCRIPT 或 restart_plantai_9000.sh": "PLANTAI_RESTART_SCRIPT or restart_plantai_9000.sh not configured",
"未配置项目重启脚本": "Project restart script not configured",
"这会提交项目重启脚本,当前页面可能短暂断开。": "This will submit the project restart script. The page may briefly disconnect.",
"确认重启": "Confirm Restart",
"项目重启脚本已提交": "Project restart script submitted",
"项目重启未提交": "Project restart not submitted",
"基因家族鉴定": "Gene Family Identification",
"系统发育分析": "Phylogenetic Analysis",
"Motif分析": "Motif Analysis",
"结构域分析": "Domain Analysis",
"基因结构分析": "Gene Structure Analysis",
"启动子元件预测": "Promoter Element Prediction",
"TF结合位点预测": "TF Binding Site Prediction",
"种内共线性分析": "Intraspecies Synteny Analysis",
"种间共线性分析": "Interspecies Synteny Analysis",
"核型/染色体分布分析": "Karyotype/Chromosome Distribution",
"PPI分析": "PPI Analysis",
"Ka/Ks分析": "Ka/Ks Analysis",
"蛋白理化性质与亚细胞定位": "Protein Properties & Subcellular Localization",
"表达矩阵分析": "Expression Matrix Analysis",
"RNA-seq QC": "RNA-seq QC",
"RNA-seq Align": "RNA-seq Align",
"RNA-seq Quant": "RNA-seq Quant",
"RNA-seq Sample QC": "RNA-seq Sample QC",
"GWAS VCF排序与HapMap转换": "GWAS VCF Sort & HapMap Conversion",
"GWAS TASSEL亲缘关系矩阵": "GWAS TASSEL Kinship Matrix",
"GWAS表型准备": "GWAS Phenotype Preparation",
"GWAS协变量准备": "GWAS Covariate Preparation",
"GWAS TASSEL MLM/CMLM": "GWAS TASSEL MLM/CMLM",
"GWAS MLM/CMLM绘图": "GWAS MLM/CMLM Plotting",
"GWAS EMMAX": "GWAS EMMAX",
"GWAS EMMAX绘图": "GWAS EMMAX Plotting",
"GWAS TASSEL GLM": "GWAS TASSEL GLM",
"群体PCA分析": "Population PCA Analysis",
"群体系统树分析": "Population Phylogenetic Tree",
"群体结构分析": "Population Structure Analysis",
"群体LD衰减分析": "Population LD Decay Analysis",
"SNP密度分析": "SNP Density Analysis",
"RNA-seq DE": "RNA-seq DE",
"组合图": "Combo Plot",
"参考亚家族分类": "Reference Subfamily Classification",
"亚家族标签确认": "Subfamily Label Confirmation",
"PPI/KaKs 参考数据": "PPI/KaKs Reference Data",
"PPI/KaKs 兜底确认": "PPI/KaKs Fallback Confirmation",
"亚家族确认输出": "Subfamily Confirmation Output",
"MSA区间重绘": "MSA Region Replot",
"MSA区间重绘已提交": "MSA Replot submitted",
"MSA区间重绘完成": "MSA Replot completed",
"MSA区间重绘失败": "MSA Replot failed",
"启动子自定义绘图已提交": "Promoter custom plot submitted",
"启动子自定义绘图完成": "Promoter custom plot completed",
"启动子自定义绘图失败": "Promoter custom plot failed",
"种内共线性 Circos 重绘已提交": "Intraspecies Circos replot submitted",
"种内共线性 Circos 重绘完成,已切换到新图": "Intraspecies Circos replot completed, switched to new figure",
"种内共线性 Circos 重绘失败": "Intraspecies Circos replot failed",
"亚家族确认 - Reference Classification": "Subfamily Confirmation - Reference Classification",
"这会停止当前 profile 的 Celery worker 并重新启动。若有任务正在运行,后端会默认拒绝执行。": "This will stop and restart the Celery worker for the current profile. Running tasks will be rejected by default.",
"Celery 已重启并完成队列检查": "Celery restarted and queue check complete",
"Celery 重启未完成": "Celery restart incomplete",
// ---- Card status_label (8) ----
"失败": "Failed",
"运行中": "Running",
"待确认": "Pending",
"待执行": "Pending",
"待核对": "Review",
"待授权": "Authorize",
"已取消": "Cancelled",
// ---- Card title (10) ----
"拓展分析候选核对": "Extension Candidate Review",
"拓展分析说明生成失败": "Description Generation Failed",
"正在生成拓展分析": "Generating Extension",
"运行结果核对": "Result Review",
"输入文件和参数": "Input Files & Parameters",
"正在恢复拓展分析状态": "Restoring Extension State",
// ---- Card purpose/summary (15) ----
"原始命令、测试数据和执行事实已经保留;这里只重新生成说明,不会重新运行原始命令。": "Raw command, test data and execution facts are preserved; only regenerate description without re-running.",
"可以直接重试,或取消后检查错误原因。": "Retry or cancel and check error cause.",
"这张卡用于核对系统从真实执行中锁定的命令、输入、参数和输出。": "Review system-locked command, inputs, parameters and outputs from real execution.",
"系统正在确定执行入口,并运行上传的代码和测试数据,提取不可修改的执行事实。": "Determining entry point, running uploaded code/test data, extracting immutable execution facts.",
"原始包可复现检查中…": "Checking reproducibility of original package…",
"这张卡用于用同一份测试数据执行已确认的工具,并生成可核对的结果。": "Run confirmed tool with same test data; generate verifiable results.",
"确认无误后点击“开始验证”。": "Click \"Start Validation\" after confirming.",
"这张卡用于查看实际命令、输出与日志;核对无误后才允许授权发布。": "View actual command, output and logs; publication requires review confirmation.",
"这张卡用于确认将已经验证的工具发布为可复用的拓展分析。": "Confirm publishing validated tool as reusable extension.",
"确认后才会发布;不会自动发布。": "Publication requires explicit confirmation; not automatic.",
"这张卡用于确认本次新数据运行的输入文件和原始命令已有参数;确认后立即执行,不会再次弹出确认。": "Confirm input files and parameters for this run; executes immediately without re-confirmation.",
"这张卡展示本次新数据运行生成的文件、标准输出和日志。": "Files, stdout and logs generated by this run.",
"页面已恢复;系统继续轮询同一个操作,不会重复提交。": "Page restored; continuing to poll the same operation without re-submitting.",
"请在页面下方的主对话输入框说明需要修订的内容,然后发送。命令和真实执行事实不会被修改。": "Describe revisions in the main chat input below. Commands and execution facts are immutable.",
"已取消;没有提交后续执行。": "Cancelled; no further execution submitted.",
// ---- Card rows labels (13) ----
"实际命令": "Actual Command",
"输出文件": "Output Files",
"标准输出": "Standard Output",
"见执行日志": "See execution log",
"功能": "Function",
"输入文件": "Input Files",
"可改参数": "Configurable Parameters",
"标准输出(直接展示)": "Stdout (direct display)",
"(无文件输出)": "(No file output)",
"(无)": "(None)",
// ---- Card error/misc (25+) ----
"操作失败": "Operation failed",
"读取拓展分析说明失败": "Failed to read extension help",
"读取拓展分析状态失败": "Failed to read extension status",
"阶段:": "Phase: ",
"原因:": "Cause: ",
"无法读取操作状态": "Cannot read operation status",
"提交失败": "Submission failed",
"原始包可复现检查提交失败": "Reproducibility check submission failed",
"阶段:upload": "Phase: Upload",
"已恢复修订;请核对最新候选。": "Revision restored; please review latest candidate.",
"✓ 语义说明已重新生成;执行命令未重新运行。": "✓ Description regenerated; command not re-run.",
"✓ 执行入口已成功复现;候选信息已生成。": "✓ Entry point reproduced successfully; candidate info generated.",
"✓ 验证已完成;结果核对卡已生成。": "✓ Validation complete; result review card generated.",
"✓ 已核对运行结果。": "✓ Results reviewed.",
"✓ 已显式授权并发布。": "✓ Explicitly authorized and published.",
"✓ 已确认输入与参数;本次运行已完成。": "✓ Inputs and parameters confirmed; run completed.",
"✓ 已恢复并完成;候选核对卡已生成。": "✓ Restored and completed; candidate review card generated.",
"✓ 已恢复确认;可以开始验证。": "✓ Confirmation restored; ready to validate.",
"✓ 已恢复验证;结果核对卡已生成。": "✓ Validation restored; result review card generated.",
"✓ 已恢复结果核对;可以授权发布。": "✓ Review restored; ready to publish.",
"✓ 已恢复并发布。": "✓ Restored and published.",
"✓ 已恢复运行;本次结果卡已生成。": "✓ Run restored; result card generated.",
"✓ 已确认候选|未作修订": "✓ Candidate confirmed | no revision",
"✓ 已确认候选|已修订:": "✓ Candidate confirmed | revised: ",
"文件上传成功,已开始生成并验收": "Upload successful; generation and validation started",
"请填写名称并提供测试数据文件或服务器路径;原始命令和原始代码至少提供一项。": "Please provide name and test data files or server path; at least command or code is required.",
"请写明修订意见。": "Please specify revision feedback.",
"读取验证结果失败": "Failed to read validation results",
"读取运行说明失败": "Failed to read run help",
"请先选择实际运行 Job。": "Please select a job first.",
"请填写每个输入文件。": "Please fill in each input file.",
"已修订:": "Revised: ",
"正在恢复 ": "Restoring ",
"…": "…",
" 提交失败": " submission failed",
" 原始包可复现检查提交失败": " Reproducibility check submission failed",
"执行入口已在隔离环境运行。请核对系统记录的事实与说明;确认后才会验证。": "Entry point ran in isolated environment. Review system-recorded facts and descriptions; validation proceeds after confirmation.",
// ---- Agent message: status/confirm/cancel (10) ----
"config.xlsx 已确认,继续当前目标:": "config.xlsx confirmed; continuing current goal: ",
"✅ 已确认使用拟南芥作为 PPI/KaKs 的显式兜底参考;该选择只写入 Ortholog/PPI/KaKs 专用参数,其它常规阶段不受影响。": "✅ Arabidopsis confirmed as PPI/KaKs explicit fallback reference; affects only Ortholog/PPI/KaKs parameters.",
"✅ 已确认自动注释,正在重新提交": "✅ Auto-annotation confirmed; re-submitting",
"✅ 已选择项目参考物种": "✅ Project reference species selected",
"已停止等待,本次未继续获取回答。": "Stopped waiting; no further response.",
"抱歉,我没有理解你的意思。请尝试更详细地描述。": "Sorry, I didn't understand. Please try describing in more detail.",
"抱歉,服务暂时不可用,请稍后重试。": "Sorry, service temporarily unavailable. Please try again later.",
// ---- Agent message: pause/block/skip (13) ----
"⏸️ PPI/KaKs 前置数据检查未通过,已暂停批量执行;请补齐参考注释包或确认参考物种后重新执行。": "⏸️ PPI/KaKs prerequisite check failed; batch paused. Add reference annotation or confirm reference species.",
"⏸️ identify 已完成,但方法学链路需要先确认基因家族成员表;保存成员确认后再继续 phylogeny。": "⏸️ identify completed; methodology chain requires confirmed gene family members before continuing phylogeny.",
"⏸️ 已打开 identify 成员初筛确认表;保存后会生成 curated_members,再继续亚家族证据阶段。": "⏸️ identify member confirmation table opened; save to generate curated_members, then continue subfamily evidence stages.",
"⏸️ 当前已有前台批次执行中;WGS 规划已保留,请在当前批次结束后重新执行。": "⏸️ Foreground batch in progress; WGS plan saved. Re-run after current batch finishes.",
",其它阶段继续执行。": ", other stages continue.",
"⏸️ 已按选择先暂停 Ortholog/PPI/KaKs,其它阶段继续执行。": "⏸️ Paused Ortholog/PPI/KaKs as selected; other stages continue.",
"⏹️ 后端预检失败,当前批次已停止;请重新拉取规划后继续。": "⏹️ Backend pre-check failed; batch stopped. Re-pull plan to continue.",
// ---- Agent message: replan/continue (5) ----
"🔁 亚家族标签已确认,正在重新规划确认后常规基因家族分析...": "🔁 Subfamily labels confirmed; re-planning post-confirmation gene family analysis...",
"确认后常规分析没有新的可执行阶段。": "No new executable stages after confirmation.",
// ---- Agent message: submit/execute (7) ----
"⚙️ 提交阶段: ": "⚙️ Submitting stage: ",
"按 per_species 拆分 ": "Split by per_species ",
// ---- Agent message: complete/success (7) ----
"✅ PPI/KaKs 前置数据检查通过:当前批次已有 Ortholog,将先生成同源映射再继续下游分析。": "✅ PPI/KaKs check passed: Ortholog exists in current batch; generating mapping first.",
// ---- Agent message: download/background (5) ----
"⬇️ 正在提交推荐近源参考物种注释包后台下载;Ortholog/PPI/KaKs 将等待参考数据,其它阶段继续执行。": "⬇️ Submitting reference annotation download; Ortholog/PPI/KaKs wait for data, other stages continue.",
// ---- Agent message: autofill (2) ----
"已根据上传文件生成 samples.yaml 草稿。请在弹窗中核对 run、sample_id、condition、replicate、链特异性和分组角色,确认后再写入正式 samples.yaml。": "samples.yaml draft generated. Review run, sample_id, condition, replicate, strand specificity and group roles in the dialog, then confirm to write.",
"已根据上传文件生成 config.xlsx 草稿。请在弹窗中核对物种代码、文件类型、物种角色和 Gene_Family,确认后再写入正式 config.xlsx。": "config.xlsx draft generated. Review species code, file type, species role and Gene_Family in the dialog, then confirm to write.",
// ---- Agent message: methodology (4) ----
"已保存方法学方案到当前 job。下一步请上传/填写目标物种和参考物种数据,并确认 config.xlsx 后再执行方法学流程。": "Methodology plan saved. Next: upload target/reference species data, confirm config.xlsx, then execute.",
"❌ 方法学执行规划失败:": "❌ Methodology execution planning failed: ",
// ---- Agent message: replot/revision (4 to fix) ----
"进化树图重绘已提交:": "Phylogeny tree redraw submitted: ",
"进化树图重绘失败:": "Phylogeny tree redraw failed: ",
"Combo 图修订已提交:": "Combo plot revision submitted: ",
"Combo 图修订失败:": "Combo plot revision failed: ",
// ---- Agent message: failure/interrupt (10) ----
"无法执行分析:": "Cannot execute analysis: ",
"服务暂时不可用:": "Service temporarily unavailable: ",
"⚠️ 批量执行完成:成功 ": "⚠️ Batch complete: success ",
"⚠️ 以下阶段因依赖失败被跳过: ": "⚠️ Stages skipped due to dependency failure: ",
"⚠️ 以下阶段等待上游暂停项处理后继续: ": "⚠️ Stages waiting for upstream paused items: ",
"未生成可执行阶段。未检测到当前 scope 的完成结果时,不再把空计划解释为已完成;请检查阶段名称或前置依赖。": "No executable stages generated. Empty plan is not interpreted as completed. Check stage names or dependencies.",
// ---- Agent message: extension analysis (6) ----
"拓展分析阶段:": "Extension stage: ",
"拓展分析阶段失败:": "Extension stage failed: ",
"已执行拓展分析阶段:": "Extension stage executed: ",
"拓展分析阶段执行失败:": "Extension stage execution failed: ",
"拓展分析帮助暂时不可用:": "Extension help temporarily unavailable: ",
"上传可执行代码、测试数据和原始命令,核对候选后验证并授权发布;发布后可指定输入和原命令已有参数运行。": "Upload executable code, test data and original command; review candidate, validate, then authorize publishing.",
// ---- Agent message: other (5) ----
"📌 当前已有前台批次执行中,新任务已转为后台执行:": "📌 Foreground batch running; new task moved to background: ",
"已识别到 RNA-seq/FASTQ 和参考资源": "RNA-seq/FASTQ and reference resources detected",
"已把目录中的可识别参考资源导入当前 job": "Reference resources imported into current job",
"我识别到你是在提供数据路径,但该路径下没有发现": "Data path detected but no usable files found",
"已选择:": "Selected: ",
// ---- Agent message: remaining dynamic patterns ----
"❌ 批量执行已取消": "❌ Batch execution cancelled",
"⏭️ 跳过阶段: ": "⏭️ Skipped stage: ",
"🚀 准备提交依赖驱动执行,共 ": "🚀 Preparing dependency-driven execution: ",
"🎉 批量执行完成!成功: ": "🎉 Batch complete! Success: ",
",失败 ": ", failed ",
"跳过阶段: ": "Skipped stage: ",
" 暂停:需要先准备参考物种 PEP/CDS 或 Ortholog 映射。": " paused: prepare reference species PEP/CDS or Ortholog mapping first.",
" 已暂停依赖 confirmed_subfamily.tsv 的后续阶段;请在亚家族确认表中保存后重新拉取规划继续执行。": " paused subsequent stages depending on confirmed_subfamily.tsv; save the subfamily confirmation table and re-pull the plan.",
"参考数据已就绪": "Reference data ready",
" 已恢复为待执行,将随当前批次继续调度。": " restored as pending; will continue with current batch.",
" 开始续跑 Ortholog/PPI/KaKs。": " resuming Ortholog/PPI/KaKs.",
" 重新提交(自动注释背景)": " re-submit (auto-annotation background)",
" 已提交后端,task_id=": " submitted to backend, task_id=",
" 准备执行 ": " preparing to execute ",
" 个阶段,请确认参数": " stages; please confirm parameters",
" 个阶段...": " stages...",
" 个分析阶段,请确认参数": " analysis stages; please confirm parameters",
"亚家族确认后已规划 ": "Post-subfamily-confirmation plan: ",
" 个常规分析阶段": " regular analysis stages",
"PPI/KaKs 前置数据检查通过:检测到已下载近源参考 ": "PPI/KaKs check passed: downloaded reference ",
",将用该参考先生成 Ortholog mapping。": ", generating Ortholog mapping first.",
"PPI/KaKs 前置数据检查通过:检测到已有 Ortholog 映射(": "PPI/KaKs check passed: Ortholog mapping exists (",
"),将复用该映射执行 ": "), reusing mapping for ",
"),将直接执行 ": "), executing directly ",
"),已自动插入 Ortholog,将先生成 mapping 再执行 ": "), Ortholog auto-inserted; generating mapping then executing ",
",已自动插入 Ortholog": ", Ortholog auto-inserted",
"推荐参考数据下载完成:": "Reference download complete: ",
")。已写入 Ortholog/PPI/Ka/Ks 专用参考物种。": "). Written to Ortholog/PPI/Ka/Ks specific reference species.",
" 已按用户确认使用 bcftools 完成": " completed with bcftools as confirmed by user",
" 前端连接短暂中断,正在按后端产物状态恢复": " frontend connection interrupted; recovering from backend state",
"亚家族确认已完成,但后端当前 workflowPhase 为 ": "Subfamily confirmation completed; backend workflowPhase is ",
",未自动打开常规分析。": "; no auto-analysis opened.",
"亚家族分类已完成预测,但确认表尚未保存;": "Subfamily classification predicted; confirmation table not yet saved; ",
"已调出": "Opened ",
"亚家族分类确认表。你可以在弹窗中修订 confirmed_subfamily,点击\"确认亚家族标签\"后保存。": " subfamily classification confirmation table. Revise confirmed_subfamily in the dialog, then click \"Confirm Subfamily Labels\" to save.",
"亚家族分类确认表没有打开:未找到可确认的分类结果。请先确认该物种已完成 reference_classification。": " subfamily classification confirmation table not opened: no confirmable results found. Confirm the species has completed reference_classification.",
"确认后常规分析没有新的可执行阶段。": "No new executable stages after confirmation.",
"⚠️ 检测到 ": "⚠️ Detected ",
",将在确认后启动本地自动注释。": "; auto-annotation will start after confirmation.",
"🧬 自动背景注释与 ": "🧬 Auto-background annotation and ",
" 已提交后端,task_id=": " submitted to backend, task_id=",
"⚠️ 亚家族确认后自动续跑规划失败:": "⚠️ Post-subfamily-confirm auto-plan failed: ",
"; Ortholog/PPI/KaKs ": "; Ortholog/PPI/KaKs ",
"推荐参考数据下载已转入后台:": "Reference download moved to background: ",
",task_id=": ", task_id=",
"后台批次完成:成功 ": "Background batch complete: success ",
"后台执行阶段: ": "Background stage: ",
"后台阶段 ": "Background stage ",
" 完成": " done",
"已保存方法学方案,但暂不执行:": "Methodology plan saved, not executing: ",
"。请在 config.xlsx 自动识别弹窗中核对/补齐数据,确认写入正式配置后再点击\"确认并执行\"。": ". Review/fill data in the config.xlsx auto-detect dialog, confirm to write then click \"Confirm & Execute\".",
"当前已有前台批次执行中;WGS 规划已保留,请在当前批次结束后重新执行。": "Foreground batch in progress; WGS plan saved. Re-run after current batch finishes.",
"拓展分析阶段执行失败:": "Extension stage execution failed: ",
"已把路径中的 ": "Soft-linked ",
" 个可识别文件软链接到当前 job": " recognizable files to current job",
" 个可识别文件软链接到当前 job,但没有发现需要自动填写 config.xlsx 或 samples.yaml 的文件类型;请检查目录或继续补充文件。": " recognizable files linked to current job; no files found for config.xlsx/samples.yaml auto-fill. Check directory or add more files.",
"前": " ago",
"秒前": "sec ago",
"分钟前": "min ago",
"小时前": "hr ago",
"天前": "d ago",
"待机": "Idle",
"分析中": "Analyzing",
"检索中": "Retrieving",
"反思中": "Reflecting",
"生成中": "Generating",
"完成": "Complete",
"错误": "Error",
"处理中...": "Processing...",
"发送": "Send",
"任务列表": "Tasks",
" 个常规分析阶段,请确认参数": " regular analysis stages; please confirm parameters",
" 亚家族分类已完成预测,但确认表尚未保存;后续会继续显示为待确认。": " subfamily classification predicted; confirmation table not yet saved; will show as pending.",
" 到后端;系统会先生成 ": " to backend; system will generate ",
" 前端连接短暂中断,正在按后端产物状态恢复,不会立即判定阶段失败": " frontend connection interrupted; recovering from backend artifact state. Stage will not be marked as failed.",
" 已有同一分析范围的有效结果,无需重复执行。": " already has valid results for the same analysis scope. No need to re-execute.",
" 的依赖尚未完成": " dependency not yet completed",
" 重新提交(自动注释背景)...": " re-submitting (auto-annotation background)...",
" 提交失败": " submission failed",
" 原始包可复现检查提交失败": " reproducibility check submission failed",
"Combo 图修订已提交:task_id=": "Combo plot revision submitted: task_id=",
"⏳ 推荐参考数据下载已转入后台:": "⏳ Reference download moved to background: ",
"⏸️ 以下阶段等待上游暂停项处理后继续: ": "⏸️ Stages waiting for upstream paused items: ",
"⚙️ 亚家族确认后已规划 ": "⚙️ Post-subfamily-confirm plan: ",
"⚙️ 准备执行 ": "⚙️ Preparing to execute ",
"⚙️ 后台执行阶段: ": "⚙️ Background stage: ",
"⚠️ 后台批次中以下阶段因依赖失败被跳过: ": "⚠️ Background batch stages skipped due to dependency failure: ",
"✅ PPI/KaKs 前置数据检查通过:检测到已下载近源参考 ": "✅ PPI/KaKs check passed: downloaded reference ",
"✅ PPI/KaKs 前置数据检查通过:检测到已有 Ortholog 映射(": "✅ PPI/KaKs check passed: Ortholog mapping found (",
"✅ 后台阶段 ": "✅ Background stage ",
"✅ 已确认自动注释,正在重新提交 ": "✅ Auto-annotation confirmed; re-submitting ",
"✅ 已选择项目参考物种 ": "✅ Selected project reference species: ",
"✅ 推荐参考数据下载完成:": "✅ Reference download complete: ",
"✅ 阶段 ": "✅ Stage ",
"☒ 已恢复并完成。": "☒ Restored and completed.",
"❌ 无法执行分析:": "❌ Cannot execute analysis: ",
"❌ 服务暂时不可用:": "❌ Service temporarily unavailable: ",
"。结果已写入当前 job workspace,输出:": ". Results written to current job workspace, output: ",
"。请在 config.xlsx 自动识别弹窗中核对/补齐数据,确认写入正式配置后再点击“确认并执行”。": ". Review/fill data in the config.xlsx auto-detect dialog; confirm to write then click \"Confirm & Execute\".",
"亚家族分类确认表。你可以在弹窗中修订 confirmed_subfamily,点击“确认亚家族标签”后保存。": "subfamily classification confirmation table. Revise confirmed_subfamily in the dialog, then click \"Confirm Subfamily Labels\" to save.",
"亚家族标签确认被跳过,已停止依赖 confirmed_subfamily.tsv 的后续阶段;如需普通无亚家族标签分析,请重新发起并明确说明\"不需要亚家族\"。": "Subfamily label confirmation skipped; subsequent stages depending on confirmed_subfamily.tsv have been stopped. For regular analysis without subfamily labels, please restart and explicitly state \"no subfamily\".",
"发送\"按已保存的方法学方案继续执行\"": "Send \"Continue with saved methodology plan\"",
"后台批次无法继续:": "Background batch cannot continue: ",
"已打开 config.xlsx 自动识别表。你可以直接修订单行,或用批量修订区筛选、预览、Apply。": "Opened config.xlsx auto-identification table. You can edit individual rows, or use the batch revision area to filter, preview, and Apply.",
"已打开 samples.yaml 自动识别表。你可以直接修订样本、分组、重复和对照组。": "Opened samples.yaml auto-identification table. You can revise samples, groups, replicates and controls directly.",
"已把目录中的可识别参考资源导入当前 job,并生成 config.xlsx 草稿。请在弹窗中核对和修订,点击“确认并写入正式配置”后再执行正式分析。": "Imported recognizable reference resources into current job and generated config.xlsx draft. Please review and revise in the dialog, then click \"Confirm & Write to Official Config\" before executing.",
"已识别到 RNA-seq FASTQ 和参考资源,优先打开 samples.yaml 草稿供你核对样本、分组和对照;config.xlsx 草稿也已生成。": "RNA-seq FASTQ and reference resources detected; opening samples.yaml draft for sample/group/control review. config.xlsx draft also generated.",
"已识别到 RNA-seq/FASTQ 数据并生成 samples.yaml 草稿。请在弹窗中核对 run、sample_id、condition、replicate、control_group 后再写入正式 samples.yaml。": "RNA-seq/FASTQ data detected and samples.yaml draft generated. Review run, sample_id, condition, replicate, control_group in the dialog, then confirm to write.",
"已重新识别并生成 config.xlsx 草稿。请在弹窗中核对并修订,确认后才会写入正式 config.xlsx。": "Re-identified and generated config.xlsx draft. Review and revise in the dialog; writes to official config.xlsx only after confirmation.",
"已重新识别并生成 samples.yaml 草稿。请确认 run、sample_id、condition、replicate 和 control_group 后再写入正式 samples.yaml。": "Re-identified and generated samples.yaml draft. Confirm run, sample_id, condition, replicate, and control_group before writing to official samples.yaml.",
"没有找到可展示的结果。": "No displayable results found.",
"点击\"浏览\"上传文献": "Click \"Browse\" to upload paper",
"点击\"知识图谱\"查看关系": "Click \"Knowledge Graph\" to view relations",
"请先核对 config.xlsx 草稿。": "Please review the config.xlsx draft first.",
"请补充你的需求。": "Please clarify your requirements.",
"进化树图重绘已提交:task_id=": "Phylogeny tree redraw submitted: task_id=",
"选择输入框上方\"Analysis\"": "Select \"Analysis\" above the input box",
"选择输入框上方\"RAG\"": "Select \"RAG\" above the input box",
",再继续富集分析。": ", then continue enrichment analysis.",
",将用该参考先生成 Ortholog mapping。": ", will generate Ortholog mapping from this reference first.",
";Ortholog/PPI/KaKs 已恢复为待执行,将随当前批次继续调度。": "; Ortholog/PPI/KaKs restored as pending; will continue with current batch.",
",将按该参考检查或生成 Ortholog,并执行 ": "; will check or generate Ortholog from this reference, and execute ",
";开始续跑 Ortholog/PPI/KaKs。": "; resuming Ortholog/PPI/KaKs.",
"),将复用该映射执行 ": "), will reuse this mapping and execute ",
"),将直接执行 ": "), will execute directly ",
",已自动插入 Ortholog,将先生成 mapping 再执行 ": ", Ortholog auto-inserted; generating mapping first then executing ",
")。已写入 Ortholog/PPI/Ka/Ks 专用参考物种。": "). Written to Ortholog/PPI/Ka/Ks specific reference species.",
" 已按用户确认使用 bcftools 完成": " completed with bcftools as user confirmed",
" 已暂停依赖 confirmed_subfamily.tsv 的后续阶段;请在亚家族确认表中保存后重新拉取规划继续执行。": " has paused subsequent stages depending on confirmed_subfamily.tsv; save the subfamily confirmation table and re-pull the plan.",
" 暂停:需要先准备参考物种 PEP/CDS 或 Ortholog 映射。": "paused: prepare reference species PEP/CDS or Ortholog mapping first.",
" 个分析阶段,请确认参数": " analysis stages, please confirm parameters",
"📦 后台批次完成:成功 ": "📦 Background batch complete: success ",
"🔄 阶段 ": "🔄 Stage ",
"🚀 阶段 ": "🚀 Stage ",
"config.xlsx 已确认,继续当前目标:": "config.xlsx confirmed; continuing current goal: ",
"按 per_species 拆分 ": "Split by per_species ",
"⚠️ 检测到 ": "⚠️ Detected ",
",将在确认后启动本地自动注释。": "; auto-annotation will start after confirmation.",
"。已写入 Ortholog/PPI/Ka/Ks 专用参考物种。": ". Written to Ortholog/PPI/Ka/Ks specific reference species.",
"🚀 准备提交依赖驱动执行,共 ": "🚀 Preparing dependency-driven execution: ",
" 个阶段...": " stages...",
"⚠️ 批量执行完成:成功 ": "⚠️ Batch complete: success ",
",失败 ": ", failed ",
"🎉 批量执行完成!成功: ": "🎉 Batch complete! Success: ",
"⏭️ 跳过阶段: ": "⏭️ Skipped stage: ",
"⚙️ 提交阶段: ": "⚙️ Submitting stage: ",
"⏭️ ": "⏭️ ",
" 已提交后端,task_id=": " submitted to backend, task_id=",
" 完成": " complete",
",task_id=": ", task_id=",
"⚠️ 亚家族确认后自动续跑规划失败:": "⚠️ Post-subfamily-confirm auto-plan failed: ",
"亚家族确认已完成,但后端当前 workflowPhase 为 ": "Subfamily confirmation complete; backend workflowPhase is ",
",未自动打开常规分析。": "; no auto-analysis opened.",
"已调出": "Opened: ",
"亚家族分类确认表没有打开:未找到可确认的分类结果。请先确认该物种已完成 reference_classification。": "Subfamily classification confirmation table not opened: no confirmable results found. Confirm the species has completed reference_classification.",
"拓展分析帮助暂时不可用:": "Extension help temporarily unavailable: ",
"已保存方法学方案,但暂不执行:": "Methodology plan saved; not executing: ",
"🧬 自动背景注释与 ": "🧬 Auto-background annotation and ",
"参考数据已就绪": "Reference data ready",
"Combo 图修订失败:": "Combo plot revision failed: ",
"进化树图重绘失败:": "Phylogeny tree redraw failed: ",
",其它阶段继续执行。": ", other stages continue.",
" 个阶段,请确认参数": " stages, please confirm parameters",
"—": "—",
"✓ 已恢复并完成。": "✓ Restored and completed.",
"后台批次完成:成功 ": "Background batch complete: success ",
"后台执行阶段: ": "Background stage: ",
"拓展分析阶段执行失败:": "Extension stage execution failed: ",
"拓展分析阶段:": "Extension stage: ",
"已执行拓展分析阶段:": "Extension stage executed: ",
"拓展分析阶段失败:": "Extension stage failed: ",
"MSA区间重绘已提交": "MSA replot submitted",
"MSA区间重绘失败": "MSA replot failed",
"已选择:": "Selected: ",
"📌 当前已有前台批次执行中,新任务已转为后台执行:": "📌 Foreground batch running; new task moved to background: ",
",已自动插入 Ortholog,将先生成 mapping 再执行": ", Ortholog auto-inserted; generating mapping first then executing",
"推荐参考数据下载完成:": "Reference download complete: ",
"ABORTED": "ABORTED",
"的依赖尚未完成": "dependency not yet completed",
"亚家族标签确认被跳过,已停止依赖 confirmed_subfamily.tsv 的后续阶段;如需普通无亚家族标签分析,请重新发起并明确说明": "Subfamily label confirmation skipped; stages depending on confirmed_subfamily.tsv stopped. For regular analysis without subfamily labels, restart and explicitly state: ",
"不需要亚家族": "no subfamily",
"。": ".",
",将复用该映射执行 ": ", will reuse this mapping and execute ",
";将按该参考检查或生成 Ortholog,并执行 ": "; will check or generate Ortholog from this reference, and execute ",
"⚠️ 以下阶段因依赖失败被跳过: ": "⚠️ Stages skipped due to dependency failure: ",
"⚠️ 以下阶段等待上游暂停项处理后继续: ": "⚠️ Stages waiting for upstream paused items: ",
"启动子自定义绘图已提交": "Promoter custom plot submitted",
"启动子自定义绘图失败": "Promoter custom plot failed",
"种内共线性 Circos 重绘已提交": "Intraspecies Circos replot submitted",
"种内共线性 Circos 重绘失败": "Intraspecies Circos replot failed",
" 重新提交(自动注释背景)": " re-submit (auto-annotation background)",
" 已暂停依赖 confirmed_subfamily.tsv": " has paused stages depending on confirmed_subfamily.tsv",
";": ";",
" 个分析阶段": " analysis stages",
" 个阶段": " stages"
};
@@ -0,0 +1,293 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>阶段性综合深度报告 - 弹窗演示</title>
<script src="https://cdn.jsdelivr.net/npm/vue@3.3.4/dist/vue.global.prod.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-plus@2.3.14/dist/index.css">
<script src="https://cdn.jsdelivr.net/npm/element-plus@2.3.14/dist/index.full.js"></script>
<style>
body { margin: 0; padding: 20px; font-family: 'Helvetica Neue', Arial, sans-serif; background: #f5f7fa; }
.demo-container { max-width: 1200px; margin: 0 auto; }
.stage-card { background: white; padding: 15px; margin: 10px 0; border-radius: 8px; box-shadow: 0 2px 12px rgba(0,0,0,0.1); }
.stage-header { display: flex; justify-content: space-between; align-items: center; }
.stage-title { font-size: 16px; font-weight: bold; }
.stage-status { padding: 4px 12px; border-radius: 12px; font-size: 12px; }
.status-completed { background: #67c23a; color: white; }
.status-running { background: #409eff; color: white; }
.status-pending { background: #909399; color: white; }
/* 弹窗样式 */
.interpretation-dialog .el-dialog__body { padding: 0; max-height: 70vh; overflow-y: auto; }
.report-container { padding: 20px; }
.report-header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; margin: -20px -20px 20px -20px; }
.report-title { font-size: 20px; font-weight: bold; margin-bottom: 10px; }
.report-meta { font-size: 14px; opacity: 0.9; }
.flow-visualization { display: flex; align-items: center; justify-content: center; padding: 20px; background: #f8f9fa; border-radius: 8px; margin: 20px 0; }
.flow-stage { text-align: center; padding: 10px 20px; }
.flow-stage-icon { font-size: 24px; margin-bottom: 5px; }
.flow-stage-name { font-size: 14px; font-weight: bold; }
.flow-stage-result { font-size: 12px; color: #666; margin-top: 5px; }
.flow-arrow { font-size: 24px; color: #409eff; margin: 0 10px; }
.section-title { font-size: 18px; font-weight: bold; margin: 30px 0 15px 0; padding-bottom: 10px; border-bottom: 2px solid #409eff; }
.connection-card { background: #f0f9ff; border-left: 4px solid #409eff; padding: 15px; margin: 15px 0; border-radius: 4px; }
.connection-header { font-weight: bold; color: #409eff; margin-bottom: 10px; }
.finding-item { background: white; border: 1px solid #e4e7ed; padding: 15px; margin: 10px 0; border-radius: 8px; }
.finding-title { font-weight: bold; color: #303133; margin-bottom: 8px; }
.finding-desc { color: #606266; font-size: 14px; line-height: 1.6; }
.finding-evidence { color: #909399; font-size: 12px; margin-top: 8px; font-style: italic; }
.story-box { background: #fdf6ec; border: 1px solid #f5dab1; padding: 20px; border-radius: 8px; line-height: 1.8; color: #5d4a2a; }
.next-step-item { display: flex; align-items: flex-start; padding: 12px; background: white; border: 1px solid #e4e7ed; margin: 8px 0; border-radius: 6px; }
.next-step-priority { padding: 2px 8px; border-radius: 4px; font-size: 12px; margin-right: 12px; }
.priority-high { background: #fef0f0; color: #f56c6c; }
.priority-medium { background: #fdf6ec; color: #e6a23c; }
.next-step-content { flex: 1; }
.next-step-title { font-weight: bold; margin-bottom: 4px; }
.next-step-desc { font-size: 13px; color: #606266; }
.dialog-footer { display: flex; justify-content: flex-end; gap: 10px; padding: 15px 20px; border-top: 1px solid #e4e7ed; }
</style>
</head>
<body>
<div id="app">
<div class="demo-container">
<h1>🧬 基因家族分析流程</h1>
<p>点击任意阶段的"深度解读"按钮查看阶段性综合报告弹窗</p>
<!-- 分析流程卡片 -->
<div class="stage-card" v-for="stage in stages" :key="stage.id">
<div class="stage-header">
<div>
<span class="stage-title">{{ stage.name }}</span>
<span :class="['stage-status', 'status-' + stage.status]">
{{ statusText[stage.status] }}
</span>
</div>
<el-button
v-if="stage.status === 'completed' || stage.status === 'running'"
type="primary"
size="small"
@click="showInterpretation(stage)"
:loading="loading"
>
🔍 深度解读
</el-button>
</div>
<div v-if="stage.result" style="margin-top: 10px; color: #666; font-size: 14px;">
结果: {{ stage.result }}
</div>
</div>
</div>
<!-- 阶段性综合解读弹窗 -->
<el-dialog
v-model="dialogVisible"
title=" "
width="80%"
:close-on-click-modal="false"
class="interpretation-dialog"
>
<div class="report-container" v-if="report">
<!-- 报告头部 -->
<div class="report-header">
<div class="report-title">🔬 {{ report.metadata.title }}</div>
<div class="report-meta">
分析流程: {{ report.metadata.included_stages.join(' → ') }} |
生成时间: {{ formatTime(report.metadata.generated_at) }}
</div>
</div>
<!-- 流程可视化 -->
<div class="section-title">📈 阶段性进展</div>
<div class="flow-visualization">
<template v-for="(stage, index) in report.stage_flow.stages" :key="stage.id">
<div class="flow-stage">
<div class="flow-stage-icon">{{ index === report.stage_flow.stages.length - 1 ? '🎯' : '✅' }}</div>
<div class="flow-stage-name">{{ stage.name }}</div>
<div class="flow-stage-result">{{ stage.key_result }}</div>
</div>
<div v-if="index < report.stage_flow.stages.length - 1" class="flow-arrow">→</div>
</template>
</div>
<!-- 阶段关联分析 -->
<div class="section-title" v-if="report.stage_connections.length > 0">🔗 阶段间关联分析</div>
<div v-for="(conn, idx) in report.stage_connections" :key="idx" class="connection-card">
<div class="connection-header">{{ conn.from }} → {{ conn.to }}</div>
<div>{{ conn.description }}</div>
<div style="margin-top: 8px; color: #409eff; font-size: 13px;">
💡 {{ conn.insight }}
</div>
</div>
<!-- 关键发现 -->
<div class="section-title">💡 阶段性科学发现</div>
<div v-for="finding in report.key_findings" :key="finding.id" class="finding-item">
<div class="finding-title">{{ finding.id }}. {{ finding.title }}</div>
<div class="finding-desc">{{ finding.description }}</div>
<div class="finding-evidence">📋 证据: {{ finding.evidence }}</div>
</div>
<!-- 生物学故事 -->
<div class="section-title">🧬 生物学故事</div>
<div class="story-box">
{{ report.biological_story }}
</div>
<!-- 下一步建议 -->
<div class="section-title">📋 下一步建议</div>
<div v-for="(step, idx) in report.next_steps" :key="idx" class="next-step-item">
<div :class="['next-step-priority', 'priority-' + step.priority]">
{{ step.priority === 'high' ? '高优先级' : '中优先级' }}
</div>
<div class="next-step-content">
<div class="next-step-title">{{ step.stage }}: {{ step.description }}</div>
<div class="next-step-desc">{{ step.rationale }}</div>
</div>
</div>
</div>
<!-- 弹窗底部按钮 -->
<div class="dialog-footer">
<el-button @click="downloadReport('markdown')">
📄 Markdown
</el-button>
<el-button @click="downloadReport('json')">
📊 JSON
</el-button>
<el-button type="primary" @click="downloadReport('pdf')">
📥 下载PDF报告
</el-button>
<el-button type="success" @click="copyToClipboard">
📋 复制到剪贴板
</el-button>
<el-button @click="dialogVisible = false">
关闭
</el-button>
</div>
</el-dialog>
</div>
<script>
const { createApp } = Vue;
const { ElMessage } = ElementPlus;
createApp({
data() {
return {
loading: false,
dialogVisible: false,
report: null,
stages: [
{ id: 'identify', name: '基因家族鉴定', status: 'completed', result: '24个基因成员' },
{ id: 'phylogeny', name: '系统发育分析', status: 'completed', result: '3个亚家族' },
{ id: 'motif', name: 'Motif分析', status: 'running', result: '分析中...' },
{ id: 'promoter', name: '启动子分析', status: 'pending', result: null },
{ id: 'expression', name: '表达分析', status: 'pending', result: null }
],
statusText: {
completed: '已完成',
running: '进行中',
pending: '待开始'
}
};
},
methods: {
async showInterpretation(stage) {
this.loading = true;
// 模拟API调用
await new Promise(resolve => setTimeout(resolve, 800));
// 模拟报告数据
this.report = {
metadata: {
title: `阶段性综合深度报告(identify → phylogeny → ${stage.id})`,
included_stages: ['identify', 'phylogeny', stage.id],
stage_count: 3,
generated_at: new Date().toISOString(),
session_id: 'demo_session_001'
},
stage_flow: {
stages: [
{ id: 'identify', name: '基因家族鉴定', status: 'completed', key_result: '24个基因成员' },
{ id: 'phylogeny', name: '系统发育分析', status: 'completed', key_result: '3个亚家族' },
{ id: stage.id, name: stage.name, status: 'running', key_result: stage.result || '进行中' }
]
},
stage_connections: [
{
from: 'identify',
to: 'phylogeny',
description: '鉴定到的24个基因成员构成了进化树的叶节点,系统发育分析揭示了3个明显的亚家族分化,暗示功能分化可能发生在基因复制事件之后。',
insight: '基因数量与亚家族数量的对应关系支持了基因复制-功能分化的经典进化模式。'
},
{
from: 'phylogeny',
to: stage.id,
description: `基于进化树的亚家族分类,我们在${stage.name}中发现了特异的模式,这与亚家族分化高度一致。`,
insight: '亚家族分化不仅体现在序列水平,也在功能和调控层面有明显差异。'
}
],
key_findings: [
{
id: 1,
title: '基因家族规模适中',
description: '24个成员符合典型植物SPL家族规模(通常15-30个),表明苦荞SPL家族经历了适度的扩张,未出现大规模基因复制事件。',
evidence: '基于HMM(E-value<1e-5)和BLAST(identity>70%)双重验证的鉴定结果'
},
{
id: 2,
title: '明显的亚家族分化',
description: '系统发育分析显示3个明显的亚家族分化,与拟南芥(17成员/3亚家族)、水稻(19成员/3亚家族)等物种的SPL家族结构高度一致。',
evidence: '进化树bootstrap值均>70%,最大似然法构建,支持度高'
},
{
id: 3,
title: '阶段性功能分化证据',
description: `从${stage.name}结果看,不同亚家族表现出特异的模式,支持功能分化的假设。`,
evidence: `${stage.name}结果与亚家族分类高度关联`
}
],
biological_story: `从基因家族鉴定到系统发育分析再到${stage.name},我们构建了一个完整的SPL家族特征图谱。苦荞SPL家族包含24个成员,进化分析显示3个明显的亚家族分化,这可能对应着不同的功能特化。进一步的分析揭示了亚家族特异的模式,为功能研究提供了重要线索。这一阶段性进展为深入理解SPL家族在苦荞生长发育中的作用奠定了基础。`,
next_steps: [
{
priority: 'high',
stage: 'expression',
description: '进行表达分析,验证不同亚家族的时空表达模式',
rationale: '基于当前亚家族分化结果,表达模式验证是功能研究的关键下一步,可以揭示亚家族是否在特定组织或发育阶段特异表达。'
},
{
priority: 'medium',
stage: 'promoter',
description: '启动子分析,探索亚家族特异的调控机制',
rationale: '亚家族分化往往伴随调控元件的差异,启动子分析可以揭示不同亚家族的转录调控特征。'
}
]
};
this.dialogVisible = true;
this.loading = false;
},
formatTime(isoString) {
const date = new Date(isoString);
return date.toLocaleString('zh-CN');
},
downloadReport(format) {
ElMessage.success(`开始下载${format.toUpperCase()}格式报告...`);
// 实际实现:调用 /api/agent/report/{session_id}/download?format={format}
},
copyToClipboard() {
const text = this.report.biological_story;
navigator.clipboard.writeText(text).then(() => {
ElMessage.success('已复制到剪贴板');
});
}
}
}).use(ElementPlus).mount('#app');
</script>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

@@ -0,0 +1,93 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test Sidebar</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-plus@2.3.14/dist/index.css">
<script src="https://cdn.jsdelivr.net/npm/vue@3.3.4/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/element-plus@2.3.14/dist/index.full.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@element-plus/icons-vue@2.1.0/dist/index.iife.js"></script>
<link rel="stylesheet" href="conversation-sidebar.css">
<style>
body { margin: 0; font-family: Arial, sans-serif; }
.main-container { display: flex; height: 100vh; }
.content { flex: 1; padding: 20px; }
</style>
</head>
<body>
<div id="app">
<div class="main-container">
<!-- 简化版侧边栏 -->
<div class="conversation-sidebar">
<div class="sidebar-header">
<button class="new-chat-btn" @click="createConversation">
<el-icon><plus /></el-icon>
<span>New Chat</span>
</button>
</div>
<div class="conversation-list">
<div class="list-section">
<div class="section-title">会话列表</div>
<div v-for="conv in conversations" :key="conv.id"
class="conversation-item"
@click="selectConv(conv)">
<div class="item-icon">
<el-icon><chat-dot-round /></el-icon>
</div>
<div class="item-content">
<div class="item-title">{{ conv.title }}</div>
<div class="item-meta">
<span class="message-count">{{ conv.message_count }}条消息</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="content">
<h1>主内容区</h1>
<p>当前会话: {{ currentConv?.title || '未选择' }}</p>
</div>
</div>
</div>
<script>
const { createApp, ref } = Vue;
const app = createApp({
setup() {
const conversations = ref([
{ id: 1, title: 'SPL分析', message_count: 5 },
{ id: 2, title: 'TCP进化', message_count: 3 },
]);
const currentConv = ref(null);
const createConversation = () => {
conversations.value.unshift({
id: Date.now(),
title: '新会话',
message_count: 0
});
};
const selectConv = (conv) => {
currentConv.value = conv;
};
return {
conversations,
currentConv,
createConversation,
selectConv
};
}
});
app.use(ElementPlus);
app.mount('#app');
</script>
</body>
</html>
+73
View File
@@ -0,0 +1,73 @@
import os
import sys
from pathlib import Path
from celery import Celery
from kombu import Exchange, Queue
LOCAL_PROJECT_ROOT = Path(__file__).resolve().parent
if str(LOCAL_PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(LOCAL_PROJECT_ROOT))
from gfa_core.project_paths import PROJECT_ROOT
os.environ.setdefault("PROJECT_ROOT", str(PROJECT_ROOT))
os.environ.setdefault("BBAV5_PROJECT_ROOT", str(PROJECT_ROOT))
QUEUE_PREFIX = os.environ.get("BBAV5_QUEUE_PREFIX", "plantai_dev_9000").strip() or "plantai_dev_9000"
REDIS_URL = os.environ.get("BBAV5_REDIS_URL", "redis://localhost:6379/10")
def q(name: str) -> str:
return f"{QUEUE_PREFIX}.{name}"
TASK_EXCHANGE = Exchange(q("tasks"), type="direct")
def queue(name: str) -> Queue:
queue_name = q(name)
return Queue(queue_name, TASK_EXCHANGE, routing_key=queue_name)
app = Celery(
"plantai_dev_9000",
broker=REDIS_URL,
backend=REDIS_URL,
include=["tasks"],
)
app.conf.update(
task_serializer="json",
accept_content=["json"],
result_serializer="json",
timezone="Asia/Shanghai",
enable_utc=True,
task_track_started=True,
task_default_queue=q("default"),
task_default_exchange=q("tasks"),
task_default_exchange_type="direct",
task_default_routing_key=q("default"),
task_queues=(
queue("default"),
queue("heavy"),
queue("medium"),
queue("light"),
queue("rnaseq"),
),
task_routes={
"tasks.execute_agent_task": {"queue": q("default"), "routing_key": q("default")},
},
task_time_limit=172800,
task_soft_time_limit=169200,
task_annotations={
"tasks.execute_agent_task": {"time_limit": 3600, "soft_time_limit": 3300},
"tasks.execute_single_stage_task": {"time_limit": 172800, "soft_time_limit": 169200},
"tasks.execute_lightweight_extension_operation": {
"time_limit": None,
"soft_time_limit": None,
},
},
worker_prefetch_multiplier=1,
)
if __name__ == "__main__":
app.start()
+154
View File
@@ -0,0 +1,154 @@
#!/usr/bin/env python3
"""
成本追踪查询脚本
"""
import requests
import json
from datetime import datetime
API_BASE = "http://localhost:7865"
def get_cost_summary():
"""获取成本摘要"""
try:
r = requests.get(f"{API_BASE}/cost/summary", timeout=10)
if r.status_code == 200:
return r.json()
else:
print(f"错误: HTTP {r.status_code}")
return None
except Exception as e:
print(f"请求失败: {e}")
return None
def get_cost_report():
"""获取成本报告"""
try:
r = requests.get(f"{API_BASE}/cost/report", timeout=10)
if r.status_code == 200:
return r.json().get("report", "")
else:
print(f"错误: HTTP {r.status_code}")
return None
except Exception as e:
print(f"请求失败: {e}")
return None
def get_agent_cost(agent_name):
"""获取特定Agent成本"""
try:
r = requests.get(f"{API_BASE}/cost/agents/{agent_name}", timeout=10)
if r.status_code == 200:
return r.json()
else:
print(f"错误: HTTP {r.status_code}")
return None
except Exception as e:
print(f"请求失败: {e}")
return None
def get_suggestions():
"""获取优化建议"""
try:
r = requests.get(f"{API_BASE}/cost/suggestions", timeout=10)
if r.status_code == 200:
return r.json().get("suggestions", [])
else:
print(f"错误: HTTP {r.status_code}")
return []
except Exception as e:
print(f"请求失败: {e}")
return []
def print_summary():
"""打印成本摘要"""
print("=" * 60)
print("BBAV20311 成本追踪摘要")
print("=" * 60)
print(f"查询时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print()
summary = get_cost_summary()
if not summary:
print("暂无成本数据")
return
print("【总体统计】")
print(f" 总调用次数: {summary.get('total_calls', 0)}")
print(f" 总Token数: {summary.get('total_tokens', 0):,}")
print(f" 总成本: ${summary.get('total_cost', 0):.6f}")
print(f" 平均每次成本: ${summary.get('avg_cost_per_call', 0):.6f}")
print(f" 平均每次Token: {summary.get('avg_tokens_per_call', 0):,}")
print()
agents = summary.get('agents', {})
if agents:
print("【Agent统计】")
for name, stats in sorted(agents.items(), key=lambda x: x[1]['cost'], reverse=True):
print(f" {name}:")
print(f" 调用: {stats['calls']}")
print(f" Token: {stats['tokens']:,}")
print(f" 成本: ${stats['cost']:.6f}")
print(f" 平均: ${stats['avg_cost']:.6f}/call")
print()
suggestions = get_suggestions()
if suggestions:
print("【优化建议】")
for s in suggestions:
print(f" • {s}")
print()
print("=" * 60)
def print_report():
"""打印完整报告"""
report = get_cost_report()
if report:
print(report)
else:
print("无法获取报告")
def main():
import sys
if len(sys.argv) > 1:
command = sys.argv[1]
if command == "summary":
print_summary()
elif command == "report":
print_report()
elif command == "agent" and len(sys.argv) > 2:
agent_name = sys.argv[2]
data = get_agent_cost(agent_name)
if data:
print(json.dumps(data, indent=2, ensure_ascii=False))
else:
print(f"Agent '{agent_name}' 未找到")
elif command == "suggestions":
suggestions = get_suggestions()
print("优化建议:")
for s in suggestions:
print(f" • {s}")
else:
print("用法:")
print(" python check_cost.py summary # 显示摘要")
print(" python check_cost.py report # 显示完整报告")
print(" python check_cost.py agent <name> # 显示Agent成本")
print(" python check_cost.py suggestions # 显示优化建议")
else:
# 默认显示摘要
print_summary()
if __name__ == "__main__":
main()
+134
View File
@@ -0,0 +1,134 @@
#!/bin/bash
# Agent版本清理脚本
# 将v2版本替换为正式版本,删除旧版本
set -e
echo "=============================================="
echo "BBAV20311 Agent版本清理"
echo "=============================================="
echo ""
AGENTS_DIR="/home/xia-lab/wutx/00test/bbav20311/gfa_core/mas/agents"
BACKUP_DIR="/home/xia-lab/wutx/00test/bbav20311/gfa_core/mas/agents/backup"
echo "1. 创建备份目录"
mkdir -p "$BACKUP_DIR"
echo " 备份目录: $BACKUP_DIR"
echo ""
echo "2. 备份旧版本文件"
for agent in diagnosis planning execution knowledge learning result_parser validator; do
if [ -f "$AGENTS_DIR/${agent}.py" ]; then
cp "$AGENTS_DIR/${agent}.py" "$BACKUP_DIR/${agent}_v1.py.bak"
echo " ✓ 备份 ${agent}.py -> backup/${agent}_v1.py.bak"
fi
done
echo ""
echo "3. 将v2版本替换为正式版本"
for agent in diagnosis planning execution; do
if [ -f "$AGENTS_DIR/${agent}_v2.py" ]; then
# 备份v2版本
cp "$AGENTS_DIR/${agent}_v2.py" "$BACKUP_DIR/${agent}_v2.py.bak"
# 替换:v2 -> 正式版本
cp "$AGENTS_DIR/${agent}_v2.py" "$AGENTS_DIR/${agent}.py"
# 修改类名:AgentV2 -> Agent
sed -i "s/class ${agent^}AgentV2/class ${agent^}Agent/g" "$AGENTS_DIR/${agent}.py"
sed -i "s/name = \"${agent}_v2\"/name = \"${agent}\"/g" "$AGENTS_DIR/${agent}.py"
echo " ✓ ${agent}_v2.py -> ${agent}.py (类名更新)"
fi
done
echo ""
echo "4. 检查其他Agent的v2版本"
for agent in knowledge learning result_parser validator; do
if [ -f "$AGENTS_DIR/${agent}_v2.py" ]; then
v1_lines=$(wc -l < "$AGENTS_DIR/${agent}.py" 2>/dev/null || echo 0)
v2_lines=$(wc -l < "$AGENTS_DIR/${agent}_v2.py" 2>/dev/null || echo 0)
if [ "$v2_lines" -gt "$v1_lines" ]; then
# v2版本更完整,替换
cp "$AGENTS_DIR/${agent}_v2.py" "$BACKUP_DIR/${agent}_v2.py.bak"
cp "$AGENTS_DIR/${agent}_v2.py" "$AGENTS_DIR/${agent}.py"
sed -i "s/name = \"${agent}_v2\"/name = \"${agent}\"/g" "$AGENTS_DIR/${agent}.py"
echo " ✓ ${agent}_v2.py -> ${agent}.py (v2更完整,$v1_lines -> $v2_lines行)"
else
echo " - ${agent}.py 保持v1版本 ($v1_lines行 > $v2_lines行)"
fi
fi
done
echo ""
echo "5. 更新__init__.py导入"
cat > "$AGENTS_DIR/__init__.py" << 'EOF'
from .base import BaseAgent, AgentState, AgentMessage, QueryMode
from .router import RouterAgent
from .planning import PlanningAgent
from .execution import ExecutionAgent
from .diagnosis import DiagnosisAgent
from .knowledge import KnowledgeAgent
from .learning import LearningAgent
from .result_parser import ResultParserAgent
from .validator import ValidatorAgent
__all__ = [
"BaseAgent",
"AgentState",
"AgentMessage",
"QueryMode",
"RouterAgent",
"PlanningAgent",
"ExecutionAgent",
"DiagnosisAgent",
"KnowledgeAgent",
"LearningAgent",
"ResultParserAgent",
"ValidatorAgent",
]
EOF
echo " ✓ __init__.py 已更新"
echo ""
echo "6. 更新orchestrator.py导入"
ORCHESTRATOR_FILE="/home/xia-lab/wutx/00test/bbav20311/gfa_core/mas/core/orchestrator.py"
# 备份原文件
cp "$ORCHESTRATOR_FILE" "$BACKUP_DIR/orchestrator.py.bak"
# 替换导入
sed -i 's/from gfa_core.mas.agents.diagnosis_v2 import DiagnosisAgentV2/from gfa_core.mas.agents.diagnosis import DiagnosisAgent/g' "$ORCHESTRATOR_FILE"
sed -i 's/from gfa_core.mas.agents.planning_v2 import PlanningAgentV2/from gfa_core.mas.agents.planning import PlanningAgent/g' "$ORCHESTRATOR_FILE"
sed -i 's/from gfa_core.mas.agents.execution_v2 import ExecutionAgentV2/from gfa_core.mas.agents.execution import ExecutionAgent/g' "$ORCHESTRATOR_FILE"
# 替换类实例化
sed -i 's/DiagnosisAgentV2/DiagnosisAgent/g' "$ORCHESTRATOR_FILE"
sed -i 's/PlanningAgentV2/PlanningAgent/g' "$ORCHESTRATOR_FILE"
sed -i 's/ExecutionAgentV2/ExecutionAgent/g' "$ORCHESTRATOR_FILE"
echo " ✓ orchestrator.py 导入已更新"
echo ""
echo "7. 清理v2文件(保留备份)"
for agent in diagnosis planning execution knowledge learning result_parser validator; do
if [ -f "$AGENTS_DIR/${agent}_v2.py" ]; then
mv "$AGENTS_DIR/${agent}_v2.py" "$BACKUP_DIR/${agent}_v2.py"
echo " ✓ 移动 ${agent}_v2.py -> backup/"
fi
done
echo ""
echo "=============================================="
echo "清理完成"
echo "=============================================="
echo ""
echo "备份文件位置: $BACKUP_DIR"
echo ""
echo "清理后的Agent文件:"
ls -la "$AGENTS_DIR/"*.py | grep -v "__pycache__" | grep -v "backup"
echo ""
echo "注意: 请重启服务使更改生效"
+49
View File
@@ -0,0 +1,49 @@
# bbav20311 API 配置
# 存放各数据库 API 的访问密钥和配置
# NCBI API
# 申请地址: https://www.ncbi.nlm.nih.gov/account/
ncbi:
api_key: "" # 可选,提高速率限制到 10 requests/second
rate_limit: 0.34 # 无 key 时 3 requests/second,有 key 时 0.1
# Phytozome API
# 申请地址: https://phytozome-next.jgi.doe.gov/
phytozome:
api_key: "" # JGI 账户 API key
rate_limit: 1.0
# TAIR API
# 申请地址: https://www.arabidopsis.org/
tair:
api_key: "" # TAIR 订阅用户 API key
rate_limit: 1.0
# 通用配置
settings:
# 默认速率限制(秒)
default_rate_limit: 1.0
# 请求超时(秒)
request_timeout: 30
# 最大重试次数
max_retries: 3
# 缓存设置
cache_enabled: true
cache_ttl: 3600 # 缓存时间(秒)
# 并行查询设置
max_workers: 5
query_timeout: 30
# 数据库端点(一般不需要修改)
endpoints:
ncbi: "https://eutils.ncbi.nlm.nih.gov/entrez/eutils"
ensembl: "https://rest.ensembl.org"
pfam: "https://www.ebi.ac.uk/interpro/api"
plantcare: "http://bioinformatics.psb.ugent.be/webtools/plantcare/html/"
phytozome: "https://phytozome-next.jgi.doe.gov/api"
tair: "https://www.arabidopsis.org/api"
planttfdb: "http://planttfdb.gao-lab.org/api"
+23
View File
@@ -0,0 +1,23 @@
# LLM配置 - 仅模型列表,API配置在config.py中统一存储
providers:
deepseek:
name: "DeepSeek"
api_base: "https://api.deepseek.com"
env_key: "DEEPSEEK_API_KEY"
models:
- name: "deepseek-v4-flash"
display_name: "DeepSeek V4 Flash"
context_length: 128000
- name: "deepseek-v4-pro"
display_name: "DeepSeek V4 Pro"
context_length: 128000
- name: "deepseek-chat"
display_name: "DeepSeek Chat"
context_length: 64000
# 默认配置由config.py设置,此处不重复
default:
provider: "deepseek"
model: "deepseek-v4-flash"
temperature: 0.7
max_tokens: 4096
@@ -0,0 +1,408 @@
{
"_comment": "自定义基因家族Pfam映射文件 - 此文件中的定义会覆盖内置映射",
"_version": "1.0",
"_last_updated": "2024-01-01",
"SPL": {
"pfam_ids": ["PF03110"],
"description": "SQUAMOSA promoter binding protein-like, SBP-box转录因子家族",
"category": "transcription_factor",
"aliases": ["SBP", "SBP-box", "SQUAMOSA", "SPL transcription factor"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 16,
"typical_count": "15-30 per genome",
"hmm_source": "Pfam",
"notes": "参与植物发育时相转变、花发育、叶片形态等"
},
"WRKY": {
"pfam_ids": ["PF03106"],
"description": "WRKY DNA-binding domain, 植物特有转录因子,参与胁迫响应和发育",
"category": "transcription_factor",
"aliases": ["WRKY transcription factor"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 74,
"typical_count": "70-130 per genome",
"hmm_source": "Pfam",
"subfamilies": ["Group I", "Group II", "Group III"],
"notes": "以保守的WRKYGQK序列命名,参与病原防御、衰老、发育等"
},
"MYB": {
"pfam_ids": ["PF00249", "PF13921"],
"description": "MYB DNA-binding domain, 大型转录因子家族",
"category": "transcription_factor",
"aliases": ["MYB transcription factor", "R2R3-MYB", "MYB-related"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 197,
"typical_count": "100-250 per genome",
"hmm_source": "Pfam",
"subfamilies": ["1R-MYB", "R2R3-MYB", "3R-MYB", "4R-MYB"],
"notes": "R2R3-MYB是植物中最大的亚家族,参与代谢、发育、胁迫响应"
},
"bHLH": {
"pfam_ids": ["PF00010"],
"description": "Basic helix-loop-helix domain, 参与光信号、激素响应和发育",
"category": "transcription_factor",
"aliases": ["basic helix-loop-helix", "HLH"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 162,
"typical_count": "150-200 per genome",
"hmm_source": "Pfam"
},
"NAC": {
"pfam_ids": ["PF02365"],
"description": "NAC domain (NAM, ATAF, CUC), 植物特有转录因子",
"category": "transcription_factor",
"aliases": ["NAM", "ATAF", "CUC", "NAC transcription factor"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 117,
"typical_count": "100-180 per genome",
"hmm_source": "Pfam",
"notes": "参与发育、衰老、胁迫响应、次生壁合成等"
},
"AP2_ERF": {
"pfam_ids": ["PF00847"],
"description": "AP2/ERF domain, 乙烯响应因子超家族",
"category": "transcription_factor",
"aliases": ["AP2", "ERF", "DREB", "CBF", "AP2/EREBP"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 147,
"typical_count": "120-200 per genome",
"hmm_source": "Pfam",
"subfamilies": ["AP2", "ERF", "DREB", "RAV", "Soloist"],
"notes": "DREB/CBF亚家族参与冷胁迫响应"
},
"NBS-LRR": {
"pfam_ids": ["PF00931", "PF13855"],
"description": "NBS-LRR抗病基因家族,植物先天免疫核心组分",
"category": "resistance",
"aliases": ["NLR", "R gene", "NB-LRR", "NBS", "R protein"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 178,
"typical_count": "100-500 per genome",
"hmm_source": "Pfam",
"subfamilies": ["TNL", "CNL", "RNL"],
"notes": "TNL含TIR结构域,CNL含CC结构域,数量在物种间差异大"
},
"MADS-box": {
"pfam_ids": ["PF00319", "PF01486"],
"description": "MADS-box转录因子,花发育ABC模型核心因子",
"category": "transcription_factor",
"aliases": ["MADS", "MIKC", "MADS-box transcription factor"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 107,
"typical_count": "70-150 per genome",
"hmm_source": "Pfam",
"subfamilies": ["Type I", "Type II (MIKC)"],
"notes": "MIKC型包含M、I、K、C四个结构域"
},
"HD-ZIP": {
"pfam_ids": ["PF00046", "PF02183"],
"description": "Homeodomain-leucine zipper, 参与发育模式建成",
"category": "transcription_factor",
"aliases": ["Homeodomain", "HD-Zip", "HOX"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 48,
"typical_count": "40-60 per genome",
"hmm_source": "Pfam",
"subfamilies": ["HD-ZIP I", "HD-ZIP II", "HD-ZIP III", "HD-ZIP IV"]
},
"GRAS": {
"pfam_ids": ["PF03514"],
"description": "GRAS domain转录因子,参与GA信号和发育",
"category": "transcription_factor",
"aliases": ["DELLA", "SCR", "SHR", "GRAS family"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 33,
"typical_count": "30-60 per genome",
"hmm_source": "Pfam",
"subfamilies": ["DELLA", "SCR", "SHR", "PAT1", "HAM", "LISCL", "SCL3"],
"notes": "DELLA蛋白是GA信号的负调控因子"
},
"bZIP": {
"pfam_ids": ["PF00170", "PF07716"],
"description": "Basic leucine zipper转录因子,参与ABA信号和胁迫响应",
"category": "transcription_factor",
"aliases": ["basic leucine zipper", "bZIP transcription factor"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 78,
"typical_count": "70-130 per genome",
"hmm_source": "Pfam",
"subfamilies": ["Group A", "Group B", "Group C", "Group D", "Group E", "Group F", "Group G", "Group H", "Group I", "Group S"]
},
"TCP": {
"pfam_ids": ["PF03634"],
"description": "TCP domain转录因子,参与细胞增殖和器官形态",
"category": "transcription_factor",
"aliases": ["TCP transcription factor", "TB1", "CYC", "PCF"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 24,
"typical_count": "20-30 per genome",
"hmm_source": "Pfam",
"subfamilies": ["Class I (PCF)", "Class II (CIN, CYC/TB1)"]
},
"ARF": {
"pfam_ids": ["PF06507", "PF02362"],
"description": "Auxin Response Factor, 生长素响应因子",
"category": "transcription_factor",
"aliases": ["Auxin response factor", "ARF transcription factor"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 23,
"typical_count": "20-40 per genome",
"hmm_source": "Pfam",
"notes": "与Aux/IAA蛋白互作调控生长素响应基因"
},
"HSF": {
"pfam_ids": ["PF00447"],
"description": "Heat shock transcription factor, 热激转录因子",
"category": "transcription_factor",
"aliases": ["Heat shock factor", "HSF transcription factor"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 21,
"typical_count": "20-30 per genome",
"hmm_source": "Pfam",
"subfamilies": ["Class A", "Class B", "Class C"]
},
"Dof": {
"pfam_ids": ["PF02701"],
"description": "Dof (DNA binding with one finger) 转录因子",
"category": "transcription_factor",
"aliases": ["Dof transcription factor", "Dof zinc finger"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 36,
"typical_count": "30-50 per genome",
"hmm_source": "Pfam"
},
"C2H2_ZF": {
"pfam_ids": ["PF00096", "PF13912"],
"description": "C2H2型锌指蛋白,经典锌指转录因子",
"category": "transcription_factor",
"aliases": ["C2H2", "C2H2 zinc finger", "Zinc finger", "ZFP"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 211,
"typical_count": "150-300 per genome",
"hmm_source": "Pfam"
},
"GATA": {
"pfam_ids": ["PF00320"],
"description": "GATA型锌指转录因子,参与氮代谢和光响应",
"category": "transcription_factor",
"aliases": ["GATA zinc finger", "GATA transcription factor"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 30,
"typical_count": "25-40 per genome",
"hmm_source": "Pfam"
},
"Trihelix": {
"pfam_ids": ["PF13837", "PF10545"],
"description": "Trihelix (GT因子) 转录因子",
"category": "transcription_factor",
"aliases": ["GT factor", "GT element binding protein"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 30,
"typical_count": "25-40 per genome",
"hmm_source": "Pfam",
"subfamilies": ["GT-1", "GT-2", "GTγ", "SH4", "SIP1"]
},
"LRR-RLK": {
"pfam_ids": ["PF00560", "PF00069", "PF07714"],
"description": "LRR受体激酶,植物最大的受体激酶家族",
"category": "kinase",
"aliases": ["LRR receptor kinase", "LRR-RK", "Leucine-rich repeat receptor kinase"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 235,
"typical_count": "200-400 per genome",
"hmm_source": "Pfam",
"notes": "包括CLV1、BAK1、FLS2等重要受体"
},
"MAPK": {
"pfam_ids": ["PF00069"],
"description": "Mitogen-activated protein kinase, 丝裂原活化蛋白激酶",
"category": "kinase",
"aliases": ["MPK", "MAP kinase"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 20,
"typical_count": "15-25 per genome",
"hmm_source": "Pfam",
"subfamilies": ["Group A", "Group B", "Group C", "Group D"]
},
"CDPK": {
"pfam_ids": ["PF00069", "PF13499", "PF00036"],
"description": "Calcium-dependent protein kinase, 钙依赖蛋白激酶",
"category": "kinase",
"aliases": ["CPK", "Calcium-dependent kinase"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 34,
"typical_count": "25-40 per genome",
"hmm_source": "Pfam",
"notes": "含有EF-hand钙结合结构域"
},
"SnRK": {
"pfam_ids": ["PF00069", "PF00571"],
"description": "SNF1-related protein kinase, 蔗糖非发酵相关激酶",
"category": "kinase",
"aliases": ["SnRK1", "SnRK2", "SnRK3", "CIPK"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 38,
"typical_count": "35-50 per genome",
"hmm_source": "Pfam",
"subfamilies": ["SnRK1", "SnRK2", "SnRK3/CIPK"],
"notes": "SnRK2参与ABA信号,SnRK3/CIPK与CBL互作"
},
"WAK": {
"pfam_ids": ["PF00069", "PF13947", "PF08488"],
"description": "Wall-associated kinase, 细胞壁相关激酶",
"category": "kinase",
"aliases": ["Wall-associated receptor kinase", "WAKL"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 26,
"typical_count": "20-100 per genome",
"hmm_source": "Pfam"
},
"Aquaporin": {
"pfam_ids": ["PF00230"],
"description": "水通道蛋白/主要内在蛋白家族",
"category": "other",
"aliases": ["MIP", "PIP", "TIP", "NIP", "SIP", "XIP", "Major intrinsic protein"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 35,
"typical_count": "30-70 per genome",
"hmm_source": "Pfam",
"subfamilies": ["PIP", "TIP", "NIP", "SIP", "XIP"],
"notes": "PIP定位质膜,TIP定位液泡膜"
},
"HSP70": {
"pfam_ids": ["PF00012"],
"description": "Heat shock protein 70, 分子伴侣",
"category": "other",
"aliases": ["HSP70", "DnaK", "BiP", "Heat shock 70"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 18,
"typical_count": "15-25 per genome",
"hmm_source": "Pfam"
},
"HSP90": {
"pfam_ids": ["PF00183", "PF02518"],
"description": "Heat shock protein 90, 分子伴侣",
"category": "other",
"aliases": ["HSP90", "Heat shock 90"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 7,
"typical_count": "5-10 per genome",
"hmm_source": "Pfam"
},
"sHSP": {
"pfam_ids": ["PF00011"],
"description": "Small heat shock protein, 小分子热激蛋白",
"category": "other",
"aliases": ["HSP20", "small HSP", "alpha-crystallin"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 19,
"typical_count": "15-30 per genome",
"hmm_source": "Pfam"
},
"LEA": {
"pfam_ids": ["PF03760", "PF03168", "PF02987", "PF00257", "PF04927", "PF00477"],
"description": "Late embryogenesis abundant protein, 胚胎发育晚期丰富蛋白",
"category": "other",
"aliases": ["LEA protein", "Dehydrin"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 51,
"typical_count": "40-100 per genome",
"hmm_source": "Pfam",
"subfamilies": ["LEA_1", "LEA_2", "LEA_3", "LEA_4", "LEA_5", "Dehydrin"],
"notes": "参与干旱、低温等非生物胁迫响应"
},
"GST": {
"pfam_ids": ["PF02798", "PF00043", "PF13417", "PF13410"],
"description": "Glutathione S-transferase, 谷胱甘肽S-转移酶",
"category": "other",
"aliases": ["Glutathione transferase"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 55,
"typical_count": "50-100 per genome",
"hmm_source": "Pfam",
"subfamilies": ["Phi", "Tau", "Theta", "Zeta", "Lambda", "DHAR", "EF1Bγ"],
"notes": "参与解毒、次生代谢、胁迫响应"
},
"Cytochrome_P450": {
"pfam_ids": ["PF00067"],
"description": "Cytochrome P450, 细胞色素P450单加氧酶",
"category": "other",
"aliases": ["CYP", "P450", "Cytochrome P450 monooxygenase"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 272,
"typical_count": "200-500 per genome",
"hmm_source": "Pfam",
"notes": "植物中最大的酶家族之一,参与次生代谢"
},
"ABC_transporter": {
"pfam_ids": ["PF00005", "PF00664", "PF01061"],
"description": "ABC transporter, ATP结合盒转运蛋白",
"category": "other",
"aliases": ["ABC transporter", "ATP-binding cassette"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 130,
"typical_count": "100-200 per genome",
"hmm_source": "Pfam",
"subfamilies": ["ABCA", "ABCB", "ABCC", "ABCD", "ABCE", "ABCF", "ABCG", "ABCI"]
},
"Expansin": {
"pfam_ids": ["PF03330", "PF01357"],
"description": "Expansin, 扩展蛋白,参与细胞壁松弛",
"category": "other",
"aliases": ["EXPA", "EXPB", "EXLA", "EXLB"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 36,
"typical_count": "30-60 per genome",
"hmm_source": "Pfam",
"subfamilies": ["α-expansin (EXPA)", "β-expansin (EXPB)", "expansin-like A (EXLA)", "expansin-like B (EXLB)"]
},
"Peroxidase": {
"pfam_ids": ["PF00141"],
"description": "Class III peroxidase, 过氧化物酶",
"category": "other",
"aliases": ["POD", "PRX", "POX", "Class III peroxidase"],
"reference_species": "Arabidopsis thaliana",
"reference_count": 73,
"typical_count": "70-150 per genome",
"hmm_source": "Pfam",
"notes": "参与木质素合成、ROS代谢、防御响应"
},
"Laccase": {
"pfam_ids": ["PF00394", "PF07731", "PF07732"],
"description": "Laccase, 漆酶,参与木质素聚合",
"category": "other",
"aliases": ["LAC", "Laccase/Diphenol oxidase"],
+248
View File
@@ -0,0 +1,248 @@
# =============================================================================
# BotanicalBaseAgent 配置文件
# =============================================================================
# 此文件包含基因家族分析Agent的全局配置
# 修改后需要重启Agent生效
# =============================================================================
# -----------------------------------------------------------------------------
# 基础路径配置
# -----------------------------------------------------------------------------
paths:
# 工作空间根目录(分析结果存放位置)
workspace: "workspace"
# 脚本目录(Perl/R脚本位置)
scripts: "scripts"
# 数据目录
data: "data"
# Pfam HMM模型目录
pfam_hmm: "data/pfam_hmm"
# 参考序列目录(如拟南芥家族成员序列)
reference: "data/reference"
# 基因组数据目录
genomes: "data/genomes"
# 知识库文档目录
kb_docs: "kb_docs"
# 向量数据库存储目录
kb_store: "kb_store"
# -----------------------------------------------------------------------------
# 工具默认参数
# -----------------------------------------------------------------------------
tools:
# HMMER参数
hmmsearch:
# 默认使用可信阈值
use_cut_tc: true
# 备用E-value阈值(当use_cut_tc=false时使用)
evalue: 1.0e-5
# CPU核心数
cpu: 4
# 超时时间(秒)
timeout: 3600
# BLAST参数
blast:
# E-value阈值
evalue: 1.0e-5
# 序列一致性阈值(%)
identity_threshold: 30.0
# 线程数
num_threads: 4
# 输出格式
outfmt: "6 std qlen slen"
# MUSCLE参数
muscle:
# 最大迭代次数
max_iterations: 16
# 超时时间(秒)
timeout: 3600
# MAFFT参数
mafft:
# 默认算法(auto会根据序列数量自动选择)
algorithm: "auto"
# 最大迭代次数
max_iterations: 1000
# 线程数
threads: 4
# 超时时间(秒)
timeout: 7200
# 自动选择算法的阈值
auto_selection:
# 序列数<=此值时使用L-INS-i
linsi_max_seqs: 200
# 序列数<=此值时使用FFT-NS-i
fftnsi_max_seqs: 500
# trimAl参数
trimal:
# 默认修剪方法
method: "gappyout"
# 可选方法: gappyout, strict, automated1
# seqtk参数
seqtk:
# 是否优先使用seqtk(比Python实现更快)
prefer_seqtk: true
# -----------------------------------------------------------------------------
# 鉴定流程参数
# -----------------------------------------------------------------------------
identification:
# 结果合并方法
merge_method: "intersection" # intersection(交集,推荐)或 union(并集)
# 最小候选基因数警告阈值
min_candidates_warning: 5
# 最大候选基因数警告阈值(可能有假阳性)
max_candidates_warning: 500
# -----------------------------------------------------------------------------
# 蛋白特征分析参数
# -----------------------------------------------------------------------------
features:
# 理化性质计算
physicochemical:
# 是否使用R脚本(更准确)
use_r_script: true
# R脚本路径
r_script: "scripts/fasta_pI_mw.R"
# 跨膜结构域预测
transmembrane:
# 首选方法: deeptmhmm, tmhmm, simple
preferred_method: "auto"
# 疏水性扫描窗口大小
window_size: 19
# 疏水性阈值
hydrophobicity_threshold: 1.6
# 亚细胞定位预测
subcellular:
# 首选方法: local, online, feature
preferred_method: "auto"
# 本地脚本路径
local_script: "scripts/get_Plant_mPLoc_out.py"
# 在线服务超时(秒)
online_timeout: 300
# -----------------------------------------------------------------------------
# 比对和进化分析参数
# -----------------------------------------------------------------------------
alignment:
# 是否自动生成多种格式
auto_convert_formats: true
# 输出格式列表
output_formats:
- "fasta"
- "phylip"
- "nexus"
# 是否自动修剪比对
auto_trim: false
# 可视化设置
visualization:
# 是否自动生成可视化
auto_generate: false
# R脚本路径
r_script: "scripts/msa_figure.R"
# -----------------------------------------------------------------------------
# LLM配置
# -----------------------------------------------------------------------------
llm:
# 模型提供商: openai, anthropic, local
provider: "openai"
# OpenAI配置
openai:
model: "gpt-4"
temperature: 0
max_tokens: 4096
# 本地模型配置(如使用Ollama)
local:
base_url: "http://localhost:11434/v1"
model: "llama2"
temperature: 0
# -----------------------------------------------------------------------------
# 向量数据库配置
# -----------------------------------------------------------------------------
vector_store:
# 类型: faiss, chroma
type: "faiss"
# 嵌入模型
embedding:
model: "BAAI/bge-m3"
# 本地模型路径(如果已下载)
local_path: "models/bge-m3_from_web"
# 设备: cpu, cuda
device: "cpu"
# 检索参数
retrieval:
# 返回的文档数量
top_k: 5
# 相似度阈值
score_threshold: 0.5
# -----------------------------------------------------------------------------
# 搜索配置
# -----------------------------------------------------------------------------
search:
# Tavily搜索
tavily:
# 搜索深度: basic, advanced
search_depth: "advanced"
# 最大结果数
max_results: 5
# SearchAPI
searchapi:
engine: "google"
max_results: 5
# -----------------------------------------------------------------------------
# 日志配置
# -----------------------------------------------------------------------------
logging:
# 日志级别: DEBUG, INFO, WARNING, ERROR
level: "INFO"
# 日志文件
file: "logs/agent.log"
# 是否输出到控制台
console: true
# 日志格式
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
# -----------------------------------------------------------------------------
# 输出配置
# -----------------------------------------------------------------------------
output:
# 是否保存中间结果
save_intermediate: true
# 是否生成分析报告
generate_report: true
# 报告格式: markdown, html, pdf
report_format: "markdown"
# 结果文件命名模板
naming_template: "{species}_{family}_{date}"
+1
View File
@@ -0,0 +1 @@
../../../PlantAI-dev4090-7/data/
@@ -0,0 +1,144 @@
#!/usr/bin/env bash
set -euo pipefail
PROJECT="PRJNA530826"
CONDA_SH="${CONDA_SH:-/home/xia-lab/miniconda3/etc/profile.d/conda.sh}"
CONDA_ENV="${CONDA_ENV:-rnaseq}"
JOBS="${JOBS:-4}"
CONNECTIONS="${CONNECTIONS:-8}"
SPLITS="${SPLITS:-8}"
MIN_SPLIT_SIZE="${MIN_SPLIT_SIZE:-20M}"
RETRY_WAIT="${RETRY_WAIT:-10}"
MAX_TRIES="${MAX_TRIES:-10}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
OUTDIR="${OUTDIR:-${SCRIPT_DIR}}"
URLS_TXT="${URLS_TXT:-${SCRIPT_DIR}/${PROJECT}.aria2c.urls.txt}"
MD5_TXT="${MD5_TXT:-${SCRIPT_DIR}/${PROJECT}.fastq.md5}"
LOG_FILE="${LOG_FILE:-${SCRIPT_DIR}/${PROJECT}.aria2c.log}"
usage() {
cat <<USAGE
Usage: bash $0 [options]
Download ${PROJECT} RNA-seq FASTQ files with aria2c.
Required file in the same directory as this script:
${PROJECT}.aria2c.urls.txt
Options:
--outdir DIR Output directory. Default: script directory
--jobs N Concurrent files. Default: ${JOBS}
--connections N Connections per file/server. Default: ${CONNECTIONS}
--splits N Split count per file. Default: ${SPLITS}
--env NAME Conda environment. Default: ${CONDA_ENV}
--help Show this help.
Examples:
bash $0
bash $0 --jobs 6 --connections 8 --splits 8
USAGE
}
while [[ $# -gt 0 ]]; do
case "$1" in
--outdir)
OUTDIR="$2"
shift 2
;;
--jobs)
JOBS="$2"
shift 2
;;
--connections)
CONNECTIONS="$2"
shift 2
;;
--splits)
SPLITS="$2"
shift 2
;;
--env)
CONDA_ENV="$2"
shift 2
;;
--help|-h)
usage
exit 0
;;
*)
echo "Unknown option: $1" >&2
usage >&2
exit 2
;;
esac
done
if [[ -f "${CONDA_SH}" ]]; then
# shellcheck source=/dev/null
source "${CONDA_SH}"
conda activate "${CONDA_ENV}" || {
echo "ERROR: failed to activate conda env: ${CONDA_ENV}" >&2
exit 1
}
else
echo "WARN: conda init script not found: ${CONDA_SH}; using current PATH" >&2
fi
if ! command -v aria2c >/dev/null 2>&1; then
cat >&2 <<ERR
ERROR: aria2c is not available in PATH after activating '${CONDA_ENV}'.
Install it first, for example:
conda install -n ${CONDA_ENV} -c conda-forge aria2
Then rerun:
bash $0
ERR
exit 127
fi
if [[ ! -f "${URLS_TXT}" ]]; then
echo "ERROR: URL list not found: ${URLS_TXT}" >&2
exit 1
fi
mkdir -p "${OUTDIR}"
URL_COUNT="$(wc -l < "${URLS_TXT}")"
if [[ "${URL_COUNT}" -eq 0 ]]; then
echo "ERROR: URL list is empty: ${URLS_TXT}" >&2
exit 1
fi
echo "FASTQ URL count: ${URL_COUNT}"
echo "Output directory: ${OUTDIR}"
echo "URL list: ${URLS_TXT}"
echo "aria2c settings: jobs=${JOBS}, connections=${CONNECTIONS}, splits=${SPLITS}"
aria2c \
--dir="${OUTDIR}" \
--input-file="${URLS_TXT}" \
--continue=true \
--max-concurrent-downloads="${JOBS}" \
--max-connection-per-server="${CONNECTIONS}" \
--split="${SPLITS}" \
--min-split-size="${MIN_SPLIT_SIZE}" \
--retry-wait="${RETRY_WAIT}" \
--max-tries="${MAX_TRIES}" \
--file-allocation=none \
--auto-file-renaming=false \
--allow-overwrite=false \
--summary-interval=60 \
--console-log-level=notice \
--log="${LOG_FILE}"
echo "Download finished."
echo "URL list: ${URLS_TXT}"
if [[ -f "${MD5_TXT}" ]]; then
echo "MD5 list: ${MD5_TXT}"
fi
echo "Log file: ${LOG_FILE}"
if [[ -f "${MD5_TXT}" ]]; then
echo "To verify MD5 after download:"
echo " cd '${OUTDIR}' && md5sum -c '${MD5_TXT}'"
fi
@@ -0,0 +1,170 @@
#!/usr/bin/env bash
set -euo pipefail
PROJECT="PRJNA530826"
CONDA_SH="${CONDA_SH:-/home/xia-lab/miniconda3/etc/profile.d/conda.sh}"
CONDA_ENV="${CONDA_ENV:-rnaseq}"
OUTDIR="${OUTDIR:-workspace/rnaseq_downloads/${PROJECT}}"
JOBS="${JOBS:-4}"
CONNECTIONS="${CONNECTIONS:-8}"
SPLITS="${SPLITS:-8}"
MIN_SPLIT_SIZE="${MIN_SPLIT_SIZE:-20M}"
RETRY_WAIT="${RETRY_WAIT:-10}"
MAX_TRIES="${MAX_TRIES:-10}"
usage() {
cat <<EOF
Usage: bash $0 [options]
Download ${PROJECT} RNA-seq FASTQ files from ENA with aria2c.
Options:
--outdir DIR Output directory. Default: ${OUTDIR}
--jobs N Concurrent files. Default: ${JOBS}
--connections N Connections per file/server. Default: ${CONNECTIONS}
--splits N Split count per file. Default: ${SPLITS}
--env NAME Conda environment. Default: ${CONDA_ENV}
--help Show this help.
Examples:
bash $0
bash $0 --jobs 6 --connections 8 --splits 8
OUTDIR=/data/rnaseq_fastq bash $0
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--outdir)
OUTDIR="$2"
shift 2
;;
--jobs)
JOBS="$2"
shift 2
;;
--connections)
CONNECTIONS="$2"
shift 2
;;
--splits)
SPLITS="$2"
shift 2
;;
--env)
CONDA_ENV="$2"
shift 2
;;
--help|-h)
usage
exit 0
;;
*)
echo "Unknown option: $1" >&2
usage >&2
exit 2
;;
esac
done
mkdir -p "${OUTDIR}"
if [[ -f "${CONDA_SH}" ]]; then
# shellcheck source=/dev/null
source "${CONDA_SH}"
conda activate "${CONDA_ENV}" || {
echo "ERROR: failed to activate conda env: ${CONDA_ENV}" >&2
exit 1
}
else
echo "WARN: conda init script not found: ${CONDA_SH}; using current PATH" >&2
fi
if ! command -v aria2c >/dev/null 2>&1; then
cat >&2 <<EOF
ERROR: aria2c is not available in PATH after activating '${CONDA_ENV}'.
Install it first, for example:
conda install -n ${CONDA_ENV} -c conda-forge aria2
Then rerun:
bash $0 --outdir "${OUTDIR}"
EOF
exit 127
fi
if ! command -v curl >/dev/null 2>&1; then
echo "ERROR: curl is required to fetch the ENA file list." >&2
exit 127
fi
META_TSV="${OUTDIR}/${PROJECT}.ena_fastq.tsv"
URLS_TXT="${OUTDIR}/${PROJECT}.aria2c.urls.txt"
MD5_TXT="${OUTDIR}/${PROJECT}.fastq.md5"
LOG_FILE="${OUTDIR}/${PROJECT}.aria2c.log"
ENA_URL="https://www.ebi.ac.uk/ena/portal/api/filereport?accession=${PROJECT}&result=read_run&fields=run_accession,sample_accession,experiment_accession,scientific_name,fastq_ftp,fastq_aspera,fastq_bytes,fastq_md5&format=tsv&download=false&limit=0"
echo "Fetching ENA FASTQ metadata: ${PROJECT}"
curl -L -sS "${ENA_URL}" -o "${META_TSV}"
awk -F '\t' '
NR > 1 && $5 != "" {
n = split($5, urls, ";")
for (i = 1; i <= n; i++) {
if (urls[i] != "") {
u = urls[i]
sub(/^ftp:\/\//, "", u)
print "https://" u
}
}
}
' "${META_TSV}" > "${URLS_TXT}"
awk -F '\t' '
NR > 1 && $8 != "" && $5 != "" {
n = split($5, urls, ";")
m = split($8, md5s, ";")
for (i = 1; i <= n; i++) {
if (urls[i] != "" && md5s[i] != "") {
file = urls[i]
sub(/^.*\//, "", file)
print md5s[i] " " file
}
}
}
' "${META_TSV}" > "${MD5_TXT}"
URL_COUNT="$(wc -l < "${URLS_TXT}")"
if [[ "${URL_COUNT}" -eq 0 ]]; then
echo "ERROR: no FASTQ URLs were generated. Check ${META_TSV}" >&2
exit 1
fi
echo "FASTQ URL count: ${URL_COUNT}"
echo "Output directory: ${OUTDIR}"
echo "aria2c settings: jobs=${JOBS}, connections=${CONNECTIONS}, splits=${SPLITS}"
aria2c \
--dir="${OUTDIR}" \
--input-file="${URLS_TXT}" \
--continue=true \
--max-concurrent-downloads="${JOBS}" \
--max-connection-per-server="${CONNECTIONS}" \
--split="${SPLITS}" \
--min-split-size="${MIN_SPLIT_SIZE}" \
--retry-wait="${RETRY_WAIT}" \
--max-tries="${MAX_TRIES}" \
--file-allocation=none \
--auto-file-renaming=false \
--allow-overwrite=false \
--summary-interval=60 \
--console-log-level=notice \
--log="${LOG_FILE}"
echo "Download finished."
echo "URL list: ${URLS_TXT}"
echo "MD5 list: ${MD5_TXT}"
echo "Log file: ${LOG_FILE}"
echo "To verify MD5 after download:"
echo " cd '${OUTDIR}' && md5sum -c '${PROJECT}.fastq.md5'"
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env python3
"""
启用bbav5持久化记忆
"""
import asyncio
from pathlib import Path
from gfa_core.mas.memory import MemoryManager
from gfa_core.mas.memory.persistent import PersistentMemory
from gfa_core.mas.memory.session import SessionMemory, SessionData
from gfa_core.mas.memory.case import CaseMemory, AnalysisCase
from gfa_core.mas.memory.knowledge import KnowledgeMemory, KnowledgeEntry
async def create_persistent_memory_manager(storage_dir: Path = None) -> MemoryManager:
"""创建带持久化的MemoryManager"""
if storage_dir is None:
storage_dir = Path("/home/xia-lab/wutx/00test/bbav5/memory_storage")
storage_dir.mkdir(parents=True, exist_ok=True)
# 创建持久化存储
session_storage = PersistentMemory(storage_dir / "sessions")
case_storage = PersistentMemory(storage_dir / "cases")
knowledge_storage = PersistentMemory(storage_dir / "knowledge")
# 创建MemoryManager
manager = MemoryManager(
session_memory=SessionMemory(), # 内存缓存 + 持久化备份
case_memory=CaseMemory(),
knowledge_memory=KnowledgeMemory(),
)
# 可选:添加持久化包装器
# 或修改SessionMemory等使用PersistentMemory作为后端
print(f"✅ MemoryManager创建成功")
print(f" 存储目录: {storage_dir}")
print(f" Session: {storage_dir / 'sessions'}")
print(f" Case: {storage_dir / 'cases'}")
print(f" Knowledge: {storage_dir / 'knowledge'}")
return manager
async def test_persistent_memory():
"""测试持久化记忆"""
manager = await create_persistent_memory_manager()
# 测试Session
session_id = "test_session_001"
session = await manager.create_session(session_id, {"test": "data"})
print(f"\n✅ Session创建: {session_id}")
# 添加消息
await manager.add_message_to_session(session_id, "user", "Hello")
await manager.add_message_to_session(session_id, "assistant", "Hi there")
print(f"✅ 消息添加完成")
# 测试Case
case = await manager.create_case(
case_id="test_case_001",
user_id="user_001",
gene_family="SPL",
species="Arabidopsis",
)
print(f"✅ Case创建: {case.case_id}")
# 更新结果
await manager.update_case_results("test_case_001", {"status": "completed"})
print(f"✅ Case结果更新")
# 检索验证
retrieved_session = await manager.get_session(session_id)
retrieved_case = await manager.get_case("test_case_001")
print(f"\n✅ 检索验证:")
print(f" Session: {retrieved_session.session_id if retrieved_session else 'None'}")
print(f" Case: {retrieved_case.case_id if retrieved_case else 'None'}")
print("\n🎉 持久化记忆测试完成!")
if __name__ == "__main__":
asyncio.run(test_persistent_memory())
+181
View File
@@ -0,0 +1,181 @@
#!/usr/bin/env python3
"""
示例:在 bbav20311 任务中集成微信通知
这个示例展示了如何在基因家族分析任务中
添加微信通知功能
"""
import asyncio
import time
from datetime import datetime
from pathlib import Path
# 导入微信通知模块
from notify_integration import notify_task_start, notify_task_complete
# 用户的微信ID(需要替换为真实ID)
USER_WECHAT_ID = "wxid_xxxxxxxxxxxxxxxx" # 替换为你的微信ID
async def run_identify_with_notification(prefix: str, user_wechat_id: str):
"""
运行基因家族鉴定任务,并发送微信通知
使用示例:
await run_identify_with_notification("Ft.SPL", "wxid_xxx")
"""
task_id = f"identify_{prefix}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
start_time = time.time()
print(f"🚀 开始任务: {task_id}")
# 1. 通知任务开始
notify_task_start(user_wechat_id, task_id, f"基因家族鉴定 ({prefix})")
try:
# 2. 执行实际任务(这里用模拟代替)
print(f" 正在分析 {prefix} 基因家族...")
# 模拟任务执行
await asyncio.sleep(5)
# 3. 任务完成,通知用户
duration = f"{int(time.time() - start_time)}秒"
output_files = [
f"{prefix}.identify.gene.list.txt",
f"{prefix}.identify.protein.fa",
f"{prefix}.identify.report.pdf"
]
notify_task_complete(
user_wechat_id=user_wechat_id,
task_id=task_id,
task_type=f"基因家族鉴定 ({prefix})",
output_files=output_files,
duration=duration
)
print(f"✅ 任务完成: {task_id}")
except Exception as e:
# 4. 任务失败,通知用户
duration = f"{int(time.time() - start_time)}秒"
notify_task_complete(
user_wechat_id=user_wechat_id,
task_id=task_id,
task_type=f"基因家族鉴定 ({prefix})",
output_files=[],
duration=duration,
error=str(e)
)
print(f"❌ 任务失败: {task_id}, 错误: {e}")
async def run_pipeline_with_notifications(
prefix: str,
stages: list,
user_wechat_id: str
):
"""
运行多阶段 pipeline,每个阶段都发送通知
使用示例:
await run_pipeline_with_notifications(
"Ft.SPL",
["identify", "phylogeny", "motif"],
"wxid_xxx"
)
"""
pipeline_id = f"pipeline_{prefix}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
start_time = time.time()
print(f"🚀 开始 Pipeline: {pipeline_id}")
print(f" 阶段: {', '.join(stages)}")
# 通知 pipeline 开始
notify_task_start(
user_wechat_id,
pipeline_id,
f"综合分析 Pipeline ({prefix})"
)
completed_stages = []
failed_stages = []
for stage in stages:
stage_start = time.time()
try:
print(f"\n 执行阶段: {stage}")
# 模拟阶段执行
await asyncio.sleep(3)
completed_stages.append(stage)
except Exception as e:
failed_stages.append((stage, str(e)))
print(f" 阶段失败: {stage}, 错误: {e}")
# Pipeline 完成通知
duration = f"{int(time.time() - start_time)}秒"
if failed_stages:
error_msg = f"完成 {len(completed_stages)}/{len(stages)} 个阶段\n"
error_msg += f"失败阶段: {', '.join([s for s, _ in failed_stages])}"
notify_task_complete(
user_wechat_id=user_wechat_id,
task_id=pipeline_id,
task_type=f"综合分析 Pipeline ({prefix})",
output_files=[f"{prefix}.{s}.result.txt" for s in completed_stages],
duration=duration,
error=error_msg
)
else:
notify_task_complete(
user_wechat_id=user_wechat_id,
task_id=pipeline_id,
task_type=f"综合分析 Pipeline ({prefix})",
output_files=[f"{prefix}.{s}.result.txt" for s in completed_stages],
duration=duration
)
print(f"\n✅ Pipeline 完成: {pipeline_id}")
# ==================== 测试 ====================
async def main():
"""测试示例"""
print("="*60)
print("🧪 微信通知集成示例")
print("="*60)
if USER_WECHAT_ID == "wxid_xxxxxxxxxxxxxxxx":
print("\n⚠️ 请修改 USER_WECHAT_ID 为你的真实微信ID")
print(" 文件位置: example_task_with_wechat.py")
return
# 测试单任务
print("\n📋 测试1: 单任务通知")
await run_identify_with_notification("Ft.SPL", USER_WECHAT_ID)
# 测试 Pipeline
print("\n📋 测试2: Pipeline 通知")
await run_pipeline_with_notifications(
"Ft.WRKY",
["identify", "phylogeny", "motif"],
USER_WECHAT_ID
)
print("\n" + "="*60)
print("✅ 所有测试完成")
print("="*60)
if __name__ == "__main__":
asyncio.run(main())
+88
View File
@@ -0,0 +1,88 @@
#!/usr/bin/env python3
"""
获取微信ID并发送测试消息
"""
import json
import subprocess
import select
def call_mcp_tool(tool_name: str, params: dict):
"""调用 MCP 工具"""
mcp_request = {
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": tool_name,
"arguments": params
},
"id": 1
}
proc = subprocess.Popen(
["bunx", "mcp-wechat-server"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
request_json = json.dumps(mcp_request) + "\n"
proc.stdin.write(request_json)
proc.stdin.flush()
proc.stdin.close()
ready, _, _ = select.select([proc.stdout], [], [], 30)
if ready:
response_line = proc.stdout.readline()
proc.terminate()
try:
response = json.loads(response_line)
if "result" in response:
result = response["result"]
if "content" in result and len(result["content"]) > 0:
return result["content"][0].get("text", "")
except:
pass
else:
proc.terminate()
return None
def main():
print("="*60)
print("🔍 获取微信联系人列表")
print("="*60)
# 尝试获取联系人
result = call_mcp_tool("get_contacts", {})
if result:
print(f"\n✅ 获取成功:")
print(result)
else:
print("\n❌ 无法获取联系人")
print("\n尝试直接发送消息到指定微信号...")
# 直接尝试发送消息
wechat_id = "w402468w"
message = "🧪 这是来自 bbav20311 的测试消息!如果收到,说明微信集成成功!"
print(f"\n💬 发送消息到 {wechat_id}...")
result = call_mcp_tool("send_text_message", {
"user_id": wechat_id,
"message": message
})
if result:
print(f"✅ 发送结果: {result}")
else:
print("❌ 发送失败")
if __name__ == "__main__":
main()
@@ -0,0 +1,28 @@
"""
bbav20311 API 客户端模块
集成多个植物数据库和转录组数据平台 API
参考 ClawBio 的 gwas-lookup 多 API 并行查询模式
"""
from .plantcare_client import PlantCAREClient
from .pfam_client import PfamClient
from .ncbi_client import NCBIClient
from .rnaseq_clients import (
EnsemblPlantsClient,
PhytozomeClient,
TAIRClient,
PlantTFDBClient,
)
from .multi_api_query import MultiAPIQuery
__all__ = [
'PlantCAREClient',
'PfamClient',
'NCBIClient',
'EnsemblPlantsClient',
'TAIRClient',
'PhytozomeClient',
'PlantTFDBClient',
'MultiAPIQuery',
]

Some files were not shown because too many files have changed in this diff Show More