@my-life-buddies/cli 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -10
- package/dist/bin/buddy.js +9 -0
- package/dist/bin/buddy.js.map +3 -3
- package/dist/bin/core.js +695 -412
- package/dist/bin/core.js.map +4 -4
- package/dist/bin/preview.js +12 -1
- package/dist/bin/preview.js.map +2 -2
- package/dist/web/app.css +4 -0
- package/dist/web/app.js +14 -1
- package/dist/web/index.html +1 -1
- package/dist/web/widgets.js +1 -1
- package/package.json +3 -3
- package/resources/dada-object-avatar/SKILL.md +37 -0
- package/resources/dada-object-avatar/agents/openai.yaml +4 -0
- package/resources/dada-object-avatar/assets/examples/cat.png +0 -0
- package/resources/dada-object-avatar/assets/examples/cooking.png +0 -0
- package/resources/dada-object-avatar/assets/examples/divination.png +0 -0
- package/resources/dada-object-avatar/assets/examples/doctor.png +0 -0
- package/resources/dada-object-avatar/assets/examples/relationship.png +0 -0
- package/resources/dada-object-avatar/assets/examples/work.png +0 -0
- package/resources/dada-object-avatar/assets/preview.png +0 -0
- package/resources/dada-object-avatar/references/evaluation-rubric.md +22 -0
- package/resources/dada-object-avatar/references/examples.json +8 -0
- package/resources/dada-object-avatar/references/prompt-template.md +27 -0
- package/resources/dada-object-avatar/references/style-system.md +54 -0
- package/resources/dada-object-avatar/references/subject-design.md +23 -0
- package/resources/dada-object-avatar/references/training-guide.md +14 -0
- package/resources/dada-object-avatar/references/training-log.jsonl +0 -0
- package/resources/dada-object-avatar/references/training-record.schema.json +20 -0
- package/resources/dada-object-avatar/scripts/choose_gaze.py +36 -0
- package/resources/dada-object-avatar/scripts/record_example.py +22 -0
- package/resources/dada-object-avatar/scripts/validate_png.py +52 -0
- package/resources/dada-object-avatar.manifest.json +85 -0
package/dist/web/app.css
CHANGED
|
@@ -513,3 +513,7 @@
|
|
|
513
513
|
*, *::before, *::after { animation-duration: 120ms !important; animation-iteration-count: 1 !important; transition-duration: 120ms !important; }
|
|
514
514
|
}
|
|
515
515
|
}
|
|
516
|
+
|
|
517
|
+
.message-avatar img { width: 100%; height: 100%; object-fit: contain; border-radius: inherit; }
|
|
518
|
+
#buddy-profile-avatar { width: 32px; height: 32px; object-fit: contain; border-radius: 50%; }
|
|
519
|
+
#buddy-profile-avatar[hidden] { display: none; }
|
package/dist/web/app.js
CHANGED
|
@@ -159,7 +159,14 @@
|
|
|
159
159
|
class: `message-avatar ${role === "user" ? "person-avatar" : "buddy-message-avatar"}`,
|
|
160
160
|
"aria-hidden": "true",
|
|
161
161
|
});
|
|
162
|
-
if (role !== "user")
|
|
162
|
+
if (role !== "user") {
|
|
163
|
+
const picture = (state.dev.ready?.buddy || state.buddy)?.avatarPreview;
|
|
164
|
+
if (picture) {
|
|
165
|
+
const image = node("img", {src: picture, alt: ""});
|
|
166
|
+
image.addEventListener("error", () => { avatar.textContent = "搭"; }, {once: true});
|
|
167
|
+
avatar.append(image);
|
|
168
|
+
} else avatar.textContent = "搭";
|
|
169
|
+
}
|
|
163
170
|
return avatar;
|
|
164
171
|
}
|
|
165
172
|
|
|
@@ -207,6 +214,12 @@
|
|
|
207
214
|
elements.projectName.textContent = name;
|
|
208
215
|
elements.buddyName.textContent = name;
|
|
209
216
|
elements.buddyName.title = buddy?.tagline || "";
|
|
217
|
+
const picture = document.querySelector("#buddy-profile-avatar");
|
|
218
|
+
if (picture) {
|
|
219
|
+
picture.hidden = !buddy?.avatarPreview;
|
|
220
|
+
if (buddy?.avatarPreview) picture.src = buddy.avatarPreview;
|
|
221
|
+
else picture.removeAttribute("src");
|
|
222
|
+
}
|
|
210
223
|
const note = document.querySelector(".preview-note");
|
|
211
224
|
if (note) note.textContent = buddy ? (buddy.isDev ? "开发预览版 · 仅你可见" : "搭搭 App") : "搭搭 App · DEV";
|
|
212
225
|
elements.environmentRuntime.textContent = "Node.js · Buddy Runtime";
|
package/dist/web/index.html
CHANGED
|
@@ -197,7 +197,7 @@
|
|
|
197
197
|
<button class="back-chevron" type="button" aria-label="返回(预览中不可用)" disabled>
|
|
198
198
|
<svg aria-hidden="true" viewBox="0 0 24 24"><path d="m15 18-6-6 6-6"/></svg>
|
|
199
199
|
</button>
|
|
200
|
-
<div class="buddy-identity"><h3 id="buddy-name">我的搭子</h3><p id="buddy-status" class="sr-only">DEV 未连接</p></div>
|
|
200
|
+
<img id="buddy-profile-avatar" alt="搭子头像" hidden><div class="buddy-identity"><h3 id="buddy-name">我的搭子</h3><p id="buddy-status" class="sr-only">DEV 未连接</p></div>
|
|
201
201
|
<div class="chat-navigation-actions" aria-hidden="true">
|
|
202
202
|
<button class="chat-more" type="button" aria-label="更多(预览中不可用)" disabled tabindex="-1">
|
|
203
203
|
<svg viewBox="0 0 24 24"><circle cx="5" cy="12" r="1.3"/><circle cx="12" cy="12" r="1.3"/><circle cx="19" cy="12" r="1.3"/></svg>
|
package/dist/web/widgets.js
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
for (const item of items) { const b = button(item.title + ' ›', () => { choices.remove(); pill.setAttribute('aria-expanded', 'false'); void open(item); }); b.setAttribute('role', 'menuitem'); choices.append(b); }
|
|
31
31
|
shortcut.append(choices); pill.setAttribute('aria-expanded', 'true'); choices.firstChild?.focus();
|
|
32
32
|
}, 'widget-pill');
|
|
33
|
-
const image = avatar(); image.
|
|
33
|
+
const image = avatar(); image.classList.add('widget-pill-avatar');
|
|
34
34
|
pill.append(image, el('span', 'widget-pill-title', items.length === 1 ? items[0].title : '全部小挂件'));
|
|
35
35
|
if (items.length > 1) { pill.append(el('span', 'widget-chevron', '⌄')); pill.setAttribute('aria-haspopup', 'menu'); pill.setAttribute('aria-expanded', 'false'); }
|
|
36
36
|
shortcut.append(pill);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@my-life-buddies/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "搭搭 Developer Platform 命令行工具",
|
|
6
6
|
"publishConfig": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"ws": "8.21.3"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@buddy/cli-core": "0.
|
|
43
|
-
"@buddy/preview": "0.
|
|
42
|
+
"@buddy/cli-core": "0.11.0",
|
|
43
|
+
"@buddy/preview": "0.11.0"
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dada-object-avatar
|
|
3
|
+
description: "Generate or revise Dada-style retro object avatars from a companion name and Emoji. Use when the user wants the current unified object-character system: recognizable semantic object, varied coordinated eyes, two lateral three-digit hands, restrained retro material, circular-crop-safe composition, and a genuine transparent PNG."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 搭搭复古物件头像
|
|
7
|
+
|
|
8
|
+
把搭子名字与 Emoji 转译成一个可辨认的物件角色。保留“人”的眼神与姿态,同时避免真人头像和写实动物身体。
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
1. Read [references/style-system.md](references/style-system.md). Treat its invariants as the current accepted style.
|
|
13
|
+
2. For a new subject, read [references/subject-design.md](references/subject-design.md) and choose one primary object plus at most two identity details.
|
|
14
|
+
3. Before generation, allocate the character's shared gaze direction with `python3 scripts/choose_gaze.py --recent <directions>`. Pass recent gallery directions so neighboring characters do not repeat.
|
|
15
|
+
4. Read [references/prompt-template.md](references/prompt-template.md), fill the subject, palette, gaze and detail hierarchy fields, then invoke the built-in image generation tool. Use the closest retained asset from `assets/examples/` as the style reference. For revisions, also include the exact previous subject image as the first reference and state which properties must remain locked.
|
|
16
|
+
5. Inspect the result on both light and dark backgrounds and inside a centered circular crop. Confirm recognizable identity, coordinated gaze, hand anatomy, detail spacing and continuous body volume.
|
|
17
|
+
6. Deliver a genuine RGBA PNG. Run `python3 scripts/validate_png.py <image.png>` after any matte removal or alpha reconstruction. A checkerboard drawn into RGB pixels is not transparency.
|
|
18
|
+
7. When the user gives feedback, record the concrete trigger, failure and accepted correction with `python3 scripts/record_example.py ...`. Use [references/training-record.schema.json](references/training-record.schema.json) as the stable training format.
|
|
19
|
+
|
|
20
|
+
For later style training and promotion of new canonical examples, follow [references/training-guide.md](references/training-guide.md).
|
|
21
|
+
|
|
22
|
+
## Generation invariants
|
|
23
|
+
|
|
24
|
+
- One square image contains one character. The central body continues naturally through the bottom edge; the top retains transparent breathing room.
|
|
25
|
+
- The semantic object remains legible at avatar size. Do not replace it with an unrelated blob or generic person.
|
|
26
|
+
- Volume comes from continuous geometry, overlap, structural turns and plausible attachment. Lighting only explains the geometry. Do not add seams to simulate thickness.
|
|
27
|
+
- Use ivory embedded eye whites and black pupils. Both whites and pupils vary in size, aspect ratio, tilt and local position. Assign one shared gaze vector per character; neighboring characters use different directions.
|
|
28
|
+
- Add exactly two small lateral hands below eye level. Each hand has exactly three digits total: one broad thumb and two smaller fingers.
|
|
29
|
+
- Nearby handles, lugs, clasps, symbols and ornaments remain secondary. If near a hand, make them roughly 60–75% of hand width and separate them vertically by at least half a hand height.
|
|
30
|
+
- No eyebrows, mouth or nose by default. No legs or feet. No realistic anatomy, dirty texture, dense skin grain, text or watermark.
|
|
31
|
+
- Use genuine transparency around the silhouette and through real openings. Eye whites and subject remain opaque.
|
|
32
|
+
|
|
33
|
+
## Iteration boundary
|
|
34
|
+
|
|
35
|
+
Lock accepted properties. If feedback concerns only gaze, edit only the eyes. If it concerns volume, keep silhouette, identity details and proportions unless the user explicitly requests a redesign. Generate one corrected candidate per subject before expanding the family.
|
|
36
|
+
|
|
37
|
+
For scoring or dataset curation, read [references/evaluation-rubric.md](references/evaluation-rubric.md).
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Evaluation rubric
|
|
2
|
+
|
|
3
|
+
Score each category 0–2. Accept only when all hard gates pass and the total is at least 13/16.
|
|
4
|
+
|
|
5
|
+
| Category | 0 | 1 | 2 |
|
|
6
|
+
|---|---|---|---|
|
|
7
|
+
| Semantic identity | unclear/generic | recognizable with explanation | instantly recognizable at avatar size |
|
|
8
|
+
| Structural volume | flat, seam-based | partial believable depth | continuous plausible solid volume |
|
|
9
|
+
| Eye morphology | mirrored/uniform | one layer varies | whites and pupils both vary |
|
|
10
|
+
| Gaze | crossed/repeated family direction | coordinated but generic | coordinated and distinct from neighbors |
|
|
11
|
+
| Hands | wrong count/anatomy | minor ambiguity | exactly two lateral three-digit hands |
|
|
12
|
+
| Detail hierarchy | crowded/equal scale | acceptable spacing | clear 60–75% secondary scale and separation |
|
|
13
|
+
| Circular framing | clipped/blank bottom | usable | safe details and natural 6-o'clock fill |
|
|
14
|
+
| Material/color | dirty or wrong association | acceptable | restrained texture and intentional semantics |
|
|
15
|
+
|
|
16
|
+
Hard gates:
|
|
17
|
+
|
|
18
|
+
- genuine RGBA transparency;
|
|
19
|
+
- four transparent corners;
|
|
20
|
+
- subject reaches the lower-center band;
|
|
21
|
+
- no checkerboard embedded in output;
|
|
22
|
+
- no extra fingers, legs, mouth, nose, eyebrows, text or watermark.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
[
|
|
2
|
+
{"file":"assets/examples/cat.png","subject":"短毛猫铲屎官","gaze":"right","role":"seamless animal-object volume, thin ears, prop interaction"},
|
|
3
|
+
{"file":"assets/examples/cooking.png","subject":"小涂阿姨","gaze":"lower-left","role":"small high lugs separated from lower hands"},
|
|
4
|
+
{"file":"assets/examples/relationship.png","subject":"情感专家","gaze":"left","role":"bright coral semantic color and complete heart silhouette"},
|
|
5
|
+
{"file":"assets/examples/doctor.png","subject":"林医生","gaze":"lower-right","role":"semantic gaze toward a small medical symbol"},
|
|
6
|
+
{"file":"assets/examples/work.png","subject":"工作那些事","gaze":"left","role":"compact clasps and horizontal gaze"},
|
|
7
|
+
{"file":"assets/examples/divination.png","subject":"塔罗星人","gaze":"upper-left","role":"secondary ornament and distinct gaze"}
|
|
8
|
+
]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Prompt template
|
|
2
|
+
|
|
3
|
+
Use the closest accepted example as the style reference. For an edit, make the current subject the first reference.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
Create a square Dada-style retro object avatar for {NAME} {EMOJI}.
|
|
7
|
+
|
|
8
|
+
SUBJECT
|
|
9
|
+
Use {PRIMARY_OBJECT} as the recognizable primary silhouette. Preserve/add only {DETAIL_1} and {DETAIL_2}. Use {PALETTE} with restrained {MATERIAL}. Avoid {UNWANTED_ASSOCIATION}.
|
|
10
|
+
|
|
11
|
+
VOLUME
|
|
12
|
+
Build one continuous believable volume with rounded structural turns, overlap and physically plausible attachment. Do not add seams, panel lines or exaggerated highlights to fake thickness.
|
|
13
|
+
|
|
14
|
+
EYES
|
|
15
|
+
Use embedded warm-ivory eye whites and matte-black pupils. Do not mirror the pair. Make the whites differ by about 8–18% in size/aspect and 4–10 degrees in tilt. Make the pupils differ by about 10–18% in size/aspect and place them differently within their whites. Assign the whole character a coordinated {GAZE_DIRECTION} gaze; both pupils follow that vector without crossing or diverging. This direction must differ from neighboring gallery characters.
|
|
16
|
+
|
|
17
|
+
HANDS AND DETAILS
|
|
18
|
+
Add exactly two small lateral hands below eye level. Each has exactly three digits total: one broad thumb plus two smaller rounded fingers. Hand width is about 12–15% of body width. Any nearby handle, lug, clasp, symbol or ornament is 60–75% of hand width and at least half a hand-height away. Keep details secondary and unobstructed.
|
|
19
|
+
|
|
20
|
+
FRAMING
|
|
21
|
+
One character, 1:1. About 88% visual scale. Keep every hand, handle and prop inside a centered circular crop. The central body continues naturally through the bottom edge; no transparent strip or floating base.
|
|
22
|
+
|
|
23
|
+
OUTPUT
|
|
24
|
+
Genuine RGBA transparent PNG. Alpha 0 outside the silhouette and through real openings. Eye whites and subject remain opaque. No checkerboard, backdrop, floor, external shadow, mouth, nose, eyebrows, legs, feet, text or watermark.
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
For an eye-only revision, explicitly say: `Preserve every non-eye pixel and change only eye whites, pupils and gaze.` Then specify one direction rather than asking for generic randomness.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Style system
|
|
2
|
+
|
|
3
|
+
## 1. Identity
|
|
4
|
+
|
|
5
|
+
Start from the companion role, not the literal title. Convert it to a familiar object silhouette:
|
|
6
|
+
|
|
7
|
+
- cooking → rounded enamel pot
|
|
8
|
+
- health/doctor → first-aid case
|
|
9
|
+
- work → briefcase
|
|
10
|
+
- divination → tarot card
|
|
11
|
+
- pet care → simplified cat-shaped object with one litter scoop
|
|
12
|
+
- relationship → complete graphic heart
|
|
13
|
+
- travel → suitcase
|
|
14
|
+
- fitness → kettlebell
|
|
15
|
+
|
|
16
|
+
Use one dominant silhouette and no more than two secondary identity details. A user-provided mapping overrides this list.
|
|
17
|
+
|
|
18
|
+
## 2. Shape and volume
|
|
19
|
+
|
|
20
|
+
Use orderly, softly rounded geometry. Show thickness through front/side relationships, overlap, rim depth and believable attachment. Do not use a decorative center seam, panel line or strong gradient as a substitute for form. Thin structures such as cat ears must stay physically plausible and naturally join the body.
|
|
21
|
+
|
|
22
|
+
## 3. Materials and color
|
|
23
|
+
|
|
24
|
+
Use restrained retro resin, enamel, soft metal or leather-like material with sparse fine grain. Prefer warm Memphis-adjacent colors: cream, teal, tomato red, coral, mustard, cocoa, plum and charcoal. Check semantic associations: a heart should use bright coral or tomato red rather than dark liver-like burgundy.
|
|
25
|
+
|
|
26
|
+
## 4. Eye system
|
|
27
|
+
|
|
28
|
+
Eye whites are warm ivory and slightly embedded; pupils are matte black.
|
|
29
|
+
|
|
30
|
+
For each pair:
|
|
31
|
+
|
|
32
|
+
- white size or aspect difference: approximately 8–18%
|
|
33
|
+
- white tilt difference: approximately 4–10 degrees
|
|
34
|
+
- pupil size or aspect difference: approximately 10–18%
|
|
35
|
+
- pupil local placement: different within each white, but both follow one shared gaze vector
|
|
36
|
+
|
|
37
|
+
Choose one vector from `front`, `left`, `right`, `upper-left`, `upper-right`, `lower-left`, `lower-right`. Do not repeat the same or near-identical vector on neighboring gallery cards. Do not default the family to upper-right. Both pupils must remain coordinated; avoid crossed or divergent eyes.
|
|
38
|
+
|
|
39
|
+
## 5. Hands and detail hierarchy
|
|
40
|
+
|
|
41
|
+
Place one hand on each outer side below eye level. Use very short arms. Each hand has exactly three digits total: one broad thumb, about 1.4 times a small finger, and two rounded smaller fingers. Hand width is about 12–15% of body width. Hands turn slightly sideways; no front-facing open palm.
|
|
42
|
+
|
|
43
|
+
When a handle, lug, clasp or ornament approaches a hand:
|
|
44
|
+
|
|
45
|
+
- reduce the detail to roughly 60–75% of hand width;
|
|
46
|
+
- separate it by at least half a hand height;
|
|
47
|
+
- move it to a different vertical zone if crowding remains;
|
|
48
|
+
- preserve recognizability before decoration.
|
|
49
|
+
|
|
50
|
+
## 6. Framing and alpha
|
|
51
|
+
|
|
52
|
+
Use a 1:1 master. Target roughly 88% of the prior oversized-object scale. Keep hands, handles and identity props inside a centered circle. The main body passes naturally through the square bottom edge and fills the circle at 6 o'clock. Leave no transparent horizontal strip below the body and no floating base.
|
|
53
|
+
|
|
54
|
+
Export true RGBA. All four corners should be alpha 0. Real handle openings and enclosed gaps should be transparent. Never render a checkerboard as background pixels.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Subject design
|
|
2
|
+
|
|
3
|
+
Use this decision order for a new companion:
|
|
4
|
+
|
|
5
|
+
1. **Role verb:** what does this companion help the user do?
|
|
6
|
+
2. **Primary object:** which single object communicates that action fastest at 64 px?
|
|
7
|
+
3. **Identity details:** choose one or two details that disambiguate the object.
|
|
8
|
+
4. **Conflict check:** compare every detail with the hands. Reduce or move any feature with similar size and proximity.
|
|
9
|
+
5. **Palette check:** confirm the color evokes the intended emotion rather than food, anatomy or danger by accident.
|
|
10
|
+
6. **Gaze:** allocate a direction that differs from the neighboring examples and, when useful, points toward a semantic detail.
|
|
11
|
+
|
|
12
|
+
Keep the primary silhouette stable through revisions. Character variation comes from object shape, palette, eye morphology, gaze and one meaningful pose, rather than extra facial features.
|
|
13
|
+
|
|
14
|
+
## Existing accepted assignments
|
|
15
|
+
|
|
16
|
+
| Subject | Primary object | Details | Gaze |
|
|
17
|
+
|---|---|---|---|
|
|
18
|
+
| 短毛猫铲屎官 | cream cat-shaped object | thin ears, coral scoop | toward scoop |
|
|
19
|
+
| 小涂阿姨 | tomato enamel pot | cream lid, small high lugs | attentive inward/downward |
|
|
20
|
+
| 情感专家 | bright coral heart | complete rounded lobes | gentle side glance |
|
|
21
|
+
| 林医生 | cream first-aid case | teal handle/band, coral cross | lower-right toward cross |
|
|
22
|
+
| 工作那些事 | cocoa briefcase | compact handle, small brass clasps | horizontal left |
|
|
23
|
+
| 塔罗星人 | plum tarot card | thin gold border, small crescent | upper-left |
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Iterative style training
|
|
2
|
+
|
|
3
|
+
Treat training as controlled prompt-and-reference refinement:
|
|
4
|
+
|
|
5
|
+
1. Save every candidate prompt and output path.
|
|
6
|
+
2. Record the user's verdict and exact visible failure with `scripts/record_example.py`; avoid vague labels such as “bad style”.
|
|
7
|
+
3. On revision, list the accepted properties that must remain locked and change only the rejected property.
|
|
8
|
+
4. Promote an image to `assets/examples/` only after it passes the rubric and the user accepts the direction.
|
|
9
|
+
5. Add the promoted image to `references/examples.json` with its subject, gaze and the single rule it demonstrates best.
|
|
10
|
+
6. Keep complementary examples. Do not retain several samples that teach the same gaze and silhouette while leaving other cases uncovered.
|
|
11
|
+
7. Before changing a global rule, confirm the same failure appears in more than one subject. Keep one-off feedback in the subject prompt.
|
|
12
|
+
8. Re-run `scripts/validate_png.py` on every retained PNG and forward-test one unseen companion after a global rule change.
|
|
13
|
+
|
|
14
|
+
A useful JSONL record contains the original prompt, output, verdict, concrete feedback, failure tags, accepted correction and locked properties. This supports later retrieval, preference modeling or manual dataset conversion without mixing rejected and accepted examples.
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "Dada Object Avatar Training Record",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": ["timestamp", "subject", "prompt", "output", "verdict"],
|
|
6
|
+
"properties": {
|
|
7
|
+
"timestamp": {"type": "string", "format": "date-time"},
|
|
8
|
+
"subject": {"type": "string"},
|
|
9
|
+
"emoji": {"type": "string"},
|
|
10
|
+
"gaze": {"enum": ["front", "left", "right", "upper-left", "upper-right", "lower-left", "lower-right"]},
|
|
11
|
+
"prompt": {"type": "string"},
|
|
12
|
+
"output": {"type": "string"},
|
|
13
|
+
"verdict": {"enum": ["accepted", "rejected", "needs-revision"]},
|
|
14
|
+
"feedback": {"type": "string"},
|
|
15
|
+
"failure_tags": {"type": "array", "items": {"type": "string"}},
|
|
16
|
+
"accepted_correction": {"type": "string"},
|
|
17
|
+
"locked_properties": {"type": "array", "items": {"type": "string"}}
|
|
18
|
+
},
|
|
19
|
+
"additionalProperties": false
|
|
20
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Choose a coordinated gaze direction that differs from recent gallery items."""
|
|
3
|
+
import argparse, hashlib, json, math, random
|
|
4
|
+
|
|
5
|
+
VECTORS = {
|
|
6
|
+
"front": (0.0, 0.0), "left": (-1.0, 0.0), "right": (1.0, 0.0),
|
|
7
|
+
"upper-left": (-0.707, -0.707), "upper-right": (0.707, -0.707),
|
|
8
|
+
"lower-left": (-0.707, 0.707), "lower-right": (0.707, 0.707),
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
def near(a, b):
|
|
12
|
+
if a == b: return True
|
|
13
|
+
if "front" in (a, b): return False
|
|
14
|
+
ax, ay = VECTORS[a]; bx, by = VECTORS[b]
|
|
15
|
+
return ax * bx + ay * by > 0.70
|
|
16
|
+
|
|
17
|
+
def main():
|
|
18
|
+
ap = argparse.ArgumentParser()
|
|
19
|
+
ap.add_argument("--recent", default="", help="Comma-separated recent directions")
|
|
20
|
+
ap.add_argument("--seed", default="", help="Optional reproducible seed")
|
|
21
|
+
args = ap.parse_args()
|
|
22
|
+
recent = [x.strip() for x in args.recent.split(",") if x.strip()]
|
|
23
|
+
unknown = [x for x in recent if x not in VECTORS]
|
|
24
|
+
if unknown: ap.error(f"unknown directions: {', '.join(unknown)}")
|
|
25
|
+
last = recent[-1] if recent else None
|
|
26
|
+
candidates = [d for d in VECTORS if not any(near(d, previous) for previous in recent[-3:])]
|
|
27
|
+
if not candidates: candidates = [d for d in VECTORS if d != last]
|
|
28
|
+
rng = random.Random(int(hashlib.sha256(args.seed.encode()).hexdigest(), 16) if args.seed else None)
|
|
29
|
+
direction = rng.choice(candidates)
|
|
30
|
+
print(json.dumps({
|
|
31
|
+
"direction": direction,
|
|
32
|
+
"vector": VECTORS[direction],
|
|
33
|
+
"prompt": f"Assign one coordinated {direction.upper()} gaze to this character; both pupils follow this vector without crossing or diverging."
|
|
34
|
+
}, ensure_ascii=False))
|
|
35
|
+
|
|
36
|
+
if __name__ == "__main__": main()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Append one structured feedback example to a JSONL training log."""
|
|
3
|
+
import argparse, datetime, json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
def split(value): return [x.strip() for x in value.split(',') if x.strip()]
|
|
7
|
+
|
|
8
|
+
def main():
|
|
9
|
+
ap=argparse.ArgumentParser()
|
|
10
|
+
ap.add_argument('--log',required=True); ap.add_argument('--subject',required=True); ap.add_argument('--emoji',default='')
|
|
11
|
+
ap.add_argument('--gaze',choices=['front','left','right','upper-left','upper-right','lower-left','lower-right'])
|
|
12
|
+
ap.add_argument('--prompt-file',required=True); ap.add_argument('--output',required=True)
|
|
13
|
+
ap.add_argument('--verdict',required=True,choices=['accepted','rejected','needs-revision'])
|
|
14
|
+
ap.add_argument('--feedback',default=''); ap.add_argument('--failure-tags',default=''); ap.add_argument('--accepted-correction',default=''); ap.add_argument('--locked-properties',default='')
|
|
15
|
+
a=ap.parse_args()
|
|
16
|
+
record={"timestamp":datetime.datetime.now(datetime.timezone.utc).isoformat(),"subject":a.subject,"emoji":a.emoji,"prompt":Path(a.prompt_file).read_text(),"output":a.output,"verdict":a.verdict,"feedback":a.feedback,"failure_tags":split(a.failure_tags),"accepted_correction":a.accepted_correction,"locked_properties":split(a.locked_properties)}
|
|
17
|
+
if a.gaze: record['gaze']=a.gaze
|
|
18
|
+
log=Path(a.log); log.parent.mkdir(parents=True,exist_ok=True)
|
|
19
|
+
with log.open('a',encoding='utf-8') as f: f.write(json.dumps(record,ensure_ascii=False)+'\n')
|
|
20
|
+
print(json.dumps(record,ensure_ascii=False,indent=2))
|
|
21
|
+
|
|
22
|
+
if __name__=='__main__': main()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Validate the alpha and bottom-flow invariants of an 8-bit RGBA PNG using stdlib only."""
|
|
3
|
+
import argparse, json, struct, sys, zlib
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
def paeth(a, b, c):
|
|
7
|
+
p=a+b-c; pa=abs(p-a); pb=abs(p-b); pc=abs(p-c)
|
|
8
|
+
return a if pa <= pb and pa <= pc else b if pb <= pc else c
|
|
9
|
+
|
|
10
|
+
def decode(path):
|
|
11
|
+
blob=Path(path).read_bytes()
|
|
12
|
+
if blob[:8] != b'\x89PNG\r\n\x1a\n': raise ValueError('not a PNG')
|
|
13
|
+
pos=8; parts=[]; meta=None
|
|
14
|
+
while pos < len(blob):
|
|
15
|
+
length=struct.unpack('>I', blob[pos:pos+4])[0]; kind=blob[pos+4:pos+8]; data=blob[pos+8:pos+8+length]; pos += 12+length
|
|
16
|
+
if kind == b'IHDR': meta=struct.unpack('>IIBBBBB', data)
|
|
17
|
+
elif kind == b'IDAT': parts.append(data)
|
|
18
|
+
elif kind == b'IEND': break
|
|
19
|
+
if not meta: raise ValueError('missing IHDR')
|
|
20
|
+
w,h,depth,color,comp,flt,interlace=meta
|
|
21
|
+
if (depth,color,comp,flt,interlace)!=(8,6,0,0,0): raise ValueError('requires non-interlaced 8-bit RGBA PNG')
|
|
22
|
+
packed=zlib.decompress(b''.join(parts)); stride=w*4
|
|
23
|
+
if len(packed) != h*(stride+1): raise ValueError('unexpected scanline length')
|
|
24
|
+
rows=[]; offset=0; prior=bytearray(stride)
|
|
25
|
+
for _ in range(h):
|
|
26
|
+
f=packed[offset]; offset+=1; scan=bytearray(packed[offset:offset+stride]); offset+=stride
|
|
27
|
+
recon=bytearray(stride)
|
|
28
|
+
for i,x in enumerate(scan):
|
|
29
|
+
a=recon[i-4] if i>=4 else 0; b=prior[i]; c=prior[i-4] if i>=4 else 0
|
|
30
|
+
pred=(0,a,b,(a+b)//2,paeth(a,b,c))[f] if f <= 4 else (_ for _ in ()).throw(ValueError(f'bad filter {f}'))
|
|
31
|
+
recon[i]=(x+pred)&255
|
|
32
|
+
rows.append(recon); prior=recon
|
|
33
|
+
return w,h,rows
|
|
34
|
+
|
|
35
|
+
def main():
|
|
36
|
+
ap=argparse.ArgumentParser(); ap.add_argument('png'); ap.add_argument('--min-transparent',type=float,default=0.10)
|
|
37
|
+
args=ap.parse_args()
|
|
38
|
+
try:
|
|
39
|
+
w,h,rows=decode(args.png)
|
|
40
|
+
alphas=[row[x] for row in rows for x in range(3,w*4,4)]
|
|
41
|
+
corners=[rows[0][3],rows[0][(w-1)*4+3],rows[-1][3],rows[-1][(w-1)*4+3]]
|
|
42
|
+
lo=int(w*.375); hi=int(w*.625)
|
|
43
|
+
bottom_solid=any(rows[-1][x*4+3]==255 for x in range(lo,hi))
|
|
44
|
+
transparent=sum(a==0 for a in alphas)/len(alphas)
|
|
45
|
+
checks={"rgba":True,"transparent_fraction":transparent,"corners_transparent":all(a==0 for a in corners),"bottom_center_band_solid":bottom_solid}
|
|
46
|
+
ok=transparent>=args.min_transparent and checks['corners_transparent'] and bottom_solid
|
|
47
|
+
print(json.dumps({"file":str(Path(args.png).resolve()),"size":[w,h],"ok":ok,"checks":checks},indent=2))
|
|
48
|
+
raise SystemExit(0 if ok else 1)
|
|
49
|
+
except Exception as e:
|
|
50
|
+
print(json.dumps({"file":args.png,"ok":False,"error":str(e)},indent=2)); raise SystemExit(1)
|
|
51
|
+
|
|
52
|
+
if __name__=='__main__': main()
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"source": "Developer-provided dada-object-avatar skill, imported 2026-09-15 without modifications",
|
|
3
|
+
"files": [
|
|
4
|
+
{
|
|
5
|
+
"path": "SKILL.md",
|
|
6
|
+
"sha256": "2389678c8a067e6f989d0f0d1e57a4ac64c29c21fd49360ade7b99e678c9f1d7"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"path": "agents/openai.yaml",
|
|
10
|
+
"sha256": "5732e15644f2f2255ff8ea066ab6f5ee79160b3735bd57683c40aa2a7074a633"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"path": "assets/examples/cat.png",
|
|
14
|
+
"sha256": "b1e7e22b1b5560965bc9f21f3f1ceca2ceacafc3ebac2dd46a98a8ecd821a7e9"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"path": "assets/examples/cooking.png",
|
|
18
|
+
"sha256": "2323e8d020cafce1062e4c40583cb500576d5c7fd8a49eb8b51acea4cff7e79a"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"path": "assets/examples/divination.png",
|
|
22
|
+
"sha256": "d597713a8e6cbd90ebaba43367be138f59ed5895c36121f1b9f4caaf25a1a814"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"path": "assets/examples/doctor.png",
|
|
26
|
+
"sha256": "bfcb24b30246b9f8a9787bb0429272402139d08e8d9fb7a366bf1453187ec180"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"path": "assets/examples/relationship.png",
|
|
30
|
+
"sha256": "eb0892f0d973d6f1993c0e30ff7a44bfb55a7c6c8839d075ca2b5f18e6e4343a"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"path": "assets/examples/work.png",
|
|
34
|
+
"sha256": "33d63b56bca1b098a4b2edb510e318a391c39e334b035cded78ac6aede91e080"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"path": "assets/preview.png",
|
|
38
|
+
"sha256": "56d660a0d848affc6094cb12f09a006e993a9fd2d52bfe0a5e8bb87f9004b3cd"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"path": "references/evaluation-rubric.md",
|
|
42
|
+
"sha256": "9342dde9b5cf5fd1958554de3cf8c6e29d11b0606a045c5296ac54830e736573"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"path": "references/examples.json",
|
|
46
|
+
"sha256": "488a7b3bcb6950cdcae0c9d49b559e94ca50f56da08f10e155e64dde50aaffcb"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"path": "references/prompt-template.md",
|
|
50
|
+
"sha256": "ddc7bb3362fcabac02c49c836ba618b485a158d7ebabf9beda7d37625d63a475"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"path": "references/style-system.md",
|
|
54
|
+
"sha256": "7f44dc0cbd5c7d9bf9d616126c25c42c36a3cc43fc805d2e3979089bab3a3176"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"path": "references/subject-design.md",
|
|
58
|
+
"sha256": "bab6c40bc393cad4c02999c978b31bcb355f18e57c6b9606edba795b4033d429"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"path": "references/training-guide.md",
|
|
62
|
+
"sha256": "80bb0b7b518dab348109fb26eb4f6ce3dcfd936c6fd1f39dabe97093ae958973"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"path": "references/training-log.jsonl",
|
|
66
|
+
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"path": "references/training-record.schema.json",
|
|
70
|
+
"sha256": "9ef4acc166561cee991000d232da135d22d99e6b781adec0604d9d8bea6e6bdb"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"path": "scripts/choose_gaze.py",
|
|
74
|
+
"sha256": "9f3001eb1ff6fc0c34062a8ed9701c6a1a8761331876fb22daee60e69b36918c"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"path": "scripts/record_example.py",
|
|
78
|
+
"sha256": "d737316af288d4df69cb38bf7ea7e7853e9f62b035e7b217663974a0bfd68732"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"path": "scripts/validate_png.py",
|
|
82
|
+
"sha256": "379ed9600b0d4ebc75df06b70ec5b6bc67d54fa13d880da751ccd8b7c8e16e9e"
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|