veogent 1.5.0 → 1.5.2

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 CHANGED
@@ -187,13 +187,15 @@ veogent request --type GENERATE_VIDEO \
187
187
 
188
188
  | Command | Description |
189
189
  |---------|-------------|
190
- | `request` | Create a single generation job (`GENERATE_IMAGES` / `GENERATE_VIDEO`) |
190
+ | `request` | Create a single generation job (`GENERATE_IMAGES` / `GENERATE_VIDEO` / `VIDEO_UPSCALE`) |
191
191
  | `batch-request` | Batch generation for multiple/all scenes (`--all`) |
192
192
  | `requests` | List existing generation jobs |
193
+ | `request-status` | Check a specific job by request ID (includes asset URL) |
193
194
  | `failed-requests` | List failed requests for a chapter |
194
195
  | `wait-images` | Poll until all image jobs finish |
195
196
  | `wait-videos` | Poll until all video jobs finish |
196
197
  | `queue-status` | Current queue/concurrency status |
198
+ | `download-upscale` | Download 4K upscaled video as `.mp4` (decodes base64 from flow-media) |
197
199
 
198
200
  ### Monitoring
199
201
 
@@ -201,6 +203,7 @@ veogent request --type GENERATE_VIDEO \
201
203
  |---------|-------------|
202
204
  | `scene-status` | Scene-level image+video status with asset URLs |
203
205
  | `workflow-status` | Full snapshot: scenes + requests + assets (best for agents) |
206
+ | `request-status` | Check a specific job by request ID |
204
207
 
205
208
  ### YouTube
206
209
 
@@ -245,6 +248,27 @@ Uses sceneA's image as start frame, sceneB's image as end frame. Both scenes mus
245
248
 
246
249
  ---
247
250
 
251
+ ## Video Upscale (4K)
252
+
253
+ ```bash
254
+ # 1. Trigger upscale
255
+ veogent request --type VIDEO_UPSCALE \
256
+ --project X --chapter Y --scene Z \
257
+ --orientation VERTICAL --resolution VIDEO_RESOLUTION_4K
258
+
259
+ # 2. Poll status by request ID
260
+ veogent request-status --id <requestId>
261
+
262
+ # 3. Download the upscaled video
263
+ veogent download-upscale \
264
+ --project X --chapter Y --scene Z \
265
+ --orientation VERTICAL --out ./scene_4k.mp4
266
+ ```
267
+
268
+ > `download-upscale` calls `/app/scene/flow-media`, decodes the base64 `encodedVideo`, and writes a `.mp4` file.
269
+
270
+ ---
271
+
248
272
  ## Concurrency
249
273
 
250
274
  Maximum **5** concurrent requests. If queue is full (E10071), CLI auto-retries once after 30s.
package/index.js CHANGED
@@ -747,8 +747,8 @@ program
747
747
  // --- Execution Request (Generate Image / Video) ---
748
748
  program
749
749
  .command('request')
750
- .description('Create a job request (GENERATE_IMAGES, GENERATE_VIDEO)')
751
- .requiredOption('--type <type>', 'Request type (e.g., GENERATE_IMAGES, GENERATE_VIDEO)')
750
+ .description('Create a job request (GENERATE_IMAGES, GENERATE_VIDEO, VIDEO_UPSCALE). Use VIDEO_UPSCALE to upscale a rendered video to 4K resolution.')
751
+ .requiredOption('--type <type>', 'Request type (e.g., GENERATE_IMAGES, GENERATE_VIDEO, VIDEO_UPSCALE)')
752
752
  .requiredOption('--project <project>', 'Project ID')
753
753
  .requiredOption('--chapter <chapter>', 'Chapter ID')
754
754
  .requiredOption('--scene <scene>', 'Scene ID')
@@ -757,6 +757,7 @@ program
757
757
  .option('--videomodel <videomodel>', 'Video Model (veo_3_1_fast, veo_3_1_fast_r2v). Default: veo_3_1_fast', 'veo_3_1_fast')
758
758
  .option('--speed <speed>', 'Video Speed (normal, timelapse, slowmotion)', 'normal')
759
759
  .option('--endscene <endscene>', 'End Scene ID for continuous video generation')
760
+ .option('--resolution <resolution>', 'Resolution for VIDEO_UPSCALE (e.g. VIDEO_RESOLUTION_4K)', 'VIDEO_RESOLUTION_4K')
760
761
  .option('--wait', 'Wait for request to complete before returning')
761
762
  .action(async (options) => {
762
763
  try {
@@ -805,7 +806,8 @@ program
805
806
  payload.imageModel = options.imagemodel;
806
807
  }
807
808
  if (['VIDEO_UPSCALE'].includes(options.type)) {
808
- payload.orientation = options.orientation || 'HORIZONTAL'; // Provide fallback
809
+ payload.orientation = options.orientation || 'VERTICAL'; // Upscale defaults to VERTICAL
810
+ payload.resolution = options.resolution || 'VIDEO_RESOLUTION_4K';
809
811
  }
810
812
 
811
813
  const data = await api.post('/app/request', payload);
@@ -1055,6 +1057,77 @@ program
1055
1057
  }
1056
1058
  });
1057
1059
 
1060
+ program
1061
+ .command('request-status')
1062
+ .description('Get status of a specific request by ID. For GENERATE_VIDEO/GENERATE_IMAGES, falls back to assets endpoint for output URL. VIDEO_UPSCALE output URL is read directly from the request object.')
1063
+ .requiredOption('--id <requestId>', 'Request ID to check')
1064
+ .action(async (options) => {
1065
+ try {
1066
+ const data = await api.get(`/app/standalone/request/${options.id}`);
1067
+ const found = unwrapData(data);
1068
+
1069
+ if (!found) {
1070
+ emitJson({ status: 'error', code: 'REQUEST_NOT_FOUND', message: `No request found with ID: ${options.id}` });
1071
+ return;
1072
+ }
1073
+
1074
+ const requestStatus = String(found?.status || '').toUpperCase();
1075
+ const type = found?.type || null;
1076
+ const projectId = found?.projectId || found?.project_id || null;
1077
+ const chapterId = found?.chapterId || found?.chapter_id || null;
1078
+ const sceneId = found?.sceneId || found?.scene_id || null;
1079
+
1080
+ let imageAsset = { url: found?.imageVerticalUri || found?.imageHorizontalUri || found?.imageUrl || null };
1081
+ // VIDEO_UPSCALE: output URL lives directly on the request object (not in assets endpoint)
1082
+ let videoAsset = { url: found?.videoVerticalUri || found?.videoHorizontalUri || found?.videoUrl || found?.outputUrl || null };
1083
+
1084
+ // For GENERATE_VIDEO only: fallback to assets endpoint if URL not on request object
1085
+ if (type === 'GENERATE_VIDEO' && projectId && chapterId && sceneId && !videoAsset.url) {
1086
+ try {
1087
+ const assetData = unwrapData(await api.get(`/app/request/assets/${projectId}/${chapterId}/${sceneId}?type=GENERATE_VIDEO`));
1088
+ const assetItems = Array.isArray(assetData) ? assetData : (assetData?.items || []);
1089
+ const matched = assetItems.find((a) => a?.id === options.id || a?.requestId === options.id)
1090
+ || assetItems.find((a) => String(a?.status || '').toUpperCase() === 'COMPLETED');
1091
+ if (matched) {
1092
+ videoAsset = { url: matched?.videoVerticalUri || matched?.videoHorizontalUri || matched?.videoUrl || matched?.outputUrl || null };
1093
+ }
1094
+ } catch { /* asset fetch optional */ }
1095
+ }
1096
+
1097
+ // For image type: fetch asset URL if not present
1098
+ if (type === 'GENERATE_IMAGES' && projectId && chapterId && sceneId && !imageAsset.url) {
1099
+ try {
1100
+ const assetData = unwrapData(await api.get(`/app/request/assets/${projectId}/${chapterId}/${sceneId}?type=GENERATE_IMAGES`));
1101
+ const assetItems = Array.isArray(assetData) ? assetData : (assetData?.items || []);
1102
+ const matched = assetItems.find((a) => a?.id === options.id || a?.requestId === options.id)
1103
+ || assetItems.find((a) => String(a?.status || '').toUpperCase() === 'COMPLETED');
1104
+ if (matched) {
1105
+ imageAsset = { url: matched?.imageVerticalUri || matched?.imageHorizontalUri || matched?.imageUrl || matched?.outputUrl || null };
1106
+ }
1107
+ } catch { /* asset fetch optional */ }
1108
+ }
1109
+
1110
+ const result = {
1111
+ status: 'success',
1112
+ requestId: found?.id || found?.requestId,
1113
+ type,
1114
+ requestStatus,
1115
+ sceneId,
1116
+ chapterId,
1117
+ projectId,
1118
+ image: imageAsset,
1119
+ video: videoAsset,
1120
+ createdAt: found?.createdAt || found?.created_at || null,
1121
+ completedAt: found?.completedAt || found?.updatedAt || null,
1122
+ raw: found,
1123
+ };
1124
+
1125
+ emitJson(result);
1126
+ } catch (error) {
1127
+ emitJson({ status: 'error', ...formatCliError(error) });
1128
+ }
1129
+ });
1130
+
1058
1131
  program
1059
1132
  .command('queue-status')
1060
1133
  .description('Get current queue/concurrency status for authenticated user')
@@ -1067,6 +1140,41 @@ program
1067
1140
  }
1068
1141
  });
1069
1142
 
1143
+ program
1144
+ .command('download-upscale')
1145
+ .description('Download the 4K upscaled video for a scene. Calls /app/scene/flow-media to retrieve the base64-encoded video and saves it as an .mp4 file.')
1146
+ .requiredOption('--project <project>', 'Project ID')
1147
+ .requiredOption('--chapter <chapter>', 'Chapter ID')
1148
+ .requiredOption('--scene <scene>', 'Scene ID')
1149
+ .option('--orientation <orientation>', 'Orientation to download (VERTICAL, HORIZONTAL)', 'VERTICAL')
1150
+ .option('--out <path>', 'Output file path (default: ./<sceneId>_upscale.mp4)')
1151
+ .action(async (options) => {
1152
+ try {
1153
+ const orientation = options.orientation.toUpperCase();
1154
+ humanLog(`⏳ Fetching upscaled video from flow-media...`);
1155
+
1156
+ const data = await api.get(`/app/scene/flow-media/${options.project}/${options.chapter}/${options.scene}/${orientation}`);
1157
+ const raw = unwrapData(data);
1158
+
1159
+ // Backend returns { video: { encodedVideo, ... } } or flat { encodedVideo }
1160
+ const encodedVideo = raw?.video?.encodedVideo || raw?.encodedVideo || null;
1161
+
1162
+ if (!encodedVideo) {
1163
+ emitJson({ status: 'error', code: 'NO_VIDEO_DATA', message: 'No encodedVideo in response. The upscale may not be ready yet.', raw });
1164
+ return;
1165
+ }
1166
+
1167
+ const outPath = options.out || `./${options.scene}_upscale.mp4`;
1168
+ const { writeFileSync } = await import('fs');
1169
+ writeFileSync(outPath, Buffer.from(encodedVideo, 'base64'));
1170
+
1171
+ humanLog(`✅ Saved upscaled video to: ${outPath}`);
1172
+ emitJson({ status: 'success', file: outPath, sceneId: options.scene, orientation });
1173
+ } catch (error) {
1174
+ emitJson({ status: 'error', ...formatCliError(error) });
1175
+ }
1176
+ });
1177
+
1070
1178
  program
1071
1179
  .command('failed-requests')
1072
1180
  .description('List failed requests for a project/chapter (agent helper)')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veogent",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "description": "The official CLI to interact with the VEOGENT API - AI Video and Image generation platform",
5
5
  "main": "index.js",
6
6
  "bin": {
package/skills/SKILL.md CHANGED
@@ -196,6 +196,25 @@ veogent request --type GENERATE_VIDEO --project X --chapter Y --scene sceneA \
196
196
  ```
197
197
  Uses sceneA image → sceneB image as start/end frames. Both must have successful images. Only `veo_3_1_fast`.
198
198
 
199
+ ### Video Upscale (4K)
200
+
201
+ ```bash
202
+ # 1. Trigger upscale
203
+ veogent request --type VIDEO_UPSCALE \
204
+ --project X --chapter Y --scene Z \
205
+ --orientation VERTICAL --resolution VIDEO_RESOLUTION_4K
206
+
207
+ # 2. Poll until COMPLETED
208
+ veogent request-status --id <requestId>
209
+
210
+ # 3. Download the upscaled .mp4 (reads from flow-media, decodes base64)
211
+ veogent download-upscale \
212
+ --project X --chapter Y --scene Z \
213
+ --orientation VERTICAL --out ./scene_4k.mp4
214
+ ```
215
+
216
+ > `download-upscale` calls `GET /app/scene/flow-media/{project}/{chapter}/{scene}/{orientation}`, decodes the base64 `encodedVideo` response, and saves it as an `.mp4` file.
217
+
199
218
  ---
200
219
 
201
220
  ## Monitoring & Status
@@ -205,6 +224,7 @@ Uses sceneA image → sceneB image as start/end frames. Both must have successfu
205
224
  | `workflow-status --project X --chapter Y` | Full snapshot: scenes + requests + assets (best for agents) |
206
225
  | `scene-status --project X --chapter Y` | Quick image/video status per scene |
207
226
  | `requests --project X --limit 10` | Check recent generation jobs |
227
+ | `request-status --id <requestId>` | Check a specific job by request ID (with asset URL) |
208
228
  | `failed-requests --project X --chapter Y` | Debug why gen failed |
209
229
  | `wait-images --project X --chapter Y --require-success` | Block until all images done |
210
230
  | `wait-videos --project X --chapter Y --require-success` | Block until all videos done |
@@ -359,8 +379,9 @@ veogent request --type GENERATE_VIDEO --project X --chapter Y --scene Z \
359
379
 
360
380
  | Command | Description | Key Options |
361
381
  |---------|-------------|-------------|
362
- | `request` | Single generation job | `--type`, `--project`, `--chapter`, `--scene`, `--orientation`, `--speed`, `--endscene`, `--wait` |
382
+ | `request` | Single generation job | `--type` (GENERATE_IMAGES, GENERATE_VIDEO, VIDEO_UPSCALE), `--project`, `--chapter`, `--scene`, `--orientation`, `--speed`, `--endscene`, `--resolution` (upscale), `--wait` |
363
383
  | `batch-request` | Batch generation | `--type`, `--project`, `--chapter`, `--all`/`--scenes`, `--orientation`, `--speed`, `--wait` |
384
+ | `download-upscale` | Download 4K upscaled video as .mp4 | `--project`, `--chapter`, `--scene`, `--orientation`, `--out` |
364
385
 
365
386
  ### Monitoring Commands
366
387
 
@@ -369,6 +390,7 @@ veogent request --type GENERATE_VIDEO --project X --chapter Y --scene Z \
369
390
  | `workflow-status` | Full snapshot (best for agents) | `--project`, `--chapter` |
370
391
  | `scene-status` | Per-scene image/video status | `--project`, `--chapter` |
371
392
  | `requests` | List generation jobs | `--project`, `--chapter`, `--status`, `--limit` |
393
+ | `request-status` | Check a specific job by ID (with asset URL) | `--id` |
372
394
  | `failed-requests` | Failed jobs only | `--project`, `--chapter` |
373
395
  | `wait-images` | Poll until images done | `--project`, `--chapter`, `--require-success` |
374
396
  | `wait-videos` | Poll until videos done | `--project`, `--chapter`, `--require-success` |