README增加完整从头到尾详细教程

This commit is contained in:
2026-05-29 14:37:18 +08:00
parent 7e2adeb142
commit cc65e368a9
2 changed files with 336 additions and 166 deletions

View File

@@ -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/<filename>` 两处的 `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` 且文件名不以 `_` 开头