【PythonAI】4.3.4 项目实战:完成一份图文并茂、设计精美的活动PPT
·
# tongyi_ppt_generator_with_img.py
import os
import json
import time
import requests
import dashscope
from PIL import Image
from io import BytesIO
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN
from pptx.enum.shapes import MSO_SHAPE
from dashscope import Generation, ImageSynthesis
# ==========================================
# ⚙️ 配置区域
# ==========================================
# ⚠️ 注意:请勿将此密钥上传至公共代码仓库
API_KEY = "your-tongyi-api-key-here"
dashscope.api_key = API_KEY
# 主题配色方案 (民族团结主题:中国红 + 辉煌金)
THEME_CONFIG = {
"primary_color": RGBColor(196, 30, 58), # 中国红
"secondary_color": RGBColor(255, 215, 0), # 辉煌金
"text_color": RGBColor(51, 51, 51), # 深灰
"bg_color": RGBColor(255, 251, 240), # 米白 (宣纸色)
"font_name": "Microsoft YaHei" # 微软雅黑
}
# 保存目录
OUTPUT_DIR = "output_ppt_project"
IMAGE_DIR = os.path.join(OUTPUT_DIR, "images")
# ==========================================
# 🛠️ 核心功能类
# ==========================================
class AIPPTStudio:
def __init__(self):
self._ensure_dirs()
def _ensure_dirs(self):
"""创建必要的目录"""
if not os.path.exists(OUTPUT_DIR):
os.makedirs(OUTPUT_DIR)
if not os.path.exists(IMAGE_DIR):
os.makedirs(IMAGE_DIR)
def generate_outline(self, topic):
"""
调用通义千问生成 PPT 大纲及配图提示词
返回结构:{'title': str, 'slides': [{'heading': str, 'content': [], 'image_prompt': str}]}
"""
print(f"🤖 正在策划《{topic}》内容结构...")
prompt = f"""
请为"{topic}"生成一份详细的 PPT 大纲。
要求:
1. 返回纯 JSON 格式,不要包含 markdown 标记。
2. 包含 6-8 页幻灯片。
3. 每一页必须包含 'heading' (标题), 'content' (3-4 个要点), 'image_prompt' (用于生成该页配图的英文提示词,描述画面内容,风格为现代插画或高质量摄影)。
JSON 结构示例:
{{
"title": "PPT 主标题",
"slides": [
{{
"heading": "页面标题",
"content": ["要点 1", "要点 2"],
"image_prompt": "A group of diverse students smiling, campus background, bright lighting, 3d render style"
}}
]
}}
"""
try:
response = Generation.call(
model=Generation.Models.qwen_turbo,
prompt=prompt,
result_format='message'
)
if response.status_code == 200:
content = response.output.choices[0].message.content
# 清理 JSON 字符串
content = content.replace('```json', '').replace('```', '').strip()
data = json.loads(content)
print("✅ 内容大纲生成成功")
return data
else:
print(f"❌ 大纲生成失败:{response.code}")
return None
except Exception as e:
print(f"❌ 发生错误:{e}")
return None
def generate_image(self, prompt, slide_index):
"""
调用通义万相生成单张图片
"""
# 增强提示词,确保风格统一
enhanced_prompt = f"High quality poster design, {prompt}, professional composition, vibrant colors, 8k resolution, suitable for presentation background"
try:
response = ImageSynthesis.call(
model="wanx-v1",
prompt=enhanced_prompt,
size="1024*1024",
n=1
)
if response.status_code == 200:
url = response.output.results[0].url
# 下载并保存
img_data = requests.get(url).content
filename = f"slide_{slide_index}.png"
filepath = os.path.join(IMAGE_DIR, filename)
with open(filepath, 'wb') as f:
f.write(img_data)
print(f"✅ 第 {slide_index} 页配图已保存")
return filepath
else:
print(f"⚠️ 第 {slide_index} 页配图生成失败,将使用占位符")
return None
except Exception as e:
print(f"⚠️ 图片生成异常:{e}")
return None
def create_ppt(self, data, images_map):
"""
组装 PPT,应用主题样式
images_map: {slide_index: filepath}
"""
print("🎨 正在组装 PPT 并应用设计样式...")
prs = Presentation()
# 设置 16:9
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)
# --- 1. 封面页 ---
slide = prs.slides.add_slide(prs.slide_layouts[0])
self._style_shape(slide.shapes.title, 44, True, THEME_CONFIG['primary_color'])
self._style_shape(slide.placeholders[1], 24, False, THEME_CONFIG['text_color'])
slide.shapes.title.text = data.get('title', 'Activity Plan')
slide.placeholders[1].text = "AI 自动生成策划方案 | 民族团结专题"
# 封面如果有图,设为背景或右侧大图 (此处简化为右侧)
if 0 in images_map:
self._insert_image(slide, images_map[0], left=8, top=1.5, width=5, height=5)
# --- 2. 内容页 ---
for i, slide_data in enumerate(data.get('slides', [])):
slide = prs.slides.add_slide(prs.slide_layouts[1]) # 标题 + 内容
# 设置标题
title_shape = slide.shapes.title
title_shape.text = slide_data['heading']
self._style_shape(title_shape, 32, True, THEME_CONFIG['primary_color'])
# 设置正文
body_shape = slide.placeholders[1]
tf = body_shape.text_frame
tf.clear()
for point in slide_data['content']:
p = tf.add_paragraph()
p.text = point
p.level = 0
p.font.size = Pt(20)
p.font.name = THEME_CONFIG['font_name']
p.space_after = Pt(14)
p.font.color.rgb = THEME_CONFIG['text_color']
# 调整文本框位置,为图片腾出空间 (左侧文字,右侧图片)
body_shape.left = Inches(0.5)
body_shape.top = Inches(1.5)
body_shape.width = Inches(6.5)
body_shape.height = Inches(5.5)
# 插入图片
if i in images_map:
# 内容页图片放在右侧
self._insert_image(slide, images_map[i], left=7.5, top=1.5, width=5, height=5)
else:
# 无图时添加占位符
self._add_placeholder(slide, left=7.5, top=1.5, width=5, height=5, text="AI 配图生成失败")
# --- 3. 保存 ---
filename = os.path.join(OUTPUT_DIR, f"{data.get('title', 'Presentation')}.pptx")
prs.save(filename)
print(f"✅ PPT 制作完成!保存路径:{filename}")
def _style_shape(self, shape, font_size, bold, color):
"""统一设置文本样式"""
for paragraph in shape.text_frame.paragraphs:
for run in paragraph.runs:
run.font.name = THEME_CONFIG['font_name']
run.font.size = Pt(font_size)
run.font.bold = bold
run.font.color.rgb = color
def _insert_image(self, slide, filepath, left, top, width, height):
"""插入图片"""
try:
slide.shapes.add_picture(filepath, Inches(left), Inches(top), Inches(width), Inches(height))
except Exception as e:
print(f"⚠️ 插入图片失败:{e}")
self._add_placeholder(slide, left, top, width, height, "Image Load Error")
def _add_placeholder(self, slide, left, top, width, height, text=""):
"""添加占位框"""
shape = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, Inches(left), Inches(top), Inches(width), Inches(height))
shape.fill.solid()
shape.fill.fore_color.rgb = RGBColor(240, 240, 240)
shape.line.color.rgb = THEME_CONFIG['secondary_color']
tf = shape.text_frame
tf.text = text
tf.paragraphs[0].alignment = PP_ALIGN.CENTER
tf.paragraphs[0].font.color.rgb = RGBColor(150, 150, 150)
# ==========================================
# 🏃 主执行流程
# ==========================================
def main():
print("="*50)
print("🚀 AI 全栈 PPT 生成工作室")
print("="*50)
# 1. 初始化
studio = AIPPTStudio()
# 2. 输入主题 (默认使用民族团结,也可修改)
topic = input("请输入 PPT 主题 (直接回车使用默认'民族团结一家亲'): ").strip()
if not topic:
topic = "民族团结一家亲·校园联谊活动策划"
# 3. 生成大纲
ppt_data = studio.generate_outline(topic)
if not ppt_data:
print("❌ 无法生成大纲,程序终止。")
return
# 4. 生成配图 (为每一页生成一张图)
# 注意:为了演示速度,这里限制生成前 5 页的配图,实际使用可去掉限制
images_map = {}
total_slides = len(ppt_data.get('slides', []))
print(f"\n🎨 开始为 {total_slides} 页幻灯片生成配图...")
# 封面图 (索引 -1 或单独处理,这里简化为第 0 页对应封面图)
# 为了让封面也有图,我们专门生成一个封面提示词
cover_prompt = f"Cover page design for {topic}, festive atmosphere, chinese style, red and gold colors, high quality"
images_map[0] = studio.generate_image(cover_prompt, "cover")
for i, slide in enumerate(ppt_data.get('slides', [])):
# 索引从 1 开始对应内容页
prompt = slide.get('image_prompt', 'abstract background')
# 限制生成数量以节省时间,实际使用请注释掉 if i < 5
if i < 5:
path = studio.generate_image(prompt, i + 1)
if path:
images_map[i + 1] = path
else:
print(f"⏭️ 跳过第 {i+1} 页配图生成以节省时间")
time.sleep(1) # 避免 API 频率限制
# 5. 组装 PPT
studio.create_ppt(ppt_data, images_map)
print("\n" + "="*50)
print("所有任务完成!请查看 output_ppt_project 文件夹")
print("="*50)
if __name__ == "__main__":
main()
运行结果:
(ai_env) $ python3 tongyi_ppt_generator_with_img.py
==================================================
AI 全栈 PPT 生成工作室
==================================================
请输入 PPT 主题 (直接回车使用默认'民族团结一家亲'):
正在策划《民族团结一家亲·校园联谊活动策划》内容结构...
✅ 内容大纲生成成功
开始为 6 页幻灯片生成配图...
✅ 第 cover 页配图已保存
✅ 第 1 页配图已保存
✅ 第 2 页配图已保存
✅ 第 3 页配图已保存
✅ 第 4 页配图已保存
✅ 第 5 页配图已保存
⏭ 跳过第 6 页配图生成以节省时间
正在组装 PPT 并应用设计样式...
✅ PPT 制作完成!保存路径:output_ppt_project/民族团结一家亲·校园联谊活动策划.pptx
==================================================
所有任务完成!请查看 output_ppt_project 文件夹
==================================================
(ai_env) $
更多推荐


所有评论(0)