Skip to content
Back to skills

Pdb Viewer Skill

ASecurity

在 WorkBuddy 内置浏览器中以 3D 结构展示 PDB 文件,支持通过自然语言操控结构(高亮、隐藏链、测量距离/角度、相互作用分析、标签、透明度控制等)。Mol* 5.9.0 本地自托管,支持本地文件和腾讯健康组学平台 COS 路径。

  • 417 stars
  • 0 votes
  • 0 copies
  • 27 views
  • Added September 8, 2026
developmentpythonbashgitapi

Works with

  • cli
  • api

Security analysis

A92/100
  • mediumUses curl or wget to download content
  • mediumUses curl or wget to download content

Pro scans all 20 files and shows the line behind each finding

Scanned November 8, 2026

npx -y skills add infometa/workbuddyskills --skill pdb-viewer-skill --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Pdb Viewer Skill?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Pdb Viewer Skill
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/infometa-pdb-viewer-skill/badge)](https://www.skillsdirectory.com/skills/infometa-pdb-viewer-skill)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: pdb-viewer-skill
displayName: 腾讯组学蛋白质结构pdb文件可视化
slug: pdb-viewer-skill
version: 1.0.0
description: 在 WorkBuddy 内置浏览器中以 3D 结构展示 PDB 文件,支持通过自然语言操控结构(高亮、隐藏链、测量距离/角度、相互作用分析、标签、透明度控制等)。Mol* 5.9.0 本地自托管,支持本地文件和腾讯健康组学平台 COS 路径。
author: WorkBuddy
tags:
  [
    pdb,
    biology,
    3d,
    structure,
    mol*,
    viewer,
    omics,
    tencent-health,
    interactive,
    natural-language,
  ]
triggers:
  - 打开 pdb
  - 查看 pdb
  - 显示 pdb 结构
  - 可视化 pdb
  - 预览蛋白结构
  - 显示三维结构
  - 展示 3d 结构
  - pdb 浏览器
  - 蛋白结构
  - protein structure
  - pdb viewer
  - molstar
  - structure viewer
  - 3d protein
  - cos pdb
  - 腾讯健康组学平台 pdb
  - alphafold 结构
  - 蛋白质结构可视化
  - 查看 @*.pdb
  - 高亮残基
  - 隐藏链
  - 测量距离
  - 活性位点
  - 结合口袋
  - 突变位点
---

# pdb-viewer-skill

在 WorkBuddy 中以 **3D 交互式方式**展示 PDB/mmCIF 生物大分子结构文件,并支持通过**自然语言指令**实时操控场景。

底层使用 [Mol\* (molstar) 5.9.0](https://molstar.org/),本地自托管(`templates/molstar.js` + `templates/molstar.css`)。COS 文件通过 **omics-platform-cli** 认证,调用 `CosBucketService.GetObjectData` 接口读取。

## 核心能力

| 类别           | 能力                          | 用户示例                          |
| -------------- | ----------------------------- | --------------------------------- |
| **数据加载**   | 本地 PDB / COS URI / RCSB ID  | "打开 xxx.pdb"                    |
| **可视化控制** | 切换表示方式(8 种)          | "显示为球棍模型"                  |
|                | 着色方案(8 种主题)          | "按二级结构着色" / "全部设为蓝色" |
|                | 透明度控制                    | "蛋白表面设为 50% 透明"           |
|                | 背景                          | "背景设为白色"                    |
| **结构操作**   | 按单链精确隐藏/显示           | "隐藏 B 链" / "显示所有链"        |
|                | 配体/水/氢原子显隐            | "去掉水分子" / "隐藏配体"         |
|                | 隔离/恢复全部                 | "只看 A 链" / "恢复全部显示"      |
|                | 重置视图                      | "重置到默认状态"                  |
| **选择器**     | 残基区间/离散列表             | "高亮 A 链 50-100 位残基"         |
|                | 按原子名/元素/配体名          | "选中所有锌离子"                  |
|                | 空间距离选择(X Å 内)        | "选中 ATP 周围 5 Å 的残基"        |
|                | 按 B-factor 阈值              | "选中 B-factor > 50 的残基"       |
| **标注**       | 残基文字标签                  | "标注 His57"                      |
|                | 自定义标签文字                | "标注 His57 为活性位点"           |
| **视角控制**   | 精确聚焦到链/选区             | "聚焦 A 链" / "聚焦 ATP 口袋"     |
|                | 正交/透视投影切换             | "切换为正交投影"                  |
|                | 视角快照保存/恢复             | "保存当前视角" / "恢复视角"       |
| **测量分析**   | 距离测量(支持任意原子)      | "测量 Lys42 NZ 与 O3 距离"        |
|                | 角度/二面角测量               | "测量 His57 NE2-N-CA 角度"        |
|                | 清除测量                      | "删除所有测量线"                  |
| **相互作用**   | 氢键/金属配位/盐桥/疏水       | "显示氢键" / "显示锌配位键"       |
|                | 碰撞检测                      | "显示空间冲突"                    |
| **结构清理**   | 视图侧隐藏水/配体/氢          | "去掉水分子"                      |
|                | 导出过滤后结构(derive_file) | "删除 HOH 并导出"                 |
| **动画与导出** | 自动旋转                      | "开始旋转" / "停止旋转"           |
|                | 截图(支持透明背景)          | "截个图" / "透明背景截图"         |
|                | 场景快照保存/恢复             | "保存当前场景"                    |
| **信息查询**   | 结构概要/链列表/配体列表      | "这个蛋白有几条链"                |
|                | B-factor 查询                 | "查询 A 链 50 号残基的 B-factor"  |

## 架构

```
┌──────────────────────────────────────────────────────────────┐
│              WorkBuddy LLM (SKILL 编排层)                     │
│                                                              │
│  自然语言 → 命令映射 → HTTP POST /api/command                 │
│                                                              │
└──────────────────────┬───────────────────────────────────────┘
                       │
                       ▼
┌──────────────────────────────────────────────────────────────┐
│               serve_pdb.py (HTTP API + 静态文件服务)          │
│                                                              │
│  数据准备:  本地文件 /__file / COS /__cos → base64 JSON       │
│  命令路由:  POST /api/command → 入队 + SSE 推送               │
│  推送机制:  GET /api/events (SSE 实时推送到浏览器)             │
│  静态服务:  templates/viewer.html + molstar.js/css           │
│  心跳监控:  页面关闭 30s 后自动释放端口                        │
│                                                              │
└──────────────────────┬───────────────────────────────────────┘
                       │
                       ▼
┌──────────────────────────────────────────────────────────────┐
│   Mol* Viewer (WorkBuddy 内置浏览器)                          │
│                                                              │
│   Mol* 5.9.0(本地自托管,templates/molstar.js)              │
│   EventSource /api/events → 浏览器内 executeOp()             │
│   viewer.html                                                │
└──────────────────────────────────────────────────────────────┘
```

## 文件结构

```
pdb-viewer-skill/
├── SKILL.md                     # 本文件
├── templates/
│   ├── molstar.js              # Mol* 5.9.0 库(本地自托管)
│   ├── molstar.css             # Mol* 5.9.0 样式
│   ├── viewer.html             # ★ 唯一查看器(含完整 executeOp)
│   └── loading.html            # ★ 加载动画页(file:// 协议加载)
└── scripts/
    └── serve_pdb.py            # ★ HTTP 服务器(主入口)
```

## 前置依赖

### 必需:omics-platform-cli(仅 COS 场景)

本地 pdb 文件不需要 omics-platform-cli。只有访问 `cos://` 路径时才需要。

**安装方式**:

请前往 [omics-platform-cli 官方 Release 页面](https://cnb.cool/tencenthealthcareomics/omics-platform-cli/-/releases) 下载对应平台的二进制文件(`darwin-arm64` / `darwin-amd64` / `linux-amd64`),按页面说明完成安装。

**登录授权**:

```bash
omics login
# 自动打开浏览器完成平台授权(OAuth 流程)
# 登录态存储在 ~/.omics-platform-cli/auth.json
```

**验证**:

```bash
omics whoami
```

### 可选:Python 3

系统自带 Python 3 即可,`serve_pdb.py` 只用标准库(http.server / urllib / base64 / json 等),无需 pip 安装任何包。

## 使用方式

本 Skill 由 WorkBuddy (LLM) 自动调用,用户无需手动执行命令。

### 启动服务

```bash
# ★ SKILL_ROOT 必须使用实际安装路径,不能硬编码
# 获取方式(由 LLM 在运行时自动执行):
#   - 用户级安装: ~/.workbuddy/skills/pdb-viewer-skill
#   - 项目级安装: <project>/.workbuddy/skills/pdb-viewer-skill

# 方式 1: 后台启动(推荐,由 LLM 自动调用 run_in_background=true)
python3 {SKILL_ROOT}/scripts/serve_pdb.py \
  {SKILL_ROOT} \
  --pdb-file /abs/path/to/structure.pdb \
  --port 8789

# 方式 2: 仅启动服务(不指定默认 PDB,浏览器通过 ?pdb= 参数指定)
python3 {SKILL_ROOT}/scripts/serve_pdb.py \
  {SKILL_ROOT} \
  --port 8789
```

> **重要约束:`{SKILL_ROOT}` 是占位符,LLM 运行时必须替换为用户本机的实际安装路径。**

> **重要约束:只允许在 WorkBuddy 内置浏览器中打开,不允许主动打开用户本机浏览器。**

### 在 WorkBuddy 内置浏览器中打开

```python
present_files(files=["http://127.0.0.1:8789"])
# 或带 ?pdb= 参数
present_files(files=["http://127.0.0.1:8789?pdb=/abs/path/to/protein.pdb"])
```

### 通过 HTTP API 控制(自然语言操作)

服务启动后,通过 POST `/api/command` 发送命令,SSE 实时推送到浏览器执行:

```bash
# 高亮 A 链 50-100 位残基
curl -X POST http://localhost:8789/api/command \
  -H "Content-Type: application/json" \
  -d '{"op": "highlight_range", "params": {"chain": "A", "start": 50, "end": 100}}'

# 切换表示方式
curl -X POST http://localhost:8789/api/command \
  -H "Content-Type: application/json" \
  -d '{"op": "set_repr", "params": {"repr": "ball-and-stick"}}'

# 隐藏 B 链
curl -X POST http://localhost:8789/api/command \
  -H "Content-Type: application/json" \
  -d '{"op": "chain_visibility", "params": {"chain": "B", "visible": false}}'

# 获取结构信息
curl http://localhost:8789/api/status
```

## API 操作列表

### 数据加载

| `op`      | 参数                          | 说明                                |
| --------- | ----------------------------- | ----------------------------------- |
| `get_pdb` | `id`/`pdb` (str), `url` (str) | 从 RCSB ID / URL / 本地路径加载 PDB |

### 可视化控制

| `op`                    | 参数                         | 说明                                                                                                    |
| ----------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------- |
| `set_repr`              | `repr` (str)                 | cartoon / ball-and-stick / spacefill / gaussian-surface / putty / sticks / trace / dots                 |
| `set_repr_by_component` | `polymer`/`ligand`/`water`   | 分组件差异化表示                                                                                        |
| `set_color`             | `theme` (str), `value` (hex) | chain-id / element-symbol / secondary-structure / b-factor / uniform / residue-type / occupancy / plddt |
| `set_color_selection`   | `value` (hex)                | 对当前选区单独染色                                                                                      |
| `set_opacity`           | `target`, `alpha` (0-1)      | 设置透明度                                                                                              |
| `set_bg`                | `color` (str)                | CSS 颜色名或 hex                                                                                        |
| `set_water`             | `visible` (bool)             | 水分子显隐                                                                                              |

### 结构操作

| `op`                 | 参数                              | 说明                               |
| -------------------- | --------------------------------- | ---------------------------------- |
| `chain_visibility`   | `chain` (str), `visible` (bool)   | 按单链精确隐藏/显示(v1.1 已修复) |
| `ligand_visibility`  | `visible` (bool)                  | 配体整体显隐                       |
| `isolate`            | `target` (str)                    | 隔离模式(如 target=chain:A)      |
| `show_all`           | —                                 | 恢复全部显示                       |
| `hide_hydrogens`     | `visible` (bool)                  | 氢原子显隐                         |
| `show_backbone_only` | —                                 | 仅显示主链骨架                     |
| `focus_chain`        | `chain` (str)                     | 精确聚焦到链(v1.1 已修复)        |
| `focus_selection`    | —                                 | 聚焦到最近选区                     |
| `reset_view`         | —                                 | 重置视角                           |
| `save_view`          | `name` (str)                      | 保存视角快照                       |
| `restore_view`       | `name` (str)                      | 恢复视角快照                       |
| `set_projection`     | `mode` (orthographic/perspective) | 切换投影模式                       |

### 选择器

| `op`                | 参数                                     | 说明                     |
| ------------------- | ---------------------------------------- | ------------------------ |
| `highlight_range`   | `chain`, `start`, `end`, `color`         | 区间高亮残基             |
| `highlight_list`    | `chain`, `residues` (list[int]), `color` | 离散残基高亮             |
| `select_by_atom`    | `atom_name` (str)                        | 按原子名选择(如 CA)    |
| `select_by_element` | `element` (str)                          | 按元素符号选择(如 ZN)  |
| `select_ligand`     | `component_id` (str)                     | 按配体名称选择(如 ATP) |
| `select_within`     | `anchor_ligand`, `distance` (Å)          | 空间距离选择             |
| `select_by_bfactor` | `op` (gt/lt/gte/lte), `value`            | 按 B-factor 阈值选择     |
| `clear_highlights`  | —                                        | 清除所有高亮             |

### 标注

| `op`                   | 参数                              | 说明                   |
| ---------------------- | --------------------------------- | ---------------------- |
| `add_label`            | `chain`, `residue`, `text` (可选) | 为残基添加文字标签     |
| `auto_label_selection` | —                                 | 对当前选区批量添加标签 |
| `clear_labels`         | —                                 | 清除所有文字标签       |

### 测量

| `op`                 | 参数                                                             | 说明                     |
| -------------------- | ---------------------------------------------------------------- | ------------------------ |
| `measure_dist`       | `chain1`, `res1`, `atom1`(可选), `chain2`, `res2`, `atom2`(可选) | 距离测量(支持任意原子) |
| `measure_angle`      | `loci1`, `loci2`, `loci3` (chain:res:atom)                       | 三原子角度测量           |
| `measure_dihedral`   | `loci1`~`loci4` (chain:res:atom)                                 | 四原子二面角测量         |
| `clear_measurements` | —                                                                | 清除所有测量             |

### 相互作用分析

| `op`                 | 参数            | 说明                         |
| -------------------- | --------------- | ---------------------------- |
| `show_hbonds`        | —               | 显示候选氢键(基于几何阈值) |
| `show_metal_coord`   | `element`(可选) | 显示金属配位键               |
| `show_salt_bridges`  | —               | 显示盐桥                     |
| `show_hydrophobic`   | —               | 显示疏水接触                 |
| `show_clashes`       | —               | 显示空间碰撞冲突             |
| `clear_interactions` | —               | 清除所有相互作用标注         |

### 信息查询

| `op`           | 参数               | 说明                                             |
| -------------- | ------------------ | ------------------------------------------------ |
| `get_info`     | —                  | 返回链数/残基数/原子数                           |
| `list_chains`  | —                  | 枚举所有链 ID(结果通过 /api/query-result 读取) |
| `list_ligands` | —                  | 枚举配体列表及实例数                             |
| `list_models`  | —                  | 枚举 NMR 模型列表                                |
| `get_bfactor`  | `chain`, `residue` | 查询指定残基各原子 B-factor                      |

### 动画与导出

| `op`                     | 参数                                           | 说明                             |
| ------------------------ | ---------------------------------------------- | -------------------------------- |
| `spin`                   | `active` (bool), `speed` (number)              | 自动旋转 ON/OFF                  |
| `screenshot`             | `width`/`height` (可选)                        | 截图下载 PNG(支持自定义分辨率) |
| `screenshot_transparent` | —                                              | 透明背景截图                     |
| `save_pdb`               | `confirm_required`, `confirmed`, `path` (可选) | 保存 PDB(需确认弹窗)           |
| `export_selection`       | `path` (str)                                   | 导出选区为新 PDB 文件            |
| `export_filtered`        | `path`, `remove`, `keep_chains`, `keep_altloc` | 过滤后导出(derive_file 模式)   |
| `save_scene`             | `name` (str)                                   | 保存完整场景状态快照             |
| `load_scene`             | `name` (str)                                   | 恢复场景状态快照                 |
| `record_video`           | —                                              | 引导使用 Mol\* 内置录制 UI       |

## 腾讯健康组学平台 COS 支持

### 路径格式

```
cos://<bucket>/[<region>/]<key.pdb>
```

- region 可省略,脚本通过 region 白名单自动识别(非 region 字符串的路径段均视为 key 的一部分)
- key 必须以 `.pdb` 结尾(服务端校验)

### 完整工作流

```
viewer.html (?pdb=cos://...)
    ↓ fetch /__cos?uri=cos://bucket/[region/]key
serve_pdb.py /__cos 路由
    ↓ 1. 检查 omics CLI 是否安装 (~/.local/bin/omics)
    ↓ 2. 读取 ~/.omics-platform-cli/auth.json 中 session_id
    ↓ 3. 读取 ~/.omics-platform-cli/omics_config.json 中 EnvironmentId
    ↓ 4. 解析 cos:// URI → bucket + key (region 丢弃)
    ↓ 5. POST https://omics.qq.com/omics/api/cgi?method=CosBucketService.GetObjectData
         body: JSON-RPC 2.0 {jsonrpc, id, method, params: {EnvironmentId, Bucket, Key}}
         headers: Cookie: omics_session=<session_id>
    ↓ 6. 返回 JSON: {"data":"<base64>", "name":"xxx.pdb"}
viewer.html
    ↓ atob(data) → pdbText
    ↓ loadStructure(plugin, pdbText, 'pdb', name)
```

### 权限范围(严格限制)

pdb-viewer-skill 只调用以下一个接口,**不做其他任何操作**:

| 接口                                                     | 用途                                                                                                 |
| -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `POST /omics/api/cgi` (`CosBucketService.GetObjectData`) | 读取指定 COS bucket/key 下的 pdb 文件内容,session_id 作为用户身份鉴权,EnvironmentId 指定环境上下文 |

**不允许通过此 SKILL 调用 omics-platform-cli 的其他命令**(如 run/status/debug 等)。

### 环境配置

环境 ID(`EnvironmentId`)从 `~/.omics-platform-cli/omics_config.json` 中的 `EnvironmentId` 字段读取,与 omics-platform-cli 的环境配置保持一致。

已连接**正式环境**(`https://omics.qq.com`)。

## 通用 COS 访问(coscli)

### 概述

除了腾讯健康组学平台绑定的 COS 桶外,pdb-viewer-skill 还支持通过 **coscli**(腾讯云官方命令行工具)访问**任意 COS 桶**中的 PDB 文件。

### 路由策略

当用户输入 `cos://` URI 时,系统按以下逻辑自动选择通道:

```
cos://<bucket>/[<region>/]<key.pdb>
           │
           ▼
   ┌─ 解析 bucket 名称 ─┐
          │
   ┌──────┴──────────┐
   │                  │
 bucket 在            bucket 不在
 ~/.cos.yaml          ~/.cos.yaml
 的 buckets 列表中?  的 buckets 列表中?
   │                  │
   ▼                  ▼
 ┌──────────┐    ┌──────────────────┐
 │ coscli   │    │  omics 通道      │
 │ (通用桶)│    │ (平台绑定桶)     │
 └──────────┘    └──────────────────┘
```

- **优先走 coscli**:如果用户在 `~/.cos.yaml` 中显式配置了该桶,说明用户意图明确访问该桶
- **fallback 到 omics**:未配置时尝试 omics 平台绑定桶

### 前置依赖

#### 安装 coscli

```bash
# macOS (Apple Silicon / M1/M2/M3)
wget https://cosbrowser.cloud.tencent.com/software/coscli/coscli-darwin-arm64
mv coscli-darwin-arm64 coscli && chmod +x coscli
sudo mv coscli /usr/local/bin/

# macOS (Intel)
wget https://cosbrowser.cloud.tencent.com/software/coscli/coscli-darwin-amd64
mv coscli-darwin-amd64 coscli && chmod +x coscli
sudo mv coscli /usr/local/bin/

# Linux (x86_64)
wget https://cosbrowser.cloud.tencent.com/software/coscli/coscli-linux-amd64
mv coscli-linux-amd64 coscli && chmod +x coscli
sudo mv coscli /usr/local/bin/

# 验证安装
coscli --version  # 应输出 v1.0.8 或更高版本
```

> 官方下载页面: https://cloud.tencent.com/document/product/436/63144

#### 配置 coscli

首次使用需要初始化配置文件:

```bash
coscli config init
```

按交互提示输入:

1. **Secret ID**: 腾讯云 API 密钥 ID(建议使用子账号密钥,遵循最小权限原则)
2. **Secret Key**: 腾讯云 API 密钥 Key
3. **Session Token**: 直接回车跳过(当前仅支持永久密钥模式)
4. **APPID**: 腾讯云账号 APPID(从 [账号信息](https://console.cloud.tencent.com/developer) 获取)
5. **Bucket Name**: 存储桶名称(格式 `<BucketName-APPID>`)
6. **Bucket Endpoint**: 存储桶地域域名(如 `cos.ap-guangzhou.myqcloud.com`)
7. **Bucket Alias**: 存储桶别名(可选,用于简化命令)

添加更多存储桶:

```bash
coscli config add -b <bucket-name-appid> -r <region> -a <alias>
```

查看当前配置:

```bash
cosli config show
```

### 配置文件格式

coscli 配置文件位于 `~/.cos.yaml`,YAML 格式:

```yaml
cos:
  base:
    secretid: <加密存储>
    secretkey: <加密存储>
    sessiontoken: ""
    protocol: https
  buckets:
    - name: mybucket-1250000000 # 存储桶全称
      alias: mybucket # 别名(可选)
      region: ap-guangzhou # 地域
      endpoint: cos.ap-guangzhou.myqcloud.com
      ofs: false
    - name: another-bucket-123456789
      alias: another
      region: ap-beijing
      endpoint: cos.ap-beijing.myqcloud.com
      ofs: false
```

### 使用方式

与 omics COS 完全一致,统一使用 `cos://` URI 格式:

```python
# 预加载通用 COS 桶的 PDB 文件
POST /api/preload
{"uri": "cos://mybucket-1250000000/path/to/structure.pdb"}

# 或在 URL 参数中指定
present_files(["http://127.0.0.1:8789?pdb=cos://mybucket-1250000000/path/to/structure.pdb"])
```

### 权限范围

coscli 通道只执行以下操作:

| 操作                               | 用途                               |
| ---------------------------------- | ---------------------------------- |
| `coscli cp <cos_url> <local_file>` | 从 COS 下载 PDB 文件到本地临时目录 |

**不允许通过此 SKILL 调用 coscli 的其他命令**(如 mb/rm/sync 等)。

### 当前限制

- 仅支持**永久密钥**模式(Session Token 留空)
- 不支持 STS 临时密钥
- 需要用户自行安装和配置 cosli

## LLM 行为约定(核心!)

### Step 1: 启动服务并拉起内置浏览器(file:// + http 两步法)

#### 1.1 端口策略

固定使用端口 **8789**(已验证代理可访问)。

#### 1.2 ★ WorkBuddy 内置浏览器面板行为规律(必读)

present_files 是否真正 GET,取决于**面板当前显示的协议**:

| 面板当前协议           | present_files 目标     | 行为                   |
| ---------------------- | ---------------------- | ---------------------- |
| `file://`(或空白)    | `http://127.0.0.1/...` | ✅ 真正 GET,完整加载  |
| `http://127.0.0.1/...` | `http://127.0.0.1/...` | ❌ 只发 HEAD,面板不动 |

> 面板一旦加载过 localhost URL,对后续所有 localhost URL 的 present_files 都只发 HEAD,**不管 URL 是否不同、服务是否重启**。唯一出路:先用 `file://` 协议切出来。

#### 1.3 ★ 核心流程:pdb_jump 直接触发协议切换

**每次打开新结构,统一走以下流程**(不杀旧服务,pdb_jump.html 同时承担协议切换 + 跳转两个角色):

```
┌─ Step A: 启动服务(后台)────────────────────────────────────┐
│  python3 serve_pdb.py SKILL_ROOT --port 8789 --no-watchdog   │
│  等待 /__healthz 返回 session_id(最多轮询 10s)              │
└───────────────────────────────────────────────────────────────┘
         ↓
┌─ Step B: 预加载 PDB 数据到服务端缓存 ────────────────────────┐
│  POST /api/preload {"uri":"<pdb_path_or_cos_uri>"}           │
│  服务端提前读取 PDB 文件,浏览器打开时直接命中缓存             │
└───────────────────────────────────────────────────────────────┘
         ↓
┌─ Step C: 清理旧跳板 + present_files pdb_jump.html ───────────┐
│  rm -f /tmp/pdb_jump_*.html  (清理旧跳板文件)               │
│  生成含 <meta http-equiv="refresh" content="0;url=..."> 的 HTML │
│  present_files(["/tmp/pdb_jump_<ts>.html"])                  │
│  ★ 面板若在 http:// → 先切到 file://(加载 pdb_jump)        │
│  ★ meta-refresh 立刻触发 file:// → http:// 跳转              │
│  ★ 面板若在 file://(或空白)→ 同样直接跳转到 http://         │
│  服务端收到真正 GET,viewer.html 完整加载 ✅                  │
└───────────────────────────────────────────────────────────────┘
         ↓ Mol* 开始初始化(通常 5~10 秒)
┌─ Step D: 浏览器就绪后自动触发 get_pdb ───────────────────────┐
│  viewer.html SSE onopen / 轮询首次成功 时,自动 POST /api/ready │
│  服务端收到后,若有预加载缓存则立即推送 get_pdb 命令 ✅        │
│  ★ 无需 LLM sleep 等待,就绪即加载                           │
└───────────────────────────────────────────────────────────────┘
```

> ⚠️ **关键约束(已验证)**:
>
> - `present_files(本地文件)` 无论面板当前是 `http://` 还是 `file://`,都会真正导航到 `file://` ✅
> - 面板在 `http://` 时,`present_files(http://...)` 只发 HEAD 不导航 ❌ → 必须借助本地文件中转
> - 必须用 `<meta http-equiv="refresh">` 而非 JS `location.replace()`,meta-refresh 是浏览器级导航,不受 CSP 限制
> - **不再需要先杀旧服务**:新服务直接启动,旧服务会在端口冲突时自动失败或被替代
> - `loading.html` 已从默认流程移除;如需过渡动画,可手动在 Step B 之前插入

#### 1.4 完整流程代码

```python
import time
import os

# ── ★ 动态获取 SKILL_ROOT(必读)─────────────────────────────
# 优先级:用户级安装 > 项目级安装
_user_skill = os.path.expanduser("~/.workbuddy/skills/pdb-viewer-skill")
_project_skill = os.path.join(os.environ.get("PROJECT_ROOT", "."), ".workbuddy/skills/pdb-viewer-skill")

if os.path.isdir(_user_skill):
    SKILL_ROOT = _user_skill
elif os.path.isdir(_project_skill):
    SKILL_ROOT = os.path.abspath(_project_skill):
else:
    raise FileNotFoundError("找不到 pdb-viewer-skill 安装位置,请先安装该 Skill")
# ─────────────────────────────────────────────────────────────

PORT = 8789
pdb_path = "/abs/path/to/structure.pdb"

# ── Step A: 启动服务(不杀旧进程)──
# [Bash, run_in_background=true]:
#   python3 {SKILL_ROOT}/scripts/serve_pdb.py {SKILL_ROOT} --port {PORT} --no-watchdog

# 等待服务就绪(轮询 /__healthz,最多 10s)
# [Bash]:
#   for i in $(seq 1 20); do
#     result=$(no_proxy='*' curl -s http://127.0.0.1:8789/__healthz)
#     if echo "$result" | grep -q "session_id"; then echo "READY: $result"; break; fi
#     sleep 0.5
#   done

# ── Step B: 预加载 PDB 数据到服务端缓存 ────────────────────────
# [Bash]: no_proxy='*' curl -s -X POST http://127.0.0.1:{PORT}/api/preload \
#   -H "Content-Type: application/json" \
#   -d '{{"uri":"{pdb_path}"}}'

# ── Step C: 清理旧跳板文件 + 通过 meta-refresh 跳转到 http viewer ──
# ★ pdb_jump.html 同时承担两个角色:
#   1. 作为本地文件,把面板从 http:// 切到 file://(如面板已在 http:// 状态)
#   2. meta-refresh 立刻从 file:// 跳回 http://,服务端收到真正 GET ✅
# [Bash]: rm -f /tmp/pdb_jump_*.html
TS = int(time.time())
jump_html = f"""<!DOCTYPE html>
<html><head><meta charset="utf-8">
<meta http-equiv="refresh" content="0;url=http://127.0.0.1:{PORT}/view/{TS}">
<title>正在打开...</title>
<style>body{{background:#1a1d24;color:#7fd97f;font-family:monospace;
display:flex;align-items:center;justify-content:center;height:100vh;margin:0;}}</style>
</head><body><p>正在打开 PDB 查看器...</p></body></html>"""
# [Write /tmp/pdb_jump_{TS}.html]: jump_html
# [present_files]: [f"/tmp/pdb_jump_{TS}.html"]
# 面板从任意状态 → file:// → 立刻跳转到 http://127.0.0.1:{PORT}/view/{TS} ✅

# ── Step D: 浏览器就绪后自动触发(无需 LLM 主动等待)──────────
# ★ viewer.html 在 SSE onopen / 轮询首次成功时,自动 POST /api/ready
# ★ 服务端收到 /api/ready 后,若有预加载缓存则立即推送 get_pdb 命令
# ★ LLM 无需再 sleep 30 等待,整个流程至此结束
```

#### 1.5 loading.html 的定位(备用)

`templates/loading.html` 已从默认流程中移除,文件保留备用。

- 默认流程中,`pdb_jump.html` 同时承担协议切换 + 跳转,用户感知到的是"瞬间切换"
- 如需在跳转前展示过渡动画,可在 Step B(preload)之前手动插入:
  ```
  present_files(["{SKILL_ROOT}/templates/loading.html"])
  sleep <N>   # 根据需要设置展示时长
  ```
- ⚠️ loading.html 内的 JS 轮询逻辑在 `file://` 下**会被 Electron CSP 阻止**,JS 不会执行,但动画仍正常展示

#### 1.6 空闲超时

服务默认 **600 秒(10 分钟)无任何 API 调用**后自动退出,释放端口。
可通过 `--idle-timeout=0` 禁用,或 `--idle-timeout=300` 调整为 5 分钟。

### Step 2: 映射自然语言 → API 操作

| 用户意图                  | `op`                   | 示例参数                                          |
| ------------------------- | ---------------------- | ------------------------------------------------- |
| "打开 X.pdb"              | `get_pdb`              | url=本地绝对路径 或 id=RCSB_ID                    |
| "从 RCSB 加载 Y"          | `get_pdb`              | id=Y (PDB ID)                                     |
| "隐藏 X 链"               | `chain_visibility`     | chain=X, visible=false                            |
| "只看 A 链"               | `chain_visibility` × N | 逐一隐藏其他链                                    |
| "去掉水"                  | `set_water`            | visible=false                                     |
| "高亮 X 链 N-M 位"        | `highlight_range`      | chain=X, start=N, end=M                           |
| "高亮这些残基 [N,M,K...]" | `highlight_list`       | residues=[N,M,K], chain=X                         |
| "设为球棍模型"            | `set_repr`             | repr=ball-and-stick                               |
| "设为表面模式"            | `set_repr`             | repr=gaussian-surface                             |
| "全部染成红色"            | `set_color`            | theme=uniform, value="#ff0000"                    |
| "按链着色"                | `set_color`            | theme=chain-id                                    |
| "测一下 X 和 Y 的距离"    | `measure_dist`         | 根据上下文推断 chain/residue                      |
| "清除测量线"              | `clear_measurements`   | —                                                 |
| "截个图"                  | `screenshot`           | —                                                 |
| "保存当前结构"            | `save_pdb`             | confirmed=true(先发 confirm_required=true 弹窗) |
| "这个结构有什么信息"      | `get_info`             | —                                                 |
| "重置"                    | `reset_view`           | —                                                 |

### Step 3: 执行操作并反馈

1. 发送 HTTP POST `/api/command` → `{ "op": "...", "params": {...} }`
2. 命令通过 **SSE 实时推送**到浏览器(无需轮询)
3. 浏览器端 `executeOp()` 执行并更新 UI
4. 向用户反馈执行结果

### Step 4: 处理多步骤请求

对于复合指令(如 "打开 X.pdb 并高亮活性位点,隐藏配体"),按以下顺序:

1. 先加载数据(`get_pdb`)
2. 再获取 `get_info`(了解链和残基)
3. 逐个发送操作命令(SSE 即时推送,每个命令自动刷新 UI)
4. 展示结果

### 重要约束

1. **必须先加载结构才能执行其他操作**
2. 使用 `get_info` 命令获取链信息后再做链级操作
3. 残基编号需要从 `get_info` 结果中确认
4. `set_repr` 的 repr 参数使用 kebab-case(如 `ball-and-stick`),不是 snake_case
5. 如果命令失败,向用户报告错误原因并建议修正
6. **只允许在 WorkBuddy 内置浏览器中打开,不允许主动打开用户本机浏览器**
7. **浏览器页面默认不显示命令日志面板**;调试时在 URL 追加 `?debug=1` 可开启

### save_pdb 特殊说明

**save_pdb 操作支持两种模式:**

#### 模式 A: 覆盖已有文件(本地文件加载时)

```bash
# Step 1: 请求用户确认
POST /api/command {"op": "save_pdb", "params": {"confirm_required": true}}

# Step 2: 用户确认后执行(自动备份原文件为 .bak)
POST /api/command {"op": "save_pdb", "params": {"confirmed": true}}
```

#### 模式 B: 保存到指定路径(URL/COS 加载时,或另存为)

当从 RCSB URL 或 COS 加载 PDB 后,原始文件不在本地,需要用户提供保存路径:

```bash
# Step 1: 设置保存路径 + 请求确认
POST /api/command {
  "op": "save_pdb",
  "params": {
    "confirm_required": true,
    "path": "/tmp/my-structure.pdb"
  }
}

# Step 2: 用户确认后执行
POST /api/command {"op": "save_pdb", "params": {"confirmed": true}}
```

**LLM 行为规范:**

- 如果 PDB 是从**本地文件**加载的,直接执行两步确认即可
- 如果 PDB 是从 **URL/RCSB/COS** 加载的,**必须先询问用户要保存到哪里**,并将路径放入 `path` 参数

## 关键 API 陷阱

**molstar 5.x 必须用 `molstar.Viewer.create(...).then(viewer => {...})`,绝不能用 `new molstar.Viewer(...)`。**

详见注释。参考: <https://github.com/molstar/molstar/issues/631>

## 浏览器面板

- 通过 `present_files(files=["http://127.0.0.1:8789"])` 打开
- 鼠标操作:左键旋转、右键平移、滚轮缩放
- 左侧面板可切换 cartoon / ball-and-stick / surface 等表示
- 调试日志:URL 追加 `?debug=1` 显示命令执行面板

## 安全与隔离

- 服务器仅绑定 `127.0.0.1`,不暴露到局域网
- session_id 仅用于调用 `CosBucketService.GetObjectData`,不通过 HTTP 暴露给浏览器
- Mol\* 库本地自托管,无 CDN 依赖

## 发布前清理清单

在将此 Skill 发布给其他用户前,完成以下验证:

1. 功能测试:加载 PDB、执行命令等核心流程正常

## 常见问题

**Q: COS PDB 加载失败,提示 "omics-platform-cli 未安装"。**
A: 请前往 [omics-platform-cli 官方 Release 页面](https://cnb.cool/tencenthealthcareomics/omics-platform-cli/-/releases) 下载并安装对应平台的二进制文件,安装完成后重试。

**Q: COS PDB 加载失败,提示 "未检测到 omics 登录凭证" 或 "已过期"。**
A: 执行 `omics login` 完成登录授权,然后重试。

**Q: COS PDB 加载失败,提示 "GetObjectData 失败"。**
A: 可能原因:

1. bucket/key 不存在
2. 当前用户没有该 bucket 的访问权限
3. EnvironmentId 配置错误或未配置(执行 `omics config set` 检查)
4. 服务端尚未将 GetObjectData 开放到外部路由

**Q: 浏览器打开后显示 "未指定 PDB 文件"。**
A: 启动服务时未通过 `--pdb-file` 指定默认文件,也未在 URL 中带 `?pdb=` 参数。使用 `get_pdb` 命令加载文件,或重启服务时指定 `--pdb-file`。

**Q: 想换 Mol\* 版本怎么办?**
A: 下载新版 `molstar.js` 和 `molstar.css` 替换 `templates/` 下的文件,同时更新本 SKILL.md 版本号。

**Q: 如何确认 SKILL_ROOT 是否正确?**
A: 在运行时查看 LLM 日志,应该能看到类似输出:

```
[pdb-viewer] serving /Users/<user>/.workbuddy/skills/pdb-viewer-skill at http://127.0.0.1:8789
```

如果报错 `找不到 pdb-viewer-skill 安装位置`,说明 Skill 未正确安装到预期路径。

**Q: 通用 COS 桶的 PDB 加载失败,提示 "coscli 未安装"。**
A: 请按以下步骤安装 coscli:

```bash
# macOS (Apple Silicon)
wget https://cosbrowser.cloud.tencent.com/software/coscli/coscli-darwin-arm64
mv coscli-darwin-arm64 coscli && chmod +x coscli
sudo mv coscli /usr/local/bin/
coscli --version
```

然后执行 `cosli config init` 完成配置(输入 SecretId、SecretKey、APPID、Bucket 信息等)。

**Q: 通用 COS 桶加载失败,提示 "coscli 配置文件不存在"。**
A: 请执行 `cosli config init` 初始化配置文件。配置完成后,目标桶名称会出现在 `~/.cos.yaml` 的 `cos.buckets` 列表中。

**Q: 通用 COS 桶加载失败,提示 "coscli cp 失败"。**
A: 可能原因:

1. bucket 名称或 key 路径不正确
2. 当前密钥没有该桶的读取权限(需要 `cos:GetObject` 权限)
3. 网络连接问题

请检查 `~/.cos.yaml` 中该桶的配置是否正确,或手动运行 `cosli cp cos://<bucket>/<key> /tmp/test.pdb` 排查。

**Q: 我的 COS 桶同时配置了 omics 和 coscli,会走哪条路?**
A: **优先走 coscli**。如果桶名称出现在 `~/.cos.yaml` 的 `buckets` 列表中,系统认为用户显式配置了该桶,会使用 coscli 通道。如需强制走 omics,可从 coscli 配置中移除该桶。

Files in this skill

  • SKILL.md40.1 KB
  • scripts/debug_logger.py6.5 KB
  • scripts/handlers/__init__.py111 B
  • scripts/handlers/api_routes.py9.4 KB
  • scripts/handlers/cos_handler.py14.9 KB
  • scripts/handlers/pdb_filter.py3.4 KB
  • scripts/handlers/preload.py1.1 KB
  • scripts/handlers/sse_queue.py3 KB
  • scripts/handlers/static_server.py9.6 KB
  • scripts/serve_pdb.py34.3 KB
  • scripts/state.py2.4 KB
  • templates/js/debug-logger.js3.5 KB
  • templates/js/executor.js5.3 KB
  • templates/js/loader.js6.3 KB
  • templates/js/ops/a1-load.js3.2 KB
  • templates/js/ops/a10-interact.js4.1 KB
  • templates/js/ops/a11-query.js7.5 KB
  • templates/js/ops/a12-export.js9.9 KB
  • templates/js/ops/a2-select.js20.1 KB
  • templates/js/ops/a3-visibility.js13.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in development →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.