Add reusable local HTTP job service for Blender add-ons
- Implement JobClient for handling HTTP requests to the JobServer. - Create ModalJobOperatorBase for managing Blender job lifecycle. - Introduce JobContext and JobServer for job management and state handling. - Add ServiceConnection and ServiceController for managing service processes. - Implement job submission, cancellation, and resource management endpoints in the server. - Ensure proper error handling and job state updates throughout the service.
This commit is contained in:
179
docs/blendjob.md
Normal file
179
docs/blendjob.md
Normal file
@@ -0,0 +1,179 @@
|
||||
# BlendJob 开发者指南
|
||||
|
||||
## 命名与边界
|
||||
|
||||
通用 module 命名为 `blendjob`。这个名字表达的是 Blender 插件与独立 Job 进程之间的桥接,不绑定 AI、模型框架或 SnapForm。
|
||||
|
||||
- `JobClient`:运行在 Blender Python 中,通过 HTTP 提交、查询和取消 Job
|
||||
- `JobServer`:对 FastAPI 的通用封装,负责 Job 注册、单任务调度、状态与取消
|
||||
- `JobContext`:单个 Job 的运行上下文,提供工作目录、进度、取消与 Resource
|
||||
- `ModalJobOperatorBase`:可直接继承的 Blender Modal Operator,内置提交线程、轮询、进度、取消和终态处理
|
||||
- `Resource`:由 Job Server 持有、跨多个 Job 复用的状态对象
|
||||
- `SnapForm Job Server`:SnapForm 创建并注册专属 Job 后得到的服务实例;代码变量使用 `server` 或 `snapform_server`
|
||||
|
||||
`blendjob` 不知道模型、输出文件或 Blender Operator。插件专属代码负责注册 Job 和 Resource,并把参数交给自己的执行逻辑。
|
||||
|
||||
## 最小接入
|
||||
|
||||
服务端只创建 Server 并注册业务函数:
|
||||
|
||||
```python
|
||||
server = JobServer("Example", jobs_directory="D:/example/jobs")
|
||||
|
||||
|
||||
@server.job("generate-depth")
|
||||
def generate_depth(context, parameters):
|
||||
output = context.directory / "depth.npz"
|
||||
run_depth(parameters["input"], output)
|
||||
context.update(1.0, "Depth is ready", output=str(output))
|
||||
```
|
||||
|
||||
Blender 端直接继承一个基类。普通任务只需要声明 Controller、Job Type 和怎么传值:
|
||||
|
||||
```python
|
||||
class GenerateDepth(ModalJobOperatorBase):
|
||||
bl_idname = "example.generate_depth"
|
||||
bl_label = "Generate Depth"
|
||||
controller_factory = staticmethod(service_controller)
|
||||
job_type = "generate-depth"
|
||||
|
||||
def job_parameters(self, context):
|
||||
return {"input": context.scene.source_path}
|
||||
```
|
||||
|
||||
这个 Operator 已经具备异步提交、Server 生成 Job ID 与目录、HTTP 轮询、进度、Esc 取消、错误报告和 Timer 清理。只有需要把产物导回 Blender 时,才覆盖 `on_job_succeeded(context, job, status)`;产物目录是 `job.directory`。
|
||||
|
||||
## Resource
|
||||
|
||||
Job 表示一次有终态的操作;Resource 表示在 Service 生命周期内被多个 Job 共用的状态。Resource 可以按需实现 `snapshot()`、`clear()` 和 `close()`:
|
||||
|
||||
```python
|
||||
models = server.add_resource("models", ModelManager(models_directory))
|
||||
|
||||
|
||||
@server.job("generate-depth")
|
||||
def generate_depth(context, parameters):
|
||||
models = context.resource("models")
|
||||
session = models.get(parameters["model"], parameters["device"])
|
||||
```
|
||||
|
||||
`JobServer` 在同一把调度锁下阻止运行中清理 Resource,关闭时按注册逆序调用 `close()`。Resource Snapshot 自动进入 `/health` 的 `resources` 字段。
|
||||
|
||||
## 服务端使用
|
||||
|
||||
开发者先创建 `JobServer`,再用装饰器注册 Job 类型:
|
||||
|
||||
```python
|
||||
from blendjob import JobCancelled, JobServer
|
||||
|
||||
|
||||
server = JobServer("Example Job Server", jobs_directory="D:/example/jobs")
|
||||
|
||||
|
||||
@server.job("generate-depth")
|
||||
def generate_depth(context, parameters):
|
||||
input_path = parameters["input"]
|
||||
output_path = context.directory / "depth.npz"
|
||||
context.update(0.1, "Loading image")
|
||||
context.check_cancelled()
|
||||
|
||||
run_model(input_path, output_path)
|
||||
|
||||
context.update(
|
||||
1.0,
|
||||
"Depth is ready",
|
||||
state="succeeded",
|
||||
output=output_path,
|
||||
)
|
||||
```
|
||||
|
||||
处理函数签名固定为 `handler(context, parameters)`。`parameters` 必须可由 JSON 表示。客户端提交的 `JobRequest` 不包含 ID;`JobServer` 接受请求时自动生成 opaque Job ID,并创建 `<jobs_directory>/<job_id>/`。处理函数通过 `context.job_id` 与 `context.directory` 获取它们。客户端不创建 Job 目录,也不应把输出目录作为业务参数传入。Job API 只保存内存状态和少量结果元数据,不创建 `status.json`。
|
||||
|
||||
`context.update()` 支持以下通用字段:
|
||||
|
||||
- `progress`:`0.0–1.0`
|
||||
- `message`:面向界面的当前步骤
|
||||
- `state`:通常自动推导,也可显式设置 `queued`、`running`、`succeeded`、`failed`、`cancelling` 或 `cancelled`
|
||||
- `error`:失败信息
|
||||
- 其它关键字:作为插件自定义状态字段原样返回
|
||||
|
||||
长耗时流程应在推理前后和循环内调用 `context.check_cancelled()`。底层库不可中断时,取消会在它返回后的最近检查点生效。
|
||||
|
||||
## Blender 端底层 API
|
||||
|
||||
`JobClient` 只依赖 Python 标准库,适合直接放入 Blender 插件:
|
||||
|
||||
```python
|
||||
from blendjob import JobClient, JobRequest, ServiceController
|
||||
|
||||
|
||||
client = JobClient("127.0.0.1", port)
|
||||
request = JobRequest.create(
|
||||
"generate-depth",
|
||||
input="D:/images/source.png",
|
||||
)
|
||||
submitted = client.submit_request(request)
|
||||
job_id = submitted["job_id"]
|
||||
job_directory = submitted["directory"]
|
||||
|
||||
status = client.status(job_id)
|
||||
if status["state"] == "running":
|
||||
update_blender_progress(status["progress"], status["message"])
|
||||
```
|
||||
|
||||
专属 Service 进程由 `ServiceController` 管理。插件只提供启动命令、工作目录和日志路径,端口、Instance ID、进程句柄、连接验证以及 `start()`、`ensure()`、`enable()`、`restart()`、`stop()`、`detach()` 都由 Controller 负责:
|
||||
|
||||
```python
|
||||
controller = ServiceController(
|
||||
lambda port, instance_id: [
|
||||
str(environment_python),
|
||||
"server.py",
|
||||
"--port", str(port),
|
||||
"--instance-id", instance_id,
|
||||
"--parent-pid", str(blender_pid),
|
||||
],
|
||||
cwd_factory=lambda: storage_root,
|
||||
log_path_factory=lambda: storage_root / "service.log",
|
||||
)
|
||||
|
||||
connection = controller.ensure()
|
||||
submitted = connection.client.submit_request(request)
|
||||
controller.stop()
|
||||
```
|
||||
|
||||
对应 HTTP API:
|
||||
|
||||
- `GET /health`:查询服务身份、忙闲状态和插件扩展状态
|
||||
- `POST /jobs`:提交 Job
|
||||
- `GET /jobs/{job_id}`:轮询进度与终态
|
||||
- `DELETE /jobs/{job_id}`:请求取消
|
||||
- `GET /resources`:查询全部 Resource
|
||||
- `GET /resources/{resource_name}`:查询一个 Resource
|
||||
- `POST /resources/{resource_name}/clear`:空闲时清理 Resource
|
||||
- `POST /shutdown`:关闭当前专属服务
|
||||
|
||||
Service 只监听 `127.0.0.1`,专属实例由启动它的 `ServiceController` 保存随机端口与 Instance ID。这个本地专属进程协议不额外使用 Token 鉴权。
|
||||
|
||||
`ModalJobOperatorBase` 默认使用 Blender Window Manager 的进度接口。插件若有自己的状态栏,可覆盖 `update_job_ui()` 与 `redraw_job_ui()`;这些属于界面定制,不是接入 Job 所必需的代码。运行态使用通用 `ModalJobState`,只包含 Controller、Job ID、目录、进度和取消状态。插件特有的完成参数可由 `create_job_data()` 返回,并通过 `job.data` 读取,不应加入通用状态类。
|
||||
|
||||
## 生命周期建议
|
||||
|
||||
每个 Blender 实例为每个插件启动一个专属 Job Server。随机端口与 Instance ID 由 `ServiceController` 生成并只保存在内存中,不写公共发现文件,也不扫描其它本地服务。
|
||||
|
||||
启动服务时传入 Blender 的 PID。服务同时监听显式 `/shutdown` 和父进程存活状态,因此正常禁用插件时可立即停止,Blender 异常退出后也能自行退出。这个方案允许同一机器出现多个服务进程,换取明确的所有权和插件隔离。
|
||||
|
||||
模型与 Environment 可以继续放在插件自己的共享 Storage Root 中;共享磁盘缓存不代表共享服务进程。若多个 Blender 可能同时写同一个模型目录,插件仍需对下载或更新操作单独加文件锁。
|
||||
|
||||
## 在其它插件复用
|
||||
|
||||
当前实现位于 `src/snapform/blendjob/`,没有 SnapForm 依赖。复用时复制整个 `blendjob` package,并在插件专属入口中完成以下工作:
|
||||
|
||||
1. 创建带 `jobs_directory` 的 `JobServer`
|
||||
2. 用 `@server.job()` 注册插件自己的处理函数
|
||||
3. 用 `server.add_resource()` 注册需要跨 Job 复用的状态
|
||||
4. 用安装环境中的 Uvicorn 运行 `server.create_app(instance_id)`
|
||||
5. Blender 端用 `ServiceController` 管理启动、停止、重启和连接检查
|
||||
6. Blender Operator 继承 `ModalJobOperatorBase`,声明 `controller_factory`、`job_type` 与 `job_parameters()`
|
||||
7. 需要导入产物时覆盖 `on_job_succeeded()`
|
||||
|
||||
后续若多个项目稳定复用,可把 `blendjob` 发布为独立 Python package;现阶段保持源码内嵌可以避免为 Blender 扩展增加安装依赖。
|
||||
@@ -15,16 +15,29 @@ uv run python pack.py
|
||||
├── src/
|
||||
│ └── snapform/
|
||||
│ ├── blender_manifest.toml
|
||||
│ ├── service.py
|
||||
│ ├── install_env.py
|
||||
│ ├── models.py
|
||||
│ ├── image_depth.py
|
||||
│ ├── operators.py
|
||||
│ ├── panel.py
|
||||
│ ├── preferences.py
|
||||
│ ├── properties.py
|
||||
│ ├── client.py
|
||||
│ └── worker.py
|
||||
│ ├── blendjob/
|
||||
│ │ ├── client.py
|
||||
│ │ ├── operator.py
|
||||
│ │ ├── service.py
|
||||
│ │ └── server.py
|
||||
│ ├── blender/
|
||||
│ │ ├── depth_plane.py
|
||||
│ │ └── surface.py
|
||||
│ └── ai_service/
|
||||
│ ├── server.py
|
||||
│ ├── model_manager.py
|
||||
│ ├── jobs.py
|
||||
│ ├── ben2_onnx.py
|
||||
│ ├── da3_onnx.py
|
||||
│ ├── moge_onnx.py
|
||||
│ └── onnx_runtime.py
|
||||
└── tests/
|
||||
```
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
(Image Empty 右键菜单)使用的推理设备,默认取本机最快的 DirectML/CoreML provider,否则 CPU,且只列出
|
||||
本机支持的设备。
|
||||
4. 在 `AI Service` 点击 `Install Environment`。首次安装会下载 Python、ONNX Runtime、FastAPI、Uvicorn;
|
||||
uv 已内置在扩展中,DA3、BEN2 与 MoGe 不安装源码包,
|
||||
uv 由 Bootstrap 下载并校验,DA3、BEN2 与 MoGe 不安装源码包,
|
||||
并在 Environment 安装后自动下载 `MoGe-2 ViT-S Normal` 和 FP16 `BEN2 Base` 推荐模型。Environment 安装
|
||||
首次安装依次显示 `uv`、`ONNX Environment`、`MoGe-2 ViT-S Normal` 与 `BEN2 Base`;每个阶段
|
||||
都独立从 0 走到 100%,进入下一阶段时进度条归零。uv 已存在时省略其阶段并重新编号。
|
||||
@@ -71,8 +71,8 @@
|
||||
Environment 安装阶段与 `Models` 面板单独下载使用相同的模型名称格式,不会改写为通用的 `Downloading packages`。
|
||||
Environment 安装后即使模型下载中断也不影响 Service 使用,可稍后在 `Models` 面板单独补下。
|
||||
安装不做启动网络预检:依赖安装默认依次尝试清华、阿里镜像并以 pypi.org 兜底;模型下载由
|
||||
worker 自行探测回退到 OmooLab 镜像,切换结果写入 service.json 的 models_from_r2 字段,
|
||||
本次周期内后续模型直接走 R2;需要手动指定依赖镜像时可通过
|
||||
Downloader 自行探测回退到 OmooLab 镜像,切换结果写入 `runtime.json` 的 `models_from_r2` 字段,
|
||||
后续下载直接走 R2;需要手动指定依赖镜像时可通过
|
||||
`UV_INDEX_URL` 环境变量覆盖。
|
||||
5. 在 3D View 按 `N`,打开 `SnapForm` 页签。
|
||||
6. 如需其他模型,展开 `Models` panel,找到模型并点击该行的 `Download`。
|
||||
|
||||
@@ -7,4 +7,5 @@
|
||||
- [Surface](surface.md):透视网格、Geometry Nodes 后处理与材质法线
|
||||
- [输出格式](outputs.md):Debug 输出类型、参数和任务产物
|
||||
- [AI Service](service.md):Environment、模型缓存、任务目录与运行机制
|
||||
- [BlendJob 开发者指南](blendjob.md):可复用 Job Server、Blender Client 与装饰器注册 API
|
||||
- [开发与许可证](development.md):开发验证、打包、上游版本与许可证
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
## 运行架构
|
||||
|
||||
SnapForm 在独立的 Python 3.12 Environment 中运行常驻 HTTP Service,Blender 只通过标准库 `urllib.request` 提交任务,不把 AI 运行库载入 Blender Python。Service 只监听 `127.0.0.1`,请求使用随机 Token;同一 Storage Root 由 `service.lock` 保证只有一个实例。
|
||||
SnapForm 在独立的 Python 3.12 Environment 中运行 HTTP Job Server,Blender 只通过标准库 HTTP Client 提交和轮询任务,不把 AI 运行库载入 Blender Python。Service 只监听 `127.0.0.1`,由 BlendJob `ServiceController` 保存随机端口与 Instance ID;专属本地进程协议不使用额外 Token 鉴权。
|
||||
|
||||
每个 Blender 实例启动并持有一个 SnapForm 专属服务,不发现或复用其它 Blender、其它插件启动的本地服务。多个 Blender 可以对应多个服务进程,但模型、Environment 与任务产物仍可共享同一个 Storage Root。
|
||||
|
||||
Environment、模型和任务结果默认保存在 `~/.snapform`:
|
||||
|
||||
@@ -12,12 +14,30 @@ Environment、模型和任务结果默认保存在 `~/.snapform`:
|
||||
├── models/
|
||||
├── jobs/
|
||||
├── manifest.json
|
||||
├── service.log
|
||||
├── service.json # Service 运行时存在
|
||||
└── service.lock # Service 运行时持有
|
||||
├── runtime.json # 持久的模型下载源状态
|
||||
├── environment.log
|
||||
├── environment-status.json
|
||||
└── service.log
|
||||
```
|
||||
|
||||
不同 Blender 版本可共享此目录。也可以在 Extension Preferences 的 `Storage Root` 中修改位置。
|
||||
不同 Blender 版本可共享此目录。也可以在 Extension Preferences 的 `Storage Root` 中修改位置。连接端口与 Instance ID 只保存在启动它们的 Blender 进程内存中。
|
||||
|
||||
通用 HTTP 层位于 `blendjob` module。`JobServer` 包装 FastAPI 并提供 Job 与 Resource API,`JobClient` 是无第三方依赖的 Blender 侧访问器。SnapForm 的 `ai_service/server.py` 只创建专属 Server、注册任务型 Job,并把 `ModelManager` 注册为 `models` Resource,不直接使用 FastAPI。完整接入方式见 [BlendJob 开发者指南](blendjob.md)。
|
||||
|
||||
SnapForm 公开的 Request 构造函数与 Job Type 一一对应:
|
||||
|
||||
- `download_model` → `download-model`
|
||||
- `remove_background` → `remove-background`
|
||||
- `extract_frames` → `extract-frames`
|
||||
- `generate_da3_depth` → `generate-da3-depth`
|
||||
- `generate_moge2_depth` → `generate-moge2-depth`
|
||||
- `generate_da3_surface` → `generate-da3-surface`
|
||||
- `generate_moge2_surface` → `generate-moge2-surface`
|
||||
- `debug_da3` → `debug-da3`
|
||||
- `debug_moge2` → `debug-moge2`
|
||||
- `debug_ben2` → `debug-ben2`
|
||||
|
||||
DA3 与 MoGe-2 的生产任务不再合并成带 Backend 参数的通用 Request。每种 Request 只携带自己的有效参数,Debug 任务也与生产任务完全分开。
|
||||
|
||||
## ONNX-only Environment
|
||||
|
||||
@@ -41,7 +61,9 @@ Windows 当前发行环境提供 DirectML 与 CPU;`Auto` 优先使用 `DmlExec
|
||||
- DA3 Small、DA3 Base
|
||||
- BEN2 Base
|
||||
|
||||
首次安装自动下载 `MoGe-2 ViT-S Normal` 与 FP16 `BEN2 Base`,其他模型在 `Models` panel 按需下载。模型按 Hugging Face 仓库末段名称保存在 `~/.snapform/models/`,并保留仓库内部结构。声明了文件清单与校验值的模型会直接走 Hugging Face `resolve` 直链流式下载,跳过文件清单与 ETag 预校验;连接源不可达时使用 3 秒 TCP 与 TLS 建连超时,随后回退到 `https://models.omoolab.xyz/<repository-name>/<relative-path>`,并把 `models_from_r2` 写入 service.json,本次 service 周期内后续模型直接走 R2,不再重复等待 Hugging Face。建连成功后不限制模型文件读取时长。R2 文件会校验大小与 SHA-256。未声明清单的仓库仍使用 `huggingface_hub` 快照下载。可用 `HF_ENDPOINT` 指定 Hugging Face 镜像。
|
||||
首次安装由 Bootstrap 流程自动下载 `MoGe-2 ViT-S Normal` 与 FP16 `BEN2 Base`。Environment 就绪后,`Models` panel 的后续下载提交为 `download-model` Job,与推理共用单任务调度、HTTP 进度和取消协议。模型按声明的目录名保存在 `~/.snapform/models/`,并保留仓库内部结构。声明了文件清单与校验值的模型会直接走 Hugging Face `resolve` 直链流式下载,跳过文件清单与 ETag 预校验;连接源不可达时使用 3 秒 TCP 与 TLS 建连超时,随后回退到 `https://models.omoolab.xyz/<repository-name>/<relative-path>`。镜像选择写入持久的 `runtime.json`,后续下载直接走 R2,避免每次 Service 重启后重复等待 Hugging Face。建连成功后不限制模型文件读取时长。R2 文件会校验大小与 SHA-256。未声明清单的仓库仍使用 `huggingface_hub` 快照下载。可用 `HF_ENDPOINT` 指定 Hugging Face 镜像。
|
||||
|
||||
`models` Resource 对外统一表示模型系统,内部区分磁盘模型与内存 Session。`ModelSessionCache` 保留 BEN2,并在 DA3 与 MoGe-2 之间只保留最近使用的一种 Depth Session。`GET /resources/models` 返回当前加载状态;`POST /resources/models/clear` 只允许在没有 Active Job 时执行。
|
||||
|
||||
DA3 ONNX 使用模型的 camera decoder 恢复外参与内参;旧版 `Use Ray Pose` 参数只为任务协议兼容保留,不参与 ONNX 推理。MoGe-2 的 metric depth、normal、mask、normalized intrinsics,以及 BEN2 的 Alpha,均在 NumPy 后处理中恢复。
|
||||
|
||||
@@ -56,9 +78,15 @@ uv 默认从 Astral 的 GitHub Release 下载,TCP 与 TLS 建连超过 3 秒
|
||||
|
||||
## 生命周期
|
||||
|
||||
扩展启用后只查找已有 Service;第一次执行 AI 操作或点击 `Start` 时才启动。每个 Blender 客户端每 5 秒发送心跳,正常关闭时注销。最后一个客户端离开后,Service 保留模型缓存 20 秒再退出。
|
||||
扩展启用后不启动 Service;第一次执行 AI 操作或点击 `Start` 时才为当前 Blender 启动专属实例。正常关闭或禁用扩展时直接停止自己启动的进程;服务也监视 Blender 父进程 PID,父进程异常退出后会自行停止。
|
||||
|
||||
Service 全局同时执行一个 AI 任务。BEN2 独立缓存,深度模型只保留最近使用的一个;切换模型时释放旧会话。取消任务不会重启 Service,ONNX Runtime 当前调用返回后在最近检查点结束。
|
||||
AI、帧提取和 Models panel 下载的 Job 进度保存在服务内存中。Blender 每 0.25 秒轮询 `GET /jobs/{job_id}`,任务目录不写 `status.json`。`JobRequest` 不包含 ID;Job 被接受时由 `JobServer` 自动生成 ID 并创建 `jobs/<opaque-job-id>/`,提交响应同时返回 `job_id` 与 `directory`。路径通过 `JobContext.directory` 传给 handler,SnapForm Service 强制将 Worker 输出写入该目录。
|
||||
|
||||
SnapForm 的 Blender 侧访问与全部 Request 构造函数集中在 `client.py`。提交线程、轮询、进度、取消和终态清理由 `blendjob.ModalJobOperatorBase` 直接提供;`operators.py` 的 `SnapFormJobOperator` 只保留 SnapForm 输入校验、Request 选取和完成后的 Blender 结果导入。通用运行态是 `ModalJobState`,SnapForm 特有的导入参数单独放在 `SnapFormJobData`。插件专属 Service 只在 `ai_service/server.py` 注册 Job,完全不直接编写 FastAPI Route。
|
||||
|
||||
只有 Environment 安装及其首次默认模型下载属于 Service 启动前的 Bootstrap 流程,使用 Storage Root 下共享的 `environment-status.json` 和 `environment.log` 回传进度,不创建 Job 目录。
|
||||
|
||||
Service 全局同时执行一个 Job,包括模型下载。取消任务不会重启 Service;流式模型下载会在分块检查点结束,ONNX Runtime 当前调用则在返回后的最近检查点结束。JobServer 最多保留 100 个已完成 Job 的内存状态,后续提交时清理更早记录。
|
||||
|
||||
启动与崩溃信息写入 `~/.snapform/service.log`。
|
||||
|
||||
|
||||
@@ -166,52 +166,21 @@ Image Empty 使用 Packed Image 时,SnapForm 会通过 Blender 写出临时 PN
|
||||
`DA3 Nested Giant Large 1.1`。Small 和 Base 没有 Gaussian head,无法由
|
||||
DA3 生成 `gs_ply`。
|
||||
|
||||
每个任务在 `~/.snapform/jobs/` 下用独立文件夹包裹。文件夹统一采用
|
||||
`动作-对象_日期-时间-微秒`,每种任务都有唯一名称,例如
|
||||
`generate-depth-plane_20260807-153000-123456`。微秒用于避免同一秒启动的任务共用目录。
|
||||
每个 Service Job 被接受时,BlendJob 在 `~/.snapform/jobs/` 下创建一个独立文件夹。文件夹名是 32 位 opaque Job ID,不包含任务类型或对象名称。执行逻辑从 `JobContext.directory` 获取路径,输出产物直接写入该目录。
|
||||
|
||||
Blender 为 Packed Image 或序列帧生成的输入副本也归档到对应 job 根目录:单图命名为
|
||||
`input.png`,序列帧命名为 `frame.0001.*`。它们以前暂存在 `jobs/inputs/`,现在不再创建这个
|
||||
公共中转文件夹。普通磁盘文件和视频仍直接读取原文件,不额外复制。
|
||||
Blender 为 Packed Image 或序列帧生成的输入副本先保存在系统临时目录,Service 读取完成后由 Blender 清理,不归档到 Job 目录。普通磁盘文件和视频仍直接读取原文件。Service Job 日志统一写入 `service.log`,进度只保存在 Service 内存中。Environment Bootstrap 使用 Storage Root 下的 `environment.log` 与 `environment-status.json`,不创建 Job 目录。
|
||||
|
||||
日志、运行中的状态文件、归档输入与输出产物均直接放在 job 根目录。各类任务名称为:
|
||||
|
||||
- `install-environment`
|
||||
- `download-model`
|
||||
- `export-reconstruction`
|
||||
- `generate-depth-plane`
|
||||
- `generate-image-mesh`
|
||||
- `remove-background`
|
||||
- `remove-image-background`
|
||||
- `generate-original-depth-plane`
|
||||
与几何输出相关的 Job Type 为 `generate-da3-depth`、`generate-moge2-depth`、`generate-da3-surface`、`generate-moge2-surface`、`debug-da3` 与 `debug-moge2`。每种 Job 只接收对应模型与输出所需的参数。
|
||||
|
||||
DA3 ONNX exporter 产生的 `depth_vis/`、`exports/mini_npz/` 会在完成后自动平铺,
|
||||
不会保留只含一层产物的子目录:
|
||||
|
||||
```text
|
||||
export-reconstruction_20260807-153000-123456/
|
||||
├── job.log
|
||||
├── status.json
|
||||
└── scene.glb
|
||||
<opaque-job-id>/
|
||||
├── scene.glb、*.ply、*.jpg 或 results.npz
|
||||
└── 其它对应 Debug 格式的产物
|
||||
|
||||
export-reconstruction_20260807-153000-123456/
|
||||
├── job.log
|
||||
├── status.json
|
||||
└── *.ply
|
||||
|
||||
export-reconstruction_20260807-153000-123456/
|
||||
├── job.log
|
||||
├── status.json
|
||||
└── *.jpg
|
||||
|
||||
export-reconstruction_20260807-153000-123456/
|
||||
├── job.log
|
||||
├── status.json
|
||||
└── results.npz
|
||||
|
||||
remove-background_20260807-153000-123456/
|
||||
├── job.log
|
||||
├── status.json
|
||||
<opaque-job-id>/
|
||||
├── foreground.png 单图结果
|
||||
├── foreground.0001.png… 视频/序列帧结果
|
||||
├── frame.0001.jpg… 视频/序列帧的源帧副本
|
||||
|
||||
Reference in New Issue
Block a user