opencode-nanobanana 0.1.0

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 (179) hide show
  1. package/.ralph-events.json +151 -0
  2. package/.ralph-last-branch +1 -0
  3. package/.ralph-monitor-state.json +7 -0
  4. package/.ralph-monitor.pid +1 -0
  5. package/.ralph-timing.json +26 -0
  6. package/README.md +708 -0
  7. package/dist/index.d.ts +18 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +21 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/platforms/android.d.ts +94 -0
  12. package/dist/platforms/android.d.ts.map +1 -0
  13. package/dist/platforms/android.js +123 -0
  14. package/dist/platforms/android.js.map +1 -0
  15. package/dist/platforms/ios.d.ts +51 -0
  16. package/dist/platforms/ios.d.ts.map +1 -0
  17. package/dist/platforms/ios.js +149 -0
  18. package/dist/platforms/ios.js.map +1 -0
  19. package/dist/platforms/macos.d.ts +33 -0
  20. package/dist/platforms/macos.d.ts.map +1 -0
  21. package/dist/platforms/macos.js +50 -0
  22. package/dist/platforms/macos.js.map +1 -0
  23. package/dist/platforms/watchos.d.ts +36 -0
  24. package/dist/platforms/watchos.d.ts.map +1 -0
  25. package/dist/platforms/watchos.js +113 -0
  26. package/dist/platforms/watchos.js.map +1 -0
  27. package/dist/platforms/web.d.ts +64 -0
  28. package/dist/platforms/web.d.ts.map +1 -0
  29. package/dist/platforms/web.js +96 -0
  30. package/dist/platforms/web.js.map +1 -0
  31. package/dist/providers/gemini.d.ts +41 -0
  32. package/dist/providers/gemini.d.ts.map +1 -0
  33. package/dist/providers/gemini.js +177 -0
  34. package/dist/providers/gemini.js.map +1 -0
  35. package/dist/tools/analyze/compare.d.ts +12 -0
  36. package/dist/tools/analyze/compare.d.ts.map +1 -0
  37. package/dist/tools/analyze/compare.js +83 -0
  38. package/dist/tools/analyze/compare.js.map +1 -0
  39. package/dist/tools/analyze/mockup.d.ts +12 -0
  40. package/dist/tools/analyze/mockup.d.ts.map +1 -0
  41. package/dist/tools/analyze/mockup.js +88 -0
  42. package/dist/tools/analyze/mockup.js.map +1 -0
  43. package/dist/tools/analyze/screenshot.d.ts +12 -0
  44. package/dist/tools/analyze/screenshot.d.ts.map +1 -0
  45. package/dist/tools/analyze/screenshot.js +61 -0
  46. package/dist/tools/analyze/screenshot.js.map +1 -0
  47. package/dist/tools/app-assets/app-icon.d.ts +9 -0
  48. package/dist/tools/app-assets/app-icon.d.ts.map +1 -0
  49. package/dist/tools/app-assets/app-icon.js +133 -0
  50. package/dist/tools/app-assets/app-icon.js.map +1 -0
  51. package/dist/tools/app-assets/device-mockup.d.ts +9 -0
  52. package/dist/tools/app-assets/device-mockup.d.ts.map +1 -0
  53. package/dist/tools/app-assets/device-mockup.js +139 -0
  54. package/dist/tools/app-assets/device-mockup.js.map +1 -0
  55. package/dist/tools/app-assets/launch-images.d.ts +3 -0
  56. package/dist/tools/app-assets/launch-images.d.ts.map +1 -0
  57. package/dist/tools/app-assets/launch-images.js +171 -0
  58. package/dist/tools/app-assets/launch-images.js.map +1 -0
  59. package/dist/tools/app-assets/resize-devices.d.ts +14 -0
  60. package/dist/tools/app-assets/resize-devices.d.ts.map +1 -0
  61. package/dist/tools/app-assets/resize-devices.js +296 -0
  62. package/dist/tools/app-assets/resize-devices.js.map +1 -0
  63. package/dist/tools/app-assets/screenshots.d.ts +14 -0
  64. package/dist/tools/app-assets/screenshots.d.ts.map +1 -0
  65. package/dist/tools/app-assets/screenshots.js +186 -0
  66. package/dist/tools/app-assets/screenshots.js.map +1 -0
  67. package/dist/tools/core/edit-image.d.ts +12 -0
  68. package/dist/tools/core/edit-image.d.ts.map +1 -0
  69. package/dist/tools/core/edit-image.js +102 -0
  70. package/dist/tools/core/edit-image.js.map +1 -0
  71. package/dist/tools/core/generate-image.d.ts +12 -0
  72. package/dist/tools/core/generate-image.d.ts.map +1 -0
  73. package/dist/tools/core/generate-image.js +96 -0
  74. package/dist/tools/core/generate-image.js.map +1 -0
  75. package/dist/tools/core/restore-image.d.ts +12 -0
  76. package/dist/tools/core/restore-image.d.ts.map +1 -0
  77. package/dist/tools/core/restore-image.js +104 -0
  78. package/dist/tools/core/restore-image.js.map +1 -0
  79. package/dist/tools/design/mockup-to-code.d.ts +3 -0
  80. package/dist/tools/design/mockup-to-code.d.ts.map +1 -0
  81. package/dist/tools/design/mockup-to-code.js +311 -0
  82. package/dist/tools/design/mockup-to-code.js.map +1 -0
  83. package/dist/tools/design/sketch-to-code.d.ts +3 -0
  84. package/dist/tools/design/sketch-to-code.d.ts.map +1 -0
  85. package/dist/tools/design/sketch-to-code.js +325 -0
  86. package/dist/tools/design/sketch-to-code.js.map +1 -0
  87. package/dist/tools/docs/architecture-diagram.d.ts +12 -0
  88. package/dist/tools/docs/architecture-diagram.d.ts.map +1 -0
  89. package/dist/tools/docs/architecture-diagram.js +179 -0
  90. package/dist/tools/docs/architecture-diagram.js.map +1 -0
  91. package/dist/tools/docs/readme-banner.d.ts +6 -0
  92. package/dist/tools/docs/readme-banner.d.ts.map +1 -0
  93. package/dist/tools/docs/readme-banner.js +108 -0
  94. package/dist/tools/docs/readme-banner.js.map +1 -0
  95. package/dist/tools/docs/sequence-diagram.d.ts +12 -0
  96. package/dist/tools/docs/sequence-diagram.d.ts.map +1 -0
  97. package/dist/tools/docs/sequence-diagram.js +161 -0
  98. package/dist/tools/docs/sequence-diagram.js.map +1 -0
  99. package/dist/tools/docs/social-preview.d.ts +11 -0
  100. package/dist/tools/docs/social-preview.d.ts.map +1 -0
  101. package/dist/tools/docs/social-preview.js +111 -0
  102. package/dist/tools/docs/social-preview.js.map +1 -0
  103. package/dist/tools/video/extend-video.d.ts +14 -0
  104. package/dist/tools/video/extend-video.d.ts.map +1 -0
  105. package/dist/tools/video/extend-video.js +39 -0
  106. package/dist/tools/video/extend-video.js.map +1 -0
  107. package/dist/tools/video/generate-video.d.ts +14 -0
  108. package/dist/tools/video/generate-video.d.ts.map +1 -0
  109. package/dist/tools/video/generate-video.js +39 -0
  110. package/dist/tools/video/generate-video.js.map +1 -0
  111. package/dist/tools/video/image-to-video.d.ts +15 -0
  112. package/dist/tools/video/image-to-video.d.ts.map +1 -0
  113. package/dist/tools/video/image-to-video.js +42 -0
  114. package/dist/tools/video/image-to-video.js.map +1 -0
  115. package/dist/tools/video/storyboard-video.d.ts +91 -0
  116. package/dist/tools/video/storyboard-video.d.ts.map +1 -0
  117. package/dist/tools/video/storyboard-video.js +230 -0
  118. package/dist/tools/video/storyboard-video.js.map +1 -0
  119. package/dist/utils/ffmpeg.d.ts +30 -0
  120. package/dist/utils/ffmpeg.d.ts.map +1 -0
  121. package/dist/utils/ffmpeg.js +205 -0
  122. package/dist/utils/ffmpeg.js.map +1 -0
  123. package/dist/utils/file-handler.d.ts +7 -0
  124. package/dist/utils/file-handler.d.ts.map +1 -0
  125. package/dist/utils/file-handler.js +10 -0
  126. package/dist/utils/file-handler.js.map +1 -0
  127. package/dist/utils/image-processing.d.ts +7 -0
  128. package/dist/utils/image-processing.d.ts.map +1 -0
  129. package/dist/utils/image-processing.js +10 -0
  130. package/dist/utils/image-processing.js.map +1 -0
  131. package/docs/PLUGIN-VERIFICATION.md +182 -0
  132. package/logs/notifications.jsonl +46 -0
  133. package/package.json +61 -0
  134. package/prd.json +216 -0
  135. package/progress.txt +145 -0
  136. package/ralph-report.html +297 -0
  137. package/src/index.ts +23 -0
  138. package/src/platforms/android/.gitkeep +0 -0
  139. package/src/platforms/ios/.gitkeep +0 -0
  140. package/src/platforms/web/.gitkeep +0 -0
  141. package/src/providers/.gitkeep +0 -0
  142. package/src/providers/gemini.ts +288 -0
  143. package/src/tools/core/.gitkeep +0 -0
  144. package/src/tools/platform/.gitkeep +0 -0
  145. package/src/tools/video/extend-video.ts +71 -0
  146. package/src/tools/video/generate-video.ts +70 -0
  147. package/src/tools/video/image-to-video.ts +76 -0
  148. package/src/tools/video/storyboard-video.ts +325 -0
  149. package/src/utils/.gitkeep +0 -0
  150. package/src/utils/ffmpeg.ts +266 -0
  151. package/src/utils/file-handler.ts +10 -0
  152. package/src/utils/image-processing.ts +10 -0
  153. package/templates/.gitkeep +0 -0
  154. package/test-analyze-screenshot.ts +50 -0
  155. package/test-app-icons.ts +55 -0
  156. package/test-cat-sunset.ts +30 -0
  157. package/test-full-plugin.ts +88 -0
  158. package/test-icon-gen.ts +30 -0
  159. package/test-output/test-edit.png +0 -0
  160. package/test-output/test-generate.png +0 -0
  161. package/test-output/test-video.mp4 +0 -0
  162. package/test-plugin-load.js +45 -0
  163. package/test-princess-emma-continue.ts +35 -0
  164. package/test-princess-emma-full.ts +38 -0
  165. package/test-princess-emma-short.ts +32 -0
  166. package/test-princess-emma-with-reference.ts +34 -0
  167. package/test-princess-emma.ts +38 -0
  168. package/test-product-ad.ts +66 -0
  169. package/test-ralph-droid.ts +30 -0
  170. package/test-social-preview.ts +61 -0
  171. package/test-veo31-live.ts +187 -0
  172. package/test-video-gen.ts +40 -0
  173. package/test-video-veo.ts +73 -0
  174. package/test-zurich-video.ts +64 -0
  175. package/tests/.gitkeep +0 -0
  176. package/tests/providers/gemini.test.ts +388 -0
  177. package/tests/utils/ffmpeg.test.ts +328 -0
  178. package/tests/video/storyboard.test.ts +469 -0
  179. package/tsconfig.json +25 -0
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Live test for Veo 3.1 API - Storyboard Video Generation
3
+ *
4
+ * Tests:
5
+ * 1. Single video generation with Veo 3.1 (with audio)
6
+ * 2. Multi-scene storyboard generation
7
+ * 3. Video with reference images (if supported)
8
+ */
9
+
10
+ import { GeminiProvider } from './src/providers/gemini.js';
11
+ import { generateStoryboardVideo } from './src/tools/video/storyboard-video.js';
12
+ import { writeFile } from 'fs/promises';
13
+ import { join } from 'path';
14
+
15
+ const API_KEY = process.env.GEMINI_API_KEY || 'AIzaSyDROqIj3wBKod1ks16MI9rwo7BZipqug9w';
16
+ const OUTPUT_DIR = './generated-assets/veo31-tests';
17
+
18
+ async function ensureDir(dir: string) {
19
+ const fs = await import('fs/promises');
20
+ await fs.mkdir(dir, { recursive: true });
21
+ }
22
+
23
+ async function testSingleVideoGeneration() {
24
+ console.log('\n' + '='.repeat(60));
25
+ console.log('TEST 1: Single Video Generation with Veo 3.1');
26
+ console.log('='.repeat(60));
27
+
28
+ const provider = new GeminiProvider(API_KEY);
29
+
30
+ try {
31
+ console.log('\nGenerating video with native audio...');
32
+ console.log('Prompt: "A cat playing with a ball of yarn in a sunny living room"');
33
+ console.log('Options: 720p, 8 seconds, audio enabled\n');
34
+
35
+ const result = await provider.generateVideo(
36
+ 'A cat playing with a ball of yarn in a sunny living room',
37
+ {
38
+ aspectRatio: '16:9',
39
+ resolution: '720p',
40
+ duration: 8,
41
+ generateAudio: true,
42
+ }
43
+ );
44
+
45
+ const outputPath = join(OUTPUT_DIR, 'test1-cat-yarn.mp4');
46
+ await writeFile(outputPath, result.buffer);
47
+
48
+ console.log(`\nāœ… SUCCESS: Video generated in ${(result.generationTime / 1000).toFixed(1)}s`);
49
+ console.log(` Output: ${outputPath}`);
50
+ console.log(` Size: ${(result.buffer.length / 1024 / 1024).toFixed(2)} MB`);
51
+
52
+ return true;
53
+ } catch (error) {
54
+ console.error('\nāŒ FAILED:', error);
55
+ return false;
56
+ }
57
+ }
58
+
59
+ async function testStoryboardGeneration() {
60
+ console.log('\n' + '='.repeat(60));
61
+ console.log('TEST 2: Storyboard Video Generation (3 scenes)');
62
+ console.log('='.repeat(60));
63
+
64
+ try {
65
+ console.log('\nGenerating 3-scene storyboard...');
66
+ console.log('Style: cinematic');
67
+ console.log('Transition: crossfade (0.5s)');
68
+ console.log('Scenes:');
69
+ console.log(' 1. Sunrise over a misty mountain');
70
+ console.log(' 2. A hiker climbing a rocky trail');
71
+ console.log(' 3. Panoramic view from the summit\n');
72
+
73
+ const result = await generateStoryboardVideo({
74
+ apiKey: API_KEY,
75
+ scenes: [
76
+ 'Sunrise over a misty mountain, golden light breaking through clouds',
77
+ 'A hiker climbing a rocky trail, determination on their face',
78
+ 'Panoramic view from the summit, endless mountains in the distance'
79
+ ],
80
+ style: 'cinematic',
81
+ aspectRatio: '16:9',
82
+ transition: 'crossfade',
83
+ transitionDuration: 0.5,
84
+ generateAudio: true,
85
+ outputPath: join(OUTPUT_DIR, 'test2-mountain-journey.mp4'),
86
+ });
87
+
88
+ console.log(`\nāœ… SUCCESS: Storyboard generated`);
89
+ console.log(` Output: ${result.videoPath}`);
90
+ console.log(` Total time: ${(result.totalTime / 1000).toFixed(1)}s`);
91
+ console.log(` Scenes: ${result.successCount}/${result.successCount + result.failureCount}`);
92
+ console.log(' Per-scene times:');
93
+ result.sceneTimes.forEach(st => {
94
+ console.log(` Scene ${st.scene}: ${(st.time / 1000).toFixed(1)}s`);
95
+ });
96
+
97
+ return true;
98
+ } catch (error) {
99
+ console.error('\nāŒ FAILED:', error);
100
+ return false;
101
+ }
102
+ }
103
+
104
+ async function testProductCommercial() {
105
+ console.log('\n' + '='.repeat(60));
106
+ console.log('TEST 3: Product Commercial (5 scenes with character)');
107
+ console.log('='.repeat(60));
108
+
109
+ try {
110
+ console.log('\nGenerating product commercial...');
111
+ console.log('Style: commercial advertising');
112
+ console.log('Character: A fit woman in athletic wear');
113
+ console.log('Scenes: 5 scenes showing product usage\n');
114
+
115
+ const result = await generateStoryboardVideo({
116
+ apiKey: API_KEY,
117
+ scenes: [
118
+ 'Woman enters a modern kitchen, morning light streaming through windows',
119
+ 'She picks up a sports nutrition container, examining the label',
120
+ 'Close-up of hands mixing the powder with water in a shaker',
121
+ 'Woman drinks the shake with a satisfied expression',
122
+ 'Wide shot, she gives a thumbs up with energy and enthusiasm'
123
+ ],
124
+ style: 'commercial advertising, bright and energetic',
125
+ characterDescription: 'A fit woman in her 30s with brown hair, wearing blue athletic wear',
126
+ aspectRatio: '16:9',
127
+ transition: 'crossfade',
128
+ transitionDuration: 0.3,
129
+ generateAudio: true,
130
+ outputPath: join(OUTPUT_DIR, 'test3-product-commercial.mp4'),
131
+ });
132
+
133
+ console.log(`\nāœ… SUCCESS: Commercial generated`);
134
+ console.log(` Output: ${result.videoPath}`);
135
+ console.log(` Total time: ${(result.totalTime / 1000).toFixed(1)}s`);
136
+ console.log(` Scenes: ${result.successCount}/${result.successCount + result.failureCount}`);
137
+
138
+ return true;
139
+ } catch (error) {
140
+ console.error('\nāŒ FAILED:', error);
141
+ return false;
142
+ }
143
+ }
144
+
145
+ async function main() {
146
+ console.log('\n' + '='.repeat(60));
147
+ console.log('VEO 3.1 LIVE API TESTS');
148
+ console.log('='.repeat(60));
149
+ console.log(`\nAPI Key: ${API_KEY.slice(0, 10)}...${API_KEY.slice(-4)}`);
150
+ console.log(`Output Directory: ${OUTPUT_DIR}`);
151
+
152
+ await ensureDir(OUTPUT_DIR);
153
+
154
+ const results: Record<string, boolean> = {};
155
+
156
+ // Test 1: Single video
157
+ results['Single Video'] = await testSingleVideoGeneration();
158
+
159
+ // Test 2: Storyboard (3 scenes)
160
+ results['Storyboard (3 scenes)'] = await testStoryboardGeneration();
161
+
162
+ // Test 3: Product commercial (5 scenes with character)
163
+ // Commenting out to save API costs - uncomment if needed
164
+ // results['Product Commercial'] = await testProductCommercial();
165
+
166
+ // Summary
167
+ console.log('\n' + '='.repeat(60));
168
+ console.log('TEST SUMMARY');
169
+ console.log('='.repeat(60));
170
+
171
+ let passed = 0;
172
+ let failed = 0;
173
+
174
+ for (const [test, success] of Object.entries(results)) {
175
+ const status = success ? 'āœ… PASSED' : 'āŒ FAILED';
176
+ console.log(` ${test}: ${status}`);
177
+ if (success) passed++;
178
+ else failed++;
179
+ }
180
+
181
+ console.log(`\nTotal: ${passed} passed, ${failed} failed`);
182
+ console.log('='.repeat(60));
183
+
184
+ process.exit(failed > 0 ? 1 : 0);
185
+ }
186
+
187
+ main().catch(console.error);
@@ -0,0 +1,40 @@
1
+ import { GeminiProvider } from './src/providers/gemini.js';
2
+ import * as fs from 'fs/promises';
3
+
4
+ async function generateVideo() {
5
+ console.log('šŸŽ¬ Generating Video - Ralph Ultra Hacking Scene...\n');
6
+
7
+ const provider = new GeminiProvider();
8
+
9
+ const prompt = `A cartoon character resembling a chubby kid with a round face and buck teeth, wearing a futuristic cyberpunk droid suit with neon purple and orange glowing circuits, approaches a computer terminal. The character sits down and starts typing rapidly on the keyboard, holographic displays appear showing code and system interfaces. Green matrix-style code reflections on the character's face. The scene has dramatic lighting with neon glows and a high-tech lab environment. Cinematic cyberpunk aesthetic, smooth animation.`;
10
+
11
+ console.log('šŸ“ Scene: Ralph Ultra approaching computer and hacking');
12
+ console.log('šŸŽØ Style: Cyberpunk, neon glows, holographic displays');
13
+ console.log('\nā³ Generating video (this may take a while)...\n');
14
+
15
+ const startTime = Date.now();
16
+
17
+ try {
18
+ const videoBuffer = await provider.generateVideo(prompt, {
19
+ duration: 5,
20
+ aspectRatio: '16:9'
21
+ });
22
+
23
+ const duration = ((Date.now() - startTime) / 1000).toFixed(1);
24
+
25
+ console.log(`āœ… Generated in ${duration}s`);
26
+ console.log(`šŸ“¦ Size: ${(videoBuffer.length / 1024 / 1024).toFixed(2)}MB\n`);
27
+
28
+ const outputPath = './generated-assets/ralph-ultra-hacking.mp4';
29
+ await fs.mkdir('./generated-assets', { recursive: true });
30
+ await fs.writeFile(outputPath, videoBuffer);
31
+
32
+ console.log(`šŸ’¾ Saved to: ${outputPath}`);
33
+ console.log('\nšŸŽ‰ Done! Your video is ready.');
34
+
35
+ } catch (error) {
36
+ console.error('āŒ Error:', error);
37
+ }
38
+ }
39
+
40
+ generateVideo().catch(console.error);
@@ -0,0 +1,73 @@
1
+ import { GoogleGenAI } from '@google/genai';
2
+ import { createWriteStream } from 'fs';
3
+ import { Readable } from 'stream';
4
+ import * as fs from 'fs/promises';
5
+
6
+ async function generateVideo() {
7
+ console.log('šŸŽ¬ Generating Video - Ralph Ultra Hacking Scene...\n');
8
+
9
+ const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
10
+
11
+ const prompt = `A cartoon character with a round face wearing a futuristic cyberpunk suit with neon purple and orange glowing circuits approaches a computer terminal. The character sits down and starts typing rapidly, holographic displays appear showing code. Green matrix-style code reflections on face. Dramatic neon lighting, high-tech lab environment. Cyberpunk aesthetic, smooth animation.`;
12
+
13
+ console.log('šŸ“ Scene: Ralph Ultra approaching computer and hacking');
14
+ console.log('šŸŽØ Style: Cyberpunk, neon glows, holographic displays');
15
+ console.log('\nā³ Starting video generation (this takes 1-3 minutes)...\n');
16
+
17
+ const startTime = Date.now();
18
+
19
+ try {
20
+ // Start video generation operation
21
+ let operation = await ai.models.generateVideos({
22
+ model: 'veo-2.0-generate-001',
23
+ prompt: prompt,
24
+ config: {
25
+ numberOfVideos: 1,
26
+ aspectRatio: '16:9',
27
+ }
28
+ });
29
+
30
+ console.log('šŸ”„ Operation started:', operation.name);
31
+
32
+ // Poll for completion
33
+ let pollCount = 0;
34
+ while (!operation.done) {
35
+ pollCount++;
36
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);
37
+ console.log(`ā³ Generating... (${elapsed}s elapsed, poll #${pollCount})`);
38
+
39
+ await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10s
40
+ operation = await ai.operations.getVideosOperation({ operation: operation });
41
+ }
42
+
43
+ const duration = ((Date.now() - startTime) / 1000).toFixed(1);
44
+ console.log(`\nāœ… Generation complete in ${duration}s`);
45
+
46
+ // Download results
47
+ if (operation.response?.generatedVideos && operation.response.generatedVideos.length > 0) {
48
+ const video = operation.response.generatedVideos[0];
49
+ const videoUrl = `${video.video?.uri}&key=${process.env.GEMINI_API_KEY}`;
50
+
51
+ console.log('šŸ“„ Downloading video...');
52
+
53
+ await fs.mkdir('./generated-assets', { recursive: true });
54
+ const outputPath = './generated-assets/ralph-ultra-hacking.mp4';
55
+
56
+ const resp = await fetch(videoUrl);
57
+ const writer = createWriteStream(outputPath);
58
+ Readable.fromWeb(resp.body as any).pipe(writer);
59
+
60
+ await new Promise(resolve => writer.on('finish', resolve));
61
+
62
+ console.log(`šŸ’¾ Saved to: ${outputPath}`);
63
+ console.log('\nšŸŽ‰ Done! Your video is ready.');
64
+ } else {
65
+ console.log('āŒ No videos were generated');
66
+ }
67
+
68
+ } catch (error: any) {
69
+ console.error('āŒ Error:', error.message || error);
70
+ }
71
+ }
72
+
73
+ generateVideo().catch(console.error);
@@ -0,0 +1,64 @@
1
+ import { GoogleGenAI } from '@google/genai';
2
+ import { createWriteStream } from 'fs';
3
+ import { Readable } from 'stream';
4
+ import * as fs from 'fs/promises';
5
+
6
+ async function generateVideo() {
7
+ console.log('šŸŽ¬ Generating Video - Zurich Bahnhofstrasse Scene...\n');
8
+
9
+ const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
10
+
11
+ const prompt = `Street scene of a well-dressed brunette woman walking along Bahnhofstrasse Zurich, boutique storefronts in background, golden hour lighting, professional cinematography`;
12
+
13
+ console.log('šŸ“ Prompt:', prompt);
14
+ console.log('\nā³ Starting video generation (this takes 30-90 seconds)...\n');
15
+
16
+ const startTime = Date.now();
17
+
18
+ let operation = await ai.models.generateVideos({
19
+ model: 'veo-2.0-generate-001',
20
+ prompt: prompt,
21
+ config: {
22
+ numberOfVideos: 1,
23
+ aspectRatio: '16:9',
24
+ }
25
+ });
26
+
27
+ console.log('šŸ”„ Operation started:', operation.name);
28
+
29
+ let pollCount = 0;
30
+ while (!operation.done) {
31
+ pollCount++;
32
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);
33
+ console.log(`ā³ Generating... (${elapsed}s elapsed, poll #${pollCount})`);
34
+
35
+ await new Promise(resolve => setTimeout(resolve, 10000));
36
+ operation = await ai.operations.getVideosOperation({ operation });
37
+ }
38
+
39
+ const duration = ((Date.now() - startTime) / 1000).toFixed(1);
40
+ console.log(`\nāœ… Generation complete in ${duration}s`);
41
+
42
+ if (operation.response?.generatedVideos && operation.response.generatedVideos.length > 0) {
43
+ const video = operation.response.generatedVideos[0];
44
+ const videoUrl = `${video.video?.uri}&key=${process.env.GEMINI_API_KEY}`;
45
+
46
+ console.log('šŸ“„ Downloading video...');
47
+
48
+ await fs.mkdir('./generated-assets', { recursive: true });
49
+ const outputPath = './generated-assets/zurich-bahnhofstrasse.mp4';
50
+
51
+ const resp = await fetch(videoUrl);
52
+ const writer = createWriteStream(outputPath);
53
+ Readable.fromWeb(resp.body as any).pipe(writer);
54
+
55
+ await new Promise(resolve => writer.on('finish', resolve));
56
+
57
+ console.log(`šŸ’¾ Saved to: ${outputPath}`);
58
+ console.log('\nšŸŽ‰ Done! Your video is ready (note: no audio).');
59
+ } else {
60
+ console.log('āŒ No videos were generated');
61
+ }
62
+ }
63
+
64
+ generateVideo().catch(console.error);
package/tests/.gitkeep ADDED
File without changes