Skip to content

改进 AI 优化后台任务、章节导出、拆书导入与 Gemini 章节分析错误处理 #141

@felixchaos

Description

@felixchaos

背景

在本地使用过程中遇到几类体验和稳定性问题:

  1. /api/polish 在部分 AI 服务返回 { content, usage } 对象时,会把整个对象写入 polished_text,导致 Pydantic 校验失败并返回 500。
  2. 已有大纲/角色设定的 AI 优化入口之前直接在前端循环调用润色接口,绕过了统一后台任务系统,因此开始后无法在右下角任务面板查看或取消。
  3. 章节管理页导出只能导出整本合并 TXT,无法选择章节范围,也无法按章节拆分导出,不方便上传到第三方写作平台。
  4. 章节列表只有搜索,缺少状态/分析/内容/大纲维度筛选。
  5. Gemini 在 promptFeedback.blockReason=PROHIBITED_CONTENT 或空候选返回时,错误信息不够清晰,章节分析容易表现为“秒失败”但原因不明确。
  6. 拆书导入时,角色生成容易根据标题或模型推断出原文不存在的人名/组织名;原文为空或 summary 为 None 时也存在兜底摘要不稳的问题。
  7. Docker build 时如果宿主机存在嵌套 node_modules,可能被复制进镜像,造成 esbuild 平台二进制不匹配。

本地补丁实现概述

1. 修复 /api/polish 返回对象导致的 500

涉及文件:

  • backend/app/api/polish.py
  • backend/app/schemas/polish.py
  • backend/app/main.py

实现:

  • 新增 _extract_generated_text(response),兼容 AI 服务返回字符串或 { content, usage } 对象。
  • PolishRequest.project_idOptional[int] 改为 Optional[str],匹配项目 UUID。
  • PolishRequest 增加 instruction 字段,用于复用润色接口做“定向优化”。
  • 修正 GenerationHistory 写入字段,使用现有模型字段 generated_contentmodel
  • 将 polish router 挂载到主应用:app.include_router(polish.router, prefix="/api")

2. 已有大纲优化改为统一后台任务

涉及文件:

  • backend/app/api/polish.py
  • backend/app/schemas/polish.py
  • backend/app/services/background_task_service.py
  • frontend/src/pages/Outline.tsx
  • frontend/src/services/api.ts
  • frontend/src/components/FloatingTaskPanel.tsx

实现:

  • 新增 POST /api/polish/outlines/background
  • 支持传入 outline_ids;为空时可扩展为全项目大纲优化。
  • 后端任务类型为 outline_optimize
  • 任务逐条处理大纲,解析 AI JSON 输出后更新:
    • outline.content
    • outline.structure.summary
    • outline.structure.content
    • key_points
    • key_events
    • emotion
    • goal
  • 前端单条“AI优化”和批量“AI优化已有大纲”都改为创建后台任务。
  • 通过 pollTaskUntilComplete 刷新状态与结果。
  • 右下角任务面板新增任务类型显示:大纲优化
  • 排队中取消的任务会在 worker 开始前被跳过。

3. 角色/组织设定优化

涉及文件:

  • backend/app/api/polish.py
  • backend/app/schemas/polish.py
  • frontend/src/pages/Characters.tsx
  • frontend/src/services/api.ts
  • frontend/src/components/FloatingTaskPanel.tsx

实现:

  • 新增 POST /api/polish/characters/background
  • 后端任务类型为 character_optimize
  • 支持批量优化选中的角色/组织。
  • 对角色优化字段:
    • personality
    • appearance
    • background
  • 对组织优化字段:
    • organization_purpose
    • motto
    • background
  • 前端“批量优化设定”改为走后台任务流程,可在任务面板查看/取消。
  • 编辑弹窗中增加单个角色/组织的 AI 优化按钮,优化结果先填入表单,由用户检查后保存。

4. 章节管理页筛选和导出增强

涉及文件:

  • backend/app/api/projects.py
  • frontend/src/pages/Chapters.tsx
  • frontend/src/services/api.ts

实现:

  • GET /api/projects/{project_id}/export 增加查询参数:
    • start_chapter
    • end_chapter
    • split
  • 支持按章节号范围导出。
  • split=true 时返回 ZIP,每章一个 TXT 文件。
  • 合并导出仍返回单个 TXT。
  • 前端导出按钮改为弹窗:
    • 全部/自定义范围
    • 合并 TXT/分章 ZIP
  • 章节管理页增加筛选:
    • 章节状态
    • 分析状态
    • 是否有正文
    • 关联大纲
  • 优化顶部工具区布局,解决搜索框和按钮区域不对齐问题。

5. Gemini 错误处理与章节分析兜底

涉及文件:

  • backend/app/services/ai_clients/gemini_client.py
  • backend/app/services/plot_analyzer.py
  • backend/app/api/chapters.py

实现:

  • Gemini client 增加:
    • GeminiResponseError
    • GeminiPromptBlockedError
    • promptFeedback.blockReason 检测
    • 空 candidate / 空 parts 检测
    • finishReason 标准化
    • usageMetadata 统一转换为 token usage
  • PlotAnalyzer 增加 last_error,将真实失败原因向外传递。
  • 对不可重试的 Gemini 拦截错误不再盲目重试。
  • 章节分析后台任务在 Gemini 专用模型被拦截时,尝试切换到默认模型兜底。
  • 批量生成中章节分析失败时,将真实 error_message 透传给上层,而不是只显示笼统的“章节分析失败”。

6. 拆书导入稳定性改进

涉及文件:

  • backend/app/services/book_import_service.py
  • backend/app/services/txt_parser_service.py

实现:

  • fallback outline summary 统一走安全方法,避免 None.strip()
  • TXT 章节识别增强:
    • 更严格区分强章节标题和弱标题。
    • 减少误把正文短句识别为章节标题。
    • 支持更完整的“第 X 节/章/回/卷/集/部/篇”形式。
  • 拆书导入生成角色/组织时传入原文章节上下文。
  • 角色卡生成要求改为“从原文抽取”,避免模型编造原文不存在的人名、组织名。
  • 增加原文姓名候选抽取与过滤逻辑:
    • 优先保留原文明确出现的名称。
    • 对原文未出现的角色/组织进行过滤。
    • AI 结果不足时,用原文高频姓名候选构建保守 fallback 角色。

7. Docker build 防宿主依赖污染

涉及文件:

  • .dockerignore
  • .gitignore

实现:

  • .dockerignore 增加 **/node_modules/,避免嵌套 node_modules 被复制进镜像。
  • .gitignore 增加 .playwright-cli/,避免本地浏览器自动化缓存误提交。

验证

本地已验证:

  • npm run build 通过。
  • python -m py_compile 覆盖相关后端文件通过。
  • git diff --check 通过。
  • Docker 容器热更新后 /health 正常。
  • OpenAPI 中可见:
    • /api/polish
    • /api/polish/outlines/background
    • /api/polish/characters/background
  • 前端刷新后控制台无新增 error。
  • 本地敏感信息检查没有发现真实 API key、.env、本地路径或项目数据进入拟提交内容。

期望

希望上游考虑合并或参考这些改动,尤其是:

  1. 让 AI 优化统一走后台任务系统。
  2. 保留明确的错误原因,特别是 Gemini 安全拦截和空响应。
  3. 增强章节导出能力,支持范围和分章 ZIP。
  4. 拆书导入应尽量从原文抽取角色,避免模型自动补全不存在的设定。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions