From 528577d8b27aed57620be006cd24ae06ab4de957 Mon Sep 17 00:00:00 2001 From: luojunlin Date: Mon, 22 Jun 2026 14:56:46 +0800 Subject: [PATCH 1/3] k1 brief + agent update --- .github/doc-review-agent/agent.py | 179 ++++++++++++++++++++++- en/key_stone/k1/k1_docs/root_overview.md | 2 + zh/key_stone/k1/k1_docs/root_overview.md | 2 + 3 files changed, 178 insertions(+), 5 deletions(-) diff --git a/.github/doc-review-agent/agent.py b/.github/doc-review-agent/agent.py index 415e0e1..dd83c01 100644 --- a/.github/doc-review-agent/agent.py +++ b/.github/doc-review-agent/agent.py @@ -715,6 +715,167 @@ def build_comment_body(sev: str, message: str, zh: bool) -> str: return f"{lbl} {message}\n\n" +# ─── Changes Summary ────────────────────────────────────────────────────────── + +def get_pr_file_patch(filename: str) -> str: + """Fetch the unified diff patch for a single file in the PR.""" + files = gh_get(f"/repos/{REPO}/pulls/{PR_NUMBER}/files?per_page=100") + # May span multiple pages; find the matching file + for f in files: + if f["filename"] == filename: + return f.get("patch", "") + return "" + + +def get_all_pr_patches(pr_files: list[dict]) -> dict[str, str]: + """Return {filename: patch} for all PR files (patches already in the pr_files list).""" + return {f["filename"]: f.get("patch", "") for f in pr_files} + + +def parse_diff_headings(patch: str) -> tuple[list[str], list[str]]: + """ + Parse added/removed Markdown headings from a unified diff patch. + Returns (added_headings, removed_headings) as lists of heading strings. + """ + added, removed = [], [] + heading_re = re.compile(r'^(#{1,4})\s+(.+)') + for line in patch.splitlines(): + if line.startswith("+") and not line.startswith("+++"): + m = heading_re.match(line[1:].strip()) + if m: + added.append(f"{'#' * len(m.group(1))} {m.group(2).strip()}") + elif line.startswith("-") and not line.startswith("---"): + m = heading_re.match(line[1:].strip()) + if m: + removed.append(f"{'#' * len(m.group(1))} {m.group(2).strip()}") + return added, removed + + +def parse_diff_stats(patch: str) -> tuple[int, int]: + """Return (lines_added, lines_removed) from a patch.""" + added = sum(1 for l in patch.splitlines() + if l.startswith("+") and not l.startswith("+++")) + removed = sum(1 for l in patch.splitlines() + if l.startswith("-") and not l.startswith("---")) + return added, removed + + +def classify_file(fpath: str) -> str: + """Return a human-readable document type label for a file path.""" + p = fpath.lower() + if "usermanual" in p: + return "User Manual" + if "_hw_faq" in p: + return "HW FAQ" + if "_sw_faq" in p: + return "SW FAQ" + if "_hw_design_guide" in p: + return "HW Design Guide" + if "_hw_avl" in p: + return "AVL" + if "_hw_resources" in p: + return "HW Resources" + if "_sdk_user_guide" in p: + return "SDK User Guide" + if "_ds." in p: + return "Datasheet" + if "root_overview" in p: + return "Product Brief" + if "_thermal" in p: + return "Thermal Design" + if "_pcb_guide" in p: + return "PCB Guide" + if "avl_veri_sop" in p: + return "AVL Verification SOP" + return "Doc" + + +def get_chip_from_path(fpath: str) -> str: + """Extract chip name (K1 / K3 / P1 / P1S) from file path.""" + chip_map = {"k1": "K1", "k3": "K3", "p1s": "P1S", "p1": "P1"} + parts = fpath.lower().split("/") + for part in parts: + for key, name in chip_map.items(): + if part == key: + return name + return "" + + +def build_changes_summary(pr_files: list[dict], patches: dict[str, str]) -> str: + """ + Build a structured '## 📄 Changes Summary' block that lists every changed + doc file with its type, language, diff stats, and heading-level changes. + """ + STATUS_ICON = {"added": "🆕", "modified": "✏️", "removed": "🗑️", "renamed": "🔀"} + + rows: list[str] = [] + + # Group by chip for a cleaner layout + chip_groups: dict[str, list[dict]] = {} + other: list[dict] = [] + + for f in pr_files: + fpath = f["filename"] + if not fpath.endswith(".md"): + continue + if not (fpath.startswith("en/") or fpath.startswith("zh/")): + continue + + chip = get_chip_from_path(fpath) + if chip: + chip_groups.setdefault(chip, []).append(f) + else: + other.append(f) + + def render_file_row(f: dict) -> str: + fpath = f["filename"] + status = f.get("status", "modified") + icon = STATUS_ICON.get(status, "✏️") + lang = "🇺🇸 EN" if fpath.startswith("en/") else "🇨🇳 ZH" + doc_type = classify_file(fpath) + patch = patches.get(fpath, "") + added_lines, removed_lines = parse_diff_stats(patch) + added_h, removed_h = parse_diff_headings(patch) + + # Short display name: just the filename + fname = pathlib.Path(fpath).name + + parts = [f"{icon} **`{fname}`** ({lang} · {doc_type})"] + + if status != "removed": + diff_str = f"+{added_lines} / -{removed_lines} lines" + parts.append(f" `{diff_str}`") + + if added_h: + for h in added_h[:5]: # cap at 5 to avoid noise + parts.append(f" - ➕ `{h}`") + if len(added_h) > 5: + parts.append(f" - ➕ *…and {len(added_h) - 5} more headings*") + + if removed_h: + for h in removed_h[:3]: + parts.append(f" - ➖ `{h}`") + if len(removed_h) > 3: + parts.append(f" - ➖ *…and {len(removed_h) - 3} more removed*") + + return "\n".join(parts) + + sections: list[str] = [] + + for chip in sorted(chip_groups.keys()): + file_rows = [render_file_row(f) for f in chip_groups[chip]] + sections.append(f"### {chip}\n\n" + "\n\n".join(file_rows)) + + if other: + file_rows = [render_file_row(f) for f in other] + sections.append("### Other\n\n" + "\n\n".join(file_rows)) + + if not sections: + return "" + + return "## 📄 Changes Summary\n\n" + "\n\n".join(sections) + + def build_pr_description_block(pr_files: list[dict]) -> str: """ Auto-generate a structured summary block describing what changed in this PR. @@ -817,12 +978,14 @@ def update_pr_description_with_summary(pr_info: dict, pr_files: list[dict]) -> N def build_summary(result: ReviewResult, zh: bool, - sync_table: str = "") -> str: + sync_table: str = "", + changes_summary: str = "") -> str: bot_tag = "" sync_section = ("\n\n" + sync_table.strip()) if sync_table else "" + changes_section = (changes_summary.strip() + "\n\n---\n") if changes_summary else "" if zh: return textwrap.dedent(f""" - ## 📋 文档审阅摘要 + {changes_section}## 📋 文档审阅摘要 | 级别 | 数量 | |------|------| @@ -837,7 +1000,7 @@ def build_summary(result: ReviewResult, zh: bool, """).strip() else: return textwrap.dedent(f""" - ## 📋 Doc Review Summary + {changes_section}## 📋 Doc Review Summary | Severity | Count | |------------|-------| @@ -944,10 +1107,16 @@ def is_included(path: str) -> bool: else: result.suggestions += 1 - # ── Item 1: Build PR-level translation sync table for the summary ───────── + # ── Build PR-level translation sync table ──────────────────────────────── sync_table = build_translation_sync_table(pr_files) - summary = build_summary(result, zh=has_zh, sync_table=sync_table) + # ── Build Changes Summary (diff-based, per file) ────────────────────────── + print("Building changes summary...") + patches = get_all_pr_patches(pr_files) + changes_summary = build_changes_summary(pr_files, patches) + + summary = build_summary(result, zh=has_zh, sync_table=sync_table, + changes_summary=changes_summary) if all_comments or result.errors + result.warnings + result.suggestions > 0: print(f"\nPosting review: {result.errors} errors, {result.warnings} warnings, " diff --git a/en/key_stone/k1/k1_docs/root_overview.md b/en/key_stone/k1/k1_docs/root_overview.md index 2751edd..0b6b1fe 100644 --- a/en/key_stone/k1/k1_docs/root_overview.md +++ b/en/key_stone/k1/k1_docs/root_overview.md @@ -6,6 +6,8 @@ Click to download **[K1 Brief (PDF)](https://cdn-resource.spacemit.com/file/chip ## Overview +**Most Widely Deployed Energy-Efficient RISC-V AI Processor** + K1 Series: 8-Core 64-bit RISC-V AI CPU The K1 series leverages homogeneous fusion computing technology, integrating eight high-performance X60™ computing cores developed by SpacemiT. It delivers 50 KDMIPS of general computing power and 2 TOPS of AI computing power, enabling seamless operation of local large models such as 0.5B and 1B parameters. diff --git a/zh/key_stone/k1/k1_docs/root_overview.md b/zh/key_stone/k1/k1_docs/root_overview.md index a813357..95d1406 100644 --- a/zh/key_stone/k1/k1_docs/root_overview.md +++ b/zh/key_stone/k1/k1_docs/root_overview.md @@ -6,6 +6,8 @@ sidebar_position: 1 ## 概述 +**量产数量最多的高能效 RISC-V AI CPU** + K1 系列是 8 核 64 位 RISC-V AI CPU。 K1 采用同构融合计算技术,集成进迭时空自研的 8 个高性能计算核 X60,可提供 50KDMIPS 通用算力,同时融合 2 TOPS AI 算力,可流畅运行 0.5B、1B 的本地大模型。 K1 系列芯片主要应用在 AI 边缘计算机、AI + 硬件、智能机器人、工业主控、云电脑、开源鸿蒙应用等领域。 From 3f0c600201cc3628bd357a6fff22d997e714b068 Mon Sep 17 00:00:00 2001 From: luojunlin Date: Mon, 22 Jun 2026 15:06:33 +0800 Subject: [PATCH 2/3] k1 en brief update --- en/key_stone/k1/k1_docs/root_overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/en/key_stone/k1/k1_docs/root_overview.md b/en/key_stone/k1/k1_docs/root_overview.md index 0b6b1fe..0a1616e 100644 --- a/en/key_stone/k1/k1_docs/root_overview.md +++ b/en/key_stone/k1/k1_docs/root_overview.md @@ -6,7 +6,7 @@ Click to download **[K1 Brief (PDF)](https://cdn-resource.spacemit.com/file/chip ## Overview -**Most Widely Deployed Energy-Efficient RISC-V AI Processor** +**The Highest-volume, Energy-efficient RISC-V AI CPU in Mass Production** K1 Series: 8-Core 64-bit RISC-V AI CPU From 27a31c2b46458f326c425eed69159a8820583222 Mon Sep 17 00:00:00 2001 From: luojunlin Date: Wed, 24 Jun 2026 11:31:41 +0800 Subject: [PATCH 3/3] dma address updated --- .../k3/k3_docs/k3_usermanual/16_peripherals/dma.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/en/key_stone/k3/k3_docs/k3_usermanual/16_peripherals/dma.md b/en/key_stone/k3/k3_docs/k3_usermanual/16_peripherals/dma.md index 3c2b796..8b13b80 100644 --- a/en/key_stone/k3/k3_docs/k3_usermanual/16_peripherals/dma.md +++ b/en/key_stone/k3/k3_docs/k3_usermanual/16_peripherals/dma.md @@ -519,12 +519,12 @@ The DMA request numbers for non-secure DMA (AP DMA) peripherals are listed below | 61 | Request for SSPA4 RxReq | 0xD4041000 | | 62 | Request for SSPA5 TxReq | 0xD4041800 | | 63 | Request for SSPA5 RxReq | 0xD4041800 | -| 0x1004 | Request for SSP0 TxReq | 0xD4040000 | -| 0x1008 | Request for SSP0 RxReq | 0xD4040000 | -| 0x100C | Request for SSP1 TxReq | 0xD4040800 | -| 0x1010 | Request for SSP1 RxReq | 0xD4040800 | -| 0x1054 | Request for QSPI RxReq | 0xD420C000 | -| 0x1058 | Request for QSPI TxReq | 0xD420C000 | +| 0x1104 | Request for SSP0 TxReq | 0xD4040000 | +| 0x1108 | Request for SSP0 RxReq | 0xD4040000 | +| 0x110C | Request for SSP1 TxReq | 0xD4040800 | +| 0x1110 | Request for SSP1 RxReq | 0xD4040800 | +| 0x1154 | Request for QSPI RxReq | 0xD420C000 | +| 0x1158 | Request for QSPI TxReq | 0xD420C000 | The DMA request numbers for secure DMA (AP DMA2) peripherals are listed below.