xhs_factory/ui/tab_create.py
zhoujie b5deafa2cc feat(config): 更新模型配置与LLM提示词指南
- 将默认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列卡片网格展示
2026-02-26 22:58:05 +08:00

183 lines
6.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
内容创作 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,
}