# -*- 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 推理 25–35 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))
