@nodaro/sdk 1.4.0 → 1.6.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 +1 -1
- package/dist/index.cjs +209 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +304 -2
- package/dist/index.d.ts +304 -2
- package/dist/index.js +208 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -270,7 +270,7 @@ try {
|
|
|
270
270
|
| `client.locations` | Location Studio: CRUD, assets, atmosphere motion |
|
|
271
271
|
| `client.objects` | Object Studio: CRUD, assets, motion |
|
|
272
272
|
| `client.creatures` | Creature Studio: CRUD, assets, motion |
|
|
273
|
-
| `client.voices` | Voice
|
|
273
|
+
| `client.voices` | Voice catalog + clones (from URL or file), voice changer, multi-speaker recast + the interactive `analyze`/stems/`exportMix` flow, design, remix, dubbing |
|
|
274
274
|
| `client.pipelines` | Showrunner pipelines: stages, approvals, chat, branch |
|
|
275
275
|
| `client.reduce` | Fan-in reducer (pick-best, concat, vote, merge…) |
|
|
276
276
|
| `client.promptHelper` | Prompt enhancement / wizard |
|
package/dist/index.cjs
CHANGED
|
@@ -1584,6 +1584,209 @@ var VoicesResource = class {
|
|
|
1584
1584
|
exportMix(input) {
|
|
1585
1585
|
return this.client.request("POST", "/v1/voice-changer-pro/export", { body: input });
|
|
1586
1586
|
}
|
|
1587
|
+
/**
|
|
1588
|
+
* Design a brand-new synthetic voice from a text description
|
|
1589
|
+
* (`POST /v1/voice-design`) — ElevenLabs text-to-voice. `text` (100–1000 chars)
|
|
1590
|
+
* is a preview line spoken in the designed voice; `voiceDescription` describes
|
|
1591
|
+
* the voice to create. Costs credits and runs async — poll `jobs.get(jobId)`
|
|
1592
|
+
* for the preview + the reusable voice id.
|
|
1593
|
+
*/
|
|
1594
|
+
design(input) {
|
|
1595
|
+
return this.client.request("POST", "/v1/voice-design", { body: input });
|
|
1596
|
+
}
|
|
1597
|
+
/**
|
|
1598
|
+
* Generate speech in a voice described in natural language, without cloning
|
|
1599
|
+
* (`POST /v1/voice-remix`). `text` (1–5000 chars) is spoken in a voice matching
|
|
1600
|
+
* `voiceDescription`. Costs credits and runs async — poll `jobs.get(jobId)`.
|
|
1601
|
+
*/
|
|
1602
|
+
remix(input) {
|
|
1603
|
+
return this.client.request("POST", "/v1/voice-remix", { body: input });
|
|
1604
|
+
}
|
|
1605
|
+
/**
|
|
1606
|
+
* Dub an audio clip into another language while preserving each speaker's voice
|
|
1607
|
+
* (`POST /v1/dubbing`). `targetLanguage` is an ISO code (e.g. `"es"`, `"fr"`);
|
|
1608
|
+
* `sourceLanguage` is auto-detected when omitted. Costs credits and runs async
|
|
1609
|
+
* — poll `jobs.get(jobId)`.
|
|
1610
|
+
*/
|
|
1611
|
+
dub(input) {
|
|
1612
|
+
return this.client.request("POST", "/v1/dubbing", { body: input });
|
|
1613
|
+
}
|
|
1614
|
+
/**
|
|
1615
|
+
* Clone a voice from an audio FILE you hold in memory
|
|
1616
|
+
* (`POST /v1/voice-clones`, multipart) — the counterpart to
|
|
1617
|
+
* {@link VoicesResource.createClone}, which clones from an already-uploaded
|
|
1618
|
+
* URL. Pass the raw audio `file` (a `Blob`/`File` in the browser, or a
|
|
1619
|
+
* `Uint8Array`/`Buffer` in Node) plus a `name`. Costs credits. Returns the new
|
|
1620
|
+
* {@link VoiceClone} (`elevenlabsVoiceId` is the id to recast/synthesize with).
|
|
1621
|
+
*/
|
|
1622
|
+
createCloneFromFile(input) {
|
|
1623
|
+
const form = new FormData();
|
|
1624
|
+
form.append("name", input.name);
|
|
1625
|
+
const blob = input.file instanceof Blob ? input.file : new Blob([input.file], { type: input.contentType ?? "audio/mpeg" });
|
|
1626
|
+
form.append("file", blob, input.filename ?? "sample");
|
|
1627
|
+
return this.client.request("POST", "/v1/voice-clones", { body: form });
|
|
1628
|
+
}
|
|
1629
|
+
};
|
|
1630
|
+
|
|
1631
|
+
// src/resources/media.ts
|
|
1632
|
+
var MediaResource = class {
|
|
1633
|
+
constructor(client) {
|
|
1634
|
+
this.client = client;
|
|
1635
|
+
}
|
|
1636
|
+
client;
|
|
1637
|
+
/**
|
|
1638
|
+
* Download a social video (YouTube / TikTok / Instagram / X / Facebook) into
|
|
1639
|
+
* your storage (`POST /v1/download-video`). `maxHeight` caps the resolution
|
|
1640
|
+
* (default "best"); `sectionStartSec` + `sectionEndSec` (both-or-neither) fetch
|
|
1641
|
+
* ONLY that time range instead of the whole video. Returns a `downloadId`;
|
|
1642
|
+
* progress streams from `GET /v1/download-video/progress/:downloadId`
|
|
1643
|
+
* (server-sent events) and the finished file lands in your library.
|
|
1644
|
+
*/
|
|
1645
|
+
downloadVideo(input) {
|
|
1646
|
+
return this.client.request("POST", "/v1/download-video", { body: input });
|
|
1647
|
+
}
|
|
1648
|
+
/**
|
|
1649
|
+
* Stream the live progress of a {@link MediaResource.downloadVideo} import
|
|
1650
|
+
* (`GET /v1/download-video/progress/:downloadId`, server-sent events) as an
|
|
1651
|
+
* async iterable. Yields a {@link DownloadVideoProgress} roughly every 500ms
|
|
1652
|
+
* until the download reaches `completed` (its event carries the stored
|
|
1653
|
+
* `videoUrl`) or `failed` (its event carries `error`), then ends. The progress
|
|
1654
|
+
* state expires server-side shortly after the download starts existing, so
|
|
1655
|
+
* start iterating promptly after `downloadVideo` returns.
|
|
1656
|
+
*
|
|
1657
|
+
* No request timeout is applied (a large import legitimately takes minutes) —
|
|
1658
|
+
* pass an `AbortSignal` to cancel from the caller.
|
|
1659
|
+
*/
|
|
1660
|
+
async *downloadVideoProgress(downloadId, opts = {}) {
|
|
1661
|
+
const url = `${this.client.baseUrl}/v1/download-video/progress/${encodeURIComponent(downloadId)}`;
|
|
1662
|
+
const token = await this.client.auth.getToken();
|
|
1663
|
+
const res = await this.client.fetch(url, {
|
|
1664
|
+
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
|
1665
|
+
signal: opts.signal
|
|
1666
|
+
});
|
|
1667
|
+
if (!res.ok) {
|
|
1668
|
+
let errBody = {};
|
|
1669
|
+
try {
|
|
1670
|
+
errBody = await res.json();
|
|
1671
|
+
} catch {
|
|
1672
|
+
}
|
|
1673
|
+
throwFromResponse(res.status, errBody);
|
|
1674
|
+
}
|
|
1675
|
+
if (!res.body) {
|
|
1676
|
+
throw new NodaroError("progress stream has no response body", "empty_stream", res.status);
|
|
1677
|
+
}
|
|
1678
|
+
const reader = res.body.getReader();
|
|
1679
|
+
const decoder = new TextDecoder();
|
|
1680
|
+
let buffer = "";
|
|
1681
|
+
try {
|
|
1682
|
+
for (; ; ) {
|
|
1683
|
+
const { done, value } = await reader.read();
|
|
1684
|
+
if (done) break;
|
|
1685
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1686
|
+
let sep;
|
|
1687
|
+
while ((sep = buffer.indexOf("\n\n")) >= 0) {
|
|
1688
|
+
const frame = buffer.slice(0, sep);
|
|
1689
|
+
buffer = buffer.slice(sep + 2);
|
|
1690
|
+
for (const line of frame.split("\n")) {
|
|
1691
|
+
if (!line.startsWith("data:")) continue;
|
|
1692
|
+
try {
|
|
1693
|
+
yield JSON.parse(line.slice(5).trim());
|
|
1694
|
+
} catch {
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
} finally {
|
|
1700
|
+
reader.releaseLock();
|
|
1701
|
+
await res.body.cancel().catch(() => {
|
|
1702
|
+
});
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
/**
|
|
1706
|
+
* Copy an external media URL into your Nodaro storage (`POST /v1/save-to-storage`)
|
|
1707
|
+
* — a server-side fetch, so nothing round-trips through the client. Poll
|
|
1708
|
+
* `jobs.get(jobId)`.
|
|
1709
|
+
*/
|
|
1710
|
+
saveToStorage(input) {
|
|
1711
|
+
return this.client.request("POST", "/v1/save-to-storage", { body: input });
|
|
1712
|
+
}
|
|
1713
|
+
/**
|
|
1714
|
+
* Trim a video to a range (`POST /v1/trim-video`). Give the range in whichever
|
|
1715
|
+
* unit fits: `startTime`/`endTime` seconds, `trim*Frames`, `trim*Seconds`, or
|
|
1716
|
+
* `keepFirst`/`keepLastSeconds`. Poll `jobs.get(jobId)`.
|
|
1717
|
+
*/
|
|
1718
|
+
trimVideo(input) {
|
|
1719
|
+
return this.client.request("POST", "/v1/trim-video", { body: input });
|
|
1720
|
+
}
|
|
1721
|
+
/**
|
|
1722
|
+
* Trim (and extract) audio from a video or audio source
|
|
1723
|
+
* (`POST /v1/trim-audio`) to `[startTime, endTime]` seconds, in `audioFormat`
|
|
1724
|
+
* (`mp3` default / `wav` / `aac`). Poll `jobs.get(jobId)`.
|
|
1725
|
+
*/
|
|
1726
|
+
trimAudio(input) {
|
|
1727
|
+
return this.client.request("POST", "/v1/trim-audio", { body: input });
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Probe a social video's metadata (`POST /v1/video-metadata`) — duration,
|
|
1731
|
+
* dimensions, title, live status — WITHOUT downloading it. A direct read, not a
|
|
1732
|
+
* job. Use it to decide whether to trim before importing.
|
|
1733
|
+
*/
|
|
1734
|
+
videoMetadata(input) {
|
|
1735
|
+
return this.client.request("POST", "/v1/video-metadata", { body: input });
|
|
1736
|
+
}
|
|
1737
|
+
};
|
|
1738
|
+
|
|
1739
|
+
// src/resources/audio.ts
|
|
1740
|
+
var AudioResource = class {
|
|
1741
|
+
constructor(client) {
|
|
1742
|
+
this.client = client;
|
|
1743
|
+
}
|
|
1744
|
+
client;
|
|
1745
|
+
/**
|
|
1746
|
+
* Separate an audio track into stems (`POST /v1/audio-separation`, Demucs).
|
|
1747
|
+
* `mode` `"vocal_instrumental"` (default) splits voice from music/SFX;
|
|
1748
|
+
* `"stems"` returns the full drums/bass/other/… breakdown. `quality`
|
|
1749
|
+
* `auto` (default) / `fast` / `best`.
|
|
1750
|
+
*/
|
|
1751
|
+
separate(input) {
|
|
1752
|
+
return this.client.request("POST", "/v1/audio-separation", { body: input });
|
|
1753
|
+
}
|
|
1754
|
+
/** Isolate the primary voice and strip background noise (`POST /v1/audio-isolation`, ElevenLabs). */
|
|
1755
|
+
isolate(input) {
|
|
1756
|
+
return this.client.request("POST", "/v1/audio-isolation", { body: input });
|
|
1757
|
+
}
|
|
1758
|
+
/**
|
|
1759
|
+
* Apply a reverb / echo / telephone / megaphone effect to an audio track
|
|
1760
|
+
* (`POST /v1/audio-fx`) — the same presets VCP's `voiceFx` uses, standalone.
|
|
1761
|
+
* `mix` (0–100) is the reverb wet/dry; `delayMs` + `decay` drive `echo`/`custom`;
|
|
1762
|
+
* `eqLow`/`eqHigh` (dB) shape telephone/megaphone.
|
|
1763
|
+
*/
|
|
1764
|
+
applyFx(input) {
|
|
1765
|
+
return this.client.request("POST", "/v1/audio-fx", { body: input });
|
|
1766
|
+
}
|
|
1767
|
+
/**
|
|
1768
|
+
* Layer multiple audio tracks into one (`POST /v1/mix-audio`). `audioUrls`
|
|
1769
|
+
* (2–20) are summed; optional `trackVolumes` (0–200% each, positionally) set
|
|
1770
|
+
* per-track level.
|
|
1771
|
+
*/
|
|
1772
|
+
mix(input) {
|
|
1773
|
+
return this.client.request("POST", "/v1/mix-audio", { body: input });
|
|
1774
|
+
}
|
|
1775
|
+
/**
|
|
1776
|
+
* Adjust an audio (or a video's audio) level (`POST /v1/adjust-volume`):
|
|
1777
|
+
* `volume` % (default 100), `normalize` to loudnorm, and `fadeIn`/`fadeOut`
|
|
1778
|
+
* seconds. Provide `audioUrl` or `videoUrl`.
|
|
1779
|
+
*/
|
|
1780
|
+
adjustVolume(input) {
|
|
1781
|
+
return this.client.request("POST", "/v1/adjust-volume", { body: input });
|
|
1782
|
+
}
|
|
1783
|
+
/**
|
|
1784
|
+
* Concatenate audio segments end-to-end (`POST /v1/combine-audio`). Each
|
|
1785
|
+
* segment is a `url` with an optional `[startTime, endTime]` sub-range.
|
|
1786
|
+
*/
|
|
1787
|
+
combine(input) {
|
|
1788
|
+
return this.client.request("POST", "/v1/combine-audio", { body: input });
|
|
1789
|
+
}
|
|
1587
1790
|
};
|
|
1588
1791
|
|
|
1589
1792
|
// src/resources/credits.ts
|
|
@@ -1886,6 +2089,8 @@ var NodaroClient = class {
|
|
|
1886
2089
|
reduce;
|
|
1887
2090
|
promptHelper;
|
|
1888
2091
|
voices;
|
|
2092
|
+
media;
|
|
2093
|
+
audio;
|
|
1889
2094
|
credits;
|
|
1890
2095
|
uploads;
|
|
1891
2096
|
library;
|
|
@@ -1913,6 +2118,8 @@ var NodaroClient = class {
|
|
|
1913
2118
|
this.reduce = new ReduceResource(this);
|
|
1914
2119
|
this.promptHelper = new PromptHelperResource(this);
|
|
1915
2120
|
this.voices = new VoicesResource(this);
|
|
2121
|
+
this.media = new MediaResource(this);
|
|
2122
|
+
this.audio = new AudioResource(this);
|
|
1916
2123
|
this.credits = new CreditsResource(this);
|
|
1917
2124
|
this.uploads = new UploadsResource(this);
|
|
1918
2125
|
this.library = new LibraryResource(this);
|
|
@@ -2079,6 +2286,7 @@ Object.defineProperty(exports, "SURROUND_DIRECTIONS", {
|
|
|
2079
2286
|
get: function () { return shared.SURROUND_DIRECTIONS; }
|
|
2080
2287
|
});
|
|
2081
2288
|
exports.AppsResource = AppsResource;
|
|
2289
|
+
exports.AudioResource = AudioResource;
|
|
2082
2290
|
exports.CREATURE_ASSET_TYPES = CREATURE_ASSET_TYPES;
|
|
2083
2291
|
exports.CallbackAuth = CallbackAuth;
|
|
2084
2292
|
exports.CharactersResource = CharactersResource;
|
|
@@ -2095,6 +2303,7 @@ exports.JobTimeoutError = JobTimeoutError;
|
|
|
2095
2303
|
exports.JobsResource = JobsResource;
|
|
2096
2304
|
exports.LibraryResource = LibraryResource;
|
|
2097
2305
|
exports.LocationsResource = LocationsResource;
|
|
2306
|
+
exports.MediaResource = MediaResource;
|
|
2098
2307
|
exports.NodaroClient = NodaroClient;
|
|
2099
2308
|
exports.NodaroError = NodaroError;
|
|
2100
2309
|
exports.NodesResource = NodesResource;
|