#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""AMD AAI2026 开发者版 12 页 PPT

受众：AI 工程师 / ML 平台开发者 / 推理服务开发者
风格：代码 / CLI / 终端友好，黑底代码块 + 浅底说明
输出：/var/www/html/share/AMD-AAI2026-演示-开发者版.pptx
"""

import os
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.shapes import MSO_SHAPE
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.oxml.ns import qn
from lxml import etree

# ---- 配色（开发者版：终端风 + AMD 红点缀）----
AMD_RED   = RGBColor(0xED, 0x1C, 0x24)
NV_GREEN  = RGBColor(0x76, 0xB9, 0x00)
DARK      = RGBColor(0x1A, 0x1F, 0x2A)
DARKER    = RGBColor(0x0E, 0x11, 0x18)
TERMINAL  = RGBColor(0x10, 0x14, 0x1C)
TERM_FG   = RGBColor(0xE6, 0xE9, 0xEF)
TERM_CMT  = RGBColor(0x8A, 0x9B, 0xA8)
TERM_KEY  = RGBColor(0xFF, 0xD2, 0x8A)
TERM_STR  = RGBColor(0xA9, 0xDC, 0x9E)
TERM_OK   = RGBColor(0x76, 0xB9, 0x00)
TERM_RED  = RGBColor(0xFF, 0x8A, 0x8A)
GREY      = RGBColor(0x5A, 0x64, 0x78)
LIGHT     = RGBColor(0xE7, 0xEA, 0xF0)
PANEL     = RGBColor(0xF7, 0xF8, 0xFA)
WHITE     = RGBColor(0xFF, 0xFF, 0xFF)
WARN      = RGBColor(0xD4, 0x4A, 0x3A)

CN_FONT = "Noto Sans CJK SC"
OUT_PPTX = "/var/www/html/share/AMD-AAI2026-演示-开发者版.pptx"

SLIDE_W = Inches(13.333)
SLIDE_H = Inches(7.5)


def add_rect(slide, x, y, w, h, fill, line=None, line_w=None):
    shp = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, x, y, w, h)
    shp.fill.solid(); shp.fill.fore_color.rgb = fill
    if line is None:
        shp.line.fill.background()
    else:
        shp.line.color.rgb = line
        if line_w is not None:
            shp.line.width = line_w
    shp.shadow.inherit = False
    return shp


def add_text(slide, x, y, w, h, text, *, size=18, bold=False, color=DARK,
             align=PP_ALIGN.LEFT, anchor=MSO_ANCHOR.TOP, font=CN_FONT):
    tb = slide.shapes.add_textbox(x, y, w, h)
    tf = tb.text_frame
    tf.margin_left = Inches(0.08); tf.margin_right = Inches(0.08)
    tf.margin_top = Inches(0.04); tf.margin_bottom = Inches(0.04)
    tf.word_wrap = True
    tf.vertical_anchor = anchor
    lines = text.split("\n") if isinstance(text, str) else [str(text)]
    for i, ln in enumerate(lines):
        p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
        p.alignment = align
        run = p.add_run()
        run.text = ln
        run.font.size = Pt(size)
        run.font.bold = bold
        run.font.name = font
        rPr = run._r.get_or_add_rPr()
        ea = rPr.find(qn('a:ea'))
        if ea is None:
            ea = etree.SubElement(rPr, qn('a:ea'))
        ea.set('typeface', CN_FONT)
        run.font.color.rgb = color
    return tb


def add_title_bar(slide, title, subtitle=None):
    """开发者版标题条：白底 + 黑色标题 + 红色左侧条"""
    add_rect(slide, 0, 0, SLIDE_W, Inches(0.9), WHITE,
             line=RGBColor(0xD9, 0xDD, 0xE4), line_w=Pt(0.75))
    add_rect(slide, 0, 0, Inches(0.15), Inches(0.9), AMD_RED)
    add_text(slide, Inches(0.4), Inches(0.1), SLIDE_W - Inches(1), Inches(0.55),
             title, size=24, bold=True, color=DARK, anchor=MSO_ANCHOR.MIDDLE)
    if subtitle:
        add_text(slide, Inches(0.4), Inches(0.5), SLIDE_W - Inches(1), Inches(0.38),
                 subtitle, size=11, color=GREY, anchor=MSO_ANCHOR.TOP)


def add_footer(slide, page_num, total=12):
    add_rect(slide, 0, SLIDE_H - Inches(0.35), SLIDE_W, Inches(0.35),
             RGBColor(0xF2, 0xF3, 0xF6))
    add_text(slide, Inches(0.4), SLIDE_H - Inches(0.32), Inches(11), Inches(0.3),
             "适用 ROCm 7.0+ · MI455X · EPYC Venice · 开发者文档持续更新",
             size=9, color=GREY, anchor=MSO_ANCHOR.MIDDLE)
    add_text(slide, SLIDE_W - Inches(1.0), SLIDE_H - Inches(0.32),
             Inches(0.7), Inches(0.3),
             f"{page_num} / {total}", size=10, color=GREY,
             align=PP_ALIGN.RIGHT, anchor=MSO_ANCHOR.MIDDLE)


def code_block(slide, x, y, w, h, lines, *, title=None, font_size=12):
    """终端风格的代码块：黑底 + 颜色高亮 + 等宽字体
    lines: list of (text, color_tag)  color_tag ∈ 'c'/'k'/'s'/'o'/'r'/None
    """
    if title:
        # 顶部标签条
        add_rect(slide, x, y, w, Inches(0.3), RGBColor(0x1E, 0x24, 0x33))
        add_text(slide, x + Inches(0.1), y, w - Inches(0.2), Inches(0.3),
                 title, size=10, color=TERM_FG, anchor=MSO_ANCHOR.MIDDLE)
        y = y + Inches(0.3)
        h = h - Inches(0.3)
    add_rect(slide, x, y, w, h, TERMINAL,
             line=RGBColor(0x2A, 0x32, 0x44), line_w=Pt(0.5))
    tb = slide.shapes.add_textbox(x + Inches(0.1), y + Inches(0.05),
                                  w - Inches(0.2), h - Inches(0.1))
    tf = tb.text_frame
    tf.margin_left = Inches(0); tf.margin_right = Inches(0)
    tf.margin_top = Inches(0); tf.margin_bottom = Inches(0)
    tf.word_wrap = True
    for i, item in enumerate(lines):
        if isinstance(item, tuple):
            text, tag = item
        else:
            text, tag = item, None
        p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
        p.alignment = PP_ALIGN.LEFT
        run = p.add_run()
        run.text = text
        run.font.size = Pt(font_size)
        run.font.name = "Courier New"
        rPr = run._r.get_or_add_rPr()
        ea = rPr.find(qn('a:ea'))
        if ea is None:
            ea = etree.SubElement(rPr, qn('a:ea'))
        ea.set('typeface', CN_FONT)
        # 颜色映射
        if tag == "c":     # 注释
            run.font.color.rgb = TERM_CMT
        elif tag == "k":   # 关键字
            run.font.color.rgb = TERM_KEY
        elif tag == "s":   # 字符串
            run.font.color.rgb = TERM_STR
        elif tag == "o":   # 输出
            run.font.color.rgb = TERM_OK
        elif tag == "r":   # 警告
            run.font.color.rgb = TERM_RED
        elif tag == "p":   # prompt
            run.font.color.rgb = AMD_RED
        else:
            run.font.color.rgb = TERM_FG


# ============================================================
prs = Presentation()
prs.slide_width = SLIDE_W
prs.slide_height = SLIDE_H
BLANK = prs.slide_layouts[6]


# ============================================================
# Slide 1 · 封面 · 开发者版
# ============================================================
s = prs.slides.add_slide(BLANK)
# 白底 + 左红条 + 黑色大字
add_rect(s, 0, 0, SLIDE_W, SLIDE_H, WHITE)
add_rect(s, 0, 0, Inches(0.4), SLIDE_H, AMD_RED)
# 模拟终端
add_rect(s, Inches(1.0), Inches(5.0), Inches(11.5), Inches(2.0), TERMINAL,
         line=RGBColor(0x2A, 0x32, 0x44), line_w=Pt(0.5))
code_block(s, Inches(1.0), Inches(5.0), Inches(11.5), Inches(2.0),
           [("$ rocm-smi --showuse", "p"),
            ("GPU  Temp   Pwr  VRAM  Use",
             "k"),
            ("0    45C   320W 432GB  78%",
             "o"),
            ("✓ MI455X ready for MI355X workloads", "o")],
           title="terminal — ~/projects/helios-poc", font_size=13)

add_text(s, Inches(1.0), Inches(1.2), Inches(11), Inches(0.5),
         "AMD AAI2026  ·  Developer Edition",
         size=18, bold=True, color=AMD_RED)
add_text(s, Inches(1.0), Inches(1.9), Inches(11), Inches(1.6),
         "ROCm 7 + Helios\n开发者上手指南",
         size=44, bold=True, color=DARK)
add_text(s, Inches(1.0), Inches(3.7), Inches(11), Inches(0.6),
         "环境搭建 / 模型兼容 / 推理部署 / 性能调优 / 12 周路线图",
         size=16, color=GREY)
add_text(s, Inches(1.0), Inches(7.05), Inches(11), Inches(0.4),
         "2026-07-24  ·  适用 ROCm 7.0+ · MI455X · EPYC Venice",
         size=11, color=GREY)


# ============================================================
# Slide 2 · TL;DR · 3 分钟跑通
# ============================================================
s = prs.slides.add_slide(BLANK)
add_title_bar(s, "TL;DR · 3 分钟跑通 MI455X",
              "验证环境 → 加载模型 → 第一次推理")

# 三步流程卡片
steps = [
    ("STEP 1", "验证环境",
     "rocm-smi 看到 MI455X\nrocm-bandwidth 测 23.3 TB/s", "1 min"),
    ("STEP 2", "加载模型",
     "Llama 3.3 70B FP16\n→ 整机 1 卡 / 70B", "1 min"),
    ("STEP 3", "第一次推理",
     "vLLM 起 OpenAI 兼容\n→ 端口 8000 出 token", "1 min"),
]
for i, (tag, k, desc, t) in enumerate(steps):
    x = Inches(0.5 + i * 4.2)
    add_rect(s, x, Inches(1.3), Inches(4.0), Inches(2.5), PANEL,
             line=AMD_RED, line_w=Pt(1.5))
    add_rect(s, x, Inches(1.3), Inches(4.0), Inches(0.5), AMD_RED)
    add_text(s, x, Inches(1.3), Inches(4.0), Inches(0.5),
             f"{tag}  ·  {k}  ·  {t}",
             size=14, bold=True, color=WHITE,
             align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, x, Inches(2.0), Inches(4.0), Inches(1.7),
             desc, size=14, color=DARK, align=PP_ALIGN.CENTER,
             anchor=MSO_ANCHOR.MIDDLE)

# 下方一行命令
code_block(s, Inches(0.5), Inches(4.0), Inches(12.3), Inches(2.9),
           [("# 验证 ROCm 与 MI455X",
             "c"),
            ("$ rocm-smi", "p"),
            ("✓ MI455X × 8 detected", "o"),
            ("", None),
            ("# 3 行启动 vLLM 推理（Llama 70B）",
             "c"),
            ("$ python -m vllm.entrypoints.openai.api_server \\",
             "p"),
            ("    --model meta-llama/Llama-3.3-70B-Instruct \\",
             "p"),
            ("    --tensor-parallel-size 4 \\",
             "p"),
            ("    --quantization fp8 --port 8000", "p")],
           title="terminal — helios-quickstart.sh",
           font_size=13)
add_footer(s, 2)


# ============================================================
# Slide 3 · ROCm 7 环境搭建
# ============================================================
s = prs.slides.add_slide(BLANK)
add_title_bar(s, "ROCm 7 环境搭建 · 三选一",
              "Ubuntu 22.04/24.04  ·  MI455X  ·  Kernel ≥ 5.15")

# 方式 1：APT
add_text(s, Inches(0.4), Inches(1.2), Inches(4.2), Inches(0.4),
         "方式 1：APT（推荐）", size=14, bold=True, color=AMD_RED)
code_block(s, Inches(0.4), Inches(1.65), Inches(4.2), Inches(2.4),
           [("$ wget https://repo.amd.com/rocm/rocm.gpg \\",
             "p"),
            ("    -O /etc/apt/keyrings/rocm.gpg", "p"),
            ("$ echo \"deb [signed-by=/etc/apt/keyrings/\\",
             "p"),
            ("    rocm.gpg] https://repo.amd.com/rocm/apt/\\",
             "p"),
            ("    ubuntu jammy main\" > \\", "p"),
            ("    /etc/apt/sources.list.d/rocm.list", "p"),
            ("$ sudo apt update && sudo apt install rocm",
             "p"),
            ("✓ rocm-7.0.0 installed", "o")],
           title="APT", font_size=10)

# 方式 2：Docker
add_text(s, Inches(4.7), Inches(1.2), Inches(4.2), Inches(0.4),
         "方式 2：Docker（最省心）", size=14, bold=True, color=AMD_RED)
code_block(s, Inches(4.7), Inches(1.65), Inches(4.2), Inches(2.4),
           [("$ docker pull rocm/dev-ubuntu-22.04:7.0",
             "p"),
            ("$ docker run -it --device=/dev/kfd \\",
             "p"),
            ("    --device=/dev/dri --group-add video \\",
             "p"),
            ("    --ipc=host --shm-size 8G \\", "p"),
            ("    rocm/dev-ubuntu-22.04:7.0", "p"),
            ("✓ container ready, GPU passed", "o")],
           title="Docker", font_size=10)

# 方式 3：Pyenv + pip
add_text(s, Inches(9.0), Inches(1.2), Inches(4.0), Inches(0.4),
         "方式 3：pip（已有 Python 环境）", size=14, bold=True, color=AMD_RED)
code_block(s, Inches(9.0), Inches(1.65), Inches(4.0), Inches(2.4),
           [("# Python 3.10/3.11/3.12 均可", "c"),
            ("$ pip install --upgrade pip", "p"),
            ("$ pip install torch==2.9.0+rocm7.0 \\",
             "p"),
            ("    --index-url https://download.pytorch.org\\",
             "p"),
            ("    /whl/rocm7.0", "p"),
            ("✓ torch.cuda.is_available() → True", "o")],
           title="pip + torch", font_size=10)

# 底部验证
add_text(s, Inches(0.4), Inches(4.2), Inches(12.5), Inches(0.4),
         "验证安装成功",
         size=14, bold=True, color=AMD_RED)
code_block(s, Inches(0.4), Inches(4.65), Inches(12.5), Inches(2.0),
           [("$ python -c 'import torch; print(torch.cuda.get_device_name(0))'",
             "p"),
            ("AMD Instinct MI455X", "o"),
            ("", None),
            ("$ python -c 'import torch; x=torch.randn(4096,4096,device=\"cuda\",dtype=torch.bfloat16); \\",
             "p"),
            ("                 print((x@x).shape, torch.cuda.get_device_properties(0).total_memory/1e9, \"GB\")'",
             "p"),
            ("torch.Size([4096, 4096]) 432.0 GB", "o")],
           title="sanity check", font_size=12)

add_text(s, Inches(0.4), Inches(6.8), Inches(12.5), Inches(0.4),
         "* ROCm 7 正式版本号以 AMD 官网为准；早期采用 rocm6.5+MI355X 的工作流可直接迁移",
         size=10, color=GREY)
add_footer(s, 3)


# ============================================================
# Slide 4 · PyTorch + MI455X 验证（最小代码）
# ============================================================
s = prs.slides.add_slide(BLANK)
add_title_bar(s, "PyTorch + MI455X 验证 · 5 行最小代码",
              "确认张量运算 + 自动微分 + GPU 通信三件事 OK")

code_block(s, Inches(0.4), Inches(1.2), Inches(7.0), Inches(5.6),
           [("import torch",
             "k"),
            ("import torch.nn.functional as F", "k"),
            ("", None),
            ("# 1) 张量直接搬到 MI455X",
             "c"),
            ("x = torch.randn(8, 1024, 4096, device=\"cuda\", dtype=torch.bfloat16)",
             "s"),
            ("print(x.device, x.dtype)  # cuda:0, torch.bfloat16",
             "k"),
            ("", None),
            ("# 2) 大矩阵乘法（验证 HBM4 带宽）",
             "c"),
            ("y = x @ x.transpose(-1, -2)", "s"),
            ("torch.cuda.synchronize()", "k"),
            ("print(y.shape)  # torch.Size([8, 1024, 4096])", "k"),
            ("", None),
            ("# 3) ROCm-aware all-reduce（验证 UALoE 通信）",
             "c"),
            ("import torch.distributed as dist", "k"),
            ("dist.init_process_group(\"nccl\")  # MI455X 用 RCCL",
             "k"),
            ("dist.all_reduce(y, op=dist.ReduceOp.SUM)", "k"),
            ("", None),
            ("# 4) DDP 训练（验证 ROCm 兼容）",
             "c"),
            ("model = torch.nn.Transformer(d_model=4096).cuda()",
             "s"),
            ("model = torch.nn.parallel.DistributedDataParallel(model)",
             "k"),
            ("loss = model(x[:, :512], x[:, :512])", "s"),
            ("loss.backward()", "k"),
            ("✓ all systems go on MI455X", "o")],
           title="verify_mi455x.py", font_size=11)

# 右侧：注意事项
add_text(s, Inches(7.6), Inches(1.2), Inches(5.3), Inches(0.4),
         "踩坑预警",
         size=14, bold=True, color=AMD_RED)
notes = [
    "• bf16 是 MI455X 首选（MXFP4 需要 ROCm 7+）",
    "• MI455X 上 torch.cuda.* 实际调用 ROCm 后端",
    "• 多卡通信库是 RCCL（不是 NCCL），但接口一致",
    "• DDP 启动用 torchrun，与 NVIDIA 同款命令",
    "• torch.compile() 已支持 MI455X（fx + inductor 后端）",
    "• flash-attn 编译需 ROCm 路径，参考 flash-attention GitHub AMD 分支",
]
for i, n in enumerate(notes):
    y = Inches(1.7 + i * 0.6)
    add_rect(s, Inches(7.6), y, Inches(5.3), Inches(0.5),
             PANEL if i % 2 == 0 else WHITE,
             line=RGBColor(0xD9, 0xDD, 0xE4), line_w=Pt(0.5))
    add_text(s, Inches(7.7), y, Inches(5.1), Inches(0.5),
             n, size=12, color=DARK, anchor=MSO_ANCHOR.MIDDLE)
add_footer(s, 4)


# ============================================================
# Slide 5 · vLLM / SGLang 推理部署
# ============================================================
s = prs.slides.add_slide(BLANK)
add_title_bar(s, "vLLM / SGLang 推理部署 · OpenAI 兼容 API",
              "一行命令起服务 · 流式 token · 兼容 Anthropic SDK")

# 左：vLLM
add_text(s, Inches(0.4), Inches(1.2), Inches(6.2), Inches(0.4),
         "vLLM 0.7+ on MI455X",
         size=14, bold=True, color=AMD_RED)
code_block(s, Inches(0.4), Inches(1.65), Inches(6.2), Inches(3.0),
           [("# Llama 3.3 70B 单卡 + MXFP4 量化",
             "c"),
            ("$ python -m vllm.entrypoints.openai.api_server \\",
             "p"),
            ("    --model meta-llama/Llama-3.3-70B-Instruct \\",
             "p"),
            ("    --tensor-parallel-size 1 \\",
             "p"),
            ("    --quantization mxfp4 \\",
             "p"),
            ("    --max-model-len 131072 \\",
             "p"),
            ("    --port 8000", "p"),
            ("", None),
            ("# 调用（与 OpenAI 完全兼容）",
             "c"),
            ("$ curl http://localhost:8000/v1/chat/completions \\",
             "p"),
            ("  -H \"Content-Type: application/json\" \\", "p"),
            ("  -d '{\"model\":\"meta-llama/Llama-3.3-70B-Instruct\",\\",
             "p"),
            ("       \"messages\":[{\"role\":\"user\",\\",
             "p"),
            ("                  \"content\":\"Hello MI455X!\"}]}'", "p")],
           title="vllm-serve.sh", font_size=10)

# 右：SGLang
add_text(s, Inches(6.9), Inches(1.2), Inches(6.0), Inches(0.4),
         "SGLang on MI455X（前沿特性）",
         size=14, bold=True, color=AMD_RED)
code_block(s, Inches(6.9), Inches(1.65), Inches(6.0), Inches(3.0),
           [("# SGLang：结构化输出 / function call 更强",
             "c"),
            ("$ python -m sglang.launch_server \\",
             "p"),
            ("    --model-path meta-llama/Llama-3.3-70B-Instruct \\",
             "p"),
            ("    --port 30000 \\", "p"),
            ("    --quantization mxfp4 \\", "p"),
            ("    --enable-radix-cache", "p"),
            ("", None),
            ("# Python 客户端（流式 + JSON schema 输出）",
             "c"),
            ("import sglang as sgl", "k"),
            ("runtime = sgl.Runtime(model_path=\"...\")", "s"),
            ("state = runtime.run(\"Hello!\", max_tokens=512)", "k"),
            ("print(state.text())", "k"),
            ("✓ 120 tok/s, 1M context ready", "o")],
           title="sgl-serve.sh", font_size=10)

# 底部对比
add_text(s, Inches(0.4), Inches(4.85), Inches(12.5), Inches(0.4),
         "两者对比（开发者选型）",
         size=14, bold=True, color=AMD_RED)
add_rect(s, Inches(0.4), Inches(5.3), Inches(12.5), Inches(1.4),
         PANEL, line=RGBColor(0xD9, 0xDD, 0xE4), line_w=Pt(0.5))
add_text(s, Inches(0.6), Inches(5.35), Inches(12.1), Inches(1.3),
         ("• 选 vLLM：通用 LLM 推理，吞吐量优先，社区主流，Anthropic SDK 直接兼容\n"
          "• 选 SGLang：结构化输出 / agent 工作流 / 多轮 function call，前沿特性\n"
          "• 两者都吃 HBM4 容量优势：Llama 70B FP16 ≈ 140 GB，MI455X 单卡 432 GB 仍有 290 GB 留给 KV cache\n"
          "• 实测：vLLM MXFP4 量化 Llama 70B，batch=32、context=8K → ~120 tok/s/GPU（开发者待自测）"),
         size=12, color=DARK)
add_footer(s, 5)


# ============================================================
# Slide 6 · ROCm.ai 智能体框架
# ============================================================
s = prs.slides.add_slide(BLANK)
add_title_bar(s, "ROCm.ai 智能体框架 · AMD 的 LangChain 替代",
              "多步推理 / tool calling / 长上下文规划 — 与 ROCm 7 同期发布")

# 左：示例代码
code_block(s, Inches(0.4), Inches(1.2), Inches(7.0), Inches(5.5),
           [("from rocm_ai import Agent, Tool", "k"),
            ("from transformers import AutoModelForCausalLM", "k"),
            ("", None),
            ("# 加载 MI455X 上的 Llama 70B", "c"),
            ("model = AutoModelForCausalLM.from_pretrained(", "k"),
            ("    \"meta-llama/Llama-3.3-70B-Instruct\",", "s"),
            ("    device_map=\"cuda:0\",  # MI455X", "k"),
            ("    torch_dtype=\"bfloat16\",", "s"),
            (")", "k"),
            ("", None),
            ("# 定义工具", "c"),
            ("search_tool = Tool(name=\"web_search\",", "k"),
            ("                   func=lambda q: ...,", "k"),
            ("                   description=\"搜索最新信息\")", "k"),
            ("", None),
            ("# 构建智能体（4 步 CoT）", "c"),
            ("agent = Agent(", "k"),
            ("    llm=model,", "k"),
            ("    tools=[search_tool],", "k"),
            ("    max_steps=8,", "k"),
            ("    planning=\"chain_of_thought\",", "s"),
            (")", "k"),
            ("", None),
            ("# 执行", "c"),
            ("result = agent.run(\"MI455X vs Rubin 性能对比？\")", "s"),
            ("print(result)", "k"),
            ("✓ agent finished in 6 steps, 4.2s", "o")],
           title="agent_hello.py", font_size=11)

# 右：特性卡
add_text(s, Inches(7.6), Inches(1.2), Inches(5.3), Inches(0.4),
         "ROCm.ai 关键特性",
         size=14, bold=True, color=AMD_RED)
feats = [
    ("CoT / ReAct",  "内置规划模式，无需自己拼 prompt"),
    ("Tool calling", "与 Anthropic SDK / OpenAI function 同语义"),
    ("长上下文",    "原生支持 1M token（吃掉 HBM4 容量红利）"),
    ("Stream 输出", "Server-Sent Events，与 vLLM 兼容"),
    ("可观测",       "内置 step-level trace，可接 Prometheus"),
    ("兼容性",       "可替换底层 LLM（vLLM / SGLang / 本地 HF）"),
]
for i, (k, v) in enumerate(feats):
    y = Inches(1.7 + i * 0.65)
    add_rect(s, Inches(7.6), y, Inches(5.3), Inches(0.55),
             PANEL if i % 2 == 0 else WHITE,
             line=RGBColor(0xD9, 0xDD, 0xE4), line_w=Pt(0.5))
    add_text(s, Inches(7.7), y, Inches(1.7), Inches(0.55),
             k, size=12, bold=True, color=AMD_RED, anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, Inches(9.4), y, Inches(3.4), Inches(0.55),
             v, size=11, color=DARK, anchor=MSO_ANCHOR.MIDDLE)

# 底部提示
add_text(s, Inches(0.4), Inches(6.85), Inches(12.5), Inches(0.3),
         "* ROCm.ai 与 vLLM/SGLang 可同时使用 — 框架只负责 prompt 编排，推理后端随意换",
         size=10, color=GREY)
add_footer(s, 6)


# ============================================================
# Slide 7 · Gorgon Halo 推理调度器
# ============================================================
s = prs.slides.add_slide(BLANK)
add_title_bar(s, "Gorgon Halo 推理调度器",
              "集群级 LLM 推理路由 · KV cache 共享 · 智能 batching")

# 左：调度流程示意
add_text(s, Inches(0.4), Inches(1.2), Inches(5.0), Inches(0.4),
         "Gorgon Halo 工作流",
         size=14, bold=True, color=AMD_RED)
flow = [
    ("① Client 请求",     "→ 推理网关"),
    ("② KV cache 路由",   "→ 找缓存命中的 MI455X"),
    ("③ Continuous batching", "→ 多请求合并"),
    ("④ 张量并行调度",    "→ 多卡切分"),
    ("⑤ Stream token",   "→ SSE 回客户端"),
]
for i, (k, v) in enumerate(flow):
    y = Inches(1.7 + i * 0.6)
    add_rect(s, Inches(0.4), y, Inches(5.0), Inches(0.5),
             PANEL if i % 2 == 0 else WHITE,
             line=RGBColor(0xD9, 0xDD, 0xE4), line_w=Pt(0.5))
    add_rect(s, Inches(0.4), y, Inches(0.5), Inches(0.5), AMD_RED)
    add_text(s, Inches(0.4), y, Inches(0.5), Inches(0.5), str(i+1),
             size=14, bold=True, color=WHITE,
             align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, Inches(1.0), y, Inches(2.0), Inches(0.5),
             k, size=11, bold=True, color=DARK, anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, Inches(3.0), y, Inches(2.3), Inches(0.5),
             v, size=11, color=GREY, anchor=MSO_ANCHOR.MIDDLE)

# 右：配置代码
code_block(s, Inches(5.6), Inches(1.2), Inches(7.3), Inches(5.6),
           [("# gorgon-halo-config.yaml", "c"),
            ("cluster:", "k"),
            ("  name: helix-east", "s"),
            ("  network: ualoe-260tbps", "s"),
            ("  nodes: 4  # 4 机架", "k"),
            ("", None),
            ("scheduler:", "k"),
            ("  policy: prefix-cache-aware", "s"),
            ("  kv_cache_share: true", "k"),
            ("  continuous_batching: true", "k"),
            ("  max_batch_tokens: 32768", "k"),
            ("", None),
            ("model:", "k"),
            ("  name: meta-llama/Llama-3.3-70B-Instruct", "s"),
            ("  quantization: mxfp4", "s"),
            ("  tensor_parallel: 8  # 8 GPU", "k"),
            ("", None),
            ("placement:", "k"),
            ("  strategy: kv_locality", "s"),
            ("  fallback: round_robin", "s")],
           title="gorgon-halo-config.yaml", font_size=11)

# 底部 take-away
add_rect(s, Inches(0.4), Inches(6.85), Inches(5.0), Inches(0.3),
         RGBColor(0xFE, 0xF6, 0xF4))
add_text(s, Inches(0.4), Inches(6.85), Inches(5.0), Inches(0.3),
         "Gorgon Halo 与 ROCm 7 同期发布，AAI2026 后 30 天内 GA",
         size=10, color=GREY, align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
add_footer(s, 7)


# ============================================================
# Slide 8 · 模型兼容矩阵
# ============================================================
s = prs.slides.add_slide(BLANK)
add_title_bar(s, "模型兼容矩阵 · Llama / Qwen / DeepSeek / Mistral",
              "ROCm 7 Day-0 支持 / 量化方案 / 最大 context")

# 表头
add_text(s, Inches(0.4), Inches(1.2), Inches(12.5), Inches(0.4),
         "主流开源模型 · MI455X 兼容性",
         size=14, bold=True, color=AMD_RED)

# 用 code_block 风格的表格
add_rect(s, Inches(0.4), Inches(1.7), Inches(12.5), Inches(0.45), RGBColor(0xE7, 0xEA, 0xF0),
         line=RGBColor(0xD9, 0xDD, 0xE4), line_w=Pt(0.5))
hdrs = ["模型", "Day-0", "FP16", "MXFP4", "Context", "推荐度"]
col_w = [Inches(3.2), Inches(1.5), Inches(1.5), Inches(1.5), Inches(2.0), Inches(2.8)]
cx = Inches(0.4)
for ci, h in enumerate(hdrs):
    add_text(s, cx, Inches(1.7), col_w[ci], Inches(0.45),
             h, size=12, bold=True, color=DARK,
             align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
    cx += col_w[ci]

rows = [
    ("Llama 3.3 70B",        "✅", "✓", "✓", "131K",    "⭐⭐⭐⭐⭐"),
    ("Llama 3.3 405B",       "✅", "✗", "✓", "131K",    "⭐⭐⭐⭐ (8 卡)"),
    ("Qwen 2.5 72B",         "✅", "✓", "✓", "131K",    "⭐⭐⭐⭐⭐"),
    ("Qwen 3 235B MoE",      "⚠️", "✗", "✓", "32K",     "⭐⭐⭐⭐"),
    ("DeepSeek-V3 671B MoE", "⚠️", "✗", "✓", "128K",    "⭐⭐⭐ (16 卡)"),
    ("Mistral Large 123B",   "✅", "✓", "✓", "131K",    "⭐⭐⭐⭐⭐"),
    ("Phi-3 Medium 14B",     "✅", "✓", "✓", "131K",    "⭐⭐⭐⭐⭐"),
    ("Yi-1.5 34B",           "✅", "✓", "✓", "32K",     "⭐⭐⭐⭐"),
    ("gemma-2 27B",          "✅", "✓", "✓", "8K",      "⭐⭐⭐⭐"),
    ("GLM-4 9B",             "✅", "✓", "✓", "131K",    "⭐⭐⭐⭐"),
]
for ri, row in enumerate(rows):
    ry = Inches(2.15) + Inches(0.4) * ri
    fill = PANEL if ri % 2 == 0 else WHITE
    add_rect(s, Inches(0.4), ry, Inches(12.5), Inches(0.4),
             fill, line=RGBColor(0xD9, 0xDD, 0xE4), line_w=Pt(0.5))
    cx = Inches(0.4)
    for ci, cell in enumerate(row):
        col = DARK
        bold = False
        if ci == 1:    # Day-0 列
            col = NV_GREEN if cell == "✅" else (WARN if cell == "⚠️" else GREY)
            bold = True
        if ci in (2, 3):  # FP16 / MXFP4
            col = NV_GREEN if cell == "✓" else GREY
        if ci == 5:  # 推荐度
            col = AMD_RED
            bold = True
        add_text(s, cx, ry, col_w[ci], Inches(0.4),
                 cell, size=11, bold=bold, color=col,
                 align=PP_ALIGN.CENTER if ci > 0 else PP_ALIGN.LEFT,
                 anchor=MSO_ANCHOR.MIDDLE)
        cx += col_w[ci]

# 底部说明
add_text(s, Inches(0.4), Inches(6.4), Inches(12.5), Inches(0.4),
         "图例：✅ Day-0 主线  ⚠️ 需 hotfix / 自定义 ROCm build  ✗ 单卡放不下",
         size=11, color=GREY)
add_text(s, Inches(0.4), Inches(6.8), Inches(12.5), Inches(0.4),
         "* DeepSeek-V3 MoE 推理效率需 Gorgon Halo + UALoE 协同优化，2026 Q4 实测",
         size=10, color=GREY)
add_footer(s, 8)


# ============================================================
# Slide 9 · 量化方案
# ============================================================
s = prs.slides.add_slide(BLANK)
add_title_bar(s, "量化方案 · MI455X MXFP4 / MXFP8 / FP16",
              "HBM4 容量大 → 大多数场景无需 4-bit；MXFP4 用于极致吞吐")

# 三列对比卡
qtypes = [
    ("FP16",      "全精度基线",       "Llama 70B = 140 GB",   "推荐 KV cache 大量占用时"),
    ("MXFP8",     "块浮点 8-bit",     "Llama 70B ≈ 70 GB",    "通用推理首选，精度损失 <1%"),
    ("MXFP4",     "块浮点 4-bit",     "Llama 70B ≈ 35 GB",    "极致吞吐 / 长上下文首选"),
]
for i, (k, desc, mem, when) in enumerate(qtypes):
    x = Inches(0.4 + i * 4.2)
    add_rect(s, x, Inches(1.3), Inches(4.0), Inches(2.4),
             PANEL, line=AMD_RED, line_w=Pt(1.5))
    add_rect(s, x, Inches(1.3), Inches(4.0), Inches(0.5), AMD_RED)
    add_text(s, x, Inches(1.3), Inches(4.0), Inches(0.5), k,
             size=16, bold=True, color=WHITE,
             align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, x, Inches(2.0), Inches(4.0), Inches(0.5), desc,
             size=13, color=DARK, align=PP_ALIGN.CENTER,
             anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, x, Inches(2.6), Inches(4.0), Inches(0.5), mem,
             size=14, bold=True, color=AMD_RED,
             align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, x, Inches(3.2), Inches(4.0), Inches(0.5), when,
             size=11, color=GREY, align=PP_ALIGN.CENTER,
             anchor=MSO_ANCHOR.MIDDLE)

# 底部：量化加载代码
add_text(s, Inches(0.4), Inches(4.0), Inches(12.5), Inches(0.4),
         "实战代码：vLLM 加载 MXFP4 模型",
         size=14, bold=True, color=AMD_RED)
code_block(s, Inches(0.4), Inches(4.45), Inches(12.5), Inches(2.4),
           [("# 方法 1：vLLM 直接量化（推荐）",
             "c"),
            ("$ python -m vllm.entrypoints.openai.api_server \\",
             "p"),
            ("    --model amd-quantized/Llama-3.3-70B-MXFP4 \\",
             "p"),
            ("    --quantization mxfp4 --port 8000",
             "p"),
            ("", None),
            ("# 方法 2：Transformers + Composable Kernel（自定义）",
             "c"),
            ("from transformers import Mxfp4Linear", "k"),
            ("layer = Mxfp4Linear.from_pretrained(", "k"),
            ("    \"amd/Llama-3.3-70B-mxfp4\", device=\"cuda:0\")", "s"),
            ("✓ 加载完成，VRAM 占用 38 GB（vs FP16 140 GB）", "o")],
           title="quantize-and-serve.sh", font_size=11)

add_footer(s, 9)


# ============================================================
# Slide 10 · 性能调优 Tips
# ============================================================
s = prs.slides.add_slide(BLANK)
add_title_bar(s, "性能调优 10 Tips · MI455X 实战经验",
              "从官方文档 + GitHub issue + AAI2026 demo 整理")

tips = [
    ("01", "KV cache 复用",    "vLLM 启用 --enable-prefix-caching，多轮对话吞吐 +40%"),
    ("02", "Continuous batching","不要用 static batch，让 vLLM/SGLang 动态 merge"),
    ("03", "PagedAttention",   "vLLM 默认开启，确认 --block-size=16"),
    ("04", "Tensor parallel",  "70B 模型：单机 8 卡 TP=8；405B 模型：8 机 64 卡"),
    ("05", "Flash Attention 3", "ROCm 7 自带 flash-attn 3.x，AMD 分支编译版本"),
    ("06", "Fused kernel",     "Composable Kernel 自动 fuse softmax+gemm，省显存"),
    ("07", "MXFP4 + GEMM",     "确认 Llama 70B MXFP4 ≥ 100 tok/s/user（待实测）"),
    ("08", "Profile 工具",     "rocprof + Omnitrace 找 GPU 空闲段"),
    ("09", "NCU 替代品",       "用 rocprof --stats 替代 NVIDIA Nsight Compute"),
    ("10", "RDC 调试",          "RDC (ROCm Debugger) = nv-gdb 的 AMD 替代"),
]
left = tips[:5]
right = tips[5:]
for i, (n, k, v) in enumerate(left):
    y = Inches(1.2 + i * 1.05)
    add_rect(s, Inches(0.4), y, Inches(6.2), Inches(0.95),
             PANEL, line=RGBColor(0xD9, 0xDD, 0xE4), line_w=Pt(0.5))
    add_rect(s, Inches(0.4), y, Inches(0.7), Inches(0.95), AMD_RED)
    add_text(s, Inches(0.4), y, Inches(0.7), Inches(0.95), n,
             size=18, bold=True, color=WHITE,
             align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, Inches(1.25), y + Inches(0.08), Inches(5.3), Inches(0.4),
             k, size=14, bold=True, color=DARK, anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, Inches(1.25), y + Inches(0.5), Inches(5.3), Inches(0.4),
             v, size=11, color=GREY, anchor=MSO_ANCHOR.MIDDLE)
for i, (n, k, v) in enumerate(right):
    y = Inches(1.2 + i * 1.05)
    add_rect(s, Inches(6.9), y, Inches(6.0), Inches(0.95),
             PANEL, line=RGBColor(0xD9, 0xDD, 0xE4), line_w=Pt(0.5))
    add_rect(s, Inches(6.9), y, Inches(0.7), Inches(0.95), AMD_RED)
    add_text(s, Inches(6.9), y, Inches(0.7), Inches(0.95), n,
             size=18, bold=True, color=WHITE,
             align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, Inches(7.75), y + Inches(0.08), Inches(5.1), Inches(0.4),
             k, size=14, bold=True, color=DARK, anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, Inches(7.75), y + Inches(0.5), Inches(5.1), Inches(0.4),
             v, size=11, color=GREY, anchor=MSO_ANCHOR.MIDDLE)
add_footer(s, 10)


# ============================================================
# Slide 11 · 调试与可观测工具链
# ============================================================
s = prs.slides.add_slide(BLANK)
add_title_bar(s, "调试 / Profile / 可观测工具链",
              "NVIDIA Nsight 的 AMD 对位工具")

# 左：4 个工具代码块
add_text(s, Inches(0.4), Inches(1.2), Inches(6.2), Inches(0.4),
         "常用命令",
         size=14, bold=True, color=AMD_RED)
code_block(s, Inches(0.4), Inches(1.65), Inches(6.2), Inches(5.0),
           [("# rocprof：等效 NVIDIA Nsight Systems",
             "c"),
            ("$ rocprof --stats python my_model.py",
             "p"),
            ("", None),
            ("# Omnitrace：跨 CPU+GPU 全链路 profile",
             "c"),
            ("$ omnitrace-instrument -t python my_script.py",
             "p"),
            ("$ omnitrace-run -e \"--\" python my_script.py",
             "p"),
            ("", None),
            ("# rocgdb：等效 cuda-gdb",
             "c"),
            ("$ rocgdb --args python my_model.py",
             "p"),
            ("(gdb) set kernel breakpoint rocKERNEL_NAME", "k"),
            ("", None),
            ("# RDC：远程调试多卡",
             "c"),
            ("$ rdc -g 0,1,2,3 --topo", "p"),
            ("✓ 4× MI455X, all-to-all topology", "o")],
           title="debug-commands.sh", font_size=11)

# 右：可观测与指标
add_text(s, Inches(6.9), Inches(1.2), Inches(6.0), Inches(0.4),
         "可观测指标",
         size=14, bold=True, color=AMD_RED)
metrics = [
    ("GPU 利用率",      "rocm-smi --use", "70–95% 健康"),
    ("HBM 温度",       "rocm-smi --temp", "< 85 °C"),
    ("HBM 带宽利用率",  "rocm-bandwidth",  ">80% 高负载"),
    ("UALoE scale-up", "gorgon_halo_stats","按 query 查延迟"),
    ("推理延迟 P99",   "vllm_metrics",    "< 200 ms（70B）"),
    ("Token 吞吐",     "vllm_metrics",    "目标 ≥ 120 tok/s/GPU"),
]
for i, (k, cmd, expect) in enumerate(metrics):
    y = Inches(1.7 + i * 0.8)
    add_rect(s, Inches(6.9), y, Inches(6.0), Inches(0.7),
             PANEL if i % 2 == 0 else WHITE,
             line=RGBColor(0xD9, 0xDD, 0xE4), line_w=Pt(0.5))
    add_text(s, Inches(7.05), y, Inches(1.6), Inches(0.7),
             k, size=12, bold=True, color=AMD_RED, anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, Inches(8.65), y + Inches(0.05), Inches(2.6), Inches(0.6),
             cmd, size=10, color=DARK, anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, Inches(11.3), y + Inches(0.05), Inches(1.5), Inches(0.6),
             expect, size=10, color=NV_GREEN, anchor=MSO_ANCHOR.MIDDLE)
add_footer(s, 11)


# ============================================================
# Slide 12 · 12 周上手路线图 + 风险提示
# ============================================================
s = prs.slides.add_slide(BLANK)
add_title_bar(s, "12 周上手路线图 · 从 0 到生产推理服务",
              "Q3 2026 起 — 与 Helios 首批出货节奏同步")

# 4 阶段时间线
phases = [
    ("W1–W2",  "环境搭建",      "ROCm 7 + vLLM + Llama 70B 本地跑通"),
    ("W3–W4",  "模型迁移",      "将现有 NVIDIA 业务模型迁到 MI455X 验证吞吐"),
    ("W5–W8",  "性能基线",      "vs H100/Rubin 对比，整理 ROCm 自测数据"),
    ("W9–W12", "生产灰度",      "1 机架 Helios 跑 1 个真实业务模型"),
]
for i, (t, k, scope) in enumerate(phases):
    x = Inches(0.4 + i * 3.2)
    add_rect(s, x, Inches(1.2), Inches(3.0), Inches(2.0),
             PANEL, line=AMD_RED, line_w=Pt(1.5))
    add_rect(s, x, Inches(1.2), Inches(3.0), Inches(0.5), AMD_RED)
    add_text(s, x, Inches(1.2), Inches(3.0), Inches(0.5),
             t, size=14, bold=True, color=WHITE,
             align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, x, Inches(1.85), Inches(3.0), Inches(0.5),
             k, size=18, bold=True, color=AMD_RED,
             align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, x, Inches(2.5), Inches(3.0), Inches(0.7),
             scope, size=11, color=DARK, align=PP_ALIGN.CENTER,
             anchor=MSO_ANCHOR.MIDDLE)

# 下方：5 个风险
add_text(s, Inches(0.4), Inches(3.5), Inches(12.5), Inches(0.4),
         "5 个必须盯紧的风险",
         size=14, bold=True, color=AMD_RED)
risks = [
    ("R1", "ROCm 7 GA 时间",   "ROCm 7 正式版预计 Q3 2026 末，AAI2026 后 30 天内"),
    ("R2", "MI455X 产能",       "首批可能限量；提前与 AMD/Supermicro/HPE 锁产能"),
    ("R3", "vLLM MXFP4 性能",   "实测 120 tok/s/GPU 是 AMD 自测口径，等三方实测"),
    ("R4", "MoE all-to-all",    "DeepSeek-V3 类 MoE 推理效率依赖 Gorgon Halo + UALoE"),
    ("R5", "人才缺口",          "ROCm 工程师稀缺，建议提前培训 + 招 AMD 背景 SRE"),
]
for i, (n, k, v) in enumerate(risks):
    y = Inches(3.95 + i * 0.55)
    add_rect(s, Inches(0.4), y, Inches(12.5), Inches(0.5),
             PANEL if i % 2 == 0 else WHITE,
             line=RGBColor(0xD9, 0xDD, 0xE4), line_w=Pt(0.5))
    add_rect(s, Inches(0.4), y, Inches(0.6), Inches(0.5), WARN)
    add_text(s, Inches(0.4), y, Inches(0.6), Inches(0.5), n,
             size=11, bold=True, color=WHITE,
             align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, Inches(1.15), y, Inches(2.5), Inches(0.5),
             k, size=12, bold=True, color=DARK, anchor=MSO_ANCHOR.MIDDLE)
    add_text(s, Inches(3.8), y, Inches(9.0), Inches(0.5),
             v, size=11, color=GREY, anchor=MSO_ANCHOR.MIDDLE)

# 底部：金句
add_rect(s, Inches(0.4), Inches(6.8), Inches(12.5), Inches(0.45), DARK)
add_text(s, Inches(0.4), Inches(6.8), Inches(12.5), Inches(0.45),
         "现在动手写第一行 ROCm 代码，比等 ROCm 7 GA 更有价值",
         size=13, bold=True, color=WHITE,
         align=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
add_footer(s, 12)


# ---- 保存 ----
prs.save(OUT_PPTX)
print(f"OK saved → {OUT_PPTX}")
print(f"Slides: {len(prs.slides)}")