Bridge 图像生成技能: gs2-sdxl (GS-2 SDXL) + gs1-flux (GS-1 FLUX)

This commit is contained in:
admin9webs
2026-08-27 15:39:17 +08:00
commit 36f3b2e387
4 changed files with 250 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
# Bridge VM 图像生成技能
给 9Webs 全部 Bridge 虚拟机使用的图像生成技能。
## 包含技能
- **gs2-sdxl** — GS-2 (192.168.9.116) Forge SDXL base 1.0 双实例 (:7861/:7862),快速出图
- **gs1-flux** — GS-1 (192.168.9.113) ComfyUI FLUX.1-dev (GGUF Q5_K_S),高质量出图
## 安装
```bash
mkdir -p ~/.hermes/skills && cd ~/.hermes/skills
git clone http://gitea.9webs.online:3000/admin9webs/bridge-skills.git
# 或仅复制所需技能目录
cp -r bridge-skills/gs2-sdxl bridge-skills/gs1-flux ~/.hermes/skills/
```
## 使用策略
- 快速草图/批量配图 → `gs2-sdxl` (steps 24-30, 约几秒/张)
- 最终成品/复杂构图 → `gs1-flux` (steps 20, 约 100 秒/张)
> 部署日期: 2026-08-27,已在全部 23 台 Bridge 上安装验证。
+85
View File
@@ -0,0 +1,85 @@
---
name: gs1-flux
description: 调用 GS-1 (192.168.9.113) ComfyUI FLUX.1-dev 图像生成 — txt2img/img2img/填充。GGUF Q5_K_S 模型,V100 双卡。触发:FLUX 出图、高质量图片、复杂构图、产品图、图生图、局部重绘、inpaint。
version: 1.0.0
author: 9Webs
license: internal
platforms: [linux]
triggers:
- FLUX
- flux1
- 高质量出图
- ComfyUI
- inpaint
- 局部重绘
- 图生图
---
# GS-1 FLUX.1-dev 图像生成 (ComfyUI API)
用 GS-1 的 ComfyUI + FLUX.1-dev (GGUF Q5_K_S) 生成高质量图片。直连 `192.168.9.113:8188` 即可。
## 服务拓扑
| 项 | 值 |
|----|----|
| 节点 | GS-1 = 192.168.9.113 (2× Tesla V100-SXM2-16GB) |
| ComfyUI | `http://192.168.9.113:8188` (v0.25.0) |
| UNet | `flux1-dev-Q5_K_S.gguf` (GGUF, V100 无 bf16 用 Q5) |
| 填充模型 | `flux1-fill-dev-Q5_K_S.gguf` (inpaint/局部重绘) |
| CLIP | `t5-v1_1-xxl-encoder-Q5_K_M.gguf` + `clip_l.safetensors` (type=flux) |
| VAE | `ae.safetensors` |
## 调用方式 (ComfyUI REST API)
1. **POST `/prompt`** 提交 API 格式工作流 (见 workflows/flux_txt2img.json),返回 `prompt_id`
2. **轮询 `GET /history/{prompt_id}`** 直到 `status.completed == true`
3. **取图 `GET /view?filename=<name>&type=output`** 下载 PNG
### 参考参数 (已实测)
- **steps 20** (18-28 均可;GGUF 量化,步数低会糊)
- **cfg 1.0** (FLUX 用 cfg≈1 + guidance;标准 KSampler 下 cfg 1.0 即可)
- **1024×1024** (FLUX 原生;V100 16GB 上限约 1024,超高会 OOM)
- **sampler `euler` / scheduler `simple`**, seed 可固定
- **耗时约 100-120 秒/张** (V100 无 flash-attention;首次调用含模型加载更慢)
### 脚本 (scripts/flux_txt2img.py)
```bash
python3 ~/.hermes/skills/gs1-flux/scripts/flux_txt2img.py "prompt here" [--steps 20] [--seed -1]
# 输出: /tmp/flux_out/flux_*.png
```
## 健康检查
```bash
curl -s http://192.168.9.113:8188/system_stats | head -c 200 # 返回 JSON = 正常
curl -s http://192.168.9.113:8188/object_info/UnetLoaderGGUF | grep -o 'flux1[^"]*' # 模型在位
curl -s http://192.168.9.113:8188/queue | python3 -c "import json,sys; d=json.load(sys.stdin); print('running:', len(d['queue_running']), 'pending:', len(d['queue_pending']))"
```
## 排障
- **提交 400** → 工作流节点错误,读 `node_errors` 详情 (常见: CLIPTextEncodeFlux 需 clip_l/t5xxl/guidance 三个输入)
- **长时间不出图** → 查队列 `queue` 是否堆积;单实例顺序执行,批量任务排队
- **OOM** → 降到 768×768 或减少 batch
- **换风格/复杂提示** → FLUX 对提示词敏感,直接写详细英文描述;负向提示基本不需要
## 服务端排障
```bash
sshpass -p 'Tt123456!' ssh admin9webs@192.168.9.113 'systemctl --user status comfyui* --no-pager | head -20'
```
## 陷阱
1. **Q5_K_S 量化**:图片质量略低于 fp8/bf16,但 V100 无 bf16 只能跑 GGUF;复杂文字/人脸注意检查。
2. **每次约 2 分钟**:批量任务要轮询串行,不要并发提交同实例。
3. **图片在 ComfyUI output 目录** (`~/ComfyUI/output/`),推荐客户端用 /view 下载,不依赖服务端目录。
4. **Flux Fill** (flux1-fill-dev) 用于局部重绘/inpaint,需配合 mask 工作流。
## 相关
- SDXL 出图用 `gs2-sdxl` 技能 (GS-2 :7861/:7862,快但质量略低)
- 配图策略: 快速草图用 SDXL,最终成品/复杂构图用 FLUX
+35
View File
@@ -0,0 +1,35 @@
import json, urllib.request, urllib.error, time
BASE = 'http://192.168.9.113:8188'
wf = {
"1": {"class_type": "UnetLoaderGGUF", "inputs": {"unet_name": "flux1-dev-Q5_K_S.gguf"}},
"2": {"class_type": "DualCLIPLoaderGGUF", "inputs": {"clip_name1": "t5-v1_1-xxl-encoder-Q5_K_M.gguf", "clip_name2": "clip_l.safetensors", "type": "flux"}},
"3": {"class_type": "VAELoader", "inputs": {"vae_name": "ae.safetensors"}},
"4": {"class_type": "CLIPTextEncode", "inputs": {"clip": ["2", 0], "text": "a red apple on a wooden table, product photo, studio lighting"}},
"5": {"class_type": "CLIPTextEncode", "inputs": {"clip": ["2", 0], "text": "blurry, low quality"}},
"6": {"class_type": "EmptyLatentImage", "inputs": {"width": 1024, "height": 1024, "batch_size": 1}},
"7": {"class_type": "KSampler", "inputs": {"model": ["1", 0], "positive": ["4", 0], "negative": ["5", 0], "latent_image": ["6", 0], "seed": 12345, "steps": 20, "cfg": 1.0, "sampler_name": "euler", "scheduler": "simple", "denoise": 1.0}},
"8": {"class_type": "VAEDecode", "inputs": {"samples": ["7", 0], "vae": ["3", 0]}},
"9": {"class_type": "SaveImage", "inputs": {"filename_prefix": "flux_test", "images": ["8", 0]}},
}
req = urllib.request.Request(BASE + '/prompt', data=json.dumps({"prompt": wf}).encode(), headers={'Content-Type': 'application/json'})
try:
r = json.loads(urllib.request.urlopen(req, timeout=30).read())
pid = r.get('prompt_id')
print('prompt_id:', pid, '| node_errors:', r.get('node_errors'))
if not pid: raise SystemExit(1)
for i in range(60):
time.sleep(5)
try:
h = json.loads(urllib.request.urlopen(BASE + '/history/' + pid, timeout=10).read())
except Exception: continue
if pid in h:
st = h[pid].get('status', {})
if st.get('completed') or st.get('status_str') == 'success':
for nid, o in h[pid].get('outputs', {}).items():
for img in o.get('images', []):
print('出图:', img.get('filename'), '| 节点', nid)
print('FLUX 生成成功!'); raise SystemExit(0)
elif st.get('status_str') == 'error':
print('FLUX 错误:', json.dumps(st)[:500]); raise SystemExit(1)
except urllib.error.HTTPError as e:
print('HTTP', e.code, e.read().decode()[:600])
+106
View File
@@ -0,0 +1,106 @@
---
name: gs2-sdxl
description: 调用 GS-2 (192.168.9.116) Forge SDXL base 1.0 图像生成 API — txt2img/img2img,双实例 :7861/:7862 轮询。触发:生成图片/产品图/配图/场景图,SDXL 出图,文生图,图生图。
---
# GS-2 SDXL 图像生成 (Forge API)
用 GS-2 的 SDXL base 1.0 生成图片。本机(任意节点)直连 `192.168.9.116` 即可,无需代理。
## 服务拓扑
| 项 | 值 |
|----|----|
| 节点 | GS-2 = 192.168.9.116 (2× RTX 3060 Laptop 12GB) |
| 实例1 | `http://192.168.9.116:7861` (GPU0, systemd `forge-sdxl.service`) |
| 实例2 | `http://192.168.9.116:7862` (GPU1, systemd `forge-sdxl-2.service`) |
| 模型 | `sd_xl_base_1.0.safetensors`**完整 SDXL base,不是 turbo!** + `sdxl_vae.safetensors` |
| API | 标准 A1111/Forge: `/sdapi/v1/txt2img`, `/sdapi/v1/img2img`, `/sdapi/v1/sd-models` |
双实例轮询:优先 7861,失败/繁忙换 7862。
## 推荐参数 (SDXL base 完整版,2026-08-27 实测)
⚠️ 模型是完整 base(非 turbo),**steps 需要 24-30**,2 步会出糊图。
| 参数 | 值 |
|------|----|
| steps | 24-30 (出图约 10-25s@1024²) |
| cfg_scale | 6-7.5 |
| width/height | 768~1024 (SDXL 原生尺寸),默认 1024×1024 或 832×1216 |
| sampler_name | `euler_a``dpmpp_2m_karras` |
| negative_prompt | `lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, cropped, worst quality, low quality, jpeg artifacts, signature, watermark, username, blurry` |
| 并发 | 单实例同时只处理 1 个请求 (12GB VRAM),批量任务轮询双实例 |
## 调用方式 (已验证)
### curl txt2img
```bash
curl -s -X POST http://192.168.9.116:7861/sdapi/v1/txt2img \
-H 'Content-Type: application/json' \
-d '{"prompt":"a cute corgi wearing sunglasses, studio photo","negative_prompt":"lowres, blurry, watermark","steps":24,"cfg_scale":7,"width":1024,"height":1024,"sampler_name":"euler_a","seed":-1}'
```
### Python (urllib,无 curl 依赖)
```python
import json, base64, urllib.request
def sdxl_txt2img(prompt, negative_prompt="", steps=24, cfg=7.0,
w=1024, h=1024, sampler="euler_a", seed=-1, port=7861):
req = urllib.request.Request(
f"http://192.168.9.116:{port}/sdapi/v1/txt2img",
data=json.dumps({"prompt": prompt, "negative_prompt": negative_prompt,
"steps": steps, "cfg_scale": cfg, "width": w, "height": h,
"sampler_name": sampler, "seed": seed}).encode(),
headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=180) as r:
data = json.loads(r.read())
return base64.b64decode(data["images"][0]) # PNG bytes
# 保存
png = sdxl_txt2img("a red apple on a wooden table, product photo", port=7861)
open("/tmp/apple.png", "wb").write(png)
```
### img2img (重绘/换风格/局部重绘)
```bash
curl -s -X POST http://192.168.9.116:7862/sdapi/v1/img2img \
-H 'Content-Type: application/json' \
-d '{"init_images":["<base64 PNG>"],"prompt":"same product, luxury studio background","denoising_strength":0.6,"steps":24,"cfg_scale":7,"width":1024,"height":1024,"sampler_name":"euler_a"}'
```
要点:
- `init_images`**base64 编码的 PNG 字符串**(无 data: 前缀)
- `denoising_strength` 0.5-0.7 重绘风格,0.3 以下基本保留原图,0.8+ 大改
## 健康检查
```bash
# 模型列表 (返回 JSON 即服务正常)
curl -s http://192.168.9.116:7861/sdapi/v1/sd-models
# 实例间轮询: 7861 → 7862
```
## 服务端排障 (需要时)
```bash
sshpass -p 'Tt123456!' ssh admin9webs@192.168.9.116 \
'export XDG_RUNTIME_DIR=/run/user/$(id -u); systemctl --user status forge-sdxl forge-sdxl-2 --no-pager | head -30'
# 重启: systemctl --user restart forge-sdxl forge-sdxl-2
```
## 陷阱
1. **是 base 模型不是 turbo**:steps 必须 24+,2-4 步出糊图/灰图。
2. **双实例各绑一张卡**:单实例并发第 2 个请求会排队或 OOM,批量任务轮询两个端口。
3. **12GB VRAM 上限**:1024×1024 稳定;超 1024 或加 ControlNet 可能 OOM,降 768。
4. **seed=-1 随机**,固定 seed 可复现。
5. 服务端 outputs 目录在 GS-2 (`~/stable-diffusion-webui-forge/outputs/`),但**推荐客户端解析 base64 直接存本地**,不依赖服务端目录。
## 相关
- 部署/版本排障细节见本地 `gpustack-cluster` 技能 (GS-2 Forge 双实例 systemd 章节)
- FlairGS (AppServer-105 :7870) 也调这两个实例:FORGE_STEPS=24, CFG=7.5, denoise=0.70 (产品图场景生成)