Files

39 KiB
Raw Permalink Blame History

系统详细设计

项目:PPT 自动生成 Agent · 赛道一:Agent 开发实战赛 · 新规项目 配套文档:PRD v1.2(项目资料/需求与思路/02-需求文档/产品需求文档_PRD.md)、设计文档(项目资料/对外资料/设计文档.md 版本:v0.42026-08-25 二次同步:UI 全语言收尾 + 网络配图管线;新增 6.6,更新 5.1/6.5/十章) 前版:v0.32026-08-25 状态同步:Sprint 2 对话修改落地、在线预览上线、LLM 零Key 接入;新增 4.7 预览设计) 前版:v0.2(2026-08-24 引擎切换改版:第5/6章改为 aura-ppt 方案,散点同步) 初版:v0.1(第1批 · 骨架,2026-08-17) 配套选型依据:项目资料/事前调查/引擎选型对比_ppt-master_vs_aura-ppt.md


一、总体架构与分层

1.1 分层架构图

前端(HTML + JS
  │  HTTP / JSON
  ▼
Flask API 层(路由 / 鉴权 / 文件上传 / 静态资源)
  │
  ▼
Agent 核心(感知 → 规划 → 行动 → 记忆)
  │  ① 参数映射(标题/内容/配色/页数 → plan.json 页面规划)
  │  ② 状态机(生成任务调度 / 进度回传 / 失败重试)
  ▼
aura-ppt 渲染引擎(项目内副本:ppt-agent/engine/aura-ppt/
  │  plan.json → 确定性渲染 PPTX → 内容保真验证
  │  (辅助:ppt-master 仅复用文档解析/搜图脚本,Sprint 3 接入)
  ▼
SQLiteusers / preferences / ppt_records / versions / chat_messages

1.2 模块职责

模块 目录 职责
Web 前端 src/web/static/ 4 页面(登录/工作台/历史/设置)+ 样式 + JS
Flask API src/web/app.py 路由注册、Session 鉴权、请求校验、错误统一处理
Agent 核心 src/agent/ perception / planning / action / memory 四子模块 + chat(对话修改)/ llm(LLM 客户端)
引擎桥接 src/engine_bridge/ 调用 aura-ppt CLI(渲染 / 保真验证)、预览图导出(COM);ppt-master 解析脚本已接入(upload.py),搜图待接
配置 config.py 引擎路径、上传限制、数据库路径、DeepSeek API 等
数据层 src/db/ SQLite 连接管理、表结构 DDL

1.3 关键设计约束

约束 说明
引擎路径可配置 config.AURA_ENGINE_PATH 指向项目内 aura-ppt 副本(渲染),config.PPT_MASTER_PATH 指向 ppt-master 副本(解析/搜图),不硬编码全局路径
引擎只经 CLI 调用 Agent 不 import 引擎内部模块,渲染统一走 engine.py --plan/--verify + subprocess
生成异步化 PPT 生成耗时长,采用后台任务 + 前端轮询进度(对应 US-2.7a 进度提示、US-2.11 跨页面状态)
状态机驱动 每个生成任务有任务 ID,状态迁移:pending → analyzing → planning → rendering → done / failed

1.4 中日文切换设计

系统支持双语言,且拆分为两个相互独立的维度:

维度 含义 切换入口 存储
UI 语言 界面文案(按钮/标签/提示)整体切换 顶栏语言下拉 + 设置页 localStorage(未登录)→ preferences(登录后同步)
生成语言 生成的 PPT 内容与演讲备注的语言 工作台「生成配置」面板下拉 每次生成独立选择,默认取偏好值

多语言实现

  • 前端 i18n 字典:src/web/static/lang/zh.jsonja.json,键值一一对应,支持动态切换无需刷新
  • 引擎侧:生成语言=ja 时,Agent 感知层输出的源 Markdown、执行器产生的演讲备注全部用日文,字体栈换为 Meiryo(参照试跑项目 ai-basics-jp
  • 偏好默认值:default_language 默认 zh,用户可改

语言洁癖约束:任一语言环境下界面与生成内容均保持单一语言,禁止中日文混排。


二、REST API 规范

2.1 通用约定

约定
基础路径 /api
内容类型 请求/响应均为 application/json(文件上传除外)
认证 除登录/注册外,所有接口需带 session cookie;未登录返回 401
响应结构 成功:{"code":0,"data":{...}};失败:{"code":<错误码>,"message":"中文提示"}
错误码前缀 10xx 认证 / 20xx 生成 / 30xx 上传解析 / 40xx 历史 / 50xx 设置 / 60xx 引擎

2.2 错误码表

错误码 含义 前端提示文案
1001 用户名已存在 "用户名已被使用"
1002 用户名或密码错误 "用户名或密码错误"
1003 两次密码不一致 "两次输入的密码不一致"
1004 未登录或会话过期 "请先登录"
2001 内容字数不足 20 "内容至少需要 20 个字"
2002 页数范围非法(min>max "最少页数不能大于最多页数"
2003 引擎繁忙 "引擎繁忙,请稍后重试"
2004 生成失败(引擎侧) "生成失败,请重试"
3001 不支持的文件类型 "不支持的文件类型"
3002 文件超过 20MB "文件大小不能超过 20MB"
3003 文件损坏无法读取 "文件损坏,无法读取"
3004 解析内容为空 "文件内容为空"
4001 历史记录不存在 "该记录不存在或已被删除"
5001 原密码错误 "原密码不正确"
6001 引擎内部错误 "引擎内部异常,请联系管理员"

2.3 接口清单

Epic 1 · 认证

# 方法 路径 说明 对应故事
1 POST /api/register 注册 US-1.1
2 POST /api/login 登录 US-1.2
3 POST /api/logout 退出登录 US-1.3
4 GET /api/me 获取当前用户信息 US-1.2

Epic 2 · PPT 生成

# 方法 路径 说明 对应故事
5 POST /api/generate 触发生成,返回任务 ID US-2.7a
6 GET /api/generate/<task_id>/status 查询生成进度 US-2.7a / US-2.11
7 GET /api/generate/<task_id>/result 生成完成后取结果 US-2.7b
8 POST /api/title/suggest 智能生成标题 US-2.4
9 GET /api/files/<record_id>/download 下载 PPTX US-2.8
10 GET /api/files/<record_id>/preview 在线预览页数据(PNG 按版本缓存) US-2.9

预览页图实际加载走 GET /api/preview-img/<record_id>/<name>(单页 PNG,归属校验 + 文件名白名单,见 4.7)。

Epic 3 · 上传解析

# 方法 路径 说明 对应故事
11 POST /api/upload 上传文档(multipart US-2.3a
12 POST /api/parse 解析上传文件为文本 US-2.3b

Epic 4 · 对话修改

# 方法 路径 说明 对应故事
13 POST /api/chat 发送修改指令 US-3.1
14 GET /api/chat/<record_id>/messages 获取本轮对话记录 US-3.2

Epic 5 · 历史记录

# 方法 路径 说明 对应故事
15 GET /api/records 历史列表(搜索/筛选/分页) US-4.1 / 4.2 / 4.3
16 GET /api/records/<id> 历史详情(含版本) US-4.4
17 DELETE /api/records/<id> 删除记录 US-4.6

Epic 6 · 个人设置

# 方法 路径 说明 对应故事
18 PUT /api/settings/username 修改用户名 US-5.1
19 PUT /api/settings/password 修改密码 US-5.2
20 PUT /api/settings/preferences 保存生成偏好 US-5.3
21 GET /api/settings 获取设置与偏好 US-5.1 / 5.3

2.4 关键接口详细定义

POST /api/generate

请求体:

{
  "title": "七月项目周报",
  "content": "本月完成模块A开发……(≥20字)",
  "scene": "report",              // report=社内汇报 / training=社内培训
  "language": "zh",               // zh=中文 PPT / ja=日文 PPT
  "canvas": "ppt169",             // ppt169=16:9(默认)/ ppt43=4:3
  "image_strategy": "web",         // web=网络搜图(默认)/ ai=AI生成 / off=不用图
  "color_scheme": "blue",         // blue/green/purple/orange/gray
  "page_min": 10,
  "page_max": 15
}

成功响应:

{
  "code": 0,
  "data": {
    "task_id": "gen_20260817_1015_3f8a",
    "status": "analyzing"
  }
}

状态迁移(US-2.7a 进度提示映射):

状态 前端提示 对应引擎阶段
analyzing "正在分析内容…" 源内容处理 / 策略师分析
planning "正在规划结构…" 策略师八大确认解析
rendering "正在排版渲染…" 执行器 SVG 逐页生成 + 导出
done 生成完成 导出完成
failed 按错误码提示 任一环节失败

GET /api/generate/<task_id>/status

{
  "code": 0,
  "data": {
    "status": "rendering",
    "progress": 68,          // 0-100,渲染阶段按已生成页/总页估算
    "message": "正在排版渲染…"
  }
}

GET /api/files/<record_id>/download

Content-Disposition: attachment; filename="标题_20260817_1015.pptx",返回二进制流。


三、SQLite 数据库设计

3.1 ER 概览

users 1 ─── 1 preferences
  │
  └── 1 ─── n ppt_records 1 ─── 0..n versions
                           │
                           └── 1 ─── n chat_messages

3.2 表结构

users(用户表)

字段 类型 约束 说明
id INTEGER PRIMARY KEY AUTOINCREMENT 主键
username TEXT UNIQUE NOT NULL 用户名
password_hash TEXT NOT NULL bcrypt 哈希,不存明文
created_at TEXT NOT NULL 创建时间(ISO8601

preferences(偏好表)

字段 类型 约束 说明
id INTEGER PRIMARY KEY AUTOINCREMENT 主键
user_id INTEGER NOT NULL, FOREIGN KEY→users.id 所属用户
default_scene TEXT DEFAULT 'training' 默认场景
default_color TEXT DEFAULT 'blue' 默认配色
default_language TEXT DEFAULT 'zh' 默认生成语言(zh/ja
default_canvas TEXT DEFAULT 'ppt169' 默认画布(ppt169/ppt43
default_image_strategy TEXT DEFAULT 'web' 默认配图策略(web/ai/off
default_page_min INTEGER DEFAULT 10 默认页数下限
default_page_max INTEGER DEFAULT 15 默认页数上限

ppt_recordsPPT 生成记录表)

字段 类型 约束 说明
id INTEGER PRIMARY KEY AUTOINCREMENT 主键
user_id INTEGER NOT NULL, FOREIGN KEY→users.id 所属用户(索引)
title TEXT NOT NULL PPT 标题
content TEXT NOT NULL 用户输入的源内容
scene TEXT NOT NULL report / training
language TEXT NOT NULL DEFAULT 'zh' 生成语言(zh/ja),历史筛选依据
color_scheme TEXT NOT NULL blue/green/purple/orange/gray
page_min INTEGER NOT NULL 页数下限
page_max INTEGER NOT NULL 页数上限
status TEXT NOT NULL DEFAULT 'done' 生成状态
file_size INTEGER NULL PPTX 文件大小(字节)
page_count INTEGER NULL 实际生成页数
generate_duration INTEGER NULL 生成耗时(秒)
created_at TEXT NOT NULL 生成时间(列表倒序排序依据)

versions(版本表,对应 US-4.4 两版本策略)

字段 类型 约束 说明
id INTEGER PRIMARY KEY AUTOINCREMENT 主键
record_id INTEGER NOT NULL, FOREIGN KEY→ppt_records.id 所属记录
version_no INTEGER NOT NULL 版本号(1=第一版,2=修改后)
file_path TEXT NOT NULL PPTX 文件相对路径
svg_dir TEXT NULL SVG 源目录相对路径
change_note TEXT NULL 本次修改说明(对话修改时记录)
created_at TEXT NOT NULL 版本生成时间

两版本策略:当前版本 + 上一版本(决策日志 2026-07-20)。生成新版本时,旧"上一版"删除,原"当前版"降为"上一版"。

chat_messages(对话消息表)

字段 类型 约束 说明
id INTEGER PRIMARY KEY AUTOINCREMENT 主键
record_id INTEGER NOT NULL, FOREIGN KEY→ppt_records.id 关联记录
role TEXT NOT NULL user / assistant
content TEXT NOT NULL 消息内容
created_at TEXT NOT NULL 时间戳

3.3 索引

索引 用途
users UNIQUE (username) 登录查询、注册唯一性
ppt_records (user_id, created_at DESC) 历史列表按时间倒序
ppt_records (user_id, scene) 场景筛选(US-4.3
versions (record_id) 版本回查(US-4.4
chat_messages (record_id, created_at) 对话历史按时间顺序

3.4 SQLite 配置

PRAGMA journal_mode = WAL;      -- 读写并发优化
PRAGMA foreign_keys = ON;       -- 外键约束
PRAGMA busy_timeout = 5000;     -- 写入冲突等待 5s

四、Agent 核心模块设计

对应设计文档「感知→规划→行动→记忆」四层架构,每个模块对应一个 Python 子包。

4.1 模块划分与文件结构

src/agent/
├── __init__.py
├── perception.py     # 感知层:输入解析 + 场景/语言/偏好识别
├── planning.py       # 规划层:结构匹配 + 页数分配 + 配色应用 + 参数映射
├── action.py         # 行动层:引擎编排 + 状态机调度
├── chat.py           # 对话修改:意图解析(LLM 优先/规则兜底)+ plan.json 变更应用
├── llm.py            # LLM 客户端:opencode serve / OpenAI 兼容双后端
├── memory.py         # 记忆层:读写 SQLite + 两版本策略
└── orchestrator.py   # 总调度:串联四层,生成/对话/解析三条流程入口

4.2 感知层(perception.py

方法 输入 输出 职责
parse_input(title, content) 标题 + 正文 结构化内容对象 清洗文本、截断超长、提取行数/字数
resolve_config(payload, user_id) 用户请求 完整生成配置 合并请求参数 + 用户偏好(未显式提供的项用偏好默认值)
detect_lang_override() 语言参数 生成语言显式传参,否则取偏好 default_language

校验规则(对齐 US-2.2 / US-2.6):内容 ≥ 20 字、页数 min ≤ max,不满足回传相应错误码(2001/2002)。

4.3 规划层(planning.py

职责:把用户配置映射为引擎可执行的方案,是"包装引擎"的核心。

方法 职责
build_plan(cfg) 配置 + 内容 → plan.jsonMarkdown 标题切块、页数预算合并/拆分、五色板/日式规格选择,详见第五章)

4.4 行动层(action.py

职责:编排生成任务,管理状态机,调用引擎。

生成流程(on /api/generate):
  1. 校验通过 → 占并发槽位(满则 2003)→ 返回 task_id
  2. 后台线程:
     a. 规划层 build_plan 产出 plan.json 并写盘(状态: planning
     b. 引擎桥接 render_plan 渲染 + verify_output 保真验证(rendering
     c. 完成后写 versions 表 + 记录 file_size/page_count/duration → status=done
     d. 失败 → 记录失败原因 → status=failed
  3. 前端通过 status 接口轮询(1~2s 间隔)

4.5 记忆层(memory.py

方法 职责
create_record(...) / list_records(...) 历史记录增查(含搜索/筛选/分页)
save_version(record_id, file_path, change_note) 两版本策略写盘
load_history(record_id) 版本回查(当前+上一版)
record_chat(record_id, role, content) 对话消息落库
read_preferences(user_id) / save_preferences(...) 偏好读写

两版本策略规则(决策日志 7-20):新版本生成时,删除旧"上一版",原"当前版"降级为"上一版",新文件成为"当前版"。

4.6 对话修改流程(chat.pySprint 2 已实现)

用户消息(POST /api/chat
  → 意图解析(chat.parse_intentLLM 优先解析任意自然语言并自动定位页码,规则句式中/日双语兜底;降级链见 5.6)
  → 应用变更到 plan.jsonchat._apply_to_plan)并写回磁盘
  → aura 全量重渲(秒级)+ 内容保真验证
  → 记忆层:save_version 两版本策略(新版本=1,旧版本降为2)+ 对话落库
  → 返回确认回复(含新版本号与变更明细)
意图类型 指令示例(中/日) 动作
change_color 换成绿色 / カラーを緑に変更 切换 corp-* 设计系统重渲(ja 固定 report-jp,返回不支持提示)
change_title 把标题改成XX / タイトルを「XX」に変更 更新 plan.title + 封面页 + ppt_records.title
edit_page 第2页把A改成B / 第3页删除"xx" / 第2页添加"yy" 定位 slides[n] 增删改要点
unknown 其余 返回帮助文案,不重渲染

实现说明:设计原则为"只重新生成受影响内容";aura-ppt 引擎全量重渲仅数秒,等效满足体验目标,且保证整册风格一致性(如换色必须全册生效)。plan.json 是唯一演进基准(见 6.3)。

4.7 在线预览设计(2026-08-25 上线)

预览请求(前端弹层)
  → GET /api/files/<id>/preview        # 校验记录归属当前用户 → 返回版本列表与页面清单
  → bridge.export_preview_images       # PowerPoint COM 导出每页 PNGWPS 兜底),按版本缓存
                                       #   落盘 projects/<slug>/preview/<版本>/Slide<N>.PNG(文件名归一化)
  → GET /api/preview-img/<id>/<name>   # 单页图片读取:归属校验 + 文件名白名单
设计点 说明
渲染方式 PowerPoint COM 自动化导出(本机 Office,WPS 兜底),零额外服务依赖
缓存策略 按版本缓存 PNG,同版本二次打开零等待;新版本自动增量导出
安全 两路由均校验 record 归属当前用户;文件名白名单(Slide.PNG),防路径穿越
前端 工作台结果卡片「预览」按钮弹出翻页弹层,默认展示对话修改后的最新版本

五、Agent 参数映射规则

2026-08-24 引擎切换后改版:原「八大确认自动应答」方案废弃,改为 用户配置 → aura-ppt plan.json 的确定性映射。规划层不再模拟人工确认,直接产出引擎可执行的结构化页面规划。

5.1 配置 → plan.json 映射总表

用户配置 plan.json 落点 映射规则
title / content title + slides 结构 content 按 Markdown 标题切块分页(见 5.3
language=ja design: report-jp 日语固定走日式报告规格(法人蓝 #0B3D91,与本部长报告会母版对齐)
language=zh + color_scheme design: corp-* 五色板设计系统(见 5.2),默认 corp-blue
canvas 画布尺寸 当前仅支持 ppt169(16:9);ppt43 自动回退并写入任务告警(引擎待验证项)
page_min ~ page_max slides 数量预算 扣除封面/目次/结尾 3 页后,对内容块做合并/拆分(见 5.3)
scene ppt_records 落库字段 v1 分页算法与场景无关,场景值用于历史筛选,Sprint 2 增强为骨架模板
image_strategy plan.slides[].image web=内容页配图(见 6.6,失败降级无图);ai/off=落库字段,暂不配图

5.2 五色板设计系统(对应 US-2.5)

在引擎 DESIGN_SYSTEMS 注册表扩展(继承 business-report 浅色骨架,覆写颜色令牌):

方案名 design 键 主色 辅色 卡片底 说明
商务蓝(默认) corp-blue #1565C0 #2196F3 #E3F2FD 产品默认
清新绿 corp-green #2E7D32 #34A853 #E8F5E9
科技紫 corp-purple #5B21B6 #7C3AED #EDE9FE
活力橙 corp-orange #D97706 #F59E0B #FEF3C7
深灰 corp-gray #374151 #6B7280 #F3F4F6 图表灰阶+蓝红点睛

日语生成走 report-jp#0B3D91/#1976D2),即公司确认的强调色 R11 G61 B145 / R25 G118 B210。

5.3 内容分页算法(planning.build_plan

输入 contentMarkdown 文本)
 1. 逐行扫描:#/##/### 标题行 → 新建页面块;"-/*"行 → 当前块要点;普通行 → 要点
 2. 页数预算 = clamp(page_min,page_max) - 3(封面/目次/结尾)
 3. 块数 > 预算上限:小块合并(无标题且合计 ≤5 条优先并给前一有题块)
 4. 块数 < 预算下限:最大块对半拆分(续页标题追加「(续)/(続き)」)
 5. 单块要点 >10 条:按每页 5 条拆分为多页
输出 slides = [cover] + [toc(≥2 页时)] + [content × N] + [end]
  • 无标题块回退标题:中文「要点 n」/日文「ポイント n」
  • 目次条目即各 content 页标题;语言文案包内置 zh/ja 两套(目录/致谢页等)

5.4 公司母版继承策略(--template 模式)

配置 默认 说明
COMPANY_TEMPLATE engine/aura-ppt/assets/公司模板.pptx 项目资产副本(技能原版只读)
COMPANY_TEMPLATE_MODE ja always=全部用模板 / ja=仅日语生成用 / off=不用
生效行为 继承母版背景/Logo/页脚,以「白紙」版式建页,引擎元素叠加;页面尺寸随母版(10.83×7.5in)

5.5 语言映射

维度 zh ja
design corp-{color} report-jp(固定)
回退标题 要点 n ポイント n
目录/结尾 目录 / 谢谢聆听 目次 / ご清聴ありがとうございました
续页标记 (续) (続き)

5.6 LLM 智能规划模式(2026-08-25 接入,08-26 改版为无降级)

后端:默认复用 opencode serveopencode serve --port 4096,零 Key,模型 mimo-v2.5-free 经基准选定);预留 OpenAI 兼容接口(DeepSeek 等,配 Key 即切)。配置项:LLM_BACKEND / OPENCODE_SERVE / OPENCODE_MODEL / OPENAI_API_* / PLAN_CHUNK_CHARS / PLAN_MAX_CHUNKS

产品决策(2026-08-26取消规则降级——要么产出总结版,要么明确报生成失败(含具体原因),绝不静默产出照搬版。规划失败抛 PlanningError → 任务 failed → 前端 toast 透传原因。

能力与流程

环节 实现 失败处理
长文档两级规划 >6000 字先分段通读(Map:每段提炼小节摘要+关键数据)→ 汇总产出大纲(Reduce);全文覆盖,不再只读前3000字 单段调用重试2次,仍失败报错
短文档直通 ≤6000 字直接出大纲 同上
页数硬约束 _validate_slides 裁剪保证最终页数不超上限;每轮尝试均为 LLM 规划,共两轮 两轮均败→任务失败
智能标题 /api/title/suggest 返回 3 个候选 首行截断
对话意图解析 parse_intent_llm + 封面替换规范化为改标题;规则句式兜底 返回帮助文案
数字保真 提示词约束 → 数字消毒器 → 引擎 --verify 门禁 保真不过→下一轮重新规划→仍败则报错

质量保障LLM 产出经 _validate_slides 严格校验(类型白名单/长度截断/首尾页规范/页数硬上限)+ _sanitize_fidelity 数字消毒;引擎 --verify 内容保真为最终门禁。

六、aura-ppt 集成方式

2026-08-24 选型切换(对比依据:项目资料/事前调查/引擎选型对比_ppt-master_vs_aura-ppt.md)。渲染出口统一为 aura-ppt;ppt-master 降级为辅助引擎,仅复用其文档解析(source_to_md)与网络搜图(image_search)独立脚本。

6.1 渲染调用链(action.run_generation

步骤 操作 实现 状态机
① 规划 GenerateConfig → plan dict planning.build_plan(cfg)(第五章算法) planning
② 写盘 projects/<slug>_<ts>/ 建 sources/source.md + plan.json action 直接写文件 planning
③ 渲染 engine.py --plan plan.json --output out.pptx [--template 公司模板.pptx] bridge.render_plan() subprocess rendering
④ 验证 engine.py --verify out.pptx --plan plan.json bridge.verify_output(),失败重试 1 次 rendering
⑤ 落库 ppt_records + versions(version_no=1) memory.save_generated_record done

6.2 调用实现要点

要点 说明
CLI 调用 subprocess.run([python, engine.py, ...], cwd=AURA_ENGINE_PATH),不 import 引擎内部模块
编码 子进程强制 PYTHONIOENCODING=utf-8 语义(bridge 以 utf-8 解码),规避 GBK 控制台报错
成功判据 渲染:退出码 0 且输出文件存在;验证:stdout 含「内容保真验证通过」且无「保真失败」
失败处理 EngineError → 任务 failed(错误码 2004);保真失败重试 1 次仍失败即终止
并发控制 进程内信号量(MAX_CONCURRENT_GENERATION),占满返回 2003 引擎繁忙
超时 渲染 600s / 验证 300s,超时抛 EngineError
模板模式 日语生成默认继承公司母版(5.4);模板模式页面尺寸随母版

6.3 生成目录结构

src/web/data/projects/<标题slug>_<时间戳>/
├── sources/
│   └── source.md          # 用户原始内容(留档/复盘)
├── plan.json              # 本次生成的完整页面规划(可独立重放渲染)
└── exports/
    └── <slug>_<时间戳>.pptx  # 成品文件(versions.file_path 相对引用)

plan.json 即「执行合同」:下载、预览、对话修改均以它为基准做增量演进(Sprint 2 局部重渲染)。

6.4 双引擎分工与配置

引擎 角色 路径配置 当前接入点
aura-ppt 主渲染引擎 AURA_ENGINE_PATH / AURA_ENGINE_SCRIPT bridge.render_plan / verify_output
ppt-master 辅助:文档解析 + 网络搜图 PPT_MASTER_PATH 文档解析已接入(agent/upload.py 调 source_to_md 五脚本);配图(image_search)待接

6.5 上传解析链路(2026-08-25 落地)

前端选择文件/粘贴URL → POST /api/upload(扩展名白名单 + 20MB + 24h 过期清理,存 UPLOAD_DIR
  → POST /api/parse → agent/upload.py 按扩展名分派:
     .md/.txt 直读;.pdf/.docx/.doc/.html/.xlsx/.xlsm/.pptx 经 subprocess 调
     ppt-master scripts/source_to_md/{pdf,doc,excel,ppt}_to_md.pyURL 调 web_to_md.py
  → 产物清洗(去转换器横幅/内部文件名引用/图片与资源引用、Markdown 反转义、压空行、3万字截断)
  → 回传 {text, chars},前端自动切回文本页并回填正文框
错误映射:3001 类型不支持 / 3002 超 20MB / 3003 解析失败 / 3004 内容为空

### 6.6 网络配图链路(2026-08-25 落地)

image_strategy=web → action 挂载 imaging.attach_images(plan.slides, project_dir) → 取前 MAX_IMAGE_SLIDES(4) 个内容页,以页面标题为关键词 → IMAGE_SEARCH_MODE web = subprocess 调 ppt-master scripts/image_search.py openverse/wikimedia 零配置;pexels/pixabay 配 Key 即启用) test = 本地样例图通道(IMAGE_SEARCH_TEST_DIRe2e 确定性) off = 禁用 → 成图落 projects//images/slide_x.jpg,路径写入 plan.slides[].image 并随 plan.json 落盘 → aura-ppt 渲染:content 页左文右图(文本区收窄 58%,图片等比缩放/垂直居中/细边框) 容错:单页失败仅记任务告警,全部失败降级为无图版式;verify 保真检查跳过 image 键。 现状:本机网络 openverse/wikimedia 不可达(超时/重置),管线与降级已验证, 真实搜图待更换网络环境或配置 pexels/pixabay Key 即自动启用。

6.5 引擎扩展点(已落地与待移植)

状态
五色板设计系统注册(corp-* 已落地(engine.py DESIGN_SYSTEMS
公司模板 assets 副本 已拷入 engine/aura-ppt/assets/
KPI 卡片 / 数据源脚注 / 阴影开关 / 精选图标 移植第一批(见选型对比文档第五章)
幻灯片插图片(content 页右图布局) 已落地(_place_image,见 6.6
4:3 画布 待试跑验证后实现
动画 ✕ 放弃(python-pptx 限制)

七、异常与错误码体系

对齐 PRD 4.3「错误提示以中文展示,不显示原始异常栈」。前端直接展示 message 字段,后端日志记录完整堆栈。

7.1 错误码全景表

错误码 触发场景 后端处理 前端提示文案
1001 注册用户名已存在 唯一索引冲突捕获 用户名已被使用
1002 登录用户名或密码错误 哈希比对失败 用户名或密码错误
1003 注册两次密码不一致 请求参数校验 两次输入的密码不一致
1004 未登录访问受限接口 Session 校验拦截 请先登录
2001 生成内容不足 20 字 校验拦截 内容至少需要 20 个字
2002 页数 min > max 校验拦截 最少页数不能大于最多页数
2003 引擎繁忙(并发上限) 任务队列拒绝 引擎繁忙,请稍后重试
2004 生成失败(引擎已重试) 任务标记 failed 生成失败,请重试
2005 生成中断(服务重启/超时) 任务标记 failed 生成中断,请重新生成
3001 上传文件类型不在白名单 扩展名校验拦截 不支持的文件类型
3002 上传文件超过 20MB 大小校验拦截 文件大小不能超过 20MB
3003 文档解析失败(损坏) 解析器异常捕获 文件损坏,无法读取
3004 解析结果为空 解析后空文本检测 文件内容为空
3005 文件上传失败 存储异常捕获 上传失败,请重试
4001 历史记录不存在/已被删除 查询无结果 该记录不存在或已被删除
4002 下载文件不存在 文件系统检查 文件已丢失,请重新生成
5001 修改密码原密码错误 哈希比对失败 原密码不正确
5002 用户名/密码格式非法 正则校验 用户名 3-20 位,密码至少 6 位
6001 引擎进程非零退出 subprocess stderr 解析 引擎内部异常,请联系管理员
6002 引擎配置文件缺失 启动自检 系统配置异常,请稍后重试

7.2 统一错误响应结构

{
  "code": 2001,
  "message": "内容至少需要 20 个字",
  "detail": null
}

detail 仅后端调试日志输出,永不返回前端

7.3 引擎失败分类与重试策略

分类 判定 动作 前端码
可恢复(网络/限速/图片源超时) 退出码非零 + stderr 匹配网络关键字 重试 1 次(指数退避 2s→4s 重试成功继续,失败 2004
不可恢复(脚本缺参/SVG 质检 error 无法修复) 退出码非零 + 逻辑错误 直接失败 2004 / 6001
资源性(同时任务超限) 任务队列满载 拒绝入队 2003
中断性(服务重启) 任务表 status=processing 且服务重启 标记 failed 2005

7.4 前端错误处理约定

场景 行为
字段校验错误 Toast 提示对应文案,不清空用户输入
接口 401 跳转登录页
联网失败(fetch 异常) 提示"网络异常,请检查网络后重试",保留页面状态
生成中失败 结果卡片红色区域展示错误文案 +「重新生成」按钮(US-2.7b)

八、安全设计

对齐 PRD 4.2。本项目为内网自用系统,采用适度防护,不做过度设计。

维度 措施 实现
密码存储 bcrypt 哈希,不存明文 werkzeug.security.generate_password_hash,成本因子 12
会话管理 Flask Session + 签名 Cookie SECRET_KEY 存于 config.SECRET_KEY(环境变量注入,不进仓库)
CSRF 防护 同源校验 所有写接口校验 Origin/Referer 头 + Session 内 CSRF Token
文件上传 扩展名白名单 + 大小限制 8 种格式白名单,≤20MB,存储到非 web 根目录
SQL 注入防护 参数化查询 全部 SQL 用 ? 占位符,禁止字符串拼接
路径穿越 下载路径校验 record_id 反查数据库后拼接相对路径,禁止直接拼接用户输入文件名
日志脱敏 不记录密码/令牌 统一日志过滤器屏蔽敏感字段
内网安全 仅监听 127.0.0.1 Flask 运行绑定本机回环地址,不开放公网

九、目录结构与部署

9.1 项目目录树

ppt-agent/
├── src/
│   ├── web/
│   │   ├── app.py              # Flask 入口 + 路由 + 中间件
│   │   ├── static/
│   │   │   ├── css/
│   │   │   ├── js/
│   │   │   └── lang/           # zh.json / ja.jsonUI 语言包)
│   │   ├── templates/          # 4 页面 Jinja2 模板
│   │   └── data/
│   │       ├── ppt.db          # SQLite
│   │       └── projects/        # 生成任务输出目录
│   ├── agent/                  # Agent 核心(第4章)
│   ├── engine_bridge/          # 引擎 CLI 调用封装
│   └── db/                     # 连接管理 + DDL
├── engine/
│   ├── aura-ppt/               # ⚠️ 主渲染引擎副本(真值,优化在此)
│   │   └── assets/公司模板.pptx
│   └── ppt-master/             # 辅助引擎副本(解析/搜图脚本复用)
├── tests/                      # 单元/集成测试
├── scripts/                    # 辅助脚本(DB 初始化等)
├── requirements.txt
├── config.py                   # 常量与配置
├── .gitignore
└── README.md

9.2 运行方式

# 安装依赖
pip install -r requirements.txt

# 初始化数据库(幂等,可重复执行)
python -m src.db.init

# 启动 Web 服务(默认绑定 127.0.0.1:5000
python src/web/app.py

9.3 配置项(config.py

配置 默认值 说明
AURA_ENGINE_PATH engine/aura-ppt/ 主渲染引擎目录(可配置)
PPT_MASTER_PATH engine/ppt-master/ 辅助引擎目录(解析/搜图)
COMPANY_TEMPLATE engine/aura-ppt/assets/公司模板.pptx 公司母版(--template 模式)
COMPANY_TEMPLATE_MODE ja 模板模式策略:always/ja/off
PROJECTS_PATH src/web/data/projects/ 生成任务输出根目录
DB_PATH src/web/data/ppt.db SQLite 文件路径
SECRET_KEY 环境变量 Flask Session 密钥
MAX_UPLOAD_MB 20 上传大小上限
ALLOWED_EXT 8 种格式 扩展名白名单
ALLOWED_SCENE report/training 场景枚举
ALLOWED_COLOR blue/green/purple/orange/gray 配色枚举
ALLOWED_LANG zh/ja 生成语言枚举
ALLOWED_CANVAS ppt169/ppt43 画布枚举
ALLOWED_IMAGE web/ai/off 配图策略枚举
LLM_BACKEND opencode 大模型后端:opencode(免费零 Key/ openai(兼容接口)
OPENCODE_SERVE http://127.0.0.1:4096 opencode serve 地址(--port 4096 常驻)
OPENCODE_MODEL opencode/mimo-v2.5-free 免费模型(三模型基准选定,44s/大纲)
OPENAI_API_BASE / OPENAI_API_KEY / OPENAI_MODEL 环境变量 DeepSeek 等 OpenAI 兼容后端切换入口(配 Key 即切)
LLM_TIMEOUT 180 LLM 请求超时(秒)

十、里程碑映射

对齐 PRD「五、用户故事与开发阶段对应」的 3 个 Sprint,补充到接口/数据表/模块粒度。

10.1 Sprint 1MVP:登录→生成→下载) 已完成(2026-08-24

目标:跑通"登录 → 输入文字 → 配置 → 生成 → 下载"完整链路。

内容 明细
接口 1-9 号(认证 4 + 生成 6
数据表 users + preferences + ppt_records + versionsversions 先建表,Sprint 2 启用回退)
Agent 模块 perception(基础解析)+ action(生成编排)+ orchestrator(生成流程)
引擎集成 7 步全流程 + branding 模板(blue+ 质检门禁
语言 zh / ja 生成 + UI zh/ja 双语言包(UI 语言切换第一期启用)

10.2 Sprint 2(对话修改 + 历史闭环) 已完成(2026-08-25

目标:生成→修改→回退 完整闭环 + 在线预览。

内容 明细
接口 10、13-17 号(预览 + 对话 + 历史 CRUD)
数据表 chat_messages 启用、versions 回退逻辑启用
Agent 模块 planning(修改意图解析)+ memory(版本/对话读写)
引擎集成 只重生成受影响页面(局部渲染)
前端 对话弹窗接入真实轮询 + 历史两版本展示

完成情况与偏差:接口 13/14 号、chat_messages 落库、两版本回退均已落地,e2e_chat 16 项断言全绿;「只重生成受影响页面」调整为 plan.json 变更 + aura 全量重渲(秒级,等效满足体验且保证整册风格一致,见 4.6);在线预览以 COM 导出 PNG 实现(见 4.7);智能标题(原 Sprint 3 内容)随 LLM 接入提前完成。

10.3 Sprint 3(体验完善)

目标:上传解析 + 智能标题 + 偏好 + UI 全语言。

内容 明细
接口 11-12、18-21 号(上传解析 + 设置)
Agent 模块 memory 偏好读写、upload 解析链路
引擎集成 source_to_md/*.py 8 格式转换 + 智能标题 DeepSeek 调用
前端 设置页生成偏好绑定 + 历史页语言筛选(预留,本期可选)

进度:上传解析已提前落地(2026-08-25,见 6.5e2e_upload 21 项断言全绿);智能标题已于 LLM 接入时完成;设置偏好与历史语言筛选已落地(e2e_settings 18 项断言全绿);UI 全语言四页收尾完成(login/history 补 i18n 与切换入口);网络配图管线落地(见 6.6,e2e_image 9 项断言全绿)。Sprint 3 全部用户故事已覆盖,余一项环境依赖:真实搜图源需换网络或配 Key。

10.4 里程碑与成果物对齐

里程碑 关联成果物 验收口径
Sprint 1 完成 03 源码(主体) US-1.1~2.8 通过测试顾问验收
Sprint 2 完成 03 源码(完整)+ 04 实验报告起点 修改/回退闭环可演示
Sprint 3 完成 04 实验报告 全部 23 条用户故事覆盖
全量定稿 05 AI使用日志 + 06 演示视频 整理 8 月日志 + 录制完整流程

全 10 章完成。v0.3 已同步 Sprint 2 落地状态(对话修改 / 在线预览 / LLM 零Key 接入),e2e_web、e2e_chat、e2e_llm 三套测试全绿。