- Implement ComfyCliExecutor for async command execution - Add REST API endpoints for comfy-cli: - Configuration management (/comfy-cli/config/*) - Model management (/comfy-cli/model/*) - Node management (/comfy-cli/node/*) - Create API handlers: ConfigHandler, ModelHandler, NodeHandler - Register routes in comfy_cli_routes.py - Update main __init__.py to support dual CLI (cm-cli + comfy-cli) - Add comprehensive documentation: - COMFY_CLI_API.md: Complete API reference - COMFY_CLI_QUICKSTART.md: Quick start guide - Update README.md with dual CLI support - Update AGENTS.md development guide - Add comfy-cli reference documentation in docs/references/ - Remove trailing spaces from all Python and Markdown files - Ensure all code passes syntax validation Features: - Async job tracking for long-running operations - Structured JSON responses - Comprehensive error handling - Direct filesystem access for model listing (more reliable) - Support for CivitAI and HuggingFace API tokens
1666 lines
40 KiB
Markdown
1666 lines
40 KiB
Markdown
# ComfyCLI 配置与使用指南
|
||
|
||
> 文档版本:1.5
|
||
> 最后更新:2026-03-17
|
||
> 适用环境:ComfyUI-Nvidia-Docker 部署
|
||
> **适配 comfy-cli 版本:≥1.3.8(已验证 1.6.0 稳定版)**
|
||
> **验证报告:** `comfy-cli-verification-report.md`
|
||
> **Docker 自动化脚本:** `comfy-cli-docker-setup.sh`
|
||
> **命令参考手册:** `comfy-cli-command-reference.md` — 所有 CLI 命令的参数和输出格式
|
||
> **表格解析指南:** `comfy-cli-table-parser.md` — box table → JSON/CSV 解析方案 ⭐新增
|
||
> **API Reference:** `comfy-cli-api-reference.md` — REST API 设计参考
|
||
> **REST 实现指南:** `comfy-cli-rest-implementation.md` — REST 服务器实现代码
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [概述](#1-概述)
|
||
2. [ComfyCLI 架构](#2-comfycli-架构)
|
||
3. [安装指南](#3-安装指南)
|
||
4. [配置系统详解](#4-配置系统详解)
|
||
5. [工作区管理](#5-工作区管理)
|
||
6. [模型管理](#6-模型管理)
|
||
7. [自定义节点管理](#7-自定义节点管理)
|
||
8. [ComfyUI 生命周期管理](#8-comfyui-生命周期管理)
|
||
9. [Docker 环境特殊配置](#9-docker-环境特殊配置)
|
||
10. [REST API 集成方案](#10-rest-api-集成方案)
|
||
11. [故障排除](#11-故障排除)
|
||
12. [附录](#12-附录)
|
||
|
||
---
|
||
|
||
## 1. 概述
|
||
|
||
### 1.1 什么是 ComfyCLI
|
||
|
||
`comfy-cli` 是由 Comfy-Org 官方维护的命令行工具,用于管理和操作 ComfyUI。与 ComfyUI-Manager 的 `cm-cli` 不同,comfy-cli 是一个**独立的管理工具**,提供:
|
||
|
||
- ✅ **模型下载与管理**(核心优势)
|
||
- ✅ 自定义节点管理
|
||
- ✅ ComfyUI 安装与更新
|
||
- ✅ 工作区管理
|
||
- ✅ Workflow 执行
|
||
- ✅ 后台服务管理
|
||
|
||
### 1.2 与 cm-cli 的对比
|
||
|
||
| 功能 | cm-cli | comfy-cli |
|
||
|------|--------|-----------|
|
||
| 模型下载 | ❌ | ✅ |
|
||
| 模型列表/删除 | ❌ | ✅ |
|
||
| 节点管理 | ✅ | ✅ |
|
||
| ComfyUI 安装 | ❌ | ✅ |
|
||
| 工作区管理 | ❌ | ✅ |
|
||
| REST API | ✅ (通过 custom node) | ❌ |
|
||
|
||
### 1.3 适用场景
|
||
|
||
- 需要通过命令行下载和管理模型
|
||
- 需要脚本化 ComfyUI 管理操作
|
||
- 需要多工作区管理
|
||
- 需要与现有 ComfyUI-Manager 共存
|
||
|
||
---
|
||
|
||
## 2. ComfyCLI 架构
|
||
|
||
### 2.1 核心组件
|
||
|
||
```
|
||
comfy-cli/
|
||
├── comfy_cli/
|
||
│ ├── __init__.py # 包初始化
|
||
│ ├── cmdline.py # 命令行入口和命令注册
|
||
│ ├── config_manager.py # 配置文件管理
|
||
│ ├── workspace_manager.py # 工作区管理
|
||
│ ├── constants.py # 常量定义
|
||
│ ├── command/
|
||
│ │ ├── install.py # 安装命令
|
||
│ │ ├── launch.py # 启动命令
|
||
│ │ ├── models/ # 模型管理命令
|
||
│ │ │ └── models.py # 下载/删除/列表
|
||
│ │ └── custom_nodes/ # 自定义节点命令
|
||
│ │ └── command.py # 节点管理实现
|
||
│ └── utils/ # 工具函数
|
||
└── pyproject.toml # 项目配置
|
||
```
|
||
|
||
### 2.2 配置文件系统
|
||
|
||
```
|
||
~/.config/comfy-cli/
|
||
└── config.ini # 主配置文件
|
||
```
|
||
|
||
**config.ini 结构:**
|
||
|
||
```ini
|
||
[DEFAULT]
|
||
default_workspace = /path/to/ComfyUI
|
||
recent_workspace = /path/to/last/used
|
||
default_launch_extras = --listen 0.0.0.0
|
||
enable_tracking = true
|
||
background = ('127.0.0.1', 8188, 12345)
|
||
civitai_api_token = xxx
|
||
hf_api_token = xxx
|
||
```
|
||
|
||
### 2.3 工作区检测机制
|
||
|
||
comfy-cli 通过 Git 仓库识别 ComfyUI 安装:
|
||
|
||
```python
|
||
COMFY_ORIGIN_URL_CHOICES = {
|
||
"git@github.com:comfyanonymous/ComfyUI.git",
|
||
"https://github.com/comfyanonymous/ComfyUI.git",
|
||
"https://github.com/Comfy-Org/ComfyUI.git",
|
||
# ...
|
||
}
|
||
```
|
||
|
||
**工作区优先级:**
|
||
|
||
1. `--workspace=<path>` - 显式指定
|
||
2. `--recent` - 最近使用
|
||
3. `--here` - 当前目录
|
||
4. 当前目录是 ComfyUI 仓库
|
||
5. `set-default` 设置的默认路径
|
||
6. 默认路径 (`~/comfy/ComfyUI`)
|
||
|
||
---
|
||
|
||
## 3. 安装指南
|
||
|
||
### 3.1 前置要求
|
||
|
||
- **Python 3.9+**(必须与 ComfyUI 使用相同环境)
|
||
- **Git**(用于仓库检测)
|
||
- **pip** 或 **uv**(推荐)
|
||
|
||
### 3.2 在 Docker 环境中安装
|
||
|
||
对于 ComfyUI-Nvidia-Docker 部署,有两种安装方式:
|
||
|
||
#### 方式 A:在容器内安装(推荐)
|
||
|
||
```bash
|
||
# 进入运行中的容器
|
||
docker exec -it comfyui-nvidia bash
|
||
|
||
# 激活虚拟环境(如果有)
|
||
source /comfy/mnt/venv/bin/activate
|
||
|
||
# 安装 comfy-cli
|
||
pip install comfy-cli
|
||
|
||
# 验证安装
|
||
comfy --version
|
||
```
|
||
|
||
#### 方式 B:使用 user_script.bash 持久化
|
||
|
||
编辑 `run/user_script.bash`:
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# user_script.bash - 在容器启动时执行
|
||
|
||
# 安装 comfy-cli
|
||
if ! command -v comfy &> /dev/null; then
|
||
echo "Installing comfy-cli..."
|
||
/comfy/mnt/venv/bin/pip install comfy-cli
|
||
fi
|
||
|
||
# 设置默认工作区
|
||
/comfy/mnt/venv/bin/comfy set-default /basedir 2>/dev/null || true
|
||
```
|
||
|
||
### 3.3 验证安装
|
||
|
||
```bash
|
||
# 检查版本
|
||
comfy --version
|
||
|
||
# 查看帮助
|
||
comfy --help
|
||
|
||
# 检查环境
|
||
comfy env
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 配置系统详解
|
||
|
||
### 4.1 配置文件位置
|
||
|
||
| 操作系统 | 配置文件路径 |
|
||
|----------|-------------|
|
||
| Linux | `~/.config/comfy-cli/config.ini` |
|
||
| macOS | `~/Library/Application Support/comfy-cli/config.ini` |
|
||
| Windows | `%LOCALAPPDATA%\comfy-cli\config.ini` |
|
||
|
||
### 4.2 配置项说明
|
||
|
||
```ini
|
||
[DEFAULT]
|
||
# 默认工作区路径(通过 comfy set-default 设置)
|
||
default_workspace = /basedir
|
||
|
||
# 最近使用的工作区(自动更新)
|
||
recent_workspace = /basedir
|
||
|
||
# 启动 ComfyUI 时的默认参数
|
||
default_launch_extras = --listen 0.0.0.0 --port 8188
|
||
|
||
# 是否启用使用追踪(可选)
|
||
enable_tracking = false
|
||
|
||
# 后台运行的 ComfyUI 信息 (host, port, pid)
|
||
# 自动管理,不要手动修改
|
||
background = ('127.0.0.1', 8188, 5678)
|
||
|
||
# CivitAI API Token(用于下载需要认证的模型)
|
||
civitai_api_token = your_token_here
|
||
|
||
# HuggingFace API Token(用于下载私有模型)
|
||
hf_api_token = your_token_here
|
||
```
|
||
|
||
### 4.3 配置管理命令
|
||
|
||
```bash
|
||
# 查看当前配置
|
||
comfy env
|
||
|
||
# 设置默认工作区
|
||
comfy set-default /basedir
|
||
|
||
# 设置启动参数
|
||
comfy set-default /basedir --launch-extras="--listen 0.0.0.0"
|
||
|
||
# 查看当前工作区
|
||
comfy which
|
||
```
|
||
|
||
### 4.4 环境变量覆盖
|
||
|
||
comfy-cli 支持通过环境变量覆盖配置:
|
||
|
||
| 环境变量 | 配置项 | 优先级 |
|
||
|----------|--------|--------|
|
||
| `CIVITAI_API_TOKEN` | civitai_api_token | 高 |
|
||
| `HF_API_TOKEN` | hf_api_token | 高 |
|
||
| `COMFY_CLI_WORKSPACE` | default_workspace | 高 |
|
||
|
||
**优先级顺序:**
|
||
|
||
1. CLI 参数(如 `--set-civitai-api-token`)
|
||
2. 环境变量
|
||
3. config.ini 配置
|
||
|
||
---
|
||
|
||
## 5. 工作区管理
|
||
|
||
### 5.1 工作区概念
|
||
|
||
工作区是 ComfyUI 的安装目录,包含:
|
||
|
||
```
|
||
/basedir/ # 工作区根目录
|
||
├── ComfyUI/ # ComfyUI 核心代码
|
||
├── custom_nodes/ # 自定义节点
|
||
├── models/ # 模型文件
|
||
│ ├── checkpoints/
|
||
│ ├── loras/
|
||
│ ├── vae/
|
||
│ └── ...
|
||
├── input/ # 输入文件
|
||
├── output/ # 输出文件
|
||
└── user/ # 用户文件
|
||
```
|
||
|
||
### 5.2 指定工作区的方法
|
||
|
||
#### 方法 1:使用 `--workspace` 参数
|
||
|
||
```bash
|
||
comfy --workspace=/basedir model download --url "..."
|
||
comfy --workspace=/basedir node install ComfyUI-Impact-Pack
|
||
```
|
||
|
||
#### 方法 2:设置默认工作区
|
||
|
||
```bash
|
||
# 一次性设置
|
||
comfy set-default /basedir
|
||
|
||
# 之后可省略 --workspace
|
||
comfy model download --url "..."
|
||
```
|
||
|
||
#### 方法 3:使用 `--recent`
|
||
|
||
```bash
|
||
# 自动使用最近的工作区
|
||
comfy --recent model download --url "..."
|
||
```
|
||
|
||
#### 方法 4:使用 `--here`
|
||
|
||
```bash
|
||
cd /basedir
|
||
comfy --here model download --url "..."
|
||
```
|
||
|
||
### 5.3 多工作区管理
|
||
|
||
```bash
|
||
# 设置多个工作区
|
||
comfy set-default /basedir
|
||
comfy --workspace=/opt/comfy-test node install SomeNode
|
||
|
||
# 查看当前工作区
|
||
comfy which
|
||
|
||
# 列出所有模型(在当前工作区)
|
||
comfy model list
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 模型管理
|
||
|
||
### 6.1 下载模型
|
||
|
||
#### 从 CivitAI 下载
|
||
|
||
```bash
|
||
# 下载模型(需要 API Token)
|
||
comfy --workspace=/basedir model download \
|
||
--url "https://civitai.com/models/43331" \
|
||
--set-civitai-api-token "YOUR_TOKEN"
|
||
|
||
# 指定保存路径
|
||
comfy --workspace=/basedir model download \
|
||
--url "https://civitai.com/models/43331" \
|
||
--relative-path "models/checkpoints" \
|
||
--filename "my_model.safetensors"
|
||
```
|
||
|
||
#### 从 HuggingFace 下载
|
||
|
||
```bash
|
||
# 下载公开模型
|
||
comfy --workspace=/basedir model download \
|
||
--url "https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/resolve/main/sd_xl_base_1.0.safetensors"
|
||
|
||
# 下载私有模型(需要 Token)
|
||
comfy --workspace=/basedir model download \
|
||
--url "https://huggingface.co/username/private-model/resolve/main/model.safetensors" \
|
||
--set-hf-api-token "YOUR_HF_TOKEN"
|
||
```
|
||
|
||
#### 从直接 URL 下载
|
||
|
||
```bash
|
||
comfy --workspace=/basedir model download \
|
||
--url "https://example.com/models/model.safetensors" \
|
||
--relative-path "models/checkpoints"
|
||
```
|
||
|
||
### 6.2 列出模型
|
||
|
||
```bash
|
||
# 列出所有模型
|
||
comfy --workspace=/basedir model list
|
||
|
||
# 列出指定目录的模型
|
||
comfy --workspace=/basedir model list \
|
||
--relative-path "models/checkpoints"
|
||
|
||
# 列出 LoRA 模型
|
||
comfy --workspace=/basedir model list \
|
||
--relative-path "models/loras"
|
||
```
|
||
|
||
### 6.3 删除模型
|
||
|
||
```bash
|
||
# 删除指定模型
|
||
comfy --workspace=/basedir model remove \
|
||
--relative-path "models/checkpoints" \
|
||
--model-names "model1.safetensors" "model2.ckpt"
|
||
|
||
# 交互式选择删除
|
||
comfy --workspace=/basedir model remove
|
||
|
||
# 跳过确认提示
|
||
comfy --workspace=/basedir model remove \
|
||
--model-names "model.safetensors" \
|
||
--confirm
|
||
```
|
||
|
||
### 6.4 模型路径映射
|
||
|
||
comfy-cli 内置的模型类型映射:
|
||
|
||
```python
|
||
model_path_map = {
|
||
"lora": "loras",
|
||
"hypernetwork": "hypernetworks",
|
||
"checkpoint": "checkpoints",
|
||
"textualinversion": "embeddings",
|
||
"controlnet": "controlnet",
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 自定义节点管理
|
||
|
||
### 7.1 节点列表
|
||
|
||
```bash
|
||
# 显示已安装的节点
|
||
comfy --workspace=/basedir node simple-show installed
|
||
|
||
# 显示启用的节点
|
||
comfy --workspace=/basedir node simple-show enabled
|
||
|
||
# 显示禁用的节点
|
||
comfy --workspace=/basedir node simple-show disabled
|
||
|
||
# 显示未安装的节点
|
||
comfy --workspace=/basedir node simple-show not-installed
|
||
|
||
# 显示所有节点
|
||
comfy --workspace=/basedir node simple-show all
|
||
|
||
# 显示详细信息
|
||
comfy --workspace=/basedir node show installed
|
||
```
|
||
|
||
### 7.2 安装节点
|
||
|
||
```bash
|
||
# 安装单个节点
|
||
comfy --workspace=/basedir node install ComfyUI-Impact-Pack
|
||
|
||
# 安装多个节点
|
||
comfy --workspace=/basedir node install ComfyUI-Impact-Pack ComfyUI-Inspire-Pack
|
||
|
||
# 使用快速依赖安装
|
||
comfy --workspace=/basedir node install SomeNode --fast-deps
|
||
|
||
# 跳过依赖安装
|
||
comfy --workspace=/basedir node install SomeNode --no-deps
|
||
|
||
# 指定 channel
|
||
comfy --workspace=/basedir node install SomeNode --channel recent
|
||
```
|
||
|
||
### 7.3 更新节点
|
||
|
||
```bash
|
||
# 更新所有节点
|
||
comfy --workspace=/basedir node update all
|
||
|
||
# 更新特定节点
|
||
comfy --workspace=/basedir node update ComfyUI-Impact-Pack
|
||
|
||
# 指定 channel 和 mode
|
||
comfy --workspace=/basedir node update all --channel recent --mode remote
|
||
```
|
||
|
||
### 7.4 启用/禁用节点
|
||
|
||
```bash
|
||
# 禁用节点
|
||
comfy --workspace=/basedir node disable ComfyUI-Impact-Pack
|
||
|
||
# 启用节点
|
||
comfy --workspace=/basedir node enable ComfyUI-Impact-Pack
|
||
```
|
||
|
||
### 7.5 卸载节点
|
||
|
||
```bash
|
||
# 卸载节点
|
||
comfy --workspace=/basedir node uninstall ComfyUI-Impact-Pack
|
||
```
|
||
|
||
### 7.6 依赖管理
|
||
|
||
```bash
|
||
# 安装依赖
|
||
comfy --workspace=/basedir node install-deps
|
||
|
||
# 从 workflow 生成依赖
|
||
comfy --workspace=/basedir node deps-in-workflow \
|
||
--workflow /path/to/workflow.json \
|
||
--output /path/to/deps.json
|
||
```
|
||
|
||
### 7.7 快照管理
|
||
|
||
```bash
|
||
# 保存快照
|
||
comfy --workspace=/basedir node save-snapshot
|
||
|
||
# 保存到指定文件
|
||
comfy --workspace=/basedir node save-snapshot --output backup.json
|
||
|
||
# 恢复快照
|
||
comfy --workspace=/basedir node restore-snapshot backup.json
|
||
|
||
# 列出快照
|
||
comfy --workspace=/basedir node simple-show snapshot-list
|
||
```
|
||
|
||
### 7.8 调试节点问题(Bisect)
|
||
|
||
```bash
|
||
# 开始 bisect 会话
|
||
comfy --workspace=/basedir node bisect start
|
||
|
||
# 标记当前状态为好
|
||
comfy --workspace=/basedir node bisect good
|
||
|
||
# 标记当前状态为坏
|
||
comfy --workspace=/basedir node bisect bad
|
||
|
||
# 重置 bisect 会话
|
||
comfy --workspace=/basedir node bisect reset
|
||
```
|
||
|
||
---
|
||
|
||
## 8. ComfyUI 生命周期管理
|
||
|
||
### 8.1 安装 ComfyUI
|
||
|
||
```bash
|
||
# 默认安装(最新 nightly 版本)
|
||
comfy install
|
||
|
||
# 指定工作区
|
||
comfy --workspace=~/my-comfy install
|
||
|
||
# 安装特定版本
|
||
comfy install --version latest
|
||
|
||
# 安装 nightly 版本
|
||
comfy install --version nightly
|
||
|
||
# 跳过 Manager 安装
|
||
comfy install --skip-manager
|
||
|
||
# 从特定 PR 安装
|
||
comfy install --pr "#1234"
|
||
|
||
# 指定 GPU 类型
|
||
comfy install --nvidia
|
||
comfy install --amd
|
||
comfy install --cpu
|
||
```
|
||
|
||
### 8.2 启动 ComfyUI
|
||
|
||
```bash
|
||
# 前台启动
|
||
comfy --workspace=/basedir launch
|
||
|
||
# 后台启动
|
||
comfy --workspace=/basedir launch --background
|
||
|
||
# 带参数启动
|
||
comfy --workspace=/basedir launch -- --listen 0.0.0.0 --port 8188
|
||
|
||
# 使用默认参数启动
|
||
comfy --workspace=/basedir launch --
|
||
|
||
# 测试前端 PR
|
||
comfy --workspace=/basedir launch --frontend-pr "#456"
|
||
```
|
||
|
||
### 8.3 停止 ComfyUI
|
||
|
||
```bash
|
||
# 停止后台运行的实例
|
||
comfy stop
|
||
```
|
||
|
||
### 8.4 更新 ComfyUI
|
||
|
||
```bash
|
||
# 更新 ComfyUI 核心
|
||
comfy --workspace=/basedir update comfy
|
||
|
||
# 更新所有(包括节点)
|
||
comfy --workspace=/basedir update all
|
||
```
|
||
|
||
### 8.5 运行 Workflow
|
||
|
||
```bash
|
||
# 运行 workflow 文件
|
||
comfy --workspace=/basedir run \
|
||
--workflow /path/to/workflow.json
|
||
|
||
# 等待完成
|
||
comfy --workspace=/basedir run \
|
||
--workflow /path/to/workflow.json \
|
||
--wait
|
||
|
||
# 详细输出
|
||
comfy --workspace=/basedir run \
|
||
--workflow /path/to/workflow.json \
|
||
--verbose
|
||
|
||
# 指定主机和端口
|
||
comfy --workspace=/basedir run \
|
||
--workflow /path/to/workflow.json \
|
||
--host 127.0.0.1 \
|
||
--port 8188 \
|
||
--timeout 60
|
||
```
|
||
|
||
---
|
||
|
||
## 9. Docker 环境特殊配置
|
||
|
||
### 9.1 ComfyUI-Nvidia-Docker 目录结构
|
||
|
||
```
|
||
run/ # 容器运行数据
|
||
├── venv/ # Python 虚拟环境
|
||
├── ComfyUI/ # ComfyUI 源代码
|
||
└── ...
|
||
|
||
basedir/ # 用户数据(持久化)
|
||
├── custom_nodes/ # 自定义节点
|
||
├── models/ # 模型文件
|
||
├── input/ # 输入
|
||
├── output/ # 输出
|
||
└── user/ # 用户配置
|
||
```
|
||
|
||
### 9.2 在 Docker 中安装 comfy-cli
|
||
|
||
#### 方法 A:通过 user_script.bash(推荐)
|
||
|
||
**⚠️ 重要提示**:在 Docker 环境中,`comfy set-default` 会失败,因为 comfy-cli 通过 Git 仓库检测验证 ComfyUI 安装,而 `/basedir` 目录下没有 ComfyUI 的 Git 仓库(代码在 `/comfy/mnt/ComfyUI`)。
|
||
|
||
**解决方案**:直接写入 `config.ini` 配置文件,绕过 Git 检测。
|
||
|
||
##### 方案 A1:使用自动化脚本(推荐)
|
||
|
||
我们提供了完整的自动化脚本 `docs/comfy-cli-docker-setup.sh`,包含:
|
||
|
||
- ✅ 自动检测并安装 comfy-cli
|
||
- ✅ 直接配置 config.ini(绕过 Git 检测)
|
||
- ✅ 环境变量支持(CivitAI/HF API Token)
|
||
- ✅ 配置验证
|
||
|
||
**使用步骤:**
|
||
|
||
```bash
|
||
# 1. 复制脚本到 run 目录
|
||
cp docs/comfy-cli-docker-setup.sh run/user_script.bash
|
||
|
||
# 2. 确保执行权限
|
||
chmod +x run/user_script.bash
|
||
|
||
# 3. 重启容器
|
||
docker restart comfyui-nvidia
|
||
|
||
# 4. 查看日志确认配置成功
|
||
docker logs comfyui-nvidia | grep -A 20 "ComfyCLI"
|
||
```
|
||
|
||
##### 方案 A2:手动编写 user_script.bash
|
||
|
||
创建/编辑 `run/user_script.bash`:
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# user_script.bash - 容器启动时执行
|
||
|
||
echo "=== Setting up comfy-cli ==="
|
||
|
||
# 配置变量
|
||
VENV_PIP="/comfy/mnt/venv/bin/pip"
|
||
COMFY_CMD="/comfy/mnt/venv/bin/comfy"
|
||
CONFIG_DIR="$HOME/.config/comfy-cli"
|
||
CONFIG_FILE="$CONFIG_DIR/config.ini"
|
||
|
||
# 检查并安装 comfy-cli
|
||
if ! $COMFY_CMD --version &> /dev/null; then
|
||
echo "Installing comfy-cli..."
|
||
$VENV_PIP install comfy-cli -q
|
||
fi
|
||
|
||
# 创建配置目录
|
||
mkdir -p "$CONFIG_DIR"
|
||
|
||
# 直接写入 config.ini(绕过 set-default 的 Git 检测)
|
||
cat > "$CONFIG_FILE" << EOF
|
||
[DEFAULT]
|
||
default_workspace = /basedir
|
||
recent_workspace = /basedir
|
||
default_launch_extras = --listen 0.0.0.0 --port 8188
|
||
enable_tracking = false
|
||
EOF
|
||
|
||
echo "Config file written to $CONFIG_FILE"
|
||
|
||
# 验证配置
|
||
$COMFY_CMD which
|
||
```
|
||
|
||
##### 为什么不能直接用 `comfy set-default`?
|
||
|
||
comfy-cli 的 `set-default` 命令会验证路径是否为有效的 ComfyUI Git 仓库:
|
||
|
||
```python
|
||
# comfy_cli/workspace_manager.py
|
||
def _is_comfy_repo(path: Path) -> bool:
|
||
"""检查是否为 ComfyUI 仓库"""
|
||
git_dir = path / ".git"
|
||
if not git_dir.exists():
|
||
return False
|
||
# 检查 remote URLs 是否匹配 ComfyUI 官方仓库
|
||
...
|
||
```
|
||
|
||
在 Docker 环境中:
|
||
- `/comfy/mnt/ComfyUI` 是 ComfyUI 代码(可能有 Git)
|
||
- `/basedir` 是用户数据目录(没有 Git)
|
||
- `set-default /basedir` 会失败:`Specified path is not a ComfyUI path`
|
||
|
||
**直接写入 config.ini 是安全的**,因为:
|
||
1. comfy-cli 读取配置时不验证 Git
|
||
2. 模型/节点管理只关心子目录结构(`models/`, `custom_nodes/`)
|
||
3. ComfyUI 启动时会正确加载模型路径
|
||
|
||
#### 方法 B:手动安装(不推荐)
|
||
|
||
```bash
|
||
# 进入容器
|
||
docker exec -it comfyui-nvidia bash
|
||
|
||
# 激活虚拟环境
|
||
source /comfy/mnt/venv/bin/activate
|
||
|
||
# 安装 comfy-cli
|
||
pip install comfy-cli
|
||
|
||
# ❌ 这会失败:Specified path is not a ComfyUI path
|
||
comfy set-default /basedir
|
||
|
||
# ✅ 改为直接编辑配置文件
|
||
mkdir -p ~/.config/comfy-cli
|
||
cat > ~/.config/comfy-cli/config.ini << EOF
|
||
[DEFAULT]
|
||
default_workspace = /basedir
|
||
recent_workspace = /basedir
|
||
enable_tracking = false
|
||
EOF
|
||
|
||
# 验证
|
||
comfy which
|
||
|
||
# 退出容器
|
||
exit
|
||
```
|
||
|
||
### 9.3 环境变量配置
|
||
|
||
在 `docker-compose.yml` 或 `docker run` 中添加:
|
||
|
||
```yaml
|
||
environment:
|
||
- CIVITAI_API_TOKEN=your_token_here
|
||
- HF_API_TOKEN=your_token_here
|
||
- COMFY_CLI_WORKSPACE=/basedir
|
||
```
|
||
|
||
### 9.4 权限问题处理
|
||
|
||
ComfyUI-Nvidia-Docker 使用 `WANTED_UID`/`WANTED_GID` 映射用户权限:
|
||
|
||
```bash
|
||
docker run ... \
|
||
-e WANTED_UID=$(id -u) \
|
||
-e WANTED_GID=$(id -g) \
|
||
...
|
||
```
|
||
|
||
确保 comfy-cli 配置文件的权限正确:
|
||
|
||
```bash
|
||
# 在容器内
|
||
chown -R $(id -u):$(id -g) ~/.config/comfy-cli/
|
||
```
|
||
|
||
### 9.5 模型下载优化
|
||
|
||
在 Docker 环境中,模型下载到 `basedir`,这是持久化存储:
|
||
|
||
```bash
|
||
# 模型会保存到 /basedir/models/...
|
||
docker exec comfyui-nvidia comfy model download \
|
||
--url "https://..." \
|
||
--relative-path "models/checkpoints"
|
||
```
|
||
|
||
---
|
||
|
||
## 10. REST API 集成方案
|
||
|
||
### 10.1 方案概述
|
||
|
||
由于 comfy-cli 本身不提供 REST API,需要通过 custom node 将命令暴露为 HTTP 端点。
|
||
|
||
**📚 相关文档:**
|
||
- **API Reference:** `comfy-cli-api-reference.md` — 所有命令的输入输出格式详解
|
||
- **实现指南:** `comfy-cli-rest-implementation.md` — 完整的 REST API 服务器实现代码
|
||
|
||
有两种实现方案:
|
||
|
||
| 方案 | 优点 | 缺点 |
|
||
|------|------|------|
|
||
| **方案 A:扩展现有 cm-cli-rest** | 复用现有代码 | 需要修改现有项目 |
|
||
| **方案 B:新建 comfy-cli-rest** | 独立、清晰 | 需要从头开发 |
|
||
|
||
**推荐:方案 A**(扩展 cm-cli-rest)
|
||
|
||
### 10.1.1 为什么需要 REST API?
|
||
|
||
直接调用 CLI 的问题:
|
||
|
||
| 问题 | CLI 直接调用 | REST API |
|
||
|------|-------------|----------|
|
||
| 输出格式 | 原始文本,需解析 | 结构化 JSON |
|
||
| 异步任务 | 需手动管理进程 | 统一任务队列 |
|
||
| 错误处理 | 退出码 + stderr | 统一错误响应 |
|
||
| 认证授权 | 无 | 可集成 |
|
||
| 并发控制 | 无 | 可限制 |
|
||
|
||
### 10.1.2 输出解析策略
|
||
|
||
| 命令类型 | 原始输出 | 建议解析方式 |
|
||
|----------|----------|-------------|
|
||
| `model list` | 每行一个文件名 | 按行分割 → 数组 |
|
||
| `node simple-show` | 每行一个节点名 | 按行分割 → 数组 |
|
||
| `model download` | 进度 + 完成消息 | 正则提取进度% |
|
||
| `env` | 键值对列表 | 分割 `:` → 对象 |
|
||
| `node show` | 多行详细信息 | 复杂解析或改用文件系统 |
|
||
|
||
**推荐:对于简单查询(list),直接文件系统访问比 CLI 更可靠。**
|
||
|
||
### 10.2 方案 A:扩展 cm-cli-rest
|
||
|
||
#### 10.2.1 项目结构
|
||
|
||
```
|
||
cm-cli-rest/
|
||
├── __init__.py # 入口点
|
||
├── api/
|
||
│ ├── routes.py # 路由定义
|
||
│ └── handlers/
|
||
│ ├── nodes.py # 节点管理
|
||
│ ├── models.py # 【新增】模型管理
|
||
│ └── jobs.py # 任务跟踪
|
||
├── comfy_cli/
|
||
│ └── executor.py # 【新增】comfy-cli 执行器
|
||
├── config/
|
||
│ └── config.json # 配置
|
||
└── README.md
|
||
```
|
||
|
||
#### 10.2.2 comfy-cli 执行器实现
|
||
|
||
```python
|
||
# comfy_cli/executor.py
|
||
import asyncio
|
||
import json
|
||
import os
|
||
import subprocess
|
||
import uuid
|
||
from typing import Dict, Optional, Any
|
||
|
||
class ComfyCliExecutor:
|
||
"""comfy-cli 命令执行器"""
|
||
|
||
def __init__(self, workspace_path: str = "/basedir"):
|
||
self.workspace_path = workspace_path
|
||
self.comfy_cmd = ["comfy", f"--workspace={workspace_path}"]
|
||
self.jobs: Dict[str, Dict] = {}
|
||
|
||
async def execute(
|
||
self,
|
||
command: list,
|
||
async_mode: bool = True
|
||
) -> Dict[str, Any]:
|
||
"""执行 comfy-cli 命令"""
|
||
job_id = str(uuid.uuid4())
|
||
|
||
full_cmd = self.comfy_cmd + command
|
||
|
||
if async_mode:
|
||
# 异步执行(用于长时间运行的命令)
|
||
task = asyncio.create_task(
|
||
self._run_async(job_id, full_cmd)
|
||
)
|
||
self.jobs[job_id] = {
|
||
"status": "running",
|
||
"command": command,
|
||
"task": task
|
||
}
|
||
return {
|
||
"job_id": job_id,
|
||
"status": "running",
|
||
"message": f"Command started: {' '.join(command)}"
|
||
}
|
||
else:
|
||
# 同步执行
|
||
result = await self._run_sync(full_cmd)
|
||
return result
|
||
|
||
async def _run_async(self, job_id: str, cmd: list):
|
||
"""异步运行命令"""
|
||
try:
|
||
process = await asyncio.create_subprocess_exec(
|
||
*cmd,
|
||
stdout=asyncio.subprocess.PIPE,
|
||
stderr=asyncio.subprocess.PIPE,
|
||
cwd=self.workspace_path
|
||
)
|
||
|
||
stdout, stderr = await process.communicate()
|
||
|
||
if process.returncode == 0:
|
||
self.jobs[job_id] = {
|
||
"status": "completed",
|
||
"output": stdout.decode(),
|
||
"error": stderr.decode()
|
||
}
|
||
else:
|
||
self.jobs[job_id] = {
|
||
"status": "failed",
|
||
"error": stderr.decode(),
|
||
"output": stdout.decode()
|
||
}
|
||
except Exception as e:
|
||
self.jobs[job_id] = {
|
||
"status": "failed",
|
||
"error": str(e)
|
||
}
|
||
|
||
async def _run_sync(self, cmd: list) -> Dict[str, Any]:
|
||
"""同步运行命令"""
|
||
try:
|
||
process = await asyncio.create_subprocess_exec(
|
||
*cmd,
|
||
stdout=asyncio.subprocess.PIPE,
|
||
stderr=asyncio.subprocess.PIPE,
|
||
cwd=self.workspace_path
|
||
)
|
||
|
||
stdout, stderr = await process.communicate()
|
||
|
||
if process.returncode == 0:
|
||
return {
|
||
"success": True,
|
||
"data": stdout.decode(),
|
||
"error": None
|
||
}
|
||
else:
|
||
return {
|
||
"success": False,
|
||
"data": None,
|
||
"error": stderr.decode()
|
||
}
|
||
except Exception as e:
|
||
return {
|
||
"success": False,
|
||
"data": None,
|
||
"error": str(e)
|
||
}
|
||
|
||
def get_job_status(self, job_id: str) -> Optional[Dict]:
|
||
"""获取任务状态"""
|
||
return self.jobs.get(job_id)
|
||
|
||
def remove_job(self, job_id: str) -> bool:
|
||
"""移除任务"""
|
||
if job_id in self.jobs:
|
||
del self.jobs[job_id]
|
||
return True
|
||
return False
|
||
```
|
||
|
||
#### 10.2.3 模型管理 Handler
|
||
|
||
```python
|
||
# api/handlers/models.py
|
||
from aiohttp import web
|
||
import json
|
||
from ..comfy_cli.executor import ComfyCliExecutor
|
||
|
||
executor = ComfyCliExecutor(workspace_path="/basedir")
|
||
|
||
async def download_model(request):
|
||
"""下载模型"""
|
||
try:
|
||
data = await request.json()
|
||
url = data.get("url")
|
||
relative_path = data.get("relative_path", "models/checkpoints")
|
||
filename = data.get("filename")
|
||
civitai_token = data.get("civitai_api_token")
|
||
hf_token = data.get("hf_api_token")
|
||
|
||
if not url:
|
||
return web.json_response({
|
||
"success": False,
|
||
"error": {"code": "MISSING_URL", "message": "URL is required"}
|
||
}, status=400)
|
||
|
||
# 构建命令
|
||
cmd = ["model", "download", "--url", url]
|
||
|
||
if relative_path:
|
||
cmd.extend(["--relative-path", relative_path])
|
||
|
||
if filename:
|
||
cmd.extend(["--filename", filename])
|
||
|
||
if civitai_token:
|
||
cmd.extend(["--set-civitai-api-token", civitai_token])
|
||
|
||
if hf_token:
|
||
cmd.extend(["--set-hf-api-token", hf_token])
|
||
|
||
# 执行命令(异步)
|
||
result = await executor.execute(cmd, async_mode=True)
|
||
|
||
return web.json_response({
|
||
"success": True,
|
||
"data": result
|
||
}, status=202) # 202 Accepted
|
||
|
||
except json.JSONDecodeError:
|
||
return web.json_response({
|
||
"success": False,
|
||
"error": {"code": "INVALID_JSON", "message": "Invalid JSON"}
|
||
}, status=400)
|
||
except Exception as e:
|
||
return web.json_response({
|
||
"success": False,
|
||
"error": {"code": "INTERNAL_ERROR", "message": str(e)}
|
||
}, status=500)
|
||
|
||
async def list_models(request):
|
||
"""列出模型"""
|
||
try:
|
||
relative_path = request.query.get("relative_path", "models")
|
||
|
||
cmd = ["model", "list"]
|
||
if relative_path:
|
||
cmd.extend(["--relative-path", relative_path])
|
||
|
||
result = await executor.execute(cmd, async_mode=False)
|
||
|
||
if result["success"]:
|
||
# 解析输出
|
||
models = result["data"].strip().split("\n") if result["data"] else []
|
||
return web.json_response({
|
||
"success": True,
|
||
"data": {"models": models, "path": relative_path}
|
||
})
|
||
else:
|
||
return web.json_response({
|
||
"success": False,
|
||
"error": {"code": "LIST_FAILED", "message": result["error"]}
|
||
}, status=500)
|
||
|
||
except Exception as e:
|
||
return web.json_response({
|
||
"success": False,
|
||
"error": {"code": "INTERNAL_ERROR", "message": str(e)}
|
||
}, status=500)
|
||
|
||
async def remove_model(request):
|
||
"""删除模型"""
|
||
try:
|
||
data = await request.json()
|
||
model_names = data.get("model_names", [])
|
||
relative_path = data.get("relative_path", "models/checkpoints")
|
||
confirm = data.get("confirm", False)
|
||
|
||
if not model_names:
|
||
return web.json_response({
|
||
"success": False,
|
||
"error": {"code": "MISSING_NAMES", "message": "model_names is required"}
|
||
}, status=400)
|
||
|
||
cmd = ["model", "remove", "--relative-path", relative_path]
|
||
|
||
for name in model_names:
|
||
cmd.extend(["--model-names", name])
|
||
|
||
if confirm:
|
||
cmd.append("--confirm")
|
||
|
||
result = await executor.execute(cmd, async_mode=False)
|
||
|
||
if result["success"]:
|
||
return web.json_response({
|
||
"success": True,
|
||
"data": {"message": f"Removed {len(model_names)} model(s)"}
|
||
})
|
||
else:
|
||
return web.json_response({
|
||
"success": False,
|
||
"error": {"code": "REMOVE_FAILED", "message": result["error"]}
|
||
}, status=500)
|
||
|
||
except Exception as e:
|
||
return web.json_response({
|
||
"success": False,
|
||
"error": {"code": "INTERNAL_ERROR", "message": str(e)}
|
||
}, status=500)
|
||
|
||
async def get_job_status(request):
|
||
"""获取任务状态"""
|
||
job_id = request.match_info.get("job_id")
|
||
|
||
status = executor.get_job_status(job_id)
|
||
|
||
if status:
|
||
return web.json_response({
|
||
"success": True,
|
||
"data": status
|
||
})
|
||
else:
|
||
return web.json_response({
|
||
"success": False,
|
||
"error": {"code": "JOB_NOT_FOUND", "message": f"Job {job_id} not found"}
|
||
}, status=404)
|
||
|
||
async def remove_job(request):
|
||
"""移除任务"""
|
||
job_id = request.match_info.get("job_id")
|
||
|
||
if executor.remove_job(job_id):
|
||
return web.json_response({
|
||
"success": True,
|
||
"data": {"message": f"Job {job_id} removed"}
|
||
})
|
||
else:
|
||
return web.json_response({
|
||
"success": False,
|
||
"error": {"code": "JOB_NOT_FOUND", "message": f"Job {job_id} not found"}
|
||
}, status=404)
|
||
```
|
||
|
||
#### 10.2.4 路由定义
|
||
|
||
```python
|
||
# api/routes.py
|
||
from aiohttp import web
|
||
from .handlers import nodes, models, jobs
|
||
|
||
def setup_routes(app):
|
||
"""注册路由"""
|
||
|
||
# 健康检查
|
||
app.router.add_get("/cm-cli-rest/health", health_check)
|
||
|
||
# 节点管理(现有)
|
||
app.router.add_get("/cm-cli-rest/nodes", nodes.list_nodes)
|
||
app.router.add_post("/cm-cli-rest/nodes/install", nodes.install_node)
|
||
# ...
|
||
|
||
# 模型管理(新增)
|
||
app.router.add_post("/cm-cli-rest/models/download", models.download_model)
|
||
app.router.add_get("/cm-cli-rest/models", models.list_models)
|
||
app.router.add_post("/cm-cli-rest/models/remove", models.remove_model)
|
||
|
||
# 任务跟踪
|
||
app.router.add_get("/cm-cli-rest/jobs", jobs.list_jobs)
|
||
app.router.add_get("/cm-cli-rest/jobs/{job_id}", models.get_job_status)
|
||
app.router.add_delete("/cm-cli-rest/jobs/{job_id}", models.remove_job)
|
||
|
||
async def health_check(request):
|
||
"""健康检查"""
|
||
return web.json_response({
|
||
"status": "healthy",
|
||
"service": "cm-cli-rest",
|
||
"version": "0.2.0", # 更新版本号
|
||
"features": ["nodes", "models", "jobs"],
|
||
"timestamp": datetime.utcnow().isoformat()
|
||
})
|
||
```
|
||
|
||
#### 10.2.5 API 端点列表
|
||
|
||
| 方法 | 端点 | 描述 | 异步 |
|
||
|------|------|------|------|
|
||
| GET | `/cm-cli-rest/health` | 健康检查 | ❌ |
|
||
| POST | `/cm-cli-rest/models/download` | 下载模型 | ✅ |
|
||
| GET | `/cm-cli-rest/models` | 列出模型 | ❌ |
|
||
| POST | `/cm-cli-rest/models/remove` | 删除模型 | ❌ |
|
||
| GET | `/cm-cli-rest/jobs` | 列出任务 | ❌ |
|
||
| GET | `/cm-cli-rest/jobs/{id}` | 获取任务状态 | ❌ |
|
||
| DELETE | `/cm-cli-rest/jobs/{id}` | 移除任务 | ❌ |
|
||
|
||
#### 10.2.6 请求/响应示例
|
||
|
||
**下载模型请求:**
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8188/cm-cli-rest/models/download \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"url": "https://civitai.com/models/43331",
|
||
"relative_path": "models/checkpoints",
|
||
"filename": "my_model.safetensors",
|
||
"civitai_api_token": "your_token"
|
||
}'
|
||
```
|
||
|
||
**响应(202 Accepted):**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"job_id": "abc12345",
|
||
"status": "running",
|
||
"message": "Command started: model download --url ..."
|
||
}
|
||
}
|
||
```
|
||
|
||
**查询任务状态:**
|
||
|
||
```bash
|
||
curl http://localhost:8188/cm-cli-rest/jobs/abc12345
|
||
```
|
||
|
||
**响应:**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"status": "completed",
|
||
"output": "Model downloaded successfully...",
|
||
"error": null
|
||
}
|
||
}
|
||
```
|
||
|
||
**列出模型:**
|
||
|
||
```bash
|
||
curl "http://localhost:8188/cm-cli-rest/models?relative_path=models/checkpoints"
|
||
```
|
||
|
||
**响应:**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"models": [
|
||
"model1.safetensors",
|
||
"model2.ckpt",
|
||
"model3.safetensors"
|
||
],
|
||
"path": "models/checkpoints"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 10.3 方案 B:新建 comfy-cli-rest
|
||
|
||
如果希望保持独立,可以创建新的 custom node:
|
||
|
||
```bash
|
||
# 目录结构
|
||
custom_nodes/comfy-cli-rest/
|
||
├── __init__.py
|
||
├── server.py
|
||
├── handlers/
|
||
│ ├── models.py
|
||
│ ├── nodes.py
|
||
│ └── workflows.py
|
||
├── comfy_executor.py
|
||
├── config.json
|
||
└── requirements.txt
|
||
```
|
||
|
||
**requirements.txt:**
|
||
|
||
```
|
||
aiohttp>=3.9.0
|
||
```
|
||
|
||
**__init__.py:**
|
||
|
||
```python
|
||
import asyncio
|
||
import os
|
||
from aiohttp import web
|
||
from server import PromptServer
|
||
|
||
from .handlers import models, nodes
|
||
from .comfy_executor import ComfyCliExecutor
|
||
|
||
WEB_DIRECTORY = "./web"
|
||
|
||
executor = ComfyCliExecutor(
|
||
workspace_path=os.environ.get("COMFYUI_BASEDIR", "/basedir")
|
||
)
|
||
|
||
@PromptServer.instance.routes.get("/comfy-cli/health")
|
||
async def health_check(request):
|
||
return web.json_response({
|
||
"status": "healthy",
|
||
"service": "comfy-cli-rest",
|
||
"version": "1.0.0"
|
||
})
|
||
|
||
@PromptServer.instance.routes.post("/comfy-cli/model/download")
|
||
async def download_model(request):
|
||
return await models.download_model(request, executor)
|
||
|
||
@PromptServer.instance.routes.get("/comfy-cli/model/list")
|
||
async def list_models(request):
|
||
return await models.list_models(request, executor)
|
||
|
||
# ... 其他路由
|
||
```
|
||
|
||
### 10.4 安全考虑
|
||
|
||
1. **API 认证**
|
||
```json
|
||
{
|
||
"api_key": "your_secret_key",
|
||
"enabled": true
|
||
}
|
||
```
|
||
|
||
2. **输入验证**
|
||
- 验证所有路径参数,防止路径遍历攻击
|
||
- 限制可执行的命令白名单
|
||
|
||
3. **速率限制**
|
||
- 限制每个 IP 的请求频率
|
||
- 限制并发任务数量
|
||
|
||
4. **日志记录**
|
||
- 记录所有 API 调用
|
||
- 记录错误和异常
|
||
|
||
---
|
||
|
||
## 11. 故障排除
|
||
|
||
### 11.1 常见问题
|
||
|
||
#### 问题 1:`comfy: command not found`
|
||
|
||
**原因:** comfy-cli 未安装或未添加到 PATH
|
||
|
||
**解决:**
|
||
|
||
```bash
|
||
# 在容器内
|
||
source /comfy/mnt/venv/bin/activate
|
||
pip install comfy-cli
|
||
|
||
# 或使用完整路径
|
||
/comfy/mnt/venv/bin/comfy --version
|
||
```
|
||
|
||
#### 问题 2:`ComfyUI not found` 或 `Specified path is not a ComfyUI path`
|
||
|
||
**原因:** 工作区配置错误,或在 Docker 环境中使用 `set-default` 命令
|
||
|
||
**解决:**
|
||
|
||
**Docker 环境特殊情况:**
|
||
|
||
`comfy set-default /basedir` 会失败,因为 comfy-cli 通过 Git 仓库检测验证路径,而 `/basedir` 是数据目录而非 Git 仓库。
|
||
|
||
```bash
|
||
# ❌ 这会失败
|
||
comfy set-default /basedir
|
||
# 错误:Specified path is not a ComfyUI path: /basedir
|
||
|
||
# ✅ 方案 A:使用自动化脚本(推荐)
|
||
# 将 docs/comfy-cli-docker-setup.sh 复制为 run/user_script.bash 并重启容器
|
||
|
||
# ✅ 方案 B:直接编辑配置文件
|
||
mkdir -p ~/.config/comfy-cli
|
||
cat > ~/.config/comfy-cli/config.ini << EOF
|
||
[DEFAULT]
|
||
default_workspace = /basedir
|
||
recent_workspace = /basedir
|
||
enable_tracking = false
|
||
EOF
|
||
|
||
# ✅ 方案 C:每次使用 --workspace 参数
|
||
comfy --workspace=/basedir model list
|
||
```
|
||
|
||
**非 Docker 环境:**
|
||
|
||
```bash
|
||
# 设置默认工作区
|
||
comfy set-default /path/to/ComfyUI
|
||
|
||
# 或显式指定
|
||
comfy --workspace=/basedir model list
|
||
```
|
||
|
||
#### 问题 3:模型下载失败(401/403)
|
||
|
||
**原因:** 缺少 API Token
|
||
|
||
**解决:**
|
||
|
||
```bash
|
||
# 设置 Token
|
||
comfy model download --url "..." \
|
||
--set-civitai-api-token "YOUR_TOKEN"
|
||
|
||
# 或使用环境变量
|
||
export CIVITAI_API_TOKEN="YOUR_TOKEN"
|
||
comfy model download --url "..."
|
||
```
|
||
|
||
#### 问题 4:权限错误
|
||
|
||
**原因:** Docker 用户权限映射问题
|
||
|
||
**解决:**
|
||
|
||
```bash
|
||
# 在容器内修复权限
|
||
chown -R $(id -u):$(id -g) ~/.config/comfy-cli/
|
||
chown -R $(id -u):$(id -g) /basedir/
|
||
```
|
||
|
||
#### 问题 5:Python 版本不兼容
|
||
|
||
**原因:** comfy-cli 需要 Python 3.9+
|
||
|
||
**解决:**
|
||
|
||
```bash
|
||
# 检查 Python 版本
|
||
python --version
|
||
|
||
# 使用正确的 Python 环境
|
||
/comfy/mnt/venv/bin/python -m pip install comfy-cli
|
||
```
|
||
|
||
### 11.2 调试技巧
|
||
|
||
```bash
|
||
# 启用详细日志
|
||
comfy --workspace=/basedir model download --url "..." -v
|
||
|
||
# 查看 comfy-cli 配置
|
||
cat ~/.config/comfy-cli/config.ini
|
||
|
||
# 检查环境
|
||
comfy env
|
||
|
||
# 验证工作区
|
||
comfy which
|
||
```
|
||
|
||
### 11.3 获取帮助
|
||
|
||
```bash
|
||
# 主帮助
|
||
comfy --help
|
||
|
||
# 命令帮助
|
||
comfy model --help
|
||
comfy model download --help
|
||
comfy node --help
|
||
|
||
# 查看源码
|
||
# https://github.com/Comfy-Org/comfy-cli
|
||
```
|
||
|
||
---
|
||
|
||
## 12. 附录
|
||
|
||
### 12.1 完整命令参考
|
||
|
||
```
|
||
comfy [OPTIONS] COMMAND [ARGS]
|
||
|
||
Options:
|
||
--workspace PATH Path to ComfyUI workspace
|
||
--recent Execute from recent path
|
||
--here Execute from current path
|
||
--version Print version and exit
|
||
--help Show help
|
||
|
||
Commands:
|
||
install Download and install ComfyUI
|
||
update Update ComfyUI environment
|
||
launch Launch ComfyUI
|
||
stop Stop background ComfyUI
|
||
set-default Set default ComfyUI path
|
||
which Show which ComfyUI is selected
|
||
env Print environment variables
|
||
model Model management
|
||
download Download model file
|
||
list List models
|
||
remove Remove models
|
||
node Custom node management
|
||
install Install nodes
|
||
uninstall Uninstall nodes
|
||
update Update nodes
|
||
enable Enable nodes
|
||
disable Disable nodes
|
||
show Show node list
|
||
simple-show Show node list (simple)
|
||
save-snapshot Save snapshot
|
||
restore-snapshot Restore snapshot
|
||
run Run workflow
|
||
feedback Provide feedback
|
||
```
|
||
|
||
### 12.2 配置文件模板
|
||
|
||
```ini
|
||
# ~/.config/comfy-cli/config.ini
|
||
[DEFAULT]
|
||
default_workspace = /basedir
|
||
recent_workspace = /basedir
|
||
default_launch_extras = --listen 0.0.0.0 --port 8188
|
||
enable_tracking = false
|
||
civitai_api_token =
|
||
hf_api_token =
|
||
```
|
||
|
||
### 12.3 Docker Compose 示例
|
||
|
||
```yaml
|
||
version: '3.8'
|
||
|
||
services:
|
||
comfyui:
|
||
image: mmartial/comfyui-nvidia-docker:latest
|
||
container_name: comfyui-nvidia
|
||
runtime: nvidia
|
||
environment:
|
||
- USE_UV=true
|
||
- WANTED_UID=1000
|
||
- WANTED_GID=1000
|
||
- BASE_DIRECTORY=/basedir
|
||
- SECURITY_LEVEL=normal
|
||
- CIVITAI_API_TOKEN=${CIVITAI_API_TOKEN}
|
||
- HF_API_TOKEN=${HF_API_TOKEN}
|
||
volumes:
|
||
- ./run:/comfy/mnt
|
||
- ./basedir:/basedir
|
||
ports:
|
||
- "127.0.0.1:8188:8188"
|
||
deploy:
|
||
resources:
|
||
reservations:
|
||
devices:
|
||
- driver: nvidia
|
||
count: all
|
||
capabilities: [gpu]
|
||
```
|
||
|
||
### 12.4 参考资源
|
||
|
||
- **comfy-cli 官方仓库:** https://github.com/Comfy-Org/comfy-cli
|
||
- **comfy-cli PyPI:** https://pypi.org/project/comfy-cli/
|
||
- **ComfyUI-Nvidia-Docker:** https://github.com/mmartial/ComfyUI-Nvidia-Docker
|
||
- **ComfyUI-Manager:** https://github.com/ltdrdata/ComfyUI-Manager
|
||
- **cm-cli-rest:** https://github.com/fno2010/cm-cli-rest
|
||
|
||
---
|
||
|
||
## 修订历史
|
||
|
||
| 版本 | 日期 | 作者 | 变更 |
|
||
|------|------|------|------|
|
||
| 1.5 | 2026-03-17 | Zero | 添加表格解析指南 `comfy-cli-table-parser.md`,修正输出格式说明(box table) |
|
||
| 1.4 | 2026-03-16 | Zero | 添加 CLI 命令参考手册 `comfy-cli-command-reference.md` |
|
||
| 1.3 | 2026-03-16 | Zero | 添加 API Reference 和 REST 实现指南文档链接、输出解析策略说明 |
|
||
| 1.2 | 2026-03-16 | Zero | 添加 Docker 环境 `set-default` 失败解决方案、自动化脚本 `comfy-cli-docker-setup.sh` |
|
||
| 1.1 | 2026-03-16 | Zero | 添加参数命名规则说明、完成 v1.6.0 源码验证 |
|
||
| 1.0 | 2026-03-16 | Zero | 初始版本 |
|
||
|
||
---
|
||
|
||
## 版本说明
|
||
|
||
**本文档基于以下 comfy-cli 版本调研编写:**
|
||
|
||
| 来源 | 版本 | 说明 |
|
||
|------|------|------|
|
||
| PyPI 最新稳定版 | `1.6.0` | ✅ 已验证,推荐使用 |
|
||
| GitHub main 分支 | 开发中 | 文档编写时(2026-03-16)的代码状态 |
|
||
| 最低兼容版本 | `1.3.8` | 低于此版本可能有命令差异 |
|
||
|
||
**验证你安装的版本:**
|
||
|
||
```bash
|
||
comfy --version
|
||
```
|
||
|
||
如果版本低于 `1.3.8`,建议升级:
|
||
|
||
```bash
|
||
pip install --upgrade comfy-cli
|
||
```
|
||
|
||
## 参数命名规则
|
||
|
||
comfy-cli 使用 **typer** 框架,Python 参数名会自动转换为 CLI 标志:
|
||
|
||
| Python 参数名 | CLI 标志 | 转换规则 |
|
||
|--------------|----------|----------|
|
||
| `relative_path` | `--relative-path` | snake_case → kebab-case |
|
||
| `model_names` | `--model-names` | snake_case → kebab-case |
|
||
| `confirm` | `--confirm` | 无变化 |
|
||
| `fast_deps` | `--fast-deps` | snake_case → kebab-case |
|
||
|
||
**示例:**
|
||
|
||
```python
|
||
# Python 源码
|
||
relative_path: Annotated[str | None, typer.Option(...)]
|
||
|
||
# CLI 使用
|
||
comfy model download --relative-path "models/checkpoints"
|
||
```
|
||
|
||
所有文档中的命令参数都遵循此规则。完整验证报告见 `comfy-cli-verification-report.md`。
|
||
|
||
---
|
||
|
||
*本文档由 Zero (零号) 生成。所有命令已通过 v1.6.0 源码验证。*
|