mathruffian-dot/teaching-exam-skills · Archived

jh-math-exam

國中數學段考出題與審題專家技能。當使用? 建立雙向細目表、分析題目認知層次分佈,或產出完整格式的題目卷與答案卷時,請一定要使用此技能。 觸發? 「產出國中數學試題」、「段考命題」、「數學考卷格式」等。 此技能整合修訂版 Bloom 認知層次四級分類(記憶/理解/應用/分析)、雙向細目表格式,以及?

First seen Jun 5, 2026

Installation

$ npx skills add mathruffian-dot/teaching-exam-skills --skill jh-math-exam

Summary

國中數學段考出題與審題專家技能。當使用者需要為國中數學(七年級、八年級、九年級)設計段考試題、審核試題品質、 建立雙向細目表、分析題目認知層次分佈,或產出完整格式的題目卷與答案卷時,請一定要使用此技能。 觸發情境包含:「幫我出數學考題」、「審一下這份考卷」、「做雙向細目表」、「依Bloom分級檢查題目」、…

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from mathruffian-dot/teaching-exam-skills.

npx skills add mathruffian-dot/teaching-exam-skills

Browse all from mathruffian-dot/teaching-exam-skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 2
License LICENSE
Default branch master
Open issues 0
Status Archived

Skill metadata

Parsed from SKILL.md frontmatter.

Declared agents claude-code

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 29,816 B
  • docs SUMMARY.md 717 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

國中數學段考命題審題技能

技能概覽

本技能支援兩種模式,協助教師完成國中數學段考的完整命題與審題流程:

模式 A:出題模式(全新命題)

  1. 需求訪談 — 確認年級、範圍、題型、配分
  2. 規劃雙向細目表 — 章節 × 認知層次比例
  3. 生成題目 — 按 Bloom 四級分類產出
  4. 幾何圖形渲染 — 若有幾何題,自動呼叫 jh-math-geometry 技能的渲染腳本產生配圖 PNG
  5. 格式輸出 — 題目卷、答案卷、雙向細目表(三份 Word),幾何圖自動插入對應位置

模式 B:審題模式(審核現有考卷)

  1. 接收考卷 — 使用者貼入文字或上傳圖片/Word
  2. 逐題審查 — 判定 Bloom 層次、section 歸屬、答案與題目品質
  3. 輸出分級報告 — 顯示統計與偏差提示
  4. 格式輸出 — 僅產出雙向細目表(一份 Word)

環境約定(所有 Step 共用)

本技能不假設任何特定沙箱或工具名稱,路徑一律依下列約定:

名稱 意義
本技能目錄$SKILL_DIR 這份 SKILL.md 所在的資料夾
output/ 當前工作目錄下的產出資料夾:中間檔(exam_data.json、幾何圖)與最終 Word 都放這裡
$GEOM_DIR jh-math-geometry 技能的 scripts/:同 repo 的 skills/jh-math-geometry/scripts/,或已安裝的 jh-math-geometry 技能
SKILL_DIR="<本技能目錄的絕對路徑>"        # 例:~/.claude/skills/jh-math-exam
mkdir -p output

# 幾何腳本位置:同 repo 的 skills/jh-math-geometry/,或已安裝的 jh-math-geometry 技能
GEOM_DIR=""
for d in "$SKILL_DIR/../jh-math-geometry/scripts" "$HOME/.claude/skills/jh-math-geometry/scripts"; do
  [ -f "$d/geometry_renderer.py" ] && GEOM_DIR="$d" && break
done
echo "幾何腳本目錄:${GEOM_DIR:-(找不到,幾何題將無法配圖)}"

python3 -m pip install -q python-docx lxml cairosvg   # 首次使用安裝一次;Linux 系統 Python 拒絕時加 --break-system-packages

- Windows 若沒有 python3 指令,把下文的 python3 換成 python;Bash 片段請在 Git Bash/WSL 執行。
- 文中的「視覺確認」一律指讀取檔案(用你的檔案讀取工具開啟 .svg.png),不依賴任何特定工具。
- 產出留在 output/,完成後在對話中列出檔案路徑即可,不需再複製到別處。


處理流程

Step 1:需求確認(必做)

向使用者確認以下資訊(未提供則詢問):

項目 說明
年級 七年級 / 八年級 / 九年級
學期 & 次別 第一學期第三次段考 等
考試範圍 章節名稱 + 版本(翰林版 / 康軒版 / 南一版)
題型需求 選擇題幾題、非選擇題幾題、配分
難度目標 參考 Bloom 各級比例,或教師自訂
模式 A. 出題(全新產出題目卷+答案卷+細目表) / B. 審題(審核現有考卷,只產細目表)

Step 2:建立雙向細目表

雙向細目表格式(本技能內建,不需外部檔案):

  • 縱軸:教材章節(依考試範圍列出各節名稱,如「1-1 等差數列」)
  • 橫軸:認知層次(記憶 / 理解 / 應用 / 分析)
  • 細格分數(題數),例如 6(2);最右欄「小計」,最下兩列「合計」與「百分比」
  • 表頭:學年度、學期、年級、次別、考試範圍;需要時加「對應課綱」欄(學習內容代碼 N/A/S/F/D,請上網查教育部十二年國教數學領綱)
章節 \ 層次 記憶 理解 應用 分析 小計
1-1 等差數列 4(1) 8(2) 12(3) 6(2) 30(8)
合計 10 20 40 30 100
百分比 10% 20% 40% 30% 100%

Bloom 四級判定準則與建議佔比(Step 3 出題與 Step 4 審題共用這一份,不另外讀檔):

層次 定義 判定關鍵字 國中數學範例 建議佔比
第1級:記憶 回憶公式、定義、術語 辨認、指出、寫出 「下列何者是一元一次方程式?」 10%
第2級:理解 解釋步驟、歸納、辨別差異 解釋、判斷、比較 「下列哪一步驟開始發生錯誤?」 20%
第3級:應用 給定具體數值/情境,帶公式計算、解方程式 求、計算、列式 「某商店打折問題,求原價」 40%
第4級:分析 多條件整合、多步驟推理、推論隱含關係 推論、整合、證明 「已知多個方程組,求某變數關係」 30%

⚠️ 若偏離此比例超過 ±10%,需提醒調整。


Step 3:題目生成(出題模式 A 專用)

依雙向細目表各格生成題目,每題須標註:

  • 題號、題型(選擇 / 非選擇)
  • Bloom 等級與判定關鍵理由
  • 正確答案 + 解題過程
  • 幾何圖形需求(若題目需要圖,填寫 geometry 欄位,見下方 JSON 規格)

各層次出題原則:依 Step 2 的「Bloom 四級判定準則」表(定義、關鍵字、範例皆在該表)。

選擇題格式規範

  • 四選一(A/B/C/D),每題必須提供完整四個選項
  • 干擾選項需具學習意義(常見錯誤)
  • 每題明確有唯一正確答案

答案分佈規則(必須嚴格遵守)

  • 答案必須平均分佈於 A、B、C、D 四個選項,每個選項出現次數應大致相等(±1題以內)
  • 例如:16 題選擇題 → A、B、C、D 各出現 4 次
  • 禁止連續兩題答案相同(例如:第3題答A,第4題不得再答A)
  • 命題完成後,必須自我檢查答案序列,確認無連續重複,並確認各選項出現次數平衡

答案分佈自我檢查表(完成命題後填寫):

答案序列:題1=?, 題2=?, 題3=?, ...(列出全部)
A 出現 _ 次|B 出現 _ 次|C 出現 _ 次|D 出現 _ 次
是否有連續重複:□ 無 □ 有(需修正)

非選擇題格式規範

  • 需有完整的解題過程要求
  • 分為多個子題 (1)(2)(3),各子題標明配分
  • 建議最後一題為情境應用題(第3-4級)

Step 4:認知層次審查(審題模式 B 專用)

觸發條件:使用者提供已出好的考卷(貼入文字、上傳圖片或 .docx),要求審題或產雙向細目表。

4-1 接收考卷資訊

向使用者確認以下資訊(若考卷內已有則自動提取,不需重複詢問):

項目 說明
年級 七年級 / 八年級 / 九年級
學期 & 次別 第一學期第一次段考 等
考試範圍 章節名稱(用於 section 歸屬)
配分規則 選擇題每題幾分、各大題配分

4-2 逐題審查

依 Step 2 的「Bloom 四級判定準則」表,對每道題目判定:

  • section:歸屬哪個節次(如「1-1 等差數列」),依考試範圍的章節名稱填寫
  • bloom_level:第1~4級,填寫完整格式如「第3級(應用)」
  • 品質檢查:題目是否清晰、選項是否有意義、非選題是否合理

審查輸出格式(在對話中顯示)

[題目審查報告]

題號 | 題目摘要(20字以內)  | section      | 判定層次   | 判定理由
-----|----------------------|-------------|-----------|------------------
01   | 辨認等差數列公差       | 1-1 等差數列 | 第1級(記憶)| 僅需辨認定義特徵
02   | 代入首項公差求第n項    | 1-1 等差數列 | 第3級(應用)| 給定數值帶公式計算
...

[統計摘要]
各節次題數:1-1 等差數列 X題 / 1-2 等差級數 X題 / ...
Bloom 分佈:1級 __%、2級 __%、3級 __%、4級 __%
建議比例:1級 10%、2級 20%、3級 40%、4級 30%
△ 差異提示:[若偏離 ±10% 則列出調整建議]
[品質問題]:[若有問題題目,列出題號與說明]

4-3 整理為審題 JSON

審查完成後,將考卷資訊整理為審題 JSON,儲存為 output/exam_data.json

審題模式不需填寫 answersolution(可留空字串),重點在 sectionbloom_level
非選擇題的 subquestions 每小題必須填入 bloomlevelpoints,才能正確計入細目表。
審題模式必須額外填寫 review_report 欄位(見下方格式),腳本才會同步產出審題報告 Word 檔。

review_report 欄位格式(加在 JSON 最外層)

"review_report": {
  "mc_rows": [
    {
      "number": 1,
      "summary": "辨認等差數列公差",
      "section": "1-1 等差數列",
      "bloom_level": "第1級(記憶)",
      "answer": "C",
      "reason": "僅需辨認定義特徵"
    }
  ],
  "open_rows": [
    {
      "big_number": 1,
      "label": "(1)",
      "summary": "代入首項公差求第n項",
      "section": "1-1 等差數列",
      "bloom_level": "第3級(應用)",
      "points": 4,
      "reason": "給定具體數值帶公式計算"
    }
  ],
  "section_stats": [
    { "section": "1-1 等差數列", "mc_pts": 20, "open_pts": 5, "total": 25 }
  ],
  "bloom_stats": {
    "第1級(記憶)": { "pts": 10, "pct": 10, "suggest": 10 },
    "第2級(理解)": { "pts": 20, "pct": 20, "suggest": 20 },
    "第3級(應用)": { "pts": 40, "pct": 40, "suggest": 40 },
    "第4級(分析)": { "pts": 30, "pct": 30, "suggest": 30 }
  },
  "quality_issues": [
    {
      "type": "error",
      "title": "配分說明有誤(需修正)",
      "description": "說明欄寫「1-16題每題4分,15-21題每題3分」,應為「17-21題每題3分」。"
    }
  ]
}

4-4 產出雙向細目表 + 審題報告(審題模式)

Step 6 的規格撰寫(或沿用已存在的)output/generateexamdocx.py,加 --blueprint-only 執行:

python3 output/generate_exam_docx.py output/exam_data.json output/ --blueprint-only
ls output/*.docx

產出 output/<年級>數學第<次別>次段考雙向細目表.docx審題報告.docx,完成後在對話中列出兩個檔案路徑。


Step 5:整理為 JSON 資料

將所有題目整理為以下格式,儲存為 output/exam_data.json

▶ geometry 欄位說明(出題模式專用)

若題目需要幾何圖形配圖,在該題加入 geometry 欄位;不需要圖形則設為 null

幾何圖形 spec 對照(常用類型快速複製):

題目類型 geometry.spec.type 常用 subtype
直角三角形 triangle right
等腰三角形 triangle isosceles
一般三角形 triangle general
平行四邊形 quadrilateral parallelogram
梯形 quadrilateral trapezoid
圓(弦弧切) circle
坐標平面 coordinate_plane
角柱/角錐 solid_3d rectangular_prism / cone
平行線截角 parallel_lines

常用範例見本 SKILL.md 末尾「幾何圖形 spec 速查」;完整參數見 jh-math-geometry 技能的 references/figure-catalog.md(同 repo skills/jh-math-geometry/references/figure-catalog.md

JSON 格式(含 geometry 欄位):

{
  "school_year": "114",
  "semester": "1",
  "exam_number": "3",
  "grade": "七年級",
  "scope": "翰林版第一冊第一章~第二章",
  "total_pages": 2,
  "mc_scoring": "1~7題每題4分、8~16題每題3分,共85分",
  "mc_questions": [
    {
      "number": 1,
      "section": "1-1 等差數列",
      "bloom_level": "第3級(應用)",
      "question": "如圖,△ABC 中,∠C = 90°,AC = 3,BC = 4,則 AB = ?",
      "options": { "A": "5", "B": "6", "C": "7", "D": "8" },
      "answer": "A",
      "solution": "由畢氏定理 AB² = AC² + BC² = 9 + 16 = 25,AB = 5",
      "geometry": {
        "caption": "圖一",
        "spec": {
          "type": "triangle",
          "config": {
            "subtype": "right",
            "vertex_labels": ["A", "B", "C"],
            "right_angle_at": "C",
            "side_labels": {"AC": "3", "BC": "4", "AB": "?"}
          },
          "canvas": {"width": 250, "height": 200}
        }
      }
    },
    {
      "number": 2,
      "section": "1-2 等差級數",
      "bloom_level": "第2級(理解)",
      "question": "不需要圖的題目範例",
      "options": { "A": "", "B": "", "C": "", "D": "" },
      "answer": "B",
      "solution": "",
      "geometry": null
    }
  ],
  "open_questions": [
    {
      "number": 1,
      "section": "1-2 等差級數",
      "total_points": 10,
      "context": "如圖,梯形 ABCD 中,AD∥BC,AD = 6,BC = 10,高為 4。",
      "geometry": {
        "caption": "圖二",
        "spec": {
          "type": "quadrilateral",
          "config": {
            "subtype": "trapezoid",
            "vertex_labels": ["A", "B", "C", "D"],
            "side_labels": {"AD": "6", "BC": "10"},
            "show_height": true,
            "height_label": "4"
          },
          "canvas": {"width": 280, "height": 220}
        }
      },
      "sub_questions": [
        {
          "label": "(1)",
          "bloom_level": "第3級(應用)",
          "points": 4,
          "question": "求梯形 ABCD 的面積。",
          "answer": "32",
          "solution": "面積 = (AD + BC) × 高 ÷ 2 = (6 + 10) × 4 ÷ 2 = 32"
        }
      ]
    }
  ]
}

注意geometry 欄位可放在 mcquestions 的每題,也可放在 openquestions 的大題 context 層級(整題共用一圖),或子題層級(每小題有各自的圖)。


Step 5.5:幾何圖形渲染(若 JSON 中有 geometry 欄位)

判斷是否需要執行:掃描 exam_data.json,若任何題目的 geometry 欄位不為 null,則執行本步驟。

# 前提:已依「環境約定」設定 $GEOM_DIR

# ── 1. 從 exam_data.json 提取所有 geometry spec,建立 geometry_spec.json ──
python3 - <<'PYEOF'
import json, pathlib

exam = json.load(open('output/exam_data.json', encoding='utf-8'))
figures = []

def collect(q, prefix):
    geo = q.get('geometry')
    if geo and geo.get('spec'):
        spec = dict(geo['spec'])
        spec['id'] = f"{prefix}_fig"
        spec.setdefault('canvas', {'width': 260, 'height': 210})
        figures.append({
            'id': spec['id'],
            'type': spec['type'],
            'config': spec.get('config', {}),
            'canvas': spec['canvas'],
            '_caption': geo.get('caption', ''),
            '_question_key': prefix
        })

# 選擇題
for q in exam.get('mc_questions', []):
    collect(q, f"mc_{q['number']}")

# 非選擇題(大題層級)
for q in exam.get('open_questions', []):
    collect(q, f"open_{q['number']}")
    # 子題層級
    for sq in q.get('sub_questions', []):
        label = sq['label'].strip('()')
        collect(sq, f"open_{q['number']}_{label}")

if figures:
    spec_data = {
        'figures': [{'id': f['id'], 'type': f['type'], 'config': f['config'], 'canvas': f['canvas']} for f in figures],
        'options': {'format': 'png', 'dpi': 150}
    }
    json.dump(spec_data, open('output/geometry_spec.json', 'w', encoding='utf-8'), ensure_ascii=False, indent=2)
    # 儲存 caption mapping 供後續插入使用
    mapping = {f['id']: {'caption': f['_caption'], 'question_key': f['_question_key']} for f in figures}
    json.dump(mapping, open('output/geometry_mapping.json', 'w', encoding='utf-8'), ensure_ascii=False, indent=2)
    print(f"✅ 需要渲染 {len(figures)} 張幾何圖形")
else:
    print("ℹ️ 本份考卷無幾何圖形,跳過渲染")
PYEOF

# ── 2. 渲染(若有圖形)────────────────────────────────────
if [ -f output/geometry_spec.json ]; then
  mkdir -p output/geometry_output
  python3 "$GEOM_DIR/geometry_renderer.py" \
      output/geometry_spec.json \
      output/geometry_output/
  echo "✅ 幾何圖形渲染完成:"
  ls output/geometry_output/*.png 2>/dev/null || echo "(無 PNG 輸出)"
fi

視覺確認:讀取 output/geometryoutput/*.svg(或 .png)確認圖形正確再繼續。若圖形有誤(標籤偏移、比例不佳),修改 examdata.json 中對應的 geometry.spec.config,重新執行 Step 5.5。


Step 6:匯出 Word 文件(必做)

本 repo 不附 generateexamdocx.py;請依下列規格用 python-docx 撰寫 output/generateexamdocx.py(工作目錄已有就直接沿用),再執行:

python3 output/generate_exam_docx.py output/exam_data.json output/                    # 出題模式:三份 Word
python3 output/generate_exam_docx.py output/exam_data.json output/ --blueprint-only   # 審題模式:細目表+審題報告
ls output/*.docx

6-1 腳本規格(題目卷/答案卷版面)

項目 規格
介面 generateexamdocx.py <exam_data.json> <輸出目錄> [--blueprint-only]
輸出檔名 <grade>數學第<examnumber>次段考題目卷.docx答案卷(教師版).docx雙向細目表.docx;JSON 有 reviewreport 時另產 審題報告.docx
題目卷版面 A4 直式、邊界 1.5 cm、標楷體/Times New Roman 12pt。頁首:「<schoolyear>學年度第<semester>學期 <grade>數學科第<examnumber>次段考」、考試範圍、「班級__座號__姓名___」。「一、選擇題(<mcscoring>)」每題一段、以 N. 開頭,選項 (A)…(B)…(C)…(D)… 接在同段或下一段;「二、非選擇題」每大題以 N、 開頭,子題 (1)(2) 各一段並標配分,留作答空白;totalpages 決定頁數,頁尾「第 x 頁/共 y 頁」
答案卷 同版面;選擇題答案表(題號/答案)+每題 solution;非選各子題 answersolution(依換行分段)
雙向細目表 依 Step 2 的表格結構,由每題 section × bloom_level 自動彙總 分數(題數),含合計、百分比與建議比例列
審題報告 reviewreport.mcrowsopenrows 各一張表(題號、摘要、section、層次、答案/配分、理由)+ sectionstatsbloomstats 表+ qualityissues 條列
數學式 題目、選項、解答中的 {…} 標記一律轉成 OMML(見 6-2),不可留成純文字

題目卷的段落開頭格式(選擇題 N.、非選 N、)是 Step 6.5 定位插圖的依據,請勿更動。

6-2 {} → OMML 轉換(可直接複製進腳本)

import re
from docx.oxml import OxmlElement
from docx.oxml.ns import qn

def mt(s):                               # <m:r><m:t>s</m:t></m:r>
    r = OxmlElement('m:r'); t = OxmlElement('m:t'); t.text = s; r.append(t); return r
def wrap(tag, *parts):
    e = OxmlElement(tag)
    for p in parts: e.append(p)
    return e
def frac(n, d): return wrap('m:f', wrap('m:num', mt(n)), wrap('m:den', mt(d)))
def sup(b, x):  return wrap('m:sSup', wrap('m:e', mt(b)), wrap('m:sup', mt(x)))
def sub(b, x):  return wrap('m:sSub', wrap('m:e', mt(b)), wrap('m:sub', mt(x)))
def sqrt(x, deg=None):
    pr = OxmlElement('m:radPr'); dh = OxmlElement('m:degHide'); dh.set(qn('m:val'), '0' if deg else '1'); pr.append(dh)
    return wrap('m:rad', pr, wrap('m:deg', *([mt(deg)] if deg else [])), wrap('m:e', mt(x)))

SYM = {'<=': '≤', '>=': '≥', '!=': '≠'}
def math_node(s):
    s = s.strip()
    if m := re.fullmatch(r'frac\((.+?),(.+)\)', s):          return frac(m[1], m[2])
    if m := re.fullmatch(r'sqrt(?:\[(.+?)\])?\((.+)\)', s):  return sqrt(m[2], m[1])
    if m := re.fullmatch(r'(.+?)\^\{?([^{}]+)\}?', s):        return sup(m[1], m[2])
    if m := re.fullmatch(r'(.+?)_(\w+)', s):                  return sub(m[1], m[2])
    if m := re.fullmatch(r'\((.+)\)/(.+)', s):                return frac(m[1], m[2])
    return mt(SYM.get(s, s.replace('*', '×')))

def add_math_text(paragraph, text):
    """把含 {math} 標記的字串寫入段落:純文字用 add_run,{…} 轉成 <m:oMath>,順序保持"""
    for piece in re.split(r'(\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\})', text):
        if not piece: continue
        if piece[0] == '{' and piece[-1] == '}':
            paragraph._p.append(wrap('m:oMath', math_node(piece[1:-1])))
        else:
            paragraph.add_run(piece)

腳本中所有寫入題目/選項/解答文字的地方,一律呼叫 addmathtext(paragraph, text),不要直接 add_run

Step 6.5:將幾何圖形插入題目卷(若有幾何圖)

若 Step 5.5 有產出幾何圖形,執行以下後處理腳本,將 PNG 插入對應題目後方:

# 確認是否有幾何圖形需要插入
if [ ! -f output/geometry_mapping.json ]; then
  echo "ℹ️ 無幾何圖形,跳過插入步驟"
else

python3 - <<'PYEOF'
import json, re
from pathlib import Path
from docx import Document
from docx.shared import Cm, Pt
from docx.enum.text import WD_ALIGN_PARAGRAPH

exam   = json.load(open('output/exam_data.json',    encoding='utf-8'))
mapping = json.load(open('output/geometry_mapping.json', encoding='utf-8'))
grade  = exam['grade']
en     = exam['exam_number']

docx_path = f"output/{grade}數學第{en}次段考_題目卷.docx"
doc = Document(docx_path)

# ── 建立「題號 → 段落索引」對照 ──────────────────────────────
# 策略:找段落文字以 "N." 開頭(選擇題)或 "(N)" / "大題N" 開頭(非選擇題)
para_index = {}
for i, para in enumerate(doc.paragraphs):
    text = para.text.strip()
    # 選擇題:匹配「1.」「2.」...「16.」
    m = re.match(r'^(\d{1,2})[\..]', text)
    if m:
        key = f"mc_{m.group(1)}"
        para_index.setdefault(key, i)

# 備援:找含「如圖」、「右圖」的段落
for i, para in enumerate(doc.paragraphs):
    text = para.text.strip()
    if '如圖' in text or '右圖' in text or '下圖' in text:
        # 嘗試從前文找題號
        for back in range(1, 4):
            if i - back >= 0:
                prev = doc.paragraphs[i - back].text.strip()
                m = re.match(r'^(\d{1,2})[\..]', prev)
                if m:
                    key = f"mc_{m.group(1)}"
                    para_index.setdefault(key, i)
                    break

# ── 依 mapping 插入圖形 ──────────────────────────────────────
# 先排序:讓插入從後往前,避免段落索引位移
insertions = []
for fig_id, info in mapping.items():
    png_path = Path(f"output/geometry_output/{fig_id}.png")
    if not png_path.exists():
        print(f"⚠️ 找不到圖形:{png_path}")
        continue
    qkey = info['question_key']
    caption = info.get('caption', '')
    if qkey in para_index:
        insertions.append((para_index[qkey], png_path, caption))
    else:
        # 找不到對應段落:插在文件末尾並提示
        print(f"⚠️ 找不到題號段落 {qkey},圖形將插在文件末尾")
        insertions.append((len(doc.paragraphs) - 1, png_path, f"[{qkey}] {caption}"))

# 從後往前插入,保持段落索引正確
insertions.sort(key=lambda x: -x[0])

for para_idx, png_path, caption in insertions:
    # 在目標段落「之後」插入圖片段落(python-docx 沒有原生 after 插入,用 XML 搬移)
    img_para = doc.add_paragraph()
    img_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
    run = img_para.add_run()
    run.add_picture(str(png_path), width=Cm(5.5))  # 試卷圖寬 5.5cm

    if caption:
        cap_para = doc.add_paragraph(caption)
        cap_para.alignment = WD_ALIGN_PARAGRAPH.CENTER
        for r in cap_para.runs:
            r.font.size = Pt(9)
            r.font.italic = True

    # 把剛 add 的段落(現在在文件末)移到目標位置後面
    target_el = doc.paragraphs[para_idx]._element
    img_el = img_para._element

    # 如果有 caption,一起移動
    if caption:
        cap_el = cap_para._element
        target_el.addnext(cap_el)
        target_el.addnext(img_el)
    else:
        target_el.addnext(img_el)

    print(f"✅ 已插入 {png_path.name} 於段落 {para_idx} 之後")

doc.save(docx_path)
print(f"✅ 幾何圖形插入完成:{docx_path}")
PYEOF

fi  # end if geometry_mapping exists

Step 6.6:完成回報

ls output/*.docx

在對話中列出 output/ 下三份 Word(題目卷、答案卷、雙向細目表)的路徑,並簡述 Bloom 分佈與答案分佈檢查結果。


數學標記語法(題目撰寫規則)

在題目文字中,用大括號 {} 包住數學式,系統會自動轉為 Word OMML 格式正確顯示:

標記語法 說明 範例
{x^2} x 的平方(上標)
{x^{n+1}} 上標含運算式 x^(n+1)
{x_1} x 下標 1 x₁
{sqrt(2)} 根號 2 √2
{sqrt[3](8)} 三次方根 ∛8
{frac(3,4)} 分數 3/4 ¾
{(a+b)/2} 含運算式的分數 (a+b)/2
`{\ x-3\ }` 絕對值 \ x-3\
{<=} 小於等於符號
{>=} 大於等於符號
{!=} 不等於符號
{a*b} 乘號 a×b

提醒:簡單的文字方程式(如 2x + 3 = 7)不需加 {},保持普通文字即可。


快速參考:資料位置

需要什麼 位置
Bloom 四級判定準則、建議佔比、出題原則 本 SKILL.md Step 2(內嵌)
雙向細目表格式 本 SKILL.md Step 2(內嵌)
題目卷 / 答案卷版面、Word 腳本規格、OMML 轉換 本 SKILL.md Step 6(內嵌)
幾何圖形 spec 完整參數 jh-math-geometry 技能的 references/figure-catalog.md(同 repo skills/jh-math-geometry/references/figure-catalog.md);常用範例見下方「幾何圖形 spec 速查」
108 課綱學習內容代碼(N/A/S/F/D)、學習表現代碼 本 repo 未附;需要時上網查教育部「十二年國教數學領域課程綱要」

注意事項

  • 數學式一律使用 {} 標記,不使用 x^2 或 √ 等文字替代
  • 情境題(第3-4級)應與日常生活掛鉤,情境需真實合理
  • 選擇題選項不得出現「以上皆是」或「以上皆非」
  • 非選擇題每小題配分需明確標示於 points 欄位
  • 解題過程(solution)請用換行分隔每個步驟,方便排版
  • 【答案分佈】 選擇題答案必須平均分佈於 A/B/C/D,且禁止連續兩題答案相同。整份 JSON 的 mc_questions 填寫完後,必須重新審查 answer 欄位序列,若有連續重複或嚴重不均,立即調整該題答案順序(同步調整 options 內容以匹配新答案)。
  • 【幾何圖形】 若題目文字含「如圖」、「右圖」、「下圖」等字樣,必須填寫 geometry 欄位,不可留為 null。圖形 canvas 尺寸:試卷用圖建議 280×220;若兩圖並排則各用 200×160

幾何圖形 spec 速查

每種 type 的完整 config 參數表請讀取 jh-math-geometry 技能的 references/figure-catalog.md;下表是段考最常用的圖形,可直接複製進 geometry.spec
批次格式:{"figures":[{"id":"fig1","type":…,"config":{…},"canvas":{"width":280,"height":220}}],"options":{"format":"png","dpi":150}}

題目類型 直接複製的 spec
畢氏定理 {"type":"triangle","config":{"subtype":"right","vertexlabels":["A","B","C"],"rightangleat":"C","sidelabels":{"AB":"c","BC":"a","CA":"b"}}}
全等三角形(SSS) {"type":"triangle","config":{"subtype":"general","vertexlabels":["A","B","C"],"equalmarks":{"AB":1,"BC":2,"CA":3}}}
圓心角+圓周角 {"type":"circle","config":{"centerlabel":"O","points":{"A":30,"B":150,"C":270},"radiuslines":["A","B"],"centralangle":["A","B"],"inscribedangle":{"vertex":"C","arc":["A","B"]}}}
平行四邊形對角線 {"type":"quadrilateral","config":{"subtype":"parallelogram","vertexlabels":["A","B","C","D"],"diagonals":true,"equalmarks":{"AB":1,"CD":1,"BC":2,"AD":2}}}
等腰梯形 {"type":"quadrilateral","config":{"subtype":"trapezoid","vertexlabels":["A","B","C","D"],"equalmarks":{"AB":1,"CD":1}}}
四角柱 {"type":"solid3d","config":{"subtype":"rectangularprism","vertexlabels":["A","B","C","D","E","F","G","H"],"showhidden":true}}
一次函數 {"type":"coordinateplane","config":{"xrange":[-3,5],"y_range":[-4,8],"lines":[{"slope":2,"intercept":-1,"label":"y=2x-1"}]}}
拋物線 {"type":"coordinateplane","config":{"xrange":[-2,5],"y_range":[-5,6],"parabolas":[{"a":1,"b":-2,"c":-3,"label":"y=x²-2x-3"}]}}