文档整理

This commit is contained in:
Ukawka
2026-09-21 00:23:16 +08:00
parent fe4ee1a08e
commit e9072aecf2
6 changed files with 643 additions and 866 deletions
+118
View File
@@ -17,3 +17,121 @@
- 测试在 `ai-spine` 环境下执行:`conda run -n ai-spine npm test`。不要为了绕过依赖问题临时新建环境。
- 验证结果必须如实记录;缺少依赖导致未运行的检查,不得声称通过。
- 保留用户已有修改和实验产物,不覆盖旧实验输出。
## 跨会话上下文与阅读顺序
本节于 2026-09-21 根据当前代码与已检查产物整理。它是后续对话的上下文入口;后续修改应同步更新对应状态,实际源码、配置和具体实验 manifest 优先于历史总结。不要把旧实验统计套到新输出上。
1. 先阅读本文件和 `git status --short`,保留用户已有修改。
2. 阅读 [README](README.md) 了解项目、环境、配置与命令。
3. 按任务阅读 [第一阶段](docs/1-understanding-stage.md)、[第二阶段](docs/2-segmentation-stage.md)、[第三阶段](docs/3-completion-stage.md),再核对相关实现与实际产物。
4. 用户说“继续”时,先核对工作区和最近任务进展,不能只凭历史总结重复请求付费模型或覆盖实验。
## 用户目标与固定偏好
- 目标是将单张 2D 角色图拆成可以用于 Spine 的部件,保留画风、姿态、左右、不对称性及原有像素关系,补足遮挡和关节连接。
- 第二阶段使用本地 SAM 代码和权重,通过临时 Conda 子进程在本机 GPU 推理,完成后退出;不部署常驻独立服务。
- 需要可直接执行的 PowerShell 命令;说明当前已实现行为、实测结果与未来计划,不能把几何通过写成资产合格。
- 不确定的部件语义、遮挡和候选点需要复核,不得用前景检查、覆盖率或模型分数代替语义准确性。
- 输出使用独立目录,保留原候选和诊断;已有候选优先离线复检,避免无意义重复生成。
## 文档维护约定
- 各文档文件名保持不变。`docs/` 当前保留三份阶段文档;`docs/model-stages.md` 在本次文档整理前已处于用户删除状态,不自行恢复,相关说明归入 README 和阶段文档。
- 三份阶段文档有且仅有以下八个二级章节,细节必须归入对应章节:
1. 阶段简介
2. 输入、输出与执行链路
3. 阶段执行命令示例及参数说明
4. 输入格式要求
5. 执行链路中重要部分代码文件及原理说明(包括重点说明)
6. 各个代码文件职责索引
7. 产物详细说明
8. 当前阶段可改进点说明
- 外层 README 负责整体介绍、Conda 准备、配置及每阶段命令;本文件负责约定和后续会话必要上下文。已存在的环境与修改约定必须保留。
- 改进项明确写为待实现/待验证;实现后更新状态、命令、产物说明及本文件。PowerShell 反引号后不能有空格;示例变量先定义,示例输出目录相互独立。
## 工作区、环境与配置
- 当前实际项目目录:`F:\Study\taonier\AI_spine`。用户历史命令也出现过 `F:\Study\taonier\AI\_spine`,不要盲目复制旧路径,先确认 cwd。
- 当前 SAM 根目录为 `F:\Study\SAM3`;源码仓库 `F:\Study\SAM3\sam3`;权重 `F:\Study\SAM3\sam3.1checkpoint\sam3.1_multiplex.pt`。早期 `F:\Study\sam3.1` 已不是当前约定路径。
- 已验证组合:Python 3.11、torch 2.7.1+cu126、torchvision 0.22.1、NumPy 1.26.4、OpenCV 4.11.0.86;RTX 3060 Laptop 6 GB。机器环境可能变化,执行前按需探测。
- Node.js >=20,无额外 npm 运行时依赖。自动化使用 Conda ai-spine 执行 Node/Python;运行 SAM 可用 `conda run --no-capture-output -n ai-spine node ...`。
- 默认配置是 `configs/astra-qwen.json`;示例推荐明确传 config,避免环境变量导致选错提供方。
- `configs/deepseek-qwen.json`:deepseek-flash / Chat Completions / 非流式;补全 qwen-image-3.0。
- `configs/astra-qwen.json`:gpt-6-astra / Responses / 流式;补全 qwen-image-3.0。
- 上述两份读取 VECTOR_ENGINE_BASE_URL / VECTOR_ENGINE_API_KEY,模型变量为 SPINE_UNDERSTANDING_MODEL / SPINE_COMPLETION_MODEL。
- `configs/tiantoken.json`:独立 TIANTOKEN_BASE_URL / TIANTOKEN_API_KEY,地址 https://api.tiantoken.com;理解 gpt-6-astra,补全 gpt-image-2;模型变量为 TIANTOKEN_UNDERSTANDING_MODEL / TIANTOKEN_COMPLETION_MODEL。
- CLI 模型 > stage.model > 对应模型环境变量 > default_model;shell 同名变量优先于 .env。模型 ID 原样发送,不加隐式别名。
- 用户提供的密钥仅留在本地忽略的 `.env`;禁止在文档、命令日志、聊天或提交中暴露,不要读取/打印完整 .env 来诊断。
- 三份配置的图片编辑能力均为 multiple_images=false、mask=false。接口已预留分支不代表中转已支持;开启前需验证。Astra 理解接口与图片编辑接口不同,当前没有 Astra Responses 图片生成工具链。
## 三阶段实现与不能丢失的边界
### 第一阶段:理解与几何候选
- 入口 `tools/model-check.mjs --stage understanding`,或 `pipeline.mjs --mode annotated-parts`;后者仅转发新入口。
- `stages/model-stage.mjs` 调用视觉模型,`lib/validate-parts.mjs` 校验 v2:rig_role、bind_to、三项 completion 及 needs_completion 一致性。
- `normalize_reference.py` 保留原画布,使用 Alpha 或边界连通近白背景处理;`geometry_grounding.py` 用 Alpha/ROI 距离变换生成候选,不是再次请求 AI。
- 模型原始点仅诊断;程序候选也未获语义确认;pivot 独立保留,不吸附前景。
- 第二阶段输入必须为同一实验的 source.png、semantic-parts.json、segmentation-prompts.json。
- `--parts-file` 可离线迁移 v1/检查 v2 并生成新候选;旧 annotated.svg 不会自动更新。
### 第二阶段:SAM 可见拆件
- 入口 `--stage segmentation --input-dir 理解目录`;实现为 stages/segmentation-stage.mjs、sam_runtime.py、sam_segment.py、segmentation_outputs.py。
- 环境探测与推理分别为短期子进程,禁止在线下载权重。multiplex detector 适配实际严格加载 1130 个张量,忽略 36 个未使用视频 neck 张量;不要因此改成 strict=False 或修改外部 SAM 源码。
- BF16 仅用于推理 autocast;不要整体转换模型而破坏复数缓冲区/FP32 路径。
- 使用文本和文本+粗框两组候选;当前图像概念接口未接收点提示,Alpha 种子仅参与 mask 排序。
- 与原图 Alpha 取交集后提取原像素;mask 为原画布二值图,parts 为紧裁剪 RGBA。重叠保留、覆盖率仅为像素覆盖,semantic_verified=false。
- annotated.png 为原图纹理上半透明颜色叠加,parts-sheet.png 为白底拆件;纯色遮罩角色图与可选大模型去毛边尚未实现。
### 第三阶段:受限部件补全
- 入口 `--stage completion --input-dir SAM目录`;实现为 stages/completion-stage.mjs、completion_geometry.py、providers/image-edits.mjs。
- 输入须含 source.png、v2 计划、segmentation.json 及所有记录的全画布 masks;单独 parts/ 不够。
- 仅处理 needs_completion=true、非隐藏、有可见 mask 且允许区域非空的部件。--part 不绕过筛选;目前不重新评估 SAM 缺损。
- 默认 1024 方形局部画布,原像素不缩放。允许区来自轮廓外 32 像素范围与遮挡 mask / pivot 圆盘交集,排除可见 mask;不是完整隐藏形状生成。
- 当前真实请求只发白底 input.png;context.png、edit-mask.png 默认不发送。开启 multiple_images 也只是发送同坐标局部 context,并非独立全角色参考。
- 图片解码已修复“空 b64_json 但有有效 URL”情况,回退下载 URL;该问题与画布尺寸不符不同。
- 在线请求现显式传 size,配置冲突失败。strict 默认拒绝尺寸不同;uniform 仅恢复同宽高比整画布尺寸,保留原候选,继续原有验收,不单独移动/缩放物体。
- 验收阈值:可见不透明像素 RGB MAE≤30、保留率≥95%;有效新增须在允许区且连接可见部件;原可见 RGBA 随后逐像素恢复。
- unfulfilled_regions 当前只记录、不硬拒绝;语义错误、接缝、关节补够与否尚无可靠验收。错误 SAM 可见像素会被强制保留。
- prepare-only 不联网;candidates-dir 可读平铺 ID.png 或匹配 manifest 的旧任务首张候选。--resume 不是失败断点续发,准备/生成/复检使用独立目录。
- parts/ 只含通过检查的补全部件,不包含全部原拆件。完整角色组装、旋转验收、新管线 Spine 导出尚未接入。
- 旧 `--stage completion --image ... --prompt-file ...` 是接口探针,不能和 input-dir 混用,不执行完整几何验收。
## 已检查实验与质量结论
以下为已有实验记录,不代表后续每次运行的结果;不必为了文档修改重跑 GPU 或付费模型。
| 目录(相对于项目) | 事实与意义 |
| --- | --- |
| output/sombrero-grounding-v2 | 旧计划离线几何检查,28 个程序候选通过前景检查;未证明语义正确 |
| output/sombrero-sam31-v3 | 较早 SAM 实验,28 个 mask,约 67.18% 覆盖率;肢体/鞋子重复、漏分,不合格 |
| output/20260918-183532/sam | 当前讨论基线:32 个计划项、10 个 hidden、22 个 mask;约 83.3% 覆盖,32719 像素未分配;前臂/手混入衣料、袖子与上衣缺损 |
| output/20260918-183532/complete2_gpt | 真实 Tiantoken gpt-image-2 请求 12 部件;旧请求未传 size,返回 1248/1254,预期 1024,全部 CANVAS_SIZE_MISMATCH |
| output/20260918-183532/complete2_gpt-size-recheck-v2 | 离线 uniform 复检,未重生成:8 个几何通过;head、pants_thigh_l、pants_thigh_r、shoe_l 4 个拒绝;通过项仍有误分和未完成区域 |
| output/20260918-183532/complete-recovered-head-check | 更早 Qwen 头部候选恢复检查,不能与 GPT 批次混为一谈 |
- 当前 22→12 的原因:sombrero、sleeve_l、sleeve_r、eye_l、eye_r、eyebrow_l、eyebrow_r、nose、mouth、mustache 共 10 个被第一阶段标记 NO_COMPLETION_NEEDED;不能解释为它们的实际 SAM mask 已完整。
- 2026-09-20 尺寸修复后曾通过 22 项 Node 测试(含 Python 补全回归)。这是历史验证;新改动按范围重新验证,不自动沿用“全部通过”。显式 size 构造已测试,修复后中转是否遵守尚无新实测。
- 总体判断:上游部件归属、模型缺少原图参考与遮罩、区域规则粗糙、验收不足共同导致低质量。不能仅换模型、强制处理全部 mask、放宽阈值或解决尺寸错误就宣称修好。
## 当前改进方向与后续顺序
本轮用户要求重整文档,以下功能是待实现需求,不因写入文档就成为已完成功能:
1. 第二阶段输出仅色彩遮罩组成的完整角色图,保留当前原图叠色预览,并明确未分配/重叠区域。
2. 第二阶段每个 SAM 部件可选经过一次大模型去毛边,保留原始拆件、原图参考、坐标、变更区域与前后对照。
3. 第三阶段将角色原图或部件相关原图局部作为参考交给补全模型,验证中转多图/遮罩能力及实际发送内容。
4. 第三阶段输出使用补全部件组装的完整角色,复用无需补全的原部件,明确失败/回退状态。
5. 技术优先级:先修正 SAM 部件归属与输入门槛,再按实际 mask 重建补全计划;用头、前臂、上衣三类小样验证参考图和遮罩,然后增加回贴与关节旋转验收,最后批量与 Spine 导出。
详细改进说明保留在各阶段文档第 8 节;若后续用户改变优先级,应更新此处。
## 旧管线与范围识别
- `pipeline.mjs` 未指定 --mode annotated-parts 时走旧“生成拆件图→CV 定位→Spine”流程,不是新三阶段自动串联。
- `segment.py` 为旧拆件图分割;`compose_preview.py` 为旧布局组装;`run_case_matrix.py` 为旧定位对照工具。不要因为 IDE 当前打开这些文件就误改新阶段入口。
- 相邻 `spine-animation-ai` 为外部只读依赖,保留其 PolyForm Noncommercial 许可证约束;新阶段尚未复用为完成的导出流程。
- 不要把文档改写任务扩大成付费图片生成、SAM 推理、依赖安装或功能实现;需要实现时遵从用户后续任务范围。
+141 -170
View File
@@ -1,83 +1,45 @@
# AI Spine 角色拆件与动画管线
本项目用于把单张 2D 角色参考图转换为可供 Spine 动画使用的语义部件、透明拆件和骨骼资源。
本项目探索将单张 2D 角色图转换为可用于 Spine 动画的部件与骨骼资源。当前主线分为三个阶段:视觉 LLM 理解结构、本地 SAM 分割可见部件、图片编辑模型补全隐藏区域和关节连接。
当前正在实现的新管线分为三个核心阶段:
| 阶段 | 输入 → 输出 | 当前状态 |
| --- | --- | --- |
| 1. 结构理解 | PNG → v2 语义计划、粗框、pivot、程序候选点 | 可在线理解或离线复检;语义待复核 |
| 2. SAM 分割 | 第一阶段目录 → mask、原像素透明部件、标注图与拆解图 | 本机 GPU 实测可运行;存在误分与漏分 |
| 3. 部件补全 | SAM 目录 → 局部编辑候选、几何 QA、通过检查的补全部件 | 已真实调用图片模型;结果质量尚不合格 |
1. 视觉 LLM 输出语义、层级、骨骼/附件分类、遮挡、粗框和粗关节;程序用 Alpha 检查 ROI 并生成候选种子。
2. 使用 SAM 根据语义、粗框和程序候选生成 mask,经语义/几何检查后从原图提取可见像素。
3. 使用图片编辑模型补全被遮挡的部件,再进行几何验收和 Spine 导出。
第三阶段尚未输出使用补全部件组装的完整角色,新管线 Spine 导出也未完成。执行成功、mask 覆盖率高、几何检查通过,均不等于动画资产可用。
目前第一、二阶段可运行,第三阶段已接入部件画布准备、图片编辑请求、候选几何检查及可见像素恢复。第二阶段在 `ai-spine` Conda 环境的临时子进程中加载本地 SAM 3.1 权重,使用 GPU 分割并生成半透明标注图、白底拆解图和透明部件。分割与补全结果仍需语义复核;新管线的 Spine 导出尚未完成。第三阶段已通过离线及 mock 接口验证,真实图片编辑质量尚待验证。
仓库保留旧版“生成白底拆件图 → OpenCV 拆分 → Genielabs 定位 → Spine 导出”作为对照;它与当前三阶段主线并存,产物不能直接混用。
仓库仍保留旧版“AI 生成白底拆件图 → OpenCV 拆分 → Genielabs 定位 → Spine 导出”流程,用于对照和回归测试。
## 文档入口
## 文档
- [AGENTS.md](AGENTS.md):修改约定、跨会话上下文、当前基线及后续优先级。
- [第一阶段](docs/1-understanding-stage.md):理解、数据契约、Alpha 候选与粗标注。
- [第二阶段](docs/2-segmentation-stage.md):本地 SAM、mask 选择、拆件与质量边界。
- [第三阶段](docs/3-completion-stage.md):筛选、局部画布、图片请求、几何验收及补全改进。
- [项目修改约定](AGENTS.md):每次修改都必须遵守,Python 固定使用 `ai-spine` Conda 环境。
- [第一阶段:视觉 LLM 角色结构理解](docs/1-understanding-stage.md):执行流程、代码对应关系、数据格式和输出文件。
- [第二阶段:本地 SAM 分割](docs/2-segmentation-stage.md):环境、运行命令、权重适配、输出和质量边界。
- [第三阶段:部件补全](docs/3-completion-stage.md):局部画布、遮挡/关节延展区域、生成调用、可见像素恢复及几何检查。
- [模型阶段配置与实验说明](docs/model-stages.md):模型切换、协议适配、图片编辑探针、缓存和错误处理。
阶段文档统一采用八节:简介;输入输出与链路;命令参数;输入格式;重要代码原理;职责索引;产物;可改进点。配置与实验说明已归入上述文档。
## 环境准备
## Conda 环境准备
### Node.js
所有 Python 操作固定使用 **ai-spine**,不使用 `.venv`、其他虚拟环境、Conda base 或系统 Python。Node.js 要求 20 或以上;项目没有额外 npm 运行时依赖。
第一阶段要求 Node.js 20 或更高版本,以及下方 Python 几何依赖;没有额外 npm 运行时依赖。
在 PowerShell 中进入实际项目根目录。本工作区路径如下;若本机使用其他目录,仅替换这一行:
```powershell
Set-Location F:\Study\taonier\AI_spine
node --version
conda run -n ai-spine npm test
conda env list
```
### 中转站配置
在项目目录复制环境变量模板:
仅在没有 ai-spine 环境的新机器上,手动创建一次;当前机器已有环境则跳过:
```powershell
Copy-Item .\.env.example .\.env
conda create -n ai-spine python=3.11 -y
```
编辑 `.env`:
```dotenv
VECTOR_ENGINE_BASE_URL=https://router.genarrative.world/v1
VECTOR_ENGINE_API_KEY=你的令牌
# 可选:覆盖配置文件中的默认模型
SPINE_UNDERSTANDING_MODEL=deepseek-flash
SPINE_COMPLETION_MODEL=qwen-image-3.0
# 本地 SAM 根目录和源码仓库;分割结束后子进程退出
SAM_MODEL_DIR=F:/Study/SAM3
SAM_CODE_DIR=F:/Study/SAM3/sam3
```
模型 ID 会原样发送给中转站,不进行隐式别名转换。不要把 API Key 写进 JSON 配置或提交到版本库。
另一个中转站 Tiantoken 使用独立配置 [configs/tiantoken.json](configs/tiantoken.json)。在本地 `.env` 设置 `TIANTOKEN_BASE_URL=https://api.tiantoken.com` 和 `TIANTOKEN_API_KEY`,运行时增加 `--config .\configs\tiantoken.json`;原中转站配置保持独立。
```powershell
node .\tools\model-check.mjs --config .\configs\tiantoken.json --list-models
node .\tools\model-check.mjs --config .\configs\tiantoken.json --dry-run
```
该配置默认第一阶段使用 `gpt-6-astra`(Responses),第三阶段使用 `gpt-image-2`(images/edits),可通过 `TIANTOKEN_UNDERSTANDING_MODEL`、`TIANTOKEN_COMPLETION_MODEL` 或对应 CLI 参数覆盖。2026-09-20 已验证认证与模型列表访问,返回 113 个模型,含上述两个 ID;尚未验证实际理解、图片编辑或 Responses 图片生成工具能力。此配置不等于已接入 Astra 主导的第三阶段图片生成。
### Python 与外部项目
本项目固定使用 **Conda 环境 `ai-spine`**,不使用或创建 `.venv`。第一阶段的 Alpha 校验需要 Python 3、`Pillow`、`numpy`、`opencv-python`。
执行项目命令前先 `conda activate ai-spine`。Node 管线会检查 Python 属于该 Conda 环境;`--python` 也只能指定该环境的解释器。未激活环境或缺少依赖时会报错,不会自动创建环境或安装依赖。
旧版拆件和 Spine 导出还需要:
- Python 3;
- `Pillow`、`numpy`、`opencv-python`;
- 相邻目录中的 `spine-animation-ai` 项目。
当前本机验证组合为 Python 3.11、PyTorch 2.7.1 + CUDA 12.6、torchvision 0.22.1。在 `AI_spine` 目录补全依赖;已有此 CUDA 版本时跳过第一条安装命令:
补齐项目依赖。以下是本机已验证的 CUDA 12.6 组合;已有匹配 PyTorch 时可跳过第一条安装命令。代码不会自动安装依赖或创建环境。
```powershell
conda activate ai-spine
@@ -86,174 +48,183 @@ python -m pip install -r .\requirements.txt
python -m pip install --no-deps --no-build-isolation -e F:\Study\SAM3\sam3
```
不激活终端也可明确指定安装目标:
不激活终端时,明确指定目标环境:
```powershell
conda run -n ai-spine python -m pip install -r .\requirements.txt
```
检查解释器和依赖:
本地 SAM 代码和权重由用户提供,当前位置为:
```powershell
conda run -n ai-spine python -c "import sys, cv2, PIL, numpy; print(sys.executable); print('Dependencies OK')"
```text
F:/Study/SAM3/sam3/ 源码仓库
F:/Study/SAM3/sam3.1checkpoint/sam3.1_multiplex.pt 权重
```
`spine-animation-ai` 是外部只读依赖,使用时需要遵守其 PolyForm Noncommercial 许可证。
## 常用命令
以下命令默认在 `AI_spine` 目录、已激活的 `ai-spine` Conda 环境中运行。自动化可使用 `conda run -n ai-spine node ...`。
### 查询中转站模型
检查解释器、基础依赖与 GPU:
```powershell
node .\tools\model-check.mjs --list-models
conda run -n ai-spine python -c "import sys, cv2, PIL, numpy, torch; print(sys.executable); print('torch', torch.__version__); print('CUDA', torch.cuda.is_available()); print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'No CUDA GPU')"
```
### 检查本地配置
第二阶段要求可用 CUDA GPU。本机已验证 RTX 3060 Laptop 6 GB;默认 BF16 推理保留模型参数和缓冲区所需精度。第一、三阶段的本地几何处理不运行 SAM。Node 入口会验证 Python 属于 ai-spine;`--python` 也不能绕过此约定。
不请求模型,也不生成付费内容:
## 中转站配置
仅在本地 `.env` 不存在时复制模板,随后自行填写密钥:
```powershell
node .\pipeline.mjs --mode annotated-parts `
if (-not (Test-Path .\.env)) { Copy-Item .\.env.example .\.env }
```
```dotenv
# 原中转站
VECTOR_ENGINE_BASE_URL=https://router.genarrative.world/v1
VECTOR_ENGINE_API_KEY=填写你的令牌
# Tiantoken 独立配置
TIANTOKEN_BASE_URL=https://api.tiantoken.com
TIANTOKEN_API_KEY=填写你的令牌
# 本地 SAM
SAM_MODEL_DIR=F:/Study/SAM3
SAM_CODE_DIR=F:/Study/SAM3/sam3
```
不要把密钥写入文档、JSON 配置或提交到版本库;不要输出 `.env` 内容。
| 配置文件 | 第一阶段 | 第三阶段 | 模型环境变量 |
| --- | --- | --- | --- |
| [deepseek-qwen.json](configs/deepseek-qwen.json) | deepseek-flash,Chat Completions,非流式 | qwen-image-3.0,images/edits | SPINE_UNDERSTANDING_MODEL / SPINE_COMPLETION_MODEL |
| [astra-qwen.json](configs/astra-qwen.json) | gpt-6-astra,Responses,流式 | qwen-image-3.0,images/edits | 同上 |
| [tiantoken.json](configs/tiantoken.json) | gpt-6-astra,Responses,流式 | gpt-image-2,images/edits | TIANTOKEN_UNDERSTANDING_MODEL / TIANTOKEN_COMPLETION_MODEL |
CLI > 配置 stage.model > 对应模型环境变量 > default_model;shell 环境变量优先于 `.env`。不指定配置时入口默认 astra-qwen.json,建议实验始终显式指定。模型 ID 原样发送,中转能力以实际请求为准。Tiantoken 图片编辑已真实执行;第三阶段尚未适配 Astra Responses 图片生成工具。
三个配置当前均关闭多图参考与编辑 mask 能力。第三阶段默认只发送白底单部件图;本地 context.png/edit-mask.png 已生成但不默认发送。改进计划见第三阶段文档。
查询模型列表和检查配置:
```powershell
node .\tools\model-check.mjs --config .\configs\tiantoken.json --list-models
node .\tools\model-check.mjs --config .\configs\tiantoken.json --dry-run
```
前者联网,后者不请求模型;列表存在某个 ID 不代表其所有能力已验证。
## 三阶段执行命令
以下命令按顺序在同一个 PowerShell 会话执行。反引号后不能带空格。每次实验使用新的 runId;分阶段重开终端时,将路径变量设置成已有的对应目录。
```powershell
conda activate ai-spine
$runId = Get-Date -Format "yyyyMMdd-HHmmss"
$runRoot = ".\output\$runId"
$reference = ".\output\20260918-183532\sam\source.png"
```
示例复用现有角色原图,可替换 `$reference` 为自己的 PNG。不要混用不同实验的 source、计划和 mask。
### 第一阶段:理解角色结构
此命令调用视觉模型:
```powershell
node .\tools\model-check.mjs --stage understanding `
--config .\configs\deepseek-qwen.json `
--reference ..\spine-animation-ai\demo\character_reference.png `
--dry-run
--reference $reference `
--out-dir "$runRoot\understand"
```
### 使用 DeepSeek Flash 理解角色结构
检查 `understand/report.html`、`semantic-parts.json`、`geometry-validation.json`。程序候选点来自 Alpha 距离变换,落在前景不代表属于正确部件。
当前已验证可用的配置是 `deepseek-flash + chat-completions + stream=false`:
已有计划可离线重新检查;输出独立目录,不重跑模型:
```powershell
node .\pipeline.mjs --mode annotated-parts `
--config .\configs\deepseek-qwen.json `
--reference ..\spine-animation-ai\demo\character_reference.png `
--out-dir .\output\sombrero-understand-deepseek `
--stop-after understand
node .\tools\model-check.mjs --stage understanding `
--reference .\output\20260918-183532\sam\source.png `
--parts-file .\output\20260918-183532\sam\semantic-parts.json `
--out-dir "$runRoot\understand-offline"
```
重点检查输出目录中的:
- `report.html`:人工复核页面;
- `semantic-parts.json`:v2 语义计划,包含 `rig_role`、`bind_to`、三项 `completion`;
- `geometry-validation.json`:原始点诊断、框内前景比例、候选及阻塞原因;
- `segmentation-prompts.json`:程序生成的 SAM 候选提示;模型原始正负点不会传入;
- `validation.json`:本地结构校验结果;
- `manifest.json`:模型、输入、代码版本和产物记录。
输入保留画布尺寸。已有透明背景直接保留 Alpha;不透明白底只移除与边界连通的近白区域。其他背景需先提供抠图 PNG。候选来自粗框内前景的距离变换,不能保证属于目标部件,仍需语义复核。关节点不会吸附到前景。
已有结果可离线检查,无需再次请求模型:
### 第二阶段:本地 SAM 分割
```powershell
node .\tools\model-check.mjs `
--reference .\output\sombrero-understand-deepseek-flash\source.png `
--parts-file .\output\sombrero-understand-deepseek-flash\semantic-parts.json `
--out-dir .\output\sombrero-grounding-review
```
旧版 v1 计划会保守迁移到 v2,迁移推断写入 notes,仍需复核;原文件不覆盖。
### 使用 GPT-6 Astra 做对照实验
```powershell
node .\pipeline.mjs --mode annotated-parts `
--config .\configs\astra-qwen.json `
--reference ..\spine-animation-ai\demo\character_reference.png `
--out-dir .\output\sombrero-understand-astra `
--stop-after understand
```
当前中转站的 Astra 通道要求 Responses 协议和流式响应。若中转站返回 overloaded,应使用新的输出目录稍后重试。
### 临时覆盖理解模型
```powershell
node .\pipeline.mjs --mode annotated-parts `
--config .\configs\deepseek-qwen.json `
--understanding-model YOUR_EXACT_MODEL_ID `
--understanding-protocol chat-completions `
--stream false `
--reference .\reference.png `
--out-dir .\output\model-experiment `
--stop-after understand
```
每组模型实验应使用独立的输出目录,避免覆盖对照结果。只有输入、配置、代码和产物哈希全部一致时,才可以通过 `--resume` 复用结果。
### 使用本地 SAM 生成标注和拆解图
复用已有第一阶段结果,不重新请求 DeepSeek,也不需要中转站密钥:
```powershell
conda run --no-capture-output -n ai-spine node .\tools\model-check.mjs `
--stage segmentation `
--input-dir .\output\sombrero-grounding-v2 `
--out-dir .\output\sombrero-sam-local `
node .\tools\model-check.mjs --stage segmentation `
--input-dir "$runRoot\understand" `
--out-dir "$runRoot\sam" `
--sam-dir F:/Study/SAM3
```
打开输出目录的 `report.html`:`annotated.png` 是原图上的不同半透明颜色标注,`parts-sheet.png` 是白底拆解图,`parts/` 保存原像素透明部件。运行期间加载 GPU 权重,完成后子进程退出,不启动常驻服务。
若使用前面的离线计划,input-dir 改为 understand-offline。该命令只运行本地临时 GPU 子进程;添加 `--dry-run` 可探测环境而不加载模型。检查 `sam/report.html`、`annotated.png`、`parts-sheet.png`、漏分图和 mask 归属,错误部件应先修正。
加入 `--dry-run` 可检查环境与本地路径,不加载权重推理。输入必须含 `source.png`、v2 `semantic-parts.json`、`segmentation-prompts.json`。完整参数与质量检查见[第二阶段文档](docs/2-segmentation-stage.md)。
### 第三阶段:准备与补全
### 第三阶段:按部件补全
先从已有 SAM 输出准备画布、允许新增区域和提示词,不请求模型:
先离线准备任务,不请求模型:
```powershell
node .\tools\model-check.mjs --stage completion `
--input-dir .\output\sombrero-sam31-v3 `
--out-dir .\output\sombrero-completion-prepare `
--completion-model qwen-image-3.0 `
--config .\configs\tiantoken.json `
--input-dir "$runRoot\sam" `
--out-dir "$runRoot\complete-prepare" `
--prepare-only
```
打开 `report.html` 检查部件和允许新增区域。以下命令对 `head` 发起一次部件编辑任务,再检查候选并恢复原图可见像素;会调用中转站图片模型:
复核允许区域后,按实际存在的 ID 试一个部件;下面会调用图片模型:
```powershell
node .\tools\model-check.mjs --stage completion `
--input-dir .\output\sombrero-sam31-v3 `
--out-dir .\output\sombrero-completion-head `
--completion-model qwen-image-3.0 `
--config .\configs\tiantoken.json `
--input-dir "$runRoot\sam" `
--out-dir "$runRoot\complete-head" `
--part head
```
`--part` 可重复;省略则处理所有具备可见 mask、补全需求和允许区域的部件。当前 SAM 示例仍有错分,应先复核。补全不会自动纠正上游语义;通过几何检查的 PNG 保存到 `parts/`,仍需人工复核。完整参数、离线候选导入与限制见[第三阶段文档](docs/3-completion-stage.md)。
第三阶段请求会显式发送与局部画布一致的 `size`(默认 `1024x1024`)。如果中转站仍返回其他尺寸,可使用 `--candidates-dir 旧补全目录 --candidate-size-policy uniform` 离线复查:只允许同宽高比的画布等比例缩放,保留原候选,继续检查位置与新增区域并恢复原像素。默认 strict 模式仍拒绝尺寸不符;详细命令见第三阶段文档。
### 单独测试图片补全接口
此命令只验证图片编辑适配器并保存原始候选,不代表补全部件已经验收通过:
处理所有具备可见 mask、补全需求和允许区域的部件:
```powershell
node .\tools\model-check.mjs --stage completion `
--image .\local-part.png `
--prompt-file .\task.txt `
--out-dir .\output\qwen-edit-test `
--completion-model qwen-image-3.0
--config .\configs\tiantoken.json `
--input-dir "$runRoot\sam" `
--out-dir "$runRoot\complete"
```
### 运行旧版完整管线
省略 part 不意味着强制补全全部 mask。检查 `completion-plan.json` 的跳过原因和 `completion-result.json` 的 QA;parts/ 仅包含通过检查的补全部件。所有结果仍需语义复核。
旧候选尺寸不符时,可离线导入复检,避免重新生成:
```powershell
node .\tools\model-check.mjs --stage completion `
--config .\configs\tiantoken.json `
--input-dir .\output\20260918-183532\sam `
--candidates-dir .\output\20260918-183532\complete2_gpt `
--out-dir "$runRoot\complete-size-recheck" `
--candidate-size-policy uniform
```
uniform 仅恢复同宽高比的整画布尺寸,不纠正物体位移、变形或语义。在线请求现已显式传 size;参数及中转实测边界见[第三阶段文档](docs/3-completion-stage.md)。
## 旧管线与验证
旧版依赖相邻 `spine-animation-ai` 外部项目,使用时遵守其 PolyForm Noncommercial 许可证;不要修改外部依赖。旧版命令会调用图片生成并尝试定位、导出:
```powershell
node .\pipeline.mjs `
--reference ..\spine-animation-ai\demo\character_reference.png `
--out-dir .\output\legacy-character `
--reference $reference `
--out-dir "$runRoot\legacy" `
--genielabs-dir ..\spine-animation-ai `
--image-model qwen-image-3.0 `
--attempts 1 `
--animations idle,walk,wave
```
旧流程依赖生成式拆件与传统 CV 定位,对低纹理、低分辨率和生成后外观变化较大的角色不稳定。其输出应通过 `assembled.png` 和 `preview-rigged.html` 人工检查后再导入 Spine。
`segment.py` 为旧版拆件分割,`compose_preview.py` 组装预览,`run_case_matrix.py` 对照定位方案;当前 SAM 入口为 sam_segment.py。旧产物需检查 assembled.png 和 preview-rigged.html,不能据此声称新三阶段已经完成 Spine 导出。
### 运行测试
测试与命令帮助:
```powershell
conda run -n ai-spine npm test
conda run --no-capture-output -n ai-spine npm test
node .\tools\model-check.mjs --help
```
测试使用本地 mock HTTP 服务或注入响应,不调用真实付费模型。
测试使用本地 mock 或注入响应,不请求真实付费模型。自动化运行任一阶段可用 `conda run --no-capture-output -n ai-spine node ...`。保留旧实验;resume 只复用完整匹配产物,失败任务另建输出目录。
+115 -339
View File
@@ -1,371 +1,147 @@
# 第一阶段:视觉 LLM 角色结构理解
第一阶段把单张角色参考图转换为结构化的语义部件计划,供后续 SAM 分割、遮挡补全和 Spine 骨骼生成使用。
## 1. 阶段简介
本阶段只做角色结构理解和粗标注,不生成精确 mask、透明拆件 PNG 或补全后的隐藏部件。
将单张角色图转换为部件语义计划:确定部件名称、骨骼与附件分类、运动层级、遮挡、可见区域粗框、关节点和补全需求。视觉模型负责结构理解;本地程序负责格式校验和前景候选点生成。
## 1. 输入、输出与执行链路
本阶段不生成精确 mask、透明拆件、隐藏纹理或 Spine 文件。结构合法不等于识别正确,结果仍为 `quality_status=needs_review`。
输入是一张完整的 PNG 角色参考图。核心输出是 <code>semantic-parts.json</code>,其中记录:
## 2. 输入、输出与执行链路
- 角色由哪些可动部件组成;
- 每个部件的语义名称;
- 部件之间的运动父子关系;
- 部件之间的视觉遮挡关系;
- 可见、部分可见或完全隐藏状态;
- 可见区域粗框、预计关节位置,骨骼/附件角色与绑定目标;
- 程序用 Alpha 校验后另行输出的 SAM 候选点;
- 是否需要在第三阶段补全;
- 模型对判断结果的自报置信度。
输入为 PNG 角色图;在线模式需要模型配置与密钥,离线模式需要已有语义计划。核心输出为语义计划和 SAM 提示。
整体执行链路:
```text
tools/model-check.mjs(或 pipeline.mjs --mode annotated-parts)
→ 读取配置、图片、提示词与 Schema,计算实验指纹
→ Python 保留 Alpha / 去除边界连通白底,保持原画布
→ 在线:视觉模型理解;离线:读取计划并按需迁移 v1
→ 提取 JSON,校验字段、引用、层级和补全一致性
→ 在 Alpha 前景与粗框交集中生成距离变换候选点
→ 保存 semantic-parts.json、segmentation-prompts.json、诊断及报告
→ 第二阶段读取 source.png + 计划 + SAM 提示
```
~~~text
角色原图
↓
保留 Alpha 或去除边界连通白底(不缩放裁剪)
↓
读取模型配置、提示词和输出 Schema
↓
构造视觉 LLM 请求
↓
DeepSeek Flash / GPT-6 Astra
↓
提取模型返回的 JSON 文本
↓
Schema 校验和部件关系校验
↓
semantic-parts.json
↓
Alpha / ROI 校验、距离变换候选点、segmentation-prompts.json
↓
生成 annotated.svg 和 report.html
↓
人工复核后交给 SAM 分割阶段
~~~
`--parts-file` 不请求模型,也不运行 SAM。`--stop-after segment` 可接续第二阶段,输出到理解目录的 `segmentation/`;第三阶段独立调用。
## 2. 命令入口
## 3. 阶段执行命令示例及参数说明
示例:
以下 PowerShell 命令在项目根目录执行,环境准备见 [README](../README.md)。反引号必须在行尾,后面不能有空格。
~~~powershell
node .\tools\model-check.mjs `
--stage understanding `
--understanding-model gpt-6-astra `
--reference .\output\sombrero-grounding-v2\source.png `
--out-dir ".\output\$runId\understand" `
--config .\configs\tiantoken.json
~~~
```powershell
conda activate ai-spine
$runId = Get-Date -Format "yyyyMMdd-HHmmss"
node .\tools\model-check.mjs --stage understanding `
--config .\configs\deepseek-qwen.json `
--reference .\output\20260918-183532\sam\source.png `
--out-dir ".\output\$runId\understand"
```
第一步由以下两个文件负责:
参考图可替换成自己的 PNG。切换 Tiantoken:将配置改为 `--config .\configs\tiantoken.json`,默认理解模型为 `gpt-6-astra`,也可显式传入 `--understanding-model gpt-6-astra`。
1. [pipeline.mjs](../pipeline.mjs) 检测 <code>--mode annotated-parts</code>,把命令转交给新管线,不进入旧版“生成拆件图 → CV 定位”流程。
2. [tools/model-check.mjs](../tools/model-check.mjs) 解析参数、加载配置、应用命令行覆盖、检查输入并调用 <code>runUnderstanding()</code>。
已有计划离线生成新候选,不重跑 AI:
## 3. 配置解析
```powershell
node .\tools\model-check.mjs --stage understanding `
--reference .\output\20260918-183532\sam\source.png `
--parts-file .\output\20260918-183532\sam\semantic-parts.json `
--out-dir ".\output\$runId\understand-offline"
```
当前提供两组实验配置:
| 配置 | 理解模型 | 协议 | 流式 |
| --- | --- | --- | --- |
| [configs/deepseek-qwen.json](../configs/deepseek-qwen.json) | <code>deepseek-flash</code> | <code>chat-completions</code> | <code>false</code> |
| [configs/astra-qwen.json](../configs/astra-qwen.json) | <code>gpt-6-astra</code> | <code>responses</code> | <code>true</code> |
[lib/config.mjs](../lib/config.mjs) 负责读取:
- JSON 配置文件;
- 项目 <code>.env</code> 或 <code>--env-file</code>;
- 当前 shell 环境变量;
- 模型、协议、输出模式、超时和重试设置;
- 阶段提示词;
- SAM checkpoint 路径。
模型选择优先级:
~~~text
命令行 --understanding-model
> stage.model
> SPINE_UNDERSTANDING_MODEL
> stage.default_model
~~~
Shell 环境变量优先于 <code>.env</code>。模型 ID 会原样传给中转站,不做隐式别名转换。
配置中的 <code>params</code> 不能覆盖模型、消息体、输入、流式选项和认证字段,避免实验配置改变基础请求语义或泄漏密钥。
## 4. 读取参考图
[lib/images.mjs](../lib/images.mjs) 读取参考图,并得到:
- 原始文件字节;
- MIME 类型;
- 图片宽高;
- SHA-256;
- 模型请求使用的 Base64 Data URL。
本阶段要求参考图为 PNG。原始输入保存为 <code>source-original.png</code>,模型实际看到的预处理 RGBA 保存为 <code>source.png</code>,不缩放、不裁剪。已有透明背景时保留原像素;不透明白底使用连通域仅去除与画布边界相连、RGB 各通道均 ≥240 的区域。其他背景或空前景会在请求模型前失败,需先提供抠图 PNG。去白底存在白色主体接触边界的局限,预处理记录保存在 <code>preprocessing.json</code>。
这一层调用 <code>normalize_reference.py</code> 和 <code>geometry_grounding.py</code>,固定使用 Conda 环境 <code>ai-spine</code> 及 requirements.txt 中的依赖。先执行 <code>conda activate ai-spine</code>;自动化使用 <code>conda run -n ai-spine node ...</code>。--python 也只能指定该环境的解释器,不创建其他环境。每次修改须遵守 [AGENTS.md](../AGENTS.md)。
## 5. 理解提示词
提示词位于 [prompts/understand-v1.txt](../prompts/understand-v1.txt),要求视觉 LLM:
- 保留角色原始姿势、朝向和不对称性;
- 仅在独立运动有意义且图像支持时拆分部件;
- 区分运动父子关系和视觉遮挡关系;
- 使用完整画布的归一化坐标;
- 输出语义、粗框、预计关节和 rig_role/bind_to;正负提示点留空;
- 不把粗框声称为像素级 mask;
- 不凭空创造没有视觉证据的隐藏肢体或附件;
- 将不确定性和假设写入 <code>notes</code>。
请求适配器还会附加原图画布尺寸和完整 JSON Schema,并要求模型只返回符合 Schema 的 JSON。最终提示词副本保存在 <code>prompt.txt</code>。
## 6. 输出数据契约
结构定义位于 [schemas/semantic-parts.schema.json](../schemas/semantic-parts.schema.json)。顶层格式:
~~~json
{
"schema_version": 2,
"coordinate_space": "normalized_xy_top_left",
"parts": [],
"notes": []
}
~~~
每个部件包含:
| 字段 | 含义 |
| 参数 | 说明 |
| --- | --- |
| <code>id</code> | 稳定、唯一的小写 ASCII 部件 ID |
| <code>semantic</code> | 部件语义说明 |
| <code>parent</code> | 运动层级中的父部件;<code>null</code> 表示未来挂到 root |
| <code>rig_role</code> | bone_part / attachment / facial_feature,附件不自动创建骨骼 |
| <code>bind_to</code> | 附件绑定的 bone_part;骨骼部件使用 parent,bind_to 为 null |
| <code>visibility</code> | <code>visible</code>、<code>partial</code> 或 <code>hidden</code> |
| <code>bbox_norm_xyxy</code> | 可见区域粗框 <code>[xmin, ymin, xmax, ymax]</code> |
| <code>pivot_norm</code> | 预计的关节或连接点 |
| <code>positive_points_norm</code> | 模型粗估点,仅为旧版诊断兼容保留,新请求留空 |
| <code>negative_points_norm</code> | 模型负点,仅保留作记录,不传给 SAM |
| <code>occluded_by</code> | 视觉上遮挡当前部件的其他部件 |
| <code>completion</code> | occlusion_fill / joint_extension_parent / joint_extension_child 三项 boolean |
| <code>needs_completion</code> | 三项 completion 的逻辑或;包括独立旋转需要的隐藏纹理和关节重叠 |
| <code>confidence</code> | LLM 自报置信度,范围 0~1 |
| `--stage understanding` | 第一阶段,也是入口默认阶段 |
| `--reference FILE` | 必需,角色 PNG |
| `--out-dir DIR` | 实际执行必需,使用独立新目录 |
| `--config FILE` | JSON 配置;默认 `configs/astra-qwen.json` |
| `--env-file FILE` | 默认项目 `.env`;shell 同名变量优先 |
| `--understanding-model ID` | 原样发送模型 ID,不转换别名 |
| `--understanding-protocol NAME` | `chat-completions` 或 `responses` |
| `--stream true/false` | 覆盖配置流式设置 |
| `--output-mode NAME` | `text-json`、`json-object`、`json-schema`;需确认中转能力 |
| `--parts-file FILE` | 离线读取有效 v2 或保守迁移 v1 |
| `--python FILE` | 仅允许 Conda ai-spine 的解释器 |
| `--stop-after understand/segment` | 理解结束或接续 SAM |
| `--dry-run` | 检查配置与图片格式,不生成产物;不代表完整 Python 几何链路已验证 |
| `--resume` | 仅复用已完成且指纹、产物哈希一致的结果,不是失败请求续发 |
| `--list-models` | 联网查询所选提供方模型列表,不能与 dry-run 同用 |
所有坐标都以完整画布左上角为原点并归一化到 0~1。例如:
模型优先级:CLI > `stage.model` > 配置指定的模型环境变量 > `stage.default_model`。提示词路径相对于配置文件。DeepSeek 预设为 Chat Completions 非流式;两个 Astra 预设为 Responses 流式。配置不代表中转所有能力均已验证。
~~~json
"bbox_norm_xyxy": [0.36, 0.36, 0.70, 0.62]
~~~
## 4. 输入格式要求
对应像素坐标:
参考图必须是有效 PNG,建议单角色、透明背景、完整画布。透明图保留 Alpha;不透明白底只去除与边界连通、RGB 各通道均 ≥240 的区域。复杂背景需先抠图,空前景会失败;白色主体接触边界可能被误删。
~~~text
xmin = canvas_width × 0.36
ymin = canvas_height × 0.36
xmax = canvas_width × 0.70
ymax = canvas_height × 0.62
~~~
离线计划采用 [v2 Schema](../schemas/semantic-parts.schema.json):顶层 `schema_version=2`、`coordinate_space=normalized_xy_top_left`、`parts` 数组和 `notes`。实际部件数量为 1~64。
## 7. 构造视觉模型请求
[providers/vision.mjs](../providers/vision.mjs) 根据配置选择请求格式。
### Chat Completions
DeepSeek Flash 使用:
~~~text
POST /v1/chat/completions
~~~
一个用户消息中同时包含文本提示词、画布尺寸、Schema 和采用 Data URL 编码的角色原图。
### Responses
GPT-6 Astra 使用:
~~~text
POST /v1/responses
~~~
适配器把同一任务转换成 <code>input_text</code> 和 <code>input_image</code> 格式,因此模型业务逻辑与具体 API 协议保持分离。
<code>output_mode</code> 支持:
- <code>text-json</code>:通过提示词约束 JSON,再在本地严格校验;
- <code>json-object</code>:中转站确认支持后使用 JSON Object 模式;
- <code>json-schema</code>:中转站确认支持后使用 Structured Outputs。
当前已验证的 DeepSeek 配置使用 <code>text-json</code>。
## 8. 中转站通信
[providers/http.mjs](../providers/http.mjs) 负责:
- 拼接 base URL 和协议路由;
- 添加 Bearer Authorization;
- 控制请求超时;
- 对明确的 HTTP 429 和 5xx 有限重试;
- 解析普通 JSON 或完整 SSE;
- 拒绝被截断的流式响应;
- 记录请求 ID、模型、token、耗时和尝试次数;
- 从错误信息和落盘文件中脱敏 API Key。
超时或网络中断不会自动重试,因为服务端可能已经执行并计费。失败时会尽量生成 <code>response.error.json</code>,保存脱敏后的状态码、响应片段或网络错误码。
## 9. 提取与校验模型结果
[providers/vision.mjs](../providers/vision.mjs) 从不同协议的响应中提取模型文本,并拒绝:
- 模型 refusal;
- 非正常 <code>finish_reason</code>;
- 未完成的 Responses 状态;
- 没有结构理解文本的响应。
提取后的内容保存在 <code>response.txt</code>。
[lib/validate-parts.mjs](../lib/validate-parts.mjs) 首先去掉模型可能添加的 Markdown JSON 代码块,然后执行 JSON 解析和两层本地校验。
### Schema 校验
- 必填字段是否齐全;
- 类型与枚举是否正确;
- ID 格式是否合法;
- 坐标和置信度是否在 0~1;
- 部件数量是否在 1~64;
- 是否出现未知字段。
### 结构语义校验
- 部件 ID 不能重复;
- <code>parent</code> 和 <code>occluded_by</code> 必须引用已有部件;
- 部件不能引用自己;
- 父子关系和遮挡关系不能形成环;
- 可见部件必须具有正面积 bbox;
- 模型正点可为空;落在 bbox 外只产生警告并丢弃其提示作用;
- bind_to 必须引用骨骼部件,骨骼的 parent 也必须是骨骼部件;
- partial/hidden 必须声明 occlusion_fill,needs_completion 与三项补全字段一致;
- 附件和面部特征不能声明独立骨骼关节延展;
- 完全隐藏部件必须没有可见框和正点,并设置 <code>needs_completion=true</code>;
- 自报置信度低于 0.6 时产生人工复核警告。
校验结果写入 <code>validation.json</code>。只有校验通过时才会写出正式的 <code>semantic-parts.json</code>。
随后进行像素几何检查:以 <code>alpha > 0</code> 为前景,记录原始模型点是否落在前景和粗框内。在粗框与前景交集中,用距离变换选择远离轮廓和 ROI 边界的像素作为候选。像素坐标使用 floor(norm × size),1 映射到最后一个像素;候选归一化坐标使用像素中心。粗框按 floor/ceil 转为半开像素范围。
框内无前景、没有像素中心或 Alpha 不可用时标记 blocked,不生成点。隐藏部件标记 hidden。记录框内前景比例、连通域数量和候选到轮廓距离,不把候选声称为已确认的语义种子;原始 pivot 完全保留。
## 10. 可视化与人工复核
[lib/report.mjs](../lib/report.mjs) 将结构理解结果叠加到原图:
- 彩色矩形:模型预测的可见区域粗框;
- 红色实心圆:无效模型点;黄色实心圆:前景上的不可信模型点;
- 青色方块:程序生成的 Alpha 候选,仍需确认部件语义;
- 空心圆:部件 pivot;
- 虚线:当前部件到父部件的关系;
- 文本:部件 ID。
它会生成:
- <code>annotated.svg</code>:可缩放的原图标注;
- <code>report.html</code>:包含标注图、校验结果、部件表、模型说明和请求元数据的自包含检查页。
<code>status=completed</code> 只表示请求、解析和本地校验完成。成功结果仍设置 <code>quality_status=needs_review</code>,因为结构合法不等于语义和框位置一定正确。
人工复核至少应检查:
1. 是否遗漏身体、头部或关键肢体;
2. 左右肢体是否符合画面方向;
3. 是否过度拆分面部或服饰细节;
4. 父子关系能否支持预期动画;
5. 遮挡关系是否与原图一致;
6. bbox 和提示点是否落在正确部件上;
7. <code>needs_completion</code> 是否覆盖确实需要补全的部分。
## 11. 阶段调度与实验留档
[stages/model-stage.mjs](../stages/model-stage.mjs) 是第一阶段总调度器:
~~~text
读取图片
→ 计算输入、Schema、配置和代码指纹
→ 创建运行目录
→ 保存输入、提示词和请求摘要
→ 调用视觉 LLM
→ 保存原始响应和请求元数据
→ 提取并校验 JSON
→ 保存正式语义结果
→ 生成标注和检查报告
→ 更新 manifest
~~~
[lib/run-artifacts.mjs](../lib/run-artifacts.mjs) 负责输出目录、恢复校验、产物哈希和最终状态。
<code>--resume</code> 只在原图、模型、协议、参数、提示词、Schema、相关源代码和已有产物全部一致时复用结果。不同模型或提示词实验应使用不同输出目录。
## 12. 输出文件
| 文件 | 作用 |
| 部件字段 | 格式与含义 |
| --- | --- |
| <code>source-original.png</code> | 原始输入副本 |
| <code>source.png</code> | 模型实际看到的预处理 RGBA |
| <code>preprocessing.json</code> | 背景处理方式和像素统计 |
| <code>geometry-validation.json</code> | 原始点诊断、框内前景比例、连通域、候选和阻塞原因 |
| <code>segmentation-prompts.json</code> | 语义、粗框、程序生成的正点;负点为空,requires_mask_qa=true |
| <code>prompt.txt</code> | 本次解析后的阶段提示词 |
| <code>request.json</code> | 可复现实验的请求摘要,不包含 API Key 或完整 Base64 请求体 |
| <code>response.raw.json</code> | 中转站原始成功响应 |
| <code>response.txt</code> | 从协议响应中提取的模型文本 |
| <code>request-metadata.json</code> | 请求模型、返回模型、request ID、usage、耗时、次数和 wire format |
| <code>validation.json</code> | Schema 与结构语义校验结果 |
| <code>semantic-parts.json</code> | 校验通过后的正式结构理解结果 |
| <code>annotated.svg</code> | 原图上的粗框、pivot、提示点和父子连线 |
| <code>report.html</code> | 用于人工语义复核的综合页面 |
| <code>manifest.json</code> | 状态、配置、输入哈希、代码版本、SAM 信息和全部产物哈希 |
| <code>response.error.json</code> | HTTP、SSE 或网络失败时的脱敏诊断信息;成功时不存在 |
| `id` / `semantic` | 唯一小写 ASCII ID / 语义说明 |
| `parent` | 父骨骼 ID 或 null;运动关系 |
| `rig_role` | `bone_part`、`attachment`、`facial_feature` |
| `bind_to` | 附件绑定的骨骼 ID 或 null(root);骨骼自身为 null |
| `visibility` | `visible`、`partial`、`hidden` |
| `bbox_norm_xyxy` | `[xmin,ymin,xmax,ymax]` 可见粗框;隐藏为 null |
| `pivot_norm` | `[x,y]` 关节或连接点,可处于遮挡区域 |
| `positive_points_norm` / `negative_points_norm` | 旧模型点兼容字段,新提示词要求留空 |
| `occluded_by` | 遮挡者 ID 数组,与运动关系分开 |
| `completion` | `occlusion_fill`、`joint_extension_parent`、`joint_extension_child` 三个布尔值 |
| `needs_completion` | 三项 completion 的逻辑或 |
| `confidence` | 0~1 自报置信度;说明与不确定性写入顶层 notes,部件内没有 notes 字段 |
<code>request.json</code> 是请求身份摘要,不等同于线上发送的完整 HTTP body。图片内容单独保存在 <code>source.png</code>,密钥不会写入产物。
坐标以完整画布左上角为原点,归一化到 0~1。可见框须为正面积;partial/hidden 必须声明遮挡补全,hidden 无可见框和正点。附件及面部特征不能声明独立骨骼关节延展。引用必须存在,不能自引用或形成父子/遮挡环路,绑定目标必须是骨骼。完整类型与必填项以 Schema 为准。
## 13. 代码职责索引
v1 迁移依据 ID 推断角色分类和补全需求,推断写入 notes,不重新识别图片、不覆盖旧文件。计划必须对应同一张图、同一画布。
## 5. 执行链路中重要部分代码文件及原理说明(包括重点说明)
**请求和结构校验。** `stages/model-stage.mjs` 调度;`providers/vision.mjs` 将图片 Data URL、画布尺寸、提示词与 Schema 转成对应协议,再提取 JSON,拒绝 refusal、异常结束和未完成响应。`lib/validate-parts.mjs` 校验字段、引用、层级和补全一致性,成功后写正式计划。低置信度等产生告警,不能据结构校验认定语义正确。
**候选点并非重新由 AI 生成。** `geometry_grounding.py` 对粗框与 `alpha>0` 的交集计算距离变换,选取远离边界的像素中心;无有效前景则 blocked。归一化点转像素采用 floor,1 映射到最后一个像素;粗框按 floor/ceil 转半开范围。候选仍可能属于框内的其他部件。
**pivot 与种子独立。** 关节点不吸附到前景,模型原始正负点仅作诊断。第二阶段当前只用程序种子排序返回的 mask,未把它们作为 SAM 点提示。
**通信、可视化与留档。** `providers/http.mjs` 负责 HTTP、SSE、超时和脱敏;明确的 429/5xx 有限重试,超时/网络中断不自动重复请求。`lib/report.mjs` 用红/黄圆区分原模型点、青色方块表示程序候选、空心圆表示 pivot。旧输出不会随代码修改自动更新。`lib/run-artifacts.mjs` 按输入、模型、参数、提示词、Schema、代码和产物哈希复用结果;completed 仅表示执行完成。
## 6. 各个代码文件职责索引
| 文件 | 职责 |
| --- | --- |
| [pipeline.mjs](../pipeline.mjs) | 顶层入口;把 annotated-parts 模式转发到新管线 |
| [tools/model-check.mjs](../tools/model-check.mjs) | CLI 参数解析、配置解析入口、模型列表和阶段分发 |
| [configs/deepseek-qwen.json](../configs/deepseek-qwen.json) | DeepSeek 理解 + Qwen 补全实验预设 |
| [configs/astra-qwen.json](../configs/astra-qwen.json) | Astra 理解 + Qwen 补全实验预设 |
| [prompts/understand-v1.txt](../prompts/understand-v1.txt) | 第一阶段任务约束 |
| [schemas/semantic-parts.schema.json](../schemas/semantic-parts.schema.json) | 第一阶段输出数据契约 |
| [lib/config.mjs](../lib/config.mjs) | JSON、环境变量和阶段配置解析 |
| [lib/images.mjs](../lib/images.mjs) | 图片读取、格式识别、尺寸、哈希和 Data URL |
| [providers/vision.mjs](../providers/vision.mjs) | Chat Completions/Responses 请求构造与文本提取 |
| [providers/http.mjs](../providers/http.mjs) | HTTP、认证、超时、重试、SSE、元数据和脱敏 |
| [lib/validate-parts.mjs](../lib/validate-parts.mjs) | JSON 解析、Schema 校验和关系校验 |
| [lib/geometry.mjs](../lib/geometry.mjs) | Python 环境选择与几何阶段调用 |
| [geometry_grounding.py](../geometry_grounding.py) | Alpha/ROI 诊断与距离变换候选生成 |
| [normalize_reference.py](../normalize_reference.py) | RGBA 保留与边界连通白底去除 |
| [lib/report.mjs](../lib/report.mjs) | SVG 标注和 HTML 检查报告 |
| [lib/run-artifacts.mjs](../lib/run-artifacts.mjs) | 输出目录、恢复校验、状态和产物哈希 |
| [stages/model-stage.mjs](../stages/model-stage.mjs) | 第一阶段总调度与失败处理 |
| [pipeline.mjs](../pipeline.mjs) / [tools/model-check.mjs](../tools/model-check.mjs) | 新管线转发 / CLI、模型列表和阶段分发 |
| [stages/model-stage.mjs](../stages/model-stage.mjs) | 理解总调度与留档;另含图片编辑探针 |
| [lib/config.mjs](../lib/config.mjs) / [lib/images.mjs](../lib/images.mjs) | 配置解析 / 图片格式、尺寸、哈希和 Data URL |
| [lib/python-runtime.mjs](../lib/python-runtime.mjs) / [lib/geometry.mjs](../lib/geometry.mjs) | Conda 检查 / Python 几何调用 |
| [normalize_reference.py](../normalize_reference.py) / [geometry_grounding.py](../geometry_grounding.py) | Alpha 与去白底 / ROI 诊断和候选生成 |
| [providers/vision.mjs](../providers/vision.mjs) / [providers/http.mjs](../providers/http.mjs) | 视觉协议 / 通信与脱敏 |
| [lib/validate-parts.mjs](../lib/validate-parts.mjs) | 解析、Schema/关系校验、v1 迁移 |
| [lib/report.mjs](../lib/report.mjs) / [lib/run-artifacts.mjs](../lib/run-artifacts.mjs) | SVG/HTML / 状态、指纹与缓存 |
| [prompts/understand-v1.txt](../prompts/understand-v1.txt) | 理解提示词;文件名保留 v1,当前使用 v2 契约 |
| [v2 Schema](../schemas/semantic-parts.schema.json) / [v1 Schema](../schemas/semantic-parts-v1.schema.json) | 正式契约 / 兼容输入 |
| [DeepSeek](../configs/deepseek-qwen.json)、[Astra](../configs/astra-qwen.json)、[Tiantoken](../configs/tiantoken.json) 配置 | 模型、协议和环境变量预设 |
| [tests/model-stages.test.mjs](../tests/model-stages.test.mjs) / [tests/test_geometry.py](../tests/test_geometry.py) | 协议、计划、留档及几何回归 |
## 14. 当前边界与下一阶段接口
## 7. 产物详细说明
第一阶段输出的是语义计划,而不是分割结果:
| 路径 | 内容与用途 |
| --- | --- |
| `source-original.png` | 原始输入副本 |
| `source.png` | 预处理 RGBA,在线模型所见图片,后续坐标基准 |
| `preprocessing.json` | 背景处理方式与像素统计 |
| `semantic-parts.json` / `validation.json` | 正式 v2 计划 / 字段、关系校验及告警 |
| `geometry-validation.json` | 原点诊断、ROI 前景比例、连通域、候选与阻塞原因 |
| `segmentation-prompts.json` | 画布、部件 ID、candidate/hidden/blocked 状态、粗框、程序种子和 QA 要求 |
| `annotated.svg` / `report.html` | 粗标注 / 综合复核页;不是 SAM 分割图 |
| `prompt.txt` / `request.json` | 阶段提示词副本 / 请求身份摘要,不是完整 HTTP body |
| `response.raw.json` / `response.txt` | 响应留档 / 提取文本;离线模式使用本地计划记录 |
| `request-metadata.json` | 请求与返回模型、request ID、usage、耗时、次数和协议元数据 |
| `response.error.json` | 可获取时保存的脱敏请求失败诊断 |
| `manifest.json` | 模式、状态、输入/代码/产物哈希;SAM 路径仅记录,不加载模型 |
~~~text
视觉 LLM 输出
= 部件语义 + 层级 + rig_role/bind_to + 遮挡 + 粗框 + 粗关节 + 补全需求
失败可能只有部分产物。第二阶段前应复核左右、粗框、层级、遮挡、分类和补全需求,不能只看点是否落在前景。
视觉 LLM 不输出
= 可信的像素 mask + 透明拆件 + 隐藏区域补全 + 最终骨骼
~~~
## 8. 当前阶段可改进点说明
已实现的[第二阶段](2-segmentation-stage.md)读取 <code>source.png</code>、<code>semantic-parts.json</code> 和 <code>segmentation-prompts.json</code>,仅处理 status=candidate 的可见部件。SAM 图像概念接口接收文本和框;程序候选点参与返回 mask 的排序,不作为点提示传入此接口。模型原始正负点不传给 SAM。候选始终 semantic_verified=false:框内可能混有多个部件,Alpha、重叠和连通域检查不能替代语义复核。
已有 v1 结果可以通过 <code>--parts-file 旧计划.json --reference 原图.png --out-dir 新目录</code> 离线迁移与校验,不请求模型。迁移按 ID 推断骨骼/附件类型,袖子优先绑定同侧上臂,面部绑定头部;部分可见部件开启遮挡补全,骨骼连接处保守建议延展。这些推断在 notes 标注为待复核,不替代模型或人工判断。输入计划哈希和所有新产物参与 resume 校验。
第一阶段 <code>manifest.json</code> 只记录 SAM 路径信息,<code>runtime_status=local_subprocess_not_probed</code>,第一阶段不加载 SAM。第二阶段单独探测 Conda/CUDA、严格加载本地权重,并在自己的 manifest 中记录运行环境、权重哈希及子进程退出状态。
- 明确角色左右与画面左右命名约定,提升粗框、遮挡及隐藏状态判断,减少 SAM 衣料/肢体混淆。
- 根据预期动画审查拆分粒度与附件绑定,区分隐藏骨骼占位项和真正可见拆件。
- 增加可审阅的计划修正流程,修正后重新生成几何提示;Alpha 候选不能代替语义复核。
- 第二阶段后根据实际 mask 重新评估补全需求,不能因第一阶段 needs_completion=false 永久跳过有缺损的拆件。
- 增加结构和像素证据一致性检查,区分“不确定”“结构合法”“人工确认正确”。
+121 -81
View File
@@ -1,116 +1,156 @@
# 第二阶段:本地 SAM 分割
本阶段读取第一阶段的语义计划,使用本地 SAM 3.1 图像检测分支生成部件 mask,从原图提取可见像素,并输出两张预览图。Python 固定使用 `ai-spine` Conda 环境,遵守 [AGENTS.md](../AGENTS.md)。
## 1. 阶段简介
## 运行方式
读取第一阶段语义计划,用本地 SAM 3.1 图像检测分支生成部件 mask,再从原图提取可见像素。当前输出半透明颜色叠加的角色图、白底拆解图和透明部件。
在 `AI_spine` 目录执行:
SAM 在 Conda `ai-spine` 的临时 GPU 子进程中运行,结束后退出;不部署常驻服务、不下载权重、不调用中转站、不自动回退 CPU。本阶段尚无大模型去毛边步骤,也不补画隐藏纹理。
## 2. 输入、输出与执行链路
输入为第一阶段目录,加本地 SAM 代码和权重;输出为可见部件 mask、原像素拆件、诊断和预览。
```text
tools/model-check.mjs --stage segmentation
→ stages/segmentation-stage.mjs 检查输入、路径、参数与 Conda
→ 临时探测子进程检查依赖和 CUDA,不加载权重
→ 计算输入、代码、权重指纹,复制输入到新输出目录
→ 临时推理子进程:sam_segment.py → sam_runtime.py
→ 严格加载检测分支,一次编码原图
→ 每部件分别取得文本、文本+粗框候选,排序选 mask
→ 与原图 Alpha 取交集,提取原像素并渲染报告
→ 子进程退出,manifest 记录产物与退出状态
→ 第三阶段读取 source.png、计划、segmentation.json 和 masks/
```
`hidden/blocked` 不进入推理;没有合格候选会记录跳过原因,不用矩形或种子伪造 mask。所有输出仍为 `semantic_verified=false`、`quality_status=needs_review`。
## 3. 阶段执行命令示例及参数说明
在项目根目录执行,环境安装见 [README](../README.md)。以下独立命令复用已有计划,无需模型密钥:
```powershell
conda activate ai-spine
$runId = Get-Date -Format "yyyyMMdd-HHmmss"
node .\tools\model-check.mjs --stage segmentation `
--input-dir .\output\sombrero-grounding-v2 `
--out-dir ".\output\$runId\sam" `
--sam-dir F:/Study/SAM3
```
将 `--input-dir` 替换为本次第一阶段的 `understand` 目录,即可接续新实验。自动化可以使用 `conda run --no-capture-output -n ai-spine node ...`。
仅探测环境与输入,不进行模型推理:
```powershell
conda run --no-capture-output -n ai-spine node .\tools\model-check.mjs `
--stage segmentation `
--input-dir .\output\sombrero-grounding-v2 `
--out-dir .\output\sombrero-sam-local `
--sam-dir F:/Study/SAM3
node .\tools\model-check.mjs `
--stage segmentation `
--input-dir ".\output\$runId\understand" `
--out-dir ".\output\$runId\sam" `
--sam-dir F:/Study/SAM3
--sam-dir F:/Study/SAM3 `
--dry-run
```
输出目录必须是新目录。相同输入、代码、权重、参数及完整产物可加 `--resume` 复用;失败结果保留,另建目录重跑。独立分割不调用视觉 LLM 或图片编辑接口,不需要 API Key。
输入目录必须包含:
| 文件 | 要求 |
| 参数 | 说明 |
| --- | --- |
| `source.png` | 第一阶段预处理后的原尺寸 RGBA |
| `semantic-parts.json` | 通过结构校验的 v2 语义计划 |
| `segmentation-prompts.json` | 与计划 ID、画布匹配的程序候选提示 |
| `--stage segmentation` | 独立运行第二阶段 |
| `--input-dir DIR` | 必需,第一阶段输出目录 |
| `--out-dir DIR` | 推理必需,使用独立新目录;dry-run 可省略 |
| `--sam-dir DIR` | SAM 根目录,优先于 SAM_MODEL_DIR 和配置默认值 |
| `--sam-code-dir DIR` | 源码仓库,优先于 SAM_CODE_DIR 和根目录下 sam3 |
| `--sam-checkpoint FILE` | 显式本地权重,覆盖根目录自动查找 |
| `--sam-confidence FLOAT` | 候选模型分数阈值,默认 0.2,严格介于 0 和 1;不是语义准确率 |
| `--sam-precision NAME` | 默认 bf16,可选 fp32;后者显存占用更高 |
| `--config FILE` / `--env-file FILE` | 配置与环境变量文件,默认 astra-qwen.json / 项目 .env |
| `--python FILE` | 仅允许 ai-spine 的解释器 |
| `--dry-run` | 检查路径、Conda、依赖导入和 CUDA;不校验完整权重加载或推理显存 |
| `--resume` | 输入、参数、代码、权重和完整产物一致时复用;失败任务另建目录 |
仅 `status=candidate` 的可见部件进入推理。hidden/blocked 记入跳过列表;无可用 SAM mask 的部件记录失败原因,不用矩形或候选点伪造分割。
也可在第一阶段命令上使用 `--stop-after segment --sam-dir F:/Study/SAM3`,输出位于理解目录的 `segmentation/`。该方式会先执行理解阶段,可能调用付费模型。
可以在命令末尾加 `--dry-run` 检查代码路径、权重存在性、Conda、依赖导入和 CUDA;它不加载权重,因此不验证权重内容或完整推理显存需求。
## 4. 输入格式要求
如需从第一阶段接续运行,在原结构理解命令中使用 `--stop-after segment --sam-dir F:/Study/SAM3`。第二阶段输出到理解目录下的 `segmentation/`。原理解命令仍可能请求付费模型;已有计划优先使用上面的独立命令。
| 输入 | 要求 |
| --- | --- |
| `source.png` | 第一阶段预处理 RGBA,保留完整原画布 |
| `semantic-parts.json` | 通过结构校验的 v2 计划,旧版须先离线迁移 |
| `segmentation-prompts.json` | 宽高匹配 source;部件 ID 与计划完整一致 |
| candidate 提示 | 非隐藏部件,seed_source 为 alpha_roi_distance_transform;整数粗框在画布内;至少一个整数种子在粗框与 Alpha 前景内 |
| SAM 代码 | 源码仓库内部必须有 sam3/model_builder.py |
| SAM 权重 | 本地 sam3.1_multiplex.pt,与本项目适配的检测分支结构匹配 |
## 环境与权重
本机已经验证:Python 3.11、PyTorch `2.7.1+cu126`、torchvision `0.22.1+cu126`、NumPy `1.26.4`、OpenCV `4.11.0.86`、Windows Triton `3.3.1.post21`,GPU 为 RTX 3060 Laptop 6 GB。
环境补全命令见 [README](../README.md#python-与外部项目),依赖记录在 [requirements.txt](../requirements.txt)。程序不会自动安装依赖、创建环境或切换到 CPU。
默认布局:
当前本机布局:
```text
F:/Study/SAM3/
sam3/ 源码仓库
sam3/
sam3/model_builder.py
sam3.1checkpoint/
sam3.1_multiplex.pt
```
路径优先级为 CLI 覆盖、环境变量、配置默认值。`SAM_MODEL_DIR` 指定根目录,`SAM_CODE_DIR` 可单独指定源码仓库。若 `.env` 中仍是旧路径,修改为上述路径或显式传入 CLI 参数。
权重默认先查找上述子目录,再查找 SAM 根目录下同名文件。当前已验证环境为 Python 3.11、PyTorch 2.7.1+cu126、torchvision 0.22.1、NumPy 1.26.4、OpenCV 4.11.0.86,RTX 3060 Laptop 6 GB。这是本机验证组合,不是所有机器的兼容保证。
| 参数 | 含义 |
## 5. 执行链路中重要部分代码文件及原理说明(包括重点说明)
**本地生命周期与权重。** `stages/segmentation-stage.mjs` 先探测,再启动一次推理进程;离线环境变量禁止 Hugging Face 下载。推理超时 20 分钟,结束、报错或取消后退出。`sam_runtime.py` 从 multiplex 权重提取 detector 分支,适配三个特征尺度,移除未使用的第四尺度并取消 scalp;忽略不参与当前推理的视频 neck,实际加载参数使用 strict=True。外部 SAM 源码不作修改。
**精度不能简单全模型转换。** 模型参数和复数位置编码缓冲区保持原精度,在推理上下文开启 BF16 autocast;直接对整个模型调用 BF16 转换会影响复数缓冲区及要求 FP32 的路径。
**提示和选择。** `sam_segment.py` 将原图合成白底 RGB,GPU 只编码一次;每个部件分别收集 text_only 与 text_and_box 候选。排序结合模型分数、粗框内比例、Alpha 越界比例和种子命中;前景不足 4 像素或框内比例低于 10% 的候选被拒绝。粗框是提示,并非强制裁剪边界。
**重点:当前不是 SAM 点提示分割。** 所用图像概念接口接受文本和框。第一阶段程序种子仅参与返回 mask 排序,模型原始点不传入 SAM。提高种子前景命中率不能保证选中正确部件。
**像素与质量。** `segmentation_outputs.py` 用原图 Alpha 裁掉背景,从原图复制 RGB/Alpha,不重绘、不缩放;保留多部件重叠。记录越界、碎片、未命中种子、漏分、重叠和 IoU≥0.8 的疑似重复。覆盖率不是语义准确率,原像素保真也不能修复错误归属。
**当前预览含原图纹理。** `annotated.png` 是原图上 Alpha=100 的彩色 mask 叠加,不是仅用纯色区域组成的角色图;`parts-sheet.png` 为带 ID 的白底拆件。纯色遮罩角色图属于第 8 节的待实现项。
## 6. 各个代码文件职责索引
| 文件 | 职责 |
| --- | --- |
| `--sam-dir` | SAM 根目录 |
| `--sam-code-dir` | 源码仓库目录,内部应包含 `sam3/model_builder.py` |
| `--sam-checkpoint` | 本地权重文件 |
| `--sam-confidence` | SAM 候选分数阈值,默认 0.2,不是语义正确率 |
| `--sam-precision` | 默认 bf16 自动混合精度;可设 fp32,可能需要更多显存 |
| [tools/model-check.mjs](../tools/model-check.mjs) | 独立分割入口、参数解析 |
| [stages/segmentation-stage.mjs](../stages/segmentation-stage.mjs) | 输入校验、环境探测、子进程、哈希、日志与失败处理 |
| [lib/config.mjs](../lib/config.mjs) | SAM 路径与配置解析 |
| [lib/python-runtime.mjs](../lib/python-runtime.mjs) | ai-spine 解释器与基础依赖检查 |
| [lib/images.mjs](../lib/images.mjs) / [lib/validate-parts.mjs](../lib/validate-parts.mjs) | PNG 元数据 / v2 计划结构校验 |
| [lib/run-artifacts.mjs](../lib/run-artifacts.mjs) | 输出目录、复用、产物哈希 |
| [sam_runtime.py](../sam_runtime.py) | 依赖/CUDA 探测、源码路径、检测权重适配与严格加载 |
| [sam_segment.py](../sam_segment.py) | 提示校验、GPU 推理、候选排序、诊断与阶段组织 |
| [segmentation_outputs.py](../segmentation_outputs.py) | mask QA、原像素提取、标注图、拆件图、HTML |
| [tests/test_segmentation.py](../tests/test_segmentation.py) | 候选、提示、Alpha、裁剪保真和重叠回归 |
| [tests/model-stages.test.mjs](../tests/model-stages.test.mjs) | 阶段入口和相关本地回归调度 |
Node 先启动环境探测子进程,再启动一次推理子进程。模型只加载到后者;没有监听端口或常驻服务,正常结束、报错、超时或收到取消信号后退出。推理超时为 20 分钟。禁用 Hugging Face 在线下载,权重只能来自本地。
`segment.py` 是旧版白底拆件图分割器,不是本阶段 SAM 入口;`compose_preview.py`、`run_case_matrix.py` 是旧版定位/组装对照工具,不应与新阶段混用。
`sam_runtime.py` 从 multiplex checkpoint 提取 `detector.*`。SAM 3.1 的检测分支有三个特征尺度;图像 builder 的第四尺度原本会被 scalp 丢弃,因此适配器移除该未使用尺度并取消 scalp。忽略视频交互/传播 neck,随后 `strict=True` 加载所有实际使用参数;结构不匹配会报错。未修改外部 SAM 源码。
## 7. 产物详细说明
保留 FP32 参数和复数位置编码缓冲区,仅在推理上下文开启 BF16 autocast。不能直接把整个模型转换为 BF16,这会破坏复数缓冲区及上游要求 FP32 的解码器路径。
## 提示、选择与质量检查
1. 在白色背景上合成参考图,保持原尺寸;GPU 只编码一次图像。
2. 每个部件先用语义文本推理,再加入归一化粗框推理,保留两组候选。
3. 根据模型分数、粗框内比例、越出角色 Alpha 的比例及候选点命中情况排序。拒绝前景不足 4 像素或框内比例低于 10% 的结果。
4. 最终 mask 与原图 Alpha 前景取交集,从原图提取 RGB 和 Alpha,不重绘、不缩放。原始选中 mask 另存用于检查越界。
5. 记录漏分、重叠、碎片化、候选点未覆盖,以及不同部件 mask IoU ≥ 0.8 的疑似重复。
当前使用的 SAM 图像概念接口接受文本与框,不接受点。第一阶段的 Alpha 候选点仅用于 mask 排序;模型原始点仍只用于第一阶段诊断。这次 mask 来自真实 GPU 模型推理。
粗框、候选点及模型分数都不能保证部件语义正确。因此所有结果保持 `quality_status=needs_review`、`semantic_verified=false`。重叠 mask 保留,未强行分配成互斥部件,也未补全遮挡纹理。人工复核通过后才能继续补全或导出。
## 输出
| 文件 | 内容 |
| 路径 | 内容与用途 |
| --- | --- |
| `annotated.png` | 原尺寸角色图,各候选部件用不同半透明颜色叠加,透明背景显示为白色 |
| `parts-sheet.png` | 白底拆解图,部件保持原尺寸、分开排布,并标注 ID 和颜色 |
| `parts/<id>.png` | 紧裁剪的 RGBA 部件,保留原图像素及 Alpha |
| `masks/<id>.png` | 原图尺寸黑白 mask,已裁掉 Alpha 背景 |
| `candidates/<id>-raw.png` | 选中的 SAM 原始 mask,裁掉背景前 |
| `unassigned-mask.png` | 白色表示没有被任何部件 mask 覆盖的角色像素 |
| `overlap-mask.png` | 白色表示被多个部件 mask 覆盖的像素 |
| `segmentation.json` | 裁剪坐标、拆解图坐标、颜色、质量指标、运行环境和模型加载信息 |
| `candidate-diagnostics.json` | 两种提示的候选分数、排序、拒绝原因及最终选择 |
| `report.html` | 两张预览、部件链接、告警、漏分及重复检查 |
| `worker.log` / `worker-error.json` | 子进程日志 / 失败诊断(发生错误时) |
| `manifest.json` | 状态、输入/代码/权重/产物哈希,完成时记录子进程已退出 |
| `source.png` / `semantic-parts.json` / `segmentation-prompts.json` | 输入副本,保留坐标与语义来源 |
| `annotated.png` | 原尺寸原图 + 半透明彩色 mask,背景合成白色 |
| `parts-sheet.png` | 原尺寸拆件分开排布的白底图,含 ID 与颜色标记 |
| `parts/<id>.png` | 紧裁剪 RGBA 部件,保留原图像素 |
| `masks/<id>.png` | 原画布尺寸的二值 mask,0/255,已裁掉 Alpha 背景 |
| `candidates/<id>-raw.png` | 选中的原始 SAM mask,尚未裁 Alpha,用于越界诊断 |
| `unassigned-mask.png` | 白色为没有任何部件覆盖的角色前景 |
| `overlap-mask.png` | 白色为多个部件共同覆盖的区域 |
| `segmentation.json` | 部件路径、crop_xyxy、sheet_xyxy、颜色、QA、跳过列表、覆盖率、运行环境、加载记录 |
| `candidate-diagnostics.json` | 两种提示候选的分数、排序、拒绝原因和最终选择 |
| `report.html` | 预览、部件链接、告警及漏分/重复复核 |
| `worker.log` / `worker-error.json` | 日志 / 子进程错误诊断(失败时) |
| `manifest.json` | 状态、输入/代码/权重/产物哈希;完成后 gpu_worker_exited=true |
`crop_xyxy` 使用原图坐标,右下角为开区间;`sheet_xyxy` 使用白底拆解图坐标。覆盖率是像素覆盖比例,不是准确率。
`crop_xyxy` 为原图坐标,`sheet_xyxy` 为拆解图坐标,右下角均为开区间。第三阶段依赖全画布 masks,不以紧裁剪 parts 反推位置。
## 代码与验证记录
当前质量基线是 `output/20260918-183532/sam`:32 个计划项中 10 个 hidden 跳过,22 个 mask,前景覆盖率约 83.3%,32719 像素未分配。图中 forearm_r/hand_r 存在衣料误分,前臂混入手部,上衣及袖子存在缺失。更早 `sombrero-sam31-v3` 为另一批 28 个 mask、约 67.18% 覆盖率,不能混用统计。真实 GPU 推理跑通不代表拆件可直接用于动画。
- [stages/segmentation-stage.mjs](../stages/segmentation-stage.mjs):输入校验、Conda 子进程、哈希、缓存、日志和失败处理。
- [sam_runtime.py](../sam_runtime.py):环境探测和本地权重严格加载。
- [sam_segment.py](../sam_segment.py):GPU 推理、两组候选选择和诊断。
- [segmentation_outputs.py](../segmentation_outputs.py):mask QA、原像素拆件、两张预览和报告。
- [tests/test_segmentation.py](../tests/test_segmentation.py):Alpha 越界、候选选择、提示完整性、像素保真和重叠/重复检查。
## 8. 当前阶段可改进点说明
2026-09-18 实测 `output/sombrero-grounding-v2` → `output/sombrero-sam31-v3`:28 个部件返回 mask,严格加载 1130 个检测参数/缓冲张量;推理及渲染约 11.64 秒(不含环境探测和加载权重),PyTorch 峰值已分配显存约 4.97 GiB,结束后无 SAM 子进程。
以下均为待实现或待验证的改进方向:
这组结果覆盖原图前景约 67.18%,仍有 64286 像素未覆盖、30569 像素重叠。`shin_left` 和 `foot_left` 的 mask IoU 约 0.843,实际都分到了鞋子;躯干及其他肢体也存在碎片或错分。文本候选对照未解决这些问题。这说明推理和输出链路已跑通,但当前旧语义计划与提示策略尚不能产出合格的最终拆件;需要修正部件粗框并继续验证提示及 mask 语义。
同日 `conda run --no-capture-output -n ai-spine npm test` 的 17 项测试全部通过(包括 Python 分割回归用例);真实产物 `--resume` 哈希校验复用通过。测试通过仅验证程序行为,不表示上述分割质量合格。
后续已接入[第三阶段部件补全](3-completion-stage.md)。该阶段直接读取本目录的 `source.png`、`semantic-parts.json`、`segmentation.json` 和全画布 `masks/`;保留本阶段的告警,不能通过生成隐藏纹理来修复错误的部件归属。
- **输出仅色彩遮罩的完整角色图。** 在原画布上以各部件纯色展示分区,不叠加原图纹理;保留现有 annotated.png。需明确重叠显示顺序,将未分配区域单独标识,不能为了“完整”伪造已识别区域。
- **可选的大模型去毛边。** 对每个通过部件归属复核的 SAM 拆件增加一次可选边缘清理,提供对应原图局部参考,约束修改范围,保存清理前后、mask 差异和坐标。默认保留原始拆件;清理不能冒充隐藏补全,也不能把重绘结果称为原像素。
- **先修正语义误分。** 明确左右、隐藏状态和粗框,复核衣料/皮肤/手部归属;对明显错误、缺失或疑似重复输出阻断性状态,再进入补全。
- **改善覆盖和边界。** 对未分配前景、过度重叠及大孔洞做定位复核;区分合理遮挡与分割缺口,避免一刀切强制所有 mask 互斥。
- **重评补全需求。** 基于实际 mask 检查袖子、衣服等缺损,反馈第三阶段;不能仅沿用第一阶段 needs_completion。
- **增加语义验收。** 模型分数、前景命中和覆盖率只作辅助;将原图、候选、最终 mask 并排复核,记录人工修正及来源。
+148 -104
View File
@@ -1,149 +1,193 @@
# 第三阶段:部件补全
本阶段处理第一阶段声明的 `occlusion_fill`、`joint_extension_parent`、`joint_extension_child`,读取第二阶段的可见 mask,为部件生成局部画布,调用图片编辑模型并合并受限的新增像素。原图已可见区域的 RGBA 像素始终从原图恢复,不使用模型重绘的版本。
## 1. 阶段简介
使用 [AGENTS.md](../AGENTS.md) 规定的 Conda `ai-spine` 环境,不需要额外安装依赖。第三阶段几何处理使用本地 Python;图片生成通过现有中转站 `images/edits` 接口完成。
读取 SAM 可见 mask,为需要遮挡补全或关节延伸的部件准备局部画布,调用中转站图片编辑模型,再将允许区域内的新增像素与原可见像素合并。Python 几何处理固定使用 Conda `ai-spine`;图片生成在远端完成,本阶段不加载本地 SAM。
切换 Tiantoken 中转站时,在命令中增加 `--config .\configs\tiantoken.json`,并删除示例中的 `--completion-model qwen-image-3.0`,或改为 `--completion-model gpt-image-2`。该配置读取独立的 `TIANTOKEN_BASE_URL` / `TIANTOKEN_API_KEY`,第三阶段默认 `gpt-image-2`。目前仅验证模型列表可访问,实际图片编辑能力尚未实测;`gpt-6-astra` 的 Responses 图片生成工具仍需另行适配。
当前已实现准备、真实图片请求、离线候选导入、几何检查与透明补全部件输出。尚未输出使用补全部件组装的完整角色,尚未接入新管线 Spine 导出。几何通过仍为 `needs_review`,不能等同于部件可用。
## 命令
## 2. 输入、输出与执行链路
在 PowerShell 中进入项目并激活环境:
输入是第二阶段目录;输出是任务画布、候选、检查报告及通过几何检查的补全部件。
```text
tools/model-check.mjs --stage completion --input-dir SAM目录
→ stages/completion-stage.mjs 校验计划、mask 文件、参数及 Conda
→ completion_geometry.py prepare
筛选需求 → 计算允许区域 → 建立局部画布与编辑 mask
→ prepare-only:保存任务和报告后结束
→ 否则:串行请求 images/edits,或读取离线候选
→ completion_geometry.py merge
检查画布/前景/对齐 → 限制新增区域与连通性 → 恢复原可见像素
→ 每部件选第一个通过几何检查的候选
→ finalize 输出透明部件、原图坐标和报告
```
任务必须同时满足:计划 `needs_completion=true`、非 hidden、有可见 SAM mask、允许新增区域非空。指定 `--part` 只缩小范围,不强制绕过筛选。分别记录 `NO_COMPLETION_NEEDED`、`NO_VISIBLE_SAM_MASK`、`NO_ALLOWED_EXTENSION`。
以 `output/20260918-183532/sam` 为例:32 个计划项中 10 个 hidden 没有 mask;22 个有 mask,其中 12 个进入补全。帽子、两袖、两眼、两眉、鼻、嘴、胡子这 10 个因第一阶段标记不需补全而跳过,没有重新由模型判断实际 mask 完整性。
## 3. 阶段执行命令示例及参数说明
以下命令在项目根目录执行;输入示例是已有实验,不代表其 mask 已合格。
```powershell
Set-Location F:\Study\taonier\AI_spine
conda activate ai-spine
$runId = Get-Date -Format "yyyyMMdd-HHmmss"
```
$samInput = ".\output\20260918-183532\sam"
只准备任务(离线、无需 API Key):
```powershell
# 离线准备所有符合条件的任务,无需密钥
node .\tools\model-check.mjs --stage completion `
--input-dir .\output\sombrero-sam31-v3 `
--out-dir ".\output\$runId-prepare" `
--completion-model qwen-image-3.0 `
--config .\configs\tiantoken.json `
--input-dir $samInput `
--out-dir ".\output\$runId\complete-prepare" `
--prepare-only
```
真正调用模型补全一个部件,需要 `.env` 中的中转站地址与密钥,会产生图片请求:
```powershell
# 单部件真实图片编辑请求
node .\tools\model-check.mjs --stage completion `
--input-dir .\output\sombrero-sam31-v3 `
--out-dir ".\output\$runId-complete-head" `
--completion-model qwen-image-3.0 `
--config .\configs\tiantoken.json `
--input-dir $samInput `
--out-dir ".\output\$runId\complete-head" `
--completion-model gpt-image-2 `
--part head
```
`--part head --part neck` 指定多个部件。省略 `--part` 时处理所有可用且需要补全的部件,每个部件单独发出请求;当前模型配置 `n=1`。程序串行调用,沿用提供方的超时及显式 429/5xx 重试策略,超时/网络中断不自动重复生成。发生请求错误保留候选和诊断,停止后续部件。
离线导入已经生成的候选(无需 API Key):
```powershell
# 所有符合条件的部件,逐部件请求模型
node .\tools\model-check.mjs --stage completion `
--input-dir .\output\sombrero-sam31-v3 `
--out-dir ".\output\$runId-merge" `
--part head `
--candidates-dir .\completion-candidates
--config .\configs\tiantoken.json `
--input-dir $samInput `
--out-dir ".\output\$runId\complete"
```
候选文件名为 `completion-candidates/head.png`,必须与对应任务的局部画布尺寸、坐标完全一致。准备与合并必须使用相同输入、`--completion-size` 和 `--extension-radius`。缺失候选记为 `missing_candidate`,不会联网补发。可将先前任务保存的原始候选复制为 `ID.png`,离线检查它,避免重复计费。
使用 Qwen 时改为 `--config .\configs\deepseek-qwen.json --completion-model qwen-image-3.0`,读取原中转配置。Tiantoken 配置第三阶段为 `gpt-image-2`,第一阶段的 `gpt-6-astra` 不是当前图片编辑接入的替代品;未实现 Astra Responses 图片生成工具链。
`--candidates-dir` 也支持直接指向旧补全输出目录:读取 `tasks/<id>/candidate-1.png`(亦支持 jpg/webp),不下载、不重新生成。程序先核对旧 manifest 中的源图、语义计划、SAM mask 哈希及画布/延展参数是否与本次一致;不同则拒绝复用。该模式只取每部件首张原候选。
### 返回尺寸与输入不一致时
`--completion-size` 控制局部画布,不能单靠提示词保证模型输出相同尺寸。修复后第三阶段会同时发送 multipart 参数 `size=画布宽x画布高`,默认 `1024x1024`,并在每部件 `request.json` 记录实际请求尺寸。配置中的 `completion.params.size` 若与画布不同会在调用前报错。[OpenAI 编辑接口的 size 参数](https://developers.openai.com/api/reference/cli/resources/images/methods/edit)有明确的输出尺寸含义,但中转站是否遵守仍以实测结果为准。
默认 `--candidate-size-policy strict` 仍拒绝尺寸不一致。已有候选可以使用 `uniform` 模式离线尝试恢复:仅允许相同宽高比的整张画布等比例缩放,再执行原有的颜色/位置、可见像素保留率、新增区域和连通性检查。不对物体单独缩放、不平移、不裁剪,也不放宽对齐阈值。原图和 SAM mask 始终不缩放。
旧候选离线复检,不重新请求模型:
```powershell
node .\tools\model-check.mjs --stage completion `
--config .\configs\tiantoken.json `
--input-dir .\output\20260918-183532\sam `
--input-dir $samInput `
--candidates-dir .\output\20260918-183532\complete2_gpt `
--out-dir ".\output\$runId-size-recheck" `
--out-dir ".\output\$runId\complete-recheck" `
--candidate-size-policy uniform
```
该命令不请求图片模型。原始候选保留,缩放后的候选另存为 `merged-N-normalized.png`,QA 记录原始/目标尺寸、比例、重采样方法和告警。即便最终通过几何检查也仍需语义复核;如果模型同时重绘、放大或移动了部件,可能继续报 `VISIBLE_ALIGNMENT_MISMATCH`。
仅测试图片编辑接口的独立探针:
2026-09-20 对 `complete2_gpt` 的 12 张原始候选实测:输入均为 1024×1024,输出为 1248×1248 或 1254×1254。旧请求未发送 size。离线 uniform 复查后 8 个通过几何检查、4 个因对齐不符或无有效新增像素拒绝;原始文件未覆盖,也没有重新请求生成。报告位于 `output/20260918-183532/complete2_gpt-size-recheck-v2/report.html`。22 项测试通过,含请求 size、等比例恢复后的像素保真、宽高比/偏移拒绝及旧任务输入匹配检查。显式 size 已通过请求构造测试,尚未再次付费验证中转站是否遵守。
```powershell
node .\tools\model-check.mjs --stage completion `
--config .\configs\tiantoken.json `
--image .\output\20260918-183532\complete2_gpt\tasks\head\input.png `
--prompt-file .\output\20260918-183532\complete2_gpt\tasks\head\prompt.txt `
--out-dir ".\output\$runId\edit-probe"
```
每个输出目录必须是新目录;`--resume` 仅复用已完整结束且输入、参数、源码和产物哈希一致的任务。准备模式与生成模式使用不同目录。失败任务不自动续发请求。
探针只保存候选,不执行部件准备与几何验收,不能与 `--input-dir` 混用。
| 参数 | 作用 |
| 参数 | 说明 |
| --- | --- |
| `--input-dir` | SAM 输出目录,必须含 `source.png`、v2 计划、`segmentation.json`、`masks/<id>.png` |
| `--part ID` | 指定部件,可重复;省略时处理全部有补全需求的部件 |
| `--prepare-only` | 只准备画布、区域与提示词,不请求图片模型 |
| `--candidates-dir` | 离线读取 `ID.png` 或旧补全目录首张候选,与 prepare-only 互斥 |
| `--candidate-size-policy` | strict(默认):严格尺寸一致;uniform:同宽高比缩放后重新检查 |
| `--completion-size` | 方形局部画布边长,默认 1024,128~4096;不缩放原像素 |
| `--extension-radius` | 新增区域距可见 mask 的最大距离,默认 32 像素,1~256 |
| `--completion-model` | 图片模型原始 ID,当前示例使用 qwen-image-3.0 |
| `--dry-run` | 检查输入文件、计划、参数和 Python 环境,不生成画布或请求模型 |
| `--input-dir DIR` | 完整 SAM 输出目录,部件补全必需 |
| `--out-dir DIR` | 独立新目录,准备与生成使用不同目录 |
| `--part ID` | 可重复,ID 必须存在且不重复;省略时处理所有符合筛选条件的部件 |
| `--prepare-only` | 只生成画布、区域、提示词和报告,不请求模型 |
| `--candidates-dir DIR` | 离线导入候选,与 prepare-only 互斥 |
| `--completion-size N` | 方形画布边长,默认 1024,整数 128~4096;原像素不缩放 |
| `--extension-radius N` | 轮廓延展距离与关节圆盘半径,默认 32,整数 1~256 |
| `--candidate-size-policy NAME` | strict 默认拒绝尺寸不符;uniform 允许同宽高比整画布缩放后复检 |
| `--completion-model ID` | 图片模型 ID,原样发送 |
| `--config FILE` / `--env-file FILE` | 默认 astra-qwen.json / 项目 .env;shell 同名变量优先 |
| `--python FILE` | 仅允许 ai-spine 解释器 |
| `--dry-run` | 检查输入文件、计划、参数和 Python 基础环境,不准备画布或请求模型;完整像素级 mask 校验在 prepare 中执行 |
| `--resume` | 仅复用已完成、输入/配置/源码/产物一致的任务,不自动续发失败请求 |
| `--image FILE` / `--prompt-file FILE` | 仅用于探针:PNG 图片 / 文本提示词;多次 image 需配置多图能力 |
| `--mask FILE` | 仅用于探针:透明处可编辑的 RGBA PNG,需配置 mask 能力 |
旧的 `--stage completion --image ... --prompt-file ...` 保留为独立接口探针,不能与 `--input-dir` 混用。`--stop-after` 目前仍只支持 understand/segment;第三阶段独立调用。
配置中默认 `n=1`,逐部件串行调用。明确的 429/5xx 有限重试,超时/断网不自动重试;请求失败保留诊断并停止后续部件,几何拒绝会记录结果并继续。`--stop-after` 不支持 completion。
## 允许新增区域
## 4. 输入格式要求
候选不可以随意扩大部件。程序在原图坐标中构造以下区域,并始终排除原可见 mask:
- 遮挡补全:可见轮廓外 `extension-radius` 范围,与 `occluded_by` 指向的 SAM mask 的交集。
- 向父关节延展:同一距离范围,与本部件 `pivot_norm` 附近半径为 `extension-radius` 的圆盘的交集。
- 向子关节延展:同一距离范围,与直接子骨骼部件的 pivot 圆盘的交集。
这些是保守的几何候选区域,不是推断出的完整隐藏形状。缺少遮挡 mask、关节过远或没有子骨骼时,相应区域为空并记录告警。所有区域都为空时跳过该部件。完全隐藏或没有可见 SAM mask 的部件也跳过,不凭空生成完整肢体。
局部画布包含可见区域与允许新增区域,至少留 16 像素边距。`origin_xy` 记录局部左上角在原图中的坐标,可为负数;只有平移和补透明边,不进行缩放。所需范围放不下时失败,需增大画布。新增区域目前限定在原图画布范围内。
输入给模型的是白底可见部件。只有配置明确声明 `capabilities.mask=true` 时才发送 RGBA 编辑 mask(透明处可编辑);只有 `multiple_images=true` 时才发送第二张局部原图参考。默认配置二者均为 false,不假定中转站支持这些能力。无论是否发送编辑 mask,返回候选都经过本地允许区域约束。
## 返回候选的检查和合并
1. 默认要求尺寸与局部画布完全一致。显式选择 uniform 时,只对同宽高比候选做整画布等比例恢复;宽高比不同仍拒绝。所有模式都不自动重定位或裁切。
2. 已有透明背景保留;不透明白底使用边界连通近白区域去底。无法提取前景则拒绝。
3. 使用原部件 Alpha ≥240 的像素检查对齐:候选保留率至少 95%,RGB 平均绝对误差不大于 30。无不透明锚点则拒绝。这只能发现明显偏移或重绘,不能保证语义正确。
4. 只保留允许区域中的新增像素,并去掉与原可见部分不连通的新增块。越界和不连通像素数量写入 QA。没有新增像素则拒绝。
5. 原可见 mask 内 RGBA 逐像素恢复;候选仅提供新增像素。记录各补全子区域新增数量及 `unfulfilled_regions`,存在空缺的要求不会冒充已完成。
6. 每个返回候选分别检查,选择第一个通过几何条件的候选。输出始终 `semantic_verified=false`、`quality_status=needs_review`。
上游 SAM mask 有碎片、重复或语义错分时会原样影响补全,告警保存在 JSON 和报告中。颜色/位置检查也不能验证隐藏纹理是否合理。白底去除可能影响贴边白色细节,仍需人工检查。
## 产物
| 路径 | 内容 |
| 输入 | 要求 |
| --- | --- |
| `completion-plan.json` | 所有已准备任务、区域及跳过原因 |
| `tasks/<id>/input.png` | 发给模型的白底局部部件 |
| `tasks/<id>/visible.png` | 从原图保存的 RGBA 可见部件,合并时恢复像素 |
| `tasks/<id>/context.png` | 同坐标局部原图参考 |
| `tasks/<id>/edit-mask.png` | RGBA 编辑 mask,透明处允许编辑 |
| `tasks/<id>/allowed-mask.png` | 白色表示允许新增像素的区域 |
| `tasks/<id>/<补全字段>.png` | 三种补全要求各自的允许区域 |
| `tasks/<id>/task.json` / `prompt.txt` | 坐标、补全需求、上游告警 / 实际提示词 |
| `tasks/<id>/candidate-N.*` | 模型或离线导入的原始候选,拒绝时也保留 |
| `tasks/<id>/qa-N.json` | 单候选检查结果与拒绝原因 |
| `tasks/<id>/merged-N.png` | 通过几何检查后的局部 RGBA,已恢复可见像素 |
| `parts/<id>.png` | 被选中的补全候选,紧裁剪透明 PNG |
| `completion-result.json` | 每部件状态、候选 QA、原图裁剪坐标和输出路径 |
| `report.html` | 原可见部件、允许新增区域、补全候选和告警 |
| `manifest.json` | 运行模式、网络请求标记、输入/代码/产物哈希及计数 |
| `source.png` | 原画布 PNG,使用第二阶段的 RGBA 原图 |
| `semantic-parts.json` | 有效 v2 计划;部件分类、遮挡、pivot 和补全需求合法 |
| `segmentation.json` | parts 数组,ID 唯一且存在于计划中 |
| `masks/<id>.png` | segmentation.parts 中每个 ID 都必须有文件;原画布尺寸,灰度值仅 0/255,非空,不覆盖原图 Alpha=0 区域 |
| 中转配置 | 在线模式需地址、密钥、images-edits 提供方及图片模型;prepare-only/离线导入无需密钥 |
`parts/` 只包含本次被选中且通过几何检查的补全部件。无需补全、未选中和被拒绝的部件不会被伪装成新补全结果;最终组装需结合原 SAM 部件及这里的替换文件。Spine 导出尚未接入。
只提供 SAM 的 `parts/` 或白底拆解图不满足要求。输入目录中无需存在 annotated.png 才能运行,但建议先通过报告复核语义。
## 实现和验证
离线候选支持两种形式:
[stages/completion-stage.mjs](../stages/completion-stage.mjs) 调度准备、请求、候选检查及缓存;[completion_geometry.py](../completion_geometry.py) 实现区域构造、Alpha 提取、原像素恢复和报告;[providers/image-edits.mjs](../providers/image-edits.mjs) 复用现有图片接口。
- 平铺目录:`<id>.png`,必须对应本次局部画布坐标、尺寸与部件;平铺文件没有旧任务 manifest 可自动核对,需自行保证一致。
- 旧补全目录:含 manifest 和 `tasks/<id>/candidate-1.png`,也支持 jpg/webp;逐项核对源图、计划、segmentation.json、全部 mask 哈希以及画布/延展参数。每部件只取首张候选。缺失记为 missing_candidate,不联网补发。
测试覆盖原尺寸坐标映射、Alpha 保真、三个补全字段、越界裁剪、尺寸/位移/空白候选拒绝、离线模式、显式多图与 mask 能力、错误诊断和缓存失效。使用 `conda run --no-capture-output -n ai-spine npm test` 执行,不调用真实付费模型。
不同原图、mask 或参数的候选不能混用。尺寸之外,部件位置、朝向、比例也必须保持一致。
最初接入时,sombrero-sam31-v3 输出可离线准备 17 个补全任务,11 个部件因无需补全而跳过。当时验证了真实输入的画布准备与 mock 编辑响应的完整合并链路,尚未执行真实 Qwen 图片生成。
## 5. 执行链路中重要部分代码文件及原理说明(包括重点说明)
本轮验证结果:22 项 Node 测试通过(其中包含 7 个 Python 补全用例),真实输入的 `--prepare-only` 和 `--resume` 均成功。准备产物位于 `output/sombrero-completion-prepared-v2/`,打开其中 `report.html` 可检查每个部件的画布与允许新增区域。
**允许区域。** `completion_geometry.py::allowed_regions()` 先计算可见 mask 外、距轮廓不超过 extension-radius 的区域,再分别与以下区域取交集:遮挡补全用 occluded_by 的 mask 并集;父关节延展用本部件 pivot 周围圆盘;子关节延展用直接子骨骼部件 pivot 圆盘。始终排除原可见 mask,新增范围限制在原图画布内。它是保守几何范围,不是完整隐藏形状推断。
2026-09-20 用户运行 `output/20260918-183532/sam` 的补全任务时,head 的真实响应同时含有有效 `url` 和空字符串 `b64_json`。原解码器将空字符串误当图片,报“不支持的 PNG/JPEG/WebP 格式”。已修复为空值时使用 URL 下载,并覆盖空串、空白字符串及 null 的回归测试;22 项测试通过。
**局部坐标。** `prepare()` 将可见区和允许区居中放入方形画布,至少留 16 像素边距,只平移和补边。`origin_xy` 是局部左上角在原图的位置,可为负数;原图位置=局部位置+origin。放不下时失败,不能偷偷缩放原像素。
本次已从保存的 `complete/tasks/head/response.raw.json` 下载原生成结果,没有再次调用生成接口。图片保存在同级 `complete-recovered-candidates/head.png`。真实输出为 2048×2048,输入画布为 1024×1024,因此离线合并被 `CANVAS_SIZE_MISMATCH` 拒绝,报告位于 `complete-recovered-head-check/report.html`。这次格式解析问题已解决,但尺寸约束尚未通过;不能把已有 1024 输入任务的候选直接改用 `--completion-size 2048` 合并,因为新画布的像素坐标也会变化。
**重点:当前实际发送什么。** `stages/completion-stage.mjs` 默认只发送白底 `input.png`。三个现有配置均为 `multiple_images=false`、`mask=false`,因此本地生成 context.png 和 edit-mask.png 不意味着发给模型。只有开启并验证对应能力后,分支才发送第二张同坐标局部原图参考和编辑遮罩;当前没有独立全角色参考图输入。文字边界说明及返回后的区域裁剪不能替代模型侧遮罩约束。
**图片解码与尺寸。** `providers/image-edits.mjs` 使用 multipart images/edits,支持非空 b64_json 或返回 URL 下载;空 b64_json 会回退有效 URL。当前部件请求显式发送 size=画布宽x高,并写入 request.json;配置 params.size 冲突会报错。strict 模式拒绝 CANVAS_SIZE_MISMATCH;uniform 仅将同宽高比整画布 LANCZOS 缩放到目标尺寸,保留原候选,不平移、不裁剪、不单独缩放物体,也不改变原图/mask。
**几何验收与合并。** `merge_candidate()` 去除边界连通白底,在原部件 Alpha≥240 的像素处检查 RGB 平均绝对误差≤30、可见保留率≥95%;无不透明锚点拒绝。只取允许区域内且与原部件连通的新增像素,没有有效新增即拒绝。通过后逐像素恢复原可见 RGBA,模型只提供新增部分。
**重点:验收仍有缺口。** `unfulfilled_regions` 记录未补到的子区域,但当前不是硬性拒绝条件;某一区域新增少量像素也不代表关节补够。语义、接缝、材质、运动露底没有自动验收。错误 SAM 像素会被原样恢复;若头部 mask 已含眼睛/胡子,当前规则也不能清除这些内部附件生成干净脸底。
## 6. 各个代码文件职责索引
| 文件 | 职责 |
| --- | --- |
| [tools/model-check.mjs](../tools/model-check.mjs) | 部件补全与独立探针分发、参数互斥检查 |
| [stages/completion-stage.mjs](../stages/completion-stage.mjs) | 输入指纹、准备、串行请求/离线读取、候选选择、状态留档 |
| [completion_geometry.py](../completion_geometry.py) | allowed_regions、prepare、merge_candidate、finalize 与报告 |
| [normalize_reference.py](../normalize_reference.py) | 候选 Alpha 保留、边界连通白底提取 |
| [providers/image-edits.mjs](../providers/image-edits.mjs) | multipart 编辑请求、能力检查、Base64/URL 图片解码 |
| [providers/http.mjs](../providers/http.mjs) | HTTP、超时、重试、诊断和脱敏 |
| [stages/model-stage.mjs](../stages/model-stage.mjs) | runCompletionProbe,仅验证编辑接口 |
| [lib/config.mjs](../lib/config.mjs) / [lib/images.mjs](../lib/images.mjs) | 提供方、模型与能力配置 / 图片格式、尺寸和哈希 |
| [lib/python-runtime.mjs](../lib/python-runtime.mjs) / [lib/validate-parts.mjs](../lib/validate-parts.mjs) | Conda 检查 / v2 结构校验 |
| [lib/run-artifacts.mjs](../lib/run-artifacts.mjs) | 输出目录、复用、状态和产物哈希 |
| [prompts/complete-v1.txt](../prompts/complete-v1.txt) | 保持姿势、尺寸、可见纹理与隐藏区域补全约束 |
| [Tiantoken](../configs/tiantoken.json)、[DeepSeek/Qwen](../configs/deepseek-qwen.json)、[Astra/Qwen](../configs/astra-qwen.json) 配置 | 图片模型、认证变量、请求参数与能力开关 |
| [tests/completion-stage.test.mjs](../tests/completion-stage.test.mjs) / [tests/test_completion.py](../tests/test_completion.py) | mock 编辑、离线复用、尺寸/对齐拒绝、像素保真与区域回归 |
| [tests/model-stages.test.mjs](../tests/model-stages.test.mjs) | 提供方与探针相关回归 |
## 7. 产物详细说明
| 路径 | 内容与用途 |
| --- | --- |
| `source.png`、`semantic-parts.json`、`segmentation.json`、`masks/` | 输入快照,用于复现与离线候选身份核对 |
| `completion-plan.json` | 准备任务、允许区域、参数和跳过原因 |
| `tasks/<id>/input.png` | 白底局部可见部件,默认唯一模型输入图 |
| `tasks/<id>/visible.png` | 原图可见 RGBA,合并时恢复像素 |
| `tasks/<id>/context.png` | 同坐标局部原图参考,当前默认不发送 |
| `tasks/<id>/edit-mask.png` | RGBA 编辑遮罩,透明处可编辑,当前默认不发送 |
| `tasks/<id>/allowed-mask.png` | 白色表示允许新增区域 |
| `tasks/<id>/<补全字段>.png` | 启用的补全子区域 mask |
| `tasks/<id>/task.json` / `prompt.txt` | origin、区域、需求和告警 / 实际提示词 |
| `tasks/<id>/request.json` | 在线请求模型、图片哈希、是否发送 mask;修复后含 size |
| `tasks/<id>/response.raw.json` / `request-metadata.json` | 在线响应留档 / 请求 ID、耗时等元数据 |
| `tasks/<id>/response.error.json` | 可获取时保存的脱敏请求失败诊断 |
| `tasks/<id>/candidate-N.*` | 模型或离线导入的原始候选,拒绝也保留 |
| `tasks/<id>/merged-N-normalized.png` | uniform 实际重采样时保存的候选;不代表通过 |
| `tasks/<id>/qa-N.json` | 尺寸、对齐、新增/丢弃像素、各区域完成情况、拒绝原因 |
| `tasks/<id>/merged-N.png` | 通过几何检查且恢复原可见像素后的局部 RGBA |
| `parts/<id>.png` | 每部件选中结果的紧裁剪透明 PNG |
| `completion-result.json` | 每部件状态、候选 QA、原图 crop_xyxy 和路径 |
| `report.html` / `manifest.json` | 人工检查页 / 模式、网络标记、状态、输入/代码/产物哈希 |
parts/ 只含本次选中且通过检查的补全部件,不是全部 SAM 部件集合。无需补全、失败和未选中的部件不会自动复制进来,也没有完整角色组装图。
当前实验:`output/20260918-183532/complete2_gpt` 已真实请求 Tiantoken gpt-image-2 共 12 个部件。旧请求未传 size,返回 1248/1254 方形图,预期为 1024,全部严格尺寸拒绝。`complete2_gpt-size-recheck-v2` 离线复用原候选后,8 个几何通过;head、pants_thigh_l、pants_thigh_r、shoe_l 共 4 个因对齐或无有效新增拒绝。通过项中仍有衣料误分、错误手部和未补全子区域。显式 size 的请求构造已验证,但尚无修复后中转遵守 size 的新实测结论。
## 8. 当前阶段可改进点说明
- **补全后输出使用补全部件的完整角色。** 按原图坐标和遮挡顺序组装,复用无需补全的原拆件,明确标记失败项及回退来源;输出补全前后对比、接缝/重叠诊断。不能只展示少数 parts 文件作为完整结果。
- **把原图或部件相关原图区域交给补全模型参考。** 接入并实测全角色/局部上下文参考和编辑 mask,记录实际发送内容。不能仅把 capabilities 改为 true 就宣称中转支持;需验证图片顺序、mask 语义、返回尺寸和画面保持能力。
- **根据 SAM 实际结果重建需求。** 区分分割缺口修复、遮挡补全、关节延伸、附件底图清理;对应建立保留区域与可编辑区域,避免误分像素被永久保护。
- **改进画布与补全区域。** 固定 32 像素不适配所有部件;小部件在 1024 大白底中占比低。可验证按部件设计区域、显式局部放大并记录逆变换,保证回贴坐标可检查。
- **加强验收。** 对必需区域定义有效覆盖要求,增加部件语义、接缝、材质、回贴和关节旋转露底检查;不能放宽阈值来掩盖重绘、位移或错误输入。
- **按小样验证后批量。** 先修正 SAM 输入,再用头、前臂、上衣验证参考图与遮罩,比较原输入、原候选、合并图和回贴图,确认改善后再跑全量。
-172
View File
@@ -1,172 +0,0 @@
# 第一阶段:可替换模型接口与角色结构理解
本轮实现结构理解、图片编辑适配器、结构 JSON 校验、Alpha 几何校验、候选种子、诊断预览和实验缓存。几何层需要 Python 与 requirements.txt,不运行旧的“拆件图 → SIFT 定位”流程。
结构理解支持停在 `understand`,也可通过 `--stop-after segment` 接续本地 SAM 分割,或使用 `--stage segmentation --input-dir` 独立执行第二阶段。第三阶段使用 `--stage completion --input-dir SAM目录` 完成部件画布准备、候选生成、限制新增区域和原像素恢复,详见[第三阶段文档](3-completion-stage.md)。掩码语义修正、补全的语义验收和 Spine 骨骼导出尚未完成。旧的 `--image --prompt-file` 图片编辑探针仍只保存原始候选。
## 环境与模型
要求 Node.js 20 或更高版本,无新增 npm 依赖。在 `AI_spine` 目录、已激活的 `ai-spine` Conda 环境中运行。每次修改须遵守 [AGENTS.md](../AGENTS.md)。
复用现有 `.env` 的地址和密钥,可增加:
```dotenv
SPINE_UNDERSTANDING_MODEL=gpt-6-astra
SPINE_COMPLETION_MODEL=qwen-image-3.0
SAM_MODEL_DIR=F:/Study/SAM3
```
不配置这三项时,`configs/astra-qwen.json` 已提供相同默认值。不会自动改写用户的 `.env`。
查询中转站模型 ID(只读取列表,不调用生成):
```powershell
node .\tools\model-check.mjs --list-models
```
模型展示名不等于 API ID。2026-09-17 的本机接口查询包含 `gpt-6-astra` 和 `qwen-image-3.0`。支持列表不保证所有端点/多图/mask 参数可用,需要分别验证。
本地配置检查(不联网,不生成图片):
```powershell
node .\tools\model-check.mjs --dry-run
```
## 运行结构理解
```powershell
node .\pipeline.mjs --mode annotated-parts --reference ..\spine-animation-ai\demo\character_reference.png --out-dir .\output\sombrero-astra --stop-after understand
```
首次调用会向配置的中转站发送参考图。每个实验使用新输出目录;本轮不会自动覆盖旧产物。
切换理解模型:
```powershell
node .\pipeline.mjs --mode annotated-parts --reference ..\spine-animation-ai\demo\character_reference.png --out-dir .\output\sombrero-other --understanding-model YOUR_EXACT_MODEL_ID --stop-after understand
```
切换协议(需中转站实际支持):
```powershell
node .\pipeline.mjs --mode annotated-parts --reference ..\spine-animation-ai\demo\character_reference.png --out-dir .\output\sombrero-responses --understanding-protocol responses --stop-after understand
```
协议可选 `chat-completions` / `responses`,默认 `responses`:本机中转站实测 Astra 的 codex channel 明确拒绝 `/v1/chat/completions`。输出模式默认 `text-json`:在提示词中提供 Schema,并始终在本地严格校验。显式确认中转站支持后,可使用 `--output-mode json-object` 或 `--output-mode json-schema`。不会因 400/不支持的协议自动换模型或偷偷降低输出约束。
该 Astra 通道还要求 `stream=true`,所以默认配置启用流式 Responses,并设置 `store=false`。适配器收集 SSE 后只接受完整的终止事件,输出仍是普通 JSON 文件。新模型可在阶段配置中设置 `stream: false`。`response.raw.json` 对 SSE 保存终止事件中的 response 对象,非逐字节 SSE 日志;`request-metadata.json` 记录 wire_format。
切换到非流式 Chat Completions 模型时可使用 `--understanding-protocol chat-completions --stream false`,不会沿用 Astra 的流式设置。
项目同时提供 `configs/deepseek-qwen.json`。它把第一阶段固定为
`deepseek-flash + chat-completions + stream=false`,第三阶段仍使用
`qwen-image-3.0`,适合与默认的 `configs/astra-qwen.json` 做对照实验:
```powershell
node .\pipeline.mjs --mode annotated-parts `
--config .\configs\deepseek-qwen.json `
--reference ..\spine-animation-ai\demo\character_reference.png `
--out-dir .\output\sombrero-understand-deepseek `
--stop-after understand
```
主要产物:
| 文件 | 含义 |
| --- | --- |
| `source-original.png` / `source.png` | 原始输入 / 预处理 RGBA,不缩放、不裁剪 |
| `preprocessing.json` | Alpha 保留或边界连通白底去除记录 |
| `semantic-parts.json` | 已通过结构校验的部件清单 |
| `geometry-validation.json` | 原始点 Alpha 检查、ROI 前景比例、候选来源和阻塞原因 |
| `segmentation-prompts.json` | 语义 + 粗框 + 程序候选点;不转发模型原始点,始终需要 mask QA |
| `annotated.svg` | 原图上的粗框、关节点、正点和父子连线,可直接浏览器打开 |
| `report.html` | 自包含检查页面,带部件表和模型记录 |
| `validation.json` | 字段、坐标、引用、父子环和遮挡环校验结果 |
| `response.raw.json` / `response.txt` | 原始服务端响应 / 提取的文本 |
| `prompt.txt` / `request.json` | 提示词 / 请求设置与输入哈希;图片内容单独保存在 source.png |
| `request-metadata.json` | requested/returned model、request ID、usage、耗时和请求次数 |
| `manifest.json` | 运行状态、配置、代码版本、源文件哈希和产物哈希 |
`status=completed` 仅表示这一步执行完成。`quality_status=needs_review` 表示仍需人工检查语义和框的位置。粗框不是像素 mask,输出也不是自动批准的骨骼。
v2 计划新增 `rig_role`、`bind_to` 和 `completion`(遮挡补全、父关节延展、子关节延展),`needs_completion` 必须等于三项逻辑或。新提示词让模型正负点留空;旧点仅用于诊断,程序从 ROI ∩ Alpha 前景重新生成候选,pivot 不参与前景吸附。空 ROI 标记 blocked,不生成替代点。
使用 `--parts-file semantic-parts.json --reference source.png --out-dir 新目录` 可离线迁移 v1 或检查 v2,无需密钥或网络。Python 固定使用 Conda 环境 `ai-spine`,`--python` 也必须指向该环境。依赖安装命令为 `conda run -n ai-spine python -m pip install -r requirements.txt`,完整说明见 README。背景预处理无法获得可用 Alpha 时在模型请求前失败。边界连通白底去除是一种保守启发式,贴到画布边缘的白色角色区域仍需人工检查。
校验失败保存原始响应、validation 和报告,退出码为非零,不继续分割。网络/API 失败保存失败 manifest。拒绝、截断和不完整 Responses 都不会被当作成功。
HTTP/SSE/网络失败还保存 `response.error.json`:状态码、请求 ID、耗时、尝试次数、响应体(最多 2 MB)或网络错误代码,密钥会脱敏。若服务端返回 overloaded,使用新目录稍后重跑;这不表示 schema 或分割模型出错。
## 独立测试图片编辑接口
先准备一个局部部件 PNG 和任务文本 `task.txt`,例如:
```text
The input canvas contains the screen-left forearm. Complete the hidden elbow
connection behind the sleeve. Keep the visible hand and forearm in their exact
positions. Preserve the original outline and shading. Do not add other parts.
```
调用 Qwen:
```powershell
node .\tools\model-check.mjs --stage completion --image .\local-part.png --prompt-file .\task.txt --out-dir .\output\qwen-edit-test --completion-model qwen-image-3.0
```
改 `--completion-model` 即可对比另一个兼容的图片编辑模型。此命令直接调用图片接口并可能计费,不调用结构理解。
结果保存 `candidate-1.png`(或服务端实际返回的 JPEG/WebP 扩展名)、输入图、任务提示词、原始响应和运行记录。PNG 输出会记录是否与输入画布同尺寸;尺寸相同不代表内容对齐。
默认图片适配器只发送一张图。若中转站确认支持多图,在配置中启用 `capabilities.multiple_images`,并使用重复 `--image`:第一张是局部画布,其余是原图/标注图参考。字段名通过 `image_field` 选择 `image` 或 `image[]`。
若确认支持编辑 mask,再启用 `capabilities.mask` 并使用 `--mask edit-mask.png`。当前适配器约定透明像素可编辑,要求 mask 与第一张图同尺寸、包含 alpha 通道。SAM 的普通黑白 mask 不能直接当作编辑 alpha mask。未启用能力时参数会明确报错,不静默忽略。
本轮没有恢复原始可见像素,也没有生成隐藏区域的透明掩码;因此候选始终标记 `raw_completion_probe` 和 `needs_review`,不能直接接入最终 atlas。
## 配置与切换规则
`configs/astra-qwen.json` 分离 `providers` 和 `stages`:
- provider:协议、base URL/key 的环境变量名、超时、重试次数、多图和 mask 声明。
- stage:provider 名称、模型、提示词文件、输出模式和模型特定参数。
- 提示词路径相对于配置 JSON 所在目录解析;命令行输入/输出路径相对于当前目录。
- 模型优先级:CLI > 阶段显式 `model` > `model_env` 环境变量 > `default_model`。
- shell 环境覆盖 `.env`。实验 JSON 不应存放密钥,仅引用密钥环境变量名。
- 不同服务可配置各自的 base URL/key 环境变量。
- 模型 ID 原样发送,不再把 `gpt-image-2.5` 映射成其他模型。
- `params` 允许模型特定参数,但不能覆盖 model、prompt、messages、input 等适配器保留字段。
- 新模式的超时/重试来自 provider 配置;旧模式的图片超时仍用 `VECTOR_ENGINE_IMAGE_REQUEST_TIMEOUT_MS`。
例如把理解阶段改为固定模型:
```json
{
"provider": "relay-vision",
"model": "YOUR_EXACT_MODEL_ID",
"prompt": "../prompts/understand-v1.txt",
"output_mode": "text-json",
"params": {}
}
```
## 重跑与对比
同一命令增加 `--resume`,仅当上次完整结束,且模型、协议、参数、提示词、Schema、源图、适配器代码和所有产物校验一致时复用。模型变化时要求新的输出目录,防止覆盖对照组。失败任务也保留原目录,使用新目录重跑。
理解、SAM、部件补全和补全探针各自记录独立缓存。SAM 额外校验输入计划、候选提示、本地源码和权重哈希;部件补全校验语义计划、所有输入 mask、画布参数、源码及离线候选哈希。对比补全模型时,固定相同局部画布、任务文本与掩码。
显式 429/5xx 最多按配置重试,超时或网络断开不自动重试,因为服务端可能已经执行任务。完整请求不保证模型内容可复现;seed 只在提供方确认支持时放入 params,usage 不存在时记录 null,不估造价格或 token 数。
## SAM 路径
默认根目录 `F:/Study/SAM3`:源码位于 `sam3/`,权重位于 `sam3.1checkpoint/sam3.1_multiplex.pt`。可通过 `--sam-dir`、`--sam-code-dir`、`--sam-checkpoint` 覆盖。独立分割无需中转站凭据,在 `ai-spine` Conda 临时子进程加载 GPU 模型,结束即退出。命令、权重适配及当前质量限制见[第二阶段文档](2-segmentation-stage.md)。
## 测试
```powershell
conda run -n ai-spine npm test
```
测试使用本地 mock HTTP 服务或注入响应,不调用真实付费模型。覆盖模型优先级、协议请求/响应、multipart、能力限制、数值/引用/环校验、错误响应、重试、缓存和 CLI 全链路。
2026-09-17 的集成检查:模型列表请求成功;Astra 要求 Responses + stream=true,切换后服务端返回 overloaded,尚未得到成功的真实角色标注。Qwen 适配器通过 mock 请求/响应测试,本轮未执行真实图片编辑生成。此状态不等于视觉质量已验证。