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.
- package/.env.example +6 -0
- package/README.md +483 -61
- package/assets/fonts/TikTokSans-Bold.ttf +0 -0
- package/examples/grok-imagine-test.tsx +155 -0
- package/launch-videos/06-kawaii-fruits.tsx +93 -0
- package/launch-videos/07-ugc-weight-loss.tsx +132 -0
- package/launch-videos/08-talking-head-varg.tsx +107 -0
- package/launch-videos/09-girl.tsx +160 -0
- package/launch-videos/README.md +42 -0
- package/package.json +10 -4
- package/pipeline/cookbooks/round-video-character.md +1 -1
- package/skills/varg-video-generation/SKILL.md +224 -0
- package/skills/varg-video-generation/references/templates.md +380 -0
- package/skills/varg-video-generation/scripts/setup.ts +265 -0
- package/src/ai-sdk/cache.ts +1 -3
- package/src/ai-sdk/examples/google-image.ts +62 -0
- package/src/ai-sdk/index.ts +10 -0
- package/src/ai-sdk/middleware/wrap-image-model.ts +4 -21
- package/src/ai-sdk/middleware/wrap-music-model.ts +4 -16
- package/src/ai-sdk/middleware/wrap-video-model.ts +5 -17
- package/src/ai-sdk/providers/CONTRIBUTING.md +457 -0
- package/src/ai-sdk/providers/editly/backends/index.ts +8 -0
- package/src/ai-sdk/providers/editly/backends/local.ts +94 -0
- package/src/ai-sdk/providers/editly/backends/types.ts +74 -0
- package/src/ai-sdk/providers/editly/editly.test.ts +49 -1
- package/src/ai-sdk/providers/editly/index.ts +164 -80
- package/src/ai-sdk/providers/editly/layers.ts +58 -6
- package/src/ai-sdk/providers/editly/rendi/editly-with-rendi-backend.test.ts +335 -0
- package/src/ai-sdk/providers/editly/rendi/index.ts +289 -0
- package/src/ai-sdk/providers/editly/rendi/rendi.test.ts +35 -0
- package/src/ai-sdk/providers/editly/types.ts +30 -0
- package/src/ai-sdk/providers/elevenlabs.ts +10 -2
- package/src/ai-sdk/providers/fal.test.ts +214 -0
- package/src/ai-sdk/providers/fal.ts +435 -40
- package/src/ai-sdk/providers/google.ts +423 -0
- package/src/ai-sdk/providers/together.ts +191 -0
- package/src/cli/commands/find.tsx +1 -0
- package/src/cli/commands/frame.tsx +616 -0
- package/src/cli/commands/hello.ts +85 -0
- package/src/cli/commands/help.tsx +18 -30
- package/src/cli/commands/index.ts +11 -2
- package/src/cli/commands/init.tsx +570 -0
- package/src/cli/commands/list.tsx +1 -0
- package/src/cli/commands/render.tsx +322 -76
- package/src/cli/commands/run.tsx +1 -0
- package/src/cli/commands/storyboard.tsx +1714 -0
- package/src/cli/commands/which.tsx +1 -0
- package/src/cli/index.ts +23 -4
- package/src/cli/ui/components/Badge.tsx +1 -0
- package/src/cli/ui/components/DataTable.tsx +1 -0
- package/src/cli/ui/components/Header.tsx +1 -0
- package/src/cli/ui/components/HelpBlock.tsx +1 -0
- package/src/cli/ui/components/KeyValue.tsx +1 -0
- package/src/cli/ui/components/OptionRow.tsx +1 -0
- package/src/cli/ui/components/Separator.tsx +1 -0
- package/src/cli/ui/components/StatusBox.tsx +1 -0
- package/src/cli/ui/components/VargBox.tsx +1 -0
- package/src/cli/ui/components/VargProgress.tsx +1 -0
- package/src/cli/ui/components/VargSpinner.tsx +1 -0
- package/src/cli/ui/components/VargText.tsx +1 -0
- package/src/definitions/actions/grok-edit.ts +133 -0
- package/src/definitions/actions/index.ts +16 -0
- package/src/definitions/actions/qwen-angles.ts +218 -0
- package/src/index.ts +1 -0
- package/src/providers/fal.ts +196 -0
- package/src/react/assets.ts +9 -0
- package/src/react/elements.ts +0 -5
- package/src/react/examples/branching.tsx +6 -4
- package/src/react/examples/character-video.tsx +13 -10
- package/src/react/examples/local-files-test.tsx +19 -0
- package/src/react/examples/ltx2-test.tsx +25 -0
- package/src/react/examples/madi.tsx +13 -10
- package/src/react/examples/mcmeows.tsx +40 -0
- package/src/react/examples/music-defaults.tsx +24 -0
- package/src/react/examples/quickstart-test.tsx +101 -0
- package/src/react/examples/qwen-angles-test.tsx +72 -0
- package/src/react/index.ts +3 -3
- package/src/react/layouts/grid.tsx +1 -1
- package/src/react/layouts/index.ts +2 -1
- package/src/react/layouts/slot.tsx +85 -0
- package/src/react/layouts/split.tsx +18 -0
- package/src/react/react.test.ts +60 -11
- package/src/react/renderers/burn-captions.ts +95 -0
- package/src/react/renderers/cache.test.ts +182 -0
- package/src/react/renderers/captions.ts +25 -6
- package/src/react/renderers/clip.ts +56 -25
- package/src/react/renderers/context.ts +5 -2
- package/src/react/renderers/image.ts +5 -2
- package/src/react/renderers/index.ts +0 -1
- package/src/react/renderers/music.ts +8 -3
- package/src/react/renderers/packshot/blinking-button.ts +413 -0
- package/src/react/renderers/packshot.ts +170 -8
- package/src/react/renderers/progress.ts +4 -3
- package/src/react/renderers/render.ts +127 -71
- package/src/react/renderers/speech.ts +2 -2
- package/src/react/renderers/split.ts +34 -13
- package/src/react/renderers/utils.test.ts +80 -0
- package/src/react/renderers/utils.ts +37 -1
- package/src/react/renderers/video.ts +47 -9
- package/src/react/types.ts +70 -17
- package/src/studio/stages.ts +40 -39
- package/src/studio/step-renderer.ts +14 -24
- package/src/studio/ui/index.html +2 -2
- package/src/tests/all.test.ts +4 -4
- package/src/tests/index.ts +1 -1
- package/test-slot-grid.tsx +19 -0
- package/test-slot-userland.tsx +30 -0
- package/test-sync-v2.ts +30 -0
- package/test-sync-v2.tsx +29 -0
- package/tsconfig.json +1 -1
- package/video.tsx +7 -0
- package/src/ai-sdk/providers/editly/ffmpeg.ts +0 -60
- package/src/react/renderers/animate.ts +0 -59
- /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
|
+
});
|
package/src/ai-sdk/cache.ts
CHANGED
|
@@ -106,7 +106,7 @@ function flatten(value: unknown): unknown {
|
|
|
106
106
|
* });
|
|
107
107
|
* ```
|
|
108
108
|
*/
|
|
109
|
-
const DEFAULT_TTL = "
|
|
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();
|
package/src/ai-sdk/index.ts
CHANGED
|
@@ -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
|
|
18
|
+
const { mode } = options;
|
|
19
19
|
|
|
20
20
|
return {
|
|
21
21
|
specificationVersion: "v3",
|
|
22
22
|
wrapGenerate: async ({ doGenerate, params, model }) => {
|
|
23
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
56
|
+
const { mode } = options;
|
|
57
57
|
|
|
58
58
|
return {
|
|
59
59
|
wrapGenerate: async ({ doGenerate, params, model }) => {
|
|
60
|
-
|
|
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:
|
|
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
|
-
|
|
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" | "
|
|
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
|
|
58
|
+
const { mode } = options;
|
|
59
59
|
|
|
60
60
|
return {
|
|
61
61
|
wrapGenerate: async ({ doGenerate, params, model }) => {
|
|
62
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
}
|