---
name: tiku-workbook
description: 用考古題題庫 MCP（tiku.ptsfu.org）挑題，依使用者自己的樣式產生 PDF 題本。用在「出 X 單元的題本」「幫我挑 10 題台大近五年的 page replacement 做成 PDF」。
---

# 考古題題本（自訂樣式）

題目從題庫 MCP（`https://tiku.ptsfu.org/mcp`）挑，排版在你這端做，不必到網站下載 PDF。
需要：已連上題庫 MCP、能執行 shell 並連外網。不能執行程式時（例如網頁版聊天），改給使用者 manifest 裡的 `website_url`，請他在網站按「產生 PDF 題本」。

## 1. 確認需求
問清楚（使用者沒說就用括號裡的預設）：單元或主題、題數（10）、學校（不限）、年度（近 10 年）、要排除的題目（使用者寫過的）、樣式檔（`style.json`，沒有就用預設）。

## 2. 找單元
- `resolve_topics({text, subject?})` 取得 `unit_key`；`ambiguous: true` 時把候選列給使用者選。
- 想知道某科有哪些單元：`get_subject_overview({subject, detail:"chapters"})`，再用 `chapter_key` 展開。
- 年度是**民國整數**；不確定最新年度時先 `get_catalog`。

## 3. 組題並取得 manifest（一次呼叫）
```json
build_practice_set({
  "allocations": [{"unit_key": "…", "count": 5}, {"unit_key": "…", "count": 5}],
  "schools": ["台大", "清大"], "year_from": 105,
  "exclude_ids": ["…使用者寫過的題目 ID…"],
  "seed": "任意字串，可重現",
  "include_manifest": true
})
```
- 已經自己挑好題目時改傳 `question_ids`（1–50 題，保留順序）。
- 有 `shortfalls` 代表題目不夠，告訴使用者並建議放寬學校或年度。
- 把 `structuredContent` 原樣存成 `manifest.json`。

**不要**對每題呼叫 `get_question(include_image=true)` 來抓圖：那會經過 MCP、佔用每分鐘 60 次的限流，也會把圖片塞進對話。圖片一律從 `image.url` 直接下載（有 CDN 快取）。

## 4. 排版
先下載參考程式並核對 SHA-256，**不符就停止、不要執行**，告訴使用者（可能被竄改，或已改版：到 MCP instructions 看目前的網址與雜湊）：

```bash
curl -fsSLo render_workbook.py https://tiku.ptsfu.org/agent/v1/render_workbook.py
```
SHA-256：`37008535ca2c2cf9f6d4f7791a4e63dc610026a382b6b6960bd71749b76f43d9`
（`sha256sum render_workbook.py`；Windows 用 `Get-FileHash render_workbook.py`）

核對無誤後用 uv 執行，相依套件會自動安裝（沒有 uv 時：`pip install pymupdf==1.28.2 pillow==12.3.0` 後用 python 執行；安裝任何工具前先問使用者）：

```bash
uv run render_workbook.py manifest.json -s style.json -o 題本.pdf --title "資料結構題本"
```
樣式範本（`-s` 可以直接給網址，也可以下載後修改）：
- `https://tiku.ptsfu.org/agent/style.example.json`（完整欄位，一題一頁）
- `https://tiku.ptsfu.org/agent/style.compact.json`（連續排版＋作答橫線）
圖片會快取在 `~/.cache/tiku/`，同一題不重抓；`--revalidate` 會用 ETag 向 CDN 確認是否更新。

也可以不用參考程式，用自己的工具排版。manifest 每題有：
| 欄位 | 內容 |
|---|---|
| `attribution` | 「年 校《卷名》 題號」，建議放在題目標題 |
| `original_units` | 單元標籤（第一個是主要單元） |
| `text` | 題意摘要（**未驗證**，不是完整題幹；以圖為準） |
| `image.url` | 原圖（WebP）。pdf-lib 等不支援 WebP 的工具先轉 PNG／JPEG |
| `provenance` | `source_pdf`、`pages`，可放頁尾 |
| `year`、`school`、`paper_subject`、`question_number`、`category`、`subjects`、`section` | 篩選與排版用 |

## 5. 樣式檔
只要寫想改的欄位，其他用預設值。範本裡的模板變數：`{seq} {total} {unit} {units} {attribution} {text} {year} {school} {paper_subject} {question_number} {category} {subjects} {source_pdf} {pages}`；封面另有 `{title} {date} {total}`。

| 想要 | 改這裡 |
|---|---|
| 一頁多題 | `layout.mode: "flow"` |
| 每題留作答空間 | `answer_space.lines` |
| 不要封面 | `cover.enabled: false` |
| 封面加一行紅字說明 | `cover.note` |
| 換字型 | `font.file`：單一字面的 `.ttf`／`.otf`（`.ttc` 合集可能選錯字面或無法子集化） |
| 檔案小一點 | `image.jpeg_quality` 調低；要無損改 `image.encode: "png"` |

## 6. 交付前檢查
- 打開 PDF 看幾頁：題目圖沒有被切掉、標題與題號對得上。
- 告訴使用者：題數、各單元題數、`shortfalls`、manifest 的 `website_url`（網站上也能看同一組題、產預設 PDF）。
- 題庫**沒有官方解答**；你講解時要說明是自己的推導。
- 記下這次的 `question_ids`，下次放進 `exclude_ids` 避免重複。
