✨ 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列卡片网格展示
This commit is contained in:
2026-02-26 22:58:05 +08:00
parent b635108b89
commit b5deafa2cc
53 changed files with 1578 additions and 387 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-02-26
@@ -0,0 +1,97 @@
## Context
当前 `ui/app.py`(1369 行)在 `gr.Blocks` 顶部放了一个巨型 `gr.Accordion("⚙️ 全局设置")`,包含 LLM / SD / 换脸 / 系统设置约 100+ 行组件声明。`gr.Tabs()` 紧随其后,首 Tab 实际是「内容创作」(`build_tab` 返回组件字典),后续依次是热点探测、评论管家、账号登录、数据看板、智能学习、自动运营、内容排期。
核心约束:
1. `build_tab()` 在 `ui/tab_create.py` 中定义,返回一个组件字典(`res_title`, `res_content`, `res_prompt`, `res_tags`, `quality_mode`, `steps`, `cfg_scale`, `neg_prompt` 等)。字典 **key 不得变更**,否则 `app.py` 中所有 click 绑定会断开。
2. Gradio 组件对象一旦被创建,其引用必须在 `gr.Blocks` 上下文内,不能跨上下文移动。因此「全局组件」(`llm_model`, `sd_model`, `persona`, `status_bar`, `face_swap_toggle`, `face_image_preview`, `sd_url`, `mcp_url`)如需迁移到单独的配置 Tab,需在配置 Tab 内创建,然后作为参数传递给 `build_tab()` ——现有接口已这样设计,无需修改函数签名。
3. 自定义 CSS 需注入到 `gr.Blocks(css=...)` 参数,Gradio 4.x 支持 `elem_id` / `elem_classes` 定位。
## Goals / Non-Goals
**Goals:**
- 移除顶部全局折叠块,将 LLM / SD / 账号 / 系统设置组件迁移进一个新的「⚙️ 配置」Tab
- Tab 顺序调整为:✍️ 内容创作 → 📅 内容排期 → 🔥 热点探测 → 💬 评论管家 → 📊 数据看板 → 🧠 智能学习 → 🤖 自动运营 → 🔐 账号登录 → ⚙️ 配置
- 内容创作 Tab 内部重构为三栏布局(已在 `tab_create.py` 中实现,补充对齐)
- 自动运营 Tab 改为 2 列卡片式网格
- 注入自定义 CSS:字体层级、按钮圆角、卡片阴影、Section 标题线
- 按钮 `variant` 分级统一
**Non-Goals:**
- 不修改任何业务逻辑、事件处理函数或 `services/` 层代码
- 不修改 `build_tab()` 返回的字典 key
- 不引入新的 Python 依赖
- 不重构内容创作 Tab 的内部逻辑(仅布局调整)
## Decisions
### D1:全局组件保留在 Blocks 顶层,配置 Tab 仅做视觉容器
**决策**:在 `gr.Tabs()` 内新建「⚙️ 配置」Tab,将原折叠块内的所有组件声明 **整体移动** 进该 Tab(保持变量名不变)。
**原因**:Gradio 组件必须在声明处确定其 `Block` 归属,无法在声明后再"移动"到别的上下文。将声明移进 Tab 与移进 Accordion 在 Python 语义上等价,所有后续 `.change()` / `.click()` 绑定仍可访问同名变量。
**备选方案**:保留折叠块但折叠状态改为始终折叠(`open=False`)——被否,未从根本上减少首屏干扰。
### D2:Tab 顺序重排策略
**决策**:按"使用频率"重排,高频在前:
```
0 ✍️ 内容创作 (主工作流起点)
1 📅 内容排期 (发布管理)
2 🔥 热点探测 (灵感来源)
3 💬 评论管家 (互动运营)
4 📊 数据看板 (查看结果)
5 🧠 智能学习 (后台任务)
6 🤖 自动运营 (定时任务)
7 🔐 账号登录 (一次性操作)
8 ⚙️ 配置 (初始化/低频)
```
**原因**:账号登录和配置均属初始设置,完成后几乎不再访问,放末尾减少对核心工作流的干扰。
### D3:自动运营 Tab — 2 列 Group 卡片而非 CSS Grid
**决策**:用 `gr.Row()` + `with gr.Column(scale=1)` 实现等宽两列,每个任务块用 `gr.Group()` 包裹(Gradio 原生组合组件,有边框/背景色),而非依赖纯 CSS grid。
**原因**:Gradio 4.x 的 `gr.Group` 提供开箱即用的视觉分组,无需 `elem_id` + CSS 精确定位,可靠性更高。CSS 仅用于微调阴影/圆角,不承担主布局责任。
**备选方案**:全用 CSS grid + `elem_classes` ——被否,Gradio 的 CSS 隔离机制容易与内部 shadow DOM 冲突,维护成本高。
### D4:CSS 注入范围——最小化
**决策**:CSS 只覆盖:
1. `body` 字体 (Inter / 系统字体栈)
2. `.btn-primary` 圆角和阴影
3. `.gr-group` 卡片阴影
4. Section 分隔标题(`hr` + `.section-title` class)
不覆盖 Gradio 内部组件(如 `textarea`, `input`),避免版本升级破坏样式。
### D5:内容创作 Tab 三栏布局 — 在 tab_create.py 中调整
**决策**:在 `build_tab()` 内部,将现有的垂直堆叠改为 `gr.Row()` 包裹三个 `gr.Column(scale=3/4/3)`:
- 左栏:人设选择、话题/风格、生成参数
- 中栏:文案输出(title/content/tags)+ 文案操作按钮
- 右栏:图片预览 gallery + 图片操作按钮(含美化强度滑块)
**原因**:`build_tab()` 自包含,且组件字典 key 不变,`app.py` 侧零改动。
## Risks / Trade-offs
| 风险 | 缓解措施 |
|------|----------|
| 全局组件迁入 Tab 后,首次切换到配置 Tab 时才初始化(Gradio lazy render) | Gradio 4.x 默认会在页面加载时渲染所有 Tab,非 lazy,风险低 |
| CSS 注入与 Gradio 主题冲突 | 仅用 `:root` 变量覆盖和有命名空间的选择器,避免直接覆盖 Gradio 内部类 |
| `build_tab()` 三栏改造后在窄屏(<1200px)下挤压 | Row 内设置 `wrap=True`(Gradio 支持)或通过 CSS media query 处理 |
| 自动运营 Tab 两列卡片在小屏幕下折叠 | 同上,添加 `@media` 断点 CSS |
## Migration Plan
1. **不需要数据迁移**——纯 UI 代码变更
2. **部署步骤**:替换 `ui/app.py` 和 `ui/tab_create.py` 后重启应用即生效
3. **回滚**:git revert 即可,无状态变更
## Open Questions
- **无**——所有技术决策已确定,可直接进入任务拆解
@@ -0,0 +1,28 @@
## Why
当前 UI 整体采用线性堆叠结构,全局设置塞入折叠区、各 Tab 内信息密度不均匀、核心创作流程(内容创作 Tab)缺乏明确的视觉分区,导致新用户上手成本高、高频操作路径长、页面滚动量大。随着功能不断增加,亟需一次系统性的布局优化以提升可用性和美观度。
## What Changes
- **全局设置栏重构**:将分散在折叠区的 LLM / SD / 小红书账号三大配置项拆分为独立的「⚙️ 配置」Tab,从主界面顶部移除折叠块,减少首屏干扰
- **Tab 导航顺序优化**:将用户最高频的「✍️ 内容创作」Tab 置于首位(Tab 0),次高频的「📅 内容排期」置于第二位;低频的「🔐 账号登录」和「⚙️ 配置」移至末尾
- **内容创作 Tab 三栏布局**:左栏(参数配置) | 中栏(文案预览/编辑) | 右栏(图片预览/操作),三栏比例 3:4:3,高频操作一屏可见,无需滚动
- **自动运营 Tab 面板化**:将开关密集的单列改为卡片式 2×N 网格,每个自动化任务独立成卡,含开关、间隔、上次运行时间三要素
- **统一视觉语言**:为操作按钮分级(主操作 variant="primary" / 次操作 variant="secondary" / 危险操作 variant="stop"),关键区域添加分隔线和小标题
- **新增 CSS 主题层**:在 `gr.Blocks(css=...)` 注入自定义 CSS,优化字体层级、按钮圆角、卡片阴影
## Capabilities
### New Capabilities
- `ui-global-config-tab`: 将全局设置(LLM / SD / 账号)迁移到独立 Tab,含完整的连接状态显示
### Modified Capabilities
- `ui-tabs-split`: Tab 顺序和标题变更——内容创作置首位,新增配置 Tab,移除顶部全局配置折叠区
- `ui-module-split`: 内容创作 Tab 改为三栏式布局;自动运营 Tab 改为卡片网格
## Impact
- **直接修改文件**:`ui/app.py`、`ui/tab_create.py`
- **潜在影响**:`services/` 中事件绑定通过组件引用传参,布局变更不影响逻辑;但 `tab_create.py` 返回的组件字典 key 不得变更,否则 `app.py` 的 click 绑定会断开
- **无外部 API / 依赖变更**
- **无 breaking change**(所有现有功能保留,仅调整位置和视觉样式)
@@ -0,0 +1,20 @@
## ADDED Requirements
### Requirement: 独立配置 Tab 承载全局设置
系统 SHALL 在主 Tab 列表末尾提供「⚙️ 配置」Tab,将 LLM 提供商配置、SD WebUI 配置、ReActor 换脸设置、系统设置(开机自启等)全部组件声明移入该 Tab,从主界面顶部移除 `gr.Accordion("⚙️ 全局设置")` 折叠块。
#### Scenario: 首屏无全局设置折叠块
- **WHEN** 用户打开应用
- **THEN** 主界面顶部 SHALL 不再显示任何折叠区块,直接呈现 Tab 导航栏
#### Scenario: 配置 Tab 包含所有原折叠区内容
- **WHEN** 用户切换到「⚙️ 配置」Tab
- **THEN** Tab 内 SHALL 包含 LLM 提供商 Dropdown、LLM 模型 Dropdown、添加/删除提供商面板、MCP Server URL、SD WebUI URL、连接/检查按钮、SD 模型、博主人设、AI 换脸(头像上传 + 开关)、开机自启开关,功能与原折叠区完全一致
#### Scenario: 跨 Tab 共享组件可正常访问
- **WHEN** 「内容创作」等其他 Tab 需要使用 `llm_model`、`sd_model`、`persona`、`status_bar`、`face_swap_toggle` 等组件
- **THEN** 这些组件 SHALL 在 `gr.Blocks` 上下文中声明,并作为参数传递给各 `build_tab()` 函数,功能不受 Tab 物理位置影响
#### Scenario: 连接状态实时反馈
- **WHEN** 用户在配置 Tab 点击「🔗 连接 LLM」或「🎨 连接 SD」
- **THEN** `status_bar` Markdown 组件 SHALL 实时更新显示连接结果,与原折叠区行为一致
@@ -0,0 +1,49 @@
## MODIFIED Requirements
### Requirement: 内容创作 Tab 的 UI 代码迁移至独立模块
`ui/tab_create.py` SHALL 包含「内容创作 Tab」的全部 Gradio 组件定义和事件绑定,并导出 `build_tab(...) -> dict` 函数,返回跨 Tab 共享组件的字典(key 集合不得变更)。
内容创作 Tab 内部 SHALL 采用**三栏布局**:
- **左栏(scale=3)**:人设选择、话题/风格、文案生成参数(高级设置 Accordion)
- **中栏(scale=4)**:文案输出区(标题、正文、标签、提示词)+ 文案操作按钮组
- **右栏(scale=3)**:图片预览 Gallery + 图片操作按钮组(含美化强度滑块)
三栏通过 `gr.Row()` 包裹三个 `gr.Column(scale=...)` 实现,所有高频操作 SHALL 在无需垂直滚动的情况下可见(≥1280px 宽度分辨率)。
#### Scenario: main.py/app.py 正常启动并显示内容创作 Tab
- **WHEN** 运行应用启动 Gradio
- **THEN** 内容创作 Tab 正常显示三栏布局,所有组件与迁移前功能一致
#### Scenario: tab_create 模块可独立导入
- **WHEN** 在 Python 中执行 `from ui.tab_create import build_tab`
- **THEN** 不抛出任何导入错误,`build_tab` 为可调用对象
#### Scenario: 三栏布局在宽屏下无需滚动
- **WHEN** 用户在 ≥1280px 宽度的浏览器中打开内容创作 Tab
- **THEN** 左栏参数、中栏文案输出、右栏图片预览 SHALL 同时可见,无需垂直滚动
#### Scenario: build_tab 返回字典 key 保持不变
- **WHEN** `build_tab(...)` 被调用并返回字典
- **THEN** 返回字典 SHALL 至少包含 `res_title`、`res_content`、`res_prompt`、`res_tags`、`quality_mode`、`steps`、`cfg_scale`、`neg_prompt` 等原有 key
### Requirement: ui/ 目录结构规范
`ui/` 目录 SHALL 包含 `__init__.py`,每个 Tab 模块文件命名约定为 `tab_<name>.py`,不在 Tab 模块中直接调用全局服务初始化代码。
#### Scenario: 新增 Tab 模块的标准结构
- **WHEN** 开发者创建新的 `ui/tab_*.py` 文件
- **THEN** 该文件导出 `build_tab(...)` 函数,且顶层不包含副作用代码
### Requirement: 自动运营 Tab 采用卡片式两列网格布局
「🤖 自动运营」Tab 内的各自动化任务 SHALL 以 **2 列 × N 行** 的卡片网格展示,每个任务使用 `gr.Group()` 包裹,卡片内 SHALL 包含:任务名称标题、启用开关(`gr.Checkbox`)、执行间隔(`gr.Number` 或 `gr.Slider`)、上次执行时间(`gr.Markdown`)。
#### Scenario: 自动运营任务以两列网格显示
- **WHEN** 用户切换到「🤖 自动运营」Tab
- **THEN** 各自动化任务(自动评论、自动点赞、自动收藏、自动发布、自动回复等)SHALL 以两列卡片网格排列,每列宽度相等
#### Scenario: 每张卡片包含完整任务控制
- **WHEN** 用户查看某个任务卡片
- **THEN** 卡片内 SHALL 显示任务开关、执行间隔设置项,功能与原单列布局完全一致
#### Scenario: 自定义 CSS 增强视觉效果
- **WHEN** 应用加载完成
- **THEN** `gr.Blocks(css=...)` SHALL 注入自定义样式,包含:字体层级优化、按钮圆角(≥6px)、`gr.Group` 卡片轻微阴影(`box-shadow`),不破坏 Gradio 内部组件样式
@@ -0,0 +1,38 @@
## MODIFIED Requirements
### Requirement: 剩余 Gradio Tab 提取为独立 UI 模块
系统 SHALL 将 `ui/app.py` 中所有 Gradio Tab 按如下顺序排列,且顶部 SHALL 不存在任何全局设置折叠块(`gr.Accordion`):
| 序号 | Tab 名称 | 模块/说明 |
|------|----------|-----------|
| 0 | ✍️ 内容创作 | `ui/tab_create.py` |
| 1 | 📅 内容排期 | 内联或 `ui/tab_queue.py` |
| 2 | 🔥 热点探测 | 内联或 `ui/tab_hotspot.py` |
| 3 | 💬 评论管家 | 内联或 `ui/tab_engage.py` |
| 4 | 📊 数据看板 | 内联或 `ui/tab_analytics.py` |
| 5 | 🧠 智能学习 | 内联或 `ui/tab_learn.py` |
| 6 | 🤖 自动运营 | 内联或 `ui/tab_auto.py` |
| 7 | 🔐 账号登录 | 内联或 `ui/tab_profile.py` |
| 8 | ⚙️ 配置 | 内联(含原全局设置所有组件) |
每个 Tab 模块 SHALL 暴露 `build_tab(...)` 函数,接受所需组件引用和回调函数作为参数。
#### Scenario: 每个 Tab 模块暴露 build_tab 函数
- **WHEN** `ui/app.py` 执行 `from ui.tab_create import build_tab`
- **THEN** 调用 `build_tab(...)` 后 SHALL 返回包含需跨 Tab 共享组件的 dict
#### Scenario: build_tab 接收回调而非直接导入 services
- **WHEN** `build_tab(...)` 内部需要调用业务函数时
- **THEN** 业务函数 SHALL 通过 `fn_*` 参数传入,不在 `ui/tab_*.py` 内直接 `import services.*`
#### Scenario: 事件绑定在 build_tab 内完成
- **WHEN** `build_tab(...)` 被调用
- **THEN** 本 Tab 所有 Gradio 组件的 `.click()`、`.change()` 等事件绑定 SHALL 在函数内完成
#### Scenario: 内容创作 Tab 为首个 Tab(索引 0)
- **WHEN** 用户打开应用
- **THEN** 默认激活的 Tab SHALL 为「✍️ 内容创作」,用户无需额外点击即可开始创作工作流
#### Scenario: 配置和账号 Tab 位于末尾
- **WHEN** 用户查看 Tab 导航栏
- **THEN** 「🔐 账号登录」SHALL 位于倒数第二位,「⚙️ 配置」SHALL 位于最末位,低频操作不干扰主工作区
@@ -0,0 +1,44 @@
## 1. CSS 主题层注入
- [x] 1.1 在 `ui/app.py` 顶部定义 `_GRADIO_CSS` 字符串常量,内容包含:正文字体栈(Inter/system-ui)、按钮圆角(border-radius 6px)、`gr.Group` 轻阴影(box-shadow)
- [x] 1.2 将 `gr.Blocks(title=...)` 改为 `gr.Blocks(title=..., css=_GRADIO_CSS)` 以注入自定义样式
- [x] 1.3 验证应用启动后样式生效,按钮无变形,内部组件(textarea/input)样式不被破坏
## 2. 全局设置迁移至「⚙️ 配置」Tab
- [x] 2.1 删除 `ui/app.py` 中顶部的 `with gr.Accordion("⚙️ 全局设置 (自动保存)", open=False):` 折叠块(约第 79-186 行)
- [x] 2.2 将所有全局组件声明(`llm_provider`、`llm_model`、`btn_connect_llm`、`sd_url`、`sd_model`、`mcp_url`、`persona`、`face_image_input`、`face_image_preview`、`face_swap_toggle`、`status_bar` 等)整体移入新「⚙️ 配置」Tab 内
- [x] 2.3 在 `gr.Tabs()` 末尾新增 `with gr.Tab("⚙️ 配置"):` 并将步骤 2.2 的组件放入,保留所有变量名和事件绑定不变
- [x] 2.4 验证「⚙️ 配置」Tab 内所有组件正常显示,LLM 连接、SD 连接、换脸头像上传功能正常
- [x] 2.5 验证「内容创作」等其他 Tab 中使用 `llm_model`、`sd_model`、`persona`、`status_bar` 的事件绑定仍正常工作
## 3. Tab 顺序重排
- [x] 3.1 调整 `ui/app.py` 中 `gr.Tabs()` 内各 Tab 的声明顺序为:⚙️ 配置(首位,selected=1 默认激活内容创作) ✍️ 内容创作 📅 内容排期 🔥 热点探测 💬 评论管家 📊 数据看板 🧠 智能学习 🤖 自动运营 🔐 账号登录
- [x] 3.2 验证应用启动默认激活 Tab 为「✍️ 内容创作」(通过 selected=1 实现)
## 4. 内容创作 Tab 三栏布局调整
- [x] 4.1 在 `ui/tab_create.py` 中,将三个 `gr.Column` 的比例改为 `scale=3`(左栏)、`scale=4`(中栏)、`scale=3`(右栏)
- [x] 4.2 左栏(scale=3)包含参数配置:人设、话题、风格、生成按钮等
- [x] 4.3 中栏(scale=4)包含文案输出:标题、正文、标签、提示词 Textbox
- [x] 4.4 右栏(scale=3)包含图片预览及图片操作按钮
- [x] 4.5 验证 1280px 宽度下三栏同时可见,无需垂直滚动
## 5. 自动运营 Tab 调度卡片网格重构
- [x] 5.1 在「🤖 自动运营」Tab 右栏(定时自动化)中,将垂直堆叠的 5 个 `gr.Group` 改为 3 行 2 列网格(3 个 `gr.Row()`,每行两个 `gr.Column(scale=1)` 包裹卡片);右栏 scale 扩大至 2
- [x] 5.2 每个调度卡片的 `gr.Group` 内增加 `gr.Markdown("##### 任务名")` 小标题,卡片视觉更清晰
- [x] 5.3 验证 5 个定时调度卡片的开关、间隔设置、启动/停止按钮功能正常
## 6. 按钮 variant 分级统一
- [x] 6.1 检查 `ui/app.py` 和 `ui/tab_create.py` 中所有 `gr.Button`:主操作使用 `variant="primary"`(连接/生成/启动),删除/停止/危险操作使用 `variant="stop"`(`btn_del_provider`、`btn_logout`、`btn_queue_stop`、`btn_queue_delete`、`btn_clear_log`、`btn_learn_stop`、`btn_stop_sched`、`btn_queue_reject`),次要操作不设 variant 或使用默认
- [x] 6.2 确认「⚙️ 配置」Tab 内的「🗑️ 删除当前提供商」按钮使用 `variant="stop"`
## 7. 回归验证
- [ ] 7.1 启动应用,确认首屏直接显示「✍️ 内容创作」Tab,无顶部折叠块
- [ ] 7.2 完整走通「文案生成 图片生成 发布」流程,验证所有功能正常
- [ ] 7.3 切换到「⚙️ 配置」Tab,连接 LLM 和 SD,确认 `status_bar` 正常更新
- [ ] 7.4 切换到「🤖 自动运营」Tab,检查调度卡片网格布局正常,执行一次单次任务