Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/skills/splitting-image-grids-by-content/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ scan -> inspect source + candidate previews -> inventory intended assets
7. Accept a source crop or composite only when the confirmed asset count and names match, each subject is complete and uncontaminated, identity and view are correct, no unintended text, caption, watermark, border, duplicate, or foreign foreground remains, and the manifest has no unresolved triage or repair item. The contact sheet is a review artifact; `delivery.images` are the primary production assets. `delivery.transparent_images` are optional production variants only after their independent quality gate passes; `alpha_images`, `transparent_candidates`, and masks are not approved deliverables.
8. Submit a visual verdict for every primary route, not only generated reconstruction. Use `pass` only after all primary success conditions pass. Review transparent candidates separately with `--transparent-verdict pass`, `retryable`, or `reject`; a missing or rejected optional transparent variant does not block a valid primary delivery. On `retryable`, name the failed condition, revise the candidate choice or plan, re-apply, and review again. Retry only when a concrete change addresses the failure; if the same failure repeats twice, stop with explicit failure evidence instead of looping indefinitely.
9. If status is `needs_user_decision`, finish semantic triage before proceeding. If status is `awaiting_user_approval`, run `ultrasplit repair prepare`; show deliverable, repair, and ignored counts, every clean repair preview plus original context, reason, target count, call count, and two-attempt limit, then wait for explicit approval.
10. After approval, record it with `ultrasplit repair approve`. Generate one regular grid per conflict group, ingest it, and return to the same delivery review gate. Never retry a repair group more than twice. Deliver the final status, counts, absolute output directory, review contact sheet, manifest, and title-free production asset paths.
10. After approval, record it with `ultrasplit repair approve`. Generate one regular grid per conflict group, ingest it, and return to the same delivery review gate. Never retry a repair group more than twice. After the primary visual verdict passes, include `delivery.layered_psd` in the final handoff; it contains one named layer per approved asset. Deliver the final status, counts, absolute output directory, review contact sheet, manifest, layered PSD, and title-free production asset paths.

Generated completion is inferred content. Always identify it as reconstruction, never extraction or factual recovery.

Expand Down
3 changes: 3 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ The manifest separates four artifact roles:
- `delivery.images` contains only title-free production assets;
- `delivery.transparent_candidates` contains unapproved alpha variants and the legacy `alpha_images` field aliases those paths;
- `delivery.transparent_images` contains only alpha variants that passed automatic checks and an explicit independent visual verdict;
- `delivery.layered_psd` points to the first Photoshop-compatible layered document generated only after the primary visual verdict passes. Assets are packed at native pixel dimensions into one PSD page when they fit within 30,000×30,000 pixels, or into numbered PSD pages when they do not; oversized individual assets are split into named pixel tiles with source coordinates recorded in `delivery.layered_psd_info`. No resampling is performed, and independently approved transparent variants are used when available;
- `review/contact-sheet.png` is the named, automatically arranged delivery preview, not an alternate production asset;
- `review/triage-sheet.png` labels every retained candidate as `deliver`, `repair`, or `triage`, and shows structured exclusions as `ignore`;
- `delivery.pending_repair_images` and `delivery.ignored_images` remain review evidence and never masquerade as finished assets.
Expand Down Expand Up @@ -70,6 +71,8 @@ Preparation never invokes a model. The manifest moves to `awaiting_user_approval

## Evaluation and bounded loop

For the evaluator entry points, review-state branches, and layered-PSD export gate, see the [Evaluator Pipeline](docs/evaluator-pipeline.md) (English) or [中文流程图](docs/evaluator-pipeline.zh-CN.md).

Deterministic grid checks cover dimensions, expected occupied cells, uniform background, edge contact, minimum margin, and obvious duplicate cells. A multimodal host then compares every reconstructed subject with the visible source anchors: identity, pose, silhouette, color, material, ornament, and absence of redesign.

Visual verdicts are:
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Instead of asking a vision model to guess crop coordinates, UltraSplitter lets t
- **Source-first output** — intact assets remain original-pixel crops. Separable overlaps use foreground masks and clean re-layout rather than regeneration.
- **Approval-gated AIGC repair** — recognizable clipped or occluded subjects are grouped into one efficient repair grid. The user sees the scope before any generation call.
- **Bounded quality loop** — generated grids are checked for count, duplicates, background, resolution, edge contact, safe margin, and visible identity; each group stops after at most two attempts.
- **Production-ready delivery** — named primary images, independently reviewed optional transparent variants, compact review sheets, provenance, status, evaluation evidence, and absolute access paths are written to `output/` and `manifest.json`.
- **Production-ready delivery** — named primary images, independently reviewed optional transparent variants, a layered PSD after visual approval, compact review sheets, provenance, status, evaluation evidence, and absolute access paths are written to `output/` and `manifest.json`.
- **Agent-native operation** — install the Skill for Codex, Claude Code, or another compatible coding agent, or use the Python CLI directly.

## Showcases
Expand Down Expand Up @@ -102,6 +102,8 @@ ultrasplit evaluate output/character-views/manifest.json --visual-verdict pass
ultrasplit evaluate output/character-views/manifest.json --transparent-verdict pass
```

After the primary visual review passes, UltraSplitter exports editable PSD layers at native pixel dimensions. It uses one `layers.psd` when assets fit within a 30,000×30,000 px canvas, and numbered PSD pages when they do not. An individual asset larger than the page limit is split into named pixel tiles with source coordinates recorded in the manifest. No resampling is performed. Independently approved transparent variants are used when available; otherwise the PSD uses the primary assets. Individual PNGs remain available as separate files.

`ultrasplit run` is a deterministic shortcut for simple inputs. It does not replace the Skill's model-guided inventory and scope-alignment workflow, and its output remains `needs_review` until an explicit visual pass.

<details>
Expand Down Expand Up @@ -129,6 +131,8 @@ ultrasplit evaluate output/task/manifest.json --visual-verdict pass

Every run writes a schema-v3 manifest with exact source coordinates, route evidence, provenance, approval state, bounded repair attempts, evaluation status, and absolute delivery paths. See [ARCHITECTURE.md](ARCHITECTURE.md).

For the evaluation and layered-PSD export flow, see the [Evaluator Pipeline](docs/evaluator-pipeline.md).

## Current boundary

- Supports framed panels and spatially separated objects on transparent or approximately uniform backgrounds.
Expand Down
6 changes: 5 additions & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ UltraSplitter 不让视觉模型猜最终裁剪坐标。多模态宿主负责判
- **优先保留原图像素**——完整素材直接裁切;检测框重叠但轮廓可分时,通过前景掩码清理和重排解决,不重新生成。
- **需要 AIGC 补全时先审批**——可识别但被截断、遮挡的主体会合并成一次高效宫格任务;调用生成模型前,先向用户展示范围与成本。
- **有界质量循环**——检查数量、重复、背景、分辨率、触边、留白和可见身份特征;每个冲突组最多尝试两次,不无限生成。
- **直接交付生产资产**——在 `output/` 和 `manifest.json` 中提供命名主资产、独立审阅后的可选透明变体、紧凑审阅图、来源、状态、评估证据和绝对访问路径。
- **直接交付生产资产**——在 `output/` 和 `manifest.json` 中提供命名主资产、独立审阅后的可选透明变体、审核通过后生成的分层 PSD、紧凑审阅图、来源、状态、评估证据和绝对访问路径。
- **AI 原生调用**——可为 Codex、Claude Code 等兼容 Agent 安装 Skill,也可直接使用 Python CLI。

## Showcases
Expand Down Expand Up @@ -102,6 +102,8 @@ ultrasplit evaluate output/character-views/manifest.json --visual-verdict pass
ultrasplit evaluate output/character-views/manifest.json --transparent-verdict pass
```

主资产视觉审核通过后会生成分层 PSD。素材能装入 30,000×30,000 像素画布时,交付一个 `layers.psd`;装不下时自动分卷为 `layers.psd`、`layers-02.psd` 等文件,每份都保留独立图层。单个素材边长超过 30,000 像素时会按原像素切块,并在 manifest 中记录来源坐标。导出不缩放、不重采样;分卷避免因画布尺寸超过阈值直接失败。透明变体通过独立审核后,PSD 会使用透明版本;否则保留主资产像素。拆出的 PNG 仍会单独交付,分卷路径与图层来源记录在 manifest 中。

`ultrasplit run` 只是面向简单输入的确定性快捷命令,不能替代 Skill 中由模型完成的资产盘点和范围对齐;在显式视觉通过前,输出保持 `needs_review`。

<details>
Expand Down Expand Up @@ -129,6 +131,8 @@ ultrasplit evaluate output/task/manifest.json --visual-verdict pass

每次运行都会写入 schema v3 的 `manifest.json`,记录准确的源图坐标、路由依据、来源追踪、批准状态、有界修复次数、评估结果和绝对访问路径。完整设计见 [ARCHITECTURE.md](ARCHITECTURE.md)。

评估及分层 PSD 导出流程见[Evaluator 评估流程](docs/evaluator-pipeline.zh-CN.md)。

## 当前能力边界

- 支持带边框的分栏图,以及透明或近似纯色背景中空间分离的主体。
Expand Down
45 changes: 45 additions & 0 deletions docs/evaluator-pipeline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Evaluator Pipeline

This diagram covers the two evaluator paths: deterministic checks for generated repair grids, and manifest review with the primary-review gate for layered PSD export.

```mermaid
flowchart TD
subgraph A["Repair-grid checks: evaluate_grid"]
A1["repair ingest receives generated grid"] --> A2["Check resolution, background, occupied-cell count, margins, edge contact, and duplicates"]
A2 --> A3{"Checks pass?"}
A3 -- "No" --> A4["Record failed attempt and issues; wait for retry or manual handling"]
A3 -- "Yes" --> A5["Split repaired assets and update manifest and delivery"]
A5 --> B1
end

subgraph B["Manifest review and PSD: evaluate_manifest"]
B1["Load manifest and validate schema v3"] --> B2["Check semantic triage, conflict groups, repair attempts, and visual verdict"]
B2 --> B3{"Any untriaged item?"}
B3 -- "Yes" --> B4["needs_user_decision"]
B3 -- "No" --> B31{"Pending conflict group without approval?"}
B31 -- "Yes" --> B5["awaiting_user_approval"]
B31 -- "No" --> B32{"Repair attempts exhausted?"}
B32 -- "Yes" --> B6["retry_exhausted"]
B32 -- "No" --> B33{"Visual verdict is identity_uncertain?"}
B33 -- "Yes" --> B4
B33 -- "No" --> B34{"Retryable, failed repair, or pending work?"}
B34 -- "Yes" --> B7["needs_review"]
B34 -- "No" --> B35{"Visual verdict is pass?"}
B35 -- "Yes" --> B8["success"]
B35 -- "No" --> B7
B4 --> B9["Apply optional transparency verdict"]
B5 --> B9
B6 --> B9
B7 --> B9
B8 --> B9
B9 --> B10{"Final status is success?"}
B10 -- "No" --> B11["Do not export PSD; write review state"]
B10 -- "Yes" --> B12["Export one or more PSD pages: layers.psd, layers-02.psd, …"]
B12 --> B13["Record first path, all PSD paths, and export details in manifest"]
end

C["CLI: evaluate manifest.json"] --> B1
A4 --> A1
```

`ultrasplit run` creates and routes the manifest; it does not itself pass the evaluation gate. The CLI `evaluate` command, or repair ingestion after a successful grid check, calls `evaluate_manifest` and can reach PSD export.
45 changes: 45 additions & 0 deletions docs/evaluator-pipeline.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Evaluator 评估流程

本图包含两条路径:对生成式修复宫格进行确定性检查,以及审核 manifest 并在主资产审核通过后导出分层 PSD。

```mermaid
flowchart TD
subgraph A["修复宫格检查:evaluate_grid"]
A1["repair ingest 收到生成的宫格图"] --> A2["检查分辨率、背景、有效格子数、留白、触边和重复图形"]
A2 --> A3{"检查通过?"}
A3 -- "否" --> A4["记录失败尝试和问题;等待重试或人工处理"]
A3 -- "是" --> A5["拆出修复资产并更新 manifest 和交付项"]
A5 --> B1
end

subgraph B["Manifest 审核与 PSD:evaluate_manifest"]
B1["读取 manifest 并校验 schema v3"] --> B2["检查语义分诊、冲突组、修复次数和视觉审核结论"]
B2 --> B3{"是否存在未分诊项?"}
B3 -- "是" --> B4["needs_user_decision"]
B3 -- "否" --> B31{"是否有未批准的待处理冲突组?"}
B31 -- "是" --> B5["awaiting_user_approval"]
B31 -- "否" --> B32{"修复次数是否耗尽?"}
B32 -- "是" --> B6["retry_exhausted"]
B32 -- "否" --> B33{"视觉结论是否为 identity_uncertain?"}
B33 -- "是" --> B4
B33 -- "否" --> B34{"是否有可重试失败或待处理修复?"}
B34 -- "是" --> B7["needs_review"]
B34 -- "否" --> B35{"视觉结论是否为 pass?"}
B35 -- "是" --> B8["success"]
B35 -- "否" --> B7
B4 --> B9["应用可选的透明图审核结论"]
B5 --> B9
B6 --> B9
B7 --> B9
B8 --> B9
B9 --> B10{"最终状态为 success?"}
B10 -- "否" --> B11["不导出 PSD;写回审核状态"]
B10 -- "是" --> B12["导出一份或多份 PSD:layers.psd、layers-02.psd、…"]
B12 --> B13["在 manifest 中记录首个路径、全部 PSD 路径和导出详情"]
end

C["CLI:evaluate manifest.json"] --> B1
A4 --> A1
```

`ultrasplit run` 负责生成并路由 manifest,本身不会通过审核门控。CLI 的 `evaluate` 命令,或修复宫格检查通过后的导入流程,会调用 `evaluate_manifest` 并可能进入 PSD 导出。
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ classifiers = [
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
dependencies = ["Pillow>=10.0,<13"]
dependencies = ["Pillow>=10.0,<13", "psd-tools>=1.11,<2"]

[project.urls]
Homepage = "https://github.com/PlevanTem/UltraSplitter"
Expand Down
6 changes: 5 additions & 1 deletion src/ultrasplitter/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,11 @@ def apply_plan(
manifest_path = output_dir / "manifest.json"

ordinal_width = max(2, len(str(len(items_plan))))
planned_paths = [manifest_path, review_dir / "contact-sheet.png"]
planned_paths = [
manifest_path,
review_dir / "contact-sheet.png",
output_dir / "delivery" / "layers.psd",
]
output_names: list[str] = []
for index, label in enumerate(labels, 1):
output_name = f"{index:0{ordinal_width}d}-{label}.png"
Expand Down
19 changes: 19 additions & 0 deletions src/ultrasplitter/evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from .core import estimate_background, foreground_mask
from .contracts import MAX_REPAIR_ATTEMPTS, load_json, require_v3, write_json
from .layered_psd import export_layered_psd
from .transparency import apply_transparent_verdict


Expand Down Expand Up @@ -167,5 +168,23 @@ def evaluate_manifest(
manifest["status"] = "success"
manifest["review_required"] = manifest["status"] != "success"
apply_transparent_verdict(manifest, transparent_verdict)
delivery = manifest.setdefault("delivery", {})
delivery["layered_psd"] = None
delivery["layered_psd_files"] = []
delivery["layered_psd_info"] = None
manifest.setdefault("evaluation", {})["layered_psd"] = "pending_primary_review"
if manifest["status"] == "success":
try:
psd_info = export_layered_psd(manifest, manifest_path.parent / "delivery" / "layers.psd")
except (OSError, ValueError) as exc:
manifest["status"] = "failed"
manifest["review_required"] = True
manifest.setdefault("warnings", []).append(f"layered_psd_export_failed:{exc}")
manifest.setdefault("evaluation", {})["layered_psd"] = "failed"
else:
delivery["layered_psd"] = psd_info["path"]
delivery["layered_psd_files"] = psd_info["paths"]
delivery["layered_psd_info"] = psd_info
manifest.setdefault("evaluation", {})["layered_psd"] = "pass"
write_json(manifest_path, manifest)
return manifest
Loading
Loading