feat: 形象圖改為「依人格資料重繪」,並驗證 Wiki 同步
1. 不再直接使用網路上找到的圖片
舊版把裁下來的官方美術當圖示(photo 樣式)。現在改成:
找圖 → `icon headshot` 裁出**大頭照當底稿** → AI 用 Read 親眼看過 →
讀出髮型/瀏海/眼型/表情/髮飾/領口等特徵 → **由本工具重新繪製**。
* 底稿寫在 <人格>/.sync/headshot.png,**不是圖示、不同步、不發佈**。
* 產出的 SVG 不得有 <image>/base64/外連(selftest 會擋)。
* 移除 photo 樣式與 photoSvg;config 裡殘留的舊樣式會被忽略而非退回徽章。
2. 重繪引擎:五官與造型可參數化
新增 --features:hairstyle(5) / length(4) / fringe(4) / eyes(4) /
expression(4) / accessory(5) / side / collar(4) / ahoge。
渲染器新增 polygon 圖元(呆毛、緞帶、V 領、銳利眼角),SVG 與自寫柵格器
仍共用同一份圖形清單,兩邊必然一致。
另外調了臉部比例:眉毛用「髮色偏膚色」避免深髮角色眉毛與瀏海連成黑帶、
加了鼻子(否則嘴會被看成鼻子)、眼與嘴的縱向配置重排。
3. Wiki 形象圖必須同步(並且會被驗證)
新增 `sync verify`(不一致以非零結束)與 verifyIconInWiki();
`icon generate` 推完 Wiki 會自動回頭確認 icon.svg + icon.png 真的在遠端
且與本機一致。
修掉一個會讓驗證永遠失敗的 bug:Wiki 首頁內嵌了 `最後同步 ${now}`,
每次產生都不同 → 永遠 dirty、每次 push 都多一個 commit。改用圖示的
generated_at。porcelain 解析也從固定位移改為正規式。
已重繪兩個真實人格(皆為 portrait 樣式,並通過 Wiki 同步驗證):
ASUNA-01 底稿=《Unanswered//butterfly》(2026) 主視覺左側;金蜜色極長直髮、
中分瀏海、呆毛、紅褐杏眼、沉靜神情、紅上衣 V 領
YUI-01 底稿=AniList 官方角色圖;藍黑極長直髮、齊瀏海、圓大棕眼、燦爛笑容,
髮飾與配色採現行 Unital Ring 導航妖精造型(淡粉洋裝、藍花)
selftest 161 項全綠(新增第 ⑰ 節:特徵解析、換髮型/眼型/表情會畫出不同的圖、
polygon 兩邊一致、舊樣式不污染、SVG 無內嵌影像、Wiki 首頁無時間戳)。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,8 +26,8 @@ skills 是共通標準,**鎖與隔離的強制執行需要 hook,目前只有
|
||||
| **9. 人格可以匯出匯入** | `export` 把身分/情緒/記憶/心智圖/關係圖打包成單一 JSON bundle(可 `--gzip`、附 sha256),`import` 還原或換名複製;**不帶**載入鎖與 guest 租約,`journal/` 要明確 `--with-journal` 才帶走 |
|
||||
| **10. 人格有編號** | 編號 = **英文名全大寫 + 兩位索引**(同名才遞增):`ASUNA-01`、`YUI-01`、`ASUNA-02`。編號同時是新人格的本機目錄名與 Gitea 存取庫名稱;中文名先轉羅馬拼音並跟使用者確認拼法 |
|
||||
| **11. 人格存在 Gitea,依更新頻率分區** | 每個人格一個**私有存取庫**(庫名=編號)。**檔案區**放每輪都在變的活狀態(情緒/短期記憶/心裡話/說過的話/逐字),**Wiki 區**放低頻的身分與長期結構(IDENTITY/SOUL/長期記憶/心智圖/關係圖)當設定百科。本機仍是工作副本,同步失敗不阻斷對話 |
|
||||
| **12. 圖示是人物形象圖,取自最新登場的官方視覺** | `/jsc-persona:persona-icon` 上網找出該人格**最新一次登場**的官方視覺、**親眼看過**,有 Pillow+OpenCV 就直接**裁出臉**當形象圖;沒工具則畫**有五官的向量人物**(配色同樣取自那張圖),並印出安裝指令。來源網址與裁切框存進 `config.json` 備查 |
|
||||
| **13. Wiki 保存形象圖** | `icon.svg` 與 `icon.png` 一起同步到 Wiki 區,另外自動產生一頁 **Icon** 同時展示兩種格式並列出來源、樣式與裁切框;PNG 同時設為存取庫頭像 |
|
||||
| **12. 圖示是重新繪製的人物形象圖(有臉)** | 上網找出該人格**最新一次登場**的官方視覺 → 裁出**大頭照當底稿** → **親眼看過** → 讀出髮型/瀏海/眼型/表情/髮飾等特徵 → **由本工具依人格資料重新繪製**。**絕不把找到的圖片當圖示**:SVG 裡沒有 `<image>`、沒有 base64、沒有外連,底稿只留在 `.sync/` 不同步。來源網址與重繪依據存進 `config.json` 備查 |
|
||||
| **13. Wiki 必須保存並同步形象圖** | `icon.svg` 與 `icon.png` 都同步到 Wiki 區,另有自動產生的 **Icon** 頁展示兩種格式與來源;`icon generate` 推完會**回頭驗證** Wiki 真的有這兩個檔案且與本機一致,另有 `sync verify` 可隨時檢查(不一致以非零結束)|
|
||||
|
||||
---
|
||||
|
||||
@@ -150,13 +150,23 @@ AI 最容易露餡的三件事:把推理過程講出來、一次講一大段
|
||||
建立人格**並補齊 IDENTITY/SOUL 之後**產生,512×512。**優先是人物形象圖(看得到臉)**,
|
||||
依環境有無工具分三種樣式:
|
||||
|
||||
流程是 **找圖 → 裁大頭照當底稿 → 親眼看過 → 讀出特徵 → 重新繪製**:
|
||||
|
||||
| 步驟 | 指令 | 產出 |
|
||||
| --- | --- | --- |
|
||||
| 1. 找臉 | `icon faces --photo <圖>` | 圖裡所有臉的座標(多角色務必先看) |
|
||||
| 2. 裁底稿 | `icon headshot --photo <圖> --pick N` | `.sync/headshot.png`(**不是圖示、不同步**) |
|
||||
| 3. 看 | Read 打開底稿 + 讀 IDENTITY/SOUL | 髮型、瀏海、眼型、表情、髮飾、領口 |
|
||||
| 4. 重繪 | `icon generate --palette ... --features ...` | `icon.svg` + `icon.png` |
|
||||
|
||||
| 樣式 | 條件 | 長什麼樣 |
|
||||
| --- | --- | --- |
|
||||
| **`photo`** | 有參考圖 **且** 有 Pillow+OpenCV | 從官方視覺**裁出的臉**(自動臉部偵測),圓角+瞳色外框 |
|
||||
| **`portrait`** | 有參考圖但缺工具 | **有五官的向量人物**:髮型、瞳色、服裝色都取自那張圖 |
|
||||
| **`portrait`** | 有底稿(給了調色盤)→ 預設 | 依特徵重繪的人物頭像,五官俱全 |
|
||||
| **`badge`** | 完全沒有參考圖 | 雙色漸層 + 編號前兩個字母 |
|
||||
|
||||
缺工具時 CLI **會印出安裝指令**再退回 `portrait`,不會靜默降級:
|
||||
**找到的圖片只能當底稿**:產出的 SVG 沒有 `<image>`、沒有 base64、沒有外連,每個像素都是畫出來的。
|
||||
|
||||
裁底稿需要的工具缺了,CLI **會印出安裝指令**,不會靜默降級:
|
||||
|
||||
```bash
|
||||
python3 -m venv ~/.cache/jsc-persona/venv
|
||||
@@ -187,24 +197,23 @@ curl -sL -o ~/.cache/jsc-persona/lbpcascade_animeface.xml \
|
||||
- PNG 由**自寫的柵格器**畫出(3× 超取樣 + 盒式縮減當反鋸齒),再用 `zlib` 手工組出
|
||||
IHDR/IDAT/IEND 與 CRC32。這台機器沒有 rsvg/inkscape/imagemagick,也沒有影像函式庫,
|
||||
而本專案禁止 npm 依賴——所以就自己畫。
|
||||
- **為什麼沒有 emoji、也不是把照片本身當圖示**:環境裡沒有任何影像解碼器
|
||||
(rsvg/imagemagick/Pillow/ffmpeg 都沒有),JPEG/WebP 讀不進來,無法把原圖轉成 PNG;
|
||||
而且把他人的美術作品原樣放進存取庫是散布、不是引用。**取配色**是有依據又不搬運原圖的做法。
|
||||
emoji 同理無法柵格化,但仍參與雜湊配色。
|
||||
- **為什麼不直接用找到的圖**:那是別人的美術作品。底稿只用來「看」,圖示由本工具重畫。
|
||||
- **為什麼沒有 emoji**:把 emoji 畫進 PNG 需要字型柵格化,環境裡連 emoji 字型都沒有;
|
||||
emoji 仍參與雜湊配色。
|
||||
- 圖示屬於低頻資料 → `icon.svg` 與 `icon.png` 都同步到 **Wiki 區**,並自動產生一頁 **Icon**
|
||||
展示兩種格式與來源;PNG 同時設成 Gitea **存取庫頭像**。
|
||||
|
||||
```bash
|
||||
# 先看參考圖裡有幾張臉(多角色的主視覺務必先看)
|
||||
node scripts/persona.mjs icon faces --session <id> --photo "<圖片網址>"
|
||||
node scripts/persona.mjs icon faces --session <id> --photo "<圖片網址>"
|
||||
node scripts/persona.mjs icon headshot --session <id> --photo "<圖片網址>" --pick 1
|
||||
|
||||
# 裁臉 + 取色(--palette 必須配 --source-url)
|
||||
node scripts/persona.mjs icon generate --session <id> --force \
|
||||
--photo "<圖片網址>" --pick 1 \
|
||||
--palette "hair=#d9a45b,eye=#9e5b3e,accent=#c0392b,secondary=#e77a8e,light=#f2ebe3" \
|
||||
--source-url "<官方視覺的網址>" --source-note "<作品(年份)+造型描述>"
|
||||
--palette "hair=#d9a45b,eye=#9e5b3e,accent=#c0392b,secondary=#e77a8e,light=#f2ebe3,skin=#f7ddc4" \
|
||||
--features "hairstyle=straight,length=very-long,fringe=parted,eyes=almond,expression=calm,collar=v,ahoge=yes" \
|
||||
--source-url "<底稿那張圖的網址>" --source-note "<作品(年份)+重繪依據>"
|
||||
|
||||
node scripts/persona.mjs icon show --session <id> # 看樣式、配色、來源與裁切框
|
||||
node scripts/persona.mjs icon show --session <id> # 樣式、配色、特徵、來源
|
||||
node scripts/persona.mjs sync verify --session <id> --area wiki # 確認 Wiki 真的同步了
|
||||
```
|
||||
|
||||
## 人格編號與 Gitea 儲存
|
||||
@@ -369,7 +378,7 @@ node scripts/persona.mjs said check --session <id> --text "<話>" # 這句是
|
||||
node scripts/persona.mjs room script --session <id> --room <room> # 乾淨對話稿(劇場模式用)
|
||||
node scripts/persona.mjs export --session <id> --out lumi.json # 離線搬家(單檔)
|
||||
node scripts/persona.mjs sync status --session <id> # Gitea 同步狀態
|
||||
node scripts/selftest.mjs # 148 項驗證:鎖、隔離、情緒、固化、說話節制、劇場模式、匯出匯入、編號與 Gitea 分區、形象圖與裁臉、hooks
|
||||
node scripts/selftest.mjs # 161 項驗證:鎖、隔離、情緒、固化、說話節制、劇場模式、匯出匯入、編號與 Gitea、形象圖重繪與 Wiki 同步、hooks
|
||||
```
|
||||
|
||||
檔案結構:`scripts/persona-lib.mjs`(核心:鎖/隔離/情緒/記憶)、`scripts/persona.mjs`(CLI)、
|
||||
|
||||
Reference in New Issue
Block a user