Janus-Pro-7B WebUI插件开发指南:扩展自定义功能模块
Janus-Pro-7B WebUI插件开发指南:扩展自定义功能模块
你是不是觉得Janus-Pro-7B的WebUI功能已经很丰富了,但总感觉还差点什么?比如,你想在生成文本前自动过滤掉敏感词,或者在图片生成后自动添加一个水印,又或者想在界面上加一个自己设计的统计面板。这些需求,官方的WebUI可能没有直接提供。
好消息是,Janus-Pro-7B的WebUI支持插件开发,这意味着你可以像搭积木一样,给它添加任何你想要的功能。今天,我就带你从零开始,亲手打造一个属于你自己的WebUI插件。整个过程比你想象的要简单,不需要你精通前端框架,只要会点Python,就能轻松上手。
1. 准备工作:认识插件架构
在动手写代码之前,我们先花几分钟了解一下Janus-Pro-7B WebUI的插件是怎么工作的。理解了它的设计思路,后面写代码就会顺畅很多。
简单来说,WebUI的插件系统就像一个“插座”和“插头”的体系。WebUI本身提供了很多标准的“插座”(我们称之为扩展点或钩子),你的插件就是一个个“插头”。当你把插头插到对应的插座上,你的代码就能在WebUI运行的特定时刻被调用,从而改变或增强它的行为。
1.1 插件能做什么?
一个插件通常可以干这几类事:
- 添加新的处理步骤:比如在模型处理输入文本之前,你先对文本做点手脚(预处理);或者在模型输出结果之后,你再对结果加工一下(后处理)。
- 扩展用户界面:在现有的WebUI页面上,增加新的按钮、输入框、选项卡或者一整块新的显示区域。
- 集成外部服务:把WebUI和其他工具连起来,比如生成内容后自动保存到你的笔记软件,或者从数据库里读取预设的提示词。
- 修改现有行为:改变WebUI某个默认功能的运作方式。
1.2 插件的基本结构
一个最简单的插件,其实就是一个Python文件,里面包含一个继承了特定基类的类。这个类里实现几个关键的方法,WebUI在启动时就会发现它,并把它“挂载”到相应的位置。
为了让你有个直观印象,我们先来看一个插件文件的骨架长什么样:
# my_awesome_plugin.py
import modules.scripts as scripts
from modules import scripts_postprocessing
from modules.ui_components import FormRow
class MyAwesomePlugin(scripts.Script):
def title(self):
return "我的超酷插件"
def show(self, is_img2img):
return scripts.AlwaysVisible
def ui(self, is_img2img):
# 在这里定义插件在界面上显示哪些控件
with FormRow():
# 例如,添加一个复选框
my_checkbox = gr.Checkbox(label="启用我的功能", value=False)
return [my_checkbox]
def process(self, p, *args):
# 在这里编写核心的处理逻辑
# p 包含了所有的生成参数
# args 对应上面 ui() 方法返回的控件值
my_checkbox_value = args[0]
if my_checkbox_value:
# 如果用户勾选了复选框,就执行一些操作
p.prompt = "[前缀] " + p.prompt
# 处理完成后,返回修改后的参数对象 p
return p
看不懂代码细节没关系,我们后面会一步步拆解。你现在只需要知道:一个插件 = 一个Python类 + 几个必须实现的方法。
2. 开发第一个插件:文本前缀添加器
理论讲多了容易犯困,我们直接来实战。我们的第一个目标是做一个超级简单的插件:在用户输入提示词的开头,自动加上一个可自定义的前缀。
比如,用户输入“a cat”,如果前缀设置为“best quality, masterpiece, ”,那么最终发给模型的提示词就会变成“best quality, masterpiece, a cat”。这在需要统一画风或质量的场景下很有用。
2.1 创建插件文件
首先,找到你的Janus-Pro-7B WebUI安装目录。里面会有一个叫 extensions 的文件夹。所有第三方插件都放在这里。
- 在
extensions文件夹下,新建一个文件夹,名字就是你的插件名,比如my-prefix-adder。 - 进入这个新文件夹,创建一个Python文件,命名为
my_prefix_adder.py。 - 用你喜欢的代码编辑器(比如VSCode、PyCharm)打开这个文件。
2.2 编写插件核心代码
现在,把下面的代码复制到 my_prefix_adder.py 文件中。我会在代码里加上详细的注释,告诉你每一部分是干什么的。
# my_prefix_adder.py
# 导入WebUI插件开发所需的必要模块
import modules.scripts as scripts
import gradio as gr
from modules import script_callbacks
from modules.ui_components import FormRow, FormGroup
# 我们的插件类,必须继承自 scripts.Script
class MyPrefixAdderScript(scripts.Script):
"""
一个简单的插件示例:为所有提示词添加自定义前缀。
"""
# 这个方法返回插件的显示名称,会出现在WebUI的下拉列表或按钮上
def title(self):
return "文本前缀添加器"
# 这个方法决定插件何时显示。scripts.AlwaysVisible 表示始终显示。
def show(self, is_img2img):
return scripts.AlwaysVisible
# 这是最重要的方法之一,用于创建插件的用户界面(UI)
def ui(self, is_img2img):
# 创建一个UI控件列表,最终要返回它
controls = []
# 使用FormGroup可以让相关控件在UI上分组显示,更美观
with FormGroup(elem_id="my_prefix_group"):
# 使用FormRow进行水平布局
with FormRow():
# 创建一个复选框,让用户决定是否启用本插件
# label: 控件旁边显示的文字
# value: 默认值,False表示默认不勾选
enable_plugin = gr.Checkbox(label="启用前缀添加", value=False, elem_id="my_prefix_enable")
controls.append(enable_plugin) # 记住这个控件,后面要用
with FormRow():
# 创建一个文本框,让用户输入想要添加的前缀
# placeholder: 文本框内的提示文字
prefix_text = gr.Textbox(label="自定义前缀",
placeholder="例如:best quality, masterpiece, ",
value="",
elem_id="my_prefix_text")
controls.append(prefix_text) # 记住这个控件
# 返回所有需要记录值的UI控件列表
return controls
# 这是另一个核心方法,在生成流程中被调用,用于执行实际的处理逻辑
# p: 一个包含所有生成参数(如提示词、步数、尺寸等)的对象
# *args: 按顺序对应上面 ui() 方法返回的各个控件的当前值
def process(self, p, *args):
# 从args中解包出我们控件的值
# args[0] 对应 controls[0],也就是 enable_checkbox
# args[1] 对应 controls[1],也就是 prefix_textbox
is_enabled = args[0]
custom_prefix = args[1]
# 检查插件是否被启用,以及前缀是否不为空
if is_enabled and custom_prefix.strip():
print(f"[文本前缀添加器] 正在工作,前缀为: '{custom_prefix}'")
# 遍历所有的提示词(WebUI支持批量生成)
for i in range(len(p.all_prompts)):
# 在原有的提示词前加上我们自定义的前缀
p.all_prompts[i] = custom_prefix + p.all_prompts[i]
print(f"[文本前缀添加器] 处理完成。")
else:
print(f"[文本前缀添加器] 未启用或前缀为空,跳过处理。")
# 必须返回修改后的参数对象 p
return p
# 后处理钩子(可选):在生成完成后执行,这里我们暂时不用
# def postprocess(self, p, processed, *args):
# pass
2.3 安装并测试插件
代码写好了,怎么让它生效呢?非常简单。
- 重启WebUI:完全关闭正在运行的Janus-Pro-7B WebUI服务,然后重新启动它。
- 查看插件列表:启动后,在WebUI的顶部选项卡或设置页面中,找到“扩展”或“插件”标签页。你应该能看到“文本前缀添加器”出现在已安装的插件列表里,并且处于激活状态。
- 使用插件:
- 刷新你的WebUI主页面(文生图或图生图页面)。
- 在提示词输入框附近,你应该能看到我们添加的“文本前缀添加器”折叠面板或一组新的控件。
- 勾选“启用前缀添加”,在下面的文本框里输入“best quality, masterpiece, ”。
- 在提示词框输入“a cat sitting on a sofa”。
- 点击生成。观察控制台输出,你应该能看到类似
[文本前缀添加器] 正在工作...的日志。 - 生成的图片效果,应该会比不加前缀时有所提升(更偏向于高质量和大师作品风格)。
恭喜你!你的第一个插件已经成功运行了。它虽然简单,但包含了插件开发的所有核心要素:UI定义、参数获取、逻辑处理。
3. 深入进阶:开发一个后处理图片插件
只会改文字不过瘾?我们来点更实用的:开发一个后处理插件,在图片生成完成后,自动为它添加一个简单的文本水印。
这个例子会涉及到图片处理,我们会用到PIL(Python Imaging Library)这个库。确保你的环境已经安装了它(pip install Pillow)。
3.1 创建图片水印插件
在 extensions 文件夹下再新建一个文件夹,比如 my-image-watermark,然后创建 my_image_watermark.py 文件。
# my_image_watermark.py
import modules.scripts as scripts
import gradio as gr
from modules import script_callbacks, processing, images
from modules.ui_components import FormRow, FormGroup
from PIL import Image, ImageDraw, ImageFont
import os
class MyImageWatermarkScript(scripts.Script):
def title(self):
return "图片水印添加器"
def show(self, is_img2img):
return scripts.AlwaysVisible
def ui(self, is_img2img):
controls = []
with FormGroup(elem_id="my_watermark_group"):
with FormRow():
enable_watermark = gr.Checkbox(label="添加文字水印", value=False)
controls.append(enable_watermark)
with FormRow():
watermark_text = gr.Textbox(label="水印文字", value="My AI Art", placeholder="输入水印内容")
controls.append(watermark_text)
with FormRow():
# 滑块控件,用于选择水印文字大小
text_size = gr.Slider(minimum=10, maximum=100, step=1, value=36, label="字体大小")
controls.append(text_size)
with FormRow():
# 滑块控件,用于选择水印不透明度
text_opacity = gr.Slider(minimum=0.1, maximum=1.0, step=0.1, value=0.5, label="不透明度")
controls.append(text_opacity)
with FormRow():
# 单选按钮,选择水印位置
position = gr.Radio(choices=["右下角", "左下角", "右上角", "左上角", "居中"], value="右下角", label="水印位置")
controls.append(position)
return controls
# 注意:我们这次重写的是 postprocess 方法,它在图片生成后被调用
def postprocess(self, p, processed, *args):
"""
p: 处理参数对象
processed: 处理结果对象,里面包含了生成的所有图片(processed.images)
*args: UI控件的值
"""
is_enabled, watermark_text, text_size, opacity, position = args
if not is_enabled or not watermark_text.strip():
return processed # 如果未启用,直接返回原结果
print(f"[图片水印添加器] 开始为 {len(processed.images)} 张图片添加水印。")
# 尝试加载一个字体,如果失败则使用默认字体
try:
# 你可以指定一个字体文件路径,例如:
# font = ImageFont.truetype("/path/to/your/font.ttf", text_size)
font = ImageFont.load_default()
except:
font = ImageFont.load_default()
watermarked_images = []
for img in processed.images:
# 将WebUI的图片对象转换为PIL Image对象
pil_image = images.from_numpy(img)
draw = ImageDraw.Draw(pil_image, 'RGBA') # 使用RGBA模式以支持透明度
# 计算文字尺寸和位置
# 注意:load_default()字体可能无法准确获取文本尺寸,这里是一个简单估算
# 对于复杂需求,建议使用指定字体文件
text_bbox = draw.textbbox((0, 0), watermark_text, font=font)
text_width = text_bbox[2] - text_bbox[0]
text_height = text_bbox[3] - text_bbox[1]
img_width, img_height = pil_image.size
# 根据选择的位置计算坐标
padding = 10
if position == "右下角":
x = img_width - text_width - padding
y = img_height - text_height - padding
elif position == "左下角":
x = padding
y = img_height - text_height - padding
elif position == "右上角":
x = img_width - text_width - padding
y = padding
elif position == "左上角":
x = padding
y = padding
else: # 居中
x = (img_width - text_width) / 2
y = (img_height - text_height) / 2
# 绘制半透明文字(白色带透明度)
draw.text((x, y), watermark_text, font=font, fill=(255, 255, 255, int(255 * opacity)))
# 将处理后的PIL Image转换回numpy数组,并添加到新列表
watermarked_images.append(images.to_numpy(pil_image))
# 用添加了水印的图片列表替换原来的图片列表
processed.images = watermarked_images
print(f"[图片水印添加器] 水印添加完成。")
return processed
3.2 测试水印插件
- 同样,重启WebUI。
- 在文生图页面,找到新出现的“图片水印添加器”控件组。
- 勾选“添加文字水印”,输入水印文字(如“Created with Janus”),调整大小、透明度和位置。
- 输入提示词,生成一张图片。
- 查看结果,生成的图片上应该已经带上了你设置的水印。
通过这个例子,你学会了如何使用 postprocess 钩子来操作生成后的图片,并且使用了更丰富的UI控件(滑块、单选按钮)。插件的能力边界正在被你一步步拓宽。
4. 实用技巧与问题排查
开发插件时,你可能会遇到一些小麻烦。这里分享几个实用的技巧和常见问题的解决方法。
4.1 调试与日志输出
插件开发离不开调试。最直接的方法就是使用 print() 函数将信息输出到WebUI的控制台。就像我们在前面代码里做的:
print(f"[我的插件] 当前参数是: {some_variable}")
这能帮你清楚地知道代码执行到了哪一步,变量的值是什么。
4.2 理解WebUI的对象结构
插件强大的关键在于你能操作WebUI内部的数据。两个最重要的对象是:
p(在process中):StableDiffusionProcessing类的实例。它包含了生成所需的一切参数:p.prompt(提示词),p.negative_prompt(负面提示词),p.steps(步数),p.cfg_scale(引导系数),p.seed(种子)等等。修改这些属性就能影响生成过程。processed(在postprocess中):Processed类的实例。最重要的属性是processed.images,这是一个包含所有生成图片(numpy数组格式)的列表。process方法返回的p对象,最终也会被转换为processed对象。
多翻阅WebUI的源代码(特别是 modules/processing.py 和 modules/images.py),是理解这些对象的最佳途径。
4.3 常见问题与解决
- 插件不显示:检查你的插件文件夹是否放在正确的
extensions目录下。检查script.py文件中的类名是否正确,以及title()方法是否返回了非空字符串。重启WebUI。 - 控件值获取错误:确保
ui()方法返回的控件列表顺序,与process()或postprocess()方法中*args的解包顺序完全一致。 - 导入错误:确保你的插件文件开头正确导入了所需的模块(如
modules.scripts)。如果用了第三方库(如PIL),请确保已通过pip安装。 - 性能问题:在
process或postprocess中执行非常耗时的操作(如下载文件、复杂计算)会拖慢整个生成流程。尽量保持插件逻辑高效,或者考虑使用异步操作。
5. 总结
走完这两个插件的开发旅程,你应该已经感受到,为Janus-Pro-7B WebUI扩展功能并没有那么神秘。核心就是找到那个对的“钩子”(process 或 postprocess),然后在里面编写你的逻辑。
从简单的文本处理到图片后处理,你手中的工具已经可以应对很多定制化需求了。你可以尝试把两者结合起来,比如做一个“智能提示词优化+自动添加签名水印”的一站式插件。更进一步的,你可以研究 script_callbacks 模块,它提供了更多精细化的钩子,允许你在WebUI生命周期的几乎任何阶段注入代码,比如在页面加载时添加新的选项卡。
最好的学习方式就是动手去实现一个你真正需要的功能。从一个小点子开始,遇到问题就查源码、看日志、在开发者社区里交流。当你成功运行起自己开发的插件,并看到它完美地融入WebUI工作时,那种成就感是非常棒的。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐



所有评论(0)