samsar-js 0.48.16 → 0.48.18
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 +61 -0
- package/dist/index.d.ts +159 -0
- package/dist/index.js +206 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,6 +43,21 @@ const video = await samsar.createVideoFromText(
|
|
|
43
43
|
{ webhookUrl: 'https://example.com/webhook' },
|
|
44
44
|
);
|
|
45
45
|
|
|
46
|
+
// Create a text video with a generated QR outro and bottom CTA footer
|
|
47
|
+
await samsar.createVideoFromText({
|
|
48
|
+
prompt: 'A boutique hotel launch reel with cinematic room details',
|
|
49
|
+
image_model: 'GPTIMAGE2',
|
|
50
|
+
video_model: 'RUNWAYML',
|
|
51
|
+
duration: 20,
|
|
52
|
+
aspect_ratio: '9:16',
|
|
53
|
+
generate_outro_image: true,
|
|
54
|
+
cta_url: 'https://example.com/book',
|
|
55
|
+
cta_text_top: 'Scan to book',
|
|
56
|
+
cta_text_bottom: 'Opening offers',
|
|
57
|
+
add_footer_animation: true,
|
|
58
|
+
footer_metadata: [{ url: 'https://example.com/book', title: 'Book your stay' }],
|
|
59
|
+
});
|
|
60
|
+
|
|
46
61
|
// Create a video from an image list
|
|
47
62
|
const videoFromImages = await samsar.createVideoFromImageList(
|
|
48
63
|
{
|
|
@@ -91,6 +106,31 @@ await samsar.createVideoFromImageList({
|
|
|
91
106
|
],
|
|
92
107
|
});
|
|
93
108
|
|
|
109
|
+
// Update an existing outro with a new provided outro image URL
|
|
110
|
+
await samsar.updateVideoOutroImage(
|
|
111
|
+
{
|
|
112
|
+
videoSessionId: videoFromImages.data.session_id ?? videoFromImages.data.request_id!,
|
|
113
|
+
outro_image_url: 'https://cdn.example.com/outro-v2.png',
|
|
114
|
+
add_outro_animation: true,
|
|
115
|
+
add_outro_focus_area: true,
|
|
116
|
+
outro_focust_area: { x: 680, y: 296, width: 432, height: 432 },
|
|
117
|
+
},
|
|
118
|
+
{ webhookUrl: 'https://example.com/webhook' },
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
// Update an existing outro by generating a new QR CTA outro server-side
|
|
122
|
+
await samsar.updateVideoOutroImage(
|
|
123
|
+
{
|
|
124
|
+
videoSessionId: videoFromImages.data.session_id ?? videoFromImages.data.request_id!,
|
|
125
|
+
generate_outro_image: true,
|
|
126
|
+
cta_url: 'https://example.com/book',
|
|
127
|
+
cta_text_top: 'Scan to book',
|
|
128
|
+
cta_text_bottom: 'Limited availability',
|
|
129
|
+
add_outro_animation: true,
|
|
130
|
+
},
|
|
131
|
+
{ webhookUrl: 'https://example.com/webhook' },
|
|
132
|
+
);
|
|
133
|
+
|
|
94
134
|
// Translate an existing video session into another language
|
|
95
135
|
const translated = await samsar.translateVideo(
|
|
96
136
|
{
|
|
@@ -302,6 +342,24 @@ completedSessions.data.forEach((session) => {
|
|
|
302
342
|
console.log(session.session_id, session.langauge, session.result_url);
|
|
303
343
|
});
|
|
304
344
|
|
|
345
|
+
// Publish, edit, or revoke a completed session in the public publication feed (free endpoints)
|
|
346
|
+
const publication = await samsar.publishPublication({
|
|
347
|
+
session_id: videoFromImages.data.session_id ?? videoFromImages.data.request_id!,
|
|
348
|
+
title: 'Running shoe teaser',
|
|
349
|
+
description: 'Launch-day vertical cut',
|
|
350
|
+
tags: ['launch', 'footwear'],
|
|
351
|
+
creator_handle: 'acme',
|
|
352
|
+
});
|
|
353
|
+
console.log(publication.data.publication?.publication_id);
|
|
354
|
+
|
|
355
|
+
await samsar.editPublication({
|
|
356
|
+
session_id: videoFromImages.data.session_id ?? videoFromImages.data.request_id!,
|
|
357
|
+
title: 'Running shoe teaser - updated',
|
|
358
|
+
tags: ['launch', 'footwear', 'campaign'],
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
await samsar.revokePublication(videoFromImages.data.session_id ?? videoFromImages.data.request_id!);
|
|
362
|
+
|
|
305
363
|
// Image-specific status endpoint
|
|
306
364
|
const rollupStatus = await samsar.getImageStatus(rollup.data.session_id);
|
|
307
365
|
|
|
@@ -428,9 +486,12 @@ console.log(externalLibrary.data.requests.map((request) => request.request_id));
|
|
|
428
486
|
Video model support notes:
|
|
429
487
|
- `createVideoFromText` image model keys include: `GPTIMAGE2`, `IMAGEN4`, `SEEDREAM`, `HUNYUAN`, `NANOBANANA2`.
|
|
430
488
|
- `createVideoFromText` supports all express video models: `RUNWAYML`, `KLINGIMGTOVID3PRO`, `HAILUO`, `HAILUOPRO`, `SEEDANCEI2V` (Seedance 2.0), `VEO3.1I2V`, `VEO3.1I2VFAST`, `SORA2`, `SORA2PRO`.
|
|
489
|
+
- `createVideoFromText` accepts either a provided outro (`outro_image_url`) or server-generated QR outro (`generate_outro_image: true` with `cta_url`). It can also render bottom CTA footer QR cards with `add_footer_animation` and `footer_metadata`; one footer item applies to every generated scene, while multiple items map by scene index.
|
|
431
490
|
- `createVideoFromImageList` supports `VEO3.1I2V`, `SEEDANCEI2V`, `KLING3.0`, and `RUNWAYML` via `video_model`; if omitted, it defaults to `VEO3.1I2V`. `KLINGIMGTOVID3PRO` is also accepted as a compatibility alias for `KLING3.0`. Use `aspect_ratio: '16:9'` or `'9:16'`; omitted or invalid values fall back to `16:9`.
|
|
432
491
|
- `createVideoFromImageList` accepts either a provided outro (`outro_image_url`) or server-generated QR outro (`generate_outro_image: true` with `cta_url`). Do not combine the two modes in a single request.
|
|
433
492
|
- `createVideoFromImageList` can render per-scene footer QR cards by setting `add_footer_animation: true` and providing one `footer_metadata` item per image scene.
|
|
493
|
+
- `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.
|
|
494
|
+
- `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.
|
|
434
495
|
- Image-list video pricing is per rendered second: `VEO3.1I2V` and `SEEDANCEI2V` are 75 credits/sec, `KLING3.0` is 50 credits/sec, and `RUNWAYML` is 25 credits/sec.
|
|
435
496
|
|
|
436
497
|
Each method returns `{ data, status, headers, creditsCharged, creditsRemaining, raw }`. Non-2xx responses throw `SamsarRequestError` containing status, body, and credit headers (if present).
|
package/dist/index.d.ts
CHANGED
|
@@ -50,6 +50,30 @@ export interface CreateVideoFromTextInput {
|
|
|
50
50
|
session_id?: string;
|
|
51
51
|
sessionId?: string;
|
|
52
52
|
sessionID?: string;
|
|
53
|
+
outro_image_url?: string;
|
|
54
|
+
outroImageUrl?: string;
|
|
55
|
+
add_outro_animation?: boolean;
|
|
56
|
+
addOutroAnimation?: boolean;
|
|
57
|
+
add_outro_focus_area?: boolean;
|
|
58
|
+
addOutroFocusArea?: boolean;
|
|
59
|
+
outro_focust_area?: OutroFocusArea | null;
|
|
60
|
+
outro_focus_area?: OutroFocusArea | null;
|
|
61
|
+
outroFocustArea?: OutroFocusArea | null;
|
|
62
|
+
outroFocusArea?: OutroFocusArea | null;
|
|
63
|
+
generate_outro_image?: boolean;
|
|
64
|
+
generateOutroImage?: boolean;
|
|
65
|
+
cta_url?: string;
|
|
66
|
+
ctaUrl?: string;
|
|
67
|
+
cta_text_top?: string;
|
|
68
|
+
ctaTextTop?: string;
|
|
69
|
+
cta_text_bottom?: string;
|
|
70
|
+
ctaTextBottom?: string;
|
|
71
|
+
cta_logo?: string;
|
|
72
|
+
ctaLogo?: string;
|
|
73
|
+
add_footer_animation?: boolean;
|
|
74
|
+
addFooterAnimation?: boolean;
|
|
75
|
+
footer_metadata?: FooterMetadataItem[];
|
|
76
|
+
footerMetadata?: FooterMetadataItem[];
|
|
53
77
|
[key: string]: unknown;
|
|
54
78
|
}
|
|
55
79
|
export interface CreateVideoResponse {
|
|
@@ -204,6 +228,24 @@ export interface UpdateVideoOutroImageInput {
|
|
|
204
228
|
outroImageUrl?: string;
|
|
205
229
|
new_outro_image_url?: string;
|
|
206
230
|
newOutroImageUrl?: string;
|
|
231
|
+
add_outro_animation?: boolean;
|
|
232
|
+
addOutroAnimation?: boolean;
|
|
233
|
+
add_outro_focus_area?: boolean;
|
|
234
|
+
addOutroFocusArea?: boolean;
|
|
235
|
+
outro_focust_area?: OutroFocusArea | null;
|
|
236
|
+
outro_focus_area?: OutroFocusArea | null;
|
|
237
|
+
outroFocustArea?: OutroFocusArea | null;
|
|
238
|
+
outroFocusArea?: OutroFocusArea | null;
|
|
239
|
+
generate_outro_image?: boolean;
|
|
240
|
+
generateOutroImage?: boolean;
|
|
241
|
+
cta_url?: string;
|
|
242
|
+
ctaUrl?: string;
|
|
243
|
+
cta_text_top?: string;
|
|
244
|
+
ctaTextTop?: string;
|
|
245
|
+
cta_text_bottom?: string;
|
|
246
|
+
ctaTextBottom?: string;
|
|
247
|
+
cta_logo?: string;
|
|
248
|
+
ctaLogo?: string;
|
|
207
249
|
[key: string]: unknown;
|
|
208
250
|
}
|
|
209
251
|
export interface UpdateVideoOutroImageResponse {
|
|
@@ -316,6 +358,96 @@ export interface CompletedVideoSession {
|
|
|
316
358
|
[key: string]: unknown;
|
|
317
359
|
}
|
|
318
360
|
export type ListCompletedVideoSessionsResponse = CompletedVideoSession[];
|
|
361
|
+
export interface SessionPublicationInput {
|
|
362
|
+
session_id?: string;
|
|
363
|
+
sessionId?: string;
|
|
364
|
+
sessionID?: string;
|
|
365
|
+
video_session_id?: string;
|
|
366
|
+
videoSessionId?: string;
|
|
367
|
+
videoSessionID?: string;
|
|
368
|
+
id?: string;
|
|
369
|
+
title?: string;
|
|
370
|
+
description?: string;
|
|
371
|
+
tags?: string[] | string;
|
|
372
|
+
aspect_ratio?: string;
|
|
373
|
+
aspectRatio?: string;
|
|
374
|
+
creator_handle?: string;
|
|
375
|
+
creatorHandle?: string;
|
|
376
|
+
slug?: string;
|
|
377
|
+
image_hash?: string;
|
|
378
|
+
imageHash?: string;
|
|
379
|
+
splash_image?: string;
|
|
380
|
+
splashImage?: string;
|
|
381
|
+
image_model?: string;
|
|
382
|
+
imageModel?: string;
|
|
383
|
+
video_model?: string;
|
|
384
|
+
videoModel?: string;
|
|
385
|
+
original_prompt?: string;
|
|
386
|
+
originalPrompt?: string;
|
|
387
|
+
prompt?: string;
|
|
388
|
+
session_language?: string;
|
|
389
|
+
sessionLanguage?: string;
|
|
390
|
+
language?: string;
|
|
391
|
+
language_code?: string;
|
|
392
|
+
languageString?: string;
|
|
393
|
+
language_string?: string;
|
|
394
|
+
[key: string]: unknown;
|
|
395
|
+
}
|
|
396
|
+
export interface SessionPublicationSummary {
|
|
397
|
+
id?: string | null;
|
|
398
|
+
publication_id?: string | null;
|
|
399
|
+
session_id?: string | null;
|
|
400
|
+
sessionId?: string | null;
|
|
401
|
+
video_url?: string | null;
|
|
402
|
+
videoUrl?: string | null;
|
|
403
|
+
title?: string | null;
|
|
404
|
+
description?: string;
|
|
405
|
+
tags?: string[];
|
|
406
|
+
creator_handle?: string;
|
|
407
|
+
creatorHandle?: string;
|
|
408
|
+
slug?: string | null;
|
|
409
|
+
image_hash?: string | null;
|
|
410
|
+
imageHash?: string | null;
|
|
411
|
+
splash_image?: string | null;
|
|
412
|
+
splashImage?: string | null;
|
|
413
|
+
image_model?: string | null;
|
|
414
|
+
imageModel?: string | null;
|
|
415
|
+
video_model?: string | null;
|
|
416
|
+
videoModel?: string | null;
|
|
417
|
+
original_prompt?: string;
|
|
418
|
+
originalPrompt?: string;
|
|
419
|
+
session_language?: string | null;
|
|
420
|
+
sessionLanguage?: string | null;
|
|
421
|
+
language_string?: string | null;
|
|
422
|
+
languageString?: string | null;
|
|
423
|
+
aspect_ratio?: string | null;
|
|
424
|
+
aspectRatio?: string | null;
|
|
425
|
+
created_at?: string | null;
|
|
426
|
+
createdAt?: string | null;
|
|
427
|
+
updated_at?: string | null;
|
|
428
|
+
updatedAt?: string | null;
|
|
429
|
+
[key: string]: unknown;
|
|
430
|
+
}
|
|
431
|
+
export interface SessionPublicationSessionSummary {
|
|
432
|
+
id?: string | null;
|
|
433
|
+
session_id?: string | null;
|
|
434
|
+
is_published?: boolean;
|
|
435
|
+
published_publication_id?: string | null;
|
|
436
|
+
published_video_url?: string | null;
|
|
437
|
+
published_at?: string | null;
|
|
438
|
+
[key: string]: unknown;
|
|
439
|
+
}
|
|
440
|
+
export interface SessionPublicationResponse {
|
|
441
|
+
created?: boolean;
|
|
442
|
+
revoked?: boolean;
|
|
443
|
+
publication_id?: string | null;
|
|
444
|
+
publication?: SessionPublicationSummary | null;
|
|
445
|
+
session?: SessionPublicationSessionSummary | null;
|
|
446
|
+
sessionId?: string;
|
|
447
|
+
session_id?: string;
|
|
448
|
+
ispublishedVideo?: boolean;
|
|
449
|
+
[key: string]: unknown;
|
|
450
|
+
}
|
|
319
451
|
export interface SupportedTextToVideoModelsResponse {
|
|
320
452
|
IMAGE_MODELS: SupportedTextToVideoModelOption[];
|
|
321
453
|
VIDEO_MODELS: SupportedTextToVideoModelOption[];
|
|
@@ -1471,6 +1603,33 @@ export declare class SamsarClient {
|
|
|
1471
1603
|
listCompletedVideoSessions(options?: SamsarRequestOptions & {
|
|
1472
1604
|
limit?: number;
|
|
1473
1605
|
}): Promise<SamsarResult<ListCompletedVideoSessionsResponse>>;
|
|
1606
|
+
/**
|
|
1607
|
+
* Publish a completed Samsar video session to the public publication feed.
|
|
1608
|
+
* This is a free endpoint. The session must belong to the authenticated API key/auth token.
|
|
1609
|
+
*/
|
|
1610
|
+
publishPublication(input: string | SessionPublicationInput, options?: SamsarRequestOptions): Promise<SamsarResult<SessionPublicationResponse>>;
|
|
1611
|
+
/**
|
|
1612
|
+
* Alias for publishPublication, named around the underlying VideoSession resource.
|
|
1613
|
+
*/
|
|
1614
|
+
publishSessionPublication(input: string | SessionPublicationInput, options?: SamsarRequestOptions): Promise<SamsarResult<SessionPublicationResponse>>;
|
|
1615
|
+
/**
|
|
1616
|
+
* Edit an existing publication for a Samsar video session.
|
|
1617
|
+
* Omitted fields keep their current publication values.
|
|
1618
|
+
*/
|
|
1619
|
+
editPublication(input: SessionPublicationInput, options?: SamsarRequestOptions): Promise<SamsarResult<SessionPublicationResponse>>;
|
|
1620
|
+
/**
|
|
1621
|
+
* Alias for editPublication, named around the underlying VideoSession resource.
|
|
1622
|
+
*/
|
|
1623
|
+
editSessionPublication(input: SessionPublicationInput, options?: SamsarRequestOptions): Promise<SamsarResult<SessionPublicationResponse>>;
|
|
1624
|
+
/**
|
|
1625
|
+
* Revoke a publication for a Samsar video session.
|
|
1626
|
+
* This deletes the publication record and clears published fields on the session.
|
|
1627
|
+
*/
|
|
1628
|
+
revokePublication(input: string | SessionPublicationInput, options?: SamsarRequestOptions): Promise<SamsarResult<SessionPublicationResponse>>;
|
|
1629
|
+
/**
|
|
1630
|
+
* Alias for revokePublication, named around the underlying VideoSession resource.
|
|
1631
|
+
*/
|
|
1632
|
+
revokeSessionPublication(input: string | SessionPublicationInput, options?: SamsarRequestOptions): Promise<SamsarResult<SessionPublicationResponse>>;
|
|
1474
1633
|
/**
|
|
1475
1634
|
* Fetch the supported image/video model keys for the text_to_video route.
|
|
1476
1635
|
* Maps to GET /video/supported_models.
|
package/dist/index.js
CHANGED
|
@@ -34,11 +34,53 @@ function resolveAliasedInputValue(raw, aliases, canonicalName) {
|
|
|
34
34
|
}
|
|
35
35
|
return hasResolved ? resolved : undefined;
|
|
36
36
|
}
|
|
37
|
-
function assertOptionalBoolean(value, fieldName) {
|
|
37
|
+
function assertOptionalBoolean(value, fieldName, context = 'createVideoFromImageList') {
|
|
38
38
|
if (value !== undefined && typeof value !== 'boolean') {
|
|
39
|
-
throw new Error(`${fieldName} must be a boolean for
|
|
39
|
+
throw new Error(`${fieldName} must be a boolean for ${context}`);
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
function normalizeCreateVideoFromTextInput(input) {
|
|
43
|
+
const raw = input;
|
|
44
|
+
const normalized = { ...input };
|
|
45
|
+
const aliases = [
|
|
46
|
+
['session_id', ['session_id', 'sessionId', 'sessionID']],
|
|
47
|
+
['aspect_ratio', ['aspect_ratio', 'aspectRatio']],
|
|
48
|
+
['outro_image_url', ['outro_image_url', 'outroImageUrl']],
|
|
49
|
+
['add_outro_animation', ['add_outro_animation', 'addOutroAnimation']],
|
|
50
|
+
['add_outro_focus_area', ['add_outro_focus_area', 'addOutroFocusArea']],
|
|
51
|
+
['outro_focust_area', ['outro_focust_area', 'outro_focus_area', 'outroFocustArea', 'outroFocusArea']],
|
|
52
|
+
['generate_outro_image', ['generate_outro_image', 'generateOutroImage']],
|
|
53
|
+
['cta_url', ['cta_url', 'ctaUrl']],
|
|
54
|
+
['cta_text_top', ['cta_text_top', 'ctaTextTop']],
|
|
55
|
+
['cta_text_bottom', ['cta_text_bottom', 'ctaTextBottom']],
|
|
56
|
+
['cta_logo', ['cta_logo', 'ctaLogo']],
|
|
57
|
+
['add_footer_animation', ['add_footer_animation', 'addFooterAnimation']],
|
|
58
|
+
['footer_metadata', ['footer_metadata', 'footerMetadata']],
|
|
59
|
+
['enable_subtitles', ['enable_subtitles', 'enableSubtitles']],
|
|
60
|
+
['font_key', ['font_key', 'fontKey']],
|
|
61
|
+
];
|
|
62
|
+
for (const [canonicalName, aliasList] of aliases) {
|
|
63
|
+
const value = resolveAliasedInputValue(raw, aliasList, canonicalName);
|
|
64
|
+
if (value !== undefined) {
|
|
65
|
+
normalized[canonicalName] = value;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
assertOptionalBoolean(normalized.enable_subtitles, 'enable_subtitles', 'createVideoFromText');
|
|
69
|
+
assertOptionalBoolean(normalized.add_outro_animation, 'add_outro_animation', 'createVideoFromText');
|
|
70
|
+
assertOptionalBoolean(normalized.add_outro_focus_area, 'add_outro_focus_area', 'createVideoFromText');
|
|
71
|
+
assertOptionalBoolean(normalized.generate_outro_image, 'generate_outro_image', 'createVideoFromText');
|
|
72
|
+
assertOptionalBoolean(normalized.add_footer_animation, 'add_footer_animation', 'createVideoFromText');
|
|
73
|
+
if (normalized.generate_outro_image === true) {
|
|
74
|
+
const ctaUrl = typeof normalized.cta_url === 'string' ? normalized.cta_url.trim() : '';
|
|
75
|
+
if (!ctaUrl) {
|
|
76
|
+
throw new Error('cta_url is required when generate_outro_image is true for createVideoFromText');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else if (normalized.add_outro_focus_area === true && normalized.add_outro_animation !== true) {
|
|
80
|
+
throw new Error('add_outro_focus_area requires add_outro_animation to be true for createVideoFromText');
|
|
81
|
+
}
|
|
82
|
+
return normalized;
|
|
83
|
+
}
|
|
42
84
|
function normalizeCreateVideoFromImageListInput(input) {
|
|
43
85
|
const raw = input;
|
|
44
86
|
if (!Array.isArray(input.image_urls) || input.image_urls.length === 0) {
|
|
@@ -57,6 +99,8 @@ function normalizeCreateVideoFromImageListInput(input) {
|
|
|
57
99
|
['cta_text_top', ['cta_text_top', 'ctaTextTop']],
|
|
58
100
|
['cta_text_bottom', ['cta_text_bottom', 'ctaTextBottom']],
|
|
59
101
|
['cta_logo', ['cta_logo', 'ctaLogo']],
|
|
102
|
+
['add_footer_animation', ['add_footer_animation', 'addFooterAnimation']],
|
|
103
|
+
['footer_metadata', ['footer_metadata', 'footerMetadata']],
|
|
60
104
|
['enable_subtitles', ['enable_subtitles', 'enableSubtitles']],
|
|
61
105
|
['font_key', ['font_key', 'fontKey']],
|
|
62
106
|
];
|
|
@@ -70,6 +114,7 @@ function normalizeCreateVideoFromImageListInput(input) {
|
|
|
70
114
|
assertOptionalBoolean(normalized.add_outro_animation, 'add_outro_animation');
|
|
71
115
|
assertOptionalBoolean(normalized.add_outro_focus_area, 'add_outro_focus_area');
|
|
72
116
|
assertOptionalBoolean(normalized.generate_outro_image, 'generate_outro_image');
|
|
117
|
+
assertOptionalBoolean(normalized.add_footer_animation, 'add_footer_animation');
|
|
73
118
|
if (normalized.generate_outro_image === true) {
|
|
74
119
|
const ctaUrl = typeof normalized.cta_url === 'string' ? normalized.cta_url.trim() : '';
|
|
75
120
|
if (!ctaUrl) {
|
|
@@ -81,6 +126,58 @@ function normalizeCreateVideoFromImageListInput(input) {
|
|
|
81
126
|
}
|
|
82
127
|
return normalized;
|
|
83
128
|
}
|
|
129
|
+
function normalizeSessionPublicationInput(input, context) {
|
|
130
|
+
if (typeof input !== 'string' && (!input || typeof input !== 'object' || Array.isArray(input))) {
|
|
131
|
+
throw new Error(`input must be a session id or object for ${context}`);
|
|
132
|
+
}
|
|
133
|
+
const raw = typeof input === 'string' ? { session_id: input } : { ...input };
|
|
134
|
+
const sessionId = resolveAliasedInputValue(raw, [
|
|
135
|
+
'session_id',
|
|
136
|
+
'sessionId',
|
|
137
|
+
'sessionID',
|
|
138
|
+
'video_session_id',
|
|
139
|
+
'videoSessionId',
|
|
140
|
+
'videoSessionID',
|
|
141
|
+
'id',
|
|
142
|
+
], 'session_id');
|
|
143
|
+
const normalizedSessionId = typeof sessionId === 'string' ? sessionId.trim() : '';
|
|
144
|
+
if (!normalizedSessionId) {
|
|
145
|
+
throw new Error(`session_id is required for ${context}`);
|
|
146
|
+
}
|
|
147
|
+
const normalized = {
|
|
148
|
+
...raw,
|
|
149
|
+
session_id: normalizedSessionId,
|
|
150
|
+
};
|
|
151
|
+
const aliases = [
|
|
152
|
+
['aspect_ratio', ['aspect_ratio', 'aspectRatio']],
|
|
153
|
+
['creator_handle', ['creator_handle', 'creatorHandle']],
|
|
154
|
+
['image_hash', ['image_hash', 'imageHash']],
|
|
155
|
+
['splash_image', ['splash_image', 'splashImage']],
|
|
156
|
+
['image_model', ['image_model', 'imageModel']],
|
|
157
|
+
['video_model', ['video_model', 'videoModel']],
|
|
158
|
+
['original_prompt', ['original_prompt', 'originalPrompt', 'prompt']],
|
|
159
|
+
['session_language', ['session_language', 'sessionLanguage', 'language', 'language_code']],
|
|
160
|
+
['language_string', ['language_string', 'languageString']],
|
|
161
|
+
];
|
|
162
|
+
for (const [canonicalName, aliasList] of aliases) {
|
|
163
|
+
const value = resolveAliasedInputValue(raw, aliasList, canonicalName);
|
|
164
|
+
if (value !== undefined) {
|
|
165
|
+
normalized[canonicalName] = value;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (normalized.tags !== undefined &&
|
|
169
|
+
!Array.isArray(normalized.tags) &&
|
|
170
|
+
typeof normalized.tags !== 'string') {
|
|
171
|
+
throw new Error(`tags must be a string or string array for ${context}`);
|
|
172
|
+
}
|
|
173
|
+
if (Array.isArray(normalized.tags)) {
|
|
174
|
+
normalized.tags = normalized.tags
|
|
175
|
+
.filter((tag) => typeof tag === 'string')
|
|
176
|
+
.map((tag) => tag.trim())
|
|
177
|
+
.filter(Boolean);
|
|
178
|
+
}
|
|
179
|
+
return normalized;
|
|
180
|
+
}
|
|
84
181
|
export class SamsarClient {
|
|
85
182
|
constructor(options) {
|
|
86
183
|
if (!options?.apiKey) {
|
|
@@ -100,8 +197,9 @@ export class SamsarClient {
|
|
|
100
197
|
* Create a new video generation job from text.
|
|
101
198
|
*/
|
|
102
199
|
async createVideoFromText(input, options) {
|
|
200
|
+
const normalizedInput = normalizeCreateVideoFromTextInput(input);
|
|
103
201
|
const body = {
|
|
104
|
-
input,
|
|
202
|
+
input: normalizedInput,
|
|
105
203
|
webhookUrl: options?.webhookUrl,
|
|
106
204
|
};
|
|
107
205
|
return this.post('video/create', body, options);
|
|
@@ -140,9 +238,10 @@ export class SamsarClient {
|
|
|
140
238
|
* Create a text-to-video request attributed to an external user while billing against the shared API key.
|
|
141
239
|
*/
|
|
142
240
|
async createExternalVideoFromText(externalUser, input, options) {
|
|
241
|
+
const normalizedInput = normalizeCreateVideoFromTextInput(input);
|
|
143
242
|
const body = {
|
|
144
243
|
external_user: normalizeExternalUserIdentity(externalUser),
|
|
145
|
-
input,
|
|
244
|
+
input: normalizedInput,
|
|
146
245
|
webhookUrl: options?.webhookUrl,
|
|
147
246
|
};
|
|
148
247
|
return this.post('external_users/text_to_video', body, options);
|
|
@@ -477,17 +576,75 @@ export class SamsarClient {
|
|
|
477
576
|
raw.outroImageUrl ??
|
|
478
577
|
raw.new_outro_image_url ??
|
|
479
578
|
raw.newOutroImageUrl;
|
|
579
|
+
const rawGenerateOutroImage = raw.generate_outro_image ??
|
|
580
|
+
raw.generateOutroImage;
|
|
581
|
+
const rawAddOutroAnimation = raw.add_outro_animation ??
|
|
582
|
+
raw.addOutroAnimation;
|
|
583
|
+
const rawAddOutroFocusArea = raw.add_outro_focus_area ??
|
|
584
|
+
raw.addOutroFocusArea;
|
|
585
|
+
const rawOutroFocusArea = raw.outro_focust_area ??
|
|
586
|
+
raw.outro_focus_area ??
|
|
587
|
+
raw.outroFocustArea ??
|
|
588
|
+
raw.outroFocusArea;
|
|
589
|
+
const ctaUrl = raw.cta_url ??
|
|
590
|
+
raw.ctaUrl;
|
|
591
|
+
const ctaTextTop = raw.cta_text_top ??
|
|
592
|
+
raw.ctaTextTop;
|
|
593
|
+
const ctaTextBottom = raw.cta_text_bottom ??
|
|
594
|
+
raw.ctaTextBottom;
|
|
595
|
+
const ctaLogo = raw.cta_logo ??
|
|
596
|
+
raw.ctaLogo;
|
|
597
|
+
const generateOutroImage = rawGenerateOutroImage === true ||
|
|
598
|
+
(rawGenerateOutroImage === undefined && !outroImageUrl && Boolean(ctaUrl));
|
|
480
599
|
if (!videoSessionId) {
|
|
481
600
|
throw new Error('videoSessionId is required for updateVideoOutroImage');
|
|
482
601
|
}
|
|
483
|
-
if (
|
|
484
|
-
throw new Error('
|
|
602
|
+
if (rawGenerateOutroImage !== undefined && typeof rawGenerateOutroImage !== 'boolean') {
|
|
603
|
+
throw new Error('generate_outro_image must be a boolean for updateVideoOutroImage');
|
|
604
|
+
}
|
|
605
|
+
if (rawAddOutroAnimation !== undefined && typeof rawAddOutroAnimation !== 'boolean') {
|
|
606
|
+
throw new Error('add_outro_animation must be a boolean for updateVideoOutroImage');
|
|
607
|
+
}
|
|
608
|
+
if (rawAddOutroFocusArea !== undefined && typeof rawAddOutroFocusArea !== 'boolean') {
|
|
609
|
+
throw new Error('add_outro_focus_area must be a boolean for updateVideoOutroImage');
|
|
610
|
+
}
|
|
611
|
+
if (generateOutroImage && outroImageUrl) {
|
|
612
|
+
throw new Error('Use either generate_outro_image with cta_url or outro_image_url for updateVideoOutroImage');
|
|
613
|
+
}
|
|
614
|
+
if (!generateOutroImage && !outroImageUrl) {
|
|
615
|
+
throw new Error('outro_image_url is required for updateVideoOutroImage unless generate_outro_image is true');
|
|
616
|
+
}
|
|
617
|
+
if (generateOutroImage) {
|
|
618
|
+
if (!ctaUrl || !String(ctaUrl).trim()) {
|
|
619
|
+
throw new Error('cta_url is required when generate_outro_image is true for updateVideoOutroImage');
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
else if (rawAddOutroFocusArea === true && rawAddOutroAnimation !== true) {
|
|
623
|
+
throw new Error('add_outro_focus_area requires add_outro_animation to be true for updateVideoOutroImage');
|
|
624
|
+
}
|
|
625
|
+
if (!generateOutroImage && rawAddOutroFocusArea === true) {
|
|
626
|
+
if (!rawOutroFocusArea || typeof rawOutroFocusArea !== 'object' || Array.isArray(rawOutroFocusArea)) {
|
|
627
|
+
throw new Error('outro_focust_area must be an object with x, y, width, height for updateVideoOutroImage');
|
|
628
|
+
}
|
|
629
|
+
const { x, y, width, height } = rawOutroFocusArea;
|
|
630
|
+
const isInvalid = [x, y, width, height].some((value) => typeof value !== 'number' || !Number.isFinite(value));
|
|
631
|
+
if (isInvalid) {
|
|
632
|
+
throw new Error('outro_focust_area x, y, width, height must be valid numbers for updateVideoOutroImage');
|
|
633
|
+
}
|
|
485
634
|
}
|
|
486
635
|
const body = {
|
|
487
636
|
input: {
|
|
488
637
|
...input,
|
|
489
638
|
videoSessionId: String(videoSessionId),
|
|
490
|
-
outro_image_url: String(outroImageUrl),
|
|
639
|
+
...(outroImageUrl ? { outro_image_url: String(outroImageUrl) } : {}),
|
|
640
|
+
generate_outro_image: generateOutroImage,
|
|
641
|
+
...(generateOutroImage ? { cta_url: String(ctaUrl).trim() } : {}),
|
|
642
|
+
...(ctaTextTop ? { cta_text_top: String(ctaTextTop) } : {}),
|
|
643
|
+
...(ctaTextBottom ? { cta_text_bottom: String(ctaTextBottom) } : {}),
|
|
644
|
+
...(ctaLogo ? { cta_logo: String(ctaLogo) } : {}),
|
|
645
|
+
...(rawAddOutroAnimation !== undefined ? { add_outro_animation: rawAddOutroAnimation === true } : {}),
|
|
646
|
+
...(rawAddOutroFocusArea !== undefined ? { add_outro_focus_area: rawAddOutroFocusArea === true } : {}),
|
|
647
|
+
...(rawOutroFocusArea !== undefined ? { outro_focust_area: rawOutroFocusArea } : {}),
|
|
491
648
|
},
|
|
492
649
|
webhookUrl: options?.webhookUrl,
|
|
493
650
|
};
|
|
@@ -669,6 +826,48 @@ export class SamsarClient {
|
|
|
669
826
|
data: normalizedData,
|
|
670
827
|
};
|
|
671
828
|
}
|
|
829
|
+
/**
|
|
830
|
+
* Publish a completed Samsar video session to the public publication feed.
|
|
831
|
+
* This is a free endpoint. The session must belong to the authenticated API key/auth token.
|
|
832
|
+
*/
|
|
833
|
+
async publishPublication(input, options) {
|
|
834
|
+
const payload = normalizeSessionPublicationInput(input, 'publishPublication');
|
|
835
|
+
return this.post('publications/publish', payload, options);
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Alias for publishPublication, named around the underlying VideoSession resource.
|
|
839
|
+
*/
|
|
840
|
+
async publishSessionPublication(input, options) {
|
|
841
|
+
return this.publishPublication(input, options);
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Edit an existing publication for a Samsar video session.
|
|
845
|
+
* Omitted fields keep their current publication values.
|
|
846
|
+
*/
|
|
847
|
+
async editPublication(input, options) {
|
|
848
|
+
const payload = normalizeSessionPublicationInput(input, 'editPublication');
|
|
849
|
+
return this.post('publications/edit', payload, options);
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Alias for editPublication, named around the underlying VideoSession resource.
|
|
853
|
+
*/
|
|
854
|
+
async editSessionPublication(input, options) {
|
|
855
|
+
return this.editPublication(input, options);
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* Revoke a publication for a Samsar video session.
|
|
859
|
+
* This deletes the publication record and clears published fields on the session.
|
|
860
|
+
*/
|
|
861
|
+
async revokePublication(input, options) {
|
|
862
|
+
const payload = normalizeSessionPublicationInput(input, 'revokePublication');
|
|
863
|
+
return this.post('publications/revoke', payload, options);
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Alias for revokePublication, named around the underlying VideoSession resource.
|
|
867
|
+
*/
|
|
868
|
+
async revokeSessionPublication(input, options) {
|
|
869
|
+
return this.revokePublication(input, options);
|
|
870
|
+
}
|
|
672
871
|
/**
|
|
673
872
|
* Fetch the supported image/video model keys for the text_to_video route.
|
|
674
873
|
* Maps to GET /video/supported_models.
|