✨ 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:
@@ -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**(所有现有功能保留,仅调整位置和视觉样式)
|
||||
+20
@@ -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,检查调度卡片网格布局正常,执行一次单次任务
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-02-25
|
||||
@@ -0,0 +1,86 @@
|
||||
## Context
|
||||
|
||||
当前系统使用 Stable Diffusion WebUI API 生成图片,通过 `sd_service.py` 中的 `SD_MODEL_PROFILES` 静态配置各模型的参数预设(快速/标准/精细三档)和 prompt 增强词。图片生成后经 `anti_detect_postprocess()` 做反 AI 检测后处理。`llm_service.py` 的 `get_sd_prompt_guide()` 向 LLM 提供绘图 Prompt 写作指南。
|
||||
|
||||
**现状痛点:**
|
||||
- 各模型的"精细"档步数(35-40步)和分辨率偏低,SDXL 模型未充分利用 Hires Fix 提升细节
|
||||
- `prompt_prefix` 中的中国人面孔特征词偏弱或措辞泛化(如 `asian girl` 无权重),欧美面孔偏向风险未完全规避
|
||||
- `anti_detect_postprocess` 将噪声扰动与美化处理混在一起,无法独立调节美化强度
|
||||
- LLM Prompt 指南缺少针对人物真实感/中国审美的专项指导词模板
|
||||
|
||||
**约束:**
|
||||
- 不引入新的外部 Python 依赖
|
||||
- Hires Fix 仅对 SDXL 模型启用(SD 1.5 显存不足)
|
||||
- 现有 `txt2img` API 接口签名不做 breaking change,新参数均使用默认值向后兼容
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- 为各模型新增"高画质"预设档,SDXL 启用 Hires Fix 参数
|
||||
- 系统性强化各模型 `prompt_prefix` 中的中国人审美特征词(精致五官、白皙透亮、杏眼、减龄感、中式气质)
|
||||
- 将 `anti_detect_postprocess` 拆分为独立的 `beauty_enhance()` + `anti_detect_postprocess()` 两段,支持通过 `enhance_level` 参数控制美化强度
|
||||
- 扩充 LLM Prompt 指南中的人物真实感描述规则,加入中国审美专项指导词模板
|
||||
- 在 UI 绘图参数面板新增"美化强度"控件,通过 `services/content.py` 传递至后处理管线
|
||||
|
||||
**Non-Goals:**
|
||||
- 不新增 SD 模型支持(不修改模型识别逻辑)
|
||||
- 不做图片超分(Real-ESRGAN 等外部工具)
|
||||
- 不修改 ReActor 换脸逻辑
|
||||
- 不改变发布流程或队列逻辑
|
||||
|
||||
## Decisions
|
||||
|
||||
### 决策 1:Hires Fix 仅对 SDXL 模型启用
|
||||
|
||||
**选择:** 在 `txt2img` payload 中,当模型 `arch == "sdxl"` 且 `quality_mode` 为高画质档时注入 Hires Fix 参数(`enable_hr: true`, `hr_scale: 1.5`, `hr_upscaler: "4x-UltraSharp"`, `denoising_strength: 0.4`)。
|
||||
|
||||
**理由:** SD 1.5 模型显存通常不足以做 Hires Fix,SDXL 的 832×1216 基础分辨率放大 1.5x 可达 1248×1824,大幅提升皮肤/五官细节,代价是生成时间增加约 50%。
|
||||
|
||||
**替代方案:** 后处理做 PIL 超分 → 效果差、无 AI 重绘细节;全模型启用 → 触发 SD 1.5 OOM 风险。
|
||||
|
||||
---
|
||||
|
||||
### 决策 2:beauty_enhance 作为独立函数,enhance_level 控制强度
|
||||
|
||||
**选择:** 将原 `anti_detect_postprocess` 中的美化逻辑(锐化、色彩增强)抽取为 `beauty_enhance(img, level: float = 1.0) -> Image`,`level=0` 跳过,`level=1` 为默认,`level=2` 为强化。`anti_detect_postprocess` 保持仅做扰动逻辑,调用顺序:`beauty_enhance → anti_detect_postprocess`。
|
||||
|
||||
**理由:** 当前两者混在同一函数中,美化参数硬编码无法从 UI 调节;分离后可独立测试,且 UI 控件可直接映射到 `enhance_level`。
|
||||
|
||||
**替代方案:** 在 `anti_detect_postprocess` 中增加 flag 参数 → 函数职责混乱,不符合单一职责原则。
|
||||
|
||||
---
|
||||
|
||||
### 决策 3:中国审美词以"权重词组"方式注入 prompt_prefix
|
||||
|
||||
**选择:** 在各模型 `prompt_prefix` 中为中国人面孔特征词加入权重括号,如 `(almond eyes:1.2)`, `(delicate nose:1.1)`, `(porcelain skin:1.2)`, `(youthful appearance:1.1)`, `(chinese beauty:1.2)`,同时在 `negative_prompt` 中补充 `deep-set eyes, strong jawline, prominent brow ridge` 等欧美特征排除词。
|
||||
|
||||
**理由:** SD 权重词是最直接有效的方式;不引入新依赖;各模型独立配置可针对其风格微调权重值。
|
||||
|
||||
---
|
||||
|
||||
### 决策 4:LLM Prompt 指南新增中国审美人物描述模板
|
||||
|
||||
**选择:** 在 `get_sd_prompt_guide()` 中新增"人物描述词库"段落,按五官/肤色/气质/发型四个维度分别给出推荐词,并加一条规则:描述人物时优先从该词库选词,禁用 `beautiful girl` 等无导向泛化词。
|
||||
|
||||
**理由:** LLM 倾向于使用泛化美感词,不加约束时易生成欧美审美偏向的描述,规则化词库可强制对齐目标审美。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **[风险] Hires Fix 生成时间大幅增加** → 缓解:仅在新增"极致 (约5分钟)"档才默认开启,其他档保持原速;UI 标注预计用时
|
||||
- **[风险] 中国审美词过强导致所有图片千人一面** → 缓解:权重控制在 1.1-1.2 之间,不超过 1.3;`PERSONA_SD_PROFILES` 各人设保留差异化风格词
|
||||
- **[风险] beauty_enhance 引入 numpy 依赖(实际已存在)** → 无风险,现有代码已 `import numpy`
|
||||
- **[Trade-off] enhance_level UI 控件增加 UI 复杂度** → 接受:放在"高级设置"面板折叠区,不影响主流程
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. 修改 `sd_service.py`:更新各模型 `prompt_prefix`/`negative_prompt`,新增高画质预设,拆分 `beauty_enhance`
|
||||
2. 修改 `llm_service.py`:更新 `get_sd_prompt_guide()` 指南内容
|
||||
3. 修改 `services/content.py`:`generate_images` 新增 `enhance_level` 参数(默认 `1.0`,向后兼容)
|
||||
4. 修改 `ui/tab_create.py`:在"高级设置"中新增"美化强度"滑块,范围 0.0-2.0,默认 1.0
|
||||
|
||||
无数据库迁移,无配置文件格式变更。回滚:git revert 即可。
|
||||
|
||||
## Open Questions
|
||||
|
||||
- Hires Fix 的 `hr_upscaler` 在用户环境中是否普遍可用(需确认 "4x-UltraSharp" 模型是否已下载);若不存在应降级为 "Latent" 作为 fallback
|
||||
- `beauty_enhance` 的最优参数值(锐化半径、色彩增益系数)需在实际出图中调试确认
|
||||
@@ -0,0 +1,31 @@
|
||||
## Why
|
||||
|
||||
当前图片生成管线存在两个核心问题:一是 SD 参数预设偏保守(步数少、CFG 偏低),LLM 绘图 Prompt 对真实感与美感的引导词不够精准,后处理未做美化增强直接引入扰动,导致出图偏平、细节不足;二是人物面孔与气质的正向引导词缺乏针对中国审美的专项优化(精致五官、白皙透亮肤色、杏眼桃花眼、减龄气质、中式温柔感等小红书目标用户偏好特征),导致生成人物不够符合用户审美认同。现在正是系统内容数量稳定增长、需要提升质量口碑与用户共鸣的时机。
|
||||
|
||||
## What Changes
|
||||
|
||||
- 新增"高画质"生成预设,提升各模型的步数、采样器(DPM++ 2M SDE Karras 等),增加 Hires Fix / 放大修复支持
|
||||
- 优化 LLM 生成绘图 Prompt 的系统指导词,注入更多真实感/光影/皮肤细节关键词,区分人物与场景图风格指导
|
||||
- 在各模型 `prompt_prefix` 与 `PERSONA_SD_PROFILES` 中系统性强化中国人审美特征词(精致五官、白皙透亮、杏眼/桃花眼、减龄感、中式气质),并剔除容易偏向欧美面孔的泛化词
|
||||
- 将后处理管线拆解为"美化增强"(锐化、肤色修正、色彩提升)→ "反 AI 检测扰动"两个独立阶段,确保美化先于扰动执行
|
||||
- 在 `services/content.py` 的 `generate_images` 调用链中暴露"美化强度"参数,传递至后处理管线
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `image-quality-presets`:各 SD 模型的高画质预设参数(高步数、高分辨率、Hires Fix 支持),以及预设选择逻辑优化
|
||||
- `image-post-enhancement`:生成后专用美化增强管线(智能锐化、肤色色调微调、饱和度提升),在反 AI 扰动之前执行
|
||||
- `llm-prompt-aesthetics`:LLM 绘图 Prompt 生成指南的美感/真实感强化规则,针对人物与场景分别给出增强词模板
|
||||
- `chinese-aesthetic-profile`:针对中国审美偏好的人物面孔与气质关键词体系,包含模型级 `prompt_prefix` 增强词库和各人设档位的面孔风格词,覆盖"精致五官、白皙透亮、减龄感、中式气质"等维度
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
(无现有 spec 涉及图片生成质量,无需修改现有 spec)
|
||||
|
||||
## Impact
|
||||
|
||||
- **`sd_service.py`**:`SD_MODEL_PROFILES` 各模型的 `presets` 字段(新增高画质档)、`prompt_prefix`/`negative_prompt`(中国审美词优化)、`PERSONA_SD_PROFILES` 各人设的 `prompt_boost`(面孔风格词强化)、`txt2img` 方法(Hires Fix 参数注入)、`anti_detect_postprocess`(拆分为 beauty_enhance + anti_detect 两段)
|
||||
- **`llm_service.py`**:`get_sd_prompt_guide()` 方法中的系统指导词内容(含中国审美人物描述指南)
|
||||
- **`services/content.py`**:`generate_images()` 函数签名新增 `enhance_level` 参数
|
||||
- **`ui/tab_create.py`**:绘图参数面板新增"美化强度"滑块控件
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 各 SD 模型 prompt_prefix 包含中国审美面孔特征词
|
||||
系统 SHALL 在 `SD_MODEL_PROFILES` 每个模型的 `prompt_prefix` 中包含以下中国审美特征词(具体权重值由各模型风格微调,但不得省略):
|
||||
- 眼型:`(almond eyes:1.2)` 或 `(delicate almond-shaped eyes:1.2)`
|
||||
- 肤色:`(porcelain skin:1.2)` 或 `(fair porcelain skin:1.2)` 或 `(luminous fair skin:1.2)`
|
||||
- 五官精致感:`(delicate facial features:1.2)` 或 `(refined features:1.2)`
|
||||
- 气质:`(youthful appearance:1.1)` 或 `(elegant temperament:1.1)`
|
||||
|
||||
#### Scenario: 生成的人物图像呈现中国大众偏好的精致感
|
||||
- **WHEN** 使用任意 SD 模型生成含人物的图片
|
||||
- **THEN** `prompt_prefix` 中包含杏眼、白皙肤色、精致五官三类词汇中各至少一个
|
||||
|
||||
### Requirement: 各 SD 模型 negative_prompt 补充欧美面孔排除词
|
||||
系统 SHALL 在 `SD_MODEL_PROFILES` 每个模型的 `negative_prompt` 中包含以下欧美面孔特征排除词(在现有基础上补充):
|
||||
- `strong jawline`、`prominent brow ridge`、`deep-set eyes`(如已存在则保留权重)
|
||||
- `angular facial structure`、`square jaw`、`heavy brow`
|
||||
|
||||
#### Scenario: negative_prompt 明确排除欧美面孔结构特征
|
||||
- **WHEN** 任意模型进行人物图片生成
|
||||
- **THEN** negative_prompt 中包含 `strong jawline`、`prominent brow ridge`、`deep-set eyes` 至少两个排除词
|
||||
|
||||
### Requirement: PERSONA_SD_PROFILES 各人设包含中式气质差异化增强词
|
||||
系统 SHALL 在 `PERSONA_SD_PROFILES` 中,每个人设的 `prompt_boost` 包含至少 1 个与中国审美相关的气质词,且各人设之间的气质词须有差异化区分(如:甜妹-减龄感、知性-优雅气质、赛博博主-精致感 + 未来感)。
|
||||
|
||||
#### Scenario: 不同人设生成的人物具有可感知的气质差异
|
||||
- **WHEN** 分别以"甜妹"和"知性"人设各生成一批图片
|
||||
- **THEN** 两批图片中 `prompt_boost` 的核心气质词不重复,体现差异化风格
|
||||
|
||||
### Requirement: 美化增强对肤色偏向做修正
|
||||
`beauty_enhance()` 函数 SHALL 在饱和度提升时对色调偏暖方向微调(暖白/自然肤色),避免饱和度提升导致肤色偏黄或偏红。具体实现通过调整 PIL 色调(Hue)向暖白方向 ±5° 以内微调。
|
||||
|
||||
#### Scenario: 美化后肤色不发黄不发红
|
||||
- **WHEN** 调用 `beauty_enhance(img, level=1.0)` 对含人物的图片处理
|
||||
- **THEN** 输出图片肤色区域饱和度提升的同时,色调保持在自然暖白范围内(目视无偏黄/偏红现象)
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: beauty_enhance 作为独立美化增强函数
|
||||
系统 SHALL 在 `sd_service.py` 中提供 `beauty_enhance(img: Image.Image, level: float = 1.0) -> Image.Image` 函数,支持以下增强操作(所有操作的强度随 `level` 线性缩放):
|
||||
- 智能锐化(基于 `ImageFilter.UnsharpMask`,强调五官轮廓与发丝细节)
|
||||
- 亮度与对比度微增(`level=1.0` 时各 +2-3%,`level=2.0` 时各 +4-6%)
|
||||
- 饱和度提升(`level=1.0` 时 +5%,`level=2.0` 时 +10%,令肤色更均匀饱满)
|
||||
- `level=0` 时 SHALL 直接返回原图,跳过所有处理
|
||||
|
||||
#### Scenario: 正常调用增强管线
|
||||
- **WHEN** 调用 `beauty_enhance(img, level=1.0)`
|
||||
- **THEN** 返回经过锐化、亮度微调、饱和度提升处理的 PIL Image,图片尺寸不变
|
||||
|
||||
#### Scenario: level=0 时跳过处理
|
||||
- **WHEN** 调用 `beauty_enhance(img, level=0)`
|
||||
- **THEN** 直接返回原始 img 对象,不执行任何增强操作
|
||||
|
||||
#### Scenario: level=2 时增强效果加倍
|
||||
- **WHEN** 调用 `beauty_enhance(img, level=2.0)`
|
||||
- **THEN** 锐化、亮度、饱和度的调整幅度均为 level=1.0 时的 2 倍
|
||||
|
||||
### Requirement: 后处理管线顺序为美化先于反 AI 扰动
|
||||
系统 SHALL 在 `txt2img` 和 `img2img` 生成流程中,对每张输出图片依次执行:`beauty_enhance(img, level) → anti_detect_postprocess(img)`,确保美化增强在扰动引入之前完成。
|
||||
|
||||
#### Scenario: 生成图片经过完整两阶段后处理
|
||||
- **WHEN** `txt2img` 成功生成图片
|
||||
- **THEN** 每张图片先经过 `beauty_enhance`,再经过 `anti_detect_postprocess`,最终返回给调用方
|
||||
|
||||
### Requirement: enhance_level 参数从 UI 传递至后处理管线
|
||||
系统 SHALL 支持 `enhance_level: float` 参数从 Gradio UI 经 `services/content.py` 的 `generate_images()` 函数传递至 `SDService.txt2img()`,最终传入 `beauty_enhance()`。新参数默认值为 `1.0`,向后兼容。
|
||||
|
||||
#### Scenario: UI 美化强度滑块值传递到生成结果
|
||||
- **WHEN** 用户在"高级设置"中将美化强度滑块调整为 2.0 并点击生成
|
||||
- **THEN** 生成图片经过 `beauty_enhance(img, level=2.0)` 处理
|
||||
|
||||
#### Scenario: 旧调用方不传 enhance_level 时行为不变
|
||||
- **WHEN** `generate_images()` 未传入 `enhance_level` 参数
|
||||
- **THEN** 默认使用 `level=1.0`,行为与优化前相同
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 各 SD 模型新增高画质预设档
|
||||
系统 SHALL 在 `SD_MODEL_PROFILES` 的每个模型 `presets` 字典中新增 `"高画质 (约5分钟)"` 档位,参数须满足:SD 1.5 模型步数 ≥ 50、CFG 6.5-7.5、采样器为 `DPM++ SDE`;SDXL 模型步数 ≥ 40、CFG 5.5-6.5、采样器为 `DPM++ 2M SDE`,并启用 Hires Fix 参数(`enable_hr: true`)。
|
||||
|
||||
#### Scenario: 用户选择高画质档后生成请求包含 Hires Fix
|
||||
- **WHEN** 用户将质量模式切换为"高画质 (约5分钟)"且当前模型为 SDXL 架构
|
||||
- **THEN** `txt2img` API 请求 payload 中包含 `enable_hr: true`、`hr_scale: 1.5`、`hr_upscaler` 字段
|
||||
|
||||
#### Scenario: SD 1.5 模型高画质档不启用 Hires Fix
|
||||
- **WHEN** 用户将质量模式切换为"高画质 (约5分钟)"且当前模型 `arch == "sd15"`
|
||||
- **THEN** payload 中不含 `enable_hr` 字段,以避免 OOM
|
||||
|
||||
#### Scenario: Hires Fix upscaler 不存在时降级
|
||||
- **WHEN** `hr_upscaler` 指定的放大器模型(如 "4x-UltraSharp")在 SD WebUI 中不可用
|
||||
- **THEN** 系统 SHALL 自动降级为 `"Latent"` 作为 fallback,并通过日志记录警告
|
||||
|
||||
### Requirement: 预设名称在 UI 中按模型动态更新
|
||||
系统 SHALL 在用户切换 SD 模型后,更新 UI 质量模式单选按钮的选项列表,使其始终反映当前模型的可用预设档名称。
|
||||
|
||||
#### Scenario: 切换模型后预设列表刷新
|
||||
- **WHEN** 用户在连接设置中切换 SD 模型
|
||||
- **THEN** 创作页"生成模式"单选按钮的选项 SHALL 更新为该模型 `presets` 中的键名列表
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: LLM Prompt 指南包含人物真实感描述规则
|
||||
`get_sd_prompt_guide()` 返回的指南 SHALL 包含"人物描述规则"段落,内容要求:
|
||||
- 明确禁止使用 `beautiful girl`、`pretty woman`、`good looking` 等无导向泛化词
|
||||
- 要求从五官(眼型、鼻型、唇型)、肤色(白皙、透亮、均匀)、气质(减龄、温柔、知性)三个维度分别提供具体描述词
|
||||
- 对于有人物的 Prompt,要求至少包含 2 个五官/肤色词和 1 个气质词
|
||||
|
||||
#### Scenario: LLM 生成含人物的 Prompt 时使用规范词汇
|
||||
- **WHEN** LLM 根据指南生成包含人物描述的 SD Prompt
|
||||
- **THEN** Prompt 中不含 `beautiful`、`pretty`、`good looking` 等泛化词,而是包含如 `almond eyes`、`porcelain skin`、`youthful appearance` 等具体描述词
|
||||
|
||||
### Requirement: LLM Prompt 指南区分人物图与纯场景图的写作策略
|
||||
`get_sd_prompt_guide()` 返回的指南 SHALL 明确区分两种写作模式:人物主体图(需详细描述人物特征)和纯场景/物品图(无需人物词,优先描述氛围、色彩、光线)。
|
||||
|
||||
#### Scenario: 生成场景图 Prompt 时不误加人物词
|
||||
- **WHEN** 文案主题为室内布置或产品展示(无人物)
|
||||
- **THEN** LLM 生成的 Prompt 中不包含人物特征描述词
|
||||
|
||||
#### Scenario: 生成人物图 Prompt 时包含完整人物描述
|
||||
- **WHEN** 文案主题为穿搭、美妆或生活场景(含人物)
|
||||
- **THEN** LLM 生成的 Prompt 中包含五官、肤色、气质三个维度的描述词各至少 1 个
|
||||
|
||||
### Requirement: LLM Prompt 指南包含光影与摄影感描述规范
|
||||
`get_sd_prompt_guide()` 返回的指南 SHALL 包含光影描述规则,要求生成 Prompt 时指定具体光源类型(如 `soft window light`、`golden hour`、`studio lighting`)而非泛化词(如 `good lighting`)。
|
||||
|
||||
#### Scenario: Prompt 中包含具体光影词而非泛化词
|
||||
- **WHEN** LLM 根据指南生成 SD Prompt
|
||||
- **THEN** Prompt 中包含 `soft window light`、`golden hour`、`studio lighting`、`diffused natural light` 等具体光影词之一
|
||||
@@ -0,0 +1,50 @@
|
||||
## 1. sd_service.py — 中国审美词优化
|
||||
|
||||
- [x] 1.1 更新 `majicmixRealistic` 模型 `prompt_prefix`:添加 `(almond eyes:1.2)`、`(porcelain skin:1.2)`、`(youthful appearance:1.1)`,确保 `delicate facial features` 带权重
|
||||
- [x] 1.2 更新 `realisticVision` 模型 `prompt_prefix`:添加 `(almond eyes:1.1)`、`(luminous fair skin:1.2)`、`(refined features:1.2)`、`(elegant temperament:1.1)`
|
||||
- [x] 1.3 更新 `juggernautXL` 模型 `prompt_prefix`:添加 `(almond eyes:1.2)`、`(porcelain skin:1.2)`、`(delicate facial features:1.2)`、`(youthful appearance:1.1)`,`asian girl` 改为 `(chinese beauty:1.2)`
|
||||
- [x] 1.4 在三个模型 `negative_prompt` 中补充 `strong jawline, prominent brow ridge, angular facial structure, square jaw, heavy brow`
|
||||
- [x] 1.5 更新各 `PERSONA_SD_PROFILES` 人设的 `prompt_boost`:确保每个人设包含至少 1 个与中国审美相关的差异化气质词(甜妹-减龄感、知性-优雅气质、赛博博主-精致感 + 未来感等)
|
||||
|
||||
## 2. sd_service.py — 高画质预设与 Hires Fix
|
||||
|
||||
- [x] 2.1 在 `majicmixRealistic` `presets` 中新增 `"高画质 (约5分钟)"`:steps=50, cfg_scale=7.0, width=640, height=960, sampler="DPM++ SDE", scheduler="Karras", batch_size=1
|
||||
- [x] 2.2 在 `realisticVision` `presets` 中新增 `"高画质 (约5分钟)"`:steps=50, cfg_scale=7.0, width=640, height=960, sampler="DPM++ SDE", scheduler="Karras", batch_size=1
|
||||
- [x] 2.3 在 `juggernautXL` `presets` 中新增 `"高画质 (约5分钟)"`:steps=40, cfg_scale=6.0, width=832, height=1216, sampler="DPM++ 2M SDE", scheduler="Karras", batch_size=1,并增加 `enable_hr: True, hr_scale: 1.5, hr_upscaler: "4x-UltraSharp", hr_second_pass_steps: 20, denoising_strength: 0.4`
|
||||
- [x] 2.4 在 `txt2img` 方法中:当 preset 包含 `enable_hr` 字段时,将该字段注入 SD API payload;当架构为 sd15 时强制忽略 `enable_hr`
|
||||
- [x] 2.5 添加 Hires Fix upscaler fallback 逻辑:捕获 SD API 返回的 upscaler 不存在错误,降级为 `"Latent"` 并记录 warning 日志
|
||||
|
||||
## 3. sd_service.py — 美化增强管线拆分
|
||||
|
||||
- [x] 3.1 新增 `beauty_enhance(img: Image.Image, level: float = 1.0) -> Image.Image` 函数:`level=0` 时直接返回原图
|
||||
- [x] 3.2 实现 `beauty_enhance` 锐化逻辑:使用 `ImageFilter.UnsharpMask(radius=1.5*level, percent=int(120*level), threshold=2)`
|
||||
- [x] 3.3 实现 `beauty_enhance` 亮度/对比度/饱和度增强:亮度系数 `1.0 + 0.02*level`,对比度系数 `1.0 + 0.02*level`,饱和度系数 `1.0 + 0.05*level`
|
||||
- [x] 3.4 实现 `beauty_enhance` 暖白肤色微调:对皮肤色调区域做降红提蓝校正(numpy 实现,无 numpy 时跳过)
|
||||
- [x] 3.5 修改 `txt2img` 方法:在 `anti_detect_postprocess(img)` 调用前插入 `beauty_enhance(img, level=enhance_level)`,`enhance_level` 参数从方法签名传入(默认 `1.0`)
|
||||
- [x] 3.6 修改 `img2img` 方法:同样应用 `beauty_enhance → anti_detect_postprocess` 两阶段后处理
|
||||
|
||||
## 4. llm_service.py — Prompt 指南优化
|
||||
|
||||
- [x] 4.1 在 `get_sd_prompt_guide()` 中添加"人物描述规则"段落:明确禁止 `beautiful girl`/`pretty woman`/`good looking` 等泛化词
|
||||
- [x] 4.2 在指南中添加五官/肤色/气质三维度词库:眼型推荐词(`almond eyes`, `phoenix eyes`, `bright doe eyes`)、肤色推荐词(`porcelain skin`, `luminous fair skin`, `translucent skin`)、气质推荐词(`youthful`, `elegant temperament`, `gentle charm`, `intellectual beauty`)
|
||||
- [x] 4.3 在指南中添加人物图 vs 纯场景图写作策略区分说明
|
||||
- [x] 4.4 在指南中添加光影具体描述规范:要求使用 `soft window light`/`golden hour`/`studio lighting`/`diffused natural light` 等词,禁用 `good lighting`
|
||||
|
||||
## 5. services/content.py — 参数传递
|
||||
|
||||
- [x] 5.1 为 `generate_images()` 函数增加 `enhance_level: float = 1.0` 参数
|
||||
- [x] 5.2 将 `enhance_level` 传入 `svc.txt2img()` 调用
|
||||
|
||||
## 6. ui/tab_create.py — UI 控件
|
||||
|
||||
- [x] 6.1 在"高级设置 (覆盖预设)"折叠面板中新增 `enhance_level` 滑块:`gr.Slider(0.0, 2.0, value=1.0, step=0.1, label="美化强度", info="0=关闭 1=默认 2=强化")`
|
||||
- [x] 6.2 将 `enhance_level` 滑块值存入配置(`fn_cfg_set("enhance_level", ...)`)并在加载时读取
|
||||
- [x] 6.3 将 `enhance_level` 加入 `btn_gen_img.click` 的 `inputs` 列表,并更新 `fn_gen_img` 函数签名
|
||||
|
||||
## 7. 验证与测试
|
||||
|
||||
- [ ] 7.1 生成含人物的测试图片:确认 `majicmixRealistic` 和 `juggernautXL` 输出人物具有明显中国面孔特征
|
||||
- [ ] 7.2 测试高画质档:SDXL 模型 API payload 中确认包含 `enable_hr: true`
|
||||
- [ ] 7.3 测试 `beauty_enhance(img, level=0)` 返回原图不变
|
||||
- [ ] 7.4 测试 `beauty_enhance(img, level=2.0)` 效果目视无偏黄/偏红
|
||||
- [ ] 7.5 验证 `generate_images()` 不传 `enhance_level` 时行为与修改前一致(回归测试)
|
||||
@@ -0,0 +1,35 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 各 SD 模型 prompt_prefix 包含中国审美面孔特征词
|
||||
系统 SHALL 在 `SD_MODEL_PROFILES` 每个模型的 `prompt_prefix` 中包含以下中国审美特征词(具体权重值由各模型风格微调,但不得省略):
|
||||
- 眼型:`(almond eyes:1.2)` 或 `(delicate almond-shaped eyes:1.2)`
|
||||
- 肤色:`(porcelain skin:1.2)` 或 `(fair porcelain skin:1.2)` 或 `(luminous fair skin:1.2)`
|
||||
- 五官精致感:`(delicate facial features:1.2)` 或 `(refined features:1.2)`
|
||||
- 气质:`(youthful appearance:1.1)` 或 `(elegant temperament:1.1)`
|
||||
|
||||
#### Scenario: 生成的人物图像呈现中国大众偏好的精致感
|
||||
- **WHEN** 使用任意 SD 模型生成含人物的图片
|
||||
- **THEN** `prompt_prefix` 中包含杏眼、白皙肤色、精致五官三类词汇中各至少一个
|
||||
|
||||
### Requirement: 各 SD 模型 negative_prompt 补充欧美面孔排除词
|
||||
系统 SHALL 在 `SD_MODEL_PROFILES` 每个模型的 `negative_prompt` 中包含以下欧美面孔特征排除词(在现有基础上补充):
|
||||
- `strong jawline`、`prominent brow ridge`、`deep-set eyes`(如已存在则保留权重)
|
||||
- `angular facial structure`、`square jaw`、`heavy brow`
|
||||
|
||||
#### Scenario: negative_prompt 明确排除欧美面孔结构特征
|
||||
- **WHEN** 任意模型进行人物图片生成
|
||||
- **THEN** negative_prompt 中包含 `strong jawline`、`prominent brow ridge`、`deep-set eyes` 至少两个排除词
|
||||
|
||||
### Requirement: PERSONA_SD_PROFILES 各人设包含中式气质差异化增强词
|
||||
系统 SHALL 在 `PERSONA_SD_PROFILES` 中,每个人设的 `prompt_boost` 包含至少 1 个与中国审美相关的气质词,且各人设之间的气质词须有差异化区分(如:甜妹-减龄感、知性-优雅气质、赛博博主-精致感 + 未来感)。
|
||||
|
||||
#### Scenario: 不同人设生成的人物具有可感知的气质差异
|
||||
- **WHEN** 分别以"甜妹"和"知性"人设各生成一批图片
|
||||
- **THEN** 两批图片中 `prompt_boost` 的核心气质词不重复,体现差异化风格
|
||||
|
||||
### Requirement: 美化增强对肤色偏向做修正
|
||||
`beauty_enhance()` 函数 SHALL 在饱和度提升时对色调偏暖方向微调(暖白/自然肤色),避免饱和度提升导致肤色偏黄或偏红。具体实现通过调整 PIL 色调(Hue)向暖白方向 ±5° 以内微调。
|
||||
|
||||
#### Scenario: 美化后肤色不发黄不发红
|
||||
- **WHEN** 调用 `beauty_enhance(img, level=1.0)` 对含人物的图片处理
|
||||
- **THEN** 输出图片肤色区域饱和度提升的同时,色调保持在自然暖白范围内(目视无偏黄/偏红现象)
|
||||
@@ -0,0 +1,38 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: beauty_enhance 作为独立美化增强函数
|
||||
系统 SHALL 在 `sd_service.py` 中提供 `beauty_enhance(img: Image.Image, level: float = 1.0) -> Image.Image` 函数,支持以下增强操作(所有操作的强度随 `level` 线性缩放):
|
||||
- 智能锐化(基于 `ImageFilter.UnsharpMask`,强调五官轮廓与发丝细节)
|
||||
- 亮度与对比度微增(`level=1.0` 时各 +2-3%,`level=2.0` 时各 +4-6%)
|
||||
- 饱和度提升(`level=1.0` 时 +5%,`level=2.0` 时 +10%,令肤色更均匀饱满)
|
||||
- `level=0` 时 SHALL 直接返回原图,跳过所有处理
|
||||
|
||||
#### Scenario: 正常调用增强管线
|
||||
- **WHEN** 调用 `beauty_enhance(img, level=1.0)`
|
||||
- **THEN** 返回经过锐化、亮度微调、饱和度提升处理的 PIL Image,图片尺寸不变
|
||||
|
||||
#### Scenario: level=0 时跳过处理
|
||||
- **WHEN** 调用 `beauty_enhance(img, level=0)`
|
||||
- **THEN** 直接返回原始 img 对象,不执行任何增强操作
|
||||
|
||||
#### Scenario: level=2 时增强效果加倍
|
||||
- **WHEN** 调用 `beauty_enhance(img, level=2.0)`
|
||||
- **THEN** 锐化、亮度、饱和度的调整幅度均为 level=1.0 时的 2 倍
|
||||
|
||||
### Requirement: 后处理管线顺序为美化先于反 AI 扰动
|
||||
系统 SHALL 在 `txt2img` 和 `img2img` 生成流程中,对每张输出图片依次执行:`beauty_enhance(img, level) → anti_detect_postprocess(img)`,确保美化增强在扰动引入之前完成。
|
||||
|
||||
#### Scenario: 生成图片经过完整两阶段后处理
|
||||
- **WHEN** `txt2img` 成功生成图片
|
||||
- **THEN** 每张图片先经过 `beauty_enhance`,再经过 `anti_detect_postprocess`,最终返回给调用方
|
||||
|
||||
### Requirement: enhance_level 参数从 UI 传递至后处理管线
|
||||
系统 SHALL 支持 `enhance_level: float` 参数从 Gradio UI 经 `services/content.py` 的 `generate_images()` 函数传递至 `SDService.txt2img()`,最终传入 `beauty_enhance()`。新参数默认值为 `1.0`,向后兼容。
|
||||
|
||||
#### Scenario: UI 美化强度滑块值传递到生成结果
|
||||
- **WHEN** 用户在"高级设置"中将美化强度滑块调整为 2.0 并点击生成
|
||||
- **THEN** 生成图片经过 `beauty_enhance(img, level=2.0)` 处理
|
||||
|
||||
#### Scenario: 旧调用方不传 enhance_level 时行为不变
|
||||
- **WHEN** `generate_images()` 未传入 `enhance_level` 参数
|
||||
- **THEN** 默认使用 `level=1.0`,行为与优化前相同
|
||||
@@ -0,0 +1,23 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 各 SD 模型新增高画质预设档
|
||||
系统 SHALL 在 `SD_MODEL_PROFILES` 的每个模型 `presets` 字典中新增 `"高画质 (约5分钟)"` 档位,参数须满足:SD 1.5 模型步数 ≥ 50、CFG 6.5-7.5、采样器为 `DPM++ SDE`;SDXL 模型步数 ≥ 40、CFG 5.5-6.5、采样器为 `DPM++ 2M SDE`,并启用 Hires Fix 参数(`enable_hr: true`)。
|
||||
|
||||
#### Scenario: 用户选择高画质档后生成请求包含 Hires Fix
|
||||
- **WHEN** 用户将质量模式切换为"高画质 (约5分钟)"且当前模型为 SDXL 架构
|
||||
- **THEN** `txt2img` API 请求 payload 中包含 `enable_hr: true`、`hr_scale: 1.5`、`hr_upscaler` 字段
|
||||
|
||||
#### Scenario: SD 1.5 模型高画质档不启用 Hires Fix
|
||||
- **WHEN** 用户将质量模式切换为"高画质 (约5分钟)"且当前模型 `arch == "sd15"`
|
||||
- **THEN** payload 中不含 `enable_hr` 字段,以避免 OOM
|
||||
|
||||
#### Scenario: Hires Fix upscaler 不存在时降级
|
||||
- **WHEN** `hr_upscaler` 指定的放大器模型(如 "4x-UltraSharp")在 SD WebUI 中不可用
|
||||
- **THEN** 系统 SHALL 自动降级为 `"Latent"` 作为 fallback,并通过日志记录警告
|
||||
|
||||
### Requirement: 预设名称在 UI 中按模型动态更新
|
||||
系统 SHALL 在用户切换 SD 模型后,更新 UI 质量模式单选按钮的选项列表,使其始终反映当前模型的可用预设档名称。
|
||||
|
||||
#### Scenario: 切换模型后预设列表刷新
|
||||
- **WHEN** 用户在连接设置中切换 SD 模型
|
||||
- **THEN** 创作页"生成模式"单选按钮的选项 SHALL 更新为该模型 `presets` 中的键名列表
|
||||
@@ -0,0 +1,29 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: LLM Prompt 指南包含人物真实感描述规则
|
||||
`get_sd_prompt_guide()` 返回的指南 SHALL 包含"人物描述规则"段落,内容要求:
|
||||
- 明确禁止使用 `beautiful girl`、`pretty woman`、`good looking` 等无导向泛化词
|
||||
- 要求从五官(眼型、鼻型、唇型)、肤色(白皙、透亮、均匀)、气质(减龄、温柔、知性)三个维度分别提供具体描述词
|
||||
- 对于有人物的 Prompt,要求至少包含 2 个五官/肤色词和 1 个气质词
|
||||
|
||||
#### Scenario: LLM 生成含人物的 Prompt 时使用规范词汇
|
||||
- **WHEN** LLM 根据指南生成包含人物描述的 SD Prompt
|
||||
- **THEN** Prompt 中不含 `beautiful`、`pretty`、`good looking` 等泛化词,而是包含如 `almond eyes`、`porcelain skin`、`youthful appearance` 等具体描述词
|
||||
|
||||
### Requirement: LLM Prompt 指南区分人物图与纯场景图的写作策略
|
||||
`get_sd_prompt_guide()` 返回的指南 SHALL 明确区分两种写作模式:人物主体图(需详细描述人物特征)和纯场景/物品图(无需人物词,优先描述氛围、色彩、光线)。
|
||||
|
||||
#### Scenario: 生成场景图 Prompt 时不误加人物词
|
||||
- **WHEN** 文案主题为室内布置或产品展示(无人物)
|
||||
- **THEN** LLM 生成的 Prompt 中不包含人物特征描述词
|
||||
|
||||
#### Scenario: 生成人物图 Prompt 时包含完整人物描述
|
||||
- **WHEN** 文案主题为穿搭、美妆或生活场景(含人物)
|
||||
- **THEN** LLM 生成的 Prompt 中包含五官、肤色、气质三个维度的描述词各至少 1 个
|
||||
|
||||
### Requirement: LLM Prompt 指南包含光影与摄影感描述规范
|
||||
`get_sd_prompt_guide()` 返回的指南 SHALL 包含光影描述规则,要求生成 Prompt 时指定具体光源类型(如 `soft window light`、`golden hour`、`studio lighting`)而非泛化词(如 `good lighting`)。
|
||||
|
||||
#### Scenario: Prompt 中包含具体光影词而非泛化词
|
||||
- **WHEN** LLM 根据指南生成 SD Prompt
|
||||
- **THEN** Prompt 中包含 `soft window light`、`golden hour`、`studio lighting`、`diffused natural light` 等具体光影词之一
|
||||
@@ -0,0 +1,16 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 开机自启管理函数迁移至独立模块
|
||||
系统 SHALL 将开机自启相关常量和函数从 `main.py` 提取至 `services/autostart.py`,包括:`_APP_NAME`、`_STARTUP_REG_KEY`、`_get_startup_script_path`、`_get_startup_bat_path`、`_create_startup_scripts`、`is_autostart_enabled`、`enable_autostart`、`disable_autostart`、`toggle_autostart`。
|
||||
|
||||
#### Scenario: 模块导入成功
|
||||
- **WHEN** `main.py` 执行 `from services.autostart import toggle_autostart, is_autostart_enabled`
|
||||
- **THEN** 函数可正常调用
|
||||
|
||||
#### Scenario: Windows 注册表操作行为不变
|
||||
- **WHEN** `enable_autostart()` 在 Windows 系统上被调用
|
||||
- **THEN** SHALL 向注册表 `HKCU\Software\Microsoft\Windows\CurrentVersion\Run` 写入启动项,行为与迁移前完全一致
|
||||
|
||||
#### Scenario: 非 Windows 平台处理不变
|
||||
- **WHEN** `enable_autostart()` 在非 Windows 系统上被调用
|
||||
- **THEN** SHALL 返回与迁移前相同的平台不支持提示信息
|
||||
@@ -0,0 +1,16 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 连接管理函数迁移至独立模块
|
||||
系统 SHALL 将所有 LLM / SD / MCP 连接管理及认证相关函数从 `main.py` 提取至 `services/connection.py`,包括:`_get_llm_config`、`connect_llm`、`add_llm_provider`、`remove_llm_provider`、`on_provider_selected`、`connect_sd`、`on_sd_model_change`、`check_mcp_status`、`get_login_qrcode`、`logout_xhs`、`_auto_fetch_xsec_token`、`check_login`、`save_my_user_id`、`upload_face_image`、`load_saved_face_image`。
|
||||
|
||||
#### Scenario: 模块导入成功
|
||||
- **WHEN** `main.py` 执行 `from services.connection import connect_llm, connect_sd` 等导入
|
||||
- **THEN** 所有函数可正常调用,行为与迁移前完全一致
|
||||
|
||||
#### Scenario: 外部依赖通过参数传入
|
||||
- **WHEN** `services/connection.py` 中的函数需要访问 `cfg`、`llm`(`LLMService`)、`sd`(`SDService`)、`mcp`(`MCPClient`)
|
||||
- **THEN** 这些依赖 SHALL 通过函数参数接收,`services/connection.py` 模块顶层不创建单例实例
|
||||
|
||||
#### Scenario: 无循环导入
|
||||
- **WHEN** Python 解释器加载 `services/connection.py`
|
||||
- **THEN** 不产生 `ImportError` 或循环导入错误
|
||||
@@ -0,0 +1,16 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 内容生成函数迁移至独立模块
|
||||
系统 SHALL 将内容生成、图片生成、发布及导出相关函数从 `main.py` 提取至 `services/content.py`,包括:`generate_copy`、`generate_images`、`one_click_export`、`publish_to_xhs`。
|
||||
|
||||
#### Scenario: 模块导入成功
|
||||
- **WHEN** `main.py` 执行 `from services.content import generate_copy, generate_images, publish_to_xhs, one_click_export`
|
||||
- **THEN** 所有函数可正常调用,行为与迁移前完全一致
|
||||
|
||||
#### Scenario: 内容生成保留现有验证逻辑
|
||||
- **WHEN** 调用 `publish_to_xhs` 时标题超过 20 字或图片数量不合法
|
||||
- **THEN** 函数 SHALL 返回与迁移前相同的错误提示,不改变验证行为
|
||||
|
||||
#### Scenario: 临时文件清理逻辑保留
|
||||
- **WHEN** `publish_to_xhs` 执行完毕(成功或失败)
|
||||
- **THEN** `finally` 块中的 AI 临时文件清理逻辑 SHALL 正常执行
|
||||
@@ -0,0 +1,16 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 互动自动化函数迁移至独立模块
|
||||
系统 SHALL 将评论、点赞、收藏、回复等互动自动化函数从 `main.py` 提取至 `services/engagement.py`,包括:`load_note_for_comment`、`ai_generate_comment`、`send_comment`、`fetch_my_notes`、`on_my_note_selected`、`fetch_my_note_comments`、`ai_reply_comment`、`send_reply`、`auto_comment_once`、`_auto_comment_with_log`、`auto_like_once`、`_auto_like_with_log`、`auto_favorite_once`、`_auto_favorite_with_log`、`auto_reply_once`、`_auto_reply_with_log`、`_auto_publish_with_log`。
|
||||
|
||||
#### Scenario: 模块导入成功
|
||||
- **WHEN** `main.py` 执行 `from services.engagement import auto_comment_once, auto_like_once` 等导入
|
||||
- **THEN** 所有函数可正常调用
|
||||
|
||||
#### Scenario: 日志回调参数化
|
||||
- **WHEN** `engagement.py` 中的 `_with_log` 函数需要追加日志时
|
||||
- **THEN** 函数 SHALL 接收 `log_fn` 参数(callable)用于写入日志,不直接依赖外部 `_auto_log` 列表
|
||||
|
||||
#### Scenario: 频率限制集成
|
||||
- **WHEN** `auto_comment_once` 等函数执行前需要检查每日限额和冷却状态
|
||||
- **THEN** 通过调用 `rate_limiter` 模块中的函数实现,不在 `engagement.py` 内复制限流逻辑
|
||||
@@ -0,0 +1,12 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 热点探测函数迁移至独立模块
|
||||
系统 SHALL 将热点搜索与分析相关函数从 `main.py` 提取至 `services/hotspot.py`,包括:`search_hotspots`、`analyze_and_suggest`、`generate_from_hotspot`、`_set_cache`、`_get_cache`、`_fetch_and_cache`、`_pick_from_cache`、`fetch_proactive_notes`、`on_proactive_note_selected`。
|
||||
|
||||
#### Scenario: 模块导入成功
|
||||
- **WHEN** `main.py` 执行 `from services.hotspot import search_hotspots, analyze_and_suggest` 等导入
|
||||
- **THEN** 所有函数可正常调用
|
||||
|
||||
#### Scenario: 线程安全缓存随模块迁移
|
||||
- **WHEN** `_cache_lock`(`threading.RLock`)随函数一起迁移至 `services/hotspot.py`
|
||||
- **THEN** `_set_cache` / `_get_cache` 的线程安全行为保持不变
|
||||
@@ -0,0 +1,16 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 人设管理函数及常量迁移至独立模块
|
||||
系统 SHALL 将人设相关的常量和函数从 `main.py` 提取至 `services/persona.py`,包括:`DEFAULT_PERSONAS`、`RANDOM_PERSONA_LABEL`、`PERSONA_POOL_MAP`、`DEFAULT_TOPICS`、`DEFAULT_STYLES`、`DEFAULT_COMMENT_KEYWORDS`、`_match_persona_pools`、`get_persona_topics`、`get_persona_keywords`、`on_persona_changed`、`_resolve_persona`。
|
||||
|
||||
#### Scenario: 常量可从模块导入
|
||||
- **WHEN** `main.py` 执行 `from services.persona import DEFAULT_PERSONAS, PERSONA_POOL_MAP`
|
||||
- **THEN** 常量值 SHALL 与迁移前完全一致
|
||||
|
||||
#### Scenario: 人设解析正确处理随机人设标签
|
||||
- **WHEN** `_resolve_persona(RANDOM_PERSONA_LABEL)` 被调用
|
||||
- **THEN** SHALL 返回从人设池中随机选取的人设文本,行为与迁移前一致
|
||||
|
||||
#### Scenario: 人设变更回调正常触发
|
||||
- **WHEN** `on_persona_changed(persona_text)` 被调用
|
||||
- **THEN** SHALL 返回更新后的话题列表和关键词列表,供 Gradio UI 使用
|
||||
@@ -0,0 +1,12 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 用户主页解析函数迁移至独立模块
|
||||
系统 SHALL 将用户主页数据获取与解析相关函数从 `main.py` 提取至 `services/profile.py`,包括:`_parse_profile_json`、`_parse_count`、`fetch_my_profile`。
|
||||
|
||||
#### Scenario: 模块导入成功
|
||||
- **WHEN** `main.py` 执行 `from services.profile import fetch_my_profile`
|
||||
- **THEN** 函数可正常调用,行为与迁移前一致
|
||||
|
||||
#### Scenario: 解析容错性保留
|
||||
- **WHEN** `_parse_count` 接收到格式异常的数值字符串(如 "1.2万"、"--")
|
||||
- **THEN** SHALL 返回与迁移前相同的浮点数或 0,不抛出异常
|
||||
@@ -0,0 +1,16 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 排期队列操作函数迁移至独立模块
|
||||
系统 SHALL 将内容排期队列相关函数从 `main.py` 提取至 `services/queue_ops.py`,包括:`generate_to_queue`、`_queue_publish_callback`、`queue_refresh_table`、`queue_refresh_calendar`、`queue_preview_item`、`queue_approve_item`、`queue_reject_item`、`queue_delete_item`、`queue_retry_item`、`queue_publish_now`、`queue_start_processor`、`queue_stop_processor`、`queue_get_status`、`queue_batch_approve`、`queue_generate_and_refresh`。
|
||||
|
||||
#### Scenario: 模块导入成功
|
||||
- **WHEN** `main.py` 执行 `from services.queue_ops import queue_generate_and_refresh, queue_refresh_table` 等导入
|
||||
- **THEN** 所有函数可正常调用
|
||||
|
||||
#### Scenario: publish callback 在 main.py 完成注册
|
||||
- **WHEN** 应用启动时 `main.py` 调用 `pub_queue.set_publish_callback(_queue_publish_callback)`(`_queue_publish_callback` 已迁移至 `queue_ops.py`)
|
||||
- **THEN** 队列发布回调 SHALL 正常注册并在队列处理时触发
|
||||
|
||||
#### Scenario: 队列操作读写 pub_queue 单例
|
||||
- **WHEN** `queue_ops.py` 中的函数需要访问 `pub_queue` 或 `queue_publisher`
|
||||
- **THEN** 这些单例 SHALL 通过函数参数传入,不在 `queue_ops.py` 模块顶层初始化
|
||||
@@ -0,0 +1,16 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 频率控制与每日限额函数迁移至独立模块
|
||||
系统 SHALL 将频率控制、每日限额及冷却相关的所有状态变量和函数从 `main.py` 提取至 `services/rate_limiter.py`,包括:`_auto_running`、`_op_history`、`_daily_stats`、`DAILY_LIMITS`、`_consecutive_errors`、`_error_cooldown_until`、`_reset_daily_stats_if_needed`、`_check_daily_limit`、`_increment_stat`、`_record_error`、`_clear_error_streak`、`_is_in_cooldown`、`_is_in_operating_hours`、`_get_stats_summary`。
|
||||
|
||||
#### Scenario: 模块级状态初始化一次
|
||||
- **WHEN** Python 首次导入 `services/rate_limiter.py`
|
||||
- **THEN** `_daily_stats`、`_op_history` 等模块级变量 SHALL 仅初始化一次(Python 模块单例语义)
|
||||
|
||||
#### Scenario: 每日限额检查正常工作
|
||||
- **WHEN** `_check_daily_limit("comment")` 被调用
|
||||
- **THEN** 返回值 SHALL 与迁移前行为完全一致
|
||||
|
||||
#### Scenario: 运营时段限制正常工作
|
||||
- **WHEN** 当前时间不在 `start_hour` 至 `end_hour` 范围内时调用 `_is_in_operating_hours`
|
||||
- **THEN** 返回 `False`,阻止自动化操作执行
|
||||
@@ -0,0 +1,16 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 自动调度器函数迁移至独立模块
|
||||
系统 SHALL 将调度器相关的状态变量和函数从 `main.py` 提取至 `services/scheduler.py`,包括:`_scheduler_next_times`、`_auto_log`(列表)、`_auto_log_append`、`_scheduler_loop`、`start_scheduler`、`stop_scheduler`、`get_auto_log`、`get_scheduler_status`、`_learn_running`、`_learn_scheduler_loop`、`start_learn_scheduler`、`stop_learn_scheduler`。
|
||||
|
||||
#### Scenario: 调度器启停正常工作
|
||||
- **WHEN** `start_scheduler(...)` 被调用并传入合法参数
|
||||
- **THEN** 调度器线程 SHALL 正常启动,`get_scheduler_status()` 返回运行中状态
|
||||
|
||||
#### Scenario: 日志追加线程安全
|
||||
- **WHEN** 多个自动化任务并发调用 `_auto_log_append(msg)`
|
||||
- **THEN** 日志条目 SHALL 正确追加,不丢失和乱序
|
||||
|
||||
#### Scenario: engagement 通过回调写日志
|
||||
- **WHEN** `services/engagement.py` 中的函数需要写日志时
|
||||
- **THEN** SHALL 通过 `log_fn` 参数(由 `scheduler.py` 传入 `_auto_log_append`)写入,不直接导入 `scheduler.py`
|
||||
@@ -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 实时更新显示连接结果,与原折叠区行为一致
|
||||
@@ -1,19 +1,49 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 内容创作 Tab 的 UI 代码迁移至独立模块
|
||||
`ui/tab_create.py` SHALL 包含原 `main.py` 中「内容创作 Tab」的全部 Gradio 组件定义和事件绑定,并导出 `build_tab() -> None` 函数,该函数接受一个 `gr.Blocks` 上下文,在其中构建 Tab 内容。`main.py` SHALL 通过 `from ui.tab_create import build_tab` 调用该函数,不在主文件中保留重复的组件代码。
|
||||
`ui/tab_create.py` SHALL 包含「内容创作 Tab」的全部 Gradio 组件定义和事件绑定,并导出 `build_tab(...) -> dict` 函数,返回跨 Tab 共享组件的字典(key 集合不得变更)。
|
||||
|
||||
#### Scenario: main.py 正常启动并显示内容创作 Tab
|
||||
- **WHEN** 运行 `python main.py` 启动 Gradio 应用
|
||||
- **THEN** 内容创作 Tab 正常显示,所有组件与迁移前功能一致
|
||||
内容创作 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 模块中直接调用全局服务初始化代码(如 `ConfigManager()`、`LLMService()` 等单例初始化应由 `main.py` 完成并通过参数或模块级引用传入)。
|
||||
`ui/` 目录 SHALL 包含 `__init__.py`,每个 Tab 模块文件命名约定为 `tab_<name>.py`,不在 Tab 模块中直接调用全局服务初始化代码。
|
||||
|
||||
#### Scenario: 新增 Tab 模块的标准结构
|
||||
- **WHEN** 开发者创建新的 `ui/tab_*.py` 文件
|
||||
- **THEN** 该文件导出 `build_tab(...)` 函数,且顶层不包含副作用代码(不在 import 时触发服务连接)
|
||||
- **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 @@
|
||||
## ADDED 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 位于最末位,低频操作不干扰主工作区
|
||||
Reference in New Issue
Block a user