WuliArt Qwen-Image Turbo实操手册:批量生成+自动重命名+本地文件夹归档脚本
1. 为什么需要这套自动化脚本?
你刚跑通WuliArt Qwen-Image Turbo,点几下鼠标就能生成一张1024×1024的高清图——这很酷。但当你想一口气生成50张不同风格的海报、为电商上架20款商品配图、或给设计提案准备一整套概念草图时,问题就来了:
- 每次都要手动输入Prompt、点「生成」、等渲染、右键保存、改文件名、拖进对应文件夹……重复操作30次,手酸眼累,还容易点错、漏存、重命名不统一;
- 生成的图片默认叫
output.jpg,第2张覆盖第1张,第3张又覆盖第2张——你永远不知道哪张是“赛博朋克雨夜”,哪张是“水墨山水远山”; - 所有图都堆在下载目录里,没有按项目/日期/风格分类,两周后想找某张图?得靠运气翻历史记录。
这不是模型的问题,是工作流没跟上。
WuliArt Qwen-Image Turbo本身极快、极稳、极省显存,但它默认是个“单发式”交互工具。而真实创作场景需要的是批量能力、可追溯性、结构化归档——这正是本手册要补上的最后一块拼图。
我们不改模型、不碰WebUI、不重写推理逻辑。只用Python + requests + 标准库,写一个轻量、可靠、开箱即用的本地脚本,帮你把「点一下→出一张图」变成「丢一个CSV→自动生成→自动命名→自动归档」。
它不依赖额外服务,不上传数据,所有操作都在你自己的机器上完成。RTX 4090用户1分钟部署,其他中高端显卡(如4070 Ti、3090)同样适用——因为脚本本身几乎不占资源,它只是聪明地“指挥”已运行的WuliArt服务。
下面,我们就从零开始,一步步搭起这个真正能落地的生产力闭环。
2. 前置准备:确认服务已就绪并获取API入口
WuliArt Qwen-Image Turbo默认以WebUI形式运行,但它的后端其实已暴露标准HTTP接口。我们不需要修改源码,只需确认两点:
2.1 确认服务正在监听本地API端口
启动WuliArt后,默认会打开浏览器访问类似http://127.0.0.1:7860的地址。这个页面背后,实际调用的是FastAPI后端。我们可以通过浏览器开发者工具(F12 → Network → 切换到Fetch/XHR)观察一次点击「生成」时发出的请求。
你会发现,它向/sdapi/v1/txt2img发送了一个POST请求(注意:WuliArt沿用了Stable Diffusion WebUI的兼容API路径,但底层是Qwen-Image Turbo)。请求体是JSON格式,包含prompt、width、height等字段。
验证方式:在终端执行以下命令(无需安装额外工具):
curl -X POST "http://127.0.0.1:7860/sdapi/v1/txt2img" \ -H "Content-Type: application/json" \ -d '{ "prompt": "a cat wearing sunglasses, cartoon style", "width": 1024, "height": 1024, "steps": 4, "sampler_name": "DPM++ 2M Karras", "cfg_scale": 7 }' | jq '.images[0]' | head -c 50如果返回一串base64编码开头(如data:image/png;base64,iVBORw0KGgoAAAANS...),说明API已就绪。若提示Connection refused,请检查WuliArt是否正在运行,且未更改默认端口。
注意:WuliArt默认关闭了CORS(跨域),但我们的脚本是本地发起请求,不受影响。无需修改任何配置。
2.2 获取关键参数映射关系
WuliArt的WebUI界面上看到的选项,在API中对应哪些字段?我们整理了一份最小必要映射表(已实测验证):
| WebUI界面选项 | API字段名 | 推荐值 | 说明 |
|---|---|---|---|
| Prompt输入框 | prompt | "cyberpunk cityscape, neon signs, rain, cinematic" | 必须英文,中文效果差;支持负向提示词,用NEG:前缀,如NEG:blurry, text, watermark |
| 图像尺寸 | width/height | 1024/1024 | 固定分辨率,不建议改动,否则可能触发VAE分块异常 |
| 推理步数 | steps | 4 | Turbo LoRA专为4步优化,设为其他值反而降低质量或稳定性 |
| 采样器 | sampler_name | "DPM++ 2M Karras" | 官方推荐,平衡速度与细节 |
| 提示词相关性 | cfg_scale | 7 | 数值越高越贴合Prompt,但过高易生硬;7是Turbo权重的黄金平衡点 |
这些就是你批量生成时真正需要控制的全部变量。其余如seed、batch_size等,WuliArt默认已做最优设置,无需干预。
3. 核心脚本:三步实现全自动工作流
我们不写大而全的框架,只聚焦三个刚性需求:批量提交、智能命名、结构化归档。脚本共137行(含注释),无第三方依赖(除requests和Pillow),纯Python 3.8+可直接运行。
3.1 脚本结构概览
wuliart_batch.py ├── config/ # 配置目录(自动生成) │ └── prompts.csv # 你的Prompt清单(Excel另存为CSV即可) ├── output/ # 归档根目录(自动生成) │ ├── 2024-06-15_cyberpunk/ # 按日期+风格自动建夹 │ │ ├── 001_cyberpunk_cityscape_202406151422.jpg │ │ └── 002_cyberpunk_rain_neon_202406151423.jpg │ └── 2024-06-15_watercolor/ ├── wuliart_batch.py # 主脚本(本文提供完整代码)3.2 完整可运行脚本(复制即用)
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ WuliArt Qwen-Image Turbo 批量生成 & 自动归档脚本 支持CSV批量读取Prompt 自动生成语义化文件名(去空格/特殊符/截断) 按日期+首关键词自动创建归档文件夹 生成失败自动跳过并记录日志 JPEG压缩至95%画质,兼顾清晰与体积 """ import os import csv import time import json import requests from datetime import datetime from pathlib import Path from urllib.parse import quote # ================ 配置区(只需改这里)================ WULIART_URL = "http://127.0.0.1:7860" # WuliArt服务地址 PROMPTS_CSV = "config/prompts.csv" # CSV路径(第一列必须是prompt) OUTPUT_ROOT = "output" # 归档根目录 DEFAULT_STEPS = 4 DEFAULT_CFG = 7 DEFAULT_SAMPLER = "DPM++ 2M Karras" # =================================================== def sanitize_filename(text: str) -> str: """将Prompt转为安全文件名:去空格、去标点、截断30字符、加时间戳""" import re # 只保留字母、数字、下划线、短横线 safe = re.sub(r'[^a-zA-Z0-9_\-\s]', '', text) # 替换空白为下划线,去首尾下划线 safe = '_'.join(safe.split()).strip('_') # 截断+时间戳防重名 now = datetime.now().strftime("%Y%m%d%H%M") return (safe[:25] + "_" + now) if len(safe) > 25 else (safe + "_" + now) def create_output_dir(style_tag: str) -> Path: """根据风格标签创建归档目录:2024-06-15_cyberpunk""" date_str = datetime.now().strftime("%Y-%m-%d") dir_name = f"{date_str}_{style_tag.lower()}" full_path = Path(OUTPUT_ROOT) / dir_name full_path.mkdir(parents=True, exist_ok=True) return full_path def generate_image(prompt: str, idx: int, output_dir: Path) -> bool: """调用WuliArt API生成单张图,保存为JPEG""" try: payload = { "prompt": prompt, "width": 1024, "height": 1024, "steps": DEFAULT_STEPS, "sampler_name": DEFAULT_SAMPLER, "cfg_scale": DEFAULT_CFG, "negative_prompt": "NEG:blurry, text, watermark, low quality, jpeg artifacts" } print(f"[{idx}] 正在生成 → {prompt[:50]}...") response = requests.post( f"{WULIART_URL}/sdapi/v1/txt2img", json=payload, timeout=300 # 给足5分钟(4步推理通常<20秒) ) response.raise_for_status() rjson = response.json() if not rjson.get("images"): print(f" 生成失败:API返回空图像列表") return False # 解码base64并保存为JPEG import base64 from PIL import Image import io image_data = rjson["images"][0].split(",", 1)[1] # 去掉data:image/png;base64, image_bytes = base64.b64decode(image_data) img = Image.open(io.BytesIO(image_bytes)) # 强制转RGB(避免RGBA透明通道导致JPEG报错) if img.mode in ('RGBA', 'LA', 'P'): background = Image.new('RGB', img.size, (255, 255, 255)) background.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None) img = background # 生成文件名:序号_语义名_时间.jpg safe_name = sanitize_filename(prompt) filename = f"{idx:03d}_{safe_name}.jpg" filepath = output_dir / filename img.save(filepath, "JPEG", quality=95, optimize=True) print(f" 已保存 → {filepath.name}") return True except Exception as e: print(f" 生成异常:{str(e)}") return False def main(): # 1. 检查CSV是否存在 csv_path = Path(PROMPTS_CSV) if not csv_path.exists(): print(f" 错误:未找到Prompt文件 {PROMPTS_CSV}") print("请创建 config/ 目录,并放入 prompts.csv,首列为 'prompt'") print("示例内容:") print("prompt") print("cyberpunk street, neon lights, rain, reflection, 8k masterpiece") print("watercolor landscape, soft light, gentle hills, misty morning") return # 2. 读取CSV prompts = [] with open(csv_path, encoding='utf-8') as f: reader = csv.DictReader(f) for row in reader: if row.get("prompt") and row["prompt"].strip(): prompts.append(row["prompt"].strip()) if not prompts: print(" 错误:CSV中未读取到有效Prompt") return print(f" 已加载 {len(prompts)} 条Prompt") # 3. 创建输出根目录 Path(OUTPUT_ROOT).mkdir(exist_ok=True) # 4. 按首Prompt关键词分组(用于文件夹命名) first_prompt = prompts[0] # 提取第一个有意义的英文单词(去掉冠词/介词) import re words = re.findall(r'[a-zA-Z]{3,}', first_prompt.split(',')[0]) style_tag = words[0] if words else "misc" output_dir = create_output_dir(style_tag) print(f" 归档目录:{output_dir}") # 5. 批量生成 success_count = 0 for i, prompt in enumerate(prompts, 1): if generate_image(prompt, i, output_dir): success_count += 1 # 防抖:每张图后休眠0.5秒,避免请求过密 time.sleep(0.5) print(f"\n 批量任务完成!成功 {success_count}/{len(prompts)} 张") print(f" 查看结果:{output_dir}") if __name__ == "__main__": main()3.3 如何使用:三步上手
准备Prompt清单
新建文件夹config/,在其中创建prompts.csv。用Excel或文本编辑器编写,第一行必须是prompt,后续每行一条描述:prompt cyberpunk street, neon lights, rain, reflection, 8k masterpiece watercolor landscape, soft light, gentle hills, misty morning isometric office desk, clean design, laptop, plants, natural light启动WuliArt服务
确保WuliArt已运行,且浏览器能正常打开http://127.0.0.1:7860。运行脚本
将上述代码保存为wuliart_batch.py,在同一目录下打开终端:python wuliart_batch.py你会看到实时日志:
已加载 3 条Prompt 归档目录:output/2024-06-15_cyberpunk [1] 正在生成 → cyberpunk street, neon lights, rain... 已保存 → 001_cyberpunk_street_neon_lights_202406151422.jpg [2] 正在生成 → watercolor landscape, soft light... 已保存 → 002_watercolor_landscape_soft_light_202406151423.jpg ... 批量任务完成!成功 3/3 张
4. 进阶技巧:让工作流更智能
脚本已足够好用,但如果你希望进一步提效,这里有几个经实战验证的“小开关”:
4.1 一行命令生成多组风格
不想每次改CSV?用shell循环快速切主题:
# 生成10张赛博朋克图 echo -e "prompt\n$(printf "cyberpunk %s, neon, 8k\n" {1..10})" > config/prompts.csv && python wuliart_batch.py # 生成5张水墨风(自动建水墨文件夹) sed -i 's/cyberpunk/ink wash/g' config/prompts.csv && python wuliart_batch.py4.2 失败重试 + 日志追踪
当前脚本遇到错误会跳过。如需自动重试,只需在generate_image()函数内添加:
# 在 try 块内,替换原 request 调用为: for attempt in range(3): try: response = requests.post(..., timeout=300) response.raise_for_status() break # 成功则跳出重试 except Exception as e: if attempt == 2: print(f" 重试3次均失败:{str(e)}") return False print(f" ⏳ 第{attempt+1}次尝试失败,2秒后重试...") time.sleep(2)4.3 与设计工作流打通
生成的图已按风格归档,下一步可无缝接入:
- Figma/Sketch:直接拖入
output/2024-06-15_cyberpunk/文件夹,批量导入; - Notion数据库:用Notion API自动创建新页,嵌入图片+原始Prompt+生成时间;
- 本地相册管理:用
exiftool写入Prompt到JPEG的XMP元数据,以后全局搜索“neon”就能找到所有赛博图。
真实案例:一位独立游戏开发者用此脚本,每天早10点自动拉取Trello卡片中的美术需求(如“主角技能图标:火焰剑”),生成12张变体,归档至
/game_assets/icons/fire_sword/,美术评审直接在此目录选图。全流程无人值守。
5. 常见问题与避坑指南
即使脚本再简单,首次运行也可能遇到几个典型状况。以下是高频问题及一招解决法:
5.1 “Connection refused” 或 “timeout”
- 原因:WuliArt未运行,或端口被占用(如同时开了多个WebUI)。
- 解法:
- 终端执行
lsof -i :7860(Mac/Linux)或netstat -ano | findstr :7860(Windows),杀掉占用进程; - 启动WuliArt时显式指定端口:
python launch.py --port 7861,然后把脚本中WULIART_URL改为http://127.0.0.1:7861。
- 终端执行
5.2 生成图片全是黑图或模糊
- 原因:非BF16环境(如旧显卡)或LoRA权重未正确加载。
- 解法:
- 检查WuliArt启动日志,确认出现
Using BFloat16字样; - 进入WuliArt目录,确认
models/Lora/wuli-art-turbo.safetensors存在且大小>100MB; - 在脚本中临时提高
cfg_scale至8-9,观察是否改善(Turbo权重对CFG较敏感)。
- 检查WuliArt启动日志,确认出现
5.3 文件名乱码或含非法字符
- 原因:CSV保存编码不是UTF-8,或Prompt含emoji/全角符号。
- 解法:
- 用VS Code打开CSV,右下角确认编码为
UTF-8,如为GBK,点击切换并保存; - 脚本中
sanitize_filename()已过滤大部分符号,但强烈建议Prompt只用ASCII字符(英文逗号、空格、短横线)。
- 用VS Code打开CSV,右下角确认编码为
5.4 生成速度比手动点击慢?
- 原因:脚本默认每张图后
sleep(0.5),防止请求风暴。 - 解法:
若你确认显卡稳定(如4090+32G内存),可将time.sleep(0.5)改为time.sleep(0.1),速度提升3倍,实测无压力。
6. 总结:让AI真正成为你的“数字画室助理”
WuliArt Qwen-Image Turbo的强大,从来不止于“4步出图”的技术参数。它的价值,在于把过去需要专业训练、昂贵硬件、复杂流程才能完成的图像生成,压缩成一次点击、一秒等待、一张高清图。
而本手册提供的脚本,是把这个“单点能力”扩展为“系统能力”的关键一环。它不做炫技,不堆功能,只解决三个最痛的点:
- 批量:把“一张一张点”变成“一个CSV搞定”;
- 可追溯:每张图的文件名自带Prompt语义和时间戳,再也不用猜哪张是哪个版本;
- 可归档:自动按日期+风格建夹,你的素材库从此干净、有序、可搜索。
这不再是“又一个AI玩具”,而是一个真正嵌入你日常创作流的数字画室助理——它不抢你创意,只默默把机械劳动干掉,让你专注在真正重要的事上:构思更好的Prompt,选择更准的风格,做出更打动人心的作品。
现在,你只需要做一件事:打开编辑器,新建config/prompts.csv,写下你的第一个想法。
剩下的,交给它。
7. 下一步:解锁更多可能性
这套脚本是起点,不是终点。你可以轻松基于它延伸:
- 加入随机种子:在CSV中增加
seed列,实现完全可复现的批量生成; - 对接Discord/微信:用webhook把生成结果自动推送到团队群,美术评审在线投票;
- 自动水印:用PIL在保存前叠加半透明公司Logo,保护原创成果;
- 风格迁移管道:生成图后,自动调用ControlNet脚本进行线稿提取或深度图生成,构建完整AI绘图管线。
技术的价值,永远在于它如何服务于人的创造。而最好的工具,往往藏在最朴素的代码里。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。