- Introduced `convert_meta_api` endpoint to fetch the latest NAV date for conversion processes, restricted to users with the "risk_officer" role. - Updated `created_at` field in `AgentMessage` to use UTC timezone for consistency in timestamp handling. - Added `get_max_product_nav_date` method in `CoreReadOnlyRepository` to support the new API functionality. - Enhanced Milvus template loading in `MilvusTemplateVectorStore` to ensure collections are loaded when they exist. This update improves the API's capability to handle conversion metadata and ensures accurate timestamp management across the application.
242 lines
9.5 KiB
Python
242 lines
9.5 KiB
Python
"""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()
|