vargai 0.4.0-alpha4 → 0.4.0-alpha40

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.
Files changed (114) hide show
  1. package/.env.example +6 -0
  2. package/README.md +483 -61
  3. package/assets/fonts/TikTokSans-Bold.ttf +0 -0
  4. package/examples/grok-imagine-test.tsx +155 -0
  5. package/launch-videos/06-kawaii-fruits.tsx +93 -0
  6. package/launch-videos/07-ugc-weight-loss.tsx +132 -0
  7. package/launch-videos/08-talking-head-varg.tsx +107 -0
  8. package/launch-videos/09-girl.tsx +160 -0
  9. package/launch-videos/README.md +42 -0
  10. package/package.json +10 -4
  11. package/pipeline/cookbooks/round-video-character.md +1 -1
  12. package/skills/varg-video-generation/SKILL.md +224 -0
  13. package/skills/varg-video-generation/references/templates.md +380 -0
  14. package/skills/varg-video-generation/scripts/setup.ts +265 -0
  15. package/src/ai-sdk/cache.ts +1 -3
  16. package/src/ai-sdk/examples/google-image.ts +62 -0
  17. package/src/ai-sdk/index.ts +10 -0
  18. package/src/ai-sdk/middleware/wrap-image-model.ts +4 -21
  19. package/src/ai-sdk/middleware/wrap-music-model.ts +4 -16
  20. package/src/ai-sdk/middleware/wrap-video-model.ts +5 -17
  21. package/src/ai-sdk/providers/CONTRIBUTING.md +457 -0
  22. package/src/ai-sdk/providers/editly/backends/index.ts +8 -0
  23. package/src/ai-sdk/providers/editly/backends/local.ts +94 -0
  24. package/src/ai-sdk/providers/editly/backends/types.ts +74 -0
  25. package/src/ai-sdk/providers/editly/editly.test.ts +49 -1
  26. package/src/ai-sdk/providers/editly/index.ts +164 -80
  27. package/src/ai-sdk/providers/editly/layers.ts +58 -6
  28. package/src/ai-sdk/providers/editly/rendi/editly-with-rendi-backend.test.ts +335 -0
  29. package/src/ai-sdk/providers/editly/rendi/index.ts +289 -0
  30. package/src/ai-sdk/providers/editly/rendi/rendi.test.ts +35 -0
  31. package/src/ai-sdk/providers/editly/types.ts +30 -0
  32. package/src/ai-sdk/providers/elevenlabs.ts +10 -2
  33. package/src/ai-sdk/providers/fal.test.ts +214 -0
  34. package/src/ai-sdk/providers/fal.ts +435 -40
  35. package/src/ai-sdk/providers/google.ts +423 -0
  36. package/src/ai-sdk/providers/together.ts +191 -0
  37. package/src/cli/commands/find.tsx +1 -0
  38. package/src/cli/commands/frame.tsx +616 -0
  39. package/src/cli/commands/hello.ts +85 -0
  40. package/src/cli/commands/help.tsx +18 -30
  41. package/src/cli/commands/index.ts +11 -2
  42. package/src/cli/commands/init.tsx +570 -0
  43. package/src/cli/commands/list.tsx +1 -0
  44. package/src/cli/commands/render.tsx +322 -76
  45. package/src/cli/commands/run.tsx +1 -0
  46. package/src/cli/commands/storyboard.tsx +1714 -0
  47. package/src/cli/commands/which.tsx +1 -0
  48. package/src/cli/index.ts +23 -4
  49. package/src/cli/ui/components/Badge.tsx +1 -0
  50. package/src/cli/ui/components/DataTable.tsx +1 -0
  51. package/src/cli/ui/components/Header.tsx +1 -0
  52. package/src/cli/ui/components/HelpBlock.tsx +1 -0
  53. package/src/cli/ui/components/KeyValue.tsx +1 -0
  54. package/src/cli/ui/components/OptionRow.tsx +1 -0
  55. package/src/cli/ui/components/Separator.tsx +1 -0
  56. package/src/cli/ui/components/StatusBox.tsx +1 -0
  57. package/src/cli/ui/components/VargBox.tsx +1 -0
  58. package/src/cli/ui/components/VargProgress.tsx +1 -0
  59. package/src/cli/ui/components/VargSpinner.tsx +1 -0
  60. package/src/cli/ui/components/VargText.tsx +1 -0
  61. package/src/definitions/actions/grok-edit.ts +133 -0
  62. package/src/definitions/actions/index.ts +16 -0
  63. package/src/definitions/actions/qwen-angles.ts +218 -0
  64. package/src/index.ts +1 -0
  65. package/src/providers/fal.ts +196 -0
  66. package/src/react/assets.ts +9 -0
  67. package/src/react/elements.ts +0 -5
  68. package/src/react/examples/branching.tsx +6 -4
  69. package/src/react/examples/character-video.tsx +13 -10
  70. package/src/react/examples/local-files-test.tsx +19 -0
  71. package/src/react/examples/ltx2-test.tsx +25 -0
  72. package/src/react/examples/madi.tsx +13 -10
  73. package/src/react/examples/mcmeows.tsx +40 -0
  74. package/src/react/examples/music-defaults.tsx +24 -0
  75. package/src/react/examples/quickstart-test.tsx +101 -0
  76. package/src/react/examples/qwen-angles-test.tsx +72 -0
  77. package/src/react/index.ts +3 -3
  78. package/src/react/layouts/grid.tsx +1 -1
  79. package/src/react/layouts/index.ts +2 -1
  80. package/src/react/layouts/slot.tsx +85 -0
  81. package/src/react/layouts/split.tsx +18 -0
  82. package/src/react/react.test.ts +60 -11
  83. package/src/react/renderers/burn-captions.ts +95 -0
  84. package/src/react/renderers/cache.test.ts +182 -0
  85. package/src/react/renderers/captions.ts +25 -6
  86. package/src/react/renderers/clip.ts +56 -25
  87. package/src/react/renderers/context.ts +5 -2
  88. package/src/react/renderers/image.ts +5 -2
  89. package/src/react/renderers/index.ts +0 -1
  90. package/src/react/renderers/music.ts +8 -3
  91. package/src/react/renderers/packshot/blinking-button.ts +413 -0
  92. package/src/react/renderers/packshot.ts +170 -8
  93. package/src/react/renderers/progress.ts +4 -3
  94. package/src/react/renderers/render.ts +127 -71
  95. package/src/react/renderers/speech.ts +2 -2
  96. package/src/react/renderers/split.ts +34 -13
  97. package/src/react/renderers/utils.test.ts +80 -0
  98. package/src/react/renderers/utils.ts +37 -1
  99. package/src/react/renderers/video.ts +47 -9
  100. package/src/react/types.ts +70 -17
  101. package/src/studio/stages.ts +40 -39
  102. package/src/studio/step-renderer.ts +14 -24
  103. package/src/studio/ui/index.html +2 -2
  104. package/src/tests/all.test.ts +4 -4
  105. package/src/tests/index.ts +1 -1
  106. package/test-slot-grid.tsx +19 -0
  107. package/test-slot-userland.tsx +30 -0
  108. package/test-sync-v2.ts +30 -0
  109. package/test-sync-v2.tsx +29 -0
  110. package/tsconfig.json +1 -1
  111. package/video.tsx +7 -0
  112. package/src/ai-sdk/providers/editly/ffmpeg.ts +0 -60
  113. package/src/react/renderers/animate.ts +0 -59
  114. /package/src/cli/commands/{studio.tsx → studio.ts} +0 -0
@@ -0,0 +1,265 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * varg-video-generation setup script
4
+ *
5
+ * This script initializes a project for AI video generation.
6
+ * Can be run standalone by agents or via bunx vargai.
7
+ *
8
+ * Usage:
9
+ * bun scripts/setup.ts
10
+ */
11
+
12
+ import {
13
+ existsSync,
14
+ mkdirSync,
15
+ readFileSync,
16
+ symlinkSync,
17
+ writeFileSync,
18
+ } from "node:fs";
19
+ import { dirname, join } from "node:path";
20
+
21
+ const COLORS = {
22
+ reset: "\x1b[0m",
23
+ bold: "\x1b[1m",
24
+ dim: "\x1b[2m",
25
+ green: "\x1b[32m",
26
+ yellow: "\x1b[33m",
27
+ blue: "\x1b[34m",
28
+ red: "\x1b[31m",
29
+ cyan: "\x1b[36m",
30
+ };
31
+
32
+ const log = {
33
+ info: (msg: string) =>
34
+ console.log(`${COLORS.blue}info${COLORS.reset} ${msg}`),
35
+ success: (msg: string) =>
36
+ console.log(`${COLORS.green}done${COLORS.reset} ${msg}`),
37
+ warn: (msg: string) =>
38
+ console.log(`${COLORS.yellow}warn${COLORS.reset} ${msg}`),
39
+ error: (msg: string) =>
40
+ console.log(`${COLORS.red}error${COLORS.reset} ${msg}`),
41
+ step: (msg: string) =>
42
+ console.log(
43
+ `\n${COLORS.bold}${COLORS.cyan}==>${COLORS.reset} ${COLORS.bold}${msg}${COLORS.reset}`,
44
+ ),
45
+ };
46
+
47
+ // .env template
48
+ const ENV_TEMPLATE = `# Varg AI Video Generation - API Keys
49
+ # Get your keys from the URLs below
50
+
51
+ # REQUIRED - Fal.ai (image & video generation)
52
+ # Get it: https://fal.ai/dashboard/keys
53
+ FAL_API_KEY=
54
+
55
+ # OPTIONAL - ElevenLabs (music & voice)
56
+ # Get it: https://elevenlabs.io/app/settings/api-keys
57
+ ELEVENLABS_API_KEY=
58
+
59
+ # OPTIONAL - Replicate (lipsync)
60
+ # Get it: https://replicate.com/account/api-tokens
61
+ REPLICATE_API_TOKEN=
62
+
63
+ # OPTIONAL - Groq (transcription)
64
+ # Get it: https://console.groq.com/keys
65
+ GROQ_API_KEY=
66
+ `;
67
+
68
+ // Example video file
69
+ const EXAMPLE_VIDEO = `/**
70
+ * Example: Simple animated video
71
+ * Run: bun run examples/my-first-video.tsx
72
+ */
73
+ import { render, Render, Clip, Image, Animate } from "vargai/react";
74
+ import { fal } from "vargai/ai";
75
+
76
+ async function main() {
77
+ console.log("Creating your first AI video...\\n");
78
+
79
+ await render(
80
+ <Render width={720} height={720}>
81
+ <Clip duration={3}>
82
+ <Animate
83
+ image={Image({
84
+ prompt: "a friendly robot waving hello, cartoon style, blue colors",
85
+ model: fal.imageModel("flux-schnell"),
86
+ aspectRatio: "1:1",
87
+ })}
88
+ motion="robot waves hello, friendly gesture"
89
+ model={fal.videoModel("wan-2.5")}
90
+ duration={3}
91
+ />
92
+ </Clip>
93
+ </Render>,
94
+ {
95
+ output: "output/my-first-video.mp4",
96
+ cache: ".cache/ai"
97
+ }
98
+ );
99
+
100
+ console.log("\\nDone! Check output/my-first-video.mp4");
101
+ }
102
+
103
+ main().catch(console.error);
104
+ `;
105
+
106
+ async function main() {
107
+ console.log(`
108
+ ${COLORS.bold}${COLORS.cyan}varg-video-generation${COLORS.reset} ${COLORS.dim}setup${COLORS.reset}
109
+ `);
110
+
111
+ const cwd = process.cwd();
112
+
113
+ // Step 1: Check/create directories
114
+ log.step("Setting up project structure");
115
+
116
+ const dirs = ["output", ".cache/ai", "examples"];
117
+ for (const dir of dirs) {
118
+ const path = join(cwd, dir);
119
+ if (!existsSync(path)) {
120
+ mkdirSync(path, { recursive: true });
121
+ log.success(`Created ${dir}/`);
122
+ } else {
123
+ log.info(`${dir}/ already exists`);
124
+ }
125
+ }
126
+
127
+ // Step 2: Check/create .env
128
+ log.step("Checking API keys");
129
+
130
+ const envPath = join(cwd, ".env");
131
+ let envContent = "";
132
+ let hasFalKey = false;
133
+
134
+ if (existsSync(envPath)) {
135
+ envContent = readFileSync(envPath, "utf8");
136
+ hasFalKey = /^FAL_API_KEY=.+/m.test(envContent);
137
+
138
+ if (hasFalKey) {
139
+ log.success("FAL_API_KEY found in .env");
140
+ } else {
141
+ log.warn("FAL_API_KEY not found in .env");
142
+ }
143
+
144
+ // Check optional keys
145
+ const hasElevenLabs = /^ELEVENLABS_API_KEY=.+/m.test(envContent);
146
+ const hasReplicate = /^REPLICATE_API_TOKEN=.+/m.test(envContent);
147
+ const hasGroq = /^GROQ_API_KEY=.+/m.test(envContent);
148
+
149
+ if (hasElevenLabs)
150
+ log.info("ELEVENLABS_API_KEY found (music/voice enabled)");
151
+ if (hasReplicate) log.info("REPLICATE_API_TOKEN found (lipsync enabled)");
152
+ if (hasGroq) log.info("GROQ_API_KEY found (transcription enabled)");
153
+
154
+ if (!hasElevenLabs && !hasReplicate && !hasGroq) {
155
+ log.info("No optional keys found (basic video generation only)");
156
+ }
157
+ } else {
158
+ log.warn(".env file not found");
159
+ }
160
+
161
+ // If no FAL key, prompt for it
162
+ if (!hasFalKey) {
163
+ console.log(`
164
+ ${COLORS.yellow}FAL_API_KEY is required for video generation.${COLORS.reset}
165
+
166
+ Get your free API key at: ${COLORS.cyan}https://fal.ai/dashboard/keys${COLORS.reset}
167
+ `);
168
+
169
+ process.stdout.write("Enter your FAL_API_KEY (or press Enter to skip): ");
170
+
171
+ const falKey = await new Promise<string>((resolve) => {
172
+ let input = "";
173
+ process.stdin.setEncoding("utf8");
174
+ process.stdin.once("data", (data) => {
175
+ input = data.toString().trim();
176
+ resolve(input);
177
+ });
178
+ });
179
+
180
+ if (falKey) {
181
+ if (existsSync(envPath)) {
182
+ const newEnvContent = envContent.includes("FAL_API_KEY")
183
+ ? envContent.replace(/^FAL_API_KEY=.*/m, `FAL_API_KEY=${falKey}`)
184
+ : `${envContent}\nFAL_API_KEY=${falKey}`;
185
+ writeFileSync(envPath, newEnvContent);
186
+ } else {
187
+ writeFileSync(
188
+ envPath,
189
+ ENV_TEMPLATE.replace("FAL_API_KEY=", `FAL_API_KEY=${falKey}`),
190
+ );
191
+ }
192
+ log.success("FAL_API_KEY saved to .env");
193
+ hasFalKey = true;
194
+ } else {
195
+ if (!existsSync(envPath)) {
196
+ writeFileSync(envPath, ENV_TEMPLATE);
197
+ log.info("Created .env template - add your keys manually");
198
+ }
199
+ }
200
+ }
201
+
202
+ // Step 3: Create example file
203
+ log.step("Creating example files");
204
+
205
+ const examplePath = join(cwd, "examples/my-first-video.tsx");
206
+ if (!existsSync(examplePath)) {
207
+ writeFileSync(examplePath, EXAMPLE_VIDEO);
208
+ log.success("Created examples/my-first-video.tsx");
209
+ } else {
210
+ log.info("examples/my-first-video.tsx already exists");
211
+ }
212
+
213
+ // Step 4: Add to .gitignore
214
+ log.step("Updating .gitignore");
215
+
216
+ const gitignorePath = join(cwd, ".gitignore");
217
+ const gitignoreEntries = [".env", ".cache/", "output/"];
218
+ let gitignoreContent = existsSync(gitignorePath)
219
+ ? readFileSync(gitignorePath, "utf8")
220
+ : "";
221
+
222
+ let added = false;
223
+ for (const entry of gitignoreEntries) {
224
+ if (!gitignoreContent.includes(entry)) {
225
+ gitignoreContent += `\n${entry}`;
226
+ added = true;
227
+ }
228
+ }
229
+
230
+ if (added) {
231
+ writeFileSync(gitignorePath, gitignoreContent.trim() + "\n");
232
+ log.success("Updated .gitignore");
233
+ } else {
234
+ log.info(".gitignore already configured");
235
+ }
236
+
237
+ // Summary
238
+ console.log(`
239
+ ${COLORS.green}${COLORS.bold}Setup complete!${COLORS.reset}
240
+
241
+ ${COLORS.bold}Next steps:${COLORS.reset}
242
+ `);
243
+
244
+ if (!hasFalKey) {
245
+ console.log(` ${COLORS.yellow}1. Add FAL_API_KEY to .env${COLORS.reset}
246
+ Get it at: https://fal.ai/dashboard/keys
247
+ `);
248
+ }
249
+
250
+ console.log(` ${hasFalKey ? "1" : "2"}. Install vargai package:
251
+ ${COLORS.cyan}bun add vargai${COLORS.reset}
252
+
253
+ ${hasFalKey ? "2" : "3"}. Run your first video:
254
+ ${COLORS.cyan}bun run examples/my-first-video.tsx${COLORS.reset}
255
+
256
+ ${COLORS.dim}Documentation: https://github.com/vargHQ/sdk${COLORS.reset}
257
+ `);
258
+
259
+ process.exit(0);
260
+ }
261
+
262
+ main().catch((error) => {
263
+ log.error(error.message);
264
+ process.exit(1);
265
+ });
@@ -106,7 +106,7 @@ function flatten(value: unknown): unknown {
106
106
  * });
107
107
  * ```
108
108
  */
109
- const DEFAULT_TTL = "1h";
109
+ const DEFAULT_TTL = "7d";
110
110
 
111
111
  export function withCache<T extends object, R>(
112
112
  fn: (options: T) => Promise<R>,
@@ -115,7 +115,6 @@ export function withCache<T extends object, R>(
115
115
  const storage = options.storage ?? defaultStorage;
116
116
  const ttl = parseTTL(options.ttl ?? DEFAULT_TTL);
117
117
  const prefix = fn.name || "anonymous";
118
-
119
118
  return async (opts: WithCacheKey<T>): Promise<R> => {
120
119
  const { cacheKey, ...rest } = opts;
121
120
 
@@ -128,7 +127,6 @@ export function withCache<T extends object, R>(
128
127
  if (cached !== undefined) {
129
128
  return cached as R;
130
129
  }
131
-
132
130
  const result = await fn(rest as T);
133
131
  const flattened = flatten(result);
134
132
  await storage.set(key, flattened, ttl);
@@ -0,0 +1,62 @@
1
+ import { generateImage } from "ai";
2
+ import { File, google } from "../index";
3
+
4
+ async function main() {
5
+ console.log("testing google image generation via varg provider...\n");
6
+
7
+ console.log("1. text-to-image with nano-banana-pro...");
8
+ try {
9
+ const { images, warnings } = await generateImage({
10
+ model: google.imageModel("nano-banana-pro"),
11
+ prompt: "a beautiful mountain landscape with snow peaks and a calm lake",
12
+ });
13
+
14
+ console.log(` generated ${images.length} image(s)`);
15
+ if (warnings.length > 0) {
16
+ console.log(
17
+ ` warnings: ${warnings.map((w) => ("details" in w ? w.details : w.type)).join(", ")}`,
18
+ );
19
+ }
20
+ if (images[0]) {
21
+ console.log(` size: ${images[0].uint8Array.byteLength} bytes`);
22
+ await Bun.write("output/google-mountain.png", images[0].uint8Array);
23
+ console.log(" saved to output/google-mountain.png");
24
+ }
25
+ } catch (error: any) {
26
+ console.error(" error:", error.message || error);
27
+ }
28
+
29
+ console.log("\n2. image-to-image with nano-banana-pro/edit...");
30
+ try {
31
+ const sourceFile = File.fromPath("output/google-mountain.png");
32
+
33
+ const { images, warnings } = await generateImage({
34
+ model: google.imageModel("nano-banana-pro/edit"),
35
+ prompt: {
36
+ text: "transform into a sunset scene with warm orange and pink sky",
37
+ images: [await sourceFile.data()],
38
+ },
39
+ });
40
+
41
+ console.log(` generated ${images.length} image(s)`);
42
+ if (warnings.length > 0) {
43
+ console.log(
44
+ ` warnings: ${warnings.map((w) => ("details" in w ? w.details : w.type)).join(", ")}`,
45
+ );
46
+ }
47
+ if (images[0]) {
48
+ console.log(` size: ${images[0].uint8Array.byteLength} bytes`);
49
+ await Bun.write(
50
+ "output/google-mountain-sunset.png",
51
+ images[0].uint8Array,
52
+ );
53
+ console.log(" saved to output/google-mountain-sunset.png");
54
+ }
55
+ } catch (error: any) {
56
+ console.error(" error:", error.message || error);
57
+ }
58
+
59
+ console.log("\ndone!");
60
+ }
61
+
62
+ main();
@@ -63,6 +63,12 @@ export {
63
63
  VOICES,
64
64
  } from "./providers/elevenlabs";
65
65
  export { createFal, type FalProvider, fal } from "./providers/fal";
66
+ export {
67
+ createGoogle,
68
+ type GoogleProvider,
69
+ type GoogleProviderSettings,
70
+ google,
71
+ } from "./providers/google";
66
72
  export {
67
73
  createHiggsfield,
68
74
  type HiggsfieldImageModelSettings,
@@ -82,6 +88,10 @@ export {
82
88
  type ReplicateProviderSettings,
83
89
  replicate,
84
90
  } from "./providers/replicate";
91
+ export {
92
+ createTogetherProvider,
93
+ together,
94
+ } from "./providers/together";
85
95
  export type {
86
96
  VideoModelV3,
87
97
  VideoModelV3CallOptions,
@@ -15,12 +15,12 @@ export interface ImagePlaceholderFallbackOptions {
15
15
  export function imagePlaceholderFallbackMiddleware(
16
16
  options: ImagePlaceholderFallbackOptions,
17
17
  ): ImageModelV3Middleware {
18
- const { mode, onFallback } = options;
18
+ const { mode } = options;
19
19
 
20
20
  return {
21
21
  specificationVersion: "v3",
22
22
  wrapGenerate: async ({ doGenerate, params, model }) => {
23
- const createPlaceholderResult = async () => {
23
+ if (mode === "preview") {
24
24
  const [width, height] = (params.size?.split("x").map(Number) ?? [
25
25
  1024, 1024,
26
26
  ]) as [number, number];
@@ -42,7 +42,7 @@ export function imagePlaceholderFallbackMiddleware(
42
42
  warnings: [
43
43
  {
44
44
  type: "other" as const,
45
- message: "placeholder: provider skipped or failed",
45
+ message: "placeholder: preview mode",
46
46
  },
47
47
  ],
48
48
  response: {
@@ -51,26 +51,9 @@ export function imagePlaceholderFallbackMiddleware(
51
51
  headers: undefined,
52
52
  },
53
53
  };
54
- };
55
-
56
- if (mode === "preview") {
57
- return createPlaceholderResult();
58
54
  }
59
55
 
60
- try {
61
- return await doGenerate();
62
- } catch (e) {
63
- if (mode === "strict") throw e;
64
-
65
- const error = e instanceof Error ? e : new Error(String(e));
66
- const promptText =
67
- typeof params.prompt === "string"
68
- ? params.prompt
69
- : ((params.prompt as { text?: string } | undefined)?.text ??
70
- "placeholder");
71
- onFallback?.(error, promptText);
72
- return createPlaceholderResult();
73
- }
56
+ return doGenerate();
74
57
  },
75
58
  };
76
59
  }
@@ -53,11 +53,11 @@ export interface MusicPlaceholderFallbackOptions {
53
53
  export function musicPlaceholderFallbackMiddleware(
54
54
  options: MusicPlaceholderFallbackOptions,
55
55
  ): MusicModelMiddleware {
56
- const { mode, onFallback } = options;
56
+ const { mode } = options;
57
57
 
58
58
  return {
59
59
  wrapGenerate: async ({ doGenerate, params, model }) => {
60
- const createPlaceholderResult = async () => {
60
+ if (mode === "preview") {
61
61
  const placeholder = await generatePlaceholder({
62
62
  type: "audio",
63
63
  prompt: params.prompt,
@@ -69,7 +69,7 @@ export function musicPlaceholderFallbackMiddleware(
69
69
  warnings: [
70
70
  {
71
71
  type: "other" as const,
72
- message: "placeholder: provider skipped or failed",
72
+ message: "placeholder: preview mode",
73
73
  },
74
74
  ],
75
75
  response: {
@@ -78,21 +78,9 @@ export function musicPlaceholderFallbackMiddleware(
78
78
  headers: undefined,
79
79
  },
80
80
  };
81
- };
82
-
83
- if (mode === "preview") {
84
- return createPlaceholderResult();
85
81
  }
86
82
 
87
- try {
88
- return await doGenerate();
89
- } catch (e) {
90
- if (mode === "strict") throw e;
91
-
92
- const error = e instanceof Error ? e : new Error(String(e));
93
- onFallback?.(error, params.prompt);
94
- return createPlaceholderResult();
95
- }
83
+ return doGenerate();
96
84
  },
97
85
  };
98
86
  }
@@ -1,7 +1,7 @@
1
1
  import type { VideoModelV3, VideoModelV3CallOptions } from "../video-model";
2
2
  import { generatePlaceholder } from "./placeholder";
3
3
 
4
- export type RenderMode = "strict" | "default" | "preview";
4
+ export type RenderMode = "strict" | "preview";
5
5
 
6
6
  export interface VideoModelMiddleware {
7
7
  transformParams?: (options: {
@@ -55,11 +55,11 @@ export interface PlaceholderFallbackOptions {
55
55
  export function placeholderFallbackMiddleware(
56
56
  options: PlaceholderFallbackOptions,
57
57
  ): VideoModelMiddleware {
58
- const { mode, onFallback } = options;
58
+ const { mode } = options;
59
59
 
60
60
  return {
61
61
  wrapGenerate: async ({ doGenerate, params, model }) => {
62
- const createPlaceholderResult = async () => {
62
+ if (mode === "preview") {
63
63
  const [width, height] = (params.resolution?.split("x").map(Number) ?? [
64
64
  1080, 1920,
65
65
  ]) as [number, number];
@@ -76,7 +76,7 @@ export function placeholderFallbackMiddleware(
76
76
  warnings: [
77
77
  {
78
78
  type: "other" as const,
79
- message: "placeholder: provider skipped or failed",
79
+ message: "placeholder: preview mode",
80
80
  },
81
81
  ],
82
82
  response: {
@@ -85,21 +85,9 @@ export function placeholderFallbackMiddleware(
85
85
  headers: undefined,
86
86
  },
87
87
  };
88
- };
89
-
90
- if (mode === "preview") {
91
- return createPlaceholderResult();
92
88
  }
93
89
 
94
- try {
95
- return await doGenerate();
96
- } catch (e) {
97
- if (mode === "strict") throw e;
98
-
99
- const error = e instanceof Error ? e : new Error(String(e));
100
- onFallback?.(error, params.prompt);
101
- return createPlaceholderResult();
102
- }
90
+ return doGenerate();
103
91
  },
104
92
  };
105
93
  }