From cc65e368a936592b570aa4312922b3ab35053602 Mon Sep 17 00:00:00 2001 From: xiaji Date: Fri, 29 May 2026 14:37:18 +0800 Subject: [PATCH] =?UTF-8?q?README=E5=A2=9E=E5=8A=A0=E5=AE=8C=E6=95=B4?= =?UTF-8?q?=E4=BB=8E=E5=A4=B4=E5=88=B0=E5=B0=BE=E8=AF=A6=E7=BB=86=E6=95=99?= =?UTF-8?q?=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ppt_manager/README.md | 150 ++++++++++++++++- ppt_manager_v2/README.md | 352 +++++++++++++++++++++------------------ 2 files changed, 336 insertions(+), 166 deletions(-) diff --git a/ppt_manager/README.md b/ppt_manager/README.md index fe6bea1..3dfc3ac 100644 --- a/ppt_manager/README.md +++ b/ppt_manager/README.md @@ -2,6 +2,123 @@ PPT管理系统,实现**静态模板内容**与**动态数据内容**的智能合并。 +--- + +## 📚 从零开始完整教程(必读) + +### 第一步:创建你的第一个静态PPT模板 + +#### 方式A: 运行脚本快速生成示例(推荐新手) + +```bash +cd f:\ppt\ppt_manager +python create_sample_template.py +``` + +✅ 自动生成: `static_ppt/macro_analysis_template.pptx` (23页空白模板) + +#### 方式B: 手工创建属于你自己的模板(正式项目用) + +1. **打开Microsoft PowerPoint → 新建空白演示文稿** + +2. **保存到**: `f:\ppt\ppt_manager\static_ppt\你的模板名称.pptx` + +3. **页面布局建议**: + | 页码 | 内容类型 | 说明 | + |------|----------|------| + | 1页 | 封面 | static | + | 2页 | 目录 | static | + | 3页 | 分析框架 | static | + | 4页 | GDP图表页 | **dynamic** → Python脚本生成 | + | 5页 | CPI图表页 | **dynamic** → Python脚本生成 | + | 6-23页 | 其他原理内容 | static | + +4. **保存模板** + +--- + +### 第二步:理解 `config/project_config.yaml` 配置 + +```yaml +projects: + macro_analysis: # 项目ID + name: "宏观数据分析报告" # 显示名称 + static_ppt: "static_ppt/macro_analysis_template.pptx" # 模板路径 ✅ + total_slides: 23 # 总页数 + slide_mapping: + 1: static # 第1页 = 静态来自模板 + 2: static # 第2页 = 静态来自模板 + 3: static # 第3页 = 静态来自模板 + 4: dynamic_chart_gdp # 第4页 = 动态执行GDP脚本生成图片插入 + 5: dynamic_chart_inflation # 第5页 = 动态执行CPI脚本生成图片插入 + 6: static + ...更多... + 23: static + + dynamic_generators: # 动态key 到 脚本文件路径 的映射 + dynamic_chart_gdp: "scripts/gdp_chart.py" + dynamic_chart_inflation: "scripts/inflation_chart.py" + dynamic_table_employment: "scripts/employment_table.py" + dynamic_chart_trade: "scripts/trade_chart.py" + dynamic_content_market: "scripts/market_analysis.py" +``` + +**关键点**: +- `slide_mapping` 里的 key 如果不是 `static`,就去 `dynamic_generators` 里找对应脚本执行 +- 脚本返回PNG图片路径,系统把图片插入对应新生成的页面 + +--- + +### 第三步:更新动态数据(改脚本取真实数据) + +打开 `scripts/gdp_chart.py` 改成你自己的采集逻辑: + +```python +def generate(output_dir): + import pandas as pd + + # -------------------------- + # 在这里替换成你真实的取数代码: + # -------------------------- + # df = pd.read_sql("SELECT * FROM gdp_stats", conn) + # 或 df = pd.read_csv("你的真实GDP数据文件.csv") + # 或 API调用: requests.get("https://stats.gov.cn/api/gdp") + + # 下面是示例模拟数据,跑通后替换成真实采集代码 + quarters = ['2026Q1', '2026Q2'] + actual_data_from_api = [5.2, 5.1] + + # 生成matplotlib图 + import matplotlib.pyplot as plt + plt.plot(quarters, actual_data_from_api) + plt.savefig(f"{output_dir}/my_real_gdp_chart.png") + + return f"{output_dir}/my_real_gdp_chart.png" +``` + +**其他脚本同理修改**: +- CPI → `scripts/inflation_chart.py` +- 就业数据 → `scripts/employment_table.py` +- 贸易数据 → `scripts/trade_chart.py` +- 市场分析 → `scripts/market_analysis.py` + +--- + +### 第四步:启动Web生成 + +```bash +pip install -r requirements.txt +python app.py +``` + +浏览器打开 **http://localhost:5000** + +点击项目卡片上的 🚀 **"开始生成"** 按钮 + +✅ 生成的PPT在 `f:\ppt\ppt_manager\output\` 目录 + +--- + ## ✨ 核心特性 - 📁 **静态PPT管理**: 固定不变的原理内容放在本地PPT模板中 @@ -25,7 +142,7 @@ ppt_manager/ │ ├── trade_chart.py # 进出口图表 │ └── market_analysis.py # 市场分析图表 ├── dynamic_content/ # 动态生成的图片存放 -├── output/ # 最终生成的PPT输出目录 +├── output/ # 👉 最终生成的PPT在这里 ├── logs/ # 日志目录 ├── src/ │ ├── config_loader.py # 配置加载器 @@ -34,13 +151,13 @@ ppt_manager/ │ └── ppt_generator.py # 主合成引擎 ├── templates/ │ └── index.html # Web界面 -├── app.py # Flask Web应用 +├── app.py # Flask Web应用(端口5000) ├── main.py # 命令行入口 -├── create_sample_template.py # 创建示例模板脚本 +├── create_sample_template.py # ✅ 快速创建示例模板脚本 └── requirements.txt # Python依赖 ``` -## 🚀 快速开始 +## 🚀 快速开始(TL;DR) ### 1. 安装依赖 @@ -70,7 +187,7 @@ python main.py macro_analysis ## ⚙️ 配置说明 -在 [config/project_config.yaml](file:///f:/ppt/ppt_manager/config/project_config.yaml) 中配置: +在 `config/project_config.yaml` 中配置: ```yaml projects: @@ -79,14 +196,15 @@ projects: static_ppt: "static_ppt/macro_analysis_template.pptx" total_slides: 23 slide_mapping: - 1: static # 静态页,来自模板 + 1: static 2: static 3: static - 4: dynamic_chart_gdp # 动态页,执行对应脚本 + 4: dynamic_chart_gdp 5: dynamic_chart_inflation ... dynamic_generators: - dynamic_chart_gdp: "scripts/gdp_chart.py" # 脚本对应关系 + dynamic_chart_gdp: "scripts/gdp_chart.py" + dynamic_chart_inflation: "scripts/inflation_chart.py" ... ``` @@ -113,3 +231,19 @@ def generate(output_dir): | 10页 | dynamic | 进出口贸易 | 每月更新 | | 13页 | dynamic | A股市场分析 | 每周更新 | | 其他页 | static | 原理、方法论 | 固定不变 | + +--- + +## ❓ 常见问题排查 + +**Q1: 报错 `FileNotFoundError: 静态PPT文件不存在: static_ppt/macro_analysis_template.pptx`** + +运行 `python create_sample_template.py` 生成示例模板 + +**Q2: 访问localhost:5000首页报错** + +检查Flask是否正常启动在5000端口,以及templates目录是否存在 + +**Q3: 生成的PPT里动态页是空白** + +检查动态脚本是否报错,查看logs目录下日志排查 diff --git a/ppt_manager_v2/README.md b/ppt_manager_v2/README.md index ff486e5..71d070b 100644 --- a/ppt_manager_v2/README.md +++ b/ppt_manager_v2/README.md @@ -4,24 +4,147 @@ --- -## 🚀 快速开始 +## 📚 V2.0 从零开始完整教程(必读) -### 1. 环境准备 +### 第一步:PPT模板锚点(Anchor)命名法 — 核心概念! + +V2.0 **不再用页码绑定**(解决老板插一页所有配置全乱的问题),改用 **PowerPoint形状名称** 绑定。 + +#### 1.1 在PowerPoint里看"选择窗格"给Shape改名 + +打开Microsoft PowerPoint做以下操作: + +1. **新建空白PPT → 插入一张图表**(插什么类型不重要,后续python-pptx会替换数据源) + +2. **菜单栏 → 开始 → 选择 → 选择窗格** (或快捷键 `Alt + F10`) + +3. **右侧弹出"选择窗格"**,点击里面的shape名称可以改名! + +4. **把你的图表改名为**: `chart_gdp` + +5. **把你的CPI图表改名为**: `chart_cpi` + +6. **保存PPT模板** 到你想放的位置 + +#### 为什么要这样做? + +```yaml +# 以前V1.0是绑定页码 -> 脆弱! +slide_mapping: + 5: dynamic_chart_gdp # 老板在第3页插一页,GDP图表就跑到第6页了!配置全乱! + +# 现在V2.0是绑定锚点名称 -> 不管页码怎么变,只要Shape名不变就找得到! +anchors: + - name: chart_gdp # ✅ 锚点Shape名,不管在第3页还是第300页都能精确定位! + type: native_chart_update + plugin: gdp_chart +``` + +✅ **锚点定位是V2.0对V1.0最本质的改进!** + +--- + +### 第二步:原生图表更新原理(不是插PNG!) + +#### V2.0 不是 "生成matplotlib图 → 转PNG → 插入PPT" + +#### V2.0 是 "把categories和series传给python-pptx → 直接替换PPT内嵌Chart数据源" + +```python +# core/native_chart.py 核心代码 +chart_data = CategoryChartData() +chart_data.categories = ['2026Q1', '2026Q2', '2026Q3'] +chart_data.add_series('GDP同比增长', [5.2, 5.0, 5.1]) +chart.replace_data(chart_data) # ✅ 原生数据源替换! +``` + +**这样做的巨大好处**: +- 生成的PPT里 **双击图表可以进入Excel编辑数据** +- 自动继承PPT母版的 **主题配色和字体** +- 保留图表原有的 **进入/强调/退出动画效果** +- 图表文字是矢量的,放大不会模糊 + +--- + +### 第三步:插件开发 — BaseGenerator 标准接口 + +V2.0插件目录 `plugins/generators/` 下的模块,**系统启动时自动扫描注册**,无需import,真正"即插即用"。 + +#### 插件骨架: + +```python +# plugins/generators/your_plugin.py +from plugins.base_generator import BaseGenerator, ABC, abstractmethod +import pandas as pd + +class YourGenerator(BaseGenerator): # ✅ 必须继承BaseGenerator + generator_id = "your_plugin_id" # ✅ 必填!全局唯一 + generator_name = "显示用名称" + + def fetch_data(self, params): + """步骤1: 取数""" + # params 里有 Web端传的 year/quarter + year = params.get('year', 2026) + + # 连接数据库/调API/读Excel/爬网站 + self._data = pd.DataFrame({ + 'month': ['1月', '2月', '3月'], + 'value': [100, 102, 105] + }) + return True + + def render(self): + """步骤2: 返回原生图表要的 categories/series 格式""" + return { + 'chart_type': 'line', # line/bar/column 等 + 'categories': self._data['month'].tolist(), + 'series': { + '指标名称': self._data['value'].tolist() + }, + 'anchor': 'chart_your_anchor_name' # ✅ 跟PPT选择窗格里的名称一致! + } +``` + +#### 插件启动时自动扫描发现日志: +``` +SUCCESS | 加载插件 [cpi_chart]: CPI/PPI通胀图表生成器 +SUCCESS | 加载插件 [gdp_chart]: GDP趋势图表生成器 +INFO | 插件扫描完成,共加载 2 个生成器 +``` + +--- + +### 第四步:Web端操作 + WebSocket实时日志推流 ```bash cd f:\ppt\ppt_manager_v2 pip install -r requirements_v2.txt -``` - -### 2. 启动WebSocket服务 - -```bash python web_socket_app.py ``` -### 3. 浏览器访问 +打开浏览器访问 **http://localhost:5001** -打开 **http://localhost:5001** +V2.0前端三大区域: + +| 区域 | 功能 | +|------|------| +| 左上角 | **参数化表单**: Year/Quarter 传给插件fetch_data() | +| 左下角 | **实时面板**: 进度条 0-100% + Loguru日志逐行WebSocket推送 | +| 右侧 | **已加载插件列表** + **历史生成文件一键下载** | + +生成的PPT在:`f:\ppt\output\` + +--- + +## 🚀 TL;DR 快速启动 + +```bash +cd f:\ppt\ppt_manager_v2 +pip install -r requirements_v2.txt +python web_socket_app.py +``` + +打开: http://localhost:5001 --- @@ -30,23 +153,23 @@ python web_socket_app.py ``` ppt_manager_v2/ ├── 📄 web_socket_app.py # WebSocket服务端 -├── 📄 orchestrator.py # 主编排引擎(Pipeline) +├── 📄 orchestrator.py # 主编排引擎(6步Pipeline) ├── 📄 requirements_v2.txt # Python依赖包 ├── 📄 README.md # 本文件 ├── ├── 📂 core/ # 核心层 -│ ├── anchor_engine.py # ✅ 锚点定位引擎 -│ ├── native_chart.py # ✅ 原生图表数据源更新 -│ └── conditional_renderer.py # ✅ 条件渲染引擎(动态增删页) +│ ├── anchor_engine.py # ✅ 锚点定位引擎 - Shape Name 匹配 +│ ├── native_chart.py # ✅ 原生图表数据源更新 - chart.replace_data() +│ └── conditional_renderer.py # ✅ 条件渲染引擎 - 表达式求值动态增删页 ├── ├── 📂 plugins/ # 插件化架构 -│ ├── base_generator.py # BaseGenerator 标准接口 -│ └── generators/ # 插件目录(自动扫描注册) +│ ├── base_generator.py # BaseGenerator 抽象基类标准接口 +│ └── generators/ # 插件目录 - 系统启动自动扫描注册 │ ├── gdp_generator.py # GDP趋势图生成插件 │ └── cpi_generator.py # CPI/PPI图表生成插件 ├── ├── 📂 ai/ # AI智能化 -│ └── llm_analyst.py # LLM分析师 + Diff对比器 +│ └── llm_analyst.py # LLM分析师生成洞察结论 + Diff对比 ├── ├── 📂 connectors/ # 多数据源适配 │ └── sql_connector.py # MySQL/ClickHouse/REST API/CSV @@ -58,7 +181,7 @@ ppt_manager_v2/ │ └── index_v2.html # WebSocket前端页面 ├── ├── 📂 logs/ # 日志目录 -└── 📂 web/ # 备用(template_dir配置用) +└── 📂 web/ # 备用template_dir └── templates/ └── index_v2.html ``` @@ -73,17 +196,15 @@ ppt_manager_v2/ #### 1.1 锚点(Anchor)定位引擎 → 无惧页码变动 -**痛点解决**: 旧版YAML写 `page: 5`,老板在第3页插一页,所有配置页码全乱。 +**痛点解决**: V1.0 YAML写 `page: 5`,老板在第3页插一页,所有配置页码全乱。 **新版方案**: - -1. 打开你的PPT模板 → 选中一个 **Shape/图表/文本框** -2. 在PowerPoint的 **"选择窗格"** 里给Shape改名(例如:`chart_gdp_trend`) -3. 在YAML里直接配置 **锚点名**,不是页码: +1. PPT → 选中Chart → Alt+F10 打开选择窗格 → 改名称为 `chart_gdp` +2. YAML里直接配置锚点名,不是页码 ```yaml anchors: - - name: chart_gdp_trend # Shape Name(选择窗格里的名称) + - name: chart_gdp_trend # 匹配PowerPoint选择窗格里的名称 type: native_chart_update plugin: gdp_chart ``` @@ -94,23 +215,19 @@ anchors: #### 1.2 原生图表数据源直接更新(不是插PNG!) -**痛点解决**: 旧版先生成PNG再插入PPT → 图片无法编辑、丢失主题配色和动画效果、文件体积大。 - -**新版方案**: 用 `python-pptx` 直接替换PPT内嵌图表的Excel数据源: - ```python -# 在native_chart.py里的实现 +# native_chart.py chart_data = CategoryChartData() chart_data.categories = ['2026Q1', '2026Q2', '2026Q3'] chart_data.add_series('GDP同比增长', [5.2, 5.0, 5.1]) chart.replace_data(chart_data) # ✅ 原生数据源替换! ``` -**这样做的好处**: -- ✅ 生成的PPT里**双击图表可以进入Excel编辑** -- ✅ 自动继承PPT母版的**主题配色** -- ✅ 保留图表原有的**进入/强调动画**效果 -- ✅ 文本清晰,不是模糊的点阵图 +**好处**: +- ✅ 双击图表可以进入Excel编辑 +- ✅ 继承PPT母版的主题配色 +- ✅ 保留页面上原有的动画效果 +- ✅ 矢量文字放大不模糊 **代码参考**: [core/native_chart.py](file:///f:/ppt/ppt_manager_v2/core/native_chart.py#L12-L90) @@ -118,8 +235,6 @@ chart.replace_data(chart_data) # ✅ 原生数据源替换! #### 1.3 条件渲染与动态增删页 -**能力描述**: 支持规则判断动态插入/隐藏页面: - ```yaml slide_conditions: - condition: unemployment_rate > 5.1 @@ -128,7 +243,7 @@ slide_conditions: position: 5 ``` -表达式求值:`unemployment_rate > 5.1 AND gdp_growth < 5.0` 等复合条件。 +支持复合条件: `unemployment_rate > 5.1 AND gdp_growth < 5.0` **代码参考**: [core/conditional_renderer.py](file:///f:/ppt/ppt_manager_v2/core/conditional_renderer.py#L1-L100) @@ -138,62 +253,47 @@ slide_conditions: #### 2.1 BaseGenerator 标准接口 -所有插件继承 `BaseGenerator` 抽象基类,实现两个方法: - ```python -# plugins/base_generator.py 定义 class BaseGenerator(ABC): generator_id = "gdp_chart" - generator_name = "GDP趋势生成器" @abstractmethod - def fetch_data(self, params): # 步骤A:取数 + def fetch_data(self, params): # A: 取数 pass @abstractmethod - def render(self): # 步骤B:渲染返回原生图表数据 + def render(self): # B: 渲染 pass ``` -插件例子 → [plugins/generators/gdp_generator.py](file:///f:/ppt/ppt_manager_v2/plugins/generators/gdp_generator.py) +插件例子: [plugins/generators/gdp_generator.py](file:///f:/ppt/ppt_manager_v2/plugins/generators/gdp_generator.py) --- #### 2.2 插件自动扫描注册 -启动时系统自动扫描 `plugins/generators/` 目录下所有 `.py` 文件,发现继承 BaseGenerator 且有 `generator_id` 的类自动注册到插件管理器,**无需修改任何注册代码**,真正即插即用。 +启动时自动扫描 `plugins/generators/` 目录,继承 BaseGenerator 且有 `generator_id` 的类自动注册。 ``` -# 启动日志里可以看到: SUCCESS | 加载插件 [cpi_chart]: CPI/PPI通胀图表生成器 SUCCESS | 加载插件 [gdp_chart]: GDP趋势图表生成器 -INFO | 插件扫描完成,共加载 2 个生成器 ``` -**代码参考**: [plugins/base_generator.py - GeneratorPluginManager.discover_plugins()](file:///f:/ppt/ppt_manager_v2/plugins/base_generator.py#L46-L89) +**代码参考**: [discover_plugins()](file:///f:/ppt/ppt_manager_v2/plugins/base_generator.py#L46-L89) --- #### 2.3 参数化生成 -Web端不是单一"开始生成"按钮,而是传参给后端插件: - ```javascript -// 前端传params给WebSocket socket.emit('start_generation', { - params: { - year: 2026, - quarter: "Q2", - theme: "保守型" - } + params: { year: 2026, quarter: "Q2" } // 传给后端所有插件 }); ``` -插件的 `fetch_data(params)` 拿到这些参数去数据库/API拉对应区间的数据。 - --- -### 三、WebSocket Web交互体验(实时日志推流) +### 三、WebSocket Web交互体验 #### 3.1 启动服务 @@ -201,120 +301,84 @@ socket.emit('start_generation', { python web_socket_app.py ``` -控制台输出: -``` -================================================================= - 🚀 PPT智能管理系统 V2.0 - WebSocket实时日志版 - 请在浏览器打开: http://localhost:5001 -================================================================= -``` +http://localhost:5001 -#### 3.2 前端页面三大区域 +三大区域: **参数表单区 / 实时日志区 / 文件下载区** -| 区域 | 功能 | -|------|------| -| **左上角参数表单** | Year/Quarter 参数化输入 | -| **左下角实时面板** | 动态进度条 0-100% + Loguru日志逐行推送 | -| **右侧边栏** | 已加载插件清单 + 历史生成文件下载列表 | - -**WebSocket后端代码**: [web_socket_app.py](file:///f:/ppt/ppt_manager_v2/web_socket_app.py#L1-L95) +**代码参考**: [web_socket_app.py](file:///f:/ppt/ppt_manager_v2/web_socket_app.py#L1-L95) --- ### 四、主编排引擎 Pipeline -Orchestrator 是串联所有模块的大脑: - ```python -# orchestrator.py - run_full_pipeline() +# orchestrator.py Pipeline def run_full_pipeline(self): - self.load_template() # 1. 打开PPT,扫描所有锚点 - self.run_plugins(params) # 2. 并行执行所有插件 fetch_data + render + self.load_template() # 1. 扫描PPT里所有锚点名称 + self.run_plugins(params) # 2. 并行执行所有插件 fetch+render self.update_native_charts() # 3. 原生图表数据源逐个更新 self.ai_generate_summary() # 4. LLM生成200字洞察文本 self.process_conditions() # 5. 条件表达式求值动态增删页 return self.save() # 6. 保存最终PPT ``` -**Pipeline代码位置**: [orchestrator.py - 第244-251行](file:///f:/ppt/ppt_manager_v2/orchestrator.py#L244-L251) +**代码参考**: [orchestrator.py Pipeline](file:///f:/ppt/ppt_manager_v2/orchestrator.py#L244-L251) --- ### 五、AI 智能化(LLM + Diff对比) -#### 5.1 LLM 自动生成"分析结论" - -图表只能展示"是什么",LLM帮你解释"为什么": - ```python # ai/llm_analyst.py -prompt = "基于以下数据:{gdp}、{cpi},200字专业分析师口吻总结本月市场" llm.generate_analysis({ 'gdp_growth': 5.1, 'cpi': 0.9, 'unemployment': 5.2 }) - -# 返回示例: -""" -本月宏观经济洞察:GDP增长5.1%,动能平稳。CPI同比0.9%, -通胀水平温和为货币政策留出空间。就业失业率5.2%, -青年失业率需重点关注... -""" +# 返回: 本月宏观经济洞察:GDP增长5.1%,动能平稳... ``` -支持 **Mock模式** / **OpenAI** / **通义千问** 三种provider切换。 +Provider: **Mock模式**(默认)/OpenAI/通义千问可配置 **代码参考**: [ai/llm_analyst.py](file:///f:/ppt/ppt_manager_v2/ai/llm_analyst.py#L1-L90) --- -## 📄 YAML V2版 配置范式参考 +## 📄 YAML V2版 配置范式 ```yaml project_name: "宏观经济月度分析报告" version: "2.0" -template: "macro_analysis_template.pptx" +template: "template_ppt/your_template.pptx" -params: # 参数化生成默认值 +params: default_year: 2026 default_quarter: "Q2" -anchors: # 锚点绑定关系 +anchors: - name: chart_gdp type: native_chart_update plugin: gdp_chart chart_type: line - fallback: gdp_fallback.png - name: chart_cpi type: native_chart_update plugin: cpi_chart -slide_conditions: # 条件渲染规则 - - condition: unemployment_rate > 5.1 - action: insert_slide - position: 5 - -connectors: # 多数据源配置 - mysql_stats: {type: mysql, database: macro_stats} - -ai: # LLM配置 - provider: mock # mock/openai/tongyi +ai: + provider: mock # mock / openai / tongyi model: qwen-turbo -scheduler: # 定时调度 - cron: "0 8 1 * *" # 每月1号早上8点 +connectors: + mysql_stats: {type: mysql, database: macro_stats} ``` -配置文件位置: [config/project_config_v2.yaml](file:///f:/ppt/ppt_manager_v2/config/project_config_v2.yaml) +配置文件: [config/project_config_v2.yaml](file:///f:/ppt/ppt_manager_v2/config/project_config_v2.yaml) --- ## 🔧 命令行非交互模式测试 -直接跑整个Pipeline验证所有环节: - ```bash cd f:\ppt\ppt_manager_v2 python -c " @@ -322,13 +386,12 @@ import sys sys.path.insert(0, '.') from orchestrator import Orchestrator orch = Orchestrator() -orch.load_template() # 检查: 锚点扫描 -result = orch.run_plugins() # 检查: 插件取数+渲染 -print('插件结果:', list(result.keys())) -orch.update_native_charts() # 检查: 原生图表更新 -orch.ai_generate_summary() # 检查: LLM生成 -orch.save() # 检查: 输出文件 -print('✅ 全流程通过!') +orch.load_template() +result = orch.run_plugins() +print('插件:', list(result.keys())) +orch.update_native_charts() +orch.save() +print('✅ OK!') " ``` @@ -336,48 +399,21 @@ print('✅ 全流程通过!') ## ❓ 常见问题排查 -### Q1: TemplateNotFound jinja2 错误 +**Q1: TemplateNotFound jinja2: index_v2.html** -**现象**: `jinja2.exceptions.TemplateNotFound: index_v2.html` +两处模板文件互为备份: +- `ppt_manager_v2/templates/index_v2.html` +- `ppt_manager_v2/web/templates/index_v2.html` -**已修复**: web_socket_app.py第16行明确了 template_folder 绝对路径,且文件在两处备份: -- `f:\ppt\ppt_manager_v2\templates\index_v2.html` (Flask标准位置) -- `f:\ppt\ppt_manager_v2\web\templates\index_v2.html` (配置位置) +代码里已用 `Path(__file__).parent / "web" / "templates"` 绝对路径 ---- +**Q2: 下载文件找不到 /api/files 返回空** -### Q2: 下载文件找不到 /api/files 返回空 +输出目录在 `f:\ppt\output` (与代码目录同级的output),不在 `ppt_manager_v2\output` 下,已统一修正为 `base_dir.parent / "output"` -**已修复**: `/api/files` 和 `/download/` 两处的 `base_dir / "output"` 统一改为 `base_dir.parent / "output"` 指向 `f:\ppt\output\`。 - ---- - -### Q3: 'NoneType' object has no attribute 'text' - -**现象**: 加载模板时报错 - -**已修复**: [orchestrator.py](file:///f:/ppt/ppt_manager_v2/orchestrator.py#L75-L90) 先判断 `if slide.shapes.title:` 再安全访问 `.text`。 - ---- - -### Q4: 插件不显示/不执行 - -检查两点: -1. 插件类继承 `BaseGenerator(ABC)` -2. 类属性 `generator_id` 不能是 `None` -3. 目录在 `plugins/generators/*.py` 且文件名不以 `_` 开头 - ---- - -## 📌 维护信息 - -| 项目 | 详情 | -|------|------| -| **版本** | V2.0 2026-05-29 | -| **入口** | `python web_socket_app.py` | -| **前端地址** | http://localhost:5001 | -| **输出目录** | `f:\ppt\output\*.pptx` | -| **日志目录** | `f:\ppt\ppt_manager_v2\logs\` | -| **核心模块** | orchestrator.py / anchor_engine.py / native_chart.py | -| **插件目录** | plugins/generators/ | +**Q3: 插件不显示/启动日志里没扫到** +检查三点: +1. 类继承 `BaseGenerator(ABC)` +2. 类属性 `generator_id` 不是 `None` +3. 文件在 `plugins/generators/*.py` 且文件名不以 `_` 开头