# קולות ואודיו

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

Source: https://nodaro.ai/he/docs/developers/sdk/voices-and-audio

**`client.voices`** עובד עם הקולות של ElevenLabs: הוא מחזיר רשימות של קולות ומחפש ביניהם, מחליף את הקול בהקלטה, נותן קול חדש לכל דובר, מעצב קולות חדשים ומדבב אודיו ווידאו לשפות אחרות. המשאב **`client.audio`** מציע את אבני הבניין של האודיו כל אחת בנפרד: הפרדה, בידוד קול, אפקטים, מיקס, עוצמה, איחוד ותמלול. כל מתודת יצירה מחזירה `jobId`; בדקו את הסטטוס של המשימה מדי כמה שניות עם [`client.jobs.getStatus()`](https://nodaro.ai/docs/developers/sdk/jobs-and-executions). המתודות קוראות לנקודות הקצה שבדף ה-API [קול ומדיה](https://nodaro.ai/docs/developers/api/voice-and-media).

## מתודות
| מתודה | מה היא עושה |
| --- | --- |
| [`voices.list()`](#voiceslist) | רשימת הקולות המוכנים מראש |
| [`voices.searchLibrary(params?)`](#voicessearchlibraryparams) | חיפוש בספריית הקולות של הקהילה |
| [`voices.listClones()`](#voiceslistclones) | רשימת הקולות המשוכפלים הקיימים שלכם |
| [`voices.deleteClone(id)`](#voicesdeletecloneid) | מחיקה של אחד הקולות המשוכפלים שלכם |
| [`voices.createClone()` ו-`createCloneFromFile()`](#voicescreateclone-and-createclonefromfile) | הוצאו משימוש |
| [`voices.change(input)`](#voiceschangeinput) | החלפת הקול בהקלטה או בסרטון |
| [`voices.recast(input)`](#voicesrecastinput) | קול אחר לכל דובר |
| [`voices.analyze(input)`](#voicesanalyzeinput) | זיהוי הדוברים לפני החלפת הקולות |
| [`voices.exportMix(input)`](#voicesexportmixinput) | רינדור סרטון מהמיקס של סטמי הקולות |
| [`voices.design(input)`](#voicesdesigninput) | יצירת קול חדש מתיאור |
| [`voices.remix(input)`](#voicesremixinput) | הקראת טקסט בקול שאתם מתארים |
| [`voices.dub(input)`](#voicesdubinput) | דיבוב של אודיו או וידאו לשפה אחרת |
| [`voices.textToDialogue(input)`](#voicestexttodialogueinput) | הקראה של תסריט עם כמה דוברים כקובץ אודיו אחד |
| [`audio.separate(input)`](#audioseparateinput) | פיצול רצועה לסטמים |
| [`audio.isolate(input)`](#audioisolateinput) | שמירה על הקול הראשי והסרת רעשים |
| [`audio.applyFx(input)`](#audioapplyfxinput) | הוספת ריוורב, הד, אפקט טלפון או מגפון |
| [`audio.mix(input)`](#audiomixinput) | שילוב של כמה רצועות בשכבות לרצועה אחת |
| [`audio.adjustVolume(input)`](#audioadjustvolumeinput) | שינוי העוצמה, נרמול או עמעום |
| [`audio.pitchTempo(input)`](#audiopitchtempoinput) | הזזת גובה הצליל, או שינוי הטמפו בלי לשנות את גובה הצליל |
| [`audio.combine(input)`](#audiocombineinput) | איחוד מקטעי אודיו ברצף |
| [`audio.transcribe(input)`](#audiotranscribeinput) | הפיכת דיבור לטקסט, עם תזמון לכל מילה |

## client.voices: קולות
### voices.list()‎
מחזירה את רשימת הקולות המוכנים מראש של ElevenLabs (`GET /v1/voices`). כשלא מוגדר בשרת מפתח של ElevenLabs, המתודה מחזירה במקום זאת קבוצת קולות שנבחרה בקפידה.

```ts
list(): Promise<Voice[]>
```

```ts
const voices = await client.voices.list()
```

### voices.searchLibrary(params?)‎
מחפשת בספריית הקולות של הקהילה (`GET /v1/voices/library`). כל הפרמטרים הם אופציונליים, וערכים ריקים לא נשלחים, כדי שברירות המחדל של השרת יחולו. השדה `hasMore` בתשובה מציין אם יש עמוד נוסף.

```ts
searchLibrary(params?: VoiceLibraryParams): Promise<{ voices: Voice[]; hasMore: boolean }>
```

<TypeTable
type={{
search: { type: 'string', description: "מילים לחיפוש." },
gender: { type: 'string', description: "סינון לפי מגדר." },
age: { type: 'string', description: "סינון לפי גיל." },
accent: { type: 'string', description: "סינון לפי מבטא." },
language: { type: 'string', description: "סינון לפי קוד שפה, כגון en." },
category: { type: 'string', description: "סינון לפי קטגוריה." },
use_cases: { type: 'string', description: "סינון לפי תרחיש שימוש." },
descriptives: { type: 'string', description: "סינון לפי תגיות תיאור." },
featured: { type: 'boolean', description: "רק קולות מומלצים." },
sort: { type: 'string', description: "סדר המיון, כגון trending." },
page: { type: 'number', default: '0', description: "מספר העמוד, החל מ-0." },
page_size: { type: 'number', default: '30', description: "מספר הקולות בעמוד, מ-1 עד 100." },
}}
/>

```ts
const { voices, hasMore } = await client.voices.searchLibrary({ search: "deep", language: "en" })
const voice = voices[0]

await client.nodes.run("text-to-speech", {
text: "Hello!",
voice: voice.voice_id,
voiceType: "library",
...(voice.recommendedProvider ? { provider: voice.recommendedProvider } : {}),
})
```

כל קול יכול לכלול שני רמזים על מודלי הדיבור שהוא אומת עליהם:

- **`recommendedProvider`** הוא המודל הטוב ביותר לקול. אפליקציות בלי תפריט בחירת מודל צריכות לשלוח אותו כ-`provider` לרכיב [טקסט לדיבור](https://nodaro.ai/docs/nodes/audio/text-to-speech), כדי שהקול יישמע כמו בדוגמה שלו בספרייה.
- **`verifiedProviders`** מפרט את כל המודלים שהקול אומת עליהם. אפליקציות עם תפריט בחירת מודל צריכות להחליף את הבחירה של המשתמש רק כשהיא לא ברשימה הזו.

בשני הרמזים המודלים מופיעים לפי הסדר ElevenLabs v4, ElevenLabs v3, ElevenLabs v4 Turbo, Turbo v2.5 ובסוף Multilingual v2. הערך של `recommendedProvider` הוא הפריט הראשון ב-`verifiedProviders`. בדקו אם מודל נמצא ברשימה, ולעולם אל תשוו לקבוצה קבועה של ערכים: מודל דיבור שיתווסף בעתיד ייכנס לרשימה מרגע שהוא זמין. שני הרמזים מציינים רק מודלים שההתקנה מציעה. קול שאין לו בהתקנה מודל מאומת לא כולל אף אחד משני השדות, ולכן השאירו את המודל הנוכחי של המשתמש.

### voices.listClones()‎
מחזירה את רשימת הקולות המשוכפלים שלכם (`GET /v1/voice-clones`). קולות משוכפלים שנוצרו לפני ששכפול הקולות הוצא משימוש עדיין עובדים כמזהי קול בכל מקום שמקבל קול.

```ts
listClones(): Promise<VoiceClone[]>
```

```ts
const clones = await client.voices.listClones()
```

### voices.deleteClone(id)‎
מוחקת אחד הקולות המשוכפלים שלכם (`DELETE /v1/voice-clones/:id`).

```ts
deleteClone(id: string): Promise<void>
```

<TypeTable
type={{
id: { type: 'string', required: true, description: "מזהה הקול המשוכפל." },
}}
/>

```ts
await client.voices.deleteClone(cloneId)
```

### voices.createClone()‎ ו-createCloneFromFile()‎
Nodaro כבר לא מציע שכפול קולות. שכפול הקולות הוצא משימוש בספטמבר 2026. שתי המתודות עדיין קיימות בלקוח ומסומנות כמיושנות. הן נכשלות עם `NodaroError` שה-`code` שלה הוא `voice_cloning_retired`, עם סטטוס 410. כדי ליצור קול חדש משלכם, קראו למתודה [`design()`](#voicesdesigninput).

## client.voices: החלפת קול
### voices.change(input)‎
מחליפה את הקול בהקלטה, או בסרטון שלם עם דיבור, בקול אחר (`POST /v1/voice-changer`), כמו רכיב [משנה קול](https://nodaro.ai/docs/nodes/audio/voice-changer). עם `videoUrl`, השרת מחלץ את האודיו מהסרטון, מחליף את הקול ומחזיר את הקול החדש לסרטון, עם התמונה המקורית.

```ts
change(input: {
voiceId: string
audioUrl?: string
videoUrl?: string
model?: string
stability?: number
similarityBoost?: number
style?: number
useSpeakerBoost?: boolean
seed?: number
removeBackgroundNoise?: boolean
}): Promise<{ jobId: string }>
```

<TypeTable
type={{
voiceId: { type: 'string', required: true, description: "הקול החדש: שם של קול מוכן מראש או מזהה קול של ElevenLabs." },
audioUrl: { type: 'string', description: "ההקלטה שבה מחליפים את הקול. שלחו audioUrl או videoUrl. כששולחים את שניהם, הסרטון גובר." },
videoUrl: { type: 'string', description: "סרטון שבו מחליפים את הקול." },
model: { type: 'string', description: "מודל המרת דיבור לדיבור במקום מודל ברירת המחדל." },
stability: { type: 'number', description: "יציבות הקול, מ-0 עד 1." },
similarityBoost: { type: 'number', description: "עד כמה להתקרב לקול היעד, מ-0 עד 1." },
style: { type: 'number', default: '0', description: "הדגשת סגנון, מ-0 עד 1. ערך מעל 0 מעצים את ההגשה, במחיר מסוים של מהירות ויציבות." },
useSpeakerBoost: { type: 'boolean', description: "מחדד את הדמיון לקול היעד, במחיר של האטה קלה." },
seed: { type: 'number', description: "מספר שלם שמאפשר לשחזר את הפלט." },
removeBackgroundNoise: { type: 'boolean', description: "עם true מקבלים קול נקי בלבד. עם false המוזיקה והאפקטים נשמרים מתחת לקול החדש." },
}}
/>

```ts
const { jobId } = await client.voices.change({
videoUrl: "https://example.com/talking.mp4",
voiceId: "Aria",
})
// the finished job's output_data has videoUrl and audioUrl
```

### voices.recast(input)‎
נותנת לכל דובר שזוהה בהקלטה קול אחר (`POST /v1/voice-changer-pro`), כמו רכיב [משנה קול Pro](https://nodaro.ai/docs/nodes/audio/voice-changer-pro). החלפת הקולות רצה ב-Nodaro Cloud כמשימה, ועולה קרדיטים.

```ts
recast(input: VoiceChangerProInput): Promise<{ jobId: string }>
```

<TypeTable
type={{
orderedVoices: { type: 'Array<VoiceChangerProVoice | null>', required: true, description: "1–8 פריטים, אחד לכל דובר שזוהה, לפי הסדר. כל פריט הוא מזהה קול, אובייקט עם הגדרות לקול הזה, או null כדי שהדובר הזה ישמור על הקול שלו. לפחות פריט אחד צריך להיות שונה מ-null." },
audioUrl: { type: 'string', description: "ההקלטה. שלחו audioUrl או videoUrl." },
videoUrl: { type: 'string', description: "סרטון שבו מחליפים את הקולות של הדוברים. הקולות החדשים חוזרים לסרטון, עם התמונה המקורית." },
model: { type: 'string', description: "מודל המרת דיבור לדיבור במקום מודל ברירת המחדל." },
preserveBackground: { type: 'boolean', default: 'true', description: "מחזיר את המוזיקה והאפקטים למיקס, מתחת לקולות החדשים. עם false מקבלים את הקולות בלבד." },
separationQuality: { type: '"fast" | "best"', default: '"fast"', description: "הערך fast מהיר יותר ושומר יותר מהקול. הערך best מפריד בין הקול למוזיקה בדיוק רב יותר." },
removeBackgroundNoise: { type: 'boolean', description: "מסיר גם רעשים מהתוצאה." },
musicVolumeMode: { type: '"match" | "normalize" | "manual"', default: '"match"', description: "העוצמה של הרקע שנשמר: העוצמה המקורית, עוצמה מנורמלת או הערך של musicVolume." },
musicVolume: { type: 'number', description: "עוצמת הרקע באחוזים, מ-0% עד 200%, כש-musicVolumeMode הוא manual." },
voiceFx: { type: '{ preset, wetDryMix?, delayMs?, decay? }', description: "אפקט על כל הקולות החדשים, שמוחל לפני שהרקע חוזר למיקס." },
output: { type: '"video" | "stems"', default: '"video"', description: "הערך video מרנדר את התוצאה המוגמרת. הערך stems מחזיר רצועות נפרדות שלא עברו מיקס, כדי שתעשו את המיקס בעצמכם ותרנדרו עם exportMix()‎." },
analysis: { type: 'VcpAnalysis', description: "התוצאה של משימת analyze()‎ קודמת, כדי לדלג על זיהוי הדוברים." },
}}
/>

כל פריט ב-`orderedVoices` הוא אחד מאלה:

- **מזהה קול**: שם של קול מוכן מראש, כגון `"Rachel"`, או מזהה קול של ElevenLabs.
- **`null`**: פריט שמירת מקור. הדובר הזה שומר על הקול שלו, והקולות של הדוברים שאחריו עדיין מוחלפים. פריטי שמירת מקור לא עולים כלום, כי משלמים רק על דוברים שהקול שלהם מוחלף.
- **אובייקט** עם `voiceId` ועם הגדרות לדובר הזה: `stability`, `similarityBoost` ו-`style` מ-0 עד 1, `useSpeakerBoost` ו-`seed` מ-0 עד 4,294,967,295. השדה `volumeMode` הוא `"match"` (ברירת המחדל, העוצמה של הדובר המקורי), `"normalize"` או `"manual"` עם `volume` באחוזים, מ-0% עד 200%. עם `engine: "v3"`, ElevenLabs v3 מקריא את השורה מחדש מהתמלול שלה, עם תמיכה בתגי אודיו (`[audio tags]`), במקום להמיר את הדיבור המוקלט. עם `engine: "v4"`, ElevenLabs v4 עושה את אותו הדבר, מקבל כל ערך של `stability` מ-0 עד 1 ומחיל את `similarityBoost`.

דובר 0 מקבל את `orderedVoices[0]`, דובר 1 מקבל את `orderedVoices[1]`, וכן הלאה. דוברים שמעבר לפריט האחרון שומרים על הקול שלהם. הקול והמוזיקה תמיד מופרדים קודם. הפרמטר `preserveBackground` קובע רק אם המוזיקה חוזרת למיקס.

השדה `voiceFx.preset` הוא חלל ריוורב (`room`, `bathroom`, `car`, `hall`, `concert-hall`, `church`, `cave`, `arena` או `outdoor`), `telephone`, `megaphone`, `echo` או `custom`. ערכות הריוורב משתמשות ב-`wetDryMix` מ-0 עד 100. הערכות `echo` ו-`custom` משתמשות ב-`delayMs` מ-20 עד 2,000 וב-`decay` מ-0 עד 1.

```ts
// Recast speakers 0 and 2, and keep speaker 1's own voice
const { jobId } = await client.voices.recast({
audioUrl: "https://example.com/panel.mp3",
orderedVoices: ["Rachel", null, "Aria"],
})

// Repeatable voices, a hall reverb, and finer separation
const { jobId: tuned } = await client.voices.recast({
audioUrl: "https://example.com/dialogue.mp3",
orderedVoices: [
{ voiceId: "Rachel", seed: 12345, stability: 0.6 },
{ voiceId: "Aria", seed: 67890, volumeMode: "manual", volume: 120 },
],
voiceFx: { preset: "hall", wetDryMix: 35 },
separationQuality: "best",
})
```

במצב וידאו, ב-`output_data` של המשימה שהסתיימה נמצאים `videoUrl` ו-`audioUrl`.

### voices.analyze(input)‎
מזהה את הדוברים בקליפ **בלי להחליף את הקולות** (`POST /v1/voice-changer-pro/analyze`). המתודה מפרידה את הקול מהמוזיקה פעם אחת ומוצאת מי מדבר ומתי. הניתוח רץ ב-Nodaro Cloud כמשימה, במחיר קבוע.

```ts
analyze(input: {
audioUrl?: string
videoUrl?: string
separationQuality?: "fast" | "best"
suggestTitle?: boolean
}): Promise<{ jobId: string }>
```

<TypeTable
type={{
audioUrl: { type: 'string', description: "ההקלטה. שלחו בדיוק אחד מהשניים, audioUrl או videoUrl." },
videoUrl: { type: 'string', description: "סרטון לניתוח." },
separationQuality: { type: '"fast" | "best"', description: "איכות ההפרדה, כמו ב-recast()‎." },
suggestTitle: { type: 'boolean', description: "מציע גם כותרת לקליפ." },
}}
/>

השדה `output_data` של המשימה שהסתיימה הוא `VcpAnalysis`: הרצועות המופרדות `vocalsUrl` ו-`backgroundUrl`, הדוברים שזוהו ב-`speakers` (לכל אחד `id`, מקטעי זמן ב-`segments`, `firstStartSec`, `wordCount` וקטע טקסט ב-`snippet`), `languageCode` עם `languageProbability`, ובנוסף `suggestedTitle` כשמבקשים אותו. העבירו את התוצאה הזו כ-`analysis` לכל קריאה מאוחרת יותר ל-`recast()`, כדי שהחלפת הקולות תשתמש שוב ברצועות המופרדות, בלי לשלם שוב על הזיהוי.

### voices.exportMix(input)‎
מרנדרת את הסרטון הסופי ממיקס של סטמים (`POST /v1/voice-changer-pro/export`). זה השלב האחרון אחרי `recast({ output: "stems" })`. הייצוא רץ ב-Nodaro Cloud כמשימה, במחיר קבוע.

```ts
exportMix(input: {
videoUrl: string
tracks: Array<{ url: string; gain: number; muted: boolean; kind?: "voice" | "background" }>
voiceFx?: { preset: AudioFxPreset; wetDryMix?: number; delayMs?: number; decay?: number }
}): Promise<{ jobId: string }>
```

<TypeTable
type={{
videoUrl: { type: 'string', required: true, description: "הסרטון. התמונה שלו מועתקת בלי קידוד מחדש." },
tracks: { type: 'VcpExportTrack[]', required: true, description: "עד 16 רצועות, ולפחות אחת מהן לא מושתקת. לכל רצועה יש url, ערך gain מ-0 עד 200, muted ו-kind אופציונלי." },
voiceFx: { type: '{ preset, wetDryMix?, delayMs?, decay? }', description: "אפקט על רצועות הקול בלבד, אף פעם לא על רצועת רקע." },
}}
/>

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

```ts

async function outputOf(jobId: string): Promise<any> {
for (;;) {
const { data } = await client.jobs.getStatus(jobId)
if (data.status === "completed") return data.output_data
if (data.status === "failed" || data.status === "cancelled") throw new Error(data.error_message ?? data.status)
await new Promise((resolve) => setTimeout(resolve, 2_000))
}
}

const { jobId: analyzeJob } = await client.voices.analyze({ videoUrl })
const analysis = (await outputOf(analyzeJob)) as VcpAnalysis

const { jobId: recastJob } = await client.voices.recast({
videoUrl,
orderedVoices: ["Rachel", null, "Aria"],
output: "stems",
analysis,
})
const stems = await outputOf(recastJob)

const { jobId: exportJob } = await client.voices.exportMix({
videoUrl,
tracks: [
{ url: stems.tracks[0].url, gain: 100, muted: false },
{ url: stems.tracks[1].url, gain: 90, muted: false },
{ url: stems.backgroundUrl, gain: 70, muted: false, kind: "background" },
],
voiceFx: { preset: "hall", wetDryMix: 25 },
})
const { videoUrl: finalVideo } = await outputOf(exportJob)
```

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

## client.voices: יצירה ותרגום
### voices.design(input)‎
יוצרת קול סינתטי חדש מתיאור כתוב (`POST /v1/voice-design`), כמו רכיב [עיצוב קול](https://nodaro.ai/docs/nodes/audio/voice-design). המשימה שהסתיימה כוללת האזנה מקדימה ואת המזהה של הקול החדש, שאפשר להשתמש בו בכל מקום שמקבל קול.

```ts
design(input: {
text: string
voiceDescription: string
model?: string
loudness?: number
guidanceScale?: number
seed?: number
quality?: number
shouldEnhance?: boolean
userPrompt?: string
}): Promise<{ jobId: string }>
```

<TypeTable
type={{
text: { type: 'string', required: true, description: "הטקסט שמוקרא בהאזנה המקדימה, 100–1,000 תווים." },
voiceDescription: { type: 'string', required: true, description: "הקול שאתם רוצים, כגון קול חם ונמוך של קריין מבוגר." },
model: { type: 'string', description: "מודל לעיצוב קול במקום מודל ברירת המחדל." },
loudness: { type: 'number', description: "העוצמה, בין ‎-1 ל-1." },
guidanceScale: { type: 'number', description: "עד כמה להיצמד לתיאור, מ-0 עד 100." },
seed: { type: 'number', description: "זרע לתוצאה שאפשר לשחזר." },
quality: { type: 'number', description: "הגדרת האיכות." },
shouldEnhance: { type: 'boolean', description: "מאפשר למודל להרחיב את התיאור שלכם." },
userPrompt: { type: 'string', description: "הבקשה המקורית שלכם, שנשמרת עם המשימה." },
}}
/>

```ts
const { jobId } = await client.voices.design({
text: "Welcome back. Tonight we follow the river north, into the mountains where the story began.",
voiceDescription: "A calm, deep voice of an older male narrator with a slight British accent",
})
```

### voices.remix(input)‎
מקריאה טקסט בקול שמתואר במילים פשוטות, בלי ליצור קול (`POST /v1/voice-remix`), כמו רכיב [רמיקס קול](https://nodaro.ai/docs/nodes/audio/voice-remix).

```ts
remix(input: { text: string; voiceDescription: string; userPrompt?: string }): Promise<{ jobId: string }>
```

<TypeTable
type={{
text: { type: 'string', required: true, description: "הטקסט להקראה, 1–5,000 תווים." },
voiceDescription: { type: 'string', required: true, description: "הקול שבו להשתמש, מתואר במילים." },
userPrompt: { type: 'string', description: "הבקשה המקורית שלכם, שנשמרת עם המשימה." },
}}
/>

```ts
const { jobId } = await client.voices.remix({
text: "Your order is on its way.",
voiceDescription: "A cheerful young woman, fast and upbeat",
})
```

### voices.dub(input)‎
מדבבת אודיו, או סרטון שלם, לשפה אחרת ושומרת על הקול של כל דובר (`POST /v1/dubbing`), כמו רכיב [דיבוב](https://nodaro.ai/docs/nodes/audio/dubbing). דיבוב של סרטון מחזיר את `output_data.videoUrl`, הקליפ המדובב, ואת `output_data.audioUrl`, רצועת האודיו המדובבת לבדה.

```ts
dub(input: DubbingInput): Promise<{ jobId: string }>
```

<TypeTable
type={{
targetLanguage: { type: 'string', required: true, description: "שפת היעד של הדיבוב, כקוד כגון es או pt-BR." },
audioUrl: { type: 'string', description: "מקור אודיו. שלחו בדיוק אחד מהשלושה: audioUrl, videoUrl או sourceUrl." },
videoUrl: { type: 'string', description: "מקור וידאו. התוצאה היא סרטון מדובב." },
sourceUrl: { type: 'string', description: "קישור ציבורי לדף שבו נמצא סרטון, או קישור ישיר למדיה, שנמשך בשבילכם." },
confirmationId: { type: 'string', description: "אישור זכויות התוכן ל-sourceUrl, מ-contentRights.confirm()‎." },
sourceLanguage: { type: 'string', description: "שפת הדיבור. כשמשמיטים אותה, היא מזוהה אוטומטית." },
numSpeakers: { type: 'number', default: '0', description: "מספר הדוברים, מ-1 עד 20, או 0 לזיהוי אוטומטי. מספר ידוע משפר את ההפרדה." },
disableVoiceCloning: { type: 'boolean', description: "משתמש בקולות כלליים במקום בקול של כל דובר." },
dropBackgroundAudio: { type: 'boolean', description: "משמיט את המוזיקה והאפקטים." },
startTime: { type: 'number', description: "מדבב רק מהנקודה הזו, בשניות." },
endTime: { type: 'number', description: "מדבב רק עד הנקודה הזו, בשניות." },
highestResolution: { type: 'boolean', description: "שומר על רזולוציית המקור בדיבוב של סרטון." },
useProfanityFilter: { type: 'boolean', description: "מסנן ניבולי פה." },
targetAccent: { type: 'string', description: "מבטא לדיבוב. ניסיוני." },
watermark: { type: 'boolean', description: "מוסיף לדיבוב של סרטון את סימן המים של יצרן המודל." },
}}
/>

```ts
const { jobId } = await client.voices.dub({
videoUrl: "https://example.com/interview.mp4",
targetLanguage: "es",
numSpeakers: 2,
})
```

המחיר נקבע לפי הדקות של הקטע המדובב, עם מינימום של דקה אחת. אורך הקטע הוא 30 דקות לכל היותר, ולכן במקורות ארוכים יותר השתמשו ב-`startTime` וב-`endTime`.

שירות הדיבוב מושך בשבילכם את `sourceUrl`, ולכן שליחה שלו היא ייבוא של הקישור הזה, שחלה עליו הצהרת זכויות התוכן. העבירו את ה-`confirmationId` שהמתודה `contentRights.confirm()` החזירה עבורו. בלי מזהה כזה, פריסה שדורשת אישור דוחה את הדיבוב עם `403`, עוד לפני שהמשימה נוצרת. מפתח או סוכן שבחשבון שלו יש הרשאה קבועה (`contentRights.authorize()`) לא צריכים מזהה כזה.

### voices.textToDialogue(input)‎
מקריאה תסריט עם כמה דוברים כקובץ אודיו **אחד** (`POST /v1/text-to-dialogue`), כמו רכיב [טקסט לדיאלוג](https://nodaro.ai/docs/nodes/audio/text-to-dialogue) עם [ElevenLabs Dialogue v3](https://nodaro.ai/docs/models/audio/elevenlabs-dialogue-v3) או עם [ElevenLabs Dialogue v4](https://nodaro.ai/docs/models/audio/elevenlabs-dialogue-v4).

```ts
textToDialogue(input: {
dialogue: Array<{ text: string; voice: string }>
provider?: "elevenlabs-dialogue" | "elevenlabs-dialogue-v4"
stability?: number
similarityBoost?: number
languageCode?: string
seed?: number
applyTextNormalization?: "auto" | "on" | "off"
}): Promise<{ jobId: string }>
```

<TypeTable
type={{
dialogue: { type: 'Array<{ text: string; voice: string }>', required: true, description: "השורות לפי סדר הדיבור. השדה voice הוא שם של קול מוכן מראש או מזהה קול של ElevenLabs. הטקסט יכול לכלול תגי אודיו, כגון ‎[laughs]‎ (צוחק)." },
provider: { type: '"elevenlabs-dialogue" | "elevenlabs-dialogue-v4"', default: '"elevenlabs-dialogue"', description: "מודל הדיאלוג: Dialogue v3, ברירת המחדל, או Dialogue v4." },
stability: { type: 'number', description: "יציבות ההגשה. Dialogue v3 מקבל רק 0, 0.5 או 1. Dialogue v4 מקבל כל ערך מ-0 עד 1." },
similarityBoost: { type: 'number', description: "ב-Dialogue v4 בלבד. עד כמה כל שורה נשארת נאמנה לקול שלה, מ-0 עד 1." },
languageCode: { type: 'string', description: "רמז לשפה, כקוד ISO 639-1. כשמשמיטים אותו, השפה מזוהה אוטומטית." },
seed: { type: 'number', description: "מ-0 עד 4,294,967,295, לתוצאה שאפשר לשחזר. השמיטו אותו כדי לקבל תוצאה אקראית." },
applyTextNormalization: { type: '"auto" | "on" | "off"', description: "אם להמיר מספרים וקיצורים למילים מלאות." },
}}
/>

```ts
const { jobId } = await client.voices.textToDialogue({
dialogue: [
{ text: "Did you hear that?", voice: "Rachel" },
{ text: "[whispers] Stay behind me.", voice: "Callum" },
],
})
```

תסריט יכול להיות באורך של עד 5,000 תווים ב-Dialogue v3 ועד 10,000 ב-Dialogue v4, והאיכות הטובה ביותר מתקבלת בפחות מ-2,000 תווים. בתסריט אפשר להשתמש ב-10 קולות שונים לכל היותר. קולות מספריית הקולות, קולות שעוצבו וקולות משוכפלים קיימים עובדים כולם, בכל שילוב. הקובץ נמצא ב-`output_data.audioUrl` של המשימה שהסתיימה. בשני המודלים, ב-`output_data.transcript` נמצאים התזמונים: המערך `words[]` עם `startMs`, `endMs` ו-`speaker`, ופריט אחד ב-`segments[]` לכל שורה, שבו השדה `speaker` הוא ה-`voice` של השורה. העבירו את `transcript.words` ל-`addCaptions` עם `autoTranscribe: false` כדי להוסיף כתוביות לדיאלוג בלי תמלול נוסף.

## client.audio
כאן נמצאות, כל אחת בנפרד, אבני הבניין של האודיו שרכיב משנה קול Pro משתמש בהן מאחורי הקלעים. כל מתודה מחזירה `jobId`.

### audio.separate(input)‎
מפצלת רצועה לסטמים (`POST /v1/audio-separation`), כמו רכיב [הפרדת אודיו](https://nodaro.ai/docs/nodes/audio/audio-separation).

```ts
separate(input: { audioUrl: string; mode?: "vocal_instrumental" | "stems"; quality?: "auto" | "fast" | "best" }): Promise<{ jobId: string }>
```

<TypeTable
type={{
audioUrl: { type: 'string', required: true, description: "הרצועה לפיצול." },
mode: { type: '"vocal_instrumental" | "stems"', default: '"vocal_instrumental"', description: "הערך vocal_instrumental מפריד את הקול מהמוזיקה ומהאפקטים. הערך stems מחזיר תופים, בס ושאר החלקים." },
quality: { type: '"auto" | "fast" | "best"', description: "איכות ההפרדה." },
}}
/>

```ts
const { jobId } = await client.audio.separate({ audioUrl: songUrl })
// output: vocalUrl and instrumentalUrl, or one URL per stem in stems mode
```

### audio.isolate(input)‎
שומרת על הקול הראשי ומסירה רעשי רקע (`POST /v1/audio-isolation`), כמו רכיב [מחלץ קול](https://nodaro.ai/docs/nodes/audio/voice-extractor).

```ts
isolate(input: { audioUrl: string }): Promise<{ jobId: string }>
```

<TypeTable
type={{
audioUrl: { type: 'string', required: true, description: "ההקלטה לניקוי." },
}}
/>

```ts
const { jobId } = await client.audio.isolate({ audioUrl: interviewUrl })
```

### audio.applyFx(input)‎
מוסיפה אפקט של ריוורב, הד, טלפון או מגפון (`POST /v1/audio-fx`), כמו רכיב [אפקטי אודיו](https://nodaro.ai/docs/nodes/audio/audio-fx). הערכות זהות לאלה של `voiceFx` בהחלפת הקול.

```ts
applyFx(input: {
audioUrl: string
preset?: AudioFxPreset
mix?: number
delayMs?: number
decay?: number
eqLow?: number
eqHigh?: number
}): Promise<{ jobId: string }>
```

<TypeTable
type={{
audioUrl: { type: 'string', required: true, description: "הרצועה לעיבוד." },
preset: { type: 'AudioFxPreset', description: "חלל ריוורב כגון room, hall או church, או telephone, megaphone, echo או custom." },
mix: { type: 'number', description: "היחס בין הצליל הרטוב ליבש בריוורב, מ-0 עד 100." },
delayMs: { type: 'number', description: "ההשהיה של ההד, ב-echo וב-custom." },
decay: { type: 'number', description: "הדעיכה של ההד, ב-echo וב-custom." },
eqLow: { type: 'number', description: "הנמכה או הגברה של התדרים הנמוכים ב-dB, ב-telephone וב-megaphone." },
eqHigh: { type: 'number', description: "הנמכה או הגברה של התדרים הגבוהים ב-dB, ב-telephone וב-megaphone." },
}}
/>

```ts
const { jobId } = await client.audio.applyFx({ audioUrl: lineUrl, preset: "telephone" })
```

### audio.mix(input)‎
משלבת כמה רצועות בשכבות לרצועה אחת (`POST /v1/mix-audio`), כמו רכיב [מיקס אודיו](https://nodaro.ai/docs/nodes/audio/mix-audio).

```ts
mix(input: {
audioUrls: string[]
trackVolumes?: number[]
duck?: { under: number; amount?: number; thresholdDb?: number; ratio?: number; attackMs?: number; releaseMs?: number }
endAt?: "longest" | "voice"
}): Promise<{ jobId: string }>
```

<TypeTable
type={{
audioUrls: { type: 'string[]', required: true, description: "2–20 רצועות, שמתנגנות יחד." },
trackVolumes: { type: 'number[]', description: "עוצמה לכל רצועה באחוזים, מ-0% עד 200%, באותו סדר." },
duck: { type: 'object', description: "כל הרצועות חוץ מ-audioUrls[under]‎ מונמכות כל עוד הרצועה הזו חזקה. השדה under הוא האינדקס (מ-0) של רצועת הקול. השדה amount הוא מ-0 עד 100, וברירת המחדל היא 75. השדות thresholdDb (בין ‎-60 ל-0, ברירת המחדל ‎-30), attackMs (מ-1 עד 2,000, ברירת המחדל 20), releaseMs (מ-10 עד 9,000, ברירת המחדל 500) ו-ratio (מ-1 עד 20, גובר על amount) הם אופציונליים. המחיר זהה עם הנמכה ובלעדיה." },
endAt: { type: '"longest" | "voice"', description: "איפה המיקס נגמר. הערך \"longest\" (ברירת המחדל) מסיים אותו כשהרצועה הארוכה ביותר שלו נגמרת. הערך \"voice\" מסיים אותו כשהרצועה שב-duck.under נגמרת, כך שמוזיקת רקע ארוכה יותר נחתכת בנקודה הזו. הערך \"voice\" דורש את duck; בלעדיו הבקשה נדחית עם 400 validation_error.", default: '"longest"' },
}}
/>

```ts
const { jobId } = await client.audio.mix({ audioUrls: [voiceUrl, musicUrl], trackVolumes: [100, 35] })

// The music dips under the voice (track 0) while it speaks.
const ducked = await client.audio.mix({ audioUrls: [voiceUrl, musicUrl], duck: { under: 0, amount: 80 } })
```

### audio.adjustVolume(input)‎
משנה את העוצמה של קובץ אודיו, או של הסאונד של סרטון (`POST /v1/adjust-volume`), כמו רכיב [כוונון עוצמה](https://nodaro.ai/docs/nodes/audio/adjust-volume).

```ts
adjustVolume(input: {
audioUrl?: string
videoUrl?: string
volume?: number
normalize?: boolean
fadeIn?: number
fadeOut?: number
}): Promise<{ jobId: string }>
```

<TypeTable
type={{
audioUrl: { type: 'string', description: "קובץ אודיו. שלחו audioUrl או videoUrl." },
videoUrl: { type: 'string', description: "סרטון שבו משנים את הסאונד." },
volume: { type: 'number', default: '100', description: "העוצמה באחוזים." },
normalize: { type: 'boolean', description: "מביא את העוצמה לרמה סטנדרטית." },
fadeIn: { type: 'number', description: "עמעום כניסה, בשניות." },
fadeOut: { type: 'number', description: "עמעום יציאה, בשניות." },
}}
/>

```ts
const { jobId } = await client.audio.adjustVolume({ audioUrl: musicUrl, volume: 60, fadeOut: 3 })
```

### audio.pitchTempo(input)‎
מזיזה את גובה הצליל, או משנה את הטמפו בלי לשנות את גובה הצליל (`POST /v1/pitch-tempo`), כמו רכיב [גובה צליל וטמפו](https://nodaro.ai/docs/nodes/audio/pitch-tempo). שלחו בדיוק אחד מהשניים, `audioUrl` או `videoUrl`. כשהמקור הוא סרטון, התמונה שלו נשמרת, והטמפו שלו נשאר 1.

```ts
pitchTempo(input: {
audioUrl?: string
videoUrl?: string
semitones?: number
tempo?: number
preserveFormants?: boolean
}): Promise<{ jobId: string }>
```

<TypeTable
type={{
audioUrl: { type: 'string', description: "האודיו לעיבוד. שלחו אותו או את videoUrl." },
videoUrl: { type: 'string', description: "הסרטון שאת הסאונד שלו מעבדים. התמונה מועתקת כמו שהיא." },
semitones: { type: 'number', description: "הזזת גובה הצליל, בין ‎-12 ל-12. הערך 12 הוא אוקטבה אחת למעלה.", default: '0' },
tempo: { type: 'number', description: "המהירות, מ-0.5 עד 2, בלי שינוי בגובה הצליל. לא נלקח בחשבון כשהמקור הוא סרטון.", default: '1' },
preserveFormants: { type: 'boolean', description: "שומר על הצליל הטבעי של הקול כשגובה הצליל משתנה.", default: 'true' },
}}
/>

ההרצה עולה 22 קרדיטים לכל דקה של הקלט, או חלק ממנה, עד 30 דקות.

```ts
const { jobId } = await client.audio.pitchTempo({ audioUrl: voiceUrl, semitones: -3 })
```
### audio.combine(input)‎
מאחדת מקטעי אודיו ברצף, זה אחרי זה (`POST /v1/combine-audio`), כמו רכיב [שילוב אודיו](https://nodaro.ai/docs/nodes/audio/combine-audio).

```ts
combine(input: { segments: Array<{ url: string; startTime?: number; endTime?: number }> }): Promise<{ jobId: string }>
```

<TypeTable
type={{
segments: { type: 'Array<{ url: string; startTime?: number; endTime?: number }>', required: true, description: "המקטעים לפי הסדר. כל מקטע יכול להשתמש רק בחלק מהקובץ שלו, מ-startTime עד endTime, בשניות." },
}}
/>

```ts
const { jobId } = await client.audio.combine({
segments: [{ url: introUrl }, { url: episodeUrl, startTime: 4 }, { url: outroUrl }],
})
```

### audio.transcribe(input)‎
הופכת את הדיבור בקובץ אודיו או וידאו לטקסט (`POST /v1/transcribe`), כמו רכיב [תמלול](https://nodaro.ai/docs/nodes/audio/transcribe).

```ts
transcribe(input: {
audioUrl: string
provider?: "elevenlabs-stt" | "incredibly-fast-whisper" | "whisper"
language?: string
diarize?: boolean
tagAudioEvents?: boolean
wordTimestamps?: boolean
confirmationId?: string
}): Promise<{ jobId: string }>
```

<TypeTable
type={{
audioUrl: { type: 'string', required: true, description: "קובץ האודיו או הווידאו." },
provider: { type: '"elevenlabs-stt" | "incredibly-fast-whisper" | "whisper"', default: '"whisper"', description: "המנוע. ראו את הטבלה שלמטה." },
language: { type: 'string', description: "קובע את השפה מראש. השמיטו אותו כדי שהשפה תזוהה אוטומטית." },
diarize: { type: 'boolean', description: "מציין מי אמר כל מילה. ב-elevenlabs-stt בלבד." },
tagAudioEvents: { type: 'boolean', description: "מתייג צחוק, מחיאות כפיים וצלילים אחרים. ב-elevenlabs-stt בלבד." },
wordTimestamps: { type: 'boolean', description: "מבקש תזמון לכל מילה." },
confirmationId: { type: 'string', description: "אישור זכויות התוכן לקישור לדף של סרטון, מ-contentRights.confirm()‎." },
}}
/>

שליחת `audioUrl` שמקשר לדף של סרטון ברשת חברתית היא ייבוא של הקישור הזה: Nodaro מוריד קודם את הסאונד שלו. העבירו את ה-`confirmationId` שהמתודה `contentRights.confirm()` החזירה לקישור הזה. בלי מזהה כזה, פריסה שדורשת אישור דוחה את הבקשה עם `403`, עוד לפני שהמשימה נוצרת. מפתח או סוכן שבחשבון שלו יש הרשאה קבועה (`contentRights.authorize()`) לא צריכים מזהה כזה. גם קישור ישיר לקובץ לא צריך מזהה כזה.

| `provider` | תזמון לכל מילה | הערות |
| --- | --- | --- |
| [`elevenlabs-stt`](https://nodaro.ai/docs/models/audio/elevenlabs-stt) | תמיד | המנוע היחיד שתומך ב-`diarize` וב-`tagAudioEvents`. |
| [`incredibly-fast-whisper`](https://nodaro.ai/docs/models/audio/incredibly-fast-whisper) | רק עם `wordTimestamps: true` | בלי הדגל, המשימה מצליחה ומשלמים עליה, אבל היא מחזירה מקטעים ברמת המשפט ורשימת `words` ריקה. |
| [`whisper`](https://nodaro.ai/docs/models/audio/whisper) | אף פעם | מקטעים ברמת המשפט בלבד. בקשה עם `wordTimestamps: true` נדחית עם `400 validation_error` לפני שנגבים קרדיטים. |

בקשה בלי `provider` רצה על `whisper`, ולכן גם בקשה עם `wordTimestamps: true` ובלי `provider` נדחית עם 400. כדי לקבל תזמון לכל מילה, ציינו את `elevenlabs-stt`, או את `incredibly-fast-whisper` עם `wordTimestamps: true`. כתוביות מונפשות צריכות את התזמון הזה.

```ts
const { jobId } = await client.audio.transcribe({ audioUrl: talkUrl, provider: "elevenlabs-stt" })
```

השדה `output_data` של המשימה שהסתיימה הוא `TranscribeJobOutput`:

| שדה | יחידות | תוכן |
| --- | --- | --- |
| `text` | | התמלול כולו כמחרוזת אחת. |
| `language` | | קוד השפה שזוהתה או שהתבקשה. |
| `words` | אלפיות שנייה | פריט אחד לכל מילה: `{ text, startMs, endMs, speaker? }`. הרשימה ריקה כשלא ביקשו מהמנוע תזמון לכל מילה. |
| `json` | אלפיות שנייה | התמלול המנורמל, `{ version, language, words, segments? }`, שהמשאב [`client.edit`](https://nodaro.ai/docs/developers/sdk/editing) מקבל. |
| `segments` | **שניות** | טווחי הזמן הגולמיים של המשפטים, רק מהמנועים הישנים יותר. המנוע `elevenlabs-stt` לא מחזיר אותם, ולכן השתמשו ב-`words`. |

המבנה של `words` זהה בדיוק למבנה של `captions` שהמתודה [`client.media.addCaptions()`](https://nodaro.ai/docs/developers/sdk/media-and-uploads#mediaaddcaptionsinput) מקבלת, כך שאפשר לתקן תמלול ולצרוב אותו ככתוביות.

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

### איך מחליפים את הקול בסרטון עם ה-SDK של Nodaro?

קראו למתודה client.voices.change עם הפרמטרים videoUrl ו-voiceId. השרת מחליף את הקול ומחזיר את הקול החדש לסרטון המקורי. בדקו את הסטטוס של המשימה מדי כמה שניות, וכשהיא מסתיימת, הסרטון נמצא ב-output_data.videoUrl.

### איך נותנים לכל דובר בהקלטה קול אחר?

קראו למתודה client.voices.recast עם הפרמטר orderedVoices: פריט אחד לכל דובר שזוהה, לפי הסדר. לדובר שצריך לשמור על הקול שלו, שלחו null. החלפת הקולות רצה ב-Nodaro Cloud.

### האם אפשר עדיין לשכפל קול עם ה-SDK?

לא. שכפול קולות הוצא משימוש בספטמבר 2026, והמתודה createClone נכשלת עכשיו עם 410 voice_cloning_retired. קולות משוכפלים קיימים עדיין עובדים. במקום זאת, עצבו קול חדש עם המתודה client.voices.design.

### איזה מנוע תמלול מחזיר תזמון לכל מילה?

המנוע elevenlabs-stt מחזיר תמיד תזמון לכל מילה. המנוע incredibly-fast-whisper מחזיר אותו רק כש-wordTimestamps מוגדר ל-true, והמנוע whisper אף פעם לא מחזיר אותו.
