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