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
@@ -196,8 +196,16 @@ export function createElevenLabs(
196
196
  };
197
197
  }
198
198
 
199
- export const elevenlabs_provider = createElevenLabs();
200
- export { elevenlabs_provider as elevenlabs, VOICES };
199
+ let _elevenlabs: ElevenLabsProvider | undefined;
200
+ export const elevenlabs = new Proxy({} as ElevenLabsProvider, {
201
+ get(_, prop) {
202
+ if (!_elevenlabs) {
203
+ _elevenlabs = createElevenLabs();
204
+ }
205
+ return _elevenlabs[prop as keyof ElevenLabsProvider];
206
+ },
207
+ });
208
+ export { VOICES };
201
209
 
202
210
  export interface GenerateMusicOptions {
203
211
  prompt: string;
@@ -0,0 +1,214 @@
1
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
2
+ import { existsSync, rmSync } from "node:fs";
3
+ import { computeFileHashes, computePendingKey } from "./fal";
4
+
5
+ const TEST_PENDING_DIR = ".cache/fal-pending-test";
6
+
7
+ describe("fal queue recovery", () => {
8
+ beforeEach(() => {
9
+ if (existsSync(TEST_PENDING_DIR)) {
10
+ rmSync(TEST_PENDING_DIR, { recursive: true });
11
+ }
12
+ });
13
+
14
+ afterEach(() => {
15
+ if (existsSync(TEST_PENDING_DIR)) {
16
+ rmSync(TEST_PENDING_DIR, { recursive: true });
17
+ }
18
+ });
19
+
20
+ describe("computePendingKey", () => {
21
+ test("produces same key for same endpoint and input", () => {
22
+ const endpoint = "fal-ai/flux-schnell";
23
+ const input = { prompt: "a cat", num_images: 1 };
24
+
25
+ const key1 = computePendingKey(endpoint, input);
26
+ const key2 = computePendingKey(endpoint, input);
27
+
28
+ expect(key1).toBe(key2);
29
+ expect(key1).toMatch(/^pending_[a-f0-9]+$/);
30
+ });
31
+
32
+ test("produces different keys for different inputs", () => {
33
+ const endpoint = "fal-ai/flux-schnell";
34
+
35
+ const key1 = computePendingKey(endpoint, { prompt: "a cat" });
36
+ const key2 = computePendingKey(endpoint, { prompt: "a dog" });
37
+
38
+ expect(key1).not.toBe(key2);
39
+ });
40
+
41
+ test("uses stableKey when provided", () => {
42
+ const endpoint = "fal-ai/flux-schnell";
43
+ const input1 = { prompt: "test", image_urls: ["https://fal.media/abc"] };
44
+ const input2 = { prompt: "test", image_urls: ["https://fal.media/xyz"] };
45
+ const stableKey = "stable-key-from-file-hashes";
46
+
47
+ const key1 = computePendingKey(endpoint, input1, stableKey);
48
+ const key2 = computePendingKey(endpoint, input2, stableKey);
49
+
50
+ expect(key1).toBe(key2);
51
+ });
52
+
53
+ test("without stableKey, different image_urls produce different keys", () => {
54
+ const endpoint = "fal-ai/flux-schnell";
55
+ const input1 = { prompt: "test", image_urls: ["https://fal.media/abc"] };
56
+ const input2 = { prompt: "test", image_urls: ["https://fal.media/xyz"] };
57
+
58
+ const key1 = computePendingKey(endpoint, input1);
59
+ const key2 = computePendingKey(endpoint, input2);
60
+
61
+ expect(key1).not.toBe(key2);
62
+ });
63
+ });
64
+
65
+ describe("computeFileHashes", () => {
66
+ test("returns empty array for undefined files", async () => {
67
+ const hashes = await computeFileHashes(undefined);
68
+ expect(hashes).toEqual([]);
69
+ });
70
+
71
+ test("returns empty array for empty files", async () => {
72
+ const hashes = await computeFileHashes([]);
73
+ expect(hashes).toEqual([]);
74
+ });
75
+
76
+ test("returns URL as-is for url type files", async () => {
77
+ const files = [
78
+ { type: "url" as const, url: "https://example.com/image.png" },
79
+ ];
80
+ const hashes = await computeFileHashes(files);
81
+ expect(hashes).toEqual(["https://example.com/image.png"]);
82
+ });
83
+
84
+ test("produces stable hash for same file bytes", async () => {
85
+ const bytes = new Uint8Array([1, 2, 3, 4, 5]);
86
+ const files = [
87
+ { type: "file" as const, data: bytes, mediaType: "image/png" },
88
+ ];
89
+
90
+ const hashes1 = await computeFileHashes(files);
91
+ const hashes2 = await computeFileHashes(files);
92
+
93
+ expect(hashes1).toEqual(hashes2);
94
+ expect(hashes1[0]).toMatch(/^[a-f0-9]+$/);
95
+ });
96
+
97
+ test("produces different hashes for different bytes", async () => {
98
+ const files1 = [
99
+ {
100
+ type: "file" as const,
101
+ data: new Uint8Array([1, 2, 3]),
102
+ mediaType: "image/png",
103
+ },
104
+ ];
105
+ const files2 = [
106
+ {
107
+ type: "file" as const,
108
+ data: new Uint8Array([4, 5, 6]),
109
+ mediaType: "image/png",
110
+ },
111
+ ];
112
+
113
+ const hashes1 = await computeFileHashes(files1);
114
+ const hashes2 = await computeFileHashes(files2);
115
+
116
+ expect(hashes1[0]).not.toBe(hashes2[0]);
117
+ });
118
+
119
+ test("handles base64 encoded data", async () => {
120
+ const bytes = new Uint8Array([72, 101, 108, 108, 111]);
121
+ const base64 = btoa(String.fromCharCode(...bytes));
122
+ const files = [
123
+ { type: "file" as const, data: base64, mediaType: "image/png" },
124
+ ];
125
+
126
+ const hashes = await computeFileHashes(files);
127
+ expect(hashes[0]).toMatch(/^[a-f0-9]+$/);
128
+ });
129
+
130
+ test("same bytes as Uint8Array and base64 produce same hash", async () => {
131
+ const bytes = new Uint8Array([72, 101, 108, 108, 111]);
132
+ const base64 = btoa(String.fromCharCode(...bytes));
133
+
134
+ const filesBytes = [
135
+ { type: "file" as const, data: bytes, mediaType: "image/png" },
136
+ ];
137
+ const filesBase64 = [
138
+ { type: "file" as const, data: base64, mediaType: "image/png" },
139
+ ];
140
+
141
+ const hashesBytes = await computeFileHashes(filesBytes);
142
+ const hashesBase64 = await computeFileHashes(filesBase64);
143
+
144
+ expect(hashesBytes[0]).toBe(hashesBase64[0]);
145
+ });
146
+ });
147
+
148
+ describe("stable key integration", () => {
149
+ test("same file bytes produce same stable key across runs", async () => {
150
+ const endpoint = "fal-ai/nano-banana-pro/edit";
151
+ const bytes = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
152
+ const files = [
153
+ { type: "file" as const, data: bytes, mediaType: "image/png" },
154
+ ];
155
+
156
+ const fileHashes = await computeFileHashes(files);
157
+ const input = { prompt: "test prompt", num_images: 1 };
158
+ const stableKey = JSON.stringify({ endpoint, input, fileHashes });
159
+
160
+ const inputWithUrl1 = {
161
+ ...input,
162
+ image_urls: ["https://fal.media/upload1"],
163
+ };
164
+ const inputWithUrl2 = {
165
+ ...input,
166
+ image_urls: ["https://fal.media/upload2"],
167
+ };
168
+
169
+ const key1 = computePendingKey(endpoint, inputWithUrl1, stableKey);
170
+ const key2 = computePendingKey(endpoint, inputWithUrl2, stableKey);
171
+
172
+ expect(key1).toBe(key2);
173
+ });
174
+
175
+ test("different file bytes produce different stable keys", async () => {
176
+ const endpoint = "fal-ai/nano-banana-pro/edit";
177
+ const input = { prompt: "test prompt", num_images: 1 };
178
+
179
+ const files1 = [
180
+ {
181
+ type: "file" as const,
182
+ data: new Uint8Array([1, 2, 3]),
183
+ mediaType: "image/png",
184
+ },
185
+ ];
186
+ const files2 = [
187
+ {
188
+ type: "file" as const,
189
+ data: new Uint8Array([4, 5, 6]),
190
+ mediaType: "image/png",
191
+ },
192
+ ];
193
+
194
+ const hashes1 = await computeFileHashes(files1);
195
+ const hashes2 = await computeFileHashes(files2);
196
+
197
+ const stableKey1 = JSON.stringify({
198
+ endpoint,
199
+ input,
200
+ fileHashes: hashes1,
201
+ });
202
+ const stableKey2 = JSON.stringify({
203
+ endpoint,
204
+ input,
205
+ fileHashes: hashes2,
206
+ });
207
+
208
+ const key1 = computePendingKey(endpoint, input, stableKey1);
209
+ const key2 = computePendingKey(endpoint, input, stableKey2);
210
+
211
+ expect(key1).not.toBe(key2);
212
+ });
213
+ });
214
+ });