# -*- coding: utf-8 -*-
"""一次性脚本:重组并瘦身《后端AI技术架构脉络说明-2》。
- 双产品重组为 4 部分;删除占位/虚构内容并替换为真实信息;长段落瘦身。
- 输出 -3,保留 -2 原件不动。视觉模板不动,只改文字 + 增删/重排页。
"""
import copy
from pptx import Presentation
from pptx.oxml.ns import qn
from pptx.util import Inches, Pt
from pptx.enum.text import PP_ALIGN

SRC = "后端AI技术架构脉络说明20260608-2.pptx"
DST = "后端AI技术架构脉络说明20260608-3.pptx"

A_P = qn('a:p'); A_R = qn('a:r'); A_T = qn('a:t')


def first_run_size(p):
    for r in p.runs:
        if r.font.size is not None:
            return r.font.size.pt
    return None


def size_templates(tf):
    d = {}
    for p in tf.paragraphs:
        if not p.runs:
            continue
        sz = first_run_size(p)
        key = sz if sz is not None else '_none'
        if key not in d:
            d[key] = copy.deepcopy(p._p)
    return d


def clone_para_with_text(template_p, text):
    new_p = copy.deepcopy(template_p)
    rs = new_p.findall(A_R)
    if not rs:
        return new_p
    first = rs[0]
    t = first.find(A_T)
    if t is None:
        t = first.makeelement(A_T, {})
        first.append(t)
    t.text = text
    for r in rs[1:]:
        new_p.remove(r)
    return new_p


def rebuild(tf, specs):
    """specs: [(text, size_pt)]  size 用于挑选要克隆格式的模板段落。"""
    templ = size_templates(tf)
    if not templ:
        return
    body = tf._txBody
    for p in body.findall(A_P):
        body.remove(p)
    for text, sz in specs:
        t = templ.get(sz)
        if t is None:
            t = next(iter(templ.values()))
        body.append(clone_para_with_text(t, text))


def shp(slide, name):
    for s in slide.shapes:
        if s.name == name:
            return s
    return None


def edit(slide, name, specs):
    s = shp(slide, name)
    if s is None or not s.has_text_frame:
        print(f"  !! 未找到形状 {name}")
        return
    rebuild(s.text_frame, specs)


def del_shape(slide, name):
    s = shp(slide, name)
    if s is not None:
        s._element.getparent().remove(s._element)


def retext(shape, text, size_pt=None, align=None):
    """改单段文字 + 可选字号/对齐,保留原 run 的颜色/字体(克隆来的)。"""
    tf = shape.text_frame
    body = tf._txBody
    for p in body.findall(A_P)[1:]:
        body.remove(p)
    p0 = tf.paragraphs[0]
    rs = p0._p.findall(A_R)
    if rs:
        first = rs[0]
        t = first.find(A_T)
        if t is None:
            t = first.makeelement(A_T, {})
            first.append(t)
        t.text = text
        for r in rs[1:]:
            p0._p.remove(r)
    if size_pt is not None:
        for r in p0.runs:
            r.font.size = Pt(size_pt)
    if align is not None:
        p0.alignment = align


def clone_shape(slide, src_name, new_name):
    """深拷贝一个形状(连同主题色/字体),分配唯一 id + 新名,返回 Shape。"""
    src = shp(slide, src_name)
    spTree = src._element.getparent()
    new_sp = copy.deepcopy(src._element)
    spTree.append(new_sp)
    ids = [int(e.get('id')) for e in spTree.iter(qn('p:cNvPr'))
           if e.get('id') and e.get('id').isdigit()]
    nid = (max(ids) + 1) if ids else 100
    cNvPr = new_sp.find(qn('p:nvSpPr')).find(qn('p:cNvPr'))
    cNvPr.set('id', str(nid))
    cNvPr.set('name', new_name)
    for s in slide.shapes:
        if s._element is new_sp:
            return s
    return None


def place(shape, left, top, width, height):
    shape.left = Inches(left)
    shape.top = Inches(top)
    shape.width = Inches(width)
    shape.height = Inches(height)


prs = Presentation(SRC)
S = prs.slides  # 原始 0-based 索引 = 幻灯片号 - 1

# ============ S1 (idx0) 封面:删除 4 段概述(标题+正文+连接线+卡片底框),只留标题/副标题 ============
# 每段含:卡片底框(9/13/17/21)、标题(10/14/18/22)、连接线(11/15/19/23)、正文(12/16/20/24)
for nm in ["AutoShape 6",
           "AutoShape 9", "AutoShape 13", "AutoShape 17", "AutoShape 21",   # 卡片底框
           "AutoShape 10", "AutoShape 14", "AutoShape 18", "AutoShape 22",  # 标题
           "AutoShape 12", "AutoShape 16", "AutoShape 20", "AutoShape 24",  # 正文
           "Connector 11", "Connector 15", "Connector 19", "Connector 23"]:
    del_shape(S[0], nm)

# 重新设计封面:左侧竖条/logo/顶部细线/页脚 保留作装饰边框;
# 主标题下移居中放大,补副标题(双产品)、议程标语(四部分)、落款单位。
cover = S[0]
# 主标题:24 -> 40,移到垂直居中偏上,左对齐与竖条呼应
retext(shp(cover, "AutoShape 7"), "后端 AI 技术架构脉络说明", size_pt=40, align=PP_ALIGN.LEFT)
place(shp(cover, "AutoShape 7"), 1.5, 2.55, 10.3, 1.0)
# 副标题:两大产品线
sub = clone_shape(cover, "AutoShape 7", "CoverSubtitle")
retext(sub, "水泥基配方大模型  ·  科研智能体应用平台", size_pt=20, align=PP_ALIGN.LEFT)
place(sub, 1.55, 3.7, 10.0, 0.6)
# 议程标语:四部分一行
agenda = clone_shape(cover, "AutoShape 7", "CoverAgenda")
retext(agenda, "总体架构与核心定位  /  五大引擎与训练  /  智能体应用平台  /  总结与展望",
       size_pt=14, align=PP_ALIGN.LEFT)
place(agenda, 1.57, 4.45, 10.5, 0.5)
# 落款单位:左下
unit = clone_shape(cover, "AutoShape 7", "CoverUnit")
retext(unit, "中国建筑材料科学研究总院 · AI 技术部", size_pt=13, align=PP_ALIGN.LEFT)
place(unit, 1.57, 6.1, 8.0, 0.4)

# ============ S2 (idx1) 目录:改为真实 4 部分 ============
edit(S[1], "AutoShape 7", [("后端 AI 技术架构 · 汇报目录", 24)])
edit(S[1], "AutoShape 12", [("总体架构与核心定位", 18)])
edit(S[1], "AutoShape 13", [("明确平台核心定位与建设目标,展示总体技术架构图与核心技术栈,奠定整体框架。", 14)])
edit(S[1], "AutoShape 17", [("配方大模型:五大引擎与训练", 18)])
edit(S[1], "AutoShape 18", [("智能问答、知识库构建、知识库问答、文档分类、实验设计五大引擎,及配方大模型训练体系与成效。", 14)])
edit(S[1], "AutoShape 22", [("科研智能体应用平台", 18)])
edit(S[1], "AutoShape 23", [("自然语言驱动的科研智能体:工作流、定位价值、14 项 Skill 能力矩阵与平台技术架构。", 14)])
edit(S[1], "AutoShape 27", [("总结与展望", 18)])
edit(S[1], "AutoShape 28", [("汇总核心成果与模型矩阵,总结建设价值,展望后续优化方向。", 14)])

# ============ S3 (idx2) PART 01:替换占位/假技术栈为真实内容 ============
edit(S[2], "AutoShape 7", [("PART 01 总体架构与核心定位", 24)])
edit(S[2], "AutoShape 10", [
    ("01 / 核心定位与目标", 18),
    ("面向行业场景构建一体化 AI 能力平台,聚焦水泥基材料,打通“通用能力接入 → 专属模型训练 → 智能推理 → 业务落地”全链路闭环。", 14)])
edit(S[2], "AutoShape 12", [
    ("02 / 总体架构分层", 18),
    ("分层解耦:应用层 → 后端服务层(五大引擎)→ 模型与数据层 → 行业模型训练模块,各层经标准接口协同,兼顾高可用与弹性扩展。", 14)])
edit(S[2], "AutoShape 14", [
    ("03 / 关键技术栈", 18),
    ("FastAPI 高并发异步后端;LangGraph + LangChain 编排;DeepSeek V3.1 / Qwen3 多模型并兼容 OpenAI 接口;Milvus 向量库;LLaMA Factory 训练。", 14)])

# ============ S6 (idx5) 核心技术栈:8 框瘦身 ============
edit(S[5], "AutoShape 12", [("高性能后端框架:FastAPI 高并发异步,保障接口高效、稳定、低延迟,支撑大规模请求与模型调用。", 14)])
edit(S[5], "AutoShape 14", [("智能体流程编排:LangGraph 可视化编排复杂逻辑,LangChain 构建调用链,兼容 OpenAI 接口,多模型高效协同。", 14)])
edit(S[5], "AutoShape 18", [("通用与微调基座:DeepSeek V3.1、Qwen3-30B-A3B 为通用基座,Qwen2.5-1.5B 行业微调,兼顾通用与适配。", 14)])
edit(S[5], "AutoShape 20", [("多模态与向量增强:Qwen2.5-VL 解析视觉内容,BGE-M3 向量化,构建全维度语义理解与知识表示。", 14)])
edit(S[5], "AutoShape 24", [("数据解析与存储:MinerU 解析 PDF/DOC 等非结构化文档,Milvus 向量库实现海量向量高维索引与快速检索。", 14)])
edit(S[5], "AutoShape 26", [("RAG 检索增强:外部知识库与大模型深度融合,有效抑制幻觉,提升回答准确性、专业性与一致性。", 14)])
edit(S[5], "AutoShape 30", [("一站式训练:LLaMA Factory 标准化训练流水线,统一接入多类开源大模型,降低开发与迭代门槛。", 14)])
edit(S[5], "AutoShape 32", [("低成本微调:PEFT + LoRA 仅训练少量关键参数即显著提效,大幅节省算力,加速行业模型落地。", 14)])

# ============ S7 (idx6) PART 02:通用假五引擎 → 真实五引擎总览 ============
edit(S[6], "AutoShape 7", [("PART 02 水泥基配方大模型:五大引擎", 24)])
edit(S[6], "AutoShape 10", [("01 智能问答中枢", 16)])
edit(S[6], "AutoShape 12", [("大模型统一入口,支持通用对话、文件问答、工具调用与多轮会话,可升级为执行任务。", 13)])
edit(S[6], "AutoShape 14", [("02 知识库构建引擎", 16)])
edit(S[6], "AutoShape 16", [("将非结构化文档解析、向量化为可检索、可追溯的企业知识资产,支撑上层应用。", 13)])
edit(S[6], "AutoShape 18", [("03 知识库问答引擎", 16)])
edit(S[6], "AutoShape 20", [("基于 RAG 结合企业知识作答,支持引用溯源,显著抑制大模型幻觉。", 13)])
edit(S[6], "AutoShape 22", [("04 AI 文档分类引擎", 16)])
edit(S[6], "AutoShape 24", [("自动识别文档领域与材料分类并归档,触发向量重建,实现知识治理自动化。", 13)])
edit(S[6], "AutoShape 26", [("05 智能实验设计引擎", 16)])
edit(S[6], "AutoShape 28", [("多阶段工作流将需求转为可执行实验方案,调用行业微调模型生成配方。", 13)])

# ============ S8 (idx7) 智能问答中枢:295 字一坨 → 瘦身 ============
edit(S[7], "AutoShape 2", [
    ("定位", 16),
    ("大模型统一入口,负责通用对话、文件问答、工具调用与多轮会话管理。", 13),
    ("核心技术", 16),
    ("• LangGraph 编排复杂对话流程", 13),
    ("• 核心模型 DeepSeek V3.1 / Qwen3-30B-A3B", 13),
    ("• 支持文件问答、多轮上下文与思考模式", 13),
    ("• MCP 工具接入外部业务系统与接口", 13),
    ("• SSE 流式输出,实时生成展示", 13),
    ("主要价值", 16),
    ("• 统一、标准化的大模型问答能力", 13),
    ("• 高扩展性,无缝集成更多业务工具", 13),
    ("• 从“回答问题”升级为“执行任务”", 13)])

# ============ S9 (idx8) 知识库构建 ============
edit(S[8], "AutoShape 2", [
    ("核心定位", 16),
    ("将非结构化文档转化为可检索、可引用、可追溯的企业知识资产,是上层应用的基础。", 13)])
edit(S[8], "AutoShape 3", [
    ("支持内容类型", 16),
    ("• 文档类:PDF / Word / PPT / Excel", 13),
    ("• 图像类:图片、扫描件、图表", 13),
    ("• 文本类:Markdown / TXT / CSV / JSON", 13)])
edit(S[8], "AutoShape 4", [
    ("主要价值", 16),
    ("• 分散资料沉淀为结构化企业知识库", 13),
    ("• 为问答、实验、训练提供高质量数据基础", 13)])

# ============ S10 (idx9) 知识库问答 ============
edit(S[9], "AutoShape 2", [
    ("定位", 16),
    ("基于 RAG 架构,让大模型结合企业内部知识作答,保证专业性与准确性。", 13)])
edit(S[9], "AutoShape 3", [
    ("核心技术", 16),
    ("• RAG 检索增强生成", 12),
    ("• BGE-M3 向量化 + Milvus 检索", 12),
    ("• DeepSeek/Qwen 结合上下文生成", 12),
    ("• 支持引用来源溯源", 12),
    ("• 多维度检索过滤", 12)])
edit(S[9], "AutoShape 4", [
    ("主要价值", 16),
    ("• 提升专业性、准确性与可追溯性", 13),
    ("• 赋能私有文档深度问答", 13),
    ("• 降低大模型幻觉风险", 13)])

# ============ S11 (idx10) 文档分类:169 字 → 瘦身 ============
edit(S[10], "AutoShape 2", [
    ("定位", 16),
    ("自动识别文档领域与材料分类并归档至对应知识库,实现知识管理自动化。", 13)])
edit(S[10], "AutoShape 3", [
    ("核心技术", 16),
    ("• 内容理解:基于 MinerU + Qwen2.5-VL 解析", 13),
    ("• 分类推理:DeepSeek V3.1 / Qwen3 判定", 13),
    ("• 智能输出:摘要、领域、分类路径、依据、置信度", 13),
    ("• 闭环管理:自动触发文档迁移与 Milvus 重建", 13)])
edit(S[10], "AutoShape 4", [
    ("主要价值", 16),
    ("• 大幅降低人工整理归档成本", 13),
    ("• 归入正确体系,提升检索效率", 13),
    ("• 为行业模型筛选标准化数据集", 13)])

# ============ S12 (idx11) 实验设计:238 字 → 瘦身 ============
edit(S[11], "AutoShape 2", [
    ("▍定位", 16),
    ("平台最核心的行业智能体能力,经多阶段工作流将需求转为可执行实验方案。", 13),
    ("▍核心技术", 16),
    ("• LangGraph 编排含人工确认的实验设计流", 13),
    ("• 混合调用:通用模型析文献,行业微调模型生成配方", 13),
    ("• 知识驱动:Milvus 检索文献作决策依据", 13),
    ("▍主要价值", 16),
    ("• 海量文献转为实验依据,降低人工成本", 13),
    ("• 方案生成全链路可追溯", 13),
    ("• 专项微调模型提升配方专业性与适配性", 13)])

# ============ S14 (idx13) 科研平台:作为 PART 03 开篇 ============
edit(S[13], "AutoShape 7", [("PART 03 科研智能体应用平台", 24)])
edit(S[13], "TextBox 9", [
    ("以自然语言为入口,平台自动识别意图、动态挂载专业能力,把科研任务串成可执行、可交付的工作流;", 13.5),
    ("关键节点由用户确认,全程运行在统一的模型、知识与安全底座之上。", 13.5)])

# ============ S15 (idx14) 定位与价值 ============
edit(S[14], "AutoShape 9", [
    ("面向科研全流程的智能体:以自然语言为入口,自动拆解任务、调度工具与专业能力,把“想法”直接转化为可交付科研产物,压缩从需求到成果的链路。", 16)])
edit(S[14], "AutoShape 14", [
    ("从问题拆解、文献检索、计算建模、出版级出图,到申报书/标准/专利起草与审稿,覆盖“调研—计算—写作—评审”全链条,无需多工具切换。", 14)])
edit(S[14], "AutoShape 18", [
    ("用自然语言描述需求,平台自动识别意图、挂载对应专业能力,按阶段化流程推进,关键节点与用户确认,过程可控可追溯。", 14)])
edit(S[14], "AutoShape 22", [
    ("不止对话回答,直接产出 Word / PPT / 图表 / 数据等规范化交付物,贴合科研与项目申报格式,降低整理排版成本。", 14)])

# ============ S16 (idx15) 能力矩阵 ============
edit(S[15], "AutoShape 12", [("申报书/任务书、国标·行标·团标、专利交底书、审稿润色,覆盖立项到评审的写作全链路。", 14)])
edit(S[15], "AutoShape 16", [("检索内部 100 万+ 篇材料学科论文库与全网文献,支持中文检索命中英文文献,提供可溯文献支撑。", 14)])
edit(S[15], "AutoShape 20", [("晶体结构 / XRD 模拟 / 相图计算,配方-性能统计建模与机器学习,服务“配比→性能”预测寻优。", 14)])
edit(S[15], "AutoShape 24", [("一键生成商务级 PPT,出版级 matplotlib 学术图(中文+矢量),让成果能看、能讲、能投稿。", 14)])
edit(S[15], "AutoShape 28", [("文生图、文生视频按需调用,为封面、概念示意与宣传材料快速产出配图与动效。", 14)])
edit(S[15], "AutoShape 32", [("科学问题拆解与路线图引导、代码实现与调试,把专业能力按任务智能编排串联。", 14)])
edit(S[15], "AutoShape 34", [("当前已沉淀 14 项专业能力(skill),按“科研写作·文献检索·科研计算·演示出图·内容生成·通用元能力”六类组织,并可持续扩展。", 13)])

# ============ S17 (idx16) 平台技术架构:8 框瘦身 ============
edit(S[16], "AutoShape 12", [("ReAct 智能体循环:“思考→调用工具→观察”自主迭代,内置重复调用守卫与异常自愈,自动收敛到可交付结果。", 14)])
edit(S[16], "AutoShape 14", [("阶段化编排:复杂任务以图式工作流编排,嵌入人工确认节点,关键决策由用户拍板,过程可追溯。", 14)])
edit(S[16], "AutoShape 18", [("意图识别 + 按需挂载:识别需求后动态加载对应 skill,不相关能力不进上下文,精准又省算力。", 14)])
edit(S[16], "AutoShape 20", [("可扩展插件:每个 skill 是独立可维护的工作流(流程+模板+脚本),新增能力即插即用。", 14)])
edit(S[16], "AutoShape 24", [("每用户 Docker 沙盒隔离:代码执行与文件读写独立容器运行,资源限额 + 网络管控 + 最小权限。", 14)])
edit(S[16], "AutoShape 26", [("丰富工具集 + MCP:内置文件、命令、Python、联网检索等工具,兼容 MCP 接入外部系统。", 14)])
edit(S[16], "AutoShape 30", [("多模型自由调度:兼容 DeepSeek、Qwen 等及 OpenAI 接口,涉密任务可切内网私有模型。", 14)])
edit(S[16], "AutoShape 32", [("RAG + 长期记忆:向量检索抑制幻觉,双层记忆与长任务断点恢复,跨会话沉淀偏好与上下文。", 14)])

# ============ S18 (idx17) 训练体系导语:215 字 → 瘦身 + 侧标改子节 ============
edit(S[17], "AutoShape 8", [("训练体系", 20)])
edit(S[17], "AutoShape 10", [
    ("聚焦水泥基材料智能配方大模型的核心训练体系——材料配方智能化设计的技术基石。", 16),
    ("阐述从数据采集、特征工程到算法选型、迭代优化的全流程逻辑,融合材料科学机理与深度学习,破解传统研发“试错成本高、周期长”的痛点。", 16),
    ("并展示模型在性能预测、多目标配方寻优等关键环节的技术突破。", 16)])

# ============ S19 (idx18) 训练基础信息 ============
edit(S[18], "AutoShape 12", [("采用 LLaMA Factory 训练框架,Qwen2.5-1.5B-Instruct 为基座,兼顾训练效率与推理性能。", 13)])
edit(S[18], "AutoShape 16", [("PEFT + LoRA:不更新主干参数,仅微调少量低秩矩阵,大幅降低显存与训练成本,精准学习配方知识。", 13)])
edit(S[18], "AutoShape 20", [("以 SFT 为核心,建立“材料性能要求 → 配方组成”的精准映射,实现需求到方案直接转化。", 13)])
edit(S[18], "AutoShape 24", [("基于 16 组实验室实测数据:输入 3 天/7 天抗压、抗折强度;输出矿粉、电石渣、脱硫石膏、粉煤灰、水、减水剂配比。", 13)])

# ============ S21 (idx20) 训练成效 ============
edit(S[20], "AutoShape 12", [
    ("损失值收敛表现", 14),
    ("初始 0.6897 → 第 50 轮 0.0073,降幅 98.9%,拟合充分且未过拟合。", 12)])
edit(S[20], "AutoShape 14", [
    ("学习率动态调整", 14),
    ("从 4.92e-04 衰减至 4.93e-07,配合损失动态适配,避免后期震荡。", 12)])
edit(S[20], "AutoShape 27", [("损失曲线全程无剧烈波动,稳定在极低水平,参数更新策略有效,鲁棒性佳。", 12)])
edit(S[20], "AutoShape 31", [("模型掌握“低强度→低掺量、高强度→高掺量”行业逻辑,配方贴合工程实际。", 12)])
edit(S[20], "AutoShape 35", [("稳定输出高精度预测值,并按工程格式生成完整配方,直接对接下游系统。", 12)])

# ============ S23 (idx22) 总结 PART 04:删除虚构指标,替换真实成果 ============
edit(S[22], "AutoShape 7", [("总结与展望", 24)])
# 标题与正文是分开的形状:标题改 AutoShape 11/16/21/26,正文改 13/18/23/28
edit(S[22], "AutoShape 11", [("01. 核心能力落地成效", 18)])
edit(S[22], "AutoShape 13", [
    ("已落地五大引擎(智能问答、知识库构建/问答、文档分类、实验设计)与科研智能体平台,沉淀 14 项专业 skill;水泥基配方大模型完成首版训练,损失收敛至 0.0073。", 14)])
edit(S[22], "AutoShape 16", [("02. 平台技术底座", 18)])
edit(S[22], "AutoShape 18", [
    ("FastAPI + LangGraph 智能体内核,DeepSeek/Qwen 多模型调度,Milvus + RAG 抑制幻觉,每用户 Docker 沙盒隔离,LLaMA Factory + LoRA 行业微调。", 14)])
edit(S[22], "AutoShape 21", [("03. 业务价值与知识资产", 18)])
edit(S[22], "AutoShape 23", [
    ("打通“数据→知识→决策”全链路闭环;内部 100 万+ 篇材料论文知识库与配方数据沉淀为可复用知识资产,支撑研发提效。", 14)])
edit(S[22], "AutoShape 26", [("04. 下一阶段规划", 18)])
edit(S[22], "AutoShape 28", [
    ("配方数据集由 16 条扩充至 200+,简化配方空间,搭建“预测—实验—反馈”闭环,目标配方达标率 ≥85%;持续扩展 skill 与场景。", 14)])

# ============ S24 (idx23) 模型矩阵汇总:6 框各 120+ 字 → 瘦身 ============
edit(S[23], "AutoShape 9", [
    ("模型矩阵架构", 18),
    ("基于 DeepSeek、Qwen 大模型底座,融合视觉模型与向量检索,构建“通用+垂直”双轮驱动体系。", 13),
    ("核心价值:打通“解析→沉淀→决策”全链路闭环,提升研发与应用效率。", 14)])
DIV = "——————————"
edit(S[23], "AutoShape 11", [
    ("01. 智能问答中枢:通用基座", 15), (DIV, 11),
    ("模型:DeepSeek V3.1 / Qwen3-30B-A3B", 12),
    ("场景:通用问答、文件问答与工具调用,平台统一入口。", 12)])
edit(S[23], "AutoShape 13", [
    ("02. 知识库构建:多模态沉淀", 15), (DIV, 11),
    ("模型:Qwen2.5-VL + BGE-M3 + Milvus", 12),
    ("场景:文档解析、图表提取,非结构化数据向量化入库。", 12)])
edit(S[23], "AutoShape 15", [
    ("03. 知识库问答:精准溯源", 15), (DIV, 11),
    ("模型:DeepSeek V3.1 + BGE-M3 + Milvus", 12),
    ("场景:RAG 精准问答,提供原文引用与溯源。", 12)])
edit(S[23], "AutoShape 17", [
    ("04. AI 文档分类:知识治理", 15), (DIV, 11),
    ("模型:Qwen3-30B-A3B + BGE-M3", 12),
    ("场景:自动识别主题、分类归档,解决海量文档管理难题。", 12)])
edit(S[23], "AutoShape 19", [
    ("05. 智能实验设计:研发提效", 15), (DIV, 11),
    ("模型:通用大模型 + Qwen2.5-1.5B(LoRA 配方模型)", 12),
    ("场景:分析文献与实验数据,生成配方初步方案。", 12)])
edit(S[23], "AutoShape 21", [
    ("06. 配方模型训练:垂直深耕", 15), (DIV, 11),
    ("模型:Qwen2.5-1.5B 基座 + BGE-M3 预处理", 12),
    ("场景:学习“性能-配方”映射,建立专属垂直模型。", 12)])

# ============ 结构:重排 + 删除(S4=idx3 与 S25=idx24 删除) ============
# 目标顺序(原始 0-based 索引):
# 开场: 0,1  | PART1: 2,4,5  | PART2: 6,7,8,9,10,11,12,17,18,19,20,21
# PART3: 13,14,15,16  | PART4: 22,23,25
order = [0, 1, 2, 4, 5,
         6, 7, 8, 9, 10, 11, 12, 17, 18, 19, 20, 21,
         13, 14, 15, 16,
         22, 23, 25]
sldIdLst = prs.slides._sldIdLst
ids = list(sldIdLst)
dropped_rids = [ids[i].get(qn('r:id')) for i in range(len(ids)) if i not in order]
for e in ids:
    sldIdLst.remove(e)
for i in order:
    sldIdLst.append(ids[i])
# 彻底移除被删幻灯片的部件(否则孤立 part 残留,PowerPoint 可能弹"修复")
for rid in dropped_rids:
    if rid in prs.part.rels:
        prs.part.drop_rel(rid)

prs.save(DST)
print(f"OK -> {DST}  共 {len(order)} 页")
