samsar-js 0.48.14 → 0.48.16
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 +47 -7
- package/dist/index.d.ts +41 -0
- package/dist/index.js +70 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,11 +34,11 @@ const samsar = new SamsarClient({ apiKey: process.env.SAMSAR_API_KEY! });
|
|
|
34
34
|
const video = await samsar.createVideoFromText(
|
|
35
35
|
{
|
|
36
36
|
prompt: 'A drone shot of a beach at sunrise',
|
|
37
|
-
image_model: '
|
|
37
|
+
image_model: 'GPTIMAGE2',
|
|
38
38
|
video_model: 'RUNWAYML',
|
|
39
39
|
duration: 30,
|
|
40
40
|
font_key: 'Poppins',
|
|
41
|
-
enable_subtitles:
|
|
41
|
+
enable_subtitles: true,
|
|
42
42
|
},
|
|
43
43
|
{ webhookUrl: 'https://example.com/webhook' },
|
|
44
44
|
);
|
|
@@ -49,13 +49,48 @@ const videoFromImages = await samsar.createVideoFromImageList(
|
|
|
49
49
|
image_urls: ['https://example.com/a.jpg', 'https://example.com/b.jpg'],
|
|
50
50
|
prompt: 'Cinematic sequence with smooth transitions',
|
|
51
51
|
metadata: { project: 'demo' },
|
|
52
|
+
video_model: 'RUNWAYML',
|
|
53
|
+
aspect_ratio: '16:9',
|
|
52
54
|
language: 'en',
|
|
53
55
|
font_key: 'Poppins',
|
|
54
|
-
enable_subtitles:
|
|
56
|
+
enable_subtitles: true,
|
|
55
57
|
},
|
|
56
58
|
{ webhookUrl: 'https://example.com/webhook' },
|
|
57
59
|
);
|
|
58
60
|
|
|
61
|
+
// Create a video with a provided outro image
|
|
62
|
+
await samsar.createVideoFromImageList({
|
|
63
|
+
image_urls: ['https://example.com/a.jpg', 'https://example.com/b.jpg'],
|
|
64
|
+
prompt: 'Product launch teaser with a clean final CTA',
|
|
65
|
+
video_model: 'KLING3.0',
|
|
66
|
+
aspect_ratio: '16:9',
|
|
67
|
+
outro_image_url: 'https://cdn.example.com/outro.png',
|
|
68
|
+
add_outro_animation: true,
|
|
69
|
+
add_outro_focus_area: true,
|
|
70
|
+
outro_focust_area: { x: 680, y: 296, width: 432, height: 432 },
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Create a video and generate the QR outro server-side from the input images
|
|
74
|
+
await samsar.createVideoFromImageList({
|
|
75
|
+
image_urls: [
|
|
76
|
+
{ image_url: 'https://example.com/a.jpg', title: 'Blue Lagoon Tour' },
|
|
77
|
+
{ image_url: 'https://example.com/b.jpg', title: 'Sunset Dinner' },
|
|
78
|
+
],
|
|
79
|
+
prompt: 'Travel offer reel with a scannable booking outro',
|
|
80
|
+
video_model: 'RUNWAYML',
|
|
81
|
+
aspect_ratio: '9:16',
|
|
82
|
+
generate_outro_image: true,
|
|
83
|
+
cta_url: 'https://example.com/book',
|
|
84
|
+
cta_text_top: 'Scan to book',
|
|
85
|
+
cta_text_bottom: 'Limited availability',
|
|
86
|
+
cta_logo: 'https://cdn.example.com/logo-white.png',
|
|
87
|
+
add_footer_animation: true,
|
|
88
|
+
footer_metadata: [
|
|
89
|
+
{ url: 'https://example.com/blue-lagoon', title: 'Blue Lagoon Tour' },
|
|
90
|
+
{ url: 'https://example.com/sunset-dinner', title: 'Sunset Dinner' },
|
|
91
|
+
],
|
|
92
|
+
});
|
|
93
|
+
|
|
59
94
|
// Translate an existing video session into another language
|
|
60
95
|
const translated = await samsar.translateVideo(
|
|
61
96
|
{
|
|
@@ -217,7 +252,9 @@ const replaced = await samsar.replaceBrandingFromImage({
|
|
|
217
252
|
// Extend image set
|
|
218
253
|
const images = await samsar.extendImageList({
|
|
219
254
|
image_urls: ['https://example.com/extra.jpg'],
|
|
255
|
+
prompt: 'Create a cinematic travel header banner',
|
|
220
256
|
num_images: 4,
|
|
257
|
+
aspect_ratio: '16:9',
|
|
221
258
|
});
|
|
222
259
|
|
|
223
260
|
// Create a reusable receipt template from one sample receipt image (free endpoint)
|
|
@@ -322,7 +359,7 @@ await platform.setExternalAssistantSystemPrompt(
|
|
|
322
359
|
// Create a render attributed to that external user
|
|
323
360
|
const externalRender = await platform.createExternalVideoFromText(externalUser, {
|
|
324
361
|
prompt: 'A sleek teaser for a futuristic running shoe',
|
|
325
|
-
image_model: '
|
|
362
|
+
image_model: 'GPTIMAGE2',
|
|
326
363
|
video_model: 'RUNWAYML',
|
|
327
364
|
duration: 10,
|
|
328
365
|
enable_subtitles: true,
|
|
@@ -389,9 +426,12 @@ console.log(externalLibrary.data.requests.map((request) => request.request_id));
|
|
|
389
426
|
```
|
|
390
427
|
|
|
391
428
|
Video model support notes:
|
|
392
|
-
- `createVideoFromText` image model keys include: `
|
|
393
|
-
- `createVideoFromText` supports all express video models: `RUNWAYML`, `KLINGIMGTOVID3PRO`, `HAILUO`, `HAILUOPRO`, `SEEDANCEI2V
|
|
394
|
-
- `createVideoFromImageList`
|
|
429
|
+
- `createVideoFromText` image model keys include: `GPTIMAGE2`, `IMAGEN4`, `SEEDREAM`, `HUNYUAN`, `NANOBANANA2`.
|
|
430
|
+
- `createVideoFromText` supports all express video models: `RUNWAYML`, `KLINGIMGTOVID3PRO`, `HAILUO`, `HAILUOPRO`, `SEEDANCEI2V` (Seedance 2.0), `VEO3.1I2V`, `VEO3.1I2VFAST`, `SORA2`, `SORA2PRO`.
|
|
431
|
+
- `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
|
+
- `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
|
+
- `createVideoFromImageList` can render per-scene footer QR cards by setting `add_footer_animation: true` and providing one `footer_metadata` item per image scene.
|
|
434
|
+
- 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.
|
|
395
435
|
|
|
396
436
|
Each method returns `{ data, status, headers, creditsCharged, creditsRemaining, raw }`. Non-2xx responses throw `SamsarRequestError` containing status, body, and credit headers (if present).
|
|
397
437
|
|
package/dist/index.d.ts
CHANGED
|
@@ -64,6 +64,12 @@ export interface OutroFocusArea {
|
|
|
64
64
|
width: number;
|
|
65
65
|
height: number;
|
|
66
66
|
}
|
|
67
|
+
export interface FooterMetadataItem {
|
|
68
|
+
url: string;
|
|
69
|
+
title?: string;
|
|
70
|
+
}
|
|
71
|
+
export type ImageListToVideoAspectRatio = '16:9' | '9:16';
|
|
72
|
+
export type ImageListToVideoModel = 'VEO3.1I2V' | 'SEEDANCEI2V' | 'KLING3.0' | 'KLINGIMGTOVID3PRO' | 'RUNWAYML';
|
|
67
73
|
export interface ImageListToVideoItem {
|
|
68
74
|
image_url?: string;
|
|
69
75
|
imageUrl?: string;
|
|
@@ -79,12 +85,25 @@ export interface ImageListToVideoItem {
|
|
|
79
85
|
fromEnhancedList?: boolean;
|
|
80
86
|
skip_enhancement?: boolean;
|
|
81
87
|
skipEnhancement?: boolean;
|
|
88
|
+
source?: string;
|
|
89
|
+
title?: string;
|
|
90
|
+
image_title?: string;
|
|
91
|
+
imageTitle?: string;
|
|
92
|
+
image_text?: string;
|
|
93
|
+
imageText?: string;
|
|
94
|
+
activity_title?: string;
|
|
95
|
+
activityTitle?: string;
|
|
96
|
+
name?: string;
|
|
97
|
+
label?: string;
|
|
82
98
|
[key: string]: unknown;
|
|
83
99
|
}
|
|
84
100
|
export interface CreateVideoFromImageListInput {
|
|
85
101
|
image_urls: Array<string | ImageListToVideoItem>;
|
|
86
102
|
metadata?: Record<string, unknown>;
|
|
87
103
|
prompt?: string;
|
|
104
|
+
video_model?: ImageListToVideoModel;
|
|
105
|
+
aspect_ratio?: ImageListToVideoAspectRatio;
|
|
106
|
+
aspectRatio?: ImageListToVideoAspectRatio;
|
|
88
107
|
language?: string;
|
|
89
108
|
languageString?: string | null;
|
|
90
109
|
font_key?: string;
|
|
@@ -98,9 +117,29 @@ export interface CreateVideoFromImageListInput {
|
|
|
98
117
|
sessionId?: string;
|
|
99
118
|
sessionID?: string;
|
|
100
119
|
outro_image_url?: string;
|
|
120
|
+
outroImageUrl?: string;
|
|
101
121
|
add_outro_animation?: boolean;
|
|
122
|
+
addOutroAnimation?: boolean;
|
|
102
123
|
add_outro_focus_area?: boolean;
|
|
124
|
+
addOutroFocusArea?: boolean;
|
|
103
125
|
outro_focust_area?: OutroFocusArea | null;
|
|
126
|
+
outro_focus_area?: OutroFocusArea | null;
|
|
127
|
+
outroFocustArea?: OutroFocusArea | null;
|
|
128
|
+
outroFocusArea?: OutroFocusArea | null;
|
|
129
|
+
generate_outro_image?: boolean;
|
|
130
|
+
generateOutroImage?: boolean;
|
|
131
|
+
cta_url?: string;
|
|
132
|
+
ctaUrl?: string;
|
|
133
|
+
cta_text_top?: string;
|
|
134
|
+
ctaTextTop?: string;
|
|
135
|
+
cta_text_bottom?: string;
|
|
136
|
+
ctaTextBottom?: string;
|
|
137
|
+
cta_logo?: string;
|
|
138
|
+
ctaLogo?: string;
|
|
139
|
+
add_footer_animation?: boolean;
|
|
140
|
+
addFooterAnimation?: boolean;
|
|
141
|
+
footer_metadata?: FooterMetadataItem[];
|
|
142
|
+
footerMetadata?: FooterMetadataItem[];
|
|
104
143
|
[key: string]: unknown;
|
|
105
144
|
}
|
|
106
145
|
export interface TranscriptBuilderPayload {
|
|
@@ -688,6 +727,7 @@ export interface ExtendImageListRequest {
|
|
|
688
727
|
num_images: number;
|
|
689
728
|
prompt?: string;
|
|
690
729
|
metadata?: Record<string, unknown>;
|
|
730
|
+
aspect_ratio?: string;
|
|
691
731
|
}
|
|
692
732
|
export interface ExtendImageListResponse {
|
|
693
733
|
status?: string;
|
|
@@ -700,6 +740,7 @@ export interface ExtendImageListResponse {
|
|
|
700
740
|
metadata?: Record<string, unknown>;
|
|
701
741
|
prompt?: string;
|
|
702
742
|
num_images?: number;
|
|
743
|
+
aspect_ratio?: string;
|
|
703
744
|
userId?: string;
|
|
704
745
|
creditsCharged?: number;
|
|
705
746
|
remainingCredits?: number;
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,72 @@ export class SamsarRequestError extends Error {
|
|
|
15
15
|
this.creditsRemaining = init.creditsRemaining;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
+
function resolveAliasedInputValue(raw, aliases, canonicalName) {
|
|
19
|
+
let resolved;
|
|
20
|
+
let hasResolved = false;
|
|
21
|
+
for (const alias of aliases) {
|
|
22
|
+
const value = raw[alias];
|
|
23
|
+
if (value === undefined) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (!hasResolved) {
|
|
27
|
+
resolved = value;
|
|
28
|
+
hasResolved = true;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (value !== resolved) {
|
|
32
|
+
throw new Error(`${canonicalName} was provided with conflicting alias values.`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return hasResolved ? resolved : undefined;
|
|
36
|
+
}
|
|
37
|
+
function assertOptionalBoolean(value, fieldName) {
|
|
38
|
+
if (value !== undefined && typeof value !== 'boolean') {
|
|
39
|
+
throw new Error(`${fieldName} must be a boolean for createVideoFromImageList`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function normalizeCreateVideoFromImageListInput(input) {
|
|
43
|
+
const raw = input;
|
|
44
|
+
if (!Array.isArray(input.image_urls) || input.image_urls.length === 0) {
|
|
45
|
+
throw new Error('image_urls must be a non-empty array for createVideoFromImageList');
|
|
46
|
+
}
|
|
47
|
+
const normalized = { ...input };
|
|
48
|
+
const aliases = [
|
|
49
|
+
['session_id', ['session_id', 'sessionId', 'sessionID']],
|
|
50
|
+
['aspect_ratio', ['aspect_ratio', 'aspectRatio']],
|
|
51
|
+
['outro_image_url', ['outro_image_url', 'outroImageUrl']],
|
|
52
|
+
['add_outro_animation', ['add_outro_animation', 'addOutroAnimation']],
|
|
53
|
+
['add_outro_focus_area', ['add_outro_focus_area', 'addOutroFocusArea']],
|
|
54
|
+
['outro_focust_area', ['outro_focust_area', 'outro_focus_area', 'outroFocustArea', 'outroFocusArea']],
|
|
55
|
+
['generate_outro_image', ['generate_outro_image', 'generateOutroImage']],
|
|
56
|
+
['cta_url', ['cta_url', 'ctaUrl']],
|
|
57
|
+
['cta_text_top', ['cta_text_top', 'ctaTextTop']],
|
|
58
|
+
['cta_text_bottom', ['cta_text_bottom', 'ctaTextBottom']],
|
|
59
|
+
['cta_logo', ['cta_logo', 'ctaLogo']],
|
|
60
|
+
['enable_subtitles', ['enable_subtitles', 'enableSubtitles']],
|
|
61
|
+
['font_key', ['font_key', 'fontKey']],
|
|
62
|
+
];
|
|
63
|
+
for (const [canonicalName, aliasList] of aliases) {
|
|
64
|
+
const value = resolveAliasedInputValue(raw, aliasList, canonicalName);
|
|
65
|
+
if (value !== undefined) {
|
|
66
|
+
normalized[canonicalName] = value;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
assertOptionalBoolean(normalized.enable_subtitles, 'enable_subtitles');
|
|
70
|
+
assertOptionalBoolean(normalized.add_outro_animation, 'add_outro_animation');
|
|
71
|
+
assertOptionalBoolean(normalized.add_outro_focus_area, 'add_outro_focus_area');
|
|
72
|
+
assertOptionalBoolean(normalized.generate_outro_image, 'generate_outro_image');
|
|
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 createVideoFromImageList');
|
|
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 createVideoFromImageList');
|
|
81
|
+
}
|
|
82
|
+
return normalized;
|
|
83
|
+
}
|
|
18
84
|
export class SamsarClient {
|
|
19
85
|
constructor(options) {
|
|
20
86
|
if (!options?.apiKey) {
|
|
@@ -44,8 +110,9 @@ export class SamsarClient {
|
|
|
44
110
|
* Create a video from a list of image URLs with optional prompt/metadata via the image_list_to_video route.
|
|
45
111
|
*/
|
|
46
112
|
async createVideoFromImageList(input, options) {
|
|
113
|
+
const normalizedInput = normalizeCreateVideoFromImageListInput(input);
|
|
47
114
|
const body = {
|
|
48
|
-
input,
|
|
115
|
+
input: normalizedInput,
|
|
49
116
|
webhookUrl: options?.webhookUrl,
|
|
50
117
|
};
|
|
51
118
|
const response = await this.post('video/image_list_to_video', body, options);
|
|
@@ -99,9 +166,10 @@ export class SamsarClient {
|
|
|
99
166
|
* Create an image-list-to-video request attributed to an external user while billing against the shared API key.
|
|
100
167
|
*/
|
|
101
168
|
async createExternalVideoFromImageList(externalUser, input, options) {
|
|
169
|
+
const normalizedInput = normalizeCreateVideoFromImageListInput(input);
|
|
102
170
|
const body = {
|
|
103
171
|
external_user: normalizeExternalUserIdentity(externalUser),
|
|
104
|
-
input,
|
|
172
|
+
input: normalizedInput,
|
|
105
173
|
webhookUrl: options?.webhookUrl,
|
|
106
174
|
};
|
|
107
175
|
return this.post('external_users/image_list_to_video', body, options);
|