Bridge 图像生成技能: gs2-sdxl (GS-2 SDXL) + gs1-flux (GS-1 FLUX)
This commit is contained in:
@@ -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
|
||||
@@ -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])
|
||||
Reference in New Issue
Block a user