Files
ai-startup/gen_pptx_guide.py
T
2026-08-05 17:25:15 +08:00

376 lines
22 KiB
Python
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.
# -*- coding: utf-8 -*-
"""生成《三阶段软硬配置及使用指南.pptx》
核心:每个阶段 = 客户好处 + 具体工作流程 + 人操作/自动化分工
"""
import os
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
BASE = r"C:\Users\Administrator\Desktop\AI落地公司企划项目"
ASSETS = os.path.join(BASE, "assets")
OUT = os.path.join(BASE, "三阶段软硬配置及使用指南.pptx")
BG_DARK = RGBColor(0x0B,0x25,0x45)
PRIMARY = RGBColor(0x13,0x31,0x5C)
ACCENT = RGBColor(0x2E,0x93,0xF7)
HIGHLIGHT= RGBColor(0xFF,0x8A,0x3D)
LIGHT = RGBColor(0xF4,0xF7,0xFB)
GRAY = RGBColor(0x6B,0x7A,0x8F)
WHITE = RGBColor(0xFF,0xFF,0xFF)
TEXTDARK = RGBColor(0x1A,0x24,0x33)
HUMAN_C = RGBColor(0xC8,0x6A,0x1B)
AUTO_C = RGBColor(0x1E,0x6F,0xB8)
prs = Presentation()
SW, SH = Inches(13.333), Inches(7.5)
prs.slide_width, prs.slide_height = SW, SH
BLANK = prs.slide_layouts[6]
def add_bg(slide, color=LIGHT):
s = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE,0,0,SW,SH)
s.fill.solid(); s.fill.fore_color.rgb=color
s.line.fill.background(); s.shadow.inherit=False
def add_title(slide, title, page=None, subtitle=None):
bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE,0,0,SW,Inches(1.15))
bar.fill.solid(); bar.fill.fore_color.rgb=PRIMARY; bar.line.fill.background(); bar.shadow.inherit=False
st = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE,0,Inches(1.15),SW,Inches(0.06))
st.fill.solid(); st.fill.fore_color.rgb=ACCENT; st.line.fill.background(); st.shadow.inherit=False
tb = slide.shapes.add_textbox(Inches(0.55),Inches(0.16),SW-Inches(1.1),Inches(0.95))
tf = tb.text_frame; tf.word_wrap=True
p = tf.paragraphs[0]; r = p.add_run(); r.text=title
r.font.size=Pt(25); r.font.bold=True; r.font.color.rgb=WHITE
if subtitle:
p2 = tf.add_paragraph(); r2=p2.add_run(); r2.text=subtitle
r2.font.size=Pt(12); r2.font.color.rgb=RGBColor(0xBB,0xD6,0xF2)
if page is not None:
ft = slide.shapes.add_textbox(Inches(0.55),SH-Inches(0.4),SW-Inches(1.6),Inches(0.3))
fp = ft.text_frame.paragraphs[0]; fr=fp.add_run()
fr.text="三阶段软硬配置及使用指南 · 【客户名称】"; fr.font.size=Pt(9); fr.font.color.rgb=GRAY
pg = slide.shapes.add_textbox(SW-Inches(1.05),SH-Inches(0.4),Inches(0.6),Inches(0.3))
pp = pg.text_frame.paragraphs[0]; pr=pp.add_run(); pr.text=str(page)
pr.font.size=Pt(9); pr.font.color.rgb=GRAY; pp.alignment=PP_ALIGN.RIGHT
def add_bullets(slide, items, left, top, width, height, size=14, color=TEXTDARK):
tb = slide.shapes.add_textbox(left,top,width,height)
tf = tb.text_frame; tf.word_wrap=True
first=True
for it in items:
text,lvl = it if isinstance(it,tuple) else (it,0)
p = tf.paragraphs[0] if first else tf.add_paragraph()
first=False; p.level=lvl; p.space_after=Pt(8)
pre = "• " if lvl==0 else " "
r = p.add_run(); r.text = pre+text
r.font.size = Pt(size if lvl==0 else size-2); r.font.color.rgb=color
def add_table(slide, data, left, top, width, height, col_widths=None, tag_col=None):
rows,cols = len(data), len(data[0])
gtbl = slide.shapes.add_table(rows,cols,left,top,width,height)
table = gtbl.table
if col_widths:
tot=sum(col_widths)
for i,cw in enumerate(col_widths):
table.columns[i].width = Emu(int(width*cw/tot))
for ri,row in enumerate(data):
for ci,val in enumerate(row):
cell = table.cell(ri,ci)
cell.margin_left=Inches(0.07); cell.margin_right=Inches(0.07)
cell.margin_top=Inches(0.03); cell.margin_bottom=Inches(0.03)
cell.vertical_anchor=MSO_ANCHOR.MIDDLE
tf = cell.text_frame; tf.word_wrap=True
p = tf.paragraphs[0]
if tag_col and ci in tag_col and ri>0:
c_left = gtbl.left + sum(table.columns[k].width for k in range(ci))
c_top = gtbl.top + sum(table.rows[k].height for k in range(ri))
c_w = table.columns[ci].width
c_h = table.rows[ri].height
badge = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE,
c_left+Emu(int(c_w*0.08)), c_top+Emu(int(c_h*0.2)),
Emu(int(c_w*0.84)), Emu(int(c_h*0.6)))
badge.fill.solid()
badge.fill.fore_color.rgb = HUMAN_C if "人" in val else AUTO_C
badge.line.fill.background(); badge.shadow.inherit=False
btf = badge.text_frame; btf.word_wrap=True
bp = btf.paragraphs[0]; bp.alignment=PP_ALIGN.CENTER
br = bp.add_run(); br.text=val
br.font.size=Pt(10); br.font.bold=True; br.font.color.rgb=WHITE
cell.text = ""
continue
r = p.add_run(); r.text=val; r.font.size=Pt(11)
if ri==0:
cell.fill.solid(); cell.fill.fore_color.rgb=PRIMARY
r.font.color.rgb=WHITE; r.font.bold=True
else:
cell.fill.solid(); cell.fill.fore_color.rgb = WHITE if ri%2 else LIGHT
r.font.color.rgb=TEXTDARK
if ci==0: r.font.bold=True
return table
def add_image(slide, path, left, top, width):
slide.shapes.add_picture(path,left,top,width=width)
def notes(slide, text):
slide.notes_slide.notes_text_frame.text = text
def new_page(title, page, subtitle=None):
s = prs.slides.add_slide(BLANK); add_bg(s); add_title(s,title,page,subtitle); return s
# ============ 1 封面 ============
cov = prs.slides.add_slide(BLANK); add_bg(cov,BG_DARK)
acc = cov.shapes.add_shape(MSO_SHAPE.RECTANGLE,0,0,Inches(0.22),SH)
acc.fill.solid(); acc.fill.fore_color.rgb=ACCENT; acc.line.fill.background(); acc.shadow.inherit=False
t = cov.shapes.add_textbox(Inches(0.9),Inches(1.8),Inches(11.5),Inches(1.7))
tf=t.text_frame; tf.word_wrap=True
p=tf.paragraphs[0]; r=p.add_run(); r.text="三阶段软硬配置及使用指南"
r.font.size=Pt(42); r.font.bold=True; r.font.color.rgb=WHITE
p2=tf.add_paragraph(); r2=p2.add_run(); r2.text="数据底座 → 模型引擎 → 日常使用运维"
r2.font.size=Pt(20); r2.font.color.rgb=ACCENT
st = cov.shapes.add_textbox(Inches(0.9),Inches(3.6),Inches(11.5),Inches(0.6))
sp=st.text_frame.paragraphs[0]; sr=sp.add_run()
sr.text="每一阶段:客户能得到什么好处 | 工作流程怎么跑 | 人操作还是自动化"
sr.font.size=Pt(16); sr.font.color.rgb=RGBColor(0xBB,0xD6,0xF2)
info = cov.shapes.add_textbox(Inches(0.9),Inches(5.6),Inches(11.5),Inches(1.0))
ip=info.text_frame
for i,line in enumerate(["客户:【客户名称】 服务商:【您的公司】",
"配套文档:商业闭环运营基板 v1.9 / 硬件与部署实现方案 v1.1 / 本地模型好用落地设计 v1.0"]):
pp=ip.paragraphs[0] if i==0 else ip.add_paragraph()
rr=pp.add_run(); rr.text=line; rr.font.size=Pt(12); rr.font.color.rgb=RGBColor(0x9F,0xB6,0xCE)
notes(cov,"【讲解】这份指南解决三个问题:客户能得到什么、流程怎么跑、哪些自动化哪些要人。")
# ============ 2 目录 ============
s = new_page("目录",1)
add_bullets(s,[
"一、整体架构速览 + 人机分工总原则",
"二、阶段一:数据底座 —— 好处 / 流程 / 人机分工",
"三、阶段二:模型引擎 —— 好处 / 流程 / 人机分工",
"四、阶段三:日常使用与运维 —— 好处 / 流程 / 人机分工",
"五、人操作 vs 自动化 总表",
"六、客户好处汇总 + 你的运维节奏",
"七、心里有底 QA + 红线兜底",
], Inches(0.9),Inches(1.7),Inches(11.5),Inches(4.6),size=17)
# ============ 3 架构总览 ============
s = new_page("一、整体架构速览",2)
add_image(s, os.path.join(ASSETS,"architecture.png"), Inches(1.6),Inches(1.35),Inches(10.1))
add_bullets(s,[
"人机分工总原则:一次性配置靠人,日常运行靠自动;老板只做两件事——看报告、问数据",
], Inches(0.9),Inches(6.6),Inches(11.5),Inches(0.6),size=13,color=PRIMARY)
notes(s,"最底下硬件是一次性装机(人);数据清洗建库是定时自动;模型常驻自动路由;最上面看板/微信推送全自动。")
# ============ 4 阶段一 目标与好处 ============
s = new_page("二之一、阶段一 数据底座:目标与客户好处",3)
add_bullets(s,[
("客户好处",0),
"① 数据收拢成「一本账」:老板随时查任何月份、任何 SKU,不再等财务做表",
"② 免费工具先学会自己看数据(演示+教学,不依赖别人)",
"③ 数据资产在自己厂里,不出厂、不上云,放心",
("本阶段做什么",0),
"免费工具 + 数据清洗整理 + SQLite 建库 + Streamlit 看板",
("自动化程度",0),
"清洗入库、看板更新 = 全自动(cron 定时);老板查数据 = 人操作(浏览器打开就看)",
], Inches(0.9),Inches(1.6),Inches(11.5),Inches(5.2),size=15)
notes(s,"阶段一对应基板阶段一/二。价值锚:让老板第一次体验到「数据看得清」。")
# ============ 5 阶段一 工作流程 ============
s = new_page("二之二、阶段一 数据底座:具体工作流程",4)
add_bullets(s,[
"① 【人·老板】每月从网店后台导出 Excel/CSV,丢进共享文件夹(教一次就会)",
"② 【自动·cron】每月 1 号凌晨,清洗脚本自动运行:去重→统一格式→入库 SQLite",
"③ 【自动】看板数据自动刷新(服务常驻,无需重启)",
"④ 【人·老板】打开浏览器随时查:月度趋势 / SKU 排行 / 区域分布 / 断码热力图",
"⑤ 【人·你】每月 1 次数据对账:抽 3–5 个关键数跟老板确认,口径不变",
"⑥ 【人·你】指标口径随业务调整时维护(季度级)",
], Inches(0.9),Inches(1.6),Inches(11.5),Inches(5.0),size=15)
notes(s,"老板的日常操作只有一件事:导数据丢文件夹。其余全自动。")
# ============ 6 阶段一 人机分工表 ============
s = new_page("二之三、阶段一 人操作 vs 自动化",5)
add_table(s,[
["功能","实现方式","频率","分工"],
["安装/配置免费工具","一次性部署到你电脑/客户机","一次性","人"],
["老板导出数据丢文件夹","平台后台导出","每周/每月","人"],
["数据清洗+入库 SQLite","Python 脚本 + cron","每月1号自动","自动"],
["看板数据刷新","Streamlit 服务常驻","实时","自动"],
["老板查数据/看板","浏览器访问内网地址","随时","人"],
["数据对账确认","抽数核对","每月1次","人"],
["指标口径维护","文档+脚本更新","按需","人"],
], Inches(0.7),Inches(1.7),Inches(11.9),Inches(4.6),col_widths=[2.6,3.2,1.8,2.4],tag_col=[3])
notes(s,"阶段一自动化集中在「清洗入库+看板」,人只做配置和每月对账。")
# ============ 7 阶段二 目标与好处 ============
s = new_page("三之一、阶段二 模型引擎:目标与客户好处",6)
add_bullets(s,[
("客户好处",0),
"① 数据不出厂也能 AI 分析:周报、归因、问答全在本地跑(敏感数据安全)",
"② 响应快:本地 30B MoE 推理 2535 Token/s,不用等网络",
"③ 成本固定:本地模型一次买断,不按次收费,越用越划算",
("本阶段做什么",0),
"EVO-X2+NAS 装机 → Ubuntu/ROCm → Ollama 多模型常驻 → Hermes Agent → API 混用兜底",
("自动化程度",0),
"模型加载、任务路由、云端兜底 = 全自动;装机配置 = 一次性人操作",
], Inches(0.9),Inches(1.6),Inches(11.5),Inches(5.2),size=15)
notes(s,"阶段二对应基板阶段三。核心卖点:敏感数据本地分析 + 固定成本。")
# ============ 8 阶段二 部署流程 ============
s = new_page("三之二、阶段二 模型引擎:部署流程",7)
add_bullets(s,[
"① 【人·你】POC 先行:先用云端 API 在客户真实数据上跑出周报样例,老板认可才买硬件",
"② 【人·你】装机:EVO-X2 装 Ubuntu 24.04 + ROCm 驱动(最大坑,样机先跑通)+ NAS RAID5",
"③ 【人·你】模型部署:Ollama 拉 35B MoE + 14B + bge-m3,设 keep_alive 常驻",
"④ 【人·你】Agent 配置:Hermes Agent 注册工具(查库/发消息/生成报告)+ 任务路由规则",
"⑤ 【人·你】API 混用配置:DeepSeek 兜底开关(置信度低自动转云端)",
"⑥ 【自动】之后:模型常驻、路由、兜底全部自动运行,无需人工干预",
], Inches(0.9),Inches(1.6),Inches(11.5),Inches(5.0),size=15)
notes(s,"阶段二是配置密集型:全部一次性配置做完,之后全自动。")
# ============ 9 阶段二 人机分工表 ============
s = new_page("三之三、阶段二 人操作 vs 自动化",8)
add_table(s,[
["功能","实现方式","频率","分工"],
["POC 效果验证","云端 API 跑样例给老板看","客户掏钱前","人"],
["硬件装机","EVO-X2+NAS 安装调试","一次性","人"],
["ROCm/驱动/系统","Ubuntu 24.04 + ROCm 配置","一次性","人"],
["模型加载/常驻","Ollama keep_alive","自动运行","自动"],
["任务路由","Agent 按任务分模型","实时","自动"],
["云端 API 兜底","置信度低自动 fallback","实时","自动"],
["月度特调模型(QLoRA","27B 特调训练","3个月后按需","人"],
], Inches(0.7),Inches(1.7),Inches(11.9),Inches(4.6),col_widths=[2.6,3.2,1.8,2.4],tag_col=[3])
notes(s,"阶段二 7 项里 5 项自动,人只做装机和 POC。")
# ============ 10 阶段三 目标与好处 ============
s = new_page("四之一、阶段三 日常使用运维:目标与客户好处",9)
add_bullets(s,[
("客户好处",0),
"① 每周一自动收《经营周报》:不用做表,微信直接看图文",
"② 断码/库存预警自动推送:缺货出事前就知道,不等老板发现",
"③ 随时问数据:像问助手一样「上月华东卖了多少」,秒回",
"④ 每月 4 次到岗专属服务:特调模型、问答库整理、巡检、答疑",
"⑤ 决策有依据:补货建议、现金流模拟、SKU 优化",
("自动化程度",0),
"周报/预警/问答 = 全自动(定时任务+Agent);月度到岗 = 人操作(你)",
], Inches(0.9),Inches(1.6),Inches(11.5),Inches(5.2),size=15)
notes(s,"阶段三对应基板阶段三运行期+阶段四。客户日常几乎零操作。")
# ============ 11 阶段三 功能流程 ============
s = new_page("四之二、阶段三 日常功能工作流程",10)
add_bullets(s,[
("周报(全自动)",0),
"① 每周一早 9 点 cron 触发 → ② Agent 读库 → ③ 35B MoE 生成图文简报 → ④ 微信推给老板",
("断码预警(全自动)",0),
"① 每日 08:00 扫描库存 → ② 命中断码阈值 → ③ Agent 生成预警 → ④ 微信推送",
("数据问答(半自动)",0),
"① 老板微信/看板提问 → ② Agent 查库 → ③ 本地模型组织答案 → ④ 秒回(复杂问题自动转云端)",
("月度到岗(人操作·你)",0),
"每月 4 次:特调模型优化 / A&Q 问答库整理 / 巡检备份 / 老板答疑",
], Inches(0.9),Inches(1.6),Inches(11.5),Inches(5.2),size=14)
notes(s,"周报、预警完全不需要人碰;问答是人问机答;到岗是你的服务承诺。")
# ============ 12 阶段三 人机分工表 ============
s = new_page("四之三、阶段三 人操作 vs 自动化",11)
add_table(s,[
["功能","实现方式","频率","分工"],
["经营周报推送","cron + Agent + 微信","每周一早9点","自动"],
["断码/库存预警","每日库存扫描 + 阈值触发","每日08:00","自动"],
["数据问答","Agent 查库 + 本地模型回答","随时","人问/机答"],
["月度到岗(4次)","上门服务","每月4次","人"],
["备份快照","NAS 每日快照 + 异地","每日/每周","自动"],
["巡检与日志检查","远程巡检","每周1次","人"],
["备份还原演练","手动演练","每月1次","人"],
["模型效果抽查","抽查5条输出质量","每周1次","人"],
], Inches(0.7),Inches(1.7),Inches(11.9),Inches(4.6),col_widths=[2.6,3.2,1.8,2.4],tag_col=[3])
notes(s,"核心功能全自动;人的动作集中在巡检、到岗、抽查。")
# ============ 13 总表 ============
s = new_page("五、人操作 vs 自动化 总表(一页看全)",12)
add_table(s,[
["环节","自动化的","需要人操作的","老板日常动作"],
["阶段一 数据底座","清洗入库、看板刷新(cron","安装配置、每月对账","导数据丢文件夹、看板查数"],
["阶段二 模型引擎","模型常驻、路由、API 兜底","POC、装机、特调","无(全自动)"],
["阶段三 使用运维","周报、断码预警、问答","月度到岗、巡检、抽查","看微信、问数据"],
["你(服务商)","—","到岗4次/月 + 远程巡检 + 维护","—"],
], Inches(0.7),Inches(1.8),Inches(11.9),Inches(3.8),col_widths=[2.2,3.4,3.6,2.8])
add_bullets(s,[
"结论:老板每周只花 10 分钟(看周报+导数据);你的日常是每周远程巡检 1 次 + 每月到岗 4 次",
], Inches(0.9),Inches(6.0),Inches(11.5),Inches(0.8),size=14,color=PRIMARY)
notes(s,"这张表是给客户看「我买了什么服务」的总图。")
# ============ 14 好处汇总 ============
s = new_page("六之一、客户得到的好处汇总(老板视角)",13)
add_table(s,[
["好处","对应功能","解决什么问题"],
["不再等财务做表","周报每周一自动推送","报表慢、人力耗"],
["数据随时看得清","看板+数据问答","看不清赚亏"],
["出事早知道","断码/异常预警","缺货、积压后知后觉"],
["敏感数据不出厂","本地模型+NAS","怕数据泄露"],
["决策有依据","补货/现金流/SKU 建议","拍脑袋备货"],
["有人全程管","月度到岗+远程运维","系统没人维护"],
], Inches(0.7),Inches(1.7),Inches(11.9),Inches(3.6),col_widths=[3.0,4.2,3.4])
add_bullets(s,[
"一句话给老板:数据留在厂里,分析自动跑,报告送到手机,出事提前提醒,决策有人给依据",
], Inches(0.9),Inches(5.6),Inches(11.5),Inches(0.8),size=15,color=HIGHLIGHT)
# ============ 15 运维节奏 ============
s = new_page("六之二、你的运维节奏(每天/每周/每月/每季)",14)
add_table(s,[
["频率","动作","耗时"],
["每天","看系统告警(模型/服务异常到你微信)","10 分钟"],
["每周","① 确认周一周报已发出 ② 抽查 5 条输出质量","20 分钟"],
["每月","4 次到岗(特调/A&Q/巡检/答疑)+ 备份还原演练 + API 用量核对","4 个半天"],
["每季度","模型效果评估 + 客户升档评估 + 特调需求评估","1 天"],
], Inches(0.7),Inches(1.7),Inches(11.9),Inches(3.4),col_widths=[1.4,6.2,2.6])
add_bullets(s,[
"单人可承受:每周合计约 1 小时远程 + 每月 4 个半天到岗 —— 这是月维护费 2000/3000 的服务边界",
], Inches(0.9),Inches(5.4),Inches(11.5),Inches(0.8),size=14,color=PRIMARY)
# ============ 16 QA ============
s = new_page("七之一、心里有底 QA(常见问题)",15)
add_table(s,[
["问题","答案"],
["机器挂了怎么办?","数据在 NAS(RAID+快照+异地),换机重装系统后还原,1 天内恢复(每月演练过)"],
["模型效果差怎么办?","按顺序调:查 RAG 检索 → 改提示词 → 换大模型 → 最后才微调;期间置信度低自动转云端,客户无感"],
["断电了怎么办?","UPS 兜底 10 分钟,来电自动恢复;NAS 有快照不怕掉盘"],
["客户要加新功能?","工具函数库加一个函数即可(模板化),半天内上线"],
["老板要查数据?","看板随时查 / 微信问一句秒回"],
["数据更新怎么进系统?","客户导出丢文件夹 → cron 自动清洗入库,不用你干预"],
["客户停缴维护费?","系统停更但已交付功能保留(威慑不撕破脸)"],
["你自己生病/忙不过来?","SOP 文档化 + 远程自动运维,关键操作留文档"],
], Inches(0.7),Inches(1.7),Inches(11.9),Inches(4.8),col_widths=[2.6,9.4])
# ============ 17 红线兜底 ============
s = new_page("七之二、红线与兜底机制",16)
add_bullets(s,[
"① 数据不出厂:NAS 只在内网,Tailscale 只放行你;云端 API 只接可脱敏任务",
"② POC 先行:客户掏钱前先用云端样例验证效果,效果好才买硬件",
"③ 验收前置:合同写明「本地完成的任务验收 = 格式正确+规则正确」,主观好坏交云端",
"④ 兜底开关:Agent 置信度低 → 自动转云端 API,客户无感切换",
"⑤ 本地主力:35B MoE 承接 80–90% 任务,云端只是保险丝(月预算 <200)",
], Inches(0.9),Inches(1.6),Inches(11.5),Inches(4.6),size=15)
# ============ 18 第一周清单 ============
s = new_page("七之三、交付后第一周清单",17)
add_bullets(s,[
"☐ 免费工具装好,老板学会自己拖数据",
"☐ 数据盘点拿到(含尺码维度,鞋类客户必查)",
"☐ 清洗脚本跑通,老板点过关键数",
"☐ 一页流程图交付(含退换货流程)",
"☐ 备忘录签署(免费边界 + 3 个月保护期 + 案例转介绍)",
"☐ 约好下周:教老板拖新数据 + 提阶段二(周报 300/次)",
], Inches(0.9),Inches(1.6),Inches(11.5),Inches(4.2),size=15)
# ============ 19 封底 ============
s = prs.slides.add_slide(BLANK); add_bg(s,BG_DARK)
t = s.shapes.add_textbox(Inches(0.9),Inches(3.0),Inches(11.5),Inches(1.5))
tf=t.text_frame; tf.word_wrap=True
p=tf.paragraphs[0]; p.alignment=PP_ALIGN.CENTER
r=p.add_run(); r.text="三阶段软硬配置及使用指南 · v1.0"
r.font.size=Pt(30); r.font.bold=True; r.font.color.rgb=WHITE
p2=tf.add_paragraph(); p2.alignment=PP_ALIGN.CENTER
r2=p2.add_run(); r2.text="配置一次 · 运行自动 · 老板零操作 · 你只做维护"
r2.font.size=Pt(16); r2.font.color.rgb=ACCENT
prs.save(OUT)
print("saved:", OUT, "slides:", len(prs.slides._sldIdLst))