Blog Publisher — 從 GitHub Tutorial 到 Hugo Blog 的自動發佈工作流教學
1. 概述
本教學說明如何將 AI-Knowledge Template (AIKT) 產出的 GitHub tutorial markdown 自動轉換為 Hugo blog post 並部署到 Netlify。
1.1 解決的問題
AIKT 的 gh-tutorial-qd workflow 會產出大量高品質的 GitHub 專案教學文件(目前已有 161 份 tutorial markdown),但這些內容只存在本地。Blog Publisher 將這些內容自動轉成 blog 文章,讓知識可被搜尋引擎索引、可分享、可累積。
1.2 完整架構
flowchart LR
subgraph AIKT["AI-Knowledge Template"]
GH["gh-tutorial-qd\nworkflow"] --> MD["tutorial.md\n(quarkdown 格式)"]
MD --> QD["tutorial.qd"]
QD --> HTML["tutorial HTML\n(quarkdown-out/)"]
end
subgraph PUBLISH["Blog Publisher"]
MD --> CONVERT["convert_to_hugo.sh\n(strip frontmatter\n+ mermaid shortcode)"]
CONVERT --> POST["content/post/\nYYYY-MM-DD-xxx/\nindex.md"]
end
subgraph DEPLOY["Deployment"]
POST --> GIT["git commit + push"]
GIT --> NETLIFY["Netlify\nauto-deploy"]
NETLIFY --> LIVE["tpow-001.netlify.app"]
end
style AIKT fill:#e7f5ff
style PUBLISH fill:#fff3bf
style DEPLOY fill:#d3f9d8
2. Blog 技術架構
2.1 技術棧 (Tech Stack)
| 元件 | 技術 | 說明 |
|---|---|---|
| SSG (Static Site Generator; 靜態網站產生器) | Hugo 0.145.0 | Go-based,build 速度極快(42 pages / 171ms) |
| Theme | hugo-theme-zen | 極簡風格,內建 search / sidebar / RSS |
| Hosting | Netlify | Git push 自動 CI/CD,免費方案足夠 |
| Domain | tpow-001.netlify.app | Netlify 子網域 |
| Diagram | Mermaid.js 11 (CDN) | 透過自建 shortcode + head partial 支援 |
| Fonts | Inter + Lato + Noto Sans Mono | 從 quarkdown minimal theme 移植,Google Fonts CDN |
| Source Banner | 自建 single.html override | 自動顯示 stars / forks / language / license |
| Source repo | TPOW-001/TPOW_250401_zen | GitHub master branch |
2.2 Hugo 目錄結構
graph TD
ROOT["TPOW_250401_zen/"] --> CONTENT["content/"]
ROOT --> LAYOUTS["layouts/"]
ROOT --> STATIC["static/"]
ROOT --> THEMES["themes/hugo-theme-zen/"]
ROOT --> CONFIG["hugo.yaml"]
ROOT --> NETLIFY["netlify.toml"]
CONTENT --> ABOUT["about.md"]
CONTENT --> POSTS["post/"]
POSTS --> P1["2026-05-20-paper-qa/\nindex.md"]
POSTS --> P2["2026-06-01-taiwan-health-mcp/\nindex.md"]
POSTS --> P3["2026-06-02-bionemo-framework/\nindex.md"]
POSTS --> P4["...更多 posts"]
LAYOUTS --> PARTIALS["partials/\nhead.html\n← Fonts + Mermaid CDN + CSS"]
LAYOUTS --> SHORTCODES["shortcodes/\nmermaid.html"]
LAYOUTS --> SINGLE["_default/\nsingle.html\n← Source Banner"]
style ROOT fill:#339af0,color:#fff
style CONFIG fill:#ff922b,color:#fff
style PARTIALS fill:#51cf66,color:#fff
style SINGLE fill:#845ef7,color:#fff
2.3 Hugo 設定 (hugo.yaml) 關鍵配置
1# 基本資訊
2title: "TPOW Lab"
3baseURL: "https://tpow-001.netlify.app/"
4languageCode: "zh-TW"
5
6# Markdown 渲染 — 必須啟用 unsafe 才能支援 HTML shortcode
7markup:
8 goldmark:
9 renderer:
10 unsafe: true
11
12# 文章設定
13params:
14 buildFuture: true # 允許未來日期的文章顯示
15 sidebar: true
16 author:
17 name: "TPOW-001"
2.4 Netlify 設定 (netlify.toml)
1[build]
2command = 'hugo'
3publish = 'public'
4
5[build.environment]
6HUGO_VERSION = '0.145.0'
7
8[context.production.environment]
9HUGO_ENV = 'production'
2.5 排版風格(quarkdown minimal theme 移植)
字型來自 quarkdown 的 minimal layout theme,透過 layouts/partials/head.html 注入 Google Fonts CDN:
graph LR
subgraph QUARKDOWN["Quarkdown Minimal Theme"]
QH["Heading: Inter"]
QB["Body: Lato"]
QC["Code: Noto Sans Mono"]
end
subgraph HUGO["Hugo Blog (head.html)"]
HH["--font-heading: Inter"]
HB["--font-body: Lato"]
HC["--font-code: Noto Sans Mono"]
end
QH -.->|"移植"| HH
QB -.->|"移植"| HB
QC -.->|"移植"| HC
style QUARKDOWN fill:#e7f5ff
style HUGO fill:#d3f9d8
| 用途 | 字型 | 來源 | CSS 變數 |
|---|---|---|---|
| 標題 (H1-H6) | Inter (wght 400-800) | Google Fonts | --font-heading |
| 內文 | Lato (wght 300-700) | Google Fonts | --font-body |
| 程式碼 | Noto Sans Mono (wght 400-600) | Google Fonts | --font-code |
2.6 Source Banner(來源資訊條)
每篇含 source_url frontmatter 的文章,標題下方自動顯示 source banner:
1Source: https://github.com/NVIDIA-BioNeMo/bionemo-framework
2⭐ 757 stars 🍴 154 forks 💻 Jupyter Notebook 📜 Apache-2.0
實作於 layouts/_default/single.html(override theme 的 _default/single.html)。Banner 只在文章 frontmatter 有 source_url 時才顯示,不影響一般文章。
3. Mermaid 支援機制
Hugo 原生不支援 Mermaid diagram (Mermaid 圖表)。本專案透過三個元件實現支援:
3.1 架構圖
flowchart TD
subgraph AUTHOR["文章撰寫"]
A1["在 md 中寫\n
\ngraph TD\n A-->B\n
"]
end
subgraph HUGO["Hugo Build"]
B1["shortcodes/mermaid.html\n轉為 pre.mermaid"] --> B2["partials/head.html\n注入 Mermaid CDN"]
B2 --> B3["frontmatter\nmermaid: true\n控制是否載入"]
end
subgraph BROWSER["瀏覽器"]
C1["Mermaid.js CDN 載入"] --> C2["document.addEventListener\ninitialize()"] --> C3["pre.mermaid 元素\n渲染為 SVG"]
end
AUTHOR --> HUGO --> BROWSER
style AUTHOR fill:#e7f5ff
style HUGO fill:#fff3bf
style BROWSER fill:#d3f9d83.2 shortcodes/mermaid.html
1<pre class="mermaid">
2{{ .Inner }}
3</pre>
3.3 partials/head.html
1{{ if .Params.mermaid }}
2<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
3<script>
4 document.addEventListener('DOMContentLoaded', function () {
5 mermaid.initialize({
6 startOnLoad: true,
7 theme: 'default',
8 securityLevel: 'loose',
9 fontFamily: '-apple-system, BlinkMacSystemFont, "Noto Sans TC", sans-serif'
10 });
11 });
12</script>
13{{ end }}
3.4 使用條件
- Frontmatter 必須包含
mermaid: true,否則不載入 CDN(節省頁面 load time) convert_to_hugo.sh會自動偵測文章中是否有 mermaid shortcode,自動加入mermaid: true
4. 轉換流程詳解
4.1 完整轉換流程
flowchart TD
A["輸入:AIKT tutorial.md\n(quarkdown 格式 frontmatter)"] --> B["Step 1: 提取原始 frontmatter\ntitle / date / tags / url\nstars / forks / language / license"]
B --> C["Step 2: awk 移除原始 frontmatter\n+ 轉換 mermaid fence\n→ Hugo shortcode"]
C --> D["Step 3: 從目錄路徑\n自動推斷 category\n(bio→Bioinformatics\nagent→AI-Agent)"]
D --> E["Step 4: 清理 tags\n移除原始引號\n統一 JSON array 格式"]
E --> F["Step 5: printf 寫入\nHugo frontmatter\ntitle / author / date\ncategories / tags\nsource_url / github\nstars / forks / language\nlicense / mermaid"]
F --> G["Step 6: cat 附加 body\n→ index.md"]
style A fill:#ff8787,color:#fff
style B fill:#ff922b,color:#fff
style F fill:#339af0,color:#fff
style G fill:#51cf66,color:#fff
4.2 Frontmatter 格式轉換對照
轉換前(AIKT quarkdown 格式):
1---
2title: "Tutorial: NVIDIA-BioNeMo/bionemo-framework — 完整解讀"
3date: 2026-06-02
4source: github
5url: https://github.com/NVIDIA-BioNeMo/bionemo-framework
6owner: NVIDIA-BioNeMo
7repo: bionemo-framework
8language: Jupyter Notebook
9stars: 757
10forks: 154
11license: Apache-2.0
12tags: [tutorial, bionemo, biopharma-foundation-model, esm2, ...]
13---
轉換後(Hugo 格式 v2 — 保留完整 metadata):
1---
2title: "Tutorial: NVIDIA-BioNeMo/bionemo-framework — 完整解讀..."
3author: "TPOW-001"
4date: 2026-06-02
5categories: ["Bioinformatics"]
6tags: ["tutorial", "bionemo", "biopharma-foundation-model", "esm2", "amplify",
7 "evo2", "geneformer", "codonfm", "moco", "drug-discovery", "nvidia"]
8source_url: "https://github.com/NVIDIA-BioNeMo/bionemo-framework"
9github: "NVIDIA-BioNeMo/bionemo-framework"
10stars: 757
11forks: 154
12language: "Jupyter Notebook"
13license: "Apache-2.0"
14mermaid: true
15---
v1 → v2 差異對照:
| 欄位 | v1 | v2 |
|---|---|---|
| title | 從 H1 提取 | 優先從原始 frontmatter,fallback H1 |
| date | 手動指定 | 自動提取 date / saved_at / 檔名 |
| tags | 固定 ["tutorial", "bioinformatics"] | 保留原始所有 tags |
| category | 手動指定 | 從目錄路徑自動推斷 |
| source_url | 無 | 自動提取 url / github_url |
| stars / forks | 無 | 自動提取 |
| language / license | 無 | 自動提取 |
4.3 Mermaid 語法轉換對照
轉換前(標準 markdown):
1
flowchart TD
A --> B
轉換後(Hugo shortcode):
1{{< mermaid >}}
2flowchart TD
3 A --> B
4{{< /mermaid >}}
4.4 執行方式(v2 — 簡化參數)
1# v2 只需 3 個參數(date / category / tags 全自動提取)
2bash scripts/convert_to_hugo.sh \
3 "<tutorial.md 路徑>" \
4 "<Hugo post 目錄>" \
5 "[author]" # 預設 TPOW-001
6
7# 實際範例
8bash scripts/convert_to_hugo.sh \
9 "projects/260520 Github repo/260602 bionemo-framework/quarkdown/2026-06-02-tutorial-bionemo-framework.md" \
10 "/tmp/TPOW_250401_zen/content/post/2026-06-02-bionemo-framework"
11# → 自動提取 date=2026-06-02, category=Bioinformatics, tags=22個, stars=757, ...
v1 vs v2 參數對比:
1# v1(5 個參數,手動指定 date / category)
2bash convert_to_hugo.sh <md> <post_dir> <date> <category> <author>
3
4# v2(2-3 個參數,全自動)
5bash convert_to_hugo.sh <md> <post_dir> [author]
5. 部署流程
5.1 端到端發佈流程
sequenceDiagram
participant U as User
participant C as Claude Code
participant S as convert_to_hugo.sh
participant G as GitHub
participant N as Netlify
U->>C: blog-publish: path/to/tutorial.qd
C->>C: 讀取 .qd 對應的 tutorial.md
C->>C: 提取 date / category
C->>S: 執行 convert_to_hugo.sh
S->>S: strip frontmatter + mermaid shortcode
S-->>C: index.md 產出
C->>G: git add + commit + push
G->>N: webhook trigger
N->>N: hugo build (0.145.0)
N-->>U: 部署完成 (1-2 min)
C->>U: Discord reply with URL
5.2 Git 操作流程
1# 1. Clone blog repo (若尚未 clone)
2git clone https://github.com/TPOW-001/TPOW_250401_zen.git /tmp/TPOW_250401_zen
3
4# 2. 轉換 tutorial
5bash scripts/convert_to_hugo.sh <args...>
6
7# 3. 本地驗證
8cd /tmp/TPOW_250401_zen && hugo --gc --minify
9
10# 4. Commit + Push
11git add content/post/<new-post>/
12git commit -m "feat: add <post-name> tutorial post"
13git push origin master
14
15# 5. 等待 Netlify 自動部署 (1-2 min)
6. 已發佈文章清單
6.1 Bio 系列(第一批 3 篇,2026-06-12 發佈)
| 日期 | 文章 | 行數 | Mermaid | 來源 |
|---|---|---|---|---|
| 2026-05-20 | paper-qa — Agentic RAG for Scientific Literature | 527 | 1 圖 | 260520 paper-qa |
| 2026-06-01 | Taiwan-Health-MCP — 台灣醫療資料 MCP 伺服器教學 | 414 | 1 圖 | 260601 Taiwan-Health-MCP |
| 2026-06-02 | NVIDIA BioNeMo Framework — 蛋白質/基因/藥物 AI 引擎教學 | 1,379 | 6 圖 | 260602 bionemo-framework |
6.2 素材庫統計
| 系列 | 可用 tutorial 數 | 說明 |
|---|---|---|
| Bio / Medical | 14 | 最核心,最符合專業背景 |
| AI Agent / Claude | 15 | Claude Code + Agent 生態系 |
| DevTools | 20+ | 開發工具、self-hosted、3D 等 |
| NVIDIA | 10+ | BioNeMo / Cosmos / GR00T / Nemotron |
| 其他 | 100+ | 金融、動畫、影片製作、面試等 |
| 合計 | 161 | 全部來自 260520 Github repo/ |
7. 故障排除
7.1 常見問題
| 問題 | 原因 | 解法 |
|---|---|---|
| Mermaid 圖不渲染 | frontmatter 缺 mermaid: true | 確認 convert script 有偵測到 mermaid |
| Mermaid 圖顯示原始碼 | 瀏覽器無網路(CDN 載入失敗) | 連網後重新整理 |
| HTML 標籤被 strip | goldmark.renderer.unsafe 未啟用 | 確認 hugo.yaml 有 unsafe: true |
| 文章不出現 | 日期是未來 | 確認 params.buildFuture: true |
| Hugo build 失敗 | shortcode 語法錯誤 | 檢查 {{< mermaid >}} 配對 |
7.2 本地測試
1# 下載 Hugo (一次性)
2curl -sL "https://github.com/gohugoio/hugo/releases/download/v0.145.0/hugo_extended_0.145.0_linux-amd64.tar.gz" | tar xz hugo
3./hugo version
4
5# Build 測試
6cd /tmp/TPOW_250401_zen
7./hugo --gc --minify
8
9# 本地預覽
10./hugo server -D # http://localhost:1313
8. 相關檔案索引
1projects/260612 blog-publisher/
2├── scripts/
3│ └── convert_to_hugo.sh ← 核心轉換 script (v2)
4├── quarkdown/
5│ └── 2026-06-12-blog-publisher-tutorial.qd
6├── quarkdown-out/
7│ └── 01-tutorial/index.html ← 本教學的 HTML 版
8└── (本教學 md 存於 inbox/)
9
10AIKT Skill:
11.claude/skills/blog-publish/
12└── SKILL.md ← blog-publish skill 定義 (Layer 21)
13
14Blog repo (GitHub):
15TPOW-001/TPOW_250401_zen
16├── hugo.yaml ← 網站設定(Inter+Lato+NotoSansMono 字型)
17├── netlify.toml ← 部署設定(Hugo 0.145.0)
18├── content/
19│ ├── about.md
20│ └── post/ ← 所有 blog 文章
21├── layouts/
22│ ├── _default/single.html ← Source Banner(stars/forks/lang/license)
23│ ├── partials/head.html ← Fonts CDN + Mermaid CDN + CSS 變數
24│ └── shortcodes/mermaid.html ← Mermaid shortcode
25└── themes/hugo-theme-zen/ ← Zen 主題(base)
9. blog-publish Skill 使用說明
9.1 觸發方式
1blog-publish: <qd 檔案路徑>
或自然語言:
1幫我把 projects/260520 Github repo/260602 bionemo-framework/quarkdown/2026-06-02-tutorial-bionemo-framework.qd 發到 blog
9.2 Skill 執行流程
flowchart TD
A["使用者指定 .qd 檔路徑"] --> B["找到對應的 tutorial.md\n(同目錄,副檔名換 .md)"]
B --> C["從檔名提取 date\n(YYYY-MM-DD 格式)"]
C --> D["從目錄名推斷 category\n(bio / ai-agent / devtools)"]
D --> E["Clone blog repo\n(git clone --depth 1)"]
E --> F["執行 convert_to_hugo.sh"]
F --> G["hugo build 驗證"]
G --> H{"Build 成功?"}
H -->|Yes| I["git add + commit + push"]
H -->|No| J["回報錯誤\n不 push"]
I --> K["Discord reply\n附上 blog URL"]
style A fill:#339af0,color:#fff
style I fill:#51cf66,color:#fff
style J fill:#ff6b6b,color:#fff
9.3 Category 自動判斷規則
| 目錄名關鍵字 | Category |
|---|---|
| bio / bionemo / drug / medical / health / causalbench / retrosynthesis / paper-qa / turbovec | Bioinformatics |
| claude / agent / mem0 / skill / mcp / anthropic / hivemind | AI-Agent |
| 其他 | DevTools |
Comments