如果你在成都做过旧改项目,大概率经历过这样的夜晚:白天跑现场、拍照、量尺寸,晚上回到办公室赶一份给社区和业主看的汇报PPT。效果图找设计师加急出,改了三四版;PPT套用公司老模板,图片拖进去还要一张张裁剪、对齐、改说明;做到一半领导又让加一段现状分析,页码全部重排。
整个过程散落在至少四五个软件里,时间耗在“搬运”和“对齐”上,真正需要动脑子的判断反而没时间做。
而最近有一种新做法正在被团队验证:把“现场照片采集—AI效果图生成—汇报PPT输出”连成一条流水线。照片进,效果图出;效果图进,PPT出。人的角色从“操作工”变成“审核者”。
这篇围绕的,就是这条流水线怎么搭、用哪些工具、脚本怎么写、会遇到哪些坑。
1. 这篇文章真正要解决的问题
先给一个明确判断:在成都老小区翻新这类场景里,AI带来的效率提升最容易被人低估的,不是单张效果图的质量,而是“最终交付物”的产能。
什么叫最终交付物?对设计师、施工方、社区工作人员来说,一套完整的方案汇报文档,包含现状分析、翻新效果图、投资概算、施工计划。业主和社区重点看效果图,决策层重点看进度和预算。以往的痛点不是能力不够,而是:
- AI出图工具散点使用,这张效果好、那张角度不对,整理成本很高。
- PPT是手工排版,图片尺寸不一致导致反复重排。
- 每个人做出来的汇报结构都不一样,经验无法复用。
- 项目一多,重复劳动成倍增加。
所以这篇文章真正要解决的是:如何用一套低成本工具链,把AI效果图和汇报PPT的生产过程标准化。你不需要会复杂的算法,不需要买昂贵的设备,只要会基本Python脚本和提示词,就能把过去一两天的人工整理工作压缩到半小时内。
什么样的读者最应该看:
如果你在做城市更新、旧房改造、室内设计、乡村振兴这类偏工程和偏现场的项目,这条流水线可以直接搬用大部分思路。如果你是学生,正在做开题答辩PPT或课程汇报,同样可以用这套“数据驱动生成PPT”的方法。
2. 从“单点AI”到“AI流水线”:区别在哪里
很多人已经习惯了单点使用AI。让AI画一张图,让AI列一个提纲,让AI润色一段文字。这种用法确实省时间,但问题是没有形成资产。每次做新项目,都要重新设计提示词、重新排版、重新找参考图。
流水线的本质是:把可复用的环节固化成脚本和模板,让每次项目的差异化内容只出现在“输入数据”里。
用旧改项目举个例子。传统方式下,你拿到一个老小区,先看现状照片,再找人画效果图,然后手动把效果图和文字排进PPT。如果小区有10栋楼,工作量就是10倍。用流水线方式,变化的是现场照片和项目参数,不变的是出图逻辑和PPT骨架。
下面用一个表格对比三种方式:
| 环节 | 传统方式 | 单点AI | 流水线方式 |
|---|---|---|---|
| 现场素材 | 手动整理、命名混乱 | 仍手动整理 | 按规范批量采集并命名 |
| 效果图 | 设计师手绘或外包 | AI散点生成 | AI批量生成,局部重绘 |
| 图片规格 | 大小不一,PPT里手动缩放 | 仍然需要手动调整 | 脚本统一压缩和裁剪 |
| PPT排版 | 手动拖拽、对齐 | AI生成文字提纲 | 脚本按JSON配置自动排版 |
| 经验复用 | 靠个人记忆 | 零散提示词 | 模板沉淀为项目资产 |
从表格里能看出来,真正的效率提升不是某个环节快了10%,而是整个链条的重复劳动被剔除了。这背后对应的是一个工程概念:数据驱动文档生成(Data-driven Document Generation)。
在你自己的项目里,哪怕只是把“图片批量处理”和“PPT自动排版”这两步做成脚本,就已经算踏上流水线了。
3. 核心概念与术语扫盲
在进入实操前,先把这条流水线涉及的核心概念讲清楚。这些术语不算难,但如果不理解,后面跑脚本时报错会找不到方向。
3.1 图生图
图生图是把一张现有图片作为底图,由AI模型在保留主体结构的前提下生成新的效果图。用在旧改场景非常合适,因为你要翻新的就是某栋楼本身,而不是凭空创造一栋楼。
实际操作时,AI工具会读取底图的构图、色调和物体轮廓,然后按照提示词的要求改变材质、颜色、附加元素。比如一张破旧外立面的照片,可以通过“保持建筑轮廓不变,改成米白色真石漆墙面,增加灰色雨棚”这样的提示词生成改造后效果。
需要注意:图生图不等于精确建模。AI可能改变窗户数量或柱子的比例,所以我的建议是生成后进行人工比对,必要时用局部重绘功能框选需要修改的区域。
3.2 提示词模板
提示词不是一句随机的话。在批量场景下,提示词应该拆成“固定部分”和“可变部分”。
固定部分是整个项目的统一风格,比如摄影角度、光线方向、改造风格。可变部分是每栋楼具体的差异化信息,比如“三单元外墙需要重新做防水”“一楼增设立体绿化”。维护一份提示词模板文件,能让AI输出的风格保持稳定。
3.3 模板化编排
模板化编排是指把一篇汇报PPT的骨架固定下来。封面放什么、目录有几章、每一页放几张图和什么文字,全部用配置文件或模板页面描述。
这样做的意义在于:当项目从5栋楼变成50栋楼时,你不需要重新设计PPT框架,只需要多传几张图和几段文字。
3.4 数据驱动文档
这个概念是这条流水线的核心。PPT的每一页内容都来自一个结构化数据源(通常是JSON或YAML),而不是在PPT里手工输入。脚本读取数据,自动生成页面。
好处是:数据可以修改,可以复用,可以和AI对话无缝衔接。比如你在AI对话里生成了项目概况,整理成JSON后,脚本自动排版成PPT页面。
3.5 工作流编排平台
如果你不想自己写Python脚本串全流程,也可以使用Dify这类AI应用开发平台。它能通过可视化方式把“上传照片—生成文案—输出结构化数据—调用HTTP请求”串成一个工作流。工作流里的每个节点可以是一个大模型调用,也可以是一个代码片段。
对于旧改汇报场景,我推荐的最小方案是:先用脚本方式跑通一条最基础的管道,再根据实际经验决定要不要迁移到平台型工作流。不要一上来就追求复杂编排,容易陷入工具学习成本。
4. 环境准备与工具选型
先说明一下,我下面给的版本和工具属于常用组合,具体版本请以实际项目为准。这套方案的优点是完全在本地跑,不需要额外购买云服务。
4.1 基础环境
- 操作系统:Windows 10/11、macOS 或 Linux 均可,本文示例以通用命令为主。
- Python版本:建议3.9及以上。
- 包管理器:使用pip即可。
4.2 Python库依赖
主要依赖两个库:
| 库名 | 作用 |
|---|---|
| python-pptx | 读取和生成PowerPoint文件 |
| Pillow | 图片压缩、尺寸统一 |
可选依赖:如果要用脚本调用大模型API生成文案,可以安装openai库(或其他平台的SDK,以官方为准)。
如果想用较新的python-pptx能力,版本建议不低于0.6.21,但请以官方发布为准。
4.3 AI绘图工具
选择AI绘图工具时,核心考虑三点:是否能图生图、是否能局部重绘、是否有批量接口。市面上主流的中文AI绘画平台和Stable Diffusion系本地工具基本都支持,建议根据你本地的显存和实际使用习惯选择。文章不绑定某一个具体工具,重点是流程方法。
4.4 项目目录结构
建议提前建好统一的目录结构,后面所有脚本都基于这个结构运行。
old_community_renovation/ ├── assets/ # 原始素材 │ ├── photos/ # 现场照片 │ └── render/ # AI生成效果图 ├── config/ │ └── project_config.json # 项目配置 ├── output/ │ └── old_community_report.pptx ├── scripts/ │ ├── preprocess_images.py # 图片预处理 │ └── generate_report.py # 生成PPT └── requirements.txt5. 核心流程拆解
这条流水线一共分5步。每一步解决一个问题,建议先跑通再优化。
5.1 现场素材采集
去老小区现场时,不要拿着手机随手拍。按楼栋、方位、重点区域三个维度采集,比如“1栋-南立面-外墙脱落.jpg”“公共区域-入口-现状.jpg”。命名规范比整理工具更有效,它决定了后面AI批量出图和PPT自动关联的效率。
采集时注意三件事:
- 同一栋楼,远景一张、近景一张、局部细节一张。
- 光线尽量保持一致,不要正午和傍晚混拍。
- 每个拍摄点附带位置信息,可以用手机便签记录“1栋3单元,北面”。
5.2 AI生成多版效果图
拿到现场照片后,用图生图模式生成翻新效果图。这里的提示词需要拆成模板。固定部分描述整体风格,可变部分对应每栋楼的问题。
示例提示词模板如下:
场景定位:成都老小区外立面翻新效果图 固定要求:真实摄影感,白天柔和光线,35mm镜头视角,墙面为米白色真石漆,窗户更换为深灰色铝合金窗,整体整洁干净 可变部分:{specific_issue},请保持建筑主体结构和楼栋位置与底图一致 意图:仅在局部重绘模式下修改指定区域,其他区域保持现状每一栋楼可以生成2到3个方案,再从中选择1个最符合预期的方案进入PPT。这里的“人工审核”环节不要省略,AI效果图可能存在结构变形或过度美化问题。
5.3 统一图片规格
这一步非常容易被忽略,但却是PPT排版观感的核心。AI出图分辨率不同,手机照片尺寸也不同,直接插入PPT会大小不一。用一个Python脚本批量做三件事:统一最长边像素、压缩尺寸、重命名。
5.4 生成PPT
使用python-pptx读取JSON配置,按章节生成PPT页面。篇幅原因,这里的完整脚本放在下一章,你可以直接复制使用。
5.5 串联全流程
跑通单步后,用一个build.sh串联预处理和PPT生成。以后每来一个新项目,只需要更新素材和配置文件,然后运行一条命令。
6. 完整示例:用Python自动生成汇报PPT
下面给出一套可以直接运行的示例。先创建requirements.txt。
python-pptx>=0.6.21 Pillow>=9.0.06.1 图片预处理脚本
这个脚本做两件事:把图片统一为最长边不超过1600像素,压缩后输出到assets/render_preview目录。
文件路径:scripts/preprocess_images.py
# -*- coding: utf-8 -*- import os from pathlib import Path from PIL import Image INPUT_DIR = Path("assets/render") OUTPUT_DIR = Path("assets/render_preview") MAX_EDGE = 1600 def compress_image(src_path: Path, dst_path: Path) -> None: with Image.open(src_path) as img: # 转换色彩模式,避免RGBA图片在JPEG下报错 if img.mode in ("RGBA", "P"): img = img.convert("RGB") width, height = img.size max_edge = max(width, height) if max_edge > MAX_EDGE: scale = MAX_EDGE / max_edge new_size = (int(width * scale), int(height * scale)) img = img.resize(new_size, Image.LANCZOS) img.save(dst_path, "JPEG", quality=85) def main() -> None: OUTPUT_DIR.mkdir(parents=True, exist_ok=True) for img_path in sorted(INPUT_DIR.glob("*.jpg")): dst_path = OUTPUT_DIR / f"{img_path.stem}_preview.jpg" compress_image(img_path, dst_path) print(f"[OK] {img_path.name} -> {dst_path.name}") if __name__ == "__main__": main()运行方式:
cd old_community_renovation python scripts/preprocess_images.py如果每栋楼的效果图较多,建议在目录组织上再增加一层楼栋子目录,但这个脚本按扁平目录处理,简单够用。
6.2 项目配置文件
这个JSON文件是整个PPT生成的数据源。它包含封面信息、章节顺序,以及每一页的图片和说明文字。
文件路径:config/project_config.json
{ "title": "成都某老小区空间更新概念方案", "subtitle": "外立面翻新与公共空间适老化改造", "author": "更新设计小组", "date": "2025", "sections": [ { "title": "01 项目概况", "type": "section", "summary": "本小区位于成都市主城区,建成于上世纪90年代,共8栋住宅,涉及居民约420户。本次更新聚焦外立面翻新、公共空间梳理和适老化改造三项内容。" }, { "title": "02 现状问题", "type": "content", "intro": "经现场排查,主要问题集中在墙面空鼓、排水管老化、公共活动空间不足三个方面。", "blocks": [ { "image": "assets/render_preview/1栋-南立面-现状_preview.jpg", "caption": "南立面现状:外墙涂料大面积脱落" }, { "image": "assets/render_preview/公共区域-入口-现状_preview.jpg", "caption": "小区入口:缺乏无障碍坡道" } ] }, { "title": "03 更新策略与效果图", "type": "content", "intro": "本方案采用AI辅助生成多视角效果图,用于快速比选立面色彩和材质组合。", "blocks": [ { "image": "assets/render_preview/1栋-方案A-米白色真石漆_preview.jpg", "caption": "方案A:米白色真石漆 + 深灰色窗框" }, { "image": "assets/render_preview/1栋-方案B-暖灰色涂料_preview.jpg", "caption": "方案B:暖灰色涂料 + 木色雨棚" } ] }, { "title": "04 实施计划", "type": "section", "summary": "计划分为三期:一期完成外立面样板栋施工,二期完成全部楼栋翻新,三期完成公共空间改造与适老化设施加装。每期施工完成后组织居民意见反馈和使用后评估。" } ] }6.3 生成PPT的Python脚本
文件路径:scripts/generate_report.py
# -*- coding: utf-8 -*- import json from pathlib import Path from pptx import Presentation from pptx.util import Inches, Pt from pptx.enum.text import PP_ALIGN class ReportGenerator: def __init__(self, config_path: str): self.config_path = Path(config_path) self.prs = Presentation() self.json_data = {} self._load_config() self._setup_slide_size() def _load_config(self) -> None: with open(self.config_path, "r", encoding="utf-8") as f: self.json_data = json.load(f) def _setup_slide_size(self) -> None: # 设置为16:9 self.prs.slide_width = Inches(13.333) self.prs.slide_height = Inches(7.5) def _add_cover(self) -> None: slide = self.prs.slides.add_slide(self.prs.slide_layouts[0]) title = slide.shapes.title subtitle = slide.placeholders[1] title.text = self.json_data["title"] title.font.size = Pt(40) subtitle.text = f"{self.json_data['subtitle']}\n{self.json_data['author']} {self.json_data['date']}" subtitle.font.size = Pt(20) def _add_section_slide(self, section: dict) -> None: slide = self.prs.slides.add_slide(self.prs.slide_layouts[1]) slide.shapes.title.text = section["title"] content = slide.placeholders[1] content.text = section.get("summary", "") content.font.size = Pt(20) def _add_content_slide(self, section: dict) -> None: slide = self.prs.slides.add_slide(self.prs.slide_layouts[5]) slide.shapes.title.text = section["title"] if "intro" in section: content = slide.placeholders[1] content.text = section["intro"] content.font.size = Pt(18) left_pos = Inches(0.8) top_pos = Inches(1.8) img_width = Inches(5.4) img_height = Inches(4.2) for idx, block in enumerate(section.get("blocks", [])): left = left_pos + idx * Inches(6.0) top = top_pos img_path = Path(block["image"]) try: slide.shapes.add_picture( str(img_path), left, top, width=img_width, height=img_height ) except FileNotFoundError: print(f"[WARN] 图片不存在: {img_path}") continue # 在图片下方添加说明文字 txBox = slide.shapes.add_textbox( left, top + Inches(4.35), img_width, Inches(0.6) ) tf = txBox.text_frame tf.text = block["caption"] tf.paragraphs[0].alignment = PP_ALIGN.CENTER tf.paragraphs[0].font.size = Pt(14) def generate(self) -> None: self._add_cover() for section in self.json_data["sections"]: if section["type"] == "section": self._add_section_slide(section) else: self._add_content_slide(section) output_dir = Path("output") output_dir.mkdir(exist_ok=True) output_path = output_dir / "old_community_report.pptx" self.prs.save(str(output_path)) print(f"[OK] PPT生成成功: {output_path}") if __name__ == "__main__": generator = ReportGenerator("config/project_config.json") generator.generate()6.4 一键串联脚本
为了把流程固定下来,再增加一个build.sh:
#!/bin/bash set -e echo ">>> 1/3 安装依赖" pip install -r requirements.txt echo ">>> 2/3 预处理图片" python scripts/preprocess_images.py echo ">>> 3/3 生成汇报PPT" python scripts/generate_report.py echo ">>> 完成,输出在 output/ 目录下"执行方式:
chmod +x build.sh ./build.sh如果你在Windows上使用,可以直接在命令行里逐条执行等价命令,无需bash脚本。
7. 运行结果与效果验证
脚本运行成功后,输出目录会出现old_community_report.pptx。用PowerPoint或WPS打开后,重点检查以下维度:
| 检查项 | 判断标准 |
|---|---|
| 封面 | 标题、副标题、作者显示完整 |
| 章节页 | 章节名称正确,摘要文字没有乱码 |
| 内容页 | 图片按顺序插入,大小一致 |
| 文字说明 | 每张图片下方有说明文字且对齐 |
| 整体页码 | 章节顺序和配置里的sections顺序一致 |
如果PPT中图片全部变形、文字溢出,优先检查图片预处理是否成功执行,以及内容页布局参数(坐标、宽度、高度)是否和你的实际分辨率匹配。
7.1 失败后的第一步排查
- 脚本报FileNotFoundError,直接检查config里图片路径和真实文件名是否一致。
- 图片能显示但很模糊,说明预处理时MAX_EDGE设得太小,建议调整到1920或2048。
- PPT打开乱码,检查JSON文件编码是否UTF-8,避免使用Windows记事本默认的ANSI编码。
8. 常见问题与排查思路
结合我实际使用中踩过的坑,列成下表:
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 图片无法插入PPT | 路径中包含空格或中文导致读取失败 | 查看脚本WARN日志,确认图片是否存在 | 使用pathlib处理路径,避免硬编码字符串拼接 |
| 生成的PPT体积过大 | 效果图未压缩或分辨率过高 | 查看输出文件大小 | 调低图片质量或MAX_EDGE值,建议quality=80~85 |
| 页面文字重叠 | 内容页预留位置与图片位置冲突 | 打开PPT查看重叠区域坐标 | 调整cons.top、图片height或文本框高度 |
| JSON中文乱码 | 文件编码不是UTF-8 | 用VS Code或Notepad++查看编码 | 保存为UTF-8无BOM格式 |
| AI效果图风格不一致 | 提示词模板未统一 | 对比多张图的生成参数 | 把固定部分完全复制,只改可变部分 |
| 楼栋结构被AI改变 | 图生图约束不够 | 对比原照片和效果图建筑轮廓 | 使用局部重绘,锁定窗外墙以外区域 |
| PPT文件被占用 | 上次打开未关闭 | 关闭PowerPoint后重试 | 增加脚本保存前检测或改用新的输出文件名 |
9. 最佳实践:让流水线可持续迭代
跑通第一版流水线后,你会发现真正拉开差距的不是脚本本身,而是你如何组织和沉淀素材。
9.1 素材命名规范
建议统一按“楼栋-位置-用途-版本”命名,例如“1栋-南立面-现状-v1.jpg”,而不是“微信图片_20250601123456.jpg”。好的命名是半个数据库。
9.2 提示词模板沉淀
每次生成效果好,就把这组提示词记录到提示词库。下次遇到类似风格需求,直接复制改造。AI绘图的质量上限,很大程度取决于提示词的沉淀质量,而不是模型本身。
9.3 配置文件当数据源,脚本尽量少改
在流水线设计里,数据和逻辑分离。JSON只存项目信息与图片清单,Python脚本只负责读取和生成。当新项目到来时,不要改脚本,新建配置文件即可。这样一套脚本可以服务很多个项目。
9.4 人工审核与合规边界
AI生成的效果图本质上是一种“意向图”,不是施工图,也不是最终承诺。在给业主和社区汇报时,建议在PPT里显眼位置标注“效果图仅供参考,最终以施工图为准”。这也是对团队和居民的双重保护。
9.5 版本管理
输出的PPT和配置文件可以用文件夹版本区分,比如config_v1、config_v2。建议不要用“最终版”“最终版2”这种命名。如果你在团队协作,可以考虑用Git管理配置和脚本,PPT二进制文件不适合频繁入库,但配置文件几乎是纯文本,非常适合版本管理。
9.6 从脚本到平台工作流的演进路径
如果以后项目变多、节点变多,比如需要AI自动生成每页文字、需要自动发送到协作平台,可以考虑迁移到Dify这类平台。Dify的自定义工作流可以把上传照片、生成文案、输出结构化JSON串起来,再把JSON喂给本地渲染脚本。迁移时先保留本地脚本作为回滚方案,不要一次性切换。
10. 后续可以继续深入的方向
这条流水线解决的是“从效果图到PPT”的标准化问题,但它只是AI辅助旧改交付的开始。
更进阶的方向有三个:
- 把AI生成的多版效果图做成“方案对比矩阵”,用工作流平台自动汇总每一栋楼的方案A和方案B差异。
- 把居民反馈文档接进来,用AI提炼高频诉求,自动生成“居民意见汇总”页面,减少整理时间。
- 把投资概算和施工计划接入配置文件,让PPT里的预算表、进度表也由数据源驱动,而不是手工填表。
刚开始不要贪多。先用今天的脚本跑通一个真实项目,拿到第一个完整的汇报PPT,再根据实际需要决定往哪个方向加节点。流水线最有价值的部分,从来不是某一个AI模型的魔法,而是把重复劳动变成可复用脚本,把个人经验变成团队模板。