samsar-js 0.48.24 → 0.48.26
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 +25 -3
- package/dist/index.d.ts +37 -4
- package/dist/index.js +138 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -153,8 +153,17 @@ const translated = await samsar.translateVideo(
|
|
|
153
153
|
{
|
|
154
154
|
videoSessionId: videoFromImages.data.session_id ?? videoFromImages.data.request_id!,
|
|
155
155
|
language: 'es',
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
enable_subtitles: false,
|
|
157
|
+
translate_outro: true,
|
|
158
|
+
translate_footer: true,
|
|
159
|
+
},
|
|
160
|
+
{ webhookUrl: 'https://example.com/webhook' },
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// Deep-clone an existing completed session and render a new final video URL
|
|
164
|
+
const cloned = await samsar.cloneVideo(
|
|
165
|
+
{
|
|
166
|
+
videoSessionId: videoFromImages.data.session_id ?? videoFromImages.data.request_id!,
|
|
158
167
|
},
|
|
159
168
|
{ webhookUrl: 'https://example.com/webhook' },
|
|
160
169
|
);
|
|
@@ -543,6 +552,7 @@ Video model support notes:
|
|
|
543
552
|
- `createVideoFromImageList` can render per-scene footer QR cards by setting `add_footer_animation: true` and providing one `footer_metadata` item per image scene.
|
|
544
553
|
- `updateVideoOutroImage` accepts either a replacement outro image URL (`outro_image_url`, `outroImageUrl`, `new_outro_image_url`) or a generated QR CTA outro (`generate_outro_image: true` with `cta_url`, or just `cta_url` when no outro image URL is supplied). Generated outro updates reuse the existing session image layers for tiling and only queue frame/video regeneration.
|
|
545
554
|
- `updateVideoFooterImage` updates the footer CTA on a cloned session with `cta_text`, `cta_logo`, and/or `cta_url`, or removes all scene footers with `remove_footer: true`. Footer updates queue only frame/video regeneration.
|
|
555
|
+
- `cloneVideo` creates a deep copy of a completed session and queues only the final video render so the clone receives a new rendered video path and URL. It does not charge credits.
|
|
546
556
|
- Main video methods and external-user methods accept the same generated outro and footer parameters. The API can resolve either internal session ids or external `extreq_...` ids on repeated video routes, so client code can keep using `translateVideo`, `joinVideos`, `addSubtitles`, `removeSubtitles`, `addVideoOutroImage`, `updateVideoOutroImage`, and `updateVideoFooterImage`; the explicit external variants are available when you want to call `/external_users/*` directly. Do not strip the `extreq_` prefix.
|
|
547
557
|
- Completed video status, latest-version, and completed-session list responses expose `has_subtitles` and `result_language` when the session metadata is available.
|
|
548
558
|
- `publishPublication`, `editPublication`, and `revokePublication` manage public feed publications for completed sessions through free `/publications/*` endpoints. They work with account API keys, customer sub-account API keys, and client auth tokens when the session belongs to the authenticated actor.
|
|
@@ -550,7 +560,7 @@ Video model support notes:
|
|
|
550
560
|
|
|
551
561
|
Upcoming `/v2` omni route adapters:
|
|
552
562
|
- `/v2` is additive; `/v1` is not deprecated.
|
|
553
|
-
- `createV2VideoFromText`, `createV2VideoFromImageList`, `updateV2VideoOutroImage`, `updateV2VideoFooterImage`, `addV2VideoOutroImage`, `getV2Status`, `getV2Credits`, `listV2Requests`, and `createV2Session` call the new omni route surface.
|
|
563
|
+
- `createV2VideoFromText`, `createV2VideoFromImageList`, `translateV2Video`, `cloneV2Video`, `updateV2VideoOutroImage`, `updateV2VideoFooterImage`, `addV2VideoOutroImage`, `getV2Status`, `getV2Credits`, `listV2Requests`, and `createV2Session` call the new omni route surface.
|
|
554
564
|
- Programmatic user billing helpers include `createV2UserRechargeCredits`, `refreshV2UserToken`, `createV2UserAppKey`, `refreshV2UserAppKey`, `getV2UserCredits`, `getV2UserUsageLogs`, and `getV2UserPaymentStatus`.
|
|
555
565
|
- Omit `externalUser` for internal account billing, pass `externalUser` to scope an external user with the account API key, or authenticate the client directly with an external-user auth token/API key.
|
|
556
566
|
|
|
@@ -571,6 +581,18 @@ const v2ExternalVideo = await platform.createV2VideoFromImageList(
|
|
|
571
581
|
{ externalUser },
|
|
572
582
|
);
|
|
573
583
|
|
|
584
|
+
const v2Translated = await platform.translateV2Video({
|
|
585
|
+
videoSessionId: v2Video.data.request_id!,
|
|
586
|
+
language: 'es',
|
|
587
|
+
enable_subtitles: false,
|
|
588
|
+
translate_outro: true,
|
|
589
|
+
translate_footer: true,
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
const v2Clone = await platform.cloneV2Video({
|
|
593
|
+
videoSessionId: v2Video.data.request_id!,
|
|
594
|
+
});
|
|
595
|
+
|
|
574
596
|
const v2Status = await platform.getV2Status(v2Video.data.request_id!);
|
|
575
597
|
console.log(v2Status.data.status);
|
|
576
598
|
```
|
package/dist/index.d.ts
CHANGED
|
@@ -219,10 +219,14 @@ export interface TranslateVideoInput {
|
|
|
219
219
|
langauge?: string;
|
|
220
220
|
langauge_code?: string;
|
|
221
221
|
langaugeCode?: string;
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
222
|
+
enable_subtitles?: boolean;
|
|
223
|
+
enableSubtitles?: boolean;
|
|
224
|
+
add_subtitles?: boolean;
|
|
225
|
+
addSubtitles?: boolean;
|
|
226
|
+
translate_outro?: boolean;
|
|
227
|
+
translateOutro?: boolean;
|
|
228
|
+
translate_footer?: boolean;
|
|
229
|
+
translateFooter?: boolean;
|
|
226
230
|
[key: string]: unknown;
|
|
227
231
|
}
|
|
228
232
|
export interface TranslateVideoResponse {
|
|
@@ -233,6 +237,26 @@ export interface TranslateVideoResponse {
|
|
|
233
237
|
remainingCredits?: number | null;
|
|
234
238
|
[key: string]: unknown;
|
|
235
239
|
}
|
|
240
|
+
export interface CloneVideoInput {
|
|
241
|
+
videoSessionId?: string;
|
|
242
|
+
video_session_id?: string;
|
|
243
|
+
videoSessionID?: string;
|
|
244
|
+
session_id?: string;
|
|
245
|
+
sessionId?: string;
|
|
246
|
+
sessionID?: string;
|
|
247
|
+
request_id?: string;
|
|
248
|
+
requestId?: string;
|
|
249
|
+
source_session_id?: string;
|
|
250
|
+
sourceSessionId?: string;
|
|
251
|
+
source_request_id?: string;
|
|
252
|
+
sourceRequestId?: string;
|
|
253
|
+
[key: string]: unknown;
|
|
254
|
+
}
|
|
255
|
+
export interface CloneVideoResponse extends GlobalStatusResponse {
|
|
256
|
+
sessionID?: string;
|
|
257
|
+
creditsCharged?: number;
|
|
258
|
+
remainingCredits?: number | null;
|
|
259
|
+
}
|
|
236
260
|
export interface UpdateVideoOutroImageInput {
|
|
237
261
|
videoSessionId?: string;
|
|
238
262
|
video_session_id?: string;
|
|
@@ -1717,6 +1741,8 @@ export declare class SamsarClient {
|
|
|
1717
1741
|
}): Promise<SamsarResult<CreateLoginTokenResponse | ExternalCreateLoginTokenResponse>>;
|
|
1718
1742
|
createV2VideoFromText(input: CreateVideoFromTextInput, options?: V2RequestOptions): Promise<SamsarResult<CreateVideoResponse | ExternalRequestResponse>>;
|
|
1719
1743
|
createV2VideoFromImageList(input: CreateVideoFromImageListInput, options?: V2RequestOptions): Promise<SamsarResult<CreateVideoFromImageListResponse | ExternalRequestResponse>>;
|
|
1744
|
+
translateV2Video(input: TranslateVideoInput, options?: V2RequestOptions): Promise<SamsarResult<TranslateVideoResponse | ExternalRequestResponse>>;
|
|
1745
|
+
cloneV2Video(input: CloneVideoInput, options?: V2RequestOptions): Promise<SamsarResult<CloneVideoResponse>>;
|
|
1720
1746
|
uploadV2ImageData(imageData: string[], options?: V2RequestOptions): Promise<SamsarResult<{
|
|
1721
1747
|
image_urls: string[];
|
|
1722
1748
|
}>>;
|
|
@@ -1802,6 +1828,13 @@ export declare class SamsarClient {
|
|
|
1802
1828
|
translateVideo(input: TranslateVideoInput, options?: {
|
|
1803
1829
|
webhookUrl?: string;
|
|
1804
1830
|
} & SamsarRequestOptions): Promise<SamsarResult<TranslateVideoResponse>>;
|
|
1831
|
+
/**
|
|
1832
|
+
* Deep-clone a completed video session and queue one final render for the new session.
|
|
1833
|
+
* The clone copies session assets, then regenerates only the final rendered video URL.
|
|
1834
|
+
*/
|
|
1835
|
+
cloneVideo(input: CloneVideoInput, options?: {
|
|
1836
|
+
webhookUrl?: string;
|
|
1837
|
+
} & SamsarRequestOptions): Promise<SamsarResult<CloneVideoResponse>>;
|
|
1805
1838
|
/**
|
|
1806
1839
|
* Join multiple existing video sessions into a single session by appending their timelines.
|
|
1807
1840
|
* Creates a new session_id and queues transcription + frame + video generation.
|
package/dist/index.js
CHANGED
|
@@ -126,6 +126,72 @@ function normalizeCreateVideoFromImageListInput(input) {
|
|
|
126
126
|
}
|
|
127
127
|
return normalized;
|
|
128
128
|
}
|
|
129
|
+
function normalizeTranslateVideoInput(input, context = 'translateVideo') {
|
|
130
|
+
const raw = input;
|
|
131
|
+
const videoSessionId = raw.videoSessionId ??
|
|
132
|
+
raw.video_session_id ??
|
|
133
|
+
raw.videoSessionID ??
|
|
134
|
+
raw.session_id ??
|
|
135
|
+
raw.sessionId ??
|
|
136
|
+
raw.sessionID ??
|
|
137
|
+
raw.request_id ??
|
|
138
|
+
raw.requestId;
|
|
139
|
+
const language = raw.language ??
|
|
140
|
+
raw.language_code ??
|
|
141
|
+
raw.languageCode ??
|
|
142
|
+
raw.langauge ??
|
|
143
|
+
raw.langauge_code ??
|
|
144
|
+
raw.langaugeCode ??
|
|
145
|
+
raw.languageString;
|
|
146
|
+
const enableSubtitles = resolveAliasedInputValue(raw, ['enable_subtitles', 'enableSubtitles', 'add_subtitles', 'addSubtitles'], 'enable_subtitles') ?? false;
|
|
147
|
+
const translateOutro = resolveAliasedInputValue(raw, ['translate_outro', 'translateOutro'], 'translate_outro') ?? true;
|
|
148
|
+
const translateFooter = resolveAliasedInputValue(raw, ['translate_footer', 'translateFooter'], 'translate_footer') ?? true;
|
|
149
|
+
if (!videoSessionId) {
|
|
150
|
+
throw new Error(`videoSessionId is required for ${context}`);
|
|
151
|
+
}
|
|
152
|
+
if (!language) {
|
|
153
|
+
throw new Error(`language is required for ${context}`);
|
|
154
|
+
}
|
|
155
|
+
assertOptionalBoolean(enableSubtitles, 'enable_subtitles', context);
|
|
156
|
+
assertOptionalBoolean(translateOutro, 'translate_outro', context);
|
|
157
|
+
assertOptionalBoolean(translateFooter, 'translate_footer', context);
|
|
158
|
+
const normalizedInput = { ...input };
|
|
159
|
+
delete normalizedInput.outro_image_url;
|
|
160
|
+
delete normalizedInput.outroImageUrl;
|
|
161
|
+
delete normalizedInput.outroImageURL;
|
|
162
|
+
delete normalizedInput.new_outro_image_url;
|
|
163
|
+
delete normalizedInput.newOutroImageUrl;
|
|
164
|
+
return {
|
|
165
|
+
...normalizedInput,
|
|
166
|
+
videoSessionId: String(videoSessionId),
|
|
167
|
+
language: String(language),
|
|
168
|
+
enable_subtitles: enableSubtitles,
|
|
169
|
+
translate_outro: translateOutro,
|
|
170
|
+
translate_footer: translateFooter,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function normalizeCloneVideoInput(input, context = 'cloneVideo') {
|
|
174
|
+
const raw = input;
|
|
175
|
+
const videoSessionId = raw.videoSessionId ??
|
|
176
|
+
raw.video_session_id ??
|
|
177
|
+
raw.videoSessionID ??
|
|
178
|
+
raw.session_id ??
|
|
179
|
+
raw.sessionId ??
|
|
180
|
+
raw.sessionID ??
|
|
181
|
+
raw.request_id ??
|
|
182
|
+
raw.requestId ??
|
|
183
|
+
raw.source_session_id ??
|
|
184
|
+
raw.sourceSessionId ??
|
|
185
|
+
raw.source_request_id ??
|
|
186
|
+
raw.sourceRequestId;
|
|
187
|
+
if (!videoSessionId) {
|
|
188
|
+
throw new Error(`videoSessionId is required for ${context}`);
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
...input,
|
|
192
|
+
videoSessionId: String(videoSessionId),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
129
195
|
function normalizeUpdateVideoOutroImageInput(input, context = 'updateVideoOutroImage') {
|
|
130
196
|
const raw = input;
|
|
131
197
|
const videoSessionId = raw.videoSessionId ??
|
|
@@ -490,6 +556,20 @@ export class SamsarClient {
|
|
|
490
556
|
webhookUrl: options?.webhookUrl,
|
|
491
557
|
}, options);
|
|
492
558
|
}
|
|
559
|
+
async translateV2Video(input, options) {
|
|
560
|
+
const normalizedInput = normalizeTranslateVideoInput(input, 'translateV2Video');
|
|
561
|
+
return this.postV2('translate_video', {
|
|
562
|
+
input: normalizedInput,
|
|
563
|
+
webhookUrl: options?.webhookUrl,
|
|
564
|
+
}, options);
|
|
565
|
+
}
|
|
566
|
+
async cloneV2Video(input, options) {
|
|
567
|
+
const normalizedInput = normalizeCloneVideoInput(input, 'cloneV2Video');
|
|
568
|
+
return this.postV2('video/clone', {
|
|
569
|
+
input: normalizedInput,
|
|
570
|
+
webhookUrl: options?.webhookUrl,
|
|
571
|
+
}, options);
|
|
572
|
+
}
|
|
493
573
|
async uploadV2ImageData(imageData, options) {
|
|
494
574
|
if (!Array.isArray(imageData) || imageData.length === 0) {
|
|
495
575
|
throw new Error('imageData must be a non-empty array of data URLs');
|
|
@@ -703,33 +783,10 @@ export class SamsarClient {
|
|
|
703
783
|
* Creates a new session_id and queues generation steps for lip sync + transcription + video render.
|
|
704
784
|
*/
|
|
705
785
|
async translateVideo(input, options) {
|
|
706
|
-
const
|
|
707
|
-
const videoSessionId = raw.videoSessionId ??
|
|
708
|
-
raw.video_session_id ??
|
|
709
|
-
raw.videoSessionID ??
|
|
710
|
-
raw.session_id ??
|
|
711
|
-
raw.sessionId ??
|
|
712
|
-
raw.sessionID ??
|
|
713
|
-
raw.request_id ??
|
|
714
|
-
raw.requestId;
|
|
715
|
-
const language = raw.language ??
|
|
716
|
-
raw.language_code ??
|
|
717
|
-
raw.languageCode ??
|
|
718
|
-
raw.langauge ??
|
|
719
|
-
raw.langauge_code ??
|
|
720
|
-
raw.langaugeCode ??
|
|
721
|
-
raw.languageString;
|
|
722
|
-
if (!videoSessionId) {
|
|
723
|
-
throw new Error('videoSessionId is required for translateVideo');
|
|
724
|
-
}
|
|
725
|
-
if (!language) {
|
|
726
|
-
throw new Error('language is required for translateVideo');
|
|
727
|
-
}
|
|
786
|
+
const normalizedInput = normalizeTranslateVideoInput(input, 'translateVideo');
|
|
728
787
|
const body = {
|
|
729
788
|
input: {
|
|
730
|
-
...
|
|
731
|
-
videoSessionId: String(videoSessionId),
|
|
732
|
-
language: String(language),
|
|
789
|
+
...normalizedInput,
|
|
733
790
|
},
|
|
734
791
|
webhookUrl: options?.webhookUrl,
|
|
735
792
|
};
|
|
@@ -754,6 +811,39 @@ export class SamsarClient {
|
|
|
754
811
|
}
|
|
755
812
|
return response;
|
|
756
813
|
}
|
|
814
|
+
/**
|
|
815
|
+
* Deep-clone a completed video session and queue one final render for the new session.
|
|
816
|
+
* The clone copies session assets, then regenerates only the final rendered video URL.
|
|
817
|
+
*/
|
|
818
|
+
async cloneVideo(input, options) {
|
|
819
|
+
const normalizedInput = normalizeCloneVideoInput(input, 'cloneVideo');
|
|
820
|
+
const body = {
|
|
821
|
+
input: {
|
|
822
|
+
...normalizedInput,
|
|
823
|
+
},
|
|
824
|
+
webhookUrl: options?.webhookUrl,
|
|
825
|
+
};
|
|
826
|
+
const response = await this.post('video/clone', body, options);
|
|
827
|
+
const data = response.data;
|
|
828
|
+
if (data && typeof data === 'object') {
|
|
829
|
+
const sessionId = typeof data.sessionID === 'string'
|
|
830
|
+
? data.sessionID
|
|
831
|
+
: typeof data.session_id === 'string'
|
|
832
|
+
? data.session_id
|
|
833
|
+
: typeof data.request_id === 'string'
|
|
834
|
+
? data.request_id
|
|
835
|
+
: undefined;
|
|
836
|
+
const normalizedSessionId = sessionId ? String(sessionId) : undefined;
|
|
837
|
+
const normalizedData = {
|
|
838
|
+
...data,
|
|
839
|
+
sessionID: data.sessionID ?? normalizedSessionId ?? '',
|
|
840
|
+
session_id: data.session_id ?? normalizedSessionId ?? null,
|
|
841
|
+
request_id: data.request_id ?? normalizedSessionId ?? null,
|
|
842
|
+
};
|
|
843
|
+
return { ...response, data: normalizedData };
|
|
844
|
+
}
|
|
845
|
+
return response;
|
|
846
|
+
}
|
|
757
847
|
/**
|
|
758
848
|
* Join multiple existing video sessions into a single session by appending their timelines.
|
|
759
849
|
* Creates a new session_id and queues transcription + frame + video generation.
|
|
@@ -1861,7 +1951,10 @@ export class SamsarClient {
|
|
|
1861
1951
|
body: parsedBody,
|
|
1862
1952
|
});
|
|
1863
1953
|
}
|
|
1864
|
-
|
|
1954
|
+
const responseMessage = getResponseErrorMessage(parsedBody);
|
|
1955
|
+
throw new SamsarRequestError(responseMessage
|
|
1956
|
+
? `Request to ${url} failed with status ${response.status}: ${responseMessage}`
|
|
1957
|
+
: `Request to ${url} failed with status ${response.status}`, {
|
|
1865
1958
|
status: response.status,
|
|
1866
1959
|
body: parsedBody,
|
|
1867
1960
|
headers: headerRecord,
|
|
@@ -1943,6 +2036,25 @@ function parseMaybeJson(value) {
|
|
|
1943
2036
|
return value;
|
|
1944
2037
|
}
|
|
1945
2038
|
}
|
|
2039
|
+
function getResponseErrorMessage(body) {
|
|
2040
|
+
if (!body || typeof body !== 'object' || Array.isArray(body)) {
|
|
2041
|
+
return typeof body === 'string' && body.trim() ? body.trim() : null;
|
|
2042
|
+
}
|
|
2043
|
+
const record = body;
|
|
2044
|
+
for (const key of ['message', 'error', 'detail']) {
|
|
2045
|
+
const value = record[key];
|
|
2046
|
+
if (typeof value === 'string' && value.trim()) {
|
|
2047
|
+
return value.trim();
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
if (record.error && typeof record.error === 'object' && !Array.isArray(record.error)) {
|
|
2051
|
+
const nestedMessage = record.error.message;
|
|
2052
|
+
if (typeof nestedMessage === 'string' && nestedMessage.trim()) {
|
|
2053
|
+
return nestedMessage.trim();
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
return null;
|
|
2057
|
+
}
|
|
1946
2058
|
function headersToObject(headers) {
|
|
1947
2059
|
const result = {};
|
|
1948
2060
|
headers.forEach((value, key) => {
|