- 将默认LLM模型从gemini-2.0-flash升级为gemini-3-flash-preview - 将博主人设从"性感福利主播"更改为"二次元coser" - 优化LLM生成SD提示词的指南,新增中国审美人物描述规则 - 为各SD模型添加颜值核心词、示范prompt和禁止使用的关键词 - 新增三维人物描述法(眼睛/肤色/气质)和专属光线词指导 📦 build(openspec): 归档旧规范并创建新规范 - 将improve-maintainability规范归档至2026-02-25目录 - 新增2026-02-26-improve-ui-layout规范,包含UI布局优化设计 - 新增2026-02-26-optimize-image-generation规范,包含图片生成优化设计 - 在根目录openspec/specs下新增图片质量、后处理、中国审美和LLM提示词规范 ♻️ refactor(sd_service): 优化SD模型配置和图片后处理 - 为各SD模型添加中国审美特征词和欧美面孔排除词 - 新增高画质预设档,SDXL模型启用Hires Fix参数 - 将后处理拆分为beauty_enhance和anti_detect_postprocess两个独立函数 - 新增美化增强功能,支持通过enhance_level参数控制强度 ♻️ refactor(services): 更新内容生成服务以支持美化增强 - 在generate_images函数中新增enhance_level参数 - 将美化强度参数传递至SDService.txt2img调用 ♻️ refactor(ui): 优化UI布局和添加美化强度控件 - 注入自定义CSS主题层,优化字体、按钮和卡片样式 - 将全局设置迁移至独立的"⚙️ 配置"Tab,优化Tab顺序 - 在内容创作Tab的高级设置中添加美化强度滑块控件 - 优化自动运营Tab布局,改为2列卡片网格展示
183 lines
6.8 KiB
Python
183 lines
6.8 KiB
Python
"""
|
||
内容创作 Tab UI 模块
|
||
包含 Tab 1「✨ 内容创作」的所有 Gradio 组件定义和事件绑定
|
||
"""
|
||
import gradio as gr
|
||
|
||
|
||
def build_tab(
|
||
config: dict,
|
||
styles: list,
|
||
sd_preset_names: list,
|
||
default_negative: str,
|
||
# 共享的 Gradio 组件(由 main.py 创建并传入)
|
||
llm_model,
|
||
sd_model,
|
||
sd_url,
|
||
persona,
|
||
status_bar,
|
||
face_swap_toggle,
|
||
face_image_preview,
|
||
mcp_url,
|
||
# 业务处理函数(由 main.py 传入,避免循环导入)
|
||
fn_gen_copy,
|
||
fn_gen_img,
|
||
fn_export,
|
||
fn_publish,
|
||
fn_get_sd_preset,
|
||
fn_cfg_set,
|
||
fn_cfg_update,
|
||
):
|
||
"""
|
||
构建「✨ 内容创作」Tab,注册所有事件绑定。
|
||
|
||
Parameters
|
||
----------
|
||
config : 当前配置字典(用于读取初始值)
|
||
styles : 文案风格列表
|
||
sd_preset_names : SD 生成模式名称列表
|
||
default_negative: 默认反向提示词
|
||
llm_model / sd_model / ... : 由全局设置栏创建的共享组件引用
|
||
fn_* : 业务逻辑回调函数
|
||
|
||
Returns
|
||
-------
|
||
None —— 所有事件绑定均在此函数内完成,无需外部再次绑定。
|
||
"""
|
||
with gr.Tab("✨ 内容创作"):
|
||
# 本 Tab 私有的图片状态(不被其他 Tab 使用)
|
||
state_images = gr.State([])
|
||
|
||
with gr.Row():
|
||
# ---- 左栏:输入 ----
|
||
with gr.Column(scale=3):
|
||
gr.Markdown("### 💡 构思")
|
||
topic = gr.Textbox(label="笔记主题", placeholder="例如:优衣库早春穿搭")
|
||
style = gr.Dropdown(
|
||
styles,
|
||
label="风格", value="好物种草",
|
||
)
|
||
btn_gen_copy = gr.Button("✨ 第一步:生成文案", variant="primary")
|
||
|
||
gr.Markdown("---")
|
||
gr.Markdown("### 🎨 绘图参数")
|
||
quality_mode = gr.Radio(
|
||
sd_preset_names,
|
||
label="生成模式",
|
||
value=config.get("quality_mode", "标准 (约1分钟)"),
|
||
info="快速≈30s 标准≈1min 精细≈2-3min (SDXL)",
|
||
)
|
||
with gr.Accordion("高级设置 (覆盖预设)", open=False):
|
||
neg_prompt = gr.Textbox(
|
||
label="反向提示词",
|
||
value=config.get("sd_negative_prompt", default_negative),
|
||
lines=2,
|
||
)
|
||
steps = gr.Slider(8, 50, value=config.get("sd_steps", 20), step=1, label="步数")
|
||
cfg_scale = gr.Slider(1, 15, value=config.get("sd_cfg_scale", 5.5), step=0.5, label="CFG Scale")
|
||
enhance_level = gr.Slider(
|
||
0.0, 2.0,
|
||
value=config.get("enhance_level", 1.0),
|
||
step=0.1,
|
||
label="美化强度",
|
||
info="0=关闭 1=默认 2=强化(锐化+皮肤校色+通透感)",
|
||
)
|
||
btn_gen_img = gr.Button("🎨 第二步:生成图片", variant="primary")
|
||
|
||
# ---- 中栏:文案编辑 ----
|
||
with gr.Column(scale=4):
|
||
gr.Markdown("### 📝 文案编辑")
|
||
res_title = gr.Textbox(
|
||
label="标题",
|
||
interactive=True,
|
||
info="小红书限制 ≤20 字,超出将无法发布",
|
||
)
|
||
res_content = gr.TextArea(
|
||
label="正文 (可手动修改)", lines=12, interactive=True,
|
||
)
|
||
res_prompt = gr.TextArea(
|
||
label="绘图提示词", lines=3, interactive=True,
|
||
)
|
||
res_tags = gr.Textbox(
|
||
label="话题标签 (逗号分隔)", interactive=True,
|
||
placeholder="穿搭, 春季, 好物种草",
|
||
)
|
||
|
||
# ---- 右栏:预览 & 发布 ----
|
||
with gr.Column(scale=3):
|
||
gr.Markdown("### 🖼️ 视觉预览")
|
||
gallery = gr.Gallery(label="AI 生成图片", columns=2, height=300)
|
||
local_images = gr.File(
|
||
label="📁 上传本地图片(可混排)",
|
||
file_count="multiple",
|
||
file_types=["image"],
|
||
)
|
||
|
||
gr.Markdown("### 🚀 发布")
|
||
schedule_time = gr.Textbox(
|
||
label="定时发布 (可选, ISO8601格式)",
|
||
placeholder="如 2026-02-08T18:00:00+08:00,留空=立即发布",
|
||
)
|
||
with gr.Row():
|
||
btn_export = gr.Button("📂 导出本地", variant="secondary")
|
||
btn_publish = gr.Button("🚀 发布到小红书", variant="primary")
|
||
publish_msg = gr.Markdown("")
|
||
|
||
# ---- 事件绑定 ----
|
||
|
||
btn_gen_copy.click(
|
||
fn=fn_gen_copy,
|
||
inputs=[llm_model, topic, style, sd_model, persona],
|
||
outputs=[res_title, res_content, res_prompt, res_tags, status_bar],
|
||
)
|
||
|
||
def save_quality_mode(mode):
|
||
fn_cfg_set("quality_mode", mode)
|
||
p = fn_get_sd_preset(mode)
|
||
return p["steps"], p["cfg_scale"]
|
||
|
||
quality_mode.change(
|
||
fn=save_quality_mode,
|
||
inputs=[quality_mode],
|
||
outputs=[steps, cfg_scale],
|
||
)
|
||
|
||
steps.change(fn=lambda s: fn_cfg_set("sd_steps", s), inputs=[steps], outputs=[])
|
||
cfg_scale.change(fn=lambda c: fn_cfg_set("sd_cfg_scale", c), inputs=[cfg_scale], outputs=[])
|
||
neg_prompt.change(fn=lambda n: fn_cfg_set("sd_negative_prompt", n), inputs=[neg_prompt], outputs=[])
|
||
enhance_level.change(fn=lambda v: fn_cfg_set("enhance_level", v), inputs=[enhance_level], outputs=[])
|
||
|
||
btn_gen_img.click(
|
||
fn=fn_gen_img,
|
||
inputs=[sd_url, res_prompt, neg_prompt, sd_model, steps, cfg_scale,
|
||
face_swap_toggle, face_image_preview, quality_mode, persona,
|
||
enhance_level],
|
||
outputs=[gallery, state_images, status_bar],
|
||
)
|
||
|
||
btn_export.click(
|
||
fn=fn_export,
|
||
inputs=[res_title, res_content, state_images],
|
||
outputs=[publish_msg],
|
||
)
|
||
|
||
btn_publish.click(
|
||
fn=fn_publish,
|
||
inputs=[res_title, res_content, res_tags, state_images,
|
||
local_images, mcp_url, schedule_time],
|
||
outputs=[publish_msg],
|
||
)
|
||
|
||
# 返回可能被其他 Tab 引用的组件
|
||
return {
|
||
"res_title": res_title,
|
||
"res_content": res_content,
|
||
"res_prompt": res_prompt,
|
||
"res_tags": res_tags,
|
||
"quality_mode": quality_mode,
|
||
"steps": steps,
|
||
"cfg_scale": cfg_scale,
|
||
"neg_prompt": neg_prompt,
|
||
"enhance_level": enhance_level,
|
||
}
|