# דמויות

> יצירה, עדכון, העברה לארכיון ושחזור של דמויות ב-REST API של Nodaro, יצירת מועמדים לפורטרט, הבעות, זוויות וקליפי תנועה, ואישור פורטרט העוגן.

Source: https://nodaro.ai/he/docs/developers/api/characters

**ה-API של הדמויות** מאפשר לעשות מקוד כל מה שעושים באולפן הדמות. יוצרים דמות, יוצרים מועמדים לפורטרט, מאשרים אחד מהם כפורטרט העוגן, ומוסיפים הבעות, זוויות, תנוחות, וריאציות תאורה וקליפי תנועה. רכיבי תמונה ווידאו משתמשים אז בדמות שוב ושוב, ולכן אותו אדם נראה זהה בכל שוט.

הנתיבים עובדים בכל המהדורות. הם מקבלים אסימון Bearer: אסימון API אישי (`ndr_…`), אסימון של אפליקציית OAuth (`ndr_app_…`), או אסימון הסשן שלכם במהדורת Community. כל נתיב מוגבל למי שקורא לו: אתם רואים ומשנים רק את הדמויות שלכם. ראו את דף ה-API [אימות](https://nodaro.ai/docs/developers/api/authentication).

## נקודות קצה
| שיטה | נתיב | מה היא עושה |
| --- | --- | --- |
| `GET` | `/v1/characters` | רשימת הדמויות שלכם, עמוד אחד בכל פעם. |
| `GET` | `/v1/characters/:id` | קבלת דמות אחת עם המשימות שלה שעדיין רצות. עם `?candidates=all`, הרשימה `previousCandidates` כוללת גם את המועמד שממנו נוצר הפורטרט הנוכחי, מסומן ב-`isPortrait: true`. |
| `POST` | `/v1/characters` | יצירת דמות, או עדכון דמות כשבגוף הבקשה יש `id`. |
| `POST` | `/v1/characters/:id/duplicate` | העתקת דמות לדמות חדשה, ששמה מקבל את הסיומת `(copy)` (עותק). |
| `DELETE` | `/v1/characters/:id` | העברת דמות לארכיון. אפשר לשחזר אותה. |
| `POST` | `/v1/characters/:id/restore` | שחזור דמות מהארכיון. |
| `GET` | `/v1/characters/:id/usage` | ספירה ורשימה של התהליכים שמשתמשים בדמות. |
| `POST` | `/v1/generate-character` | יצירה של 1–10 מועמדים לפורטרט. |
| `POST` | `/v1/generate-character-asset` | יצירת הבעה, תנוחה, זווית או וריאציית תאורה אחת. |
| `POST` | `/v1/generate-character-motion` | הנפשת הדמות לקליפ תנועה. |
| `POST` | `/v1/characters/:id/approve-portrait` | אישור מועמד כפורטרט וכתיבת התיאור של הדמות. |
| `POST` | `/v1/characters/:id/llm-caption` | כתיבת התיאור מחדש מהפורטרט הנוכחי. |

אימון מודל ייעודי על דמות הוא יכולת של Nodaro Cloud עם נתיבים משלה. ראו את דף ה-API [אימון דמויות](https://nodaro.ai/docs/developers/api/character-training).

## מה דמות כוללת
דמות היא זהות שמורה אחת. השדות שבטבלה חוזרים מ-`GET /v1/characters/:id` ב-camelCase.

| שדה | מה יש בו |
| --- | --- |
| `id`, `name` | המזהה ושם התצוגה. השמות ייחודיים בכל חשבון, בלי הבדל בין אותיות גדולות לקטנות. |
| `description`, `gender`, `style`, `baseOutfit` | הערות זהות שמעצבות כל תמונה שנוצרת של הדמות. |
| `seedPrompt` | פרומפט קצר שמתווה את הפורטרט, עד 4,000 תווים. |
| `sourceImageUrl` | פורטרט העוגן. הוא נקבע כשמאשרים מועמד. |
| `canonicalDescription` | תיאור חזותי של בין 80 ל-120 מילים בערך, ש-Nodaro כותב כשהפורטרט מאושר. הוא נכלל בפרומפטים שמשתמשים בדמות. |
| `expressions`, `poses`, `angles`, `bodyAngles`, `lightingVariations`, `motions` | קבוצות הווריאנטים. כל פריט הוא `{ name, url }`. |
| `referencePhotos` | עד 20 תמונות אמיתיות, ולכל אחת תג של המסגור שלה. |
| `realLifeRefsByVariant`, `referenceVideosByVariant` | תמונות או קליפים נוספים כייחוס לווריאנט אחד, למשל להבעה `smile`. |
| `person`, `wardrobe` | בחירות מובנות של מראה ושל מלתחה, כמו שהוגדרו בדף **בוררים** של אולפן הדמות. |
| `voice`, `personality` | הקול והאישיות של הדמות. |
| `identityLock` | עד כמה הווריאנטים שנוצרים שומרים על הפנים: `off`, `soft` או `strict`. ברירת המחדל היא `off`. |
| `deletedAt` | מוגדר כשהדמות מועברת לארכיון. |
| `catalog`, `catalogSort`, `catalogCategory` | מצב הדמות על המדף של [Nodaro Keepers](https://nodaro.ai/docs/developers/api/community#keepers). בדמויות שלכם ובכל עותק, הערכים הם `false`, `0` ו-`null`. גם הרשימה מחזירה אותם בכל רשומה. |

### קבוצות הווריאנטים
בכל קבוצה נמצאים וריאנטים של פורטרט העוגן. אפשר לתת לווריאנט כל שם; אלה שמות הערכות, כפי שה-API מקבל ושומר אותם. באולפן הדמות בעברית התגיות שלהן מתורגמות, למשל `smile` מוצגת כ**חיוך**.

| קבוצה | מה היא מציגה | ערכות |
| --- | --- | --- |
| `expressions` | ראש וכתפיים, ברגש אחר | `neutral`, `smile`, `angry`, `surprised`, `sad`, `talking`, `laughing`, `disgusted`, `fearful`, `smirk`, `crying` |
| `angles` | ראש וכתפיים מזווית מצלמה אחרת | `front`, `3/4 left`, `left profile`, `right profile`, `3/4 right` |
| `bodyAngles` | גוף מלא מזווית אחרת, עם הידיים רפויות | `front`, `3/4 left`, `left profile`, `right profile`, `3/4 right`, `back` |
| `poses` | גוף מלא בתנוחה אחרת | `standing`, `walking`, `sitting`, `running`, `crouching`, `pointing`, `fighting stance`, `jumping`, `turning` |
| `lightingVariations` | אותה תנוחה בתאורה אחרת | `daylight`, `night`, `dramatic` |
| `motions` | קליפי וידאו של הדמות בתנועה | כל תווית, למשל `walking` או `head turn` |

## רשימת דמויות
הנתיב `GET /v1/characters` מחזיר עמוד אחד של הדמויות שלכם, מהחדש לישן. המשיכו לבקש עמודים עד ש-`nextCursor` הוא `null`: בחשבון שיש בו יותר דמויות מגודל העמוד, תגובה אחת אף פעם לא כוללת את כל הדמויות.

| פרמטר שאילתה | מה הוא עושה |
| --- | --- |
| `limit` | מספר הרשומות בעמוד. ברירת המחדל היא 100 והמקסימום הוא 500. |
| `cursor` | הערך `nextCursor` מהעמוד הקודם. |
| `projectId` | רק הדמויות של פרויקט אחד. |
| `archived` | הערך `true` מחזיר במקום זאת את הדמויות שבארכיון. |
| `q` | חיפוש: רק דמויות שהשם או התיאור שלהן כוללים את כל המילים שב-`q`. ראו את הסעיף [חיפוש לפי שם או תיאור](#search). |

**curl**

```bash
CURSOR=""
while :; do
PAGE=$(curl -s "https://app.nodaro.ai/v1/characters?limit=100${CURSOR:+&cursor=$CURSOR}" \
    -H "Authorization: Bearer $NODARO_API_KEY")
echo "$PAGE" | jq -r '.characters[] | "\(.id) \(.name)"'
CURSOR=$(echo "$PAGE" | jq -r '.nextCursor // empty')
[ -z "$CURSOR" ] && break
done
```

**TypeScript SDK**

```ts

const client = createClient({
baseUrl: 'https://app.nodaro.ai',
auth: new StaticTokenAuth(process.env.NODARO_API_KEY!),
})

const all = []
let cursor: string | undefined
do {
const page = await client.characters.list({ limit: 100, cursor })
all.push(...page.characters)
cursor = page.nextCursor ?? undefined
} while (cursor)
```

**CLI**

```bash
nodaro characters list --limit 100 --json
nodaro characters list --archived
```

```json
{
"characters": [
{
"id": "3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94",
"name": "Kira",
"description": "young protagonist with auburn hair",
"sourceImageUrl": "https://cdn.nodaro.ai/characters/kira-portrait.png",
"expressions": [{ "name": "smile", "url": "https://cdn.nodaro.ai/characters/kira-smile.png" }]
}
],
"nextCursor": "eyJjcmVhdGVkQXQiOiIyMDI2LTA5LTIwVDEwOjAwOjAxWiJ9"
}
```

ה-cursor הוא ערך אטום. שלחו בחזרה רק `nextCursor` שהשרת נתן לכם, ואף פעם אל תשמרו cursor בין גרסה לגרסה. על cursor פגום מקבלים `400 validation_error`, ולא חזרה שקטה לעמוד הראשון. דמויות שנוצרות בזמן שאתם עוברים בין העמודים לא נכללות; התחילו מחדש בלי cursor כדי לראות אותן.

### חיפוש לפי שם או תיאור
הנתיב `GET /v1/characters?q=red%20car` מחזיר רק את הדמויות ש**השם או התיאור** שלהן כוללים את כל המילים שב-`q`, בלי הבדל בין אותיות גדולות לקטנות. לכן הערך `red car` מוצא גם את "Car, red". הנתיבים `GET /v1/locations`, `GET /v1/objects`, `GET /v1/creatures` ו-`GET /v1/faces` מקבלים את אותו `q` ומחפשים באותם שני שדות.

- **מילים.** הערך של `q` מפוצל לפי רווחים, והחיפוש כולל רק את 5 המילים הראשונות. כל מילה יכולה להופיע בשם או בתיאור, בכל סדר, אבל כולן חייבות להופיע.
- **כל תו במילה נבדק כמו שהוא.** התווים `%`, `_` ו-`*` הם לא תווים כלליים, והפיסוק נשמר: הערך `Smith,` מתאים רק לטקסט שכולל את הפסיק. השתמשו בקידוד URL רגיל: השאילתה `?q=100%25` מחפשת את `100%`.
- **ערך ריק פירושו שאין חיפוש.** רווחים בהתחלה ובסוף לא נלקחים בחשבון, וכשהערך של `q` ריק, הרשימה כוללת הכול. ערך של יותר מ-200 תווים נדחה עם `400 validation_error`.
- **אפשר לשלב את `q` עם כל מסנן אחר** ועם הדפדוף בין העמודים: למשל עם `projectId`, ועם `archived=true` כדי לחפש בארכיון. המשיכו לשלוח את אותו `q` עם כל `cursor`. התוצאות שומרות על הסדר של הרשימה, מהחדש לישן.
- **החיפוש לא כולל את הכיתוב שנוצר**, רק את השם ואת התיאור שנתתם.

```bash
curl -s -H "Authorization: Bearer $NODARO_API_KEY" "https://app.nodaro.ai/v1/characters?q=maya&limit=20"
```

ב-SDK, העבירו את `q`: `client.characters.list({ q: 'maya pilot' })`. ב-CLI, הריצו `nodaro characters list --search "maya pilot"`. כלי ה-MCP `list_characters` מקבל את אותו חיפוש בפרמטר `search`.

## יצירה או עדכון של דמות
הנתיב `POST /v1/characters` יוצר דמות כשאין בגוף הבקשה `id`, ומעדכן את הדמות כשיש בו `id`. יצירה דורשת `nodeId` ו-`name`. השדה `nodeId` מקשר את הדמות לרכיב על הקנבס; כשיוצרים דמות מקוד, אפשר להשתמש בכל תווית, למשל `"scripted"`.

בעדכון, נכתבים רק השדות שאתם שולחים. שדות שלא נשלחו שומרים על הערכים שלהם, ולכן שמירה אף פעם לא דורסת קבוצות וריאנטים שמשימה פעילה ממלאת. שלחו קבוצת וריאנטים רק כשאתם מתכוונים להחליף אותה.

**curl**

```bash
curl -X POST https://app.nodaro.ai/v1/characters \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
"nodeId": "scripted",
"name": "Kira",
"description": "young protagonist with auburn hair",
"style": "realistic",
"seedPrompt": "kira portrait, warm natural lighting"
}'
```

**TypeScript SDK**

```ts
const { id } = await client.characters.create({
nodeId: 'scripted',
name: 'Kira',
description: 'young protagonist with auburn hair',
style: 'realistic',
seedPrompt: 'kira portrait, warm natural lighting',
})

await client.characters.update(id, { gender: 'female', identityLock: 'soft' })
```

**CLI**

```bash
nodaro characters create --name "Kira" \
  --description "young protagonist with auburn hair" \
  --style realistic --seed-prompt "kira portrait, warm natural lighting"

nodaro characters update <id> --gender female
```

```json
{ "id": "3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94", "name": "Kira" }
```

<TypeTable
type={{
id: { type: 'string (uuid)', description: 'הדמות לעדכון. השמיטו אותו כדי ליצור דמות.' },
nodeId: { type: 'string', description: 'נדרש ביצירה. הרכיב על הקנבס שהדמות שייכת לו, או תווית כלשהי כשאין רכיב כזה.' },
name: { type: 'string', description: 'נדרש ביצירה. 1–200 תווים. שם שכבר שייך לדמות פעילה אחרת נדחה עם 409 name_taken.' },
description: { type: 'string', description: 'הערות זהות, עד 2,000 תווים.' },
gender: { type: 'string', description: 'עד 50 תווים.' },
style: { type: 'string', description: 'הסגנון החזותי, למשל realistic, anime, 3d-pixar או illustration.' },
baseOutfit: { type: 'string', description: 'התלבושת של ברירת המחדל, עד 1,000 תווים.' },
seedPrompt: { type: 'string', description: 'פרומפט קצר שמתווה את הפורטרט, עד 4,000 תווים. ערך ארוך יותר נדחה עם 400.' },
identityLock: { type: "'off' | 'soft' | 'strict'", description: 'עד כמה הווריאנטים שנוצרים שומרים על הפנים.', default: 'off' },
referencePhotos: { type: 'array', description: 'עד 20 תמונות, כל אחת בצורה ‎{ url, kind }‎. הערך של kind הוא frontFace, sideLeft, sideRight, threeQuarterLeft, threeQuarterRight, frontBody או other. כל ערך של kind מלבד other יכול להופיע פעם אחת.' },
realLifeRefsByVariant: { type: 'object', description: 'כתובות של תמונות ייחוס לכל וריאנט, למשל ‎{ "smile": [url] }‎. עד 20 מפתחות ועד 5 כתובות לכל מפתח. המפתחות נשמרים בלי רווחים בקצוות ובאותיות קטנות.' },
referenceVideosByVariant: { type: 'object', description: 'כתובות של קליפי ייחוס לכל תווית, עם אותן מגבלות. קבלו אותן בחזרה כדי להזין את referenceVideoUrls ברכיב יצירת וידאו.' },
person: { type: 'object', description: 'בחירות מראה מובנות (שיער, עיניים, מבנה גוף, גיל ועוד). הן מתווספות לפרומפטים של הפורטרט ושל הווריאנטים של הדמות עצמה.' },
wardrobe: { type: 'object', description: 'בחירות מלתחה מובנות (חלק עליון, חלק תחתון, הנעלה, פלטת צבעים, תקופה ועוד). הן מתווספות לאותם פרומפטים.' },
voice: { type: 'object | null', description: 'הקול, בצורה ‎{ voiceId, voiceName, traits, voiceType?, ttsProvider? }‎. שלחו null כדי לנקות אותו.' },
personality: { type: 'object | null', description: 'האישיות, בצורה ‎{ mood, speechStyle, movementStyle, behavioralNotes }‎.' },
canonicalDescription: { type: 'string', description: 'ערך שמחליף את התיאור ש-Nodaro כתב, עד 4,000 תווים.' },
projectId: { type: 'string (uuid)', description: 'הפרויקט שבו לשמור את הדמות.' },
}}
/>

השדות `person` ו-`wardrobe` משפיעים רק על היצירות של הפורטרט ושל הווריאנטים של הדמות עצמה. הם משתמשים באותם קטלוגים כמו הבורר [אדם](https://nodaro.ai/docs/nodes/creative-controls/person); ראו את הדף [קטלוגי הבוררים](https://nodaro.ai/docs/developers/picker-catalogs).

כשתהליך רץ, השדה `voice` של הדמות ממלא את ההגדרות של כל רכיב [טקסט לדיבור](https://nodaro.ai/docs/nodes/audio/text-to-speech) שמחובר אחרי הדמות: הקול, סוג הקול והמודל המומלץ. ערך שהוגדר ברכיב טקסט לדיבור עצמו גובר.

## יצירת מועמדים לפורטרט
הנתיב `POST /v1/generate-character` מתחיל משימה אחת לכל מועמד ומחזיר מיד את המזהים שלהן. בדקו את הסטטוס של כל משימה מדי כמה שניות דרך [ה-API של המשימות](https://nodaro.ai/docs/developers/api/jobs), עד שהוא `completed`.

עם `attachToCharacterId`, כל מועמד שמסתיים נכתב לפורטרט של הדמות, ולכן המועמד שמסתיים אחרון גובר. למועמד יחיד זה כל מה שצריך. כשיש כמה מועמדים, אשרו את המועמד שאתם מעדיפים; האישור מחליף את הפורטרט. כדי שאף מועמד לא ייכתב לפורטרט עד שתאשרו אחד מהם, הוסיפו `attachPortrait: false`.

**curl**

```bash
curl -X POST https://app.nodaro.ai/v1/generate-character \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
"name": "Kira",
"seedPrompt": "kira portrait, warm natural lighting",
"count": 4,
"attachToCharacterId": "3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94"
}'
```

**TypeScript SDK**

```ts
const { jobIds } = await client.characters.generate({
name: 'Kira',
seedPrompt: 'kira portrait, warm natural lighting',
count: 4,
attachToCharacterId: id,
})
```

**CLI**

```bash
nodaro characters generate <id> --count 4 \
  --seed-prompt "kira portrait, warm natural lighting" --watch
```

```json
{
"jobId": "a1c4e8f2-5b3d-4e6a-8f7c-2d9b1e0a3c5f",
"jobIds": [
"a1c4e8f2-5b3d-4e6a-8f7c-2d9b1e0a3c5f",
"b7d2f9a1-6c4e-4a8b-9d3f-3e0c2f1b4d6a",
"c3e5a7b9-8d1f-4c2e-a6b8-4f1d3a2c5e7b",
"d9f1b3c5-2e4a-4d6f-b8c1-5a2e4b3d6f8c"
]
}
```

<TypeTable
type={{
name: { type: 'string', description: 'שם הדמות, 1–200 תווים.', required: true },
seedPrompt: { type: 'string', description: 'הפרומפט של הפורטרט. שלחו seedPrompt, description או referencePhotos, או צרפו את המועמדים לדמות שיש לה תיאור.' },
description: { type: 'string', description: 'הערות זהות, עד 2,000 תווים.' },
referencePhotos: { type: 'array', description: 'עד 20 תמונות בצורה ‎{ url, kind }‎ שמהן נבנה הפורטרט.' },
gender: { type: 'string', description: 'עד 50 תווים.' },
style: { type: 'string', description: 'הסגנון החזותי.' },
baseOutfit: { type: 'string', description: 'עד 1,000 תווים.' },
count: { type: 'integer', description: 'מספר המועמדים ליצירה, 1–10.', default: '1' },
provider: { type: 'string', description: 'המזהה של מודל התמונה. השמיטו אותו כדי להשתמש במודל ברירת המחדל.' },
quality: { type: "'basic' | 'medium' | 'high'", description: 'רמת איכות, במודלים שיש להם רמות כאלה. משנה את המחיר.' },
resolution: { type: 'string', description: 'אחת מהרזולוציות 1K, 2K, 4K, 0.5 MP, 1 MP, 2 MP או 4 MP, במודלים שתומכים בכך. משנה את המחיר.' },
aspectRatio: { type: "'1:1' | '3:4' | '16:9' | '9:16'", description: 'יחס הגובה־רוחב של הפורטרט.', default: '3:4' },
sourceImageUrl: { type: 'string', description: 'תמונה להתחיל ממנה.' },
attachToCharacterId: { type: 'string (uuid)', description: 'הדמות שמקבלת את התוצאה כפורטרט שלה.' },
subject: { type: 'object', description: 'מי מופיע בפורטרט, כמזהים של בוררים. ראו את הסעיף ״תיאור מי שמופיע בפורטרט״.' },
}}
/>

השדות `quality` ו-`resolution` קובעים את המחיר של המשימה בדיוק כמו ברכיב [יצירת תמונה](https://nodaro.ai/docs/nodes/image/generate-image): הרצה ב-4K או באיכות גבוהה עולה יותר מהרצה של אותו מודל ברמת הבסיס שלו. כשהמודל לא מקבל ערך מהרשימה, הבקשה לא נדחית. Nodaro משתמש במקומו בערך שהמודל תומך בו, או משמיט את ההגדרה כשאין למודל הגדרה כזו. הקרדיטים נקבעים לפי הערך שרץ בפועל. הנתיבים האלה לא מחזירים רשימת `adjustments`; את הערך שרץ בפועל קוראים ב-`input_data` של המשימה, מ-`GET /v1/jobs/:id`.

### תיאור מי שמופיע בפורטרט
השדה `subject` הוא אובייקט אופציונלי של מזהי בוררים שמתארים מי מופיע בתמונה: הגיל, השיער והסטיילינג של אדם, אביזר יד, חומר או חיה. הוא מקבל את אותם מפתחות ואת אותן מגבלות כמו ה-`subject` של [`POST /v1/generate-image`](https://nodaro.ai/docs/developers/api/nodes#describe-the-subject-by-id). Nodaro כותב את הניסוח ומוסיף אותו לפרומפט, מיד אחרי `seedPrompt` או `description` ואחרי הבחירות של הדמות עצמה ב-`person` וב-`wardrobe`. בחירה שמופיעה בשניהם באותו ניסוח נכתבת פעם אחת. שלחו את המזהים במקום לכתוב את המילים ב-`seedPrompt`, כדי שכל מקום ב-Nodaro ינסח בחירה אחת באותו אופן.

- השדה `subject` הוא לא פרומפט בפני עצמו: הנתיב עדיין צריך `seedPrompt`, `referencePhotos` או `description`.
- אין עליו תוספת מחיר.
- שדה `subject` שהגיל בו הוא של קטין מפעיל את אותם אמצעי הגנה לקטינים כמו הגדרת ה-`person` של הדמות עצמה.
- הנתיב `POST /v1/generate-creature` מקבל את אותו `subject`.

```json
{
"name": "Kira",
"seedPrompt": "kira portrait, warm natural lighting",
"subject": { "type": "woman", "age": "age-30s", "hairBase": "base-short-straight" }
}
```

## יצירת הבעה, זווית, תנוחה או וריאציית תאורה
הנתיב `POST /v1/generate-character-asset` יוצר וריאנט אחד של פורטרט העוגן ומחזיר `{ jobId }`. כדי להוסיף את התוצאה לדמות, שלחו את כל שלושת שדות הצירוף: `attachToCharacterId`, `attachToColumn` ו-`attachName`. כשהמשימה מסתיימת, ה-worker מוסיף את `{ name: attachName, url }` לסוף הקבוצה הזו.

**curl**

```bash
curl -X POST https://app.nodaro.ai/v1/generate-character-asset \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
"name": "Kira",
"assetType": "expressions",
"variant": "smile",
"attachToCharacterId": "3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94",
"attachToColumn": "expressions",
"attachName": "smile"
}'
```

**TypeScript SDK**

```ts
await client.characters.generateAsset({
name: 'Kira',
assetType: 'bodyAngles',
variant: 'front',
attachToCharacterId: id,
attachToColumn: 'body_angles',
attachName: 'front',
})
```

**CLI**

```bash
nodaro characters generate-asset <id> --asset-type expressions --variant smile --watch
```

| שדה | מה הוא עושה |
| --- | --- |
| `name` | נדרש. שם הדמות. |
| `assetType` | נדרש. `expressions`, `poses`, `lighting`, `headAngles`, `angles` (זהה ל-`headAngles`), `bodyAngles` או `custom`. |
| `variant` | נדרש. הווריאנט ליצירה, 1–100 תווים, למשל `smile` או `3/4 left`. |
| `description` | תיאור של הווריאנט הזה במשפט אחד, עד 1,000 תווים. כשמצרפים לדמות ומשמיטים אותו, Nodaro מנסח תיאור מהתיאור הקנוני של הדמות. |
| `sourceImageUrl` | התמונה שממנה נוצר הווריאנט, בדרך כלל הפורטרט המאושר. |
| `provider`, `quality`, `resolution` | מודל התמונה ורמת הפלט שלו, עם תמחור כמו ברכיב יצירת תמונה. |
| `aspectRatio` | אחד מהערכים `1:1`, `3:4`, `16:9` או `9:16`. ברירת המחדל נקבעת לפי הסוג: להבעות `1:1`, לתנוחות ולזוויות גוף `9:16`, ולשאר `3:4`. |
| `attachToCharacterId`, `attachToColumn`, `attachName` | לאן התוצאה נכנסת. השדה `attachToColumn` הוא `expressions`, `poses`, `angles`, `body_angles` או `lighting_variations`. וריאנט `custom` חייב לציין את העמודה שלו. |

כשמצרפים את הווריאנט לדמות, תמונות הייחוס מהחיים שנשמרו תחת המפתח של הווריאנט ב-`realLifeRefsByVariant` נשלחות עם הבקשה אוטומטית.

## הנפשת הדמות
הנתיב `POST /v1/generate-character-motion` הופך תמונת סטילס של הדמות לקליפ וידאו ומחזיר `{ jobId }`. עם `attachToCharacterId` ו-`attachName`, הקליפ מתווסף לסוף הקבוצה `motions` כשהוא מוכן.

כשמצרפים לדמות, Nodaro בוחר את פריים הפתיחה לפי הסדר הזה:

1. ה-`sourceImageUrl` שאתם שולחים, שתמיד גובר.
2. הפריט `front` ב-`bodyAngles`. פריים של גוף מלא מונפש טוב בהרבה מפורטרט של ראש וכתפיים.
3. כל פריט אחר ב-`bodyAngles`, מהחדש לישן.
4. פורטרט העוגן.

כדי לקבל את הקליפים הטובים ביותר, צרו זווית גוף `front` לפני התנועה הראשונה.

**curl**

```bash
curl -X POST https://app.nodaro.ai/v1/generate-character-motion \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
"name": "Kira",
"motionPrompt": "slow head turn left, soft smile",
"provider": "kling",
"attachToCharacterId": "3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94",
"attachName": "head turn"
}'
```

**TypeScript SDK**

```ts
await client.characters.generateMotion({
name: 'Kira',
motionPrompt: 'slow head turn left, soft smile',
provider: 'kling',
attachToCharacterId: id,
attachName: 'head turn',
})
```

**CLI**

```bash
nodaro characters generate-motion <id> \
  --motion-prompt "slow head turn left, soft smile" --attach-name "head turn" --watch
```

| שדה | מה הוא עושה |
| --- | --- |
| `name` | נדרש. שם הדמות. |
| `motionPrompt` | נדרש. מה זז ואיך, 1–2,000 תווים. |
| `provider` | מודל הווידאו: `kling` (ברירת המחדל), `kling-turbo`, `kling-3.0`, `wan-i2v` או `wan-2.7-i2v`. |
| `sourceImageUrl` | פריים הפתיחה. נדרש כשלא מצרפים לדמות. |
| `description`, `motionDescription` | תיאור חזותי (עד 1,000 תווים) ותיאור של התנועה (עד 500). Nodaro מנסח את שניהם כשמצרפים לדמות ומשמיטים אותם. |
| `aspectRatio` | אחד מהערכים `1:1`, `3:4`, `16:9` או `9:16`. ברירת המחדל היא `9:16`, קליפ אנכי של גוף מלא. |
| `attachToCharacterId`, `attachName` | הדמות, ושם הקליפ ב-`motions`. |

המודלים האלה יכולים להנפיש דמות. המחיר הוא המחיר של המודל ליצירה מתמונה לווידאו:

| Model | Maker | Modes | Credits | Details |
| --- | --- | --- | --- | --- |
| [Kling 2.6](https://nodaro.ai/docs/models/video/kling-2-6) | Kuaishou | Image to video, Text to video | החל מ-152 | Kling 2.6 I2V — strong motion realism. 5s/10s, optional native audio. |
| [Kling 2.5 Turbo Pro](https://nodaro.ai/docs/models/video/kling-2-5-turbo-pro) | Kuaishou | Image to video, Text to video | החל מ-121 | Faster Kling — good quality at lower cost. Supports end frame. |
| [Kling 3.0](https://nodaro.ai/docs/models/video/kling-3-0) | Kuaishou | Image to video, Text to video | החל מ-297 | Premium Kling 3.0 — variable 3-15s duration, native audio, 720P/1080P. |
| [Wan 2.6 I2V](https://nodaro.ai/docs/models/video/wan-2-6-i2v) | Alibaba | Image to video | החל מ-193 | Wan 2.6 image-to-video — 5/10/15s at 720p/1080p. |
| [Wan 2.7 I2V](https://nodaro.ai/docs/models/video/wan-2-7-i2v) | Alibaba | Image to video | 207 | Wan 2.7 image-to-video — 2–15s at 720p/1080p, supports start+end frame. |

## אישור פורטרט
הנתיב `POST /v1/characters/:id/approve-portrait` קובע מועמד שהושלם כפורטרט העוגן. באותה קריאה, Nodaro בוחן את הפורטרט וכותב את `canonicalDescription`, הטקסט שפרומפטים מאוחרים יותר משתמשים בו כדי לתאר את הדמות. בלי התיאור הזה, הדמות משתנה הרבה יותר בין סצנות.

המועמד חייב להיות משימה שלכם בסטטוס `completed`. אם כתיבת התיאור נכשלת, הפורטרט בכל זאת נקבע והשדה `canonicalDescription` הוא `null`; קראו לנתיב `POST /v1/characters/:id/llm-caption` כדי לנסות שוב. אפשר לחזור על הקריאה לשני הנתיבים בלי חשש. האישור עצמו לא עולה קרדיטים. כתיבת התיאור היא קריאה למודל הראייה Claude Sonnet 4.6, שמחויבת לפי הטוקנים שהיא השתמשה בהם, בתעריף של המודל הזה. ראו את הסעיף [איך מחויבות קריאות LLM](https://nodaro.ai/docs/concepts/credits#llm-calls) בדף קרדיטים. אישור אף פעם לא נדחה בגלל קרדיטים. כשהיתרה לא מספיקה לתיאור, התמונה בכל זאת מאושרת, התיאור לא נכתב, והנתיב `llm-caption` יכול לכתוב אותו מאוחר יותר. על תיאור שהספק חייב עליו משלמים, גם כשהוא חוזר ריק. על תיאור שהספק לא חייב עליו, הקרדיטים מוחזרים.

**curl**

```bash
curl -X POST https://app.nodaro.ai/v1/characters/3f6c2a9e-8d41-4b7a-9c35-1e2f7a6b0d94/approve-portrait \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "candidateJobId": "b7d2f9a1-6c4e-4a8b-9d3f-3e0c2f1b4d6a" }'
```

**TypeScript SDK**

```ts
const { portraitUrl, canonicalDescription } =
await client.characters.approvePortrait(id, jobIds[1])

if (canonicalDescription === null) {
await client.characters.recaption(id)
}
```

**CLI**

```bash
nodaro characters approve-portrait <id> --job <jobId>
nodaro characters recaption <id>
```

```json
{
"portraitUrl": "https://cdn.nodaro.ai/characters/kira-portrait-2.png",
"canonicalDescription": "Kira is a woman in her mid-twenties with shoulder-length auburn hair, green eyes and light freckles..."
}
```

הנתיב `llm-caption` מחזיר `{ canonicalDescription }`. הנתיב מחזיר `400 no_portrait` כשלדמות עדיין אין פורטרט, ו-`502` כשלא היה אפשר לכתוב את התיאור.

גם אישור פורטרט וגם הנתיב `llm-caption` משנים את הדמות. עם אסימון של אפליקציית OAuth, הם דורשים את ההרשאה `assets:write`, כמו יצירה או מחיקה של דמות. אסימון בלי ההרשאה הזאת נדחה עם `403 insufficient_scope`. אסימון הסשן שלכם ואסימוני API אישיים לא צריכים הרשאה.

## העברה לארכיון, שחזור ושכפול של דמות
- **העברה לארכיון.** הנתיב `DELETE /v1/characters/:id` מעביר את הדמות לארכיון ומחזיר `{ success: true, archived: true }`. הדמות יוצאת מרשימת ברירת המחדל, אבל הנתיב `GET /v1/characters/:id` עדיין מחזיר אותה, ולכן תהליכים שמשתמשים בה ממשיכים לעבוד. ב-Nodaro Cloud, ההעברה לארכיון גם מבטלת אימון שבעיצומו ומסירה את המודל המאומן, והקרדיטים על האימון מוחזרים.
- **שחזור.** הנתיב `POST /v1/characters/:id/restore` מחזיר `{ id, name }`. אם בינתיים יש לדמות פעילה אחרת אותו שם, Nodaro מוסיף את הסיומת `(restored)` (שוחזר) ומחזיר את השם החדש.
- **מחיקה לצמיתות.** אין נתיב API שמוחק דמות לצמיתות. השתמשו בתצוגת הארכיון בספרייה של העורך.
- **שכפול.** הנתיב `POST /v1/characters/:id/duplicate` מחזיר `{ id, name }` של דמות חדשה עם הסיומת `(copy)` (עותק). העותק משתמש באותן כתובות של תמונות וקליפים כמו המקור, עד שתיצרו אותם מחדש.
- **שימוש.** הנתיב `GET /v1/characters/:id/usage` מחזיר `{ workflowCount, workflows: [{ id, name }] }`. בדקו אותו לפני שאתם מעבירים דמות לארכיון.

| פעולה | curl | SDK ל-TypeScript | CLI |
| --- | --- | --- | --- |
| העברה לארכיון | `DELETE /v1/characters/:id` | `client.characters.delete(id)` | `nodaro characters delete <id>` |
| שחזור | `POST /v1/characters/:id/restore` | `client.characters.restore(id)` | `nodaro characters restore <id>` |
| שכפול | `POST /v1/characters/:id/duplicate` | `client.characters.duplicate(id)` | `nodaro characters duplicate <id>` |
| שימוש | `GET /v1/characters/:id/usage` | `client.characters.usage(id)` | `nodaro characters usage <id>` |

## רצף מלא: יצירה, מועמדים, אישור והוספת וריאנטים
### יצירת הדמות
קראו לנתיב `POST /v1/characters` עם `nodeId`, `name` ו-`seedPrompt`. שמרו את ה-`id` שחוזר.

### יצירת מועמדים לפורטרט
קראו לנתיב `POST /v1/generate-character` עם `count: 4` ו-`attachToCharacterId`. בדקו את הסטטוס של כל משימה מדי כמה שניות, עד שהוא `completed` או `failed`.

### אישור המועמד המועדף
קראו לנתיב `POST /v1/characters/:id/approve-portrait` עם מזהה המשימה של המועמד הזה. הפורטרט והתיאור הקנוני נקבעים.

### הוספת וריאנטים ותנועה
צרו זווית גוף `front`, ואחריה הבעות ותנוחות, עם `POST /v1/generate-character-asset`, וקליפים עם `POST /v1/generate-character-motion`.

## שימוש בדמות ביצירות אחרות
אחרי שהווריאנטים קיימים, העבירו את הכתובות שלהם כתמונות ייחוס לרכיב [יצירת תמונה](https://nodaro.ai/docs/nodes/image/generate-image) או לרכיב [יצירת וידאו](https://nodaro.ai/docs/nodes/video/generate-video). למשל, קבלו את הפריט `smile` מהשדה `expressions` ושלחו את הכתובת שלו כייחוס עם הפרומפט שלכם. כתובות מפורשות הן הבחירה הפשוטה ביותר בקוד, כי הן לא תלויות באופן שבו תהליך מחובר. ראו את דף ה-API [הרצת רכיב יחיד](https://nodaro.ai/docs/developers/api/nodes) לשדות הבקשה.

בתהליך, חברו את רכיב [נכס דמות](https://nodaro.ai/docs/nodes/assets/character) לרכיב התמונה או הווידאו, או הזכירו את הדמות בפרומפט עם `@`, למשל `@kira:1:smile`. המדריך [תפקידי ייחוס](https://nodaro.ai/docs/guides/reference-roles) מסביר את הדקדוק של האזכורים, והמדריך [דמויות עקביות](https://nodaro.ai/docs/guides/consistent-characters) את השיטה המלאה.

## שימוש דרך MCP
עוזרי AI משתמשים באותם נתיבים דרך הכלים האלה. העברה לארכיון ושחזור לא זמינים דרך MCP, במכוון.

| כלי | מה הוא עושה |
| --- | --- |
| `list_characters`, `get_character` | מציאת דמות וקריאת כתובות התמונות שלה. |
| `create_character`, `update_character` | יצירת דמות או שינוי שדות הזהות שלה. |
| `generate_character` | יצירת פורטרט (`kind: "main"`) או וריאנט (`kind: "asset"`). |
| `generate_character_motion` | הנפשת הדמות לקליפ. |
| `approve_portrait`, `recaption_character` | אישור פורטרט, או כתיבת התיאור שלו מחדש. |

ראו את [מדריך כלי ה-MCP](https://nodaro.ai/docs/mcp/tools).

## קרדיטים
ב-Nodaro Cloud, המחירים בקרדיטים של יצירת דמויות זהים למחירים של הרכיבים המקבילים.

| נתיב | מחיר |
| --- | --- |
| `POST /v1/generate-character` | המחיר של מודל התמונה כפול `count`, משוריין לכל המועמדים לפני שהמשימה הראשונה מתחילה. |
| `POST /v1/generate-character-asset` | המחיר של מודל התמונה, לכל וריאנט. |
| `POST /v1/generate-character-motion` | המחיר של מודל הווידאו ליצירה מתמונה לווידאו, לכל קליפ. |
| `approve-portrait` | האישור לא עולה קרדיטים. כתיבת התיאור היא קריאה למודל ראייה, שמחויבת לפי הטוקנים שהיא השתמשה בהם. |
| `llm-caption` | אותה קריאה למודל ראייה, שמחויבת באותו אופן. |

המחיר המדויק מופיע בדף של כל מודל. ראו את הדף [קרדיטים](https://nodaro.ai/docs/concepts/credits).

## שגיאות
השגיאות משתמשות במעטפת הסטנדרטית, `{ "error": { "code", "message" } }`. ראו את דף ה-API [שגיאות](https://nodaro.ai/docs/developers/api/errors).

| סטטוס | קוד | משמעות |
| --- | --- | --- |
| `400` | `validation_error` | שדה חסר או לא תקין, cursor פגום, או שבבקשת יצירה אין `seedPrompt`, `description` או `referencePhotos`. |
| `400` | `no_portrait` | הקריאה ל-`llm-caption` נשלחה לפני שהיה לדמות פורטרט. |
| `401` | `unauthorized` | האסימון חסר, לא תקין או מבוטל. |
| `402` | `insufficient_credits` | ב-Nodaro Cloud בלבד. אין בחשבון מספיק קרדיטים לשריון. |
| `404` | `not_found` | אין לכם דמות או משימה עם המזהה הזה. |
| `409` | `name_taken` | השם הזה כבר שייך לדמות פעילה אחרת. |
| `502` | — | לא היה אפשר לכתוב את התיאור הקנוני. הפורטרט לא השתנה. נסו שוב. |

## שאלות נפוצות

### איך שומרים על אותה דמות בכל יצירה דרך ה-API?

כדי לשמור על אותה דמות בכל יצירה, צרו דמות, צרו לה פורטרט ואשרו אותו. Nodaro כותב אז תיאור קנוני של הדמות. העבירו את כתובות התמונות של הדמות כתמונות ייחוס לרכיב יצירת תמונה או לרכיב יצירת וידאו, או חברו את הדמות לתהליך.

### כמה מועמדים לפורטרט אפשר ליצור בקריאה אחת?

הנתיב POST /v1/generate-character מקבל count בין 1 ל-10. הקרדיטים של כל המועמדים משוריינים לפני שהמשימה הראשונה מתחילה, וכשל באמצע האצווה מבטל את השריון כולו.

### האם DELETE /v1/characters/:id מוחק דמות לצמיתות?

לא. הנתיב מעביר את הדמות לארכיון, והנתיב POST /v1/characters/:id/restore מחזיר אותה. רק תצוגת הארכיון בעורך יכולה למחוק דמות לצמיתות.

### למה canonicalDescription הוא null אחרי אישור פורטרט?

כשהשדה canonicalDescription הוא null, הפורטרט נקבע, אבל התיאור שלו לא נכתב: הכתיבה נכשלה, או שהיתרה הייתה נמוכה מדי בשבילו. קראו לנתיב POST /v1/characters/:id/llm-caption כדי לכתוב אותו. האישור עצמו לא עולה קרדיטים. כתיבת התיאור היא קריאה למודל ראייה, שמחויבת לפי הטוקנים שהיא השתמשה בהם.

### אילו מודלים יכולים להנפיש דמות?

המודלים שיכולים להנפיש דמות הם Kling 2.6 (ברירת המחדל, מזהה הספק kling), Kling 2.5 Turbo Pro, Kling 3.0, Wan 2.6 I2V ו-Wan 2.7 I2V. כל קליפ עולה כמו יצירה מתמונה לווידאו באותו מודל.
