This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-09-09
|
||||
@@ -0,0 +1,83 @@
|
||||
## Context
|
||||
|
||||
以当前工作区调用链为依据:
|
||||
|
||||
| 位置 | 发现 | 处理方向 |
|
||||
| --- | --- | --- |
|
||||
| `common/ai.py` | BEN2 专属扩展名与后端重复,Upscale 只检查路径存在 | 统一公共预检 |
|
||||
| `server/media/input.py` | 扩展名提示混排;目录过滤后仅提示没有帧 | 按错误原因和媒体类别提示 |
|
||||
| `server/models/ben2.py` | 单帧校验使用第三套提示 | 复用图片格式校验 |
|
||||
| `common/image.py` | 路径文案限定 Image Empty;序列直接复制;packed 导出失败可能留下目录 | 使用 source 文案、复制前校验、准备失败释放资源 |
|
||||
| Remove BG、Depth/Relief Plane | 内部 Operator 调用位于异常处理之外 | 捕获同步调用错误并取消 |
|
||||
| `operators/ai_setup.py`、`invoke_ai_setup_if_needed()` | 下载、安装与设置入口嵌套调用 | 在公共准备入口和设置 Operator 内处理失败 |
|
||||
| Panorama | 已捕获嵌套调用错误并清理 | 回归现有行为 |
|
||||
|
||||
BlendJob 的 `request()` 错误会被转换为 ERROR report 和 CANCELLED;Blender 的 `bpy.ops` 调用仍可能将该 report 抛为 RuntimeError。异步 Job 失败已有集中处理。前后端可以共享 `server` 内纯 Python 模块,已有 resolution 模块采用这一依赖方向;后端保持可独立加载。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
统一 AI 输入校验、用户可读的错误原因、失败取消状态和临时输入生命周期。支持格式保持 JPG/JPEG/PNG/WEBP 与现有九种视频扩展名;各 Operator 继续表达自己的静态图、尺寸与比例限制。自动转码、扩展格式支持和 BlendJob 框架重构作为独立需求处理。
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. 公共媒体模块维护格式规则与提示
|
||||
|
||||
在 `server/media/input.py` 提供轻量路径/格式校验,按图片、视频或帧目录识别输入,图片模型使用相同规则的图片子集。模块加载和预检仅依赖标准库。
|
||||
|
||||
`common/ai.py` 的 `require_input_path()` 负责 Blender 路径解析并调用该规则;删除 BEN2 专属校验及扩展名常量。`prepare_input()` 在后端再次执行校验,应对独立 Job 请求和提交后源文件变化。前端和后端使用同一消息生成位置,比只在后端检查更早反馈,也避免复制列表。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Source[Blender 源图片] --> Prepare[解析路径与准备输入]
|
||||
Prepare --> Validate[公共媒体校验]
|
||||
Validate --> Submit[提交 Job]
|
||||
Submit --> Recheck[后端公共媒体校验]
|
||||
Recheck --> Decode[读取图片或视频帧]
|
||||
Decode --> Model[模型处理]
|
||||
Validate --> Error[普通错误提示与取消]
|
||||
Recheck --> Error
|
||||
Decode --> Error
|
||||
```
|
||||
|
||||
### 2. 提示由原因决定,格式按类别列出
|
||||
|
||||
保留当前英文 UI 语言,示例模板:
|
||||
|
||||
- `Source image file does not exist: {path}` / `Source video file does not exist: {path}`。
|
||||
- `Unsupported input format: {suffix}. Supported images: {images}. Supported videos: {videos}.` 扩展名排序且小写;无扩展名使用 `(no extension)`。
|
||||
- `No supported image frames found in: {path}. Supported images: {images}.`。
|
||||
- `Unable to read image: {path}` / `Unable to read video: {path}`,底层原因保留异常链供诊断。
|
||||
|
||||
只将路径检查、文件读取与解码边界的预期异常转换为输入提示,模型推理或资源错误保留实际原因。通用输入阶段保持图片与视频类别一致;BEN2 单帧模型内部使用图片子集提示。
|
||||
|
||||
### 3. 明确目录与 Blender 序列的差别
|
||||
|
||||
Blender SEQUENCE 在创建临时目录前验证源扩展名属于支持的图片格式,不支持时直接报格式错误。已识别的同名序列按原排序和帧区间处理。
|
||||
|
||||
通用目录仍仅选择支持格式的图片文件并忽略其他文件;预检与后端使用同一收集规则。全无有效图片时报告目录及支持图片格式。这一提案修复 Blender 序列被误报为空目录的问题,混合目录按筛选契约验收。
|
||||
|
||||
格式校验针对实际提交文件。packed 图片和像素裁剪输出使用现有 PNG 导出路径,普通文件继续使用原始文件;测试应明确两条路径的预期,避免把源名称当作实际编码。`IMAGE_NAME_SUFFIXES` 是命名识别列表,继续按命名职责维护。
|
||||
|
||||
### 4. 在拥有调用与资源的边界处理失败
|
||||
|
||||
Remove BG、Depth/Relief Plane、AI Environment 的嵌套 `bpy.ops` 调用捕获预期 RuntimeError;涉及输入准备的边界同时处理 OSError/ValueError。通过已有 report 出口返回 CANCELLED,规范 Blender 添加的首个 `Error: ` 前缀与尾部换行,保留实际原因。公共 AI setup 入口复用同一报错约定;异步 Job 仍由 BlendJob 管理。
|
||||
|
||||
临时输入在准备完成前由准备函数拥有;Job 成功接管后由 Job cleanup 拥有。准备失败、同步调用抛错、返回 CANCELLED 和异步失败分别验证释放责任。packed 导出失败应清理整个临时目录。清理只能触及本次操作创建的输入,不影响用户原文件和源图片引用。
|
||||
|
||||
优先在现有公共函数与直接调用处落实职责;复用消息格式化即可,保持各业务 Operator 的调用和资源归属可见。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- 前后端文件状态可能变化 → 后端复核并提供同一原因分类。
|
||||
- 测试 mock 不会自动模拟 Blender report 抛错 → 单元测试注入 RuntimeError,补充真实 Blender 入口验证。
|
||||
- 调用层次多可能重复 report → 以最终用户提示无重复前缀、无 Python traceback 为验收点,检查 Blender UI 实际输出。
|
||||
- 解码错误与推理错误容易混淆 → 只在读取边界包装解码异常。
|
||||
- 其他未归档变更修改相关入口 → 以实施时工作区为基线,保留 Undo、源图共享引用及 Panorama 行为。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
依次落地公共校验、消费者接入、调用边界与清理,再运行相关及全量测试。删除旧 BEN2 校验入口并检查引用。变更不涉及持久数据迁移;必要时可整体回退本变更代码与测试。
|
||||
|
||||
## Open Questions
|
||||
|
||||
无实施前置问题。真实 Blender 下 report 的重复展示情况列为实施验收项。
|
||||
@@ -0,0 +1,29 @@
|
||||
## Why
|
||||
|
||||
Remove BG 与 Upscale 对同一种输入给出不同的格式提示,Remove BG 的普通校验错误还会经嵌套 Operator 调用变成 Python traceback。检查发现格式规则重复、序列过滤、路径提示和临时输入清理也存在同一调用链上的不一致,需要建立统一的输入与失败处理契约。
|
||||
|
||||
## What Changes
|
||||
|
||||
- AI 文件输入使用同一套格式规则与错误文案,前端提前校验,后端独立复核;错误说明实际扩展名及支持的图片、视频格式。
|
||||
- 区分路径缺失、格式不支持、目录无有效帧和文件无法解码,路径提示统一使用 source image/video,适用于 Image Empty 和材质 Image Texture。
|
||||
- Blender 图片序列在复制前验证格式,避免不支持的序列被当成空目录;通用帧目录明确过滤规则。
|
||||
- Remove BG、Depth/Relief Plane 与 AI Environment 的嵌套调用按普通错误取消操作,并统一资源释放;审查 Panorama 既有处理作为回归范围。
|
||||
- 保留静态图、尺寸、比例等功能专属限制,统一其异常出口;格式能力以当前实际提交文件为准。
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `ai-input-validation`: AI 文件、帧目录与 Blender 图片序列的公共校验、错误分类及文案。
|
||||
- `ai-operator-failure-handling`: AI Operator 的失败展示、取消状态与临时输入所有权。
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
无。当前 `openspec/specs/` 为空。本提案与现有 `add-texture-node-image-actions`、`add-panorama-conversion` 变更共同验收相关入口。
|
||||
|
||||
## Impact
|
||||
|
||||
- `src/anyimage/server/media/input.py`、`server/media/__init__.py`、`server/models/ben2.py`:公共格式契约、目录处理与模型输入校验。
|
||||
- `src/anyimage/common/ai.py`、`common/image.py`:前置校验、源路径与序列准备、临时资源释放。
|
||||
- `operators/remove_background.py`、`upscale.py`、`convert_to_plane/operators.py`、`ai_setup.py` 及其他公共入口消费者:错误传播与回归。
|
||||
- 更新相关行为测试,运行全量 pytest,并用 Blender 验证嵌套调用的实际报错。依赖与节点资产沿用当前版本。
|
||||
@@ -0,0 +1,61 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Shared input format validation
|
||||
|
||||
AI 输入 SHALL 使用公共格式规则,在 Blender 提交前与后端处理前校验实际输入路径。支持图片为 JPG/JPEG/PNG/WEBP,视频沿用当前 MP4/MOV/AVI/MKV/WEBM/M4V/MTS/MPG/MPEG,扩展名匹配忽略大小写。
|
||||
|
||||
#### Scenario: Unsupported file in image edits
|
||||
- **WHEN** Remove BG 与 Upscale 使用同一个存在的 `.tiff` 普通文件,且环境和模型已就绪
|
||||
- **THEN** 两者在提交 Job 前取消,展示相同格式提示,包含 `.tiff` 和分类排序的支持格式
|
||||
|
||||
#### Scenario: Direct backend input
|
||||
- **WHEN** 后端直接收到不支持格式的文件或无扩展名文件
|
||||
- **THEN** 使用与前端相同的格式提示规则,无扩展名显示 `(no extension)`
|
||||
|
||||
#### Scenario: Supported uppercase extension
|
||||
- **WHEN** 实际输入为存在的 `.PNG` 或 `.MP4` 文件
|
||||
- **THEN** 通过对应图片或视频格式校验
|
||||
|
||||
#### Scenario: Model image validation
|
||||
- **WHEN** BEN2 单帧入口收到不支持的图片扩展名
|
||||
- **THEN** 使用公共格式提示的图片子集,并与公共图片支持集合一致
|
||||
|
||||
### Requirement: Distinct input failure reasons
|
||||
|
||||
系统 SHALL 区分缺失路径、不支持格式、目录无有效帧和解码失败;提示 SHALL 适用于 Image Empty 和 Image Texture,解码异常转换 SHALL 限定于读取边界。
|
||||
|
||||
#### Scenario: Missing source file
|
||||
- **WHEN** Image Empty 或材质 Image Texture 的源图片或视频文件不存在
|
||||
- **THEN** 提示缺失的 source image/video file 及路径,不将原因报告为格式不支持
|
||||
|
||||
#### Scenario: Invalid encoded data
|
||||
- **WHEN** 支持扩展名的文件内容无法作为对应图片或视频解码
|
||||
- **THEN** 报告无法读取的媒体类型及路径,并保留底层异常供诊断
|
||||
|
||||
### Requirement: Explicit frame selection
|
||||
|
||||
系统 SHALL 在复制 Blender 序列前校验图片格式;通用目录 SHALL 仅收集支持的图片,保持现有排序及帧范围规则。
|
||||
|
||||
#### Scenario: Unsupported Blender sequence
|
||||
- **WHEN** Blender 源序列使用 `.exr` 扩展名
|
||||
- **THEN** 复制前提示不支持的图片格式,不创建临时帧目录
|
||||
|
||||
#### Scenario: Mixed directory
|
||||
- **WHEN** 通用输入目录包含 JPG、PNG、TXT 和 EXR 文件
|
||||
- **THEN** 仅 JPG 与 PNG 参与处理,前后端按相同规则选择并保持原帧范围语义
|
||||
|
||||
#### Scenario: Empty supported frame set
|
||||
- **WHEN** 通用目录为空或只有不支持的文件
|
||||
- **THEN** 提示无支持的图片帧、目录路径及支持的图片格式
|
||||
|
||||
### Requirement: Validate prepared media
|
||||
|
||||
系统 SHALL 校验实际提交的文件,保持各功能自身的媒体类型、尺寸和比例约束。
|
||||
|
||||
#### Scenario: Packed image exported as PNG
|
||||
- **WHEN** 一个名称带 `.exr` 的 packed Image 经现有流程成功导出 PNG
|
||||
- **THEN** 按导出的 PNG 校验,不按源名称拒绝
|
||||
|
||||
#### Scenario: Feature restriction
|
||||
- **WHEN** 输入通过公共格式校验但不满足 Depth Plane 的静态图限制或 Upscale 的尺寸限制
|
||||
- **THEN** 仍按对应业务原因取消,不报告为格式不支持
|
||||
@@ -0,0 +1,33 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Expected operator failures are reported normally
|
||||
|
||||
AI 操作 SHALL 将输入准备与嵌套 Operator 调用的预期失败转换为普通错误提示和 CANCELLED,包括 Remove BG、Depth/Relief Plane、AI Environment 准备及现有 Panorama 入口。提示 SHALL 保留原因并避免重复的 Blender 错误前缀。
|
||||
|
||||
#### Scenario: Nested input validation failure
|
||||
- **WHEN** 内部 Job Operator 报告无效输入且 bpy.ops 抛出 RuntimeError
|
||||
- **THEN** 外部入口返回 CANCELLED,显示原因,不向用户展示未捕获的 Python traceback
|
||||
|
||||
#### Scenario: Environment setup failure
|
||||
- **WHEN** AI Environment 设置入口调用安装或下载 Operator 同步失败
|
||||
- **THEN** 设置入口及调用它的 AI 操作按普通错误取消
|
||||
|
||||
#### Scenario: Successful job startup
|
||||
- **WHEN** 内部 Job Operator 返回 RUNNING_MODAL
|
||||
- **THEN** 外部入口保持现有成功返回与异步处理语义,源图片及 Undo 行为保持有效
|
||||
|
||||
### Requirement: Temporary inputs have explicit ownership
|
||||
|
||||
系统 SHALL 释放本次操作创建的临时输入,在准备失败、启动失败、取消及异步结束时均有负责清理的边界;用户原文件 SHALL 保持不变。
|
||||
|
||||
#### Scenario: Preparation failure
|
||||
- **WHEN** packed 图片导出或序列复制失败
|
||||
- **THEN** 准备函数删除本次临时文件和目录,并保留源图片与源文件
|
||||
|
||||
#### Scenario: Synchronous nested failure
|
||||
- **WHEN** 临时输入准备成功后内部 Operator 抛错或返回 CANCELLED
|
||||
- **THEN** 临时输入被清理,外部操作取消,源图片引用保持不变
|
||||
|
||||
#### Scenario: Asynchronous completion
|
||||
- **WHEN** Job 接管临时输入并在之后成功、失败或取消
|
||||
- **THEN** 输入在 Job 结束时清理,运行期间保持可用,用户原文件不被删除
|
||||
@@ -0,0 +1,30 @@
|
||||
## 1. 公共媒体校验
|
||||
|
||||
- [x] 1.1 在 server/media/input.py 统一路径、图片/视频扩展名与格式消息,保持标准库预检及后端独立加载;补充大小写、无扩展名和缺失路径测试。
|
||||
- [x] 1.2 让 prepare_input 与 BEN2 单帧校验复用公共规则;验证直接后端请求与前端提示一致,图片子集限制有效。
|
||||
- [x] 1.3 在实际图片/视频读取边界统一解码失败提示并保留异常原因;覆盖损坏内容,确认推理异常保留自身语义。
|
||||
|
||||
## 2. Blender 输入准备
|
||||
|
||||
- [x] 2.1 将 require_input_path 接入公共预检,移除 require_background_input_path 和 BEN2 重复常量;覆盖 Remove BG/Upscale 同一无效输入的消息及未提交 Job 行为。
|
||||
- [x] 2.2 统一 source image/video 路径提示,覆盖 Image Empty 和材质 Image Texture;回归其他公共校验消费者。
|
||||
- [x] 2.3 在 Blender 序列复制前校验图片格式;验证不支持序列、混合目录、无有效帧目录、帧排序与范围。
|
||||
- [x] 2.4 修复输入准备失败的临时目录释放,验证 packed 导出与序列复制失败;覆盖普通原文件和导出 PNG 的不同实际输入路径。
|
||||
|
||||
## 3. Operator 失败边界
|
||||
|
||||
- [x] 3.1 修复 Remove BG、Depth/Relief Plane 的嵌套调用异常出口,规范错误前缀并处理同步失败/CANCELLED 的临时输入清理。
|
||||
- [x] 3.2 补齐公共 AI setup 入口及 AI Environment 安装/下载嵌套调用的预期失败处理;回归 Panorama 已有错误边界。
|
||||
- [x] 3.3 补充准备失败、同步取消、异步成功/失败/取消的生命周期测试,确认原文件、源图片引用和 Undo 行为保持有效。
|
||||
|
||||
## 4. 验证
|
||||
|
||||
- [x] 4.1 运行相关测试,再运行 uv run pytest 并确认正常退出;检查旧校验名称、重复格式列表与最终差异。
|
||||
- [x] 4.2 在真实 Blender UI 从 Remove BG、Depth/Relief Plane 及 AI setup 入口触发同步失败,确认普通提示无重复前缀、无未捕获 traceback,并检查临时输入已释放。
|
||||
- [x] 4.3 验证有效 PNG、视频、序列与材质贴图入口,记录测试结果及实际验证限制。
|
||||
|
||||
## 验证记录
|
||||
|
||||
- `uv run pytest -q`:1025 passed、2 xfailed、52 subtests passed,退出码 0。随后新增的 4 项原生 Operator 测试通过;最终相关新增测试合计 24 项通过。
|
||||
- Blender 4.5.10 LTS 独立场景:UI 主循环依次调用 Remove BG、Upscale、Depth、Relief 和 AI setup;前四者格式错误完全一致,所有入口仅一层 Error 前缀且没有未捕获 traceback。原生回归另行验证同步失败后的临时输入清理。
|
||||
- 有效图片、视频帧、序列、材质贴图、异步完成/取消/失败和 Undo 由全量回归覆盖;本次验证使用模拟推理与安装失败,不下载模型或执行真实模型推理。
|
||||
Reference in New Issue
Block a user