agent-media-cli 1.8.1 → 1.8.3
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/dist/commands/character-video.d.ts +3 -0
- package/dist/commands/character-video.d.ts.map +1 -0
- package/dist/commands/character-video.js +320 -0
- package/dist/commands/character-video.js.map +1 -0
- package/dist/commands/text-to-video.d.ts +3 -0
- package/dist/commands/text-to-video.d.ts.map +1 -0
- package/dist/commands/text-to-video.js +148 -0
- package/dist/commands/text-to-video.js.map +1 -0
- package/dist/commands/ugc.d.ts.map +1 -1
- package/dist/commands/ugc.js +57 -4
- package/dist/commands/ugc.js.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/api.d.ts +76 -0
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +63 -0
- package/dist/lib/api.js.map +1 -1
- package/dist/tests/commands.test.js +245 -0
- package/package.json +10 -9
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"character-video.d.ts","sourceRoot":"","sources":["../../src/commands/character-video.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuGzC,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiPpE"}
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
// Copyright 2026 agent-media contributors. Apache-2.0 license.
|
|
2
|
+
/**
|
|
3
|
+
* `agent-media character-video` command.
|
|
4
|
+
*
|
|
5
|
+
* Runs the 3-step Content Machine pipeline end-to-end:
|
|
6
|
+
* 1. POST /v1/character/sheet-generate → character_sheet_url
|
|
7
|
+
* 2. POST /v1/character/storyboard-generate → storyboard_url
|
|
8
|
+
* 3. POST /v1/generate/character_video → final 720p MP4
|
|
9
|
+
*
|
|
10
|
+
* The user supplies one character source (--description / --actor /
|
|
11
|
+
* --reference-image), then either --beats or --script for the
|
|
12
|
+
* storyboard, then duration + aspect ratio for the video. A single
|
|
13
|
+
* --session-id ties the three steps together so api-v2 can backstop
|
|
14
|
+
* action_prompt from the storyboard's script/beats.
|
|
15
|
+
*/
|
|
16
|
+
import { randomUUID } from 'node:crypto';
|
|
17
|
+
import { readFileSync, existsSync, statSync } from 'node:fs';
|
|
18
|
+
import { extname, basename } from 'node:path';
|
|
19
|
+
import chalk from 'chalk';
|
|
20
|
+
import { detectOutputMode, printJson, printQuiet, createSpinner, } from '../lib/output.js';
|
|
21
|
+
import { getApiKey, resolveProfileName } from '../lib/credentials.js';
|
|
22
|
+
import { AgentMediaAPI } from '../lib/api.js';
|
|
23
|
+
import { CLIError, handleError } from '../lib/errors.js';
|
|
24
|
+
const POLL_INTERVAL_MS = 5_000;
|
|
25
|
+
const TERMINAL_STATUSES = new Set(['completed', 'failed', 'canceled']);
|
|
26
|
+
const SUPABASE_PUBLIC_BASE = 'https://ppwvarkmpffljlqxkjux.supabase.co/storage/v1/object/public/generation-inputs';
|
|
27
|
+
const IMAGE_MIME = {
|
|
28
|
+
'.png': 'image/png',
|
|
29
|
+
'.jpg': 'image/jpeg',
|
|
30
|
+
'.jpeg': 'image/jpeg',
|
|
31
|
+
'.webp': 'image/webp',
|
|
32
|
+
};
|
|
33
|
+
const MAX_REFERENCE_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
34
|
+
const VALID_DURATIONS = new Set([5, 10]);
|
|
35
|
+
const VALID_RATIOS = new Set(['9:16', '16:9', '1:1']);
|
|
36
|
+
function isUrl(s) {
|
|
37
|
+
return /^https?:\/\//i.test(s);
|
|
38
|
+
}
|
|
39
|
+
async function uploadLocalImage(api, filePath, mode) {
|
|
40
|
+
if (!existsSync(filePath)) {
|
|
41
|
+
throw new CLIError(`File not found: ${filePath}`, { code: 'FILE_NOT_FOUND' });
|
|
42
|
+
}
|
|
43
|
+
const stats = statSync(filePath);
|
|
44
|
+
if (stats.size > MAX_REFERENCE_IMAGE_BYTES) {
|
|
45
|
+
throw new CLIError(`Reference image too large: ${(stats.size / 1024 / 1024).toFixed(1)} MB (max 5 MB)`, { code: 'FILE_TOO_LARGE', suggestion: 'Use a smaller image or compress (jpeg/webp).' });
|
|
46
|
+
}
|
|
47
|
+
const ext = extname(filePath).toLowerCase();
|
|
48
|
+
const contentType = IMAGE_MIME[ext];
|
|
49
|
+
if (!contentType) {
|
|
50
|
+
throw new CLIError(`Unsupported reference image type: ${ext}. Allowed: ${Object.keys(IMAGE_MIME).join(', ')}`, { code: 'UNSUPPORTED_FILE_TYPE' });
|
|
51
|
+
}
|
|
52
|
+
const filename = basename(filePath);
|
|
53
|
+
const sp = createSpinner(`Uploading ${filename}...`);
|
|
54
|
+
if (mode === 'human')
|
|
55
|
+
sp.start();
|
|
56
|
+
const { upload_url, storage_path } = await api.getUploadUrl(filename, contentType);
|
|
57
|
+
const buf = readFileSync(filePath);
|
|
58
|
+
const ab = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
59
|
+
await api.uploadFile(upload_url, ab, contentType);
|
|
60
|
+
if (mode === 'human')
|
|
61
|
+
sp.succeed(`Uploaded ${filename}`);
|
|
62
|
+
return `${SUPABASE_PUBLIC_BASE}/${storage_path}`;
|
|
63
|
+
}
|
|
64
|
+
async function pollUntilDone(api, jobId, label, expectedSeconds, mode) {
|
|
65
|
+
const start = Date.now();
|
|
66
|
+
const spinner = createSpinner(`${label} (~${expectedSeconds}s)...`);
|
|
67
|
+
if (mode === 'human')
|
|
68
|
+
spinner.start();
|
|
69
|
+
let onSigint = null;
|
|
70
|
+
try {
|
|
71
|
+
onSigint = () => {
|
|
72
|
+
if (mode === 'human')
|
|
73
|
+
spinner.fail(`Aborted while waiting on ${label.toLowerCase()}`);
|
|
74
|
+
process.exit(130);
|
|
75
|
+
};
|
|
76
|
+
process.on('SIGINT', onSigint);
|
|
77
|
+
while (true) {
|
|
78
|
+
const job = await api.getJob(jobId);
|
|
79
|
+
if (TERMINAL_STATUSES.has(job.status)) {
|
|
80
|
+
const elapsed = Math.round((Date.now() - start) / 1000);
|
|
81
|
+
if (mode === 'human') {
|
|
82
|
+
if (job.status === 'completed')
|
|
83
|
+
spinner.succeed(`${label} complete (${elapsed}s)`);
|
|
84
|
+
else
|
|
85
|
+
spinner.fail(`${label} ${job.status}: ${job.error_message ?? 'unknown error'}`);
|
|
86
|
+
}
|
|
87
|
+
return job;
|
|
88
|
+
}
|
|
89
|
+
if (mode === 'human') {
|
|
90
|
+
const elapsed = Math.round((Date.now() - start) / 1000);
|
|
91
|
+
spinner.text = `${label} ${chalk.dim(`(${elapsed}s)`)}`;
|
|
92
|
+
}
|
|
93
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
if (onSigint)
|
|
98
|
+
process.removeListener('SIGINT', onSigint);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export function registerCharacterVideoCommand(program) {
|
|
102
|
+
program
|
|
103
|
+
.command('character-video')
|
|
104
|
+
.description('Content Machine: character sheet → storyboard → 720p video, in three orchestrated calls.\n\n' +
|
|
105
|
+
'Examples:\n' +
|
|
106
|
+
' $ agent-media character-video \\\n' +
|
|
107
|
+
' --description "Marco, 35yo Italian chef, white uniform, curly black hair" \\\n' +
|
|
108
|
+
' --script "Marco walks into his sunlit Brooklyn kitchen, takes a bite of fresh bread, smiles." \\\n' +
|
|
109
|
+
' --duration 10 --aspect 9:16 --sync\n\n' +
|
|
110
|
+
' $ agent-media character-video \\\n' +
|
|
111
|
+
' --actor mei \\\n' +
|
|
112
|
+
' --beats "waves hello,holds up product,thumbs up" \\\n' +
|
|
113
|
+
' --duration 5 --sync\n\n' +
|
|
114
|
+
' $ agent-media character-video \\\n' +
|
|
115
|
+
' --reference-image ./photo.png \\\n' +
|
|
116
|
+
' --script "..." \\\n' +
|
|
117
|
+
' --sync\n\n' +
|
|
118
|
+
'Provide ONE of --description / --actor / --reference-image, and ONE of --beats / --script.')
|
|
119
|
+
.option('--description <text>', 'Free-text character description (3-400 chars)')
|
|
120
|
+
.option('--actor <slug>', 'Actor slug from the agent-media library')
|
|
121
|
+
.option('--reference-image <pathOrUrl>', 'Local PNG/JPEG/WebP file or public HTTPS URL of a portrait (max 5 MB)')
|
|
122
|
+
.option('--beats <comma-separated>', 'Comma-separated list of 3-10 beat descriptions for the storyboard')
|
|
123
|
+
.option('--script <text>', 'Free-text script (10-1500 chars); the model splits it into 4-6 panels')
|
|
124
|
+
.option('--duration <seconds>', 'Video duration: 5 or 10', '10')
|
|
125
|
+
.option('--aspect <ratio>', 'Aspect ratio: 9:16, 16:9, or 1:1', '9:16')
|
|
126
|
+
.option('--no-audio', 'Disable Seedance audio synthesis')
|
|
127
|
+
.option('--action-prompt <text>', 'Optional explicit scene/location prompt for Seedance (otherwise derived from script/beats)')
|
|
128
|
+
.option('--webhook-url <url>', 'Webhook to call on completion of the final video step')
|
|
129
|
+
.option('-s, --sync', 'Wait for each step to complete (default: only sync on the video step)')
|
|
130
|
+
.action(async (cmdOpts) => {
|
|
131
|
+
const globalOpts = program.opts();
|
|
132
|
+
const mode = detectOutputMode(globalOpts);
|
|
133
|
+
// ── Validate flags BEFORE the auth check so bad args fail fast
|
|
134
|
+
// without requiring a login round-trip. (Same UX rationale: a user
|
|
135
|
+
// with the wrong --duration shouldn't see "Not logged in" first.)
|
|
136
|
+
// Character source — exactly one of description / actor / reference
|
|
137
|
+
const sources = [cmdOpts.description, cmdOpts.actor, cmdOpts.referenceImage].filter(Boolean).length;
|
|
138
|
+
if (sources === 0) {
|
|
139
|
+
throw new CLIError('Provide one of --description, --actor, or --reference-image', {
|
|
140
|
+
code: 'VALIDATION_ERROR',
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
if (cmdOpts.actor && cmdOpts.referenceImage) {
|
|
144
|
+
throw new CLIError('--actor and --reference-image are mutually exclusive', {
|
|
145
|
+
code: 'VALIDATION_ERROR',
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
// Storyboard source — exactly one of beats / script
|
|
149
|
+
if (Boolean(cmdOpts.beats) === Boolean(cmdOpts.script)) {
|
|
150
|
+
throw new CLIError('Provide exactly one of --beats or --script', { code: 'VALIDATION_ERROR' });
|
|
151
|
+
}
|
|
152
|
+
const duration = Number(cmdOpts.duration);
|
|
153
|
+
if (!VALID_DURATIONS.has(duration)) {
|
|
154
|
+
throw new CLIError(`Invalid --duration: ${cmdOpts.duration}`, {
|
|
155
|
+
code: 'VALIDATION_ERROR', suggestion: 'Use 5 or 10.',
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
if (!VALID_RATIOS.has(cmdOpts.aspect)) {
|
|
159
|
+
throw new CLIError(`Invalid --aspect: ${cmdOpts.aspect}`, {
|
|
160
|
+
code: 'VALIDATION_ERROR', suggestion: 'Use 9:16, 16:9, or 1:1.',
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
const beats = cmdOpts.beats
|
|
164
|
+
? cmdOpts.beats.split(',').map((b) => b.trim()).filter((b) => b.length >= 3)
|
|
165
|
+
: undefined;
|
|
166
|
+
if (beats && (beats.length < 3 || beats.length > 10)) {
|
|
167
|
+
throw new CLIError(`--beats must be 3-10 entries (≥3 chars each); got ${beats.length}`, {
|
|
168
|
+
code: 'VALIDATION_ERROR',
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
// Auth check after validation
|
|
172
|
+
const profileName = resolveProfileName(globalOpts.profile);
|
|
173
|
+
const apiKey = getApiKey(profileName);
|
|
174
|
+
if (!apiKey) {
|
|
175
|
+
throw new CLIError('Not logged in.', {
|
|
176
|
+
code: 'NOT_AUTHENTICATED',
|
|
177
|
+
suggestion: "Run 'agent-media login' to authenticate.",
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
const sessionId = randomUUID();
|
|
181
|
+
try {
|
|
182
|
+
const api = new AgentMediaAPI(apiKey);
|
|
183
|
+
// ── Resolve reference image (upload local files) ────────────────
|
|
184
|
+
let referenceImageUrl;
|
|
185
|
+
if (cmdOpts.referenceImage) {
|
|
186
|
+
referenceImageUrl = isUrl(cmdOpts.referenceImage)
|
|
187
|
+
? cmdOpts.referenceImage
|
|
188
|
+
: await uploadLocalImage(api, cmdOpts.referenceImage, mode);
|
|
189
|
+
}
|
|
190
|
+
// ── Step 1: Character sheet ────────────────────────────────────
|
|
191
|
+
if (mode === 'human') {
|
|
192
|
+
console.log();
|
|
193
|
+
console.log(chalk.bold('1/3 · Character sheet'));
|
|
194
|
+
}
|
|
195
|
+
const sheetSubmit = await api.characterSheetGenerate({
|
|
196
|
+
description: cmdOpts.description,
|
|
197
|
+
actor_slug: cmdOpts.actor,
|
|
198
|
+
reference_image_url: referenceImageUrl,
|
|
199
|
+
session_id: sessionId,
|
|
200
|
+
});
|
|
201
|
+
if (mode === 'human') {
|
|
202
|
+
console.log(chalk.dim(` Job ${sheetSubmit.job_id} · ${sheetSubmit.credits_deducted} credits`));
|
|
203
|
+
}
|
|
204
|
+
const sheetJob = await pollUntilDone(api, sheetSubmit.job_id, 'Sheet', sheetSubmit.expected_seconds ?? 180, mode);
|
|
205
|
+
if (sheetJob.status !== 'completed' || !sheetJob.output_media_url) {
|
|
206
|
+
throw new CLIError(`Character sheet failed: ${sheetJob.error_message ?? 'no output URL'}`, {
|
|
207
|
+
code: 'SHEET_FAILED',
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
const characterSheetUrl = sheetJob.output_media_url;
|
|
211
|
+
if (mode === 'human')
|
|
212
|
+
console.log(chalk.dim(` → ${characterSheetUrl}`));
|
|
213
|
+
// ── Step 2: Storyboard ─────────────────────────────────────────
|
|
214
|
+
if (mode === 'human') {
|
|
215
|
+
console.log();
|
|
216
|
+
console.log(chalk.bold('2/3 · Storyboard'));
|
|
217
|
+
}
|
|
218
|
+
const sbSubmit = await api.characterStoryboardGenerate({
|
|
219
|
+
character_sheet_url: characterSheetUrl,
|
|
220
|
+
beats,
|
|
221
|
+
script: cmdOpts.script,
|
|
222
|
+
ratio: cmdOpts.aspect,
|
|
223
|
+
session_id: sessionId,
|
|
224
|
+
});
|
|
225
|
+
if (mode === 'human') {
|
|
226
|
+
console.log(chalk.dim(` Job ${sbSubmit.job_id} · ${sbSubmit.credits_deducted} credits`));
|
|
227
|
+
}
|
|
228
|
+
const sbJob = await pollUntilDone(api, sbSubmit.job_id, 'Storyboard', sbSubmit.expected_seconds ?? 180, mode);
|
|
229
|
+
if (sbJob.status !== 'completed' || !sbJob.output_media_url) {
|
|
230
|
+
throw new CLIError(`Storyboard failed: ${sbJob.error_message ?? 'no output URL'}`, {
|
|
231
|
+
code: 'STORYBOARD_FAILED',
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
const storyboardUrl = sbJob.output_media_url;
|
|
235
|
+
if (mode === 'human')
|
|
236
|
+
console.log(chalk.dim(` → ${storyboardUrl}`));
|
|
237
|
+
// ── Step 3: Video ──────────────────────────────────────────────
|
|
238
|
+
if (mode === 'human') {
|
|
239
|
+
console.log();
|
|
240
|
+
console.log(chalk.bold('3/3 · Video'));
|
|
241
|
+
}
|
|
242
|
+
const videoSubmit = await api.characterVideoGenerate({
|
|
243
|
+
character_sheet_url: characterSheetUrl,
|
|
244
|
+
storyboard_url: storyboardUrl,
|
|
245
|
+
action_prompt: cmdOpts.actionPrompt,
|
|
246
|
+
duration: duration,
|
|
247
|
+
aspect_ratio: cmdOpts.aspect,
|
|
248
|
+
generate_audio: cmdOpts.audio,
|
|
249
|
+
session_id: sessionId,
|
|
250
|
+
webhook_url: cmdOpts.webhookUrl,
|
|
251
|
+
});
|
|
252
|
+
if (mode === 'human') {
|
|
253
|
+
console.log(chalk.dim(` Job ${videoSubmit.job_id} · ${videoSubmit.credits_deducted} credits`));
|
|
254
|
+
}
|
|
255
|
+
if (!cmdOpts.sync) {
|
|
256
|
+
// Caller doesn't want to wait on the final video; print what we have so far.
|
|
257
|
+
switch (mode) {
|
|
258
|
+
case 'json':
|
|
259
|
+
printJson({
|
|
260
|
+
session_id: sessionId,
|
|
261
|
+
character_sheet_url: characterSheetUrl,
|
|
262
|
+
storyboard_url: storyboardUrl,
|
|
263
|
+
video_job_id: videoSubmit.job_id,
|
|
264
|
+
video_status: videoSubmit.status,
|
|
265
|
+
credits_deducted: videoSubmit.credits_deducted,
|
|
266
|
+
});
|
|
267
|
+
break;
|
|
268
|
+
case 'quiet':
|
|
269
|
+
printQuiet(videoSubmit.job_id);
|
|
270
|
+
break;
|
|
271
|
+
default:
|
|
272
|
+
console.log();
|
|
273
|
+
console.log(chalk.dim(` Run 'agent-media status ${videoSubmit.job_id}' to follow the video render`));
|
|
274
|
+
console.log();
|
|
275
|
+
}
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const videoJob = await pollUntilDone(api, videoSubmit.job_id, 'Video', 180, mode);
|
|
279
|
+
if (mode === 'json') {
|
|
280
|
+
const payload = {
|
|
281
|
+
session_id: sessionId,
|
|
282
|
+
character_sheet_url: characterSheetUrl,
|
|
283
|
+
storyboard_url: storyboardUrl,
|
|
284
|
+
video_job_id: videoJob.id,
|
|
285
|
+
status: videoJob.status,
|
|
286
|
+
credits_deducted: videoSubmit.credits_deducted,
|
|
287
|
+
};
|
|
288
|
+
if (videoJob.status === 'failed') {
|
|
289
|
+
payload['error'] = videoJob.error_message ?? 'Unknown error';
|
|
290
|
+
if (videoJob.error_code)
|
|
291
|
+
payload['error_code'] = videoJob.error_code;
|
|
292
|
+
}
|
|
293
|
+
if (videoJob.output_media_url)
|
|
294
|
+
payload['video_url'] = videoJob.output_media_url;
|
|
295
|
+
printJson(payload);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (mode === 'quiet') {
|
|
299
|
+
printQuiet(videoJob.output_media_url ?? videoJob.id);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (videoJob.status === 'completed' && videoJob.output_media_url) {
|
|
303
|
+
console.log();
|
|
304
|
+
console.log(` ${chalk.bold('Sheet:')} ${chalk.cyan(characterSheetUrl)}`);
|
|
305
|
+
console.log(` ${chalk.bold('Storyboard:')} ${chalk.cyan(storyboardUrl)}`);
|
|
306
|
+
console.log(` ${chalk.bold('Video:')} ${chalk.cyan(videoJob.output_media_url)}`);
|
|
307
|
+
console.log();
|
|
308
|
+
}
|
|
309
|
+
else if (videoJob.status !== 'completed') {
|
|
310
|
+
console.log();
|
|
311
|
+
console.log(chalk.yellow(' Video did not complete successfully.'));
|
|
312
|
+
console.log();
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
catch (error) {
|
|
316
|
+
handleError(error);
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=character-video.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"character-video.js","sourceRoot":"","sources":["../../src/commands/character-video.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-to-video.d.ts","sourceRoot":"","sources":["../../src/commands/text-to-video.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyDzC,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqGjE"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// Copyright 2026 agent-media contributors. Apache-2.0 license.
|
|
2
|
+
/**
|
|
3
|
+
* `agent-media text-to-video` command.
|
|
4
|
+
*
|
|
5
|
+
* Pure-prompt video generation via Seedance 2.0 text-to-video at 720p.
|
|
6
|
+
* No character sheet, no storyboard. The prompt IS the entire creative —
|
|
7
|
+
* style, subject, mood, composition, lighting. Best for stylistic content
|
|
8
|
+
* where you want the model to invent everything from the prompt text.
|
|
9
|
+
*
|
|
10
|
+
* Cost: 350 / 700 / 1050 credits for 5 / 10 / 15s.
|
|
11
|
+
*/
|
|
12
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
13
|
+
import chalk from 'chalk';
|
|
14
|
+
import { detectOutputMode, printJson, printQuiet, createSpinner, } from '../lib/output.js';
|
|
15
|
+
import { getApiKey, resolveProfileName } from '../lib/credentials.js';
|
|
16
|
+
import { AgentMediaAPI } from '../lib/api.js';
|
|
17
|
+
import { CLIError, handleError } from '../lib/errors.js';
|
|
18
|
+
const POLL_INTERVAL_MS = 5_000;
|
|
19
|
+
const TERMINAL_STATUSES = new Set(['completed', 'failed', 'canceled']);
|
|
20
|
+
const VALID_DURATIONS = new Set([5, 10, 15]);
|
|
21
|
+
const VALID_RATIOS = new Set(['9:16', '16:9', '1:1']);
|
|
22
|
+
async function pollUntilDone(api, jobId, expectedSeconds, mode) {
|
|
23
|
+
const start = Date.now();
|
|
24
|
+
const spinner = createSpinner(`Rendering (~${expectedSeconds}s)...`);
|
|
25
|
+
if (mode === 'human')
|
|
26
|
+
spinner.start();
|
|
27
|
+
let onSigint = null;
|
|
28
|
+
try {
|
|
29
|
+
onSigint = () => {
|
|
30
|
+
if (mode === 'human')
|
|
31
|
+
spinner.fail('Aborted while waiting');
|
|
32
|
+
process.exit(130);
|
|
33
|
+
};
|
|
34
|
+
process.on('SIGINT', onSigint);
|
|
35
|
+
while (true) {
|
|
36
|
+
const job = await api.getJob(jobId);
|
|
37
|
+
if (TERMINAL_STATUSES.has(job.status)) {
|
|
38
|
+
const elapsed = Math.round((Date.now() - start) / 1000);
|
|
39
|
+
if (mode === 'human') {
|
|
40
|
+
if (job.status === 'completed')
|
|
41
|
+
spinner.succeed(`Done (${elapsed}s)`);
|
|
42
|
+
else
|
|
43
|
+
spinner.fail(`${job.status}: ${job.error_message ?? 'unknown error'}`);
|
|
44
|
+
}
|
|
45
|
+
return job;
|
|
46
|
+
}
|
|
47
|
+
if (mode === 'human') {
|
|
48
|
+
const elapsed = Math.round((Date.now() - start) / 1000);
|
|
49
|
+
spinner.text = `Rendering ${chalk.dim(`(${elapsed}s)`)}`;
|
|
50
|
+
}
|
|
51
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
if (onSigint)
|
|
56
|
+
process.removeListener('SIGINT', onSigint);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export function registerTextToVideoCommand(program) {
|
|
60
|
+
program
|
|
61
|
+
.command('text-to-video')
|
|
62
|
+
.description('Pure-prompt text-to-video via Seedance 2.0 — no character, no storyboard. The prompt is the entire creative.\n\n' +
|
|
63
|
+
'Examples:\n' +
|
|
64
|
+
' $ agent-media text-to-video \\\n' +
|
|
65
|
+
' --prompt "Handcrafted stop-motion. Miniature practical sets, animation on 2s, warm magical lighting." \\\n' +
|
|
66
|
+
' --duration 5 --aspect 9:16 --wait\n\n' +
|
|
67
|
+
' $ agent-media text-to-video --prompt-file ./prompts/stop-motion.txt --duration 10 --wait\n\n' +
|
|
68
|
+
'Use --wait to block until the video is rendered and print the R2 URL; without --wait the command prints the job_id and exits.')
|
|
69
|
+
.option('--prompt <text>', 'Full video prompt (20–1000 chars). Style + subject + mood + composition all in one string.')
|
|
70
|
+
.option('--prompt-file <path>', 'Read the prompt from a local file instead of --prompt.')
|
|
71
|
+
.option('--duration <seconds>', 'Video duration: 5, 10, or 15', '10')
|
|
72
|
+
.option('--aspect <ratio>', 'Aspect ratio: 9:16, 16:9, or 1:1', '9:16')
|
|
73
|
+
.option('--no-audio', 'Disable Seedance audio synthesis')
|
|
74
|
+
.option('--webhook-url <url>', 'HTTPS URL to receive a callback on completion')
|
|
75
|
+
.option('-w, --wait', 'Block until the job completes and print the video URL')
|
|
76
|
+
.action(async (cmdOpts) => {
|
|
77
|
+
const globalOpts = program.opts();
|
|
78
|
+
const mode = detectOutputMode(globalOpts);
|
|
79
|
+
try {
|
|
80
|
+
// Resolve prompt: --prompt wins; otherwise --prompt-file.
|
|
81
|
+
let promptText = cmdOpts.prompt;
|
|
82
|
+
if (!promptText && cmdOpts.promptFile) {
|
|
83
|
+
if (!existsSync(cmdOpts.promptFile)) {
|
|
84
|
+
throw new CLIError(`Prompt file not found: ${cmdOpts.promptFile}`, { code: 'FILE_NOT_FOUND' });
|
|
85
|
+
}
|
|
86
|
+
promptText = readFileSync(cmdOpts.promptFile, 'utf8').trim();
|
|
87
|
+
}
|
|
88
|
+
if (!promptText || promptText.trim().length < 20 || promptText.length > 1000) {
|
|
89
|
+
throw new CLIError('--prompt (or --prompt-file) is required (20–1000 chars).', { code: 'VALIDATION_ERROR' });
|
|
90
|
+
}
|
|
91
|
+
const duration = Number.parseInt(cmdOpts.duration, 10);
|
|
92
|
+
if (!VALID_DURATIONS.has(duration)) {
|
|
93
|
+
throw new CLIError(`--duration must be 5, 10, or 15 (got ${cmdOpts.duration})`, { code: 'VALIDATION_ERROR' });
|
|
94
|
+
}
|
|
95
|
+
if (!VALID_RATIOS.has(cmdOpts.aspect)) {
|
|
96
|
+
throw new CLIError(`--aspect must be 9:16, 16:9, or 1:1 (got ${cmdOpts.aspect})`, { code: 'VALIDATION_ERROR' });
|
|
97
|
+
}
|
|
98
|
+
const profile = await resolveProfileName(globalOpts.profile);
|
|
99
|
+
const apiKey = await getApiKey(profile);
|
|
100
|
+
const api = new AgentMediaAPI(apiKey ?? undefined);
|
|
101
|
+
const submit = await api.textToVideoGenerate({
|
|
102
|
+
prompt: promptText.trim(),
|
|
103
|
+
duration: duration,
|
|
104
|
+
aspect_ratio: cmdOpts.aspect,
|
|
105
|
+
generate_audio: cmdOpts.audio,
|
|
106
|
+
...(cmdOpts.webhookUrl ? { webhook_url: cmdOpts.webhookUrl } : {}),
|
|
107
|
+
});
|
|
108
|
+
if (!cmdOpts.wait) {
|
|
109
|
+
if (mode === 'json')
|
|
110
|
+
printJson({ job_id: submit.job_id, status: submit.status, credits_deducted: submit.credits_deducted });
|
|
111
|
+
else if (mode === 'quiet')
|
|
112
|
+
printQuiet(submit.job_id);
|
|
113
|
+
else {
|
|
114
|
+
console.log(chalk.green(`✔ Submitted job ${submit.job_id} (${submit.credits_deducted} cr deducted).`));
|
|
115
|
+
console.log(` Poll with: ${chalk.cyan(`agent-media inspect ${submit.job_id}`)}`);
|
|
116
|
+
}
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const job = await pollUntilDone(api, submit.job_id, duration * 30, mode);
|
|
120
|
+
if (job.status !== 'completed') {
|
|
121
|
+
throw new CLIError(`Job ${job.status}: ${job.error_message ?? 'unknown error'}`, { code: 'GENERATION_FAILED' });
|
|
122
|
+
}
|
|
123
|
+
const videoUrl = job.output_media_url;
|
|
124
|
+
if (!videoUrl) {
|
|
125
|
+
throw new CLIError(`Job completed without an output URL (id ${submit.job_id})`, { code: 'GENERATION_FAILED' });
|
|
126
|
+
}
|
|
127
|
+
if (mode === 'json') {
|
|
128
|
+
printJson({
|
|
129
|
+
job_id: submit.job_id,
|
|
130
|
+
video_url: videoUrl,
|
|
131
|
+
duration: submit.duration,
|
|
132
|
+
aspect_ratio: submit.aspect_ratio,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
else if (mode === 'quiet') {
|
|
136
|
+
printQuiet(videoUrl);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
console.log(chalk.green(`\n✔ Done.`));
|
|
140
|
+
console.log(` ${chalk.cyan(videoUrl)}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
handleError(err);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=text-to-video.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-to-video.js","sourceRoot":"","sources":["../../src/commands/text-to-video.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ugc.d.ts","sourceRoot":"","sources":["../../src/commands/ugc.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"ugc.d.ts","sourceRoot":"","sources":["../../src/commands/ugc.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgNzC,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAulBzD"}
|
package/dist/commands/ugc.js
CHANGED
|
@@ -18,8 +18,28 @@ import { AgentMediaAPI, } from '../lib/api.js';
|
|
|
18
18
|
import { CLIError, handleError } from '../lib/errors.js';
|
|
19
19
|
/** Poll interval for --sync mode, in milliseconds. */
|
|
20
20
|
const POLL_INTERVAL_MS = 5_000;
|
|
21
|
+
/** Max consecutive poll failures before we give up. ~3 minutes at 30 s back-off. */
|
|
22
|
+
const POLL_MAX_CONSECUTIVE_FAILURES = 6;
|
|
21
23
|
/** Terminal job statuses that end the polling loop. */
|
|
22
24
|
const TERMINAL_STATUSES = new Set(['completed', 'failed', 'canceled']);
|
|
25
|
+
/**
|
|
26
|
+
* Poll the API once, tolerating transient network and 5xx failures.
|
|
27
|
+
*
|
|
28
|
+
* Returns `null` when the call fails — the caller should keep looping and
|
|
29
|
+
* try again on the next tick. The CLI used to crash on any fetch error
|
|
30
|
+
* (e.g. a Railway 502 during an autoscale) even though the job kept
|
|
31
|
+
* running server-side. Now we just log a dim warning, count consecutive
|
|
32
|
+
* failures, and bail only after {@link POLL_MAX_CONSECUTIVE_FAILURES}
|
|
33
|
+
* in a row.
|
|
34
|
+
*/
|
|
35
|
+
async function pollOnce(api, jobId) {
|
|
36
|
+
try {
|
|
37
|
+
return await api.pollProvider(jobId);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
23
43
|
/** Status labels with color coding. */
|
|
24
44
|
const STATUS_COLORS = {
|
|
25
45
|
pending: chalk.yellow,
|
|
@@ -62,10 +82,31 @@ async function waitForJob(api, jobId, mode) {
|
|
|
62
82
|
const spinner = createSpinner('Producing UGC video...');
|
|
63
83
|
if (mode === 'human')
|
|
64
84
|
spinner.start();
|
|
85
|
+
let consecutiveFailures = 0;
|
|
65
86
|
try {
|
|
66
87
|
while (!interrupted) {
|
|
67
|
-
const poll = await api
|
|
88
|
+
const poll = await pollOnce(api, jobId);
|
|
68
89
|
const elapsed = Math.floor((Date.now() - startTime) / 1000);
|
|
90
|
+
if (!poll) {
|
|
91
|
+
consecutiveFailures += 1;
|
|
92
|
+
if (consecutiveFailures >= POLL_MAX_CONSECUTIVE_FAILURES) {
|
|
93
|
+
if (mode === 'human') {
|
|
94
|
+
spinner.fail(`Lost connection to the API after ${formatElapsed(elapsed)}. ` +
|
|
95
|
+
`Job ${jobId} may still be processing — re-run with ` +
|
|
96
|
+
`\`agent-media status ${jobId}\` to check.`);
|
|
97
|
+
}
|
|
98
|
+
throw new CLIError(`Lost connection to the API. Job ${jobId} may still be processing.`, {
|
|
99
|
+
code: 'POLL_ABORTED',
|
|
100
|
+
suggestion: `Re-run with: agent-media status ${jobId}`,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
if (mode === 'human') {
|
|
104
|
+
spinner.text = `${chalk.yellow('reconnecting')} elapsed ${formatElapsed(elapsed)} (attempt ${consecutiveFailures}/${POLL_MAX_CONSECUTIVE_FAILURES})`;
|
|
105
|
+
}
|
|
106
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
consecutiveFailures = 0;
|
|
69
110
|
const status = poll.status;
|
|
70
111
|
if (mode === 'human') {
|
|
71
112
|
// Show granular progress stage when available
|
|
@@ -175,7 +216,11 @@ export function registerUGCCommand(program) {
|
|
|
175
216
|
.option('--pip-animation <anim>', 'PIP overlay animation: slide-up (default), slide-left, slide-right, fade, scale')
|
|
176
217
|
.option('--pip-style <style>', 'PIP overlay frame style: none (default), rounded, shadow')
|
|
177
218
|
.option('-s, --sync', 'Wait for completion and print the output URL')
|
|
178
|
-
.action(async (scriptOrFile, cmdOpts) => {
|
|
219
|
+
.action(async (scriptOrFile, cmdOpts, command) => {
|
|
220
|
+
// Detect whether --style was passed explicitly vs falling through to the
|
|
221
|
+
// default 'hormozi'. Without this distinction we'd randomize subtitle
|
|
222
|
+
// style even when the user typed `--style hormozi` on the command line.
|
|
223
|
+
const styleWasExplicit = command.getOptionValueSource('style') === 'cli';
|
|
179
224
|
const globalOpts = program.opts();
|
|
180
225
|
const mode = detectOutputMode(globalOpts);
|
|
181
226
|
const profileName = resolveProfileName(globalOpts.profile);
|
|
@@ -352,8 +397,13 @@ export function registerUGCCommand(program) {
|
|
|
352
397
|
}
|
|
353
398
|
}
|
|
354
399
|
}
|
|
355
|
-
// ── Auto-select random style
|
|
356
|
-
|
|
400
|
+
// ── Auto-select random style only when --style was NOT passed ───
|
|
401
|
+
// Commander reports the source as 'cli' for explicit flags and
|
|
402
|
+
// 'default' when the value came from the .option(default) argument.
|
|
403
|
+
// Previously we compared the value to 'hormozi' which conflated the
|
|
404
|
+
// two — so users got randomized styles even when they explicitly
|
|
405
|
+
// asked for hormozi.
|
|
406
|
+
if (!styleWasExplicit) {
|
|
357
407
|
const ALL_STYLES = [
|
|
358
408
|
'hormozi', 'tiktok', 'minimal', 'clean', 'bold', 'impact', 'fire',
|
|
359
409
|
'pop', 'spotlight', 'aesthetic', 'pastel', 'glow', 'neon',
|
|
@@ -366,6 +416,9 @@ export function registerUGCCommand(program) {
|
|
|
366
416
|
console.log(chalk.dim(` Tip: pick a specific style with --style <name>`));
|
|
367
417
|
}
|
|
368
418
|
}
|
|
419
|
+
else if (mode === 'human') {
|
|
420
|
+
console.log(` Style: ${chalk.cyan(cmdOpts.style)}`);
|
|
421
|
+
}
|
|
369
422
|
if (cmdOpts.brollImages) {
|
|
370
423
|
const raw = cmdOpts.brollImages.split(',').map((u) => u.trim()).filter(Boolean);
|
|
371
424
|
if (raw.length === 0) {
|