Files
InternalAuditInterprise/docs/build_ppt2.py
T
2026-06-16 00:38:57 +08:00

780 lines
42 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.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""精美版:本地LLM审计方案 PPTX,带流程图/热力矩阵/架构分层/卡片排版。"""
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
from pptx.oxml.ns import qn
import copy
# ---------- 主题色 ----------
BG = RGBColor(0x0A, 0x16, 0x2E) # 主深蓝背景
BG2 = RGBColor(0x0E, 0x20, 0x42) # 次背景
CARD = RGBColor(0x14, 0x2B, 0x52) # 卡片
CARD2 = RGBColor(0x1B, 0x37, 0x66) # 卡片亮
CYAN = RGBColor(0x2D, 0xE0, 0xD0) # 主青
CYAN_D = RGBColor(0x16, 0x9B, 0x97)
BLUE = RGBColor(0x3B, 0x82, 0xF6) # 蓝
PURPLE = RGBColor(0x8B, 0x7CF if False else 0x7C, 0xF6)
GOLD = RGBColor(0xF5, 0xB7, 0x42) # 金
RED = RGBColor(0xEF, 0x5A, 0x5A) # 红(高风险)
ORANGE = RGBColor(0xF2, 0x8B, 0x3C)
GREEN = RGBColor(0x35, 0xC7, 0x59)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
LIGHT = RGBColor(0xCB, 0xD8, 0xEC) # 正文浅
MUTE = RGBColor(0x8A, 0x9C, 0xB8) # 弱化
FONT = "PingFang SC"
FONT_B = "PingFang SC"
SW, SH = Inches(13.333), Inches(7.5)
prs = Presentation()
prs.slide_width, prs.slide_height = SW, SH
BLANK = prs.slide_layouts[6]
# ---------- 底层工具 ----------
def _set_grad(shape, c1, c2, angle=90):
"""给 shape 设置线性渐变填充。"""
sp = shape.fill._xPr # spPr
# 移除已有填充
for tag in ('a:noFill','a:solidFill','a:gradFill','a:blipFill','a:pattFill','a:grpFill'):
for e in sp.findall(qn(tag)):
sp.remove(e)
grad = sp.makeelement(qn('a:gradFill'), {})
lst = grad.makeelement(qn('a:gsLst'), {})
for pos, col in ((0, c1), (100000, c2)):
gs = grad.makeelement(qn('a:gs'), {'pos': str(pos if pos else int(pos*1000))})
if pos == 0: gs.set('pos','0')
else: gs.set('pos','100000')
clr = gs.makeelement(qn('a:srgbClr'), {'val': '%02X%02X%02X' % (col[0],col[1],col[2])})
gs.append(clr); lst.append(gs)
grad.append(lst)
lin = grad.makeelement(qn('a:lin'), {'ang': str(int(angle*60000)), 'scaled':'1'})
grad.append(lin)
# 插入到 ln 之前
ln = sp.find(qn('a:ln'))
if ln is not None: sp.insert(list(sp).index(ln), grad)
else: sp.append(grad)
def bg_gradient(slide, c1=BG, c2=BG2):
r = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, SW, SH)
r.line.fill.background(); r.shadow.inherit = False
r.fill.solid(); r.fill.fore_color.rgb = c1
_set_grad(r, c1, c2, angle=120)
return r
def rrect(slide, x, y, w, h, color=None, grad=None, line=None, lw=1, radius=0.08):
sp = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, x, y, w, h)
sp.shadow.inherit = False
try:
sp.adjustments[0] = radius
except Exception:
pass
if grad:
sp.fill.solid(); sp.fill.fore_color.rgb = grad[0]
_set_grad(sp, grad[0], grad[1], angle=90)
elif color is not None:
sp.fill.solid(); sp.fill.fore_color.rgb = color
else:
sp.fill.background()
if line is not None:
sp.line.color.rgb = line; sp.line.width = Pt(lw)
else:
sp.line.fill.background()
return sp
def rect(slide, x, y, w, h, color=None, grad=None, line=None, lw=1):
sp = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, x, y, w, h)
sp.shadow.inherit = False
if grad:
sp.fill.solid(); sp.fill.fore_color.rgb = grad[0]; _set_grad(sp, grad[0], grad[1])
elif color is not None:
sp.fill.solid(); sp.fill.fore_color.rgb = color
else:
sp.fill.background()
if line is not None:
sp.line.color.rgb = line; sp.line.width = Pt(lw)
else:
sp.line.fill.background()
return sp
def circle(slide, x, y, d, color=None, grad=None, line=None, lw=1.5):
sp = slide.shapes.add_shape(MSO_SHAPE.OVAL, x, y, d, d)
sp.shadow.inherit = False
if grad:
sp.fill.solid(); sp.fill.fore_color.rgb = grad[0]; _set_grad(sp, grad[0], grad[1])
elif color is not None:
sp.fill.solid(); sp.fill.fore_color.rgb = color
else:
sp.fill.background()
if line is not None:
sp.line.color.rgb = line; sp.line.width = Pt(lw)
else:
sp.line.fill.background()
return sp
def chevron(slide, x, y, w, h, color):
sp = slide.shapes.add_shape(MSO_SHAPE.CHEVRON, x, y, w, h)
sp.shadow.inherit = False
sp.fill.solid(); sp.fill.fore_color.rgb = color
sp.line.fill.background()
return sp
def shape_text(shape, runs, align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE, wrap=True):
tf = shape.text_frame; tf.word_wrap = wrap; tf.vertical_anchor = anchor
tf.margin_left = Pt(4); tf.margin_right = Pt(4)
tf.margin_top = Pt(2); tf.margin_bottom = Pt(2)
for i, para in enumerate(runs):
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.alignment = align; p.space_after = Pt(2); p.space_before = Pt(0)
for (t, sz, c, b) in para:
r = p.add_run(); r.text = t
r.font.size = Pt(sz); r.font.color.rgb = c; r.font.bold = b; r.font.name = FONT
def txt(slide, x, y, w, h, runs, align=PP_ALIGN.LEFT, anchor=MSO_ANCHOR.TOP,
wrap=True, sa=6, line_spacing=None):
tb = slide.shapes.add_textbox(x, y, w, h); tf = tb.text_frame
tf.word_wrap = wrap; tf.vertical_anchor = anchor
for i, para in enumerate(runs):
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.alignment = align; p.space_after = Pt(sa); p.space_before = Pt(0)
if line_spacing: p.line_spacing = line_spacing
for (t, sz, c, b) in para:
r = p.add_run(); r.text = t
r.font.size = Pt(sz); r.font.color.rgb = c; r.font.bold = b; r.font.name = FONT
return tb
def header(slide, kicker, title):
rect(slide, Inches(0.7), Inches(0.62), Inches(0.14), Inches(0.62), grad=(CYAN, BLUE))
txt(slide, Inches(0.98), Inches(0.5), Inches(11.5), Inches(0.4),
[[(kicker, 13, CYAN, True)]], sa=0)
txt(slide, Inches(0.95), Inches(0.82), Inches(11.6), Inches(0.7),
[[(title, 29, WHITE, True)]], sa=0)
def footer(slide, page):
rect(slide, 0, Inches(7.18), SW, Inches(0.32), color=BG2)
txt(slide, Inches(0.7), Inches(7.16), Inches(6), Inches(0.32),
[[("数据不出域 · 审计全穿透", 9.5, MUTE, False)]], anchor=MSO_ANCHOR.MIDDLE, sa=0)
txt(slide, Inches(11.6), Inches(7.16), Inches(1.0), Inches(0.32),
[[(f"{page:02d} / 23", 10, CYAN, True)]], align=PP_ALIGN.RIGHT,
anchor=MSO_ANCHOR.MIDDLE, sa=0)
def new(kicker=None, title=None, page=None):
s = prs.slides.add_slide(BLANK)
bg_gradient(s)
# 右上角装饰圆
circle(s, Inches(11.6), Inches(-1.0), Inches(3.2), color=BG2)
circle(s, Inches(12.4), Inches(-0.4), Inches(1.6), color=CARD)
if kicker is not None:
header(s, kicker, title)
if page is not None:
footer(s, page)
return s
# ============== 1 封面 ==============
def cover():
s = prs.slides.add_slide(BLANK)
bg_gradient(s, RGBColor(0x07,0x10,0x24), RGBColor(0x10,0x29,0x52))
# 几何装饰
circle(s, Inches(9.8), Inches(-1.6), Inches(5.2), color=RGBColor(0x10,0x24,0x48))
circle(s, Inches(11.2), Inches(0.2), Inches(2.8), grad=(CYAN_D, BG))
for i, d in enumerate([Inches(0.16)]*3):
circle(s, Inches(10.2+ i*0.5), Inches(4.6 + i*0.35), d, color=CYAN)
rect(s, 0, 0, Inches(0.22), SH, grad=(CYAN, BLUE))
txt(s, Inches(0.9), Inches(1.7), Inches(3), Inches(0.5),
[[("AI · 全域内审", 15, CYAN, True)]], sa=0)
rect(s, Inches(0.95), Inches(2.2), Inches(2.4), Pt(4), color=CYAN)
txt(s, Inches(0.88), Inches(2.45), Inches(10.5), Inches(1.7),
[[("数据不出域", 56, WHITE, True)], [("审计全穿透", 56, CYAN, True)]], sa=4)
txt(s, Inches(0.95), Inches(4.95), Inches(10.5), Inches(1.2),
[[("基于本地私有化大模型的电信运营商 AI 全域内审体系", 20, WHITE, True)],
[("不是一套工具,而是一套建在自己机房里、越用越聪明的审计能力体系", 14.5, LIGHT, False)]], sa=8)
rect(s, Inches(0.95), Inches(6.35), Inches(0.5), Pt(3), color=CYAN)
txt(s, Inches(0.95), Inches(6.5), Inches(6), Inches(0.4),
[[("2026 年 6 月", 13, MUTE, False)]], sa=0)
cover()
# ============== 2 痛点:三个数字 + 三类困局 ==============
def pain():
s = new("现状 · 困局", "为什么传统审计“查不过来”?", 2)
# 三个大数字卡片
stats = [("150亿", "年业务规模", BLUE), ("5000万", "潜在异常金额", GOLD), ("5%", "传统抽样覆盖率", RED)]
x = Inches(0.95); w = Inches(3.62); gap = Inches(0.27)
for i,(num, lab, col) in enumerate(stats):
cx = x + i*(w+gap)
c = rrect(s, cx, Inches(1.75), w, Inches(1.55), color=CARD, radius=0.1)
rect(s, cx, Inches(1.75), Inches(0.1), Inches(1.55), color=col)
txt(s, cx+Inches(0.25), Inches(1.92), w-Inches(0.3), Inches(0.85),
[[(num, 38, col, True)]], sa=0)
txt(s, cx+Inches(0.27), Inches(2.75), w-Inches(0.3), Inches(0.4),
[[(lab, 14, LIGHT, False)]], sa=0)
# 三类困局
cases = [
("拆单规避", "8 个客户各签 600 万 ICT 项目全拆成 80 万以下,三重一大抽样完美避开。"),
("稳定的定,稳定的退", "每月新增 6000 人订彩铃,3 个月后首月用户全退订,渠道已领佣金、骗补后弃养。"),
("Excel 干不过来", "海量单据只能抽样,查不全查不深,5000 万异常如针落大海。"),
]
y = Inches(3.55)
for i,(t, d) in enumerate(cases):
cy = y + i*Inches(0.78)
rrect(s, Inches(0.95), cy, Inches(11.55), Inches(0.66), color=CARD if i%2 else CARD2, radius=0.12)
circle(s, Inches(1.12), cy+Inches(0.13), Inches(0.4), grad=(CYAN, BLUE))
txt(s, Inches(1.12), cy+Inches(0.13), Inches(0.4), Inches(0.4),
[[(str(i+1), 16, WHITE, True)]], align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE, sa=0)
txt(s, Inches(1.7), cy, Inches(2.4), Inches(0.66),
[[(t, 14.5, CYAN, True)]], anchor=MSO_ANCHOR.MIDDLE, sa=0)
txt(s, Inches(4.0), cy, Inches(8.3), Inches(0.66),
[[(d, 12.5, LIGHT, False)]], anchor=MSO_ANCHOR.MIDDLE, sa=0)
txt(s, Inches(0.95), Inches(6.05), Inches(11.55), Inches(0.5),
[[("核心矛盾:", 13, GOLD, True),
("数据涉政企合同/用户隐私/财务凭证,上公有云=裸奔;不上 AI 又干不过来。", 13, WHITE, False)]],
anchor=MSO_ANCHOR.MIDDLE, sa=0)
pain()
# ============== 通用表格 ==============
def style_table(table, headers, rows, col_widths, total_w, top, left=Inches(0.95),
hrow=Inches(0.52), rrow=Inches(0.62), fs=12, hfs=13):
n = len(rows)+1
for i,w in enumerate(col_widths):
table.columns[i].width = Inches(w)
table.rows[0].height = hrow
for i in range(1, n): table.rows[i].height = rrow
# remove default style banding via first row formatting
for j,h in enumerate(headers):
c = table.cell(0,j); c.fill.solid(); c.fill.fore_color.rgb = CYAN_D
c.vertical_anchor = MSO_ANCHOR.MIDDLE
p = c.text_frame.paragraphs[0]; p.alignment = PP_ALIGN.CENTER
c.text_frame.word_wrap = True
r = p.add_run(); r.text = h; r.font.size = Pt(hfs); r.font.bold = True
r.font.color.rgb = WHITE; r.font.name = FONT
for i,row in enumerate(rows, start=1):
for j,val in enumerate(row):
c = table.cell(i,j); c.fill.solid()
c.fill.fore_color.rgb = CARD if i%2 else CARD2
c.vertical_anchor = MSO_ANCHOR.MIDDLE
c.text_frame.word_wrap = True
p = c.text_frame.paragraphs[0]
p.alignment = PP_ALIGN.CENTER if j==0 else PP_ALIGN.LEFT
r = p.add_run(); r.text = val; r.font.size = Pt(fs)
r.font.bold = (j==0)
r.font.color.rgb = CYAN if j==0 else LIGHT
r.font.name = FONT
def table_slide(page, kicker, title, headers, rows, note=None, col_widths=None,
fs=12, hfs=13):
s = new(kicker, title, page)
total = sum(col_widths)
top = Inches(1.85)
shp = s.shapes.add_table(len(rows)+1, len(headers), Inches(0.95), top,
Inches(total), Inches(0.5)+Inches(0.6)*len(rows))
# 去掉自带样式
tbl = shp.table
style_table(tbl, headers, rows, col_widths, total, top, fs=fs, hfs=hfs)
if note:
ny = top + Inches(0.5)+Inches(0.62)*len(rows) + Inches(0.3)
rrect(s, Inches(0.95), ny, Inches(11.55), Inches(0.7), color=CARD2, radius=0.18)
rect(s, Inches(0.95), ny, Inches(0.1), Inches(0.7), color=GOLD)
txt(s, Inches(1.25), ny, Inches(11.1), Inches(0.7),
[[("", 13, GOLD, True), (note, 13, WHITE, True)]],
anchor=MSO_ANCHOR.MIDDLE, sa=0)
return s
# ============== 3 三方对比 ==============
table_slide(3, "破局 · 定位", "本地 LLM 让“安全”和“智能”不再二选一",
["对比维度", "传统抽样审计", "公有云 AI 审计", "本地 LLM 审计(我们)"],
[
["数据范围", "按金额抽样,查不全", "全量扫描,但数据出域", "全量扫描,数据不出机房"],
["规则能力", "规则写死,反向规避", "模型强,但合规风险高", "模型私有化,合规可控"],
["响应效率", "Excel 翻表,效率低", "实时预警,依赖外网", "内网闭环,秒级响应"],
["交互模式", "人找数据", "数据找人,但数据送人", "数据找人,数据原地不动"],
["能力归属", "经验在人脑,人走经验走", "能力在外部,租用即失", "能力沉淀本地,越用越聪明"],
],
note="把千问 70B / DeepSeek 装进本地机房,让 AI 在数据旁边干活,而不是把数据送给 AI。",
col_widths=[2.0, 3.1, 3.2, 3.25])
# ============== 4 审计域全景 + 风险热力矩阵 ==============
def domain_heat():
s = new("方法论 · 框架", "审计域全景图 + 风险分级模型", 4)
# 左:五大风险域
domains = [
("收入域", "政企穿透·跨期匹配·云空转", CYAN),
("成本域", "渠道佣金·终端补贴·摊销", BLUE),
("采购域", "网络建设·工程·围标串标", PURPLE),
("资金域", "回款挂账·网间结算·流向", GOLD),
("合规域", "员工舞弊·权限·积分套现", GREEN),
]
txt(s, Inches(0.95), Inches(1.75), Inches(6), Inches(0.4),
[[("五大风险域 · 全覆盖", 15, WHITE, True)]], sa=0)
y = Inches(2.25)
for i,(t,d,col) in enumerate(domains):
cy = y + i*Inches(0.82)
rrect(s, Inches(0.95), cy, Inches(6.0), Inches(0.68), color=CARD, radius=0.14)
rect(s, Inches(0.95), cy, Inches(0.12), Inches(0.68), color=col)
circle(s, Inches(1.2), cy+Inches(0.14), Inches(0.4), color=col)
txt(s, Inches(1.55), cy, Inches(1.5), Inches(0.68),
[[(t, 15, WHITE, True)]], anchor=MSO_ANCHOR.MIDDLE, sa=0)
txt(s, Inches(3.0), cy, Inches(3.85), Inches(0.68),
[[(d, 11.5, LIGHT, False)]], anchor=MSO_ANCHOR.MIDDLE, sa=0)
# 右:风险热力矩阵 3x3
txt(s, Inches(7.4), Inches(1.75), Inches(5), Inches(0.4),
[[("风险热力矩阵 · 有优先级", 15, WHITE, True)]], sa=0)
gx, gy = Inches(8.35), Inches(2.35)
cell = Inches(1.25)
# 颜色矩阵 [行=金额影响 高->低][列=概率 低->高]
heat = [
[ORANGE, RED, RED],
[GOLD, ORANGE, RED],
[GREEN, GOLD, ORANGE],
]
labels = [
["", "", "优先\n全量监控"],
["重点\n定向穿透", "", ""],
["", "", "批量\n聚类筛查"],
]
for r_ in range(3):
for c_ in range(3):
cx = gx + c_*cell; cyy = gy + r_*cell
rrect(s, cx, cyy, cell-Inches(0.08), cell-Inches(0.08),
color=heat[r_][c_], radius=0.12)
if labels[r_][c_]:
lines = [[(seg, 9.5, WHITE, True)] for seg in labels[r_][c_].split("\n")]
txt(s, cx, cyy, cell-Inches(0.08), cell-Inches(0.08),
lines, align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE, sa=0)
# 轴标签
txt(s, gx-Inches(0.05), gy-Inches(0.05), cell*3, Inches(0.3), [], sa=0)
txt(s, Inches(7.55), gy, Inches(0.75), cell*3,
[[("\n\n\n", 11, CYAN, True)]], align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE, sa=0)
txt(s, gx, gy+cell*3-Inches(0.02), cell*3, Inches(0.35),
[[("发生概率 低 → 高", 11, CYAN, True)]], align=PP_ALIGN.CENTER, sa=0)
# 底注
ny = Inches(6.35)
rrect(s, Inches(0.95), ny, Inches(11.55), Inches(0.62), color=CARD2, radius=0.2)
rect(s, Inches(0.95), ny, Inches(0.1), Inches(0.62), color=GOLD)
txt(s, Inches(1.25), ny, Inches(11.1), Inches(0.62),
[[("", 13, GOLD, True),
("不是工具集合,而是有体系、有优先级的全域审计框架。", 13, WHITE, True)]],
anchor=MSO_ANCHOR.MIDDLE, sa=0)
domain_heat()
# ============== 5 四大引擎(2x2卡片)==============
def engines():
s = new("能力 · 底座", "“本地 AI 审计大脑”四大核心引擎", 5)
cards = [
("01", "本地私有化 LLM 引擎", "模型本地化部署,数据绝不出域;推理、规则配置、报告生成、线索解释。", CYAN),
("02", "全量穿透引擎", "直连 BSS/OSS/ERP/财务,不抽样,对所有合同、回款、行为做关联扫描。", BLUE),
("03", "规则进化引擎(护城河)", "自然语言描述新造假→自动转规则→沙箱验证→把顾问经验固化为机构资产。", GOLD),
("04", "线索驱动引擎", "对异常聚类做人话解释,输出附证据链的高价值线索,直推审计员桌面。", GREEN),
]
W, H = Inches(5.7), Inches(2.18)
gx, gy = Inches(0.95), Inches(1.85)
gapx, gapy = Inches(0.18), Inches(0.22)
for i,(no,t,d,col) in enumerate(cards):
r,c = divmod(i,2)
x = gx + c*(W+gapx); y = gy + r*(H+gapy)
rrect(s, x, y, W, H, color=CARD, radius=0.07)
rect(s, x, y, Inches(0.14), H, color=col)
circle(s, x+Inches(0.35), y+Inches(0.32), Inches(0.85), grad=(col, BG2))
txt(s, x+Inches(0.35), y+Inches(0.32), Inches(0.85), Inches(0.85),
[[(no, 26, WHITE, True)]], align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE, sa=0)
txt(s, x+Inches(1.4), y+Inches(0.35), W-Inches(1.6), Inches(0.6),
[[(t, 17, WHITE, True)]], sa=0)
txt(s, x+Inches(1.4), y+Inches(1.0), W-Inches(1.65), Inches(1.05),
[[(d, 12.5, LIGHT, False)]], sa=0, line_spacing=1.15)
engines()
# ============== 6-13 场景页 ==============
def scene(page, no, name, color, blocks):
s = prs.slides.add_slide(BLANK); bg_gradient(s)
# 左侧色带
rect(s, 0, 0, Inches(3.0), SH, color=BG2)
rect(s, Inches(3.0), 0, Inches(0.06), SH, color=color)
circle(s, Inches(0.55), Inches(2.0), Inches(1.9), grad=(color, BG2))
txt(s, Inches(0.55), Inches(2.05), Inches(1.9), Inches(1.9),
[[(no, 60, WHITE, True)]], align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE, sa=0)
txt(s, Inches(0.3), Inches(0.55), Inches(2.4), Inches(0.4),
[[("场景", 14, color, True)]], align=PP_ALIGN.CENTER, sa=0)
txt(s, Inches(0.25), Inches(4.15), Inches(2.55), Inches(1.6),
[[(seg, 19, WHITE, True)] for seg in name.split("\n")],
align=PP_ALIGN.CENTER, sa=2)
# 右侧内容卡片
y = Inches(0.7)
icons = {"经典案例":"","扩展案例":"","AI 审计点":"","本地 LLM 能力":"","业务链路":""}
for label, text in blocks:
h = Inches(1.18) if len(text) > 46 else Inches(0.95)
rrect(s, Inches(3.3), y, Inches(9.55), h, color=CARD if "案例" not in label or "扩展" in label else CARD2, radius=0.08)
# 标签条
lab_col = color if label in ("AI 审计点","本地 LLM 能力","业务链路") else CYAN
txt(s, Inches(3.55), y+Inches(0.12), Inches(9.1), Inches(0.36),
[[(label, 13.5, lab_col, True)]], sa=0)
txt(s, Inches(3.55), y+Inches(0.46), Inches(9.1), h-Inches(0.5),
[[(text, 12.5, LIGHT, False)]], sa=0, line_spacing=1.12)
y = y + h + Inches(0.12)
footer(s, page)
scenes = [
("01","政企收入\n全链路穿透", CYAN, [
("业务链路","立项→审批→报价→签约→开票→回款,全链路穿透。"),
("经典案例(拆单规避+虚假回款)","8 个客户各签 600 万拆成 79-99 万规避审批,尾款 500 万长期挂账;注册地址同楼、法人为同一人亲属、付款账户同一实控企业。"),
("AI 审计点","合同金额阈值边缘聚集;工商关联穿透识别隐性实控人;回款时序聚类识别批量违约。"),
("本地 LLM 能力","自然语言查数、关联推理、一键生成《政企客户回款异常专项线索清单》。"),
]),
("02","市场业务\n真实性", BLUE, [
("经典案例(稳定的定,稳定的退)","每月新增 6000 人订彩铃,3 个月后首月用户全退订,骗补后弃养;号码集中乡镇、通话记录为零。"),
("扩展案例(物联网卡虚假激活)","批量开通 10 万张卡称智慧停车,激活后零流量,按激活量领每台 50 元补贴,半年后集体沉默。"),
("AI 审计点","用户生命周期时序识别;佣金与业务质量匹配;沉默/零通话用户聚类;交付物与收入交叉验证。"),
("本地 LLM 能力","识别脉冲式增长+规律性衰减的周期性造假,自动提炼为新规则。"),
]),
("03","收入与成本\n跨期匹配", PURPLE, [
("经典案例(趸交收入一次性确认)","24 个月套餐送手表,收入应分 24 月却因趸交一把确认,手表成本却摊 24 月,确认时点严重错配。"),
("扩展案例(提前确认)","云项目约定按用量计费,财务却在设备上架当月全额确认,客户前 6 月几乎零使用。"),
("AI 审计点","自动勾稽确认政策 vs 账务 vs 合同;识别一次性确认异常分录;成本摊销与收入跨期匹配。"),
("本地 LLM 能力","跨系统自动勾稽,识别收入成本确认时点错配的异常分录模式。"),
]),
("04","渠道佣金与\n代理商套利", GOLD, [
("经典案例(虚假放号+套机套卡)","批量买老人机插 5G 卡激活后丢弃,领 5G 迁转佣金每台 200 元+补贴 300 元,次月用户全流失。"),
("扩展案例(异地窜货套利)","从邻省低价采购同款机,本省以新用户入网名义领高额补贴,手机回流二级市场。"),
("AI 审计点","IMEI 与用户绑定真实性;佣金与在网时长匹配;终端流向追踪;代理商质量时序衰减。"),
("本地 LLM 能力","IMEI 级终端流向追踪,识别激活-沉默-流失套利闭环。"),
]),
("05","网络建设与\n工程采购", GREEN, [
("经典案例(围标串标+虚增工程量)","3 家投标报价差异不足 1%、方案雷同,中标后同一班组施工,签证单同一笔迹不同日期批量签字。"),
("扩展案例(虚假巡检)","系统显示月巡检 2000 次,GPS 比对实际只到 300 站,其余照片复用+坐标伪造。"),
("AI 审计点","投标报价相似度与文件雷同度;工程量与资源消耗匹配;巡检轨迹与工单交叉;马甲供应商识别。"),
("本地 LLM 能力","NLP 比对投标雷同度,GPS 轨迹与工单交叉验证,识别马甲供应商。"),
]),
("06","互联互通与\n网间结算", CYAN, [
("经典案例(话务量操纵)","与境外合谋虚假国际来话刷量,主叫为虚商号段,时长均为 30/60 秒整数倍,明显非真人。"),
("扩展案例(短信网关刷量)","SP 伪造记录申报成功发送 10 亿条按 0.05 元/条结算,实际到达率不足 10%"),
("AI 审计点","话务量时序异常与整数时长聚集;结算数据与原始信令比对;SP/CP 业务量与结算交叉验证。"),
("本地 LLM 能力","识别整数倍通话时长等非人类行为,信令级原始数据比对。"),
]),
("07","云业务/IDC\n与新兴业务", BLUE, [
("经典案例(云资源空转)","政企客户签 3 年云服务年付 100 万,CPU 利用率长期<5%、存储近空,却全额确认收入,实控人为领导亲属。"),
("扩展案例(IDC 机柜虚租)","宣称出租率 90%,实际大量机柜无设备、电费为零,收入来自关联方预付租金。"),
("AI 审计点","资源使用量 vs 计费量匹配;出租率与电力消耗勾稽;关联方与预付异常;确认与验收时序一致性。"),
("本地 LLM 能力","资源利用率与计费量自动比对,关联方网络挖掘,识别空转收入。"),
]),
("08","员工内部舞弊\n与资源滥用", PURPLE, [
("经典案例(内部号码套利)","员工用权限批量开员工测试号对外出租免流套餐,流量收入全计入内部成本未确认收入。"),
("扩展案例(积分套现)","勾结外部商户虚构消费批量刷积分兑换礼品卡变现,某商户单日发放量超正常 100 倍。"),
("AI 审计点","权限操作日志异常模式;测试号实际用途偏离;积分流向追踪;权限与岗位匹配度。"),
("本地 LLM 能力","操作日志异常挖掘,权限-岗位匹配分析,积分流向网络追踪。"),
]),
]
pg = 6
for no,name,col,blocks in scenes:
scene(pg, no, name, col, blocks); pg += 1
# ============== 14 数据治理 ==============
def governance():
s = new("工程 · 地基", "数据接入与治理层(全量穿透的前提)", 14)
items = [
("多源异构接入","适配 BSS/OSS/ERP/财务/合同/工单/信令各系统接口、数据库、文件,统一汇入本地数据湖。", CYAN),
("主数据对齐","客户、合同、号码、工单、供应商跨系统实体统一,解决主键对不上。", BLUE),
("数据质量探查与清洗","缺失、重复、口径不一自动探查清洗,建立质量评分。", PURPLE),
("增量同步与时效","从年度快照升级为近实时增量,支撑常态化监控。", GOLD),
]
W, H = Inches(5.7), Inches(1.55)
gx,gy = Inches(0.95), Inches(1.85)
for i,(t,d,col) in enumerate(items):
r,c = divmod(i,2)
x = gx + c*(W+Inches(0.18)); y = gy + r*(H+Inches(0.2))
rrect(s, x, y, W, H, color=CARD, radius=0.08)
rect(s, x, y, Inches(0.12), H, color=col)
circle(s, x+Inches(0.32), y+Inches(0.3), Inches(0.55), color=col)
txt(s, x+Inches(0.32), y+Inches(0.3), Inches(0.55), Inches(0.55),
[[(str(i+1), 18, WHITE, True)]], align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE, sa=0)
txt(s, x+Inches(1.05), y+Inches(0.2), W-Inches(1.2), Inches(0.45),
[[(t, 15.5, WHITE, True)]], sa=0)
txt(s, x+Inches(1.05), y+Inches(0.66), W-Inches(1.25), Inches(0.8),
[[(d, 12, LIGHT, False)]], sa=0, line_spacing=1.12)
ny = Inches(5.5)
rrect(s, Inches(0.95), ny, Inches(11.55), Inches(0.95), color=CARD2, radius=0.12)
rect(s, Inches(0.95), ny, Inches(0.1), Inches(0.95), color=GOLD)
txt(s, Inches(1.25), ny, Inches(11.1), Inches(0.95),
[[("我们把脏活写进方案、承担下来", 14.5, GOLD, True)],
[("数据治理是这套体系工作量最大、最该提前立项的一环,而非回避。", 12.5, WHITE, False)]],
anchor=MSO_ANCHOR.MIDDLE, sa=3)
governance()
# ============== 15 人机协同闭环(流程图)==============
def closed_loop():
s = new("闭环 · 价值", "人机协同闭环:线索之后才是价值", 15)
steps = ["AI 全量扫描","生成线索+证据链","审计员复核研判","自动生成底稿","定性 / 整改","复核销项闭环"]
cols = [CYAN, BLUE, PURPLE, BLUE, GOLD, GREEN]
n = len(steps)
x0 = Inches(0.85); y = Inches(2.1); w = Inches(1.95); h = Inches(0.95); ov = Inches(0.32)
step_w = (Inches(12.5) - w) / (n-1)
for i,(t,col) in enumerate(zip(steps, cols)):
x = x0 + step_w*i
ch = chevron(s, x, y, w+ov, h, col)
shape_text(ch, [[(seg, 12.5, WHITE, True)] for seg in t.split(" ")] if " " in t else [[(t,12.5,WHITE,True)]],
align=PP_ALIGN.CENTER)
# 返回箭头示意(闭环)
txt(s, Inches(0.85), Inches(3.05), Inches(12), Inches(0.4),
[[("◄──────────────── 规则进化反哺,越用越聪明 ────────────────►", 12, MUTE, True)]],
align=PP_ALIGN.CENTER, sa=0)
# 三栏角色
roles = [
("AI 侧","出线索、附证据链、给判定理由、自动生成可追溯底稿。", CYAN),
("审计员侧","复核研判、定性、决定整改或移交、最终签字。", BLUE),
("闭环管理","线索分派、取证留痕、整改跟踪、销项复核全流程在线。", GOLD),
]
W = Inches(3.7); gx = Inches(0.95); y2 = Inches(3.75)
for i,(t,d,col) in enumerate(roles):
x = gx + i*(W+Inches(0.22))
rrect(s, x, y2, W, Inches(1.85), color=CARD, radius=0.08)
rect(s, x, y2, W, Inches(0.5), color=col)
txt(s, x, y2, W, Inches(0.5), [[(t, 15, WHITE, True)]],
align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE, sa=0)
txt(s, x+Inches(0.25), y2+Inches(0.65), W-Inches(0.5), Inches(1.1),
[[(d, 12.5, LIGHT, False)]], sa=0, line_spacing=1.18)
ny = Inches(5.95)
rrect(s, Inches(0.95), ny, Inches(11.55), Inches(0.62), color=CARD2, radius=0.2)
rect(s, Inches(0.95), ny, Inches(0.1), Inches(0.62), color=GOLD)
txt(s, Inches(1.25), ny, Inches(11.1), Inches(0.62),
[[("", 13, GOLD, True),
("从“发现工具”升级为“办案平台”——每一步都接得住、留得痕。", 13, WHITE, True)]],
anchor=MSO_ANCHOR.MIDDLE, sa=0)
closed_loop()
# ============== 16 误报治理 ==============
def fp_control():
s = new("可信 · 落地", "误报治理与置信度分级(专业 = 诚实)", 16)
# 左:三级置信漏斗
txt(s, Inches(0.95), Inches(1.8), Inches(6), Inches(0.4),
[[("三级置信分流", 15, WHITE, True)]], sa=0)
tiers = [("高置信","直接推送处置", GREEN, 6.0),
("中置信","人工复核研判", GOLD, 4.6),
("低置信","归档备查", MUTE, 3.2)]
y = Inches(2.35)
for t,d,col,w in tiers:
ww = Inches(w)
x = Inches(0.95) + (Inches(6.0)-ww)/2
rrect(s, x, y, ww, Inches(0.85), color=col, radius=0.22)
shape = txt(s, x, y, ww, Inches(0.85),
[[(t, 15, WHITE, True)],[(d, 12, WHITE, False)]],
align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE, sa=1)
y = y + Inches(1.0)
# 右:要点卡片
pts = [
("每条线索可解释","附证据链 + 判定理由,拒绝黑盒打分。", CYAN),
("反馈学习闭环","审计员标注误报/属实,系统持续校准阈值,准确率随使用上升。", BLUE),
("公开运营指标","命中率、准确率、线索转化率上看板,成效可量化可追溯。", GOLD),
]
x = Inches(7.4); yy = Inches(2.35)
for t,d,col in pts:
rrect(s, x, yy, Inches(5.1), Inches(0.85), color=CARD, radius=0.1)
rect(s, x, yy, Inches(0.1), Inches(0.85), color=col)
txt(s, x+Inches(0.3), yy+Inches(0.1), Inches(4.7), Inches(0.32),
[[(t, 13.5, CYAN, True)]], sa=0)
txt(s, x+Inches(0.3), yy+Inches(0.42), Inches(4.7), Inches(0.4),
[[(d, 11.5, LIGHT, False)]], sa=0, line_spacing=1.05)
yy = yy + Inches(1.0)
ny = Inches(6.05)
rrect(s, Inches(0.95), ny, Inches(11.55), Inches(0.7), color=CARD2, radius=0.18)
rect(s, Inches(0.95), ny, Inches(0.1), Inches(0.7), color=GOLD)
txt(s, Inches(1.25), ny, Inches(11.1), Inches(0.7),
[[("", 13, GOLD, True),
("主动交代精准度反而显专业——藏着不说,才是最大的风险。", 13, WHITE, True)]],
anchor=MSO_ANCHOR.MIDDLE, sa=0)
fp_control()
# ============== 17 平台架构(分层)==============
def architecture():
s = new("架构 · 全栈", "本地私有化 LLM 审计平台架构", 17)
layers = [
("应用层","自然语言查询 · 线索看板 · 智能报告 · 预警推送 —— 审计人员零门槛使用", CYAN),
("引擎层","全量穿透引擎 + 规则进化引擎 + 线索生成引擎 —— LLM 驱动三大引擎", BLUE),
("数据层","本地数据湖(BSS/OSS/ERP/财务/合同/工单/信令)—— 直连内网,零出域", PURPLE),
("模型层","千问 70B / DeepSeek / 自研行业模型 —— 审计领域微调,懂电信业务", GOLD),
("算力层","本地 A100 / H100 / 国产 GPU 集群 —— 承载 70B 级推理,信创可适配", GREEN),
]
y = Inches(1.8); h = Inches(0.82); lw = Inches(9.9)
for i,(t,d,col) in enumerate(layers):
rrect(s, Inches(0.95), y, lw, h, color=CARD, radius=0.06)
rrect(s, Inches(0.95), y, Inches(1.7), h, color=col, radius=0.06)
txt(s, Inches(0.95), y, Inches(1.7), h, [[(t, 15, WHITE, True)]],
align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE, sa=0)
txt(s, Inches(2.85), y, lw-Inches(2.0), h, [[(d, 12.5, LIGHT, False)]],
anchor=MSO_ANCHOR.MIDDLE, sa=0)
y = y + h + Inches(0.12)
# 右侧贯穿条:安全合规与自审计
rrect(s, Inches(11.05), Inches(1.8), Inches(1.45), h*5+Inches(0.48), grad=(CYAN_D, BLUE), radius=0.08)
txt(s, Inches(11.05), Inches(1.8), Inches(1.45), h*5+Inches(0.48),
[[("", 17, WHITE, True)],[("", 17, WHITE, True)],[("", 17, WHITE, True)],
[("", 17, WHITE, True)],[("·", 14, WHITE, True)],[("", 17, WHITE, True)],
[("", 17, WHITE, True)],[("", 17, WHITE, True)]],
align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE, sa=1)
ny = Inches(6.6)
txt(s, Inches(0.95), ny, Inches(11.55), Inches(0.4),
[[("全链路内网闭环 · 数据零出域 · 权限分级 · 不可篡改日志 · 版本留痕", 13.5, CYAN, True)]],
align=PP_ALIGN.CENTER, sa=0)
architecture()
# ============== 18 独立性与自审计 ==============
def independence():
s = new("制度 · 独立性", "独立性与系统自审计:系统本身也经得起审计", 18)
items = [
("防放水","规则配置、阈值调整全程留痕,任何改动可追溯,杜绝调教规则放水。", CYAN),
("防拦截","线索一旦生成即不可删除,处置过程全程记录,杜绝线索被拦下。", BLUE),
("权限分级","配规则、看线索、改阈值、出报告分权管理,相互制衡。", PURPLE),
("三重留痕","模型版本、规则版本、数据版本可回溯,任一结论可还原当时状态。", GOLD),
]
W, H = Inches(5.7), Inches(1.95)
gx,gy = Inches(0.95), Inches(1.9)
for i,(t,d,col) in enumerate(items):
r,c = divmod(i,2)
x = gx + c*(W+Inches(0.18)); y = gy + r*(H+Inches(0.22))
rrect(s, x, y, W, H, color=CARD, radius=0.08)
circle(s, x+Inches(0.3), y+Inches(0.32), Inches(0.7), grad=(col, BG2))
txt(s, x+Inches(0.3), y+Inches(0.32), Inches(0.7), Inches(0.7),
[[("🔒" if False else "", 18, WHITE, True)]], align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE, sa=0)
txt(s, x+Inches(1.2), y+Inches(0.3), W-Inches(1.4), Inches(0.5),
[[(t, 17, col, True)]], sa=0)
txt(s, x+Inches(1.2), y+Inches(0.85), W-Inches(1.45), Inches(1.0),
[[(d, 12.5, LIGHT, False)]], sa=0, line_spacing=1.15)
txt(s, Inches(0.95), Inches(6.4), Inches(11.55), Inches(0.4),
[[("既当运动员又当裁判是内审大忌——用制度化留痕与分权,让系统自己也透明可查。", 13, CYAN, True)]],
align=PP_ALIGN.CENTER, sa=0)
independence()
# ============== 19 四重跃升 ==============
table_slide(19, "价值 · 跃升", "本地 LLM 带来的四重跃升",
["关键跃升", "从 → 到", "价值内涵"],
[
["审计覆盖面", "5% → 100%", "全量扫描,异常无处藏身"],
["数据出域风险", "存在 → 归零", "全链路内网闭环,满足等保最严要求"],
["审计节奏", "年度快照 → 7×24 常态化", "动态舞弊实时捕捉"],
["能力归属", "外部租用 → 本地永久沉淀", "规则进化,越用越聪明"],
],
note="安全 · 能力 · 效率 · 进化——四重价值,远超传统 BI 工具。",
col_widths=[2.8, 4.2, 4.55], fs=13, hfs=13.5)
# ============== 20 ROI ==============
table_slide(20, "测算 · 回报", "价值测算:把“异常”变成客户的钱",
["价值来源", "测算逻辑", "年化收益(保守)"],
[
["可挽回收入/止损", "全量覆盖挖出抽样漏掉的异常并整改", "数千万级"],
["外部咨询费节省", "常态化自有能力替代重复性项目采购", "百万级 / 年"],
["人力释放", "审计员从翻表取数转向研判处置", "数倍效率提升"],
["风险事件预防", "提前发现合规风险,规避处罚与声誉损失", "难以估量"],
],
note="投入一次本地化建设,沉淀的是持续产生收益的永久资产,而非每年重复支出的项目费用。",
col_widths=[2.9, 5.85, 2.8], fs=13, hfs=13.5)
# ============== 21 差异化 ==============
def differentiation():
s = new("差异化 · 主张", "我们的差异化:能力沉淀,而非一次性交付", 21)
pairs = [
("能力沉淀","项目制交付","项目制是租大脑、人走经验走;我们是装一个永久、越用越聪明的本地大脑。", CYAN),
("常态化","年度快照","舞弊是动态的,时序类造假正是本地 LLM + 全量数据的主场。", BLUE),
("数据不出域","数据出域","一比特不出机房是结构性优势,让安全合规部门站在我们这边。", PURPLE),
("共存切入","正面替代","先做以前做不动的全量穿透与常态化监控层,跑出线索、证明价值、自然扩展。", GOLD),
]
y = Inches(1.85); h = Inches(1.12)
for i,(a,b,d,col) in enumerate(pairs):
rrect(s, Inches(0.95), y, Inches(11.55), h, color=CARD if i%2 else CARD2, radius=0.07)
rrect(s, Inches(1.15), y+Inches(0.28), Inches(2.4), Inches(0.56), color=col, radius=0.3)
txt(s, Inches(1.15), y+Inches(0.28), Inches(2.4), Inches(0.56),
[[(a, 14, WHITE, True)]], align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE, sa=0)
txt(s, Inches(3.65), y, Inches(0.7), h, [[("vs", 14, MUTE, True)]],
align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE, sa=0)
rrect(s, Inches(4.35), y+Inches(0.28), Inches(2.2), Inches(0.56), color=BG2, line=MUTE, lw=1, radius=0.3)
txt(s, Inches(4.35), y+Inches(0.28), Inches(2.2), Inches(0.56),
[[(b, 13, MUTE, True)]], align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE, sa=0)
txt(s, Inches(6.75), y, Inches(5.6), h, [[(d, 12.5, LIGHT, False)]],
anchor=MSO_ANCHOR.MIDDLE, sa=0, line_spacing=1.12)
y = y + h + Inches(0.13)
differentiation()
# ============== 22 实施路径(时间轴)==============
def roadmap():
s = new("实施 · 路径", "3 个月本地部署跑通(含同台盲测验证)", 22)
phases = [
("第 1 个月","算力 + 模型部署","GPU 到位;模型本地化部署;对接各业务系统;构建本地数据湖。", CYAN),
("第 2 个月","场景微调 + 历史盲测","行业微调与场景适配;用历史数据全量重跑,与既有审计结论同台盲测。", BLUE),
("第 3 个月","投产 + 线索闭环","正式上线;生成首批 200-500 条线索;核查反馈;规则库首轮进化。", GOLD),
]
# 时间轴
rect(s, Inches(1.2), Inches(2.55), Inches(11.0), Pt(3), color=CARD2)
W = Inches(3.7); gx = Inches(0.95)
for i,(ph,t,d,col) in enumerate(phases):
x = gx + i*(W+Inches(0.22))
cx = x + W/2
circle(s, cx-Inches(0.18), Inches(2.4), Inches(0.36), color=col)
rrect(s, x, Inches(2.95), W, Inches(2.4), color=CARD, radius=0.07)
rect(s, x, Inches(2.95), W, Inches(0.6), color=col)
txt(s, x, Inches(2.95), W, Inches(0.6), [[(ph, 16, WHITE, True)]],
align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE, sa=0)
txt(s, x+Inches(0.25), Inches(3.7), W-Inches(0.5), Inches(0.5),
[[(t, 14.5, col, True)]], sa=0)
txt(s, x+Inches(0.25), Inches(4.2), W-Inches(0.5), Inches(1.1),
[[(d, 12.5, LIGHT, False)]], sa=0, line_spacing=1.18)
ny = Inches(5.7)
rrect(s, Inches(0.95), ny, Inches(11.55), Inches(0.95), color=CARD2, radius=0.1)
rect(s, Inches(0.95), ny, Inches(0.1), Inches(0.95), color=GOLD)
txt(s, Inches(1.25), ny, Inches(11.1), Inches(0.95),
[[("交付物", 14, GOLD, True)],
[("本地 AI 审计平台 + 可进化规则库 + 已验证高价值线索 + 同台盲测成效报告。", 13, WHITE, False)]],
anchor=MSO_ANCHOR.MIDDLE, sa=3)
roadmap()
# ============== 23 结尾 ==============
def closing():
s = prs.slides.add_slide(BLANK)
bg_gradient(s, RGBColor(0x07,0x10,0x24), RGBColor(0x10,0x29,0x52))
circle(s, Inches(-1.5), Inches(4.5), Inches(4.5), color=RGBColor(0x10,0x24,0x48))
circle(s, Inches(10.5), Inches(-1.5), Inches(4.5), color=RGBColor(0x10,0x24,0x48))
rect(s, 0, 0, SW, Inches(0.18), grad=(CYAN, BLUE))
rect(s, 0, Inches(7.32), SW, Inches(0.18), grad=(BLUE, CYAN))
txt(s, Inches(1.0), Inches(2.0), Inches(11.3), Inches(1.2),
[[("数据不动 · AI 动脑 · 造假者跑不掉", 40, WHITE, True)]], align=PP_ALIGN.CENTER, sa=0)
rect(s, Inches(5.4), Inches(3.25), Inches(2.5), Pt(3), color=CYAN)
txt(s, Inches(1.0), Inches(3.5), Inches(11.3), Inches(0.7),
[[("本地大模型 + 全量穿透 + 规则进化 = 运营商内审的“新质生产力”", 19, CYAN, True)]],
align=PP_ALIGN.CENTER, sa=0)
txt(s, Inches(1.0), Inches(4.5), Inches(11.3), Inches(1.2),
[[("让我们把千问 70B 装进您的机房", 17, LIGHT, False)],
[("150 亿业务全量扫描,敏感数据一比特不出域", 17, LIGHT, False)]],
align=PP_ALIGN.CENTER, sa=8)
txt(s, Inches(1.0), Inches(6.3), Inches(11.3), Inches(0.5),
[[("2026 年 6 月", 13, MUTE, False)]], align=PP_ALIGN.CENTER, sa=0)
closing()
out = "数据不出域,审计全穿透_精美版.pptx"
prs.save(out)
print("saved:", out, "slides:", len(prs.slides._sldIdLst))