chore: Bump version to 0.12.6, update BlendJob wheel to 0.1.8, and revise documentation for model catalog and server integration
Some checks failed
构建扩展 / build (push) Failing after 14s
Some checks failed
构建扩展 / build (push) Failing after 14s
This commit is contained in:
@@ -84,7 +84,7 @@ Session 逐帧推理,显存峰值不随视频帧数平方增长;Debug 多帧
|
|||||||
|
|
||||||
## 常见问题
|
## 常见问题
|
||||||
|
|
||||||
- 从 0.12.0–0.12.2 升级到 0.12.3 后,请重新执行一次 `Install Environment`,让 Storage Root 中的 Environment 更新 BlendJob 运行依赖
|
- 从 0.12.0–0.12.5 升级到 0.12.6 后,请重新执行一次 `Install Environment`,重建不再单独安装 BlendJob 的 Server Environment
|
||||||
- 首次使用需要下载模型,如果下载慢或失败,可在 Image Empty 的 `SnapForm` 右键菜单点击
|
- 首次使用需要下载模型,如果下载慢或失败,可在 Image Empty 的 `SnapForm` 右键菜单点击
|
||||||
`Download Required Models`,也可在 `Models` panel 里逐项重试
|
`Download Required Models`,也可在 `Models` panel 里逐项重试
|
||||||
- 安装 Environment 时 uv 下载失败会自动尝试 OmooLab 镜像;Python packages 需要指定镜像时设置
|
- 安装 Environment 时 uv 下载失败会自动尝试 OmooLab 镜像;Python packages 需要指定镜像时设置
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ flowchart LR
|
|||||||
- `job_runtime.py` 以入口字符串声明独立 Server,并配置 Environment、Storage Root 与首次安装后的推荐模型下载
|
- `job_runtime.py` 以入口字符串声明独立 Server,并配置 Environment、Storage Root 与首次安装后的推荐模型下载
|
||||||
- `server/__init__.py` 创建 `JobServer`、注册公开 Job,并把 `ModelManager` 注册为 Resource
|
- `server/__init__.py` 创建 `JobServer`、注册公开 Job,并把 `ModelManager` 注册为 Resource
|
||||||
- `server/media.py`、`background.py`、`da3.py`、`moge2.py` 负责业务流程;`onnx_*.py` 只处理模型输入、推理和输出恢复
|
- `server/media.py`、`background.py`、`da3.py`、`moge2.py` 负责业务流程;`onnx_*.py` 只处理模型输入、推理和输出恢复
|
||||||
- 根目录 `model_catalog.py` 是 Blender UI 与独立 Server 共用的纯数据声明;`server/model_download.py`、`server/model_manager.py` 分别负责下载和 Session 生命周期
|
- 根目录 `model_catalog.py` 供 Blender UI 与本地就绪检查使用;`server/model_catalog.py` 独立声明下载与推理所需模型,二者的模型键、目录名和 `ready_patterns` 由测试约束一致
|
||||||
- `server/geometry.py` 生成 NPZ、预览、点云和纹理网格;所有任务产物写入 Runtime 分配的 opaque-ID Job 目录
|
- `server/geometry.py` 生成 NPZ、预览、点云和纹理网格;所有任务产物写入 Runtime 分配的 opaque-ID Job 目录
|
||||||
|
|
||||||
功能细节继续按主题维护:[Depth Plane](depth-plane.md)、[Surface](surface.md)、[输出格式](outputs.md) 和 [Job Server](server.md)。
|
功能细节继续按主题维护:[Depth Plane](depth-plane.md)、[Surface](surface.md)、[输出格式](outputs.md) 和 [Job Server](server.md)。
|
||||||
@@ -61,6 +61,7 @@ flowchart LR
|
|||||||
│ │ ├── geometry.py
|
│ │ ├── geometry.py
|
||||||
│ │ ├── media.py
|
│ │ ├── media.py
|
||||||
│ │ ├── model_download.py
|
│ │ ├── model_download.py
|
||||||
|
│ │ ├── model_catalog.py
|
||||||
│ │ ├── model_manager.py
|
│ │ ├── model_manager.py
|
||||||
│ │ ├── moge2.py
|
│ │ ├── moge2.py
|
||||||
│ │ ├── onnx_ben2.py
|
│ │ ├── onnx_ben2.py
|
||||||
@@ -68,7 +69,7 @@ flowchart LR
|
|||||||
│ │ ├── onnx_moge2.py
|
│ │ ├── onnx_moge2.py
|
||||||
│ │ └── onnx_runtime.py
|
│ │ └── onnx_runtime.py
|
||||||
│ └── wheels/
|
│ └── wheels/
|
||||||
│ └── blendjob-0.1.6-py3-none-any.whl
|
│ └── blendjob-0.1.8-py3-none-any.whl
|
||||||
├── tests/
|
├── tests/
|
||||||
└── tools/
|
└── tools/
|
||||||
```
|
```
|
||||||
@@ -84,7 +85,7 @@ uv run pytest tests/test_addon.py tests/test_manifest.py tests/test_pack.py -v
|
|||||||
uv run python pack.py
|
uv run python pack.py
|
||||||
```
|
```
|
||||||
|
|
||||||
`pack.py` 根据 `blender_manifest.toml` 分别生成 Windows、macOS 和 Linux 扩展包,例如 `dist/SnapForm.v0.12.3.windows-x64.zip`。从 PyPI 下载并更换 `src/snapform/wheels/` 中随扩展分发的 wheel 后,先刷新锁文件再测试:
|
`pack.py` 根据 `blender_manifest.toml` 分别生成 Windows、macOS 和 Linux 扩展包,例如 `dist/SnapForm.v0.12.6.windows-x64.zip`。更换 `src/snapform/wheels/` 中随扩展分发的 wheel 后,先刷新锁文件再测试:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
uv lock --refresh
|
uv lock --refresh
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
## 使用
|
## 使用
|
||||||
|
|
||||||
1. 运行 `uv run python pack.py`,分别构建 `windows-x64`、`macos-arm64`、
|
1. 运行 `uv run python pack.py`,分别构建 `windows-x64`、`macos-arm64`、
|
||||||
`linux-x64` 三个平台的 Extension ZIP(如 `SnapForm.v0.12.3.macos-arm64.zip`)。
|
`linux-x64` 三个平台的 Extension ZIP(如 `SnapForm.v0.12.6.macos-arm64.zip`)。
|
||||||
安装包不携带 uv 或 AI 项目源码;首次安装 Environment 时下载固定版本 uv,官方源建连超过 3 秒后回退 OmooLab 镜像,并校验固定 SHA-256。
|
安装包不携带 uv 或 AI 项目源码;首次安装 Environment 时下载固定版本 uv,官方源建连超过 3 秒后回退 OmooLab 镜像,并校验固定 SHA-256。
|
||||||
2. 在 Blender 的 `Preferences > Extensions` 中选择 `Install from Disk`。
|
2. 在 Blender 的 `Preferences > Extensions` 中选择 `Install from Disk`。
|
||||||
3. 在 Extension Preferences 中确认 Storage Root 与 Device。Device 是正式功能
|
3. 在 Extension Preferences 中确认 Storage Root 与 Device。Device 是正式功能
|
||||||
|
|||||||
@@ -22,14 +22,14 @@ Environment、模型和任务结果默认保存在 `~/.snapform`:
|
|||||||
|
|
||||||
不同 Blender 版本可共享此目录。也可以在 Extension Preferences 的 `Storage Root` 中修改位置。连接端口与 Instance ID 只保存在启动它们的 Blender 进程内存中。
|
不同 Blender 版本可共享此目录。也可以在 Extension Preferences 的 `Storage Root` 中修改位置。连接端口与 Instance ID 只保存在启动它们的 Blender 进程内存中。
|
||||||
|
|
||||||
Blender 侧的通用 HTTP Runtime 由 `src/snapform/wheels/` 中随扩展分发的 BlendJob package 提供;独立 Environment 由 Runtime 从 PyPI 自动安装相同版本。`JobServer` 包装 FastAPI 并提供 Job、FIFO Queue 与 Resource API,`JobClient` 是无第三方依赖的 Blender 侧访问器。Blender 侧只把 `server/__init__.py:server` 入口字符串交给 Runtime,不导入 `server` package;独立进程启动后才取得其中的 `server` 实例、注册全部公开 Job,并创建 `model_manager` Resource。
|
Blender Client 与独立 Server 的通用 HTTP Runtime 都复用 `src/snapform/wheels/` 中随扩展分发的同一份 BlendJob package;Server Environment 不再从 PyPI 安装第二份。`JobServer` 包装 FastAPI 并提供 Job、FIFO Queue 与 Resource API,`JobClient` 是无第三方依赖的 Blender 侧访问器。Blender 侧只把 `server/__init__.py:server` 入口字符串交给 Runtime,不导入 `server` package;独立进程启动后才取得其中的 `server` 实例、注册全部公开 Job,并创建 `model_manager` Resource。
|
||||||
|
|
||||||
SnapForm 根 package 不再有 `client.py`、`environment.py`、`storage.py` 或 `models.py`。这些文件会制造并不存在的业务边界:
|
SnapForm 根 package 不再有 `client.py`、`environment.py`、`storage.py` 或 `models.py`。这些文件会制造并不存在的业务边界:
|
||||||
|
|
||||||
- Storage Root、`.venv`、Manifest、安装状态与日志路径由 `JobRuntime` 唯一管理;
|
- Storage Root、`.venv`、Manifest、安装状态与日志路径由 `JobRuntime` 唯一管理;
|
||||||
- `InstallEnvironment` 由 `runtime.operator_classes()` 提供,Python 与 Job 自身的额外 packages 直接声明在传给 Runtime 的 `environment` 字典中;BlendJob 不需要重复声明;
|
- `InstallEnvironment` 由 `runtime.operator_classes()` 提供,Python 与 Job 自身的额外 packages 直接声明在传给 Runtime 的 `environment` 字典中;BlendJob 不需要重复声明;
|
||||||
- 模型 catalog 由 `model_catalog.py` 统一声明;下载和 ONNX Session 属于 Server,分别位于 `model_download.py` 与 `model_manager.py`;
|
- Blender Client 使用根目录 `model_catalog.py` 构造 UI 并检查 Storage Root 下的模型必需文件;
|
||||||
- Blender UI 复用同一 catalog,直接检查 Storage Root 下的模型必需文件,不为显示下载状态启动 Server;已加载 Session 状态仍读取现有 Server Snapshot。
|
- 独立 Server 使用 `server/model_catalog.py` 下载和验证模型,不依赖 Extension 根 package。两份声明的共享存储字段由测试保持一致,已加载 Session 状态仍读取 Server Snapshot。
|
||||||
|
|
||||||
BlendJob 的 `JobClient` 只是无依赖 HTTP transport,不是 SnapForm 业务抽象,也不向 Operator 暴露 `JobRequest`。
|
BlendJob 的 `JobClient` 只是无依赖 HTTP transport,不是 SnapForm 业务抽象,也不向 Operator 暴露 `JobRequest`。
|
||||||
|
|
||||||
@@ -57,13 +57,13 @@ Server 端没有 `execute_*`、`*_result` 或 CLI worker 中转。全部 `@serve
|
|||||||
|
|
||||||
- ONNX Runtime 1.24.4;Windows 使用 `onnxruntime-directml`
|
- ONNX Runtime 1.24.4;Windows 使用 `onnxruntime-directml`
|
||||||
- NumPy 2.4.2、Pillow 12.1.1、PyAV 17.0.0、trimesh 4.11.2
|
- NumPy 2.4.2、Pillow 12.1.1、PyAV 17.0.0、trimesh 4.11.2
|
||||||
- BlendJob 0.1.6、FastAPI 0.139.2、Uvicorn 0.51.0、huggingface-hub 1.4.1
|
- FastAPI 0.139.2、Uvicorn 0.51.0、huggingface-hub 1.4.1
|
||||||
|
|
||||||
运行环境不安装 PyTorch、TorchVision、xFormers,也不安装 DA3、MoGe、BEN2 或 utils3d 的 Python 源码包。模型推理和 SnapForm 所需的相机、点云、网格后处理均由 ONNX Runtime、NumPy 与内部实现完成。
|
运行环境不安装 PyTorch、TorchVision、xFormers,也不安装 DA3、MoGe、BEN2 或 utils3d 的 Python 源码包。模型推理和 SnapForm 所需的相机、点云、网格后处理均由 ONNX Runtime、NumPy 与内部实现完成。
|
||||||
|
|
||||||
Windows 当前发行环境提供 DirectML 与 CPU;`Auto` 优先使用 `DmlExecutionProvider`。显式指定不可用设备时会安全回退到 CPU。其他平台安装标准 ONNX Runtime,并按可用 provider 选择 CoreML、OpenVINO 或 CPU。
|
Windows 当前发行环境提供 DirectML 与 CPU;`Auto` 优先使用 `DmlExecutionProvider`。显式指定不可用设备时会安全回退到 CPU。其他平台安装标准 ONNX Runtime,并按可用 provider 选择 CoreML、OpenVINO 或 CPU。
|
||||||
|
|
||||||
`environment.json` 保存规范化后的声明,`manifest.json` 保存该声明、BlendJob 版本与基础 Server packages 的 Hash。Python、packages、平台 packages、BlendJob 版本或 Environment Schema 改变后需要重新执行 `Install Environment`,不再维护手工 Manifest Revision。
|
`environment.json` 保存规范化后的声明,`manifest.json` 保存该声明与基础 Server packages 的 Hash。Python、packages、平台 packages、基础 Server packages 或 Environment Schema 改变后需要重新执行 `Install Environment`,不再维护手工 Manifest Revision。BlendJob 直接随 Extension 更新,不参与 Environment Hash。
|
||||||
|
|
||||||
## 模型
|
## 模型
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ Image Empty 的右键菜单会读取 `model_manager` 状态;缺少 MoGe-2 ViT-
|
|||||||
只下载缺失项,并把多个下载的进度合并为单次 0–100%。必需模型补齐前,右键菜单中的
|
只下载缺失项,并把多个下载的进度合并为单次 0–100%。必需模型补齐前,右键菜单中的
|
||||||
`Convert to Depth Plane` 保持禁用。
|
`Convert to Depth Plane` 保持禁用。
|
||||||
|
|
||||||
`model_manager` Resource 在 Server 内持有模型 catalog、磁盘就绪状态和内存 Session。Blender UI 使用 catalog 声明的目录名与 `ready_patterns` 直接检查 `<storage-root>/models/`,因此展开模型面板、打开转换对话框或 Image Empty 右键菜单都不会仅为状态检测启动 Server。真正下载或推理时,Server 仍通过 `ModelManager.ready()` 重新验证文件。`ModelSessionCache` 保留 BEN2,并在 DA3 与 MoGe-2 之间只保留最近使用的一种 Depth Session。`GET /resources/model_manager` 继续返回 catalog、下载状态和当前加载状态;`POST /resources/model_manager/clear` 只允许在没有 Active 或 Queued Job 时执行。
|
`model_manager` Resource 在 Server 内持有磁盘就绪状态和内存 Session。Blender UI 使用 Client catalog 声明的目录名与 `ready_patterns` 直接检查 `<storage-root>/models/`,因此展开模型面板、打开转换对话框或 Image Empty 右键菜单都不会仅为状态检测启动 Server。真正下载或推理时,Server 仍按自身 catalog 通过 `ModelManager.ready()` 重新验证文件。`ModelSessionCache` 保留 BEN2,并在 DA3 与 MoGe-2 之间只保留最近使用的一种 Depth Session。`GET /resources/model_manager` 只返回当前加载状态;`POST /resources/model_manager/clear` 只允许在没有 Active 或 Queued Job 时执行。
|
||||||
|
|
||||||
DA3 ONNX 使用模型的 camera decoder 恢复外参与内参,不提供 ray-pose 参数。MoGe-2 的 metric depth、normal、mask、normalized intrinsics,以及 BEN2 的 Alpha,均在 NumPy 后处理中恢复。
|
DA3 ONNX 使用模型的 camera decoder 恢复外参与内参,不提供 ray-pose 参数。MoGe-2 的 metric depth、normal、mask、normalized intrinsics,以及 BEN2 的 Alpha,均在 NumPy 后处理中恢复。
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "snapform"
|
name = "snapform"
|
||||||
version = "0.12.3"
|
version = "0.12.6"
|
||||||
description = "Fast image-guided structure building tools for Blender"
|
description = "Fast image-guided structure building tools for Blender"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
@@ -14,4 +14,4 @@ dev = ["numpy", "pillow", "pytest"]
|
|||||||
package = false
|
package = false
|
||||||
|
|
||||||
[tool.uv.sources]
|
[tool.uv.sources]
|
||||||
blendjob = { path = "src/snapform/wheels/blendjob-0.1.6-py3-none-any.whl" }
|
blendjob = { path = "src/snapform/wheels/blendjob-0.1.8-py3-none-any.whl" }
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
schema_version = "1.0.0"
|
schema_version = "1.0.0"
|
||||||
|
|
||||||
id = "snapform"
|
id = "snapform"
|
||||||
version = "0.12.3"
|
version = "0.12.6"
|
||||||
name = "SnapForm"
|
name = "SnapForm"
|
||||||
tagline = "Build spatial structures from images, fast"
|
tagline = "Build spatial structures from images, fast"
|
||||||
maintainer = "OmooLab"
|
maintainer = "OmooLab"
|
||||||
@@ -10,7 +10,7 @@ type = "add-on"
|
|||||||
blender_version_min = "4.5.0"
|
blender_version_min = "4.5.0"
|
||||||
platforms = ["windows-x64", "macos-arm64", "linux-x64"]
|
platforms = ["windows-x64", "macos-arm64", "linux-x64"]
|
||||||
license = ["SPDX:GPL-3.0-or-later"]
|
license = ["SPDX:GPL-3.0-or-later"]
|
||||||
wheels = ["./wheels/blendjob-0.1.6-py3-none-any.whl"]
|
wheels = ["./wheels/blendjob-0.1.8-py3-none-any.whl"]
|
||||||
|
|
||||||
[permissions]
|
[permissions]
|
||||||
network = "Access the local Job Server and download environment dependencies and model weights"
|
network = "Access the local Job Server and download environment dependencies and model weights"
|
||||||
|
|||||||
188
src/snapform/server/model_catalog.py
Normal file
188
src/snapform/server/model_catalog.py
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class ModelSpec:
|
||||||
|
key: str
|
||||||
|
label: str
|
||||||
|
directory_name: str
|
||||||
|
repository: str
|
||||||
|
license_name: str
|
||||||
|
description: str
|
||||||
|
supports_gs: bool
|
||||||
|
download_patterns: tuple[str, ...] = ()
|
||||||
|
ready_patterns: tuple[str, ...] = ("config.json", "*.safetensors")
|
||||||
|
enabled: bool = True
|
||||||
|
r2_directory: str = ""
|
||||||
|
r2_files: tuple[tuple[str, int, str], ...] = ()
|
||||||
|
|
||||||
|
|
||||||
|
MODELS = {
|
||||||
|
"SMALL": ModelSpec(
|
||||||
|
key="SMALL",
|
||||||
|
label="DA3 Small",
|
||||||
|
directory_name="DA3-SMALL",
|
||||||
|
repository="depth-anything/DA3-SMALL",
|
||||||
|
license_name="Apache 2.0",
|
||||||
|
description="Fastest any-view model using ONNX Runtime",
|
||||||
|
supports_gs=False,
|
||||||
|
download_patterns=("model.onnx",),
|
||||||
|
ready_patterns=("model.onnx",),
|
||||||
|
r2_directory="DA3-SMALL",
|
||||||
|
r2_files=(
|
||||||
|
("model.onnx", 105484029, "7a9d81475b3e2334ace0d6d2c2a816b3c93081437e1866cc434ce1789125f631"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"BASE": ModelSpec(
|
||||||
|
key="BASE",
|
||||||
|
label="DA3 Base",
|
||||||
|
directory_name="DA3-BASE",
|
||||||
|
repository="depth-anything/DA3-BASE",
|
||||||
|
license_name="Apache 2.0",
|
||||||
|
description="Balanced any-view model using ONNX Runtime",
|
||||||
|
supports_gs=False,
|
||||||
|
download_patterns=("model.onnx",),
|
||||||
|
ready_patterns=("model.onnx",),
|
||||||
|
r2_directory="DA3-BASE",
|
||||||
|
r2_files=(
|
||||||
|
("model.onnx", 412856697, "31f38fc4990539d7902ba267924b9731db1acb00d840c248a60b1865810ff9e6"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
"GIANT_1_1": ModelSpec(
|
||||||
|
key="GIANT_1_1",
|
||||||
|
label="DA3 Giant 1.1",
|
||||||
|
directory_name="da3_giant_1_1",
|
||||||
|
repository="depth-anything/DA3-GIANT-1.1",
|
||||||
|
license_name="CC BY-NC 4.0",
|
||||||
|
description="Non-commercial Giant model with Gaussian head",
|
||||||
|
supports_gs=True,
|
||||||
|
enabled=False,
|
||||||
|
),
|
||||||
|
"NESTED_GIANT_LARGE_1_1": ModelSpec(
|
||||||
|
key="NESTED_GIANT_LARGE_1_1",
|
||||||
|
label="DA3 Nested Giant Large 1.1",
|
||||||
|
directory_name="da3_nested_giant_large_1_1",
|
||||||
|
repository="depth-anything/DA3NESTED-GIANT-LARGE-1.1",
|
||||||
|
license_name="CC BY-NC 4.0",
|
||||||
|
description="Non-commercial nested model with metric depth and Gaussian head",
|
||||||
|
supports_gs=True,
|
||||||
|
enabled=False,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
BEN2_MODEL = ModelSpec(
|
||||||
|
key="BEN2_BASE",
|
||||||
|
label="BEN2 Base",
|
||||||
|
directory_name="BEN2-ONNX",
|
||||||
|
repository="onnx-community/BEN2-ONNX",
|
||||||
|
license_name="Apache 2.0",
|
||||||
|
description="Fast high-quality FP16 ONNX background removal model",
|
||||||
|
supports_gs=False,
|
||||||
|
download_patterns=("onnx/model_fp16.onnx",),
|
||||||
|
ready_patterns=("onnx/model_fp16.onnx",),
|
||||||
|
r2_directory="BEN2-ONNX",
|
||||||
|
r2_files=((
|
||||||
|
"onnx/model_fp16.onnx",
|
||||||
|
219121675,
|
||||||
|
"dfdc25f421f32a0d1268e0f2ff2153d340e8f1d52d3dd16f5dc33c1ce85cedf1",
|
||||||
|
),),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
MOGE2_MODELS = {
|
||||||
|
"MOGE2_VITS_NORMAL": ModelSpec(
|
||||||
|
key="MOGE2_VITS_NORMAL",
|
||||||
|
label="MoGe-2 ViT-S Normal",
|
||||||
|
directory_name="moge-2-vits-normal-onnx",
|
||||||
|
repository="Ruicheng/moge-2-vits-normal-onnx",
|
||||||
|
license_name="MIT",
|
||||||
|
description="Fastest MoGe-2 model using ONNX Runtime",
|
||||||
|
supports_gs=False,
|
||||||
|
download_patterns=("model.onnx",),
|
||||||
|
ready_patterns=("model.onnx",),
|
||||||
|
r2_directory="moge-2-vits-normal-onnx",
|
||||||
|
r2_files=((
|
||||||
|
"model.onnx",
|
||||||
|
140852051,
|
||||||
|
"24eacb5dc7a2c54c7bc98f7de085ffbed79ad006ea5b664c2c2cdc02ff3a52f0",
|
||||||
|
),),
|
||||||
|
),
|
||||||
|
"MOGE2_VITB_NORMAL": ModelSpec(
|
||||||
|
key="MOGE2_VITB_NORMAL",
|
||||||
|
label="MoGe-2 ViT-B Normal",
|
||||||
|
directory_name="moge-2-vitb-normal-onnx",
|
||||||
|
repository="Ruicheng/moge-2-vitb-normal-onnx",
|
||||||
|
license_name="MIT",
|
||||||
|
description="Balanced MoGe-2 model using ONNX Runtime",
|
||||||
|
supports_gs=False,
|
||||||
|
download_patterns=("model.onnx",),
|
||||||
|
ready_patterns=("model.onnx",),
|
||||||
|
r2_directory="moge-2-vitb-normal-onnx",
|
||||||
|
r2_files=((
|
||||||
|
"model.onnx",
|
||||||
|
419411850,
|
||||||
|
"bbf14e07a30f11e69d36ab861590123f5598ababcbc8946a063eb4a966f35a21",
|
||||||
|
),),
|
||||||
|
),
|
||||||
|
"MOGE2_VITL_NORMAL": ModelSpec(
|
||||||
|
key="MOGE2_VITL_NORMAL",
|
||||||
|
label="MoGe-2 ViT-L Normal",
|
||||||
|
directory_name="moge-2-vitl-normal-onnx",
|
||||||
|
repository="Ruicheng/moge-2-vitl-normal-onnx",
|
||||||
|
license_name="MIT",
|
||||||
|
description="Highest-quality MoGe-2 model using ONNX Runtime",
|
||||||
|
supports_gs=False,
|
||||||
|
download_patterns=("model.onnx",),
|
||||||
|
ready_patterns=("model.onnx",),
|
||||||
|
r2_directory="moge-2-vitl-normal-onnx",
|
||||||
|
r2_files=((
|
||||||
|
"model.onnx",
|
||||||
|
1324265014,
|
||||||
|
"afbc4ccc3450298f3afb35b90f015f4c4f552dea21dc6470d5f7b78b77e2d751",
|
||||||
|
),),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
MOGE2_MODEL = MOGE2_MODELS["MOGE2_VITS_NORMAL"]
|
||||||
|
DOWNLOADABLE_MODELS = {
|
||||||
|
**MODELS,
|
||||||
|
BEN2_MODEL.key: BEN2_MODEL,
|
||||||
|
**MOGE2_MODELS,
|
||||||
|
}
|
||||||
|
MODEL_NUMBERS = {
|
||||||
|
model_key: number for number, model_key in enumerate(MODELS)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_model(model_key):
|
||||||
|
try:
|
||||||
|
return MODELS[model_key]
|
||||||
|
except KeyError as error:
|
||||||
|
raise ValueError(f"Unknown DA3 model: {model_key}") from error
|
||||||
|
|
||||||
|
|
||||||
|
def get_downloadable_model(model_key):
|
||||||
|
try:
|
||||||
|
return DOWNLOADABLE_MODELS[model_key]
|
||||||
|
except KeyError as error:
|
||||||
|
raise ValueError(f"Unknown model: {model_key}") from error
|
||||||
|
|
||||||
|
|
||||||
|
def model_directory_name(model_key):
|
||||||
|
"""Return the model's folder name inside the shared models directory."""
|
||||||
|
return get_downloadable_model(model_key).directory_name
|
||||||
|
|
||||||
|
|
||||||
|
def model_record(model, ready=False):
|
||||||
|
"""Return public model metadata exposed by the Models Resource."""
|
||||||
|
return {
|
||||||
|
"key": model.key,
|
||||||
|
"label": model.label,
|
||||||
|
"description": model.description,
|
||||||
|
"license": model.license_name,
|
||||||
|
"supports_gs": model.supports_gs,
|
||||||
|
"enabled": model.enabled,
|
||||||
|
"family": "moge2" if model.key.startswith("MOGE2_") else (
|
||||||
|
"ben2" if model.key == BEN2_MODEL.key else "da3"
|
||||||
|
),
|
||||||
|
"ready": bool(ready),
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import time
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
|
|
||||||
import model_catalog
|
from . import model_catalog
|
||||||
from .model_download import download_model
|
from .model_download import download_model
|
||||||
|
|
||||||
|
|
||||||
@@ -144,11 +144,7 @@ class ModelManager:
|
|||||||
return self.sessions.get_moge2(model_dir, device)
|
return self.sessions.get_moge2(model_dir, device)
|
||||||
|
|
||||||
def snapshot(self):
|
def snapshot(self):
|
||||||
catalog = [
|
return {"loaded": self.sessions.snapshot()}
|
||||||
model_catalog.model_record(model, self.ready(model.key))
|
|
||||||
for model in model_catalog.DOWNLOADABLE_MODELS.values()
|
|
||||||
]
|
|
||||||
return {"loaded": self.sessions.snapshot(), "catalog": catalog}
|
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
self.sessions.close()
|
self.sessions.close()
|
||||||
|
|||||||
@@ -23,6 +23,20 @@ class ModelTest(unittest.TestCase):
|
|||||||
"snapform_models",
|
"snapform_models",
|
||||||
"src/snapform/model_catalog.py",
|
"src/snapform/model_catalog.py",
|
||||||
)
|
)
|
||||||
|
cls.server_models = load_module(
|
||||||
|
"snapform_server_models",
|
||||||
|
"src/snapform/server/model_catalog.py",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_client_and_server_catalogs_share_storage_contract(self):
|
||||||
|
client = self.models.DOWNLOADABLE_MODELS
|
||||||
|
server = self.server_models.DOWNLOADABLE_MODELS
|
||||||
|
|
||||||
|
self.assertEqual(set(client), set(server))
|
||||||
|
for key in client:
|
||||||
|
with self.subTest(key=key):
|
||||||
|
self.assertEqual(client[key].directory_name, server[key].directory_name)
|
||||||
|
self.assertEqual(client[key].ready_patterns, server[key].ready_patterns)
|
||||||
|
|
||||||
def test_base_model_is_default_friendly_apache_model(self):
|
def test_base_model_is_default_friendly_apache_model(self):
|
||||||
model = self.models.get_model("BASE")
|
model = self.models.get_model("BASE")
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class PackTest(unittest.TestCase):
|
|||||||
self.assertNotIn("server/jobs.py", names)
|
self.assertNotIn("server/jobs.py", names)
|
||||||
self.assertIn("server/__init__.py", names)
|
self.assertIn("server/__init__.py", names)
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
"wheels/blendjob-0.1.6-py3-none-any.whl",
|
"wheels/blendjob-0.1.8-py3-none-any.whl",
|
||||||
names,
|
names,
|
||||||
)
|
)
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import importlib
|
import importlib.util
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import threading
|
import threading
|
||||||
@@ -13,12 +13,15 @@ PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
|||||||
|
|
||||||
|
|
||||||
def load_server_module():
|
def load_server_module():
|
||||||
addon_directory = PROJECT_ROOT / "src" / "snapform"
|
server_directory = PROJECT_ROOT / "src" / "snapform" / "server"
|
||||||
sys.path.insert(0, str(addon_directory))
|
specification = importlib.util.spec_from_file_location(
|
||||||
try:
|
"server", server_directory / "__init__.py",
|
||||||
return importlib.import_module("server")
|
submodule_search_locations=[str(server_directory)],
|
||||||
finally:
|
)
|
||||||
sys.path.remove(str(addon_directory))
|
module = importlib.util.module_from_spec(specification)
|
||||||
|
sys.modules["server"] = module
|
||||||
|
specification.loader.exec_module(module)
|
||||||
|
return module
|
||||||
|
|
||||||
|
|
||||||
class FakeCuda:
|
class FakeCuda:
|
||||||
@@ -70,8 +73,12 @@ class ServerTest(unittest.TestCase):
|
|||||||
with tempfile.TemporaryDirectory() as directory:
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
manager = self.server_module.ModelManager(Path(directory))
|
manager = self.server_module.ModelManager(Path(directory))
|
||||||
snapshot = manager.snapshot()
|
snapshot = manager.snapshot()
|
||||||
self.assertIn("catalog", snapshot)
|
self.assertEqual(
|
||||||
self.assertTrue(snapshot["catalog"])
|
snapshot,
|
||||||
|
{"loaded": {"ben2": "", "da3": "", "moge2": ""}},
|
||||||
|
)
|
||||||
|
self.assertIn("server.model_catalog", sys.modules)
|
||||||
|
self.assertNotIn("model_catalog", sys.modules)
|
||||||
|
|
||||||
def create_cache(self):
|
def create_cache(self):
|
||||||
cache = self.server_module.ModelSessionCache.__new__(
|
cache = self.server_module.ModelSessionCache.__new__(
|
||||||
|
|||||||
10
uv.lock
generated
10
uv.lock
generated
@@ -8,10 +8,10 @@ resolution-markers = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blendjob"
|
name = "blendjob"
|
||||||
version = "0.1.6"
|
version = "0.1.8"
|
||||||
source = { path = "src/snapform/wheels/blendjob-0.1.6-py3-none-any.whl" }
|
source = { path = "src/snapform/wheels/blendjob-0.1.8-py3-none-any.whl" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ filename = "blendjob-0.1.6-py3-none-any.whl", hash = "sha256:ed7c0ee4a0c952c25a7b6606bcd860b5c782ecb04ae6f9e7b1c475a03ab9c6b1" },
|
{ filename = "blendjob-0.1.8-py3-none-any.whl", hash = "sha256:9e94b42dfe0dde62702dff119243d5db3bfd4b4b3f0553191aaada1452b4338d" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
@@ -305,7 +305,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "snapform"
|
name = "snapform"
|
||||||
version = "0.12.3"
|
version = "0.12.6"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "blendjob" },
|
{ name = "blendjob" },
|
||||||
@@ -320,7 +320,7 @@ dev = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [{ name = "blendjob", path = "src/snapform/wheels/blendjob-0.1.6-py3-none-any.whl" }]
|
requires-dist = [{ name = "blendjob", path = "src/snapform/wheels/blendjob-0.1.8-py3-none-any.whl" }]
|
||||||
|
|
||||||
[package.metadata.requires-dev]
|
[package.metadata.requires-dev]
|
||||||
dev = [
|
dev = [
|
||||||
|
|||||||
Reference in New Issue
Block a user