引入实例ID驱动传播链匹配

- 前端保存标注写入并保留 instance_id,AI 自动推理 seed 携带 source_instance_id,避免同类多 mask 只按语义混在一起。

- 后端传播任务优先用 source_instance_id/instance_id 做幂等、替换和写入前清理,并保留 source_annotation_id/source_mask_id/legacy 兼容路径。

- 前端传播链匹配、删除/分类同步和布尔合并/去重加入实例 token,保持旧 lineage 和空间最近 legacy fallback。

- 补充前后端回归测试,覆盖同类别多实例传播、重传、布尔同步、断开多区域和保存/回显 metadata。

- 更新 AGENTS 与 doc 事实文档,明确 maskid 仍只用于语义分类、GT_label 和导出,不参与实例追踪。
This commit is contained in:
2026-05-04 05:54:23 +08:00
parent 1ff757e2fa
commit 5d73eacefe
15 changed files with 325 additions and 19 deletions

View File

@@ -797,6 +797,13 @@ def propagate(
label = seed.get("label") or "Propagated Mask"
color = seed.get("color") or "#06b6d4"
model_id = sam_registry.normalize_model_id(payload.model)
source_annotation_id = seed.get("source_annotation_id")
source_mask_id = seed.get("source_mask_id")
source_instance_id = (
seed.get("source_instance_id")
or (f"annotation:{source_annotation_id}" if source_annotation_id is not None else None)
or (f"mask:{source_mask_id}" if source_mask_id else None)
)
seed_smoothing = seed.get("smoothing")
smoothing = _normalize_smoothing_options(
seed_smoothing.get("strength"),
@@ -843,6 +850,9 @@ def propagate(
"source": f"{model_id}_propagation",
"propagated_from_frame_id": source_frame.id,
"propagated_from_frame_index": source_frame.frame_index,
**({"instance_id": source_instance_id, "source_instance_id": source_instance_id} if source_instance_id else {}),
**({"source_annotation_id": source_annotation_id} if source_annotation_id is not None else {}),
**({"source_mask_id": source_mask_id} if source_mask_id else {}),
"score": max(score_values) if score_values else None,
**({"scores": score_values} if len(score_values) > 1 else {}),
**({"geometry_smoothing": smoothing} if smoothing else {}),