Files
ppt/ppt_manager_v2/README.md

420 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 📊 PPT智能管理系统 V2.0 说明书
基于 **锚点定位** + **原生图表更新** + **插件化架构** + **WebSocket实时日志** 的下一代PPT自动化平台。
---
## 📚 V2.0 从零开始完整教程(必读)
### 第一步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
python web_socket_app.py
```
打开浏览器访问 **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
---
## 📁 项目目录结构
```
ppt_manager_v2/
├── 📄 web_socket_app.py # WebSocket服务端
├── 📄 orchestrator.py # 主编排引擎6步Pipeline
├── 📄 requirements_v2.txt # Python依赖包
├── 📄 README.md # 本文件
├──
├── 📂 core/ # 核心层
│ ├── anchor_engine.py # ✅ 锚点定位引擎 - Shape Name 匹配
│ ├── native_chart.py # ✅ 原生图表数据源更新 - chart.replace_data()
│ └── conditional_renderer.py # ✅ 条件渲染引擎 - 表达式求值动态增删页
├──
├── 📂 plugins/ # 插件化架构
│ ├── base_generator.py # BaseGenerator 抽象基类标准接口
│ └── generators/ # 插件目录 - 系统启动自动扫描注册
│ ├── gdp_generator.py # GDP趋势图生成插件
│ └── cpi_generator.py # CPI/PPI图表生成插件
├──
├── 📂 ai/ # AI智能化
│ └── llm_analyst.py # LLM分析师生成洞察结论 + Diff对比
├──
├── 📂 connectors/ # 多数据源适配
│ └── sql_connector.py # MySQL/ClickHouse/REST API/CSV
├──
├── 📂 config/
│ └── project_config_v2.yaml # V2版配置文件范式
├──
├── 📂 templates/ # Flask模板目录
│ └── index_v2.html # WebSocket前端页面
├──
├── 📂 logs/ # 日志目录
└── 📂 web/ # 备用template_dir
└── templates/
└── index_v2.html
```
> **输出目录**: `f:\ppt\output\` 所有生成的PPT文件在这里
---
## 🎯 五大核心增强能力
### 一、PPT核心操作层从"拼图"到"原生替换"
#### 1.1 锚点(Anchor)定位引擎 → 无惧页码变动
**痛点解决**: V1.0 YAML写 `page: 5`老板在第3页插一页所有配置页码全乱。
**新版方案**:
1. PPT → 选中Chart → Alt+F10 打开选择窗格 → 改名称为 `chart_gdp`
2. YAML里直接配置锚点名不是页码
```yaml
anchors:
- name: chart_gdp_trend # 匹配PowerPoint选择窗格里的名称
type: native_chart_update
plugin: gdp_chart
```
**代码参考**: [core/anchor_engine.py](file:///f:/ppt/ppt_manager_v2/core/anchor_engine.py#L21-L60)
---
#### 1.2 原生图表数据源直接更新不是插PNG
```python
# 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) # ✅ 原生数据源替换!
```
**好处**:
- ✅ 双击图表可以进入Excel编辑
- ✅ 继承PPT母版的主题配色
- ✅ 保留页面上原有的动画效果
- ✅ 矢量文字放大不模糊
**代码参考**: [core/native_chart.py](file:///f:/ppt/ppt_manager_v2/core/native_chart.py#L12-L90)
---
#### 1.3 条件渲染与动态增删页
```yaml
slide_conditions:
- condition: unemployment_rate > 5.1
action: insert_slide
template: "risk_warning_template.pptx"
position: 5
```
支持复合条件: `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)
---
### 二、插件化数据流架构(真正的即插即用)
#### 2.1 BaseGenerator 标准接口
```python
class BaseGenerator(ABC):
generator_id = "gdp_chart"
@abstractmethod
def fetch_data(self, params): # A: 取数
pass
@abstractmethod
def render(self): # B: 渲染
pass
```
插件例子: [plugins/generators/gdp_generator.py](file:///f:/ppt/ppt_manager_v2/plugins/generators/gdp_generator.py)
---
#### 2.2 插件自动扫描注册
启动时自动扫描 `plugins/generators/` 目录,继承 BaseGenerator 且有 `generator_id` 的类自动注册。
```
SUCCESS | 加载插件 [cpi_chart]: CPI/PPI通胀图表生成器
SUCCESS | 加载插件 [gdp_chart]: GDP趋势图表生成器
```
**代码参考**: [discover_plugins()](file:///f:/ppt/ppt_manager_v2/plugins/base_generator.py#L46-L89)
---
#### 2.3 参数化生成
```javascript
socket.emit('start_generation', {
params: { year: 2026, quarter: "Q2" } // 传给后端所有插件
});
```
---
### 三、WebSocket Web交互体验
#### 3.1 启动服务
```bash
python web_socket_app.py
```
http://localhost:5001
三大区域: **参数表单区 / 实时日志区 / 文件下载区**
**代码参考**: [web_socket_app.py](file:///f:/ppt/ppt_manager_v2/web_socket_app.py#L1-L95)
---
### 四、主编排引擎 Pipeline
```python
# orchestrator.py Pipeline
def run_full_pipeline(self):
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
```
**代码参考**: [orchestrator.py Pipeline](file:///f:/ppt/ppt_manager_v2/orchestrator.py#L244-L251)
---
### 五、AI 智能化LLM + Diff对比
```python
# ai/llm_analyst.py
llm.generate_analysis({
'gdp_growth': 5.1,
'cpi': 0.9,
'unemployment': 5.2
})
# 返回: 本月宏观经济洞察GDP增长5.1%,动能平稳...
```
Provider: **Mock模式**(默认)/OpenAI/通义千问可配置
**代码参考**: [ai/llm_analyst.py](file:///f:/ppt/ppt_manager_v2/ai/llm_analyst.py#L1-L90)
---
## 📄 YAML V2版 配置范式
```yaml
project_name: "宏观经济月度分析报告"
version: "2.0"
template: "template_ppt/your_template.pptx"
params:
default_year: 2026
default_quarter: "Q2"
anchors:
- name: chart_gdp
type: native_chart_update
plugin: gdp_chart
chart_type: line
- name: chart_cpi
type: native_chart_update
plugin: cpi_chart
ai:
provider: mock # mock / openai / tongyi
model: qwen-turbo
connectors:
mysql_stats: {type: mysql, database: macro_stats}
```
配置文件: [config/project_config_v2.yaml](file:///f:/ppt/ppt_manager_v2/config/project_config_v2.yaml)
---
## 🔧 命令行非交互模式测试
```bash
cd f:\ppt\ppt_manager_v2
python -c "
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.save()
print('✅ OK!')
"
```
---
## ❓ 常见问题排查
**Q1: TemplateNotFound jinja2: index_v2.html**
两处模板文件互为备份:
- `ppt_manager_v2/templates/index_v2.html`
- `ppt_manager_v2/web/templates/index_v2.html`
代码里已用 `Path(__file__).parent / "web" / "templates"` 绝对路径
**Q2: 下载文件找不到 /api/files 返回空**
输出目录在 `f:\ppt\output` 与代码目录同级的output不在 `ppt_manager_v2\output` 下,已统一修正为 `base_dir.parent / "output"`
**Q3: 插件不显示/启动日志里没扫到**
检查三点:
1. 类继承 `BaseGenerator(ABC)`
2. 类属性 `generator_id` 不是 `None`
3. 文件在 `plugins/generators/*.py` 且文件名不以 `_` 开头