【Python实战】自动化生成PPT演示文稿:python-pptx+AI内容生成+图表嵌入

一、项目背景

1.1 痛点分析

PPT制作是职场高频场景,但传统方式效率极低:

环节 手工方式 时间
找模板 搜索下载 2小时
填内容 手动输入 3小时
调排版 反复调整 3小时
做图表 Excel+复制 2小时
改配色 逐页修改 1小时
总计 - 11小时

一份30页PPT就要一天半,改3版就是4天。

1.2 技术需求

核心需求:

  • AI自动生成PPT内容大纲
  • 自动创建幻灯片并填充内容
  • 自动插入数据图表
  • 支持自定义模板和配色
  • 一键导出标准.pptx文件

二、技术架构

原始内容 → AI生成大纲 → 创建幻灯片 → 填充内容 → 插入图表 → 导出PPT

↑ ↑ ↑ ↑ ↑ ↑

文本/数据 DashScope python-pptx python-pptx matplotlib python-pptx

Qwen3

复制代码
技术栈:
- **python-pptx**:PPT创建和编辑
- **DashScope/Qwen3**:AI生成内容大纲
- **matplotlib**:图表生成
- **pandas**:数据处理
- **Pillow**:图片处理

---

## 三、环境准备

### 3.1 安装依赖

```bash
pip install python-pptx dashscope matplotlib pandas pillow

3.2 配置

复制代码
# config.py
DASHSCOPE_API_KEY = "your-api-key-here"

# PPT配色方案
COLOR_SCHEMES = {
    'business': {
'primary': '2C3E50',
'secondary': '3498DB',
'accent': '2ECC71',
'text': '333333',
'background': 'FFFFFF'
    },
    'tech': {
'primary': '0D1B2A',
'secondary': '2196F3',
'accent': '00BCD4',
'text': 'EEEEEE',
'background': '1B2838'
    },
    'vibrant': {
'primary': 'FF6B6B',
'secondary': '4ECDC4',
'accent': '45B7D1',
'text': '333333',
'background': 'FFFFFF'
    }
}

四、核心模块实现

4.1 AI内容生成模块

用Qwen3自动生成PPT大纲和每页内容:

复制代码
import dashscope
import json
import re

class ContentGenerator:
def __init__(self, api_key):
        dashscope.api_key = api_key
  
    def generate_outline(self, topic, raw_content, page_count=12):
"""AI生成PPT大纲"""
        prompt = f"""
你是一位PPT设计专家。请根据以下信息,生成PPT大纲。
      
        主题:{topic}
        原始内容:{raw_content[:3000]}
        页数要求:{page_count}页
      
请返回JSON格式:
        {{
"title": "PPT标题",
"subtitle": "副标题",
"slides": [
                {{
"page": 1,
"type": "cover",
"title": "封面标题",
"subtitle": "副标题"
                }},
                {{
"page": 2,
"type": "toc",
"title": "目录",
"items": ["章节1", "章节2", "章节3"]
                }},
                {{
"page": 3,
"type": "content",
"title": "页面标题",
"bullets": ["要点1", "要点2", "要点3"]
                }},
                {{
"page": 4,
"type": "chart",
"title": "数据图表页标题",
"chart_type": "bar/line/pie",
                    "chart_data": {{"labels": [], "values": []}}
                }},
                {{
"page": 12,
"type": "end",
"title": "谢谢",
"subtitle": "Q&A"
                }}
            ]
        }}
      
规则:
1. 封面页1张、目录页1张、结尾页1张
2. 内容页每页3-5个要点
3. 至少2页数据图表页
4. 内容要有逻辑递进关系
5. 标题简洁有力,不超过15字
        """
      
        response = dashscope.Generation.call(
            model="qwen3-72b",
            messages=[{"role": "user", "content": prompt}],
            result_format="message"
        )
      
        content = response.output.choices[0].message.content
        json_match = re.search(r'\{.*\}', content, re.DOTALL)
      
        if json_match:
            return json.loads(json_match.group())
        return None
  
def generate_speaker_notes(self, slide_content):
"""AI生成演讲稿"""
        prompt = f"""
请为以下PPT页面生成演讲稿(口语化,1-2分钟):
      
        标题:{slide_content.get('title', '')}
        要点:{slide_content.get('bullets', [])}
      
要求:
- 口语化,不要念稿感
- 每个要点展开1-2句
- 有过渡语连接各点
- 总时长控制在1-2分钟
        """
      
        response = dashscope.Generation.call(
            model="qwen3-72b",
            messages=[{"role": "user", "content": prompt}],
            result_format="message"
        )
      
        return response.output.choices[0].message.content

4.2 图表生成模块

用matplotlib生成图表并保存为图片,供PPT嵌入:

复制代码
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['axes.unicode_minus'] = False

class ChartFactory:
    def __init__(self, color_scheme='business'):
        self.colors = list(COLOR_SCHEMES[color_scheme].values())[:5]
  
def create_chart(self, chart_type, data, title, output_path):
"""根据类型生成图表"""
        fig, ax = plt.subplots(figsize=(10, 6))
      
        if chart_type == 'bar':
self._bar_chart(ax, data, title)
        elif chart_type == 'line':
self._line_chart(ax, data, title)
        elif chart_type == 'pie':
self._pie_chart(ax, data, title)
        elif chart_type == 'radar':
plt.close()
            fig = plt.figure(figsize=(8, 8))
            ax = fig.add_subplot(111, projection='polar')
self._radar_chart(ax, data, title)
      
plt.tight_layout()
        plt.savefig(output_path, dpi=200, bbox_inches='tight', transparent=True)
plt.close()
        return output_path
  
def _bar_chart(self, ax, data, title):
"""柱状图"""
        labels = data['labels']
        values = data['values']
      
        bars = ax.bar(labels, values, color=['#3498DB', '#2ECC71', '#E74C3C', '#F39C12', '#9B59B6'][:len(labels)])
        ax.set_title(title, fontsize=16, fontweight='bold', pad=15)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
      
        for bar in bars:
            height = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2., height,
                   f'{height:,.0f}', ha='center', va='bottom', fontsize=12, fontweight='bold')
  
def _line_chart(self, ax, data, title):
"""折线图"""
        labels = data['labels']
        values = data['values']
      
        ax.plot(labels, values, marker='o', color='#3498DB', linewidth=2.5, markersize=8)
        ax.fill_between(range(len(labels)), values, alpha=0.15, color='#3498DB')
        ax.set_title(title, fontsize=16, fontweight='bold', pad=15)
        ax.grid(True, alpha=0.3)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
  
def _pie_chart(self, ax, data, title):
"""饼图"""
        labels = data['labels']
        values = data['values']
        colors = ['#3498DB', '#2ECC71', '#E74C3C', '#F39C12', '#9B59B6'][:len(labels)]
      
        wedges, texts, autotexts = ax.pie(
            values, labels=labels, autopct='%1.1f%%',
            colors=colors, startangle=90, textprops={'fontsize': 12}
        )
        for autotext in autotexts:
autotext.set_fontweight('bold')
        ax.set_title(title, fontsize=16, fontweight='bold', pad=15)

4.3 PPT构建模块

用python-pptx创建专业级PPT:

复制代码
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE

class PPTBuilder:
    def __init__(self, template_path=None, color_scheme='business'):
        if template_path:
            self.prs = Presentation(template_path)
else:
            self.prs = Presentation()
            self.prs.slide_width = Inches(13.33)
            self.prs.slide_height = Inches(7.5)
      
        self.scheme = COLOR_SCHEMES[color_scheme]
  
def add_cover(self, title, subtitle):
"""封面页"""
        slide = self.prs.slides.add_slide(self.prs.slide_layouts[6])  # 空白布局
      
# 背景色
        bg = slide.background
        fill = bg.fill
fill.solid()
        fill.fore_color.rgb = RGBColor.from_string(self.scheme['primary'])
      
# 标题
        txBox = slide.shapes.add_textbox(Inches(1), Inches(2), Inches(11), Inches(2))
        tf = txBox.text_frame
        tf.word_wrap = True
        p = tf.paragraphs[0]
        p.text = title
        p.font.size = Pt(44)
        p.font.bold = True
        p.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
        p.alignment = PP_ALIGN.CENTER
      
# 副标题
        txBox2 = slide.shapes.add_textbox(Inches(1), Inches(4.2), Inches(11), Inches(1))
        tf2 = txBox2.text_frame
        p2 = tf2.paragraphs[0]
        p2.text = subtitle
        p2.font.size = Pt(22)
        p2.font.color.rgb = RGBColor(0xCC, 0xCC, 0xCC)
        p2.alignment = PP_ALIGN.CENTER
  
def add_toc(self, title, items):
"""目录页"""
        slide = self.prs.slides.add_slide(self.prs.slide_layouts[6])
      
# 标题
self._add_title(slide, title)
      
# 目录项
        for i, item in enumerate(items):
            y_pos = Inches(2.2 + i * 0.8)
          
# 编号圆形
            shape = slide.shapes.add_shape(
MSO_SHAPE.OVAL, Inches(1.5), y_pos, Inches(0.5), Inches(0.5)
            )
shape.fill.solid()
            shape.fill.fore_color.rgb = RGBColor.from_string(self.scheme['secondary'])
shape.line.fill.background()
          
            tf = shape.text_frame
            tf.paragraphs[0].text = str(i + 1)
            tf.paragraphs[0].font.size = Pt(16)
            tf.paragraphs[0].font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
            tf.paragraphs[0].font.bold = True
            tf.paragraphs[0].alignment = PP_ALIGN.CENTER
            tf.vertical_anchor = MSO_ANCHOR.MIDDLE
          
# 文字
            txBox = slide.shapes.add_textbox(Inches(2.3), y_pos, Inches(8), Inches(0.5))
            tf = txBox.text_frame
            tf.paragraphs[0].text = item
            tf.paragraphs[0].font.size = Pt(20)
            tf.paragraphs[0].font.color.rgb = RGBColor.from_string(self.scheme['text'])
            tf.vertical_anchor = MSO_ANCHOR.MIDDLE
  
    def add_content(self, title, bullets, notes=None):
"""内容页"""
        slide = self.prs.slides.add_slide(self.prs.slide_layouts[6])
      
# 标题
self._add_title(slide, title)
      
# 要点
        txBox = slide.shapes.add_textbox(Inches(1), Inches(2), Inches(11), Inches(4.5))
        tf = txBox.text_frame
        tf.word_wrap = True
      
        for i, bullet in enumerate(bullets):
            if i > 0:
                p = tf.add_paragraph()
else:
                p = tf.paragraphs[0]
          
            p.text = f"  ●  {bullet}"
            p.font.size = Pt(18)
            p.font.color.rgb = RGBColor.from_string(self.scheme['text'])
            p.space_after = Pt(16)
      
# 演讲稿备注
        if notes:
            slide.notes_slide.notes_text_frame.text = notes
  
def add_chart_slide(self, title, chart_image_path):
"""图表页"""
        slide = self.prs.slides.add_slide(self.prs.slide_layouts[6])
      
# 标题
self._add_title(slide, title)
      
# 插入图表图片
slide.shapes.add_picture(
chart_image_path,
Inches(1.5), Inches(1.8),
Inches(10), Inches(5)
        )
  
    def add_end(self, title="谢谢", subtitle="Q&A"):
"""结尾页"""
        slide = self.prs.slides.add_slide(self.prs.slide_layouts[6])
      
        bg = slide.background
        fill = bg.fill
fill.solid()
        fill.fore_color.rgb = RGBColor.from_string(self.scheme['primary'])
      
        txBox = slide.shapes.add_textbox(Inches(1), Inches(2.5), Inches(11), Inches(2))
        tf = txBox.text_frame
        p = tf.paragraphs[0]
        p.text = title
        p.font.size = Pt(48)
        p.font.bold = True
...(truncated)...
相关推荐
墨染天姬1 小时前
【AI】CRISP 提示词框架
人工智能
高洁011 小时前
工业AI部署:模型量化与边缘设备部署实战
人工智能·深度学习·机器学习·数据挖掘·transformer
上海达策TECHSONIC1 小时前
汽车零配件 SAP 转型数字化标杆 上海达策实施 SAP Business One 赋能汽车底盘转向领域
大数据·运维·人工智能·汽车·运维开发·制造
小白学大数据2 小时前
Python 爬虫:拍卖网站列表页与详情页数据联动爬取
开发语言·爬虫·python
IT_陈寒2 小时前
Vue这个响应式陷阱让我加了两天班
前端·人工智能·后端
好大哥呀2 小时前
单元测试自动化的流程
运维·单元测试·自动化
HP-Patience2 小时前
【爬虫脚本自动化录制】playwright codegen使用教程
运维·爬虫·自动化
泰恒2 小时前
ChatGPT发展历程
人工智能·深度学习·yolo·机器学习·计算机视觉
Omics Pro2 小时前
斯坦福:强化学习生物约束型虚拟细胞建模
人工智能·深度学习·算法·机器学习·计算机视觉·数据挖掘·数据分析