vargai 0.4.0-alpha48 → 0.4.0-alpha49
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.
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grok Imagine Video - AI SDK Provider Test
|
|
3
|
+
*
|
|
4
|
+
* Run with: bun run examples/grok-imagine-ai-sdk.tsx
|
|
5
|
+
*
|
|
6
|
+
* Tests the Grok Imagine Video model via the AI-SDK interface
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { writeFile } from "node:fs/promises";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { fal } from "../src/ai-sdk/providers/fal";
|
|
12
|
+
|
|
13
|
+
async function testGrokTextToVideo() {
|
|
14
|
+
console.log("\n=== Grok Text-to-Video (AI-SDK) ===\n");
|
|
15
|
+
|
|
16
|
+
const model = fal.videoModel("grok-imagine");
|
|
17
|
+
|
|
18
|
+
const result = await model.doGenerate({
|
|
19
|
+
prompt:
|
|
20
|
+
"A futuristic city at night with neon lights reflecting on wet streets, flying cars passing by, cyberpunk aesthetic",
|
|
21
|
+
n: 1,
|
|
22
|
+
duration: 6,
|
|
23
|
+
aspectRatio: "16:9",
|
|
24
|
+
resolution: undefined,
|
|
25
|
+
fps: undefined,
|
|
26
|
+
seed: undefined,
|
|
27
|
+
files: undefined,
|
|
28
|
+
providerOptions: {
|
|
29
|
+
fal: {
|
|
30
|
+
resolution: "720p",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
console.log("Warnings:", result.warnings);
|
|
36
|
+
console.log("Response:", {
|
|
37
|
+
timestamp: result.response.timestamp,
|
|
38
|
+
modelId: result.response.modelId,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Save the video
|
|
42
|
+
const outputPath = join(import.meta.dir, "../output/grok-t2v-test.mp4");
|
|
43
|
+
await writeFile(outputPath, result.videos[0]!);
|
|
44
|
+
console.log(`Video saved to: ${outputPath}`);
|
|
45
|
+
|
|
46
|
+
return outputPath;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function testGrokImageToVideo() {
|
|
50
|
+
console.log("\n=== Grok Image-to-Video (AI-SDK) ===\n");
|
|
51
|
+
|
|
52
|
+
const model = fal.videoModel("grok-imagine");
|
|
53
|
+
|
|
54
|
+
// Fetch a sample image
|
|
55
|
+
const imageUrl =
|
|
56
|
+
"https://v3b.fal.media/files/b/0a8b90e0/BFLE9VDlZqsryU-UA3BoD_image_004.png";
|
|
57
|
+
const imageResponse = await fetch(imageUrl);
|
|
58
|
+
const imageBuffer = new Uint8Array(await imageResponse.arrayBuffer());
|
|
59
|
+
|
|
60
|
+
const result = await model.doGenerate({
|
|
61
|
+
prompt:
|
|
62
|
+
"The knight slowly raises their sword, preparing for battle, dramatic lighting",
|
|
63
|
+
n: 1,
|
|
64
|
+
duration: 6,
|
|
65
|
+
aspectRatio: "16:9",
|
|
66
|
+
resolution: undefined,
|
|
67
|
+
fps: undefined,
|
|
68
|
+
seed: undefined,
|
|
69
|
+
files: [
|
|
70
|
+
{
|
|
71
|
+
type: "file",
|
|
72
|
+
data: imageBuffer,
|
|
73
|
+
mediaType: "image/png",
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
providerOptions: {
|
|
77
|
+
fal: {
|
|
78
|
+
resolution: "720p",
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
console.log("Warnings:", result.warnings);
|
|
84
|
+
console.log("Response:", {
|
|
85
|
+
timestamp: result.response.timestamp,
|
|
86
|
+
modelId: result.response.modelId,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Save the video
|
|
90
|
+
const outputPath = join(import.meta.dir, "../output/grok-i2v-test.mp4");
|
|
91
|
+
await writeFile(outputPath, result.videos[0]!);
|
|
92
|
+
console.log(`Video saved to: ${outputPath}`);
|
|
93
|
+
|
|
94
|
+
return outputPath;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function testGrokEditVideo() {
|
|
98
|
+
console.log("\n=== Grok Edit Video (AI-SDK) ===\n");
|
|
99
|
+
|
|
100
|
+
const model = fal.videoModel("grok-imagine-edit");
|
|
101
|
+
|
|
102
|
+
// Use a sample video
|
|
103
|
+
const videoUrl =
|
|
104
|
+
"https://v3b.fal.media/files/b/0a8b9112/V5Z_NIPE3ppMDWivNo6_q_video_019.mp4";
|
|
105
|
+
const videoResponse = await fetch(videoUrl);
|
|
106
|
+
const videoBuffer = new Uint8Array(await videoResponse.arrayBuffer());
|
|
107
|
+
|
|
108
|
+
const result = await model.doGenerate({
|
|
109
|
+
prompt:
|
|
110
|
+
"Transform the scene into a watercolor painting style with soft pastel colors",
|
|
111
|
+
n: 1,
|
|
112
|
+
duration: undefined,
|
|
113
|
+
aspectRatio: undefined,
|
|
114
|
+
resolution: undefined,
|
|
115
|
+
fps: undefined,
|
|
116
|
+
seed: undefined,
|
|
117
|
+
files: [
|
|
118
|
+
{
|
|
119
|
+
type: "file",
|
|
120
|
+
data: videoBuffer,
|
|
121
|
+
mediaType: "video/mp4",
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
providerOptions: {
|
|
125
|
+
fal: {
|
|
126
|
+
resolution: "720p",
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
console.log("Warnings:", result.warnings);
|
|
132
|
+
console.log("Response:", {
|
|
133
|
+
timestamp: result.response.timestamp,
|
|
134
|
+
modelId: result.response.modelId,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Save the video
|
|
138
|
+
const outputPath = join(import.meta.dir, "../output/grok-edit-test.mp4");
|
|
139
|
+
await writeFile(outputPath, result.videos[0]!);
|
|
140
|
+
console.log(`Video saved to: ${outputPath}`);
|
|
141
|
+
|
|
142
|
+
return outputPath;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Main execution
|
|
146
|
+
async function main() {
|
|
147
|
+
const args = process.argv.slice(2);
|
|
148
|
+
const mode = args[0] || "t2v";
|
|
149
|
+
|
|
150
|
+
console.log("Grok Imagine Video - AI SDK Test");
|
|
151
|
+
console.log("=================================");
|
|
152
|
+
console.log(`Mode: ${mode}`);
|
|
153
|
+
|
|
154
|
+
// Ensure output directory exists
|
|
155
|
+
const { mkdir } = await import("node:fs/promises");
|
|
156
|
+
await mkdir(join(import.meta.dir, "../output"), { recursive: true });
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
switch (mode) {
|
|
160
|
+
case "t2v":
|
|
161
|
+
await testGrokTextToVideo();
|
|
162
|
+
break;
|
|
163
|
+
|
|
164
|
+
case "i2v":
|
|
165
|
+
await testGrokImageToVideo();
|
|
166
|
+
break;
|
|
167
|
+
|
|
168
|
+
case "edit":
|
|
169
|
+
await testGrokEditVideo();
|
|
170
|
+
break;
|
|
171
|
+
|
|
172
|
+
case "all":
|
|
173
|
+
await testGrokTextToVideo();
|
|
174
|
+
await testGrokImageToVideo();
|
|
175
|
+
await testGrokEditVideo();
|
|
176
|
+
break;
|
|
177
|
+
|
|
178
|
+
default:
|
|
179
|
+
console.log(`
|
|
180
|
+
Usage: bun run examples/grok-imagine-ai-sdk.tsx [mode]
|
|
181
|
+
|
|
182
|
+
Modes:
|
|
183
|
+
t2v Text-to-Video generation
|
|
184
|
+
i2v Image-to-Video generation
|
|
185
|
+
edit Video editing
|
|
186
|
+
all Run all tests
|
|
187
|
+
|
|
188
|
+
Examples:
|
|
189
|
+
bun run examples/grok-imagine-ai-sdk.tsx t2v
|
|
190
|
+
bun run examples/grok-imagine-ai-sdk.tsx all
|
|
191
|
+
`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
console.log("\nTest completed!");
|
|
195
|
+
} catch (error) {
|
|
196
|
+
console.error("\nTest failed:", error);
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
main();
|
package/package.json
CHANGED
|
@@ -69,7 +69,11 @@ export async function burnCaptions(
|
|
|
69
69
|
const { video, assPath, outputPath = "output.mp4", verbose } = options;
|
|
70
70
|
const captions: FFmpegOutput = { type: "file", path: assPath };
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
// Resolve backend first so we can check if it's cloud or local
|
|
73
|
+
// TODO: This is a hack - we should abstract backend capabilities (e.g., supportsLocalPaths)
|
|
74
|
+
// instead of checking the name directly. For now, we assume "local" is the only local backend.
|
|
75
|
+
const backend = options.backend ?? localBackend;
|
|
76
|
+
const isCloud = backend.name !== "local";
|
|
73
77
|
|
|
74
78
|
const videoInput = await resolveInputPathMaybeUpload(video, {
|
|
75
79
|
shouldUpload: isCloud,
|
|
@@ -78,14 +82,16 @@ export async function burnCaptions(
|
|
|
78
82
|
shouldUpload: isCloud,
|
|
79
83
|
});
|
|
80
84
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// FFmpeg filter syntax
|
|
84
|
-
const
|
|
85
|
+
// For cloud backends (Rendi): pass raw URL so replaceWithPlaceholders() can match
|
|
86
|
+
// and replace with {{in_X}} placeholder. Rendi downloads inputs and provides local paths.
|
|
87
|
+
// For local backend: escape for FFmpeg filter syntax (backslashes and colons)
|
|
88
|
+
const subtitlesPath = isCloud
|
|
89
|
+
? assInput
|
|
90
|
+
: assInput.replace(/\\/g, "\\\\").replace(/:/g, "\\:");
|
|
85
91
|
|
|
86
92
|
const result = await backend.run({
|
|
87
93
|
inputs: [videoInput, assInput],
|
|
88
|
-
videoFilter: `subtitles=${
|
|
94
|
+
videoFilter: `subtitles=${subtitlesPath}`,
|
|
89
95
|
outputArgs: ["-crf", "18", "-preset", "fast", "-c:a", "copy"],
|
|
90
96
|
outputPath,
|
|
91
97
|
verbose,
|