Files
group_xinghuo_jinrong/scripts/dev/build_defense_ppt.py
T

242 lines
9.5 KiB
Python
Raw Normal View History

"""Generate defense deck from docs/答辩/答辩知识点清单.md structure."""
from __future__ import annotations
from pathlib import Path
from pptx import Presentation
from pptx.dml.color import RGBColor
from pptx.enum.text import MSO_ANCHOR, PP_ALIGN
from pptx.util import Inches, Pt
ROOT = Path(__file__).resolve().parents[2]
OUT = ROOT / "docs" / "答辩" / "JinRong-答辩.pptx"
INK = RGBColor(0x13, 0x2B, 0x3A)
TEXT = RGBColor(0x17, 0x21, 0x2B)
MUTED = RGBColor(0x71, 0x80, 0x8A)
GOLD = RGBColor(0xC9, 0xA6, 0x6B)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
BG_LIGHT = RGBColor(0xF6, 0xF5, 0xF1)
def _set_slide_bg(slide, rgb: RGBColor) -> None:
fill = slide.background.fill
fill.solid()
fill.fore_color.rgb = rgb
def _add_title_slide(prs: Presentation, title: str, subtitle: str, notes: str) -> None:
slide = prs.slides.add_slide(prs.slide_layouts[6])
_set_slide_bg(slide, INK)
box = slide.shapes.add_textbox(Inches(0.7), Inches(2.0), Inches(11.5), Inches(1.2))
tf = box.text_frame
tf.text = title
p = tf.paragraphs[0]
p.font.size = Pt(40)
p.font.bold = True
p.font.color.rgb = WHITE
sub = slide.shapes.add_textbox(Inches(0.7), Inches(3.3), Inches(11.5), Inches(1.0))
stf = sub.text_frame
stf.text = subtitle
sp = stf.paragraphs[0]
sp.font.size = Pt(20)
sp.font.color.rgb = GOLD
slide.notes_slide.notes_text_frame.text = notes
def _add_section_slide(prs: Presentation, title: str, bullets: list[str], notes: str) -> None:
slide = prs.slides.add_slide(prs.slide_layouts[6])
_set_slide_bg(slide, BG_LIGHT)
bar = slide.shapes.add_shape(1, Inches(0), Inches(0), Inches(13.33), Inches(0.12))
bar.fill.solid()
bar.fill.fore_color.rgb = GOLD
bar.line.fill.background()
tbox = slide.shapes.add_textbox(Inches(0.7), Inches(0.45), Inches(12), Inches(0.8))
ttf = tbox.text_frame
ttf.text = title
tp = ttf.paragraphs[0]
tp.font.size = Pt(32)
tp.font.bold = True
tp.font.color.rgb = INK
body = slide.shapes.add_textbox(Inches(0.85), Inches(1.35), Inches(11.8), Inches(5.5))
btf = body.text_frame
btf.word_wrap = True
btf.vertical_anchor = MSO_ANCHOR.TOP
for i, line in enumerate(bullets):
p = btf.paragraphs[0] if i == 0 else btf.add_paragraph()
p.text = line
p.level = 0
p.font.size = Pt(18 if len(line) < 80 else 16)
p.font.color.rgb = TEXT
p.space_after = Pt(10)
slide.notes_slide.notes_text_frame.text = notes
def main() -> None:
prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)
slides: list[tuple[str, list[str], str, bool]] = [
(
"金融四 Agent 智能代销平台",
[],
"",
True,
),
]
# Title handled separately
_add_title_slide(
prs,
"金融四 Agent 智能代销平台",
"答辩演示 · XX 科技综合财富 · merger 基线",
"开场:代销四角色 + L0 与合规底座;Core 为模拟库;四 Agent 不互调 LLM。",
)
deck: list[tuple[str, list[str], str]] = [
(
"我们要做什么(网站三句话)",
[
"用于:持牌财富代销场景下的 AI 工作台(Web + FastAPI),不是营销落地页",
"业务:XX 科技综合财富平台 · 前端视觉「静奢智能」",
"用户:客户看资产与对话 · 分析员问数 · 风控处置 · 理财师看归属(顾问 Agent 未完整接入)",
],
"对应用户模板:用途 / 业务名 / 用户能做什么。",
),
(
"总架构(30 秒)",
[
"四角色共用 L0 事实 + 合规底座;跨线靠画像表、预警表、代销 REST",
"分层:浏览器 → FastAPI → Service → Tool/Repository → MySQL 双库 / Redis / Milvus / Core",
"对话:通用 Chat/SSE · 客服 14 节点 · 问数独立(interpret 按需解读)",
"铁律:L0 不可覆盖 · 仅 R-02 可阻断交易 · 不自动冻户 · 审计只 INSERT",
],
"MEMORY §0 + 答辩清单 §一。",
),
(
"数据怎么流",
[
"L0 Core 模拟:Agent 只读;仅模拟交易网关 INSERT core_trade",
"jinrong_agent 与 jinrong_core 物理隔离",
"Redis 6380:会话窗口、限流、问数缓存世代;MySQL 永久落盘",
"Milvus:产品规则 RAG(Ollama bge-m3 1024 维,不出内网)",
],
"§二 数据分层表口述。",
),
(
"共用底座 Wave 0",
[
"JWT + RBAC + X-Agent-Type 准入 · dev token 与 gateway 双栈(AL-09)",
"输入防护:限流 / 注入 / 超长 · 被拒 fail-fast 不建会话",
"审计:trace_id 贯通 http_access + audit_log + agent_tool_call",
"Tool:customer_id 会话注入,LLM 不能指定 · 归属校验 + 落库",
],
"F-01~F-04 演示工程化。",
),
(
"客服 Agent(主 Demo 之一)",
[
"14 节点 LangGraph:Core Tool + fin_* RAG + 1B sanitize 出口",
"C-04/C-05:阈值提醒、净值查询 · C-11 适当性 vs 营销 reject",
"Demo:CUST-9527 持仓 + 阈值 · 游客 RAG",
"SSE:Tool 同步完成后再推文本,避免半句不一致",
],
"步骤 1 客户助手 + 持仓页。",
),
(
"数据分析 Agent(主 Demo 之二)",
[
"问数与 Chat 分离:默认 interpret=false 出表 · 按钮触发 /interpret",
"五层 sql_guard + 模板命中 Tag + 结果缓存世代(D-06)",
"D-10:解读数字与表逐字比对,失败降级只出表",
"Demo:分析员问数 → 模板/缓存 Tag → 解读按钮",
],
"DEMO-SOP-问数.md。",
),
(
"风控 Agent(主 Demo 之三)",
[
"事件线:模拟交易 → R-02 适当性 → 规则 R-01~R-05 → 聚合预警 → 人工处置",
"对话线:6 只只读 Tool,无处置 Tool(状态不变)",
"前端:预警台账 / 适当性 / AML / 模拟交易 + 风控 Chat",
"Demo:prepare_all.ps1 · A-1/A-3 · 台账筛选处置",
],
"演示SOP-风控模块.md。",
),
(
"代销平台 API + 前端 web/",
[
"v0.1 canonical REST:客户/产品/顾问/合规 · 重复能力以平台 API 为准",
"React 19 + Vite + Ant Design · HashRouter · /api 代理 8000",
"四角色 Dashboard + 产品行情(nav/history 图表)",
"DevReadyBanner:前后端版本不一致先告警",
],
"FRONTEND-HANDOFF + 登录四 Demo 账号。",
),
(
"诚实边界(答辩加分)",
[
"理财师 Agent:无 advisor_service 级编排 · A-01~A-05 未做 · 勿作主 Demo",
"问数:D-09 多轮 / D-12 钻取仍 open",
"看板:无钻取 · 进页全量拉平台 API",
"测试:827 pytest · 22 Vitest(口播基线以当日 pytest 为准)",
],
"§4.2 §4.3 §4.6 诚实缺口。",
),
(
"技术选型(为什么这样)",
[
"LangGraph 显式图 · MySQL 双库隔离 · Milvus Lite 本机 RAG",
"DeepSeek 生成 · 无 Key 明确降级 · Redis RESP2 @6380",
"FastAPI 一体栈 · React+AntD 四角色 Demo 快",
"不用 Streamlit · 不用 Agent 互调 LLM",
],
"§五 选型表。",
),
(
"工程化亮点",
[
"契约优先:代销 API v0.1 · AL-09 合并接缝",
"双护栏:输入防护 + 客服 sanitize + 问数 guardrail",
"RAG 溯源 source_refs · 问数 battery 本地跑分不入库",
"docs/memory + docs/course 交互课 + 本套 SOP",
],
"§六 加分项。",
),
(
"Demo 动线(12~15 分钟标准)",
[
"0 开场 30 秒铁律 + 架构句",
"1 客户:登录 → 持仓/阈值 → 客户助手",
"2 分析员:问数 → Tag → 解读",
"3 风控:模拟交易 → 台账 → 处置",
"4 可选:行情页 · /api/ready 探针",
],
"DEMO-SOP-答辩全流程.md 路线 B。",
),
(
"谢谢 · Q&A",
[
"配套文档:docs/答辩/答辩知识点清单.md",
"Demo:docs/答辩/DEMO-SOP-答辩全流程.md",
"交互课:docs/course/jinrong-overview/index.html",
"仓库:JinRong · 分支 merger",
],
"预留 Q&A:适当性、审计、问数 guard、顾问线规划。",
),
]
for title, bullets, notes in deck:
_add_section_slide(prs, title, bullets, notes)
OUT.parent.mkdir(parents=True, exist_ok=True)
prs.save(str(OUT))
print(f"Wrote {OUT} ({len(prs.slides)} slides)")
if __name__ == "__main__":
main()