genmix 1.0.0 → 1.0.2

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/README.md CHANGED
@@ -45,7 +45,7 @@ const result = await generator.generate(
45
45
  );
46
46
 
47
47
  // Save images
48
- const savedPaths = generator.save('./output');
48
+ const savedPaths = await generator.save({ directory: './output' });
49
49
  console.log('Images saved:', savedPaths);
50
50
  ```
51
51
 
@@ -62,7 +62,7 @@ const result = await generator.generate(
62
62
  }
63
63
  );
64
64
 
65
- const savedPaths = generator.save('./output');
65
+ const savedPaths = await generator.save({ directory: './output' });
66
66
  ```
67
67
 
68
68
  ### Using URLs as Reference
@@ -76,7 +76,7 @@ const result = await generator.generate(
76
76
  }
77
77
  );
78
78
 
79
- generator.save('./output');
79
+ generator.save({ directory: './output' });
80
80
  ```
81
81
 
82
82
  ## Configuration Options
@@ -106,6 +106,46 @@ await generator.generate(prompt, options)
106
106
  | `options.quality` | string | Quality: '1K', '2K', '4K' | - |
107
107
  | `options.aspectRatio` | string | Aspect ratio: '1:1', '16:9', '4:3', etc. | - |
108
108
 
109
+ ### save() Method
110
+
111
+ ```javascript
112
+ await generator.save(options)
113
+ ```
114
+
115
+ **Parameters:**
116
+
117
+ | Option | Type | Description | Default |
118
+ | ------------------- | ------ | ------------------------------------------------ | ------- |
119
+ | `options.directory` | string | Target directory path to save images | `'.'` |
120
+ | `options.filename` | string | Custom filename (without extension). If not provided, uses hash-based filename | - |
121
+ | `options.extension` | string | File format: 'jpg', 'png', 'webp', 'avif', 'tiff' | `'jpg'` |
122
+
123
+ **Examples:**
124
+
125
+ ```javascript
126
+ // Save to specific directory with auto-generated filename (jpg by default)
127
+ await generator.save({ directory: './output' });
128
+
129
+ // Save as PNG
130
+ await generator.save({ directory: './output', extension: 'png' });
131
+
132
+ // Save to specific directory with custom filename
133
+ await generator.save({ directory: './output', filename: 'my-image' });
134
+
135
+ // Save as WebP with custom filename
136
+ await generator.save({ directory: './output', filename: 'my-image', extension: 'webp' });
137
+
138
+ // Save to current directory with custom filename
139
+ await generator.save({ filename: 'my-image' });
140
+
141
+ // Save to current directory with auto-generated filename (jpg)
142
+ await generator.save();
143
+ ```
144
+
145
+ **Note:**
146
+ - When multiple images are generated and a custom filename is provided, they will be saved as `filename_0.jpg`, `filename_1.jpg`, etc.
147
+ - The method uses Sharp for image conversion, supporting high-quality format conversion
148
+
109
149
  ## Advanced Examples
110
150
 
111
151
  ### Style Transfer
@@ -179,7 +219,7 @@ try {
179
219
  const result = await generator.generate(prompt, options);
180
220
 
181
221
  if (result.images && result.images.length > 0) {
182
- const paths = generator.save('./output');
222
+ const paths = generator.save({ directory: './output' });
183
223
  console.log('Success!', paths);
184
224
  } else {
185
225
  console.log('No images generated');
@@ -17,13 +17,25 @@ async function main() {
17
17
  'Translate this image to Portuguese',
18
18
  {
19
19
  referenceImage: localImagePath,
20
- quality: '2K',
20
+ quality: '1K',
21
21
  numberOfImages: 1
22
22
  }
23
23
  );
24
24
 
25
25
  if (result1.images && result1.images.length > 0) {
26
- const saved = generator.save(__dirname);
26
+ // Create pt directory if it doesn't exist
27
+ const ptDir = path.join(__dirname, 'pt');
28
+ if (!fs.existsSync(ptDir)) {
29
+ fs.mkdirSync(ptDir, { recursive: true });
30
+ }
31
+
32
+ // Use the same filename as the original
33
+ const originalName = path.basename(localImagePath, path.extname(localImagePath));
34
+
35
+ const saved = await generator.save({
36
+ directory: ptDir,
37
+ filename: originalName
38
+ });
27
39
  console.log('✅ Modified image saved at:', saved[0], '\n');
28
40
  } else if (result1.text) {
29
41
  console.log('📝 Result:', result1.text, '\n');
@@ -31,26 +43,26 @@ async function main() {
31
43
  }
32
44
 
33
45
 
34
- // === Option 3: Multiple variations of the same image ===
35
- if (fs.existsSync(localImagePath)) {
36
- console.log('🎨 Generating multiple variations...\n');
46
+ // // === Option 3: Multiple variations of the same image ===
47
+ // if (fs.existsSync(localImagePath)) {
48
+ // console.log('🎨 Generating multiple variations...\n');
37
49
 
38
- const result3 = await generator.generate(
39
- 'Add a vintage film look with grain and vignette effect',
40
- {
41
- referenceImage: localImagePath,
42
- quality: '1K',
43
- numberOfImages: 3
44
- }
45
- );
50
+ // const result3 = await generator.generate(
51
+ // 'Add a vintage film look with grain and vignette effect',
52
+ // {
53
+ // referenceImage: localImagePath,
54
+ // quality: '1K',
55
+ // numberOfImages: 3
56
+ // }
57
+ // );
46
58
 
47
- if (result3.images && result3.images.length > 0) {
48
- const saved = generator.save(__dirname);
49
- console.log(`✅ ${saved.length} variations saved:`);
50
- saved.forEach(p => console.log(` - ${p}`));
51
- console.log();
52
- }
53
- }
59
+ // if (result3.images && result3.images.length > 0) {
60
+ // const saved = await generator.save({ directory: __dirname });
61
+ // console.log(`✅ ${saved.length} variations saved:`);
62
+ // saved.forEach(p => console.log(` - ${p}`));
63
+ // console.log();
64
+ // }
65
+ // }
54
66
 
55
67
  console.log('🎉 All examples completed successfully!\n');
56
68
 
package/demo/example.js CHANGED
@@ -25,7 +25,7 @@ async function exampleBasicGeneration() {
25
25
  if (result.images && result.images.length > 0) {
26
26
  console.log(`Found ${result.images.length} images.`);
27
27
 
28
- const savedPaths = generator.save(__dirname);
28
+ const savedPaths = await generator.save({ directory: __dirname });
29
29
  savedPaths.forEach(p => console.log(`Saved image to ${p}`));
30
30
  } else {
31
31
  console.log('No images generated.');
Binary file
@@ -1,6 +1,7 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const hashFactory = require('hash-factory');
4
+ const sharp = require('sharp');
4
5
 
5
6
  class BaseGenerator {
6
7
  constructor(config = {}) {
@@ -20,12 +21,14 @@ class BaseGenerator {
20
21
  }
21
22
 
22
23
  /**
23
- * Saves generated images to the specified directory using hashed filenames.
24
- * @param {string} directory - Target directory path.
25
- * @returns {string[]} Array of saved file paths.
24
+ * Saves generated images to the specified directory using hashed filenames or custom filename.
25
+ * @param {Object} [options={}] - Save options
26
+ * @param {string} [options.directory='.'] - Target directory path. Defaults to current directory.
27
+ * @param {string} [options.filename] - Optional custom filename (without extension). If not provided, uses hashed filenames.
28
+ * @param {string} [options.extension='jpg'] - File extension: 'jpg', 'png', 'webp', 'avif', 'tiff'. Defaults to 'jpg'.
29
+ * @returns {Promise<string[]>} Promise that resolves to array of saved file paths.
26
30
  */
27
- save(directory) {
28
- const extension = 'png';
31
+ async save({directory = '.', filename = null, extension = 'jpg'} = {}) {
29
32
  const targetImages = this.lastGeneration?.images;
30
33
  const targetPrompt = this.lastGeneration?.prompt;
31
34
 
@@ -34,7 +37,7 @@ class BaseGenerator {
34
37
  return [];
35
38
  }
36
39
 
37
- if (!targetPrompt) {
40
+ if (!targetPrompt && !filename) {
38
41
  console.warn('No prompt available for hash generation.');
39
42
  }
40
43
 
@@ -43,18 +46,54 @@ class BaseGenerator {
43
46
  fs.mkdirSync(directory, { recursive: true });
44
47
  }
45
48
 
49
+ // Normalize extension
50
+ extension = extension.toLowerCase().replace(/^\./, '');
51
+
52
+ // Validate extension
53
+ const supportedFormats = ['jpg', 'jpeg', 'png', 'webp', 'avif', 'tiff', 'tif'];
54
+ if (!supportedFormats.includes(extension)) {
55
+ throw new Error(`Unsupported extension: ${extension}. Supported formats: ${supportedFormats.join(', ')}`);
56
+ }
57
+
58
+ // Normalize jpeg/jpg
59
+ const sharpFormat = extension === 'jpeg' ? 'jpg' : extension;
60
+ const fileExtension = extension === 'jpeg' ? 'jpg' : extension;
61
+
46
62
  const savedPaths = [];
47
- targetImages.forEach((imgData, index) => {
63
+
64
+ for (let index = 0; index < targetImages.length; index++) {
65
+ const imgData = targetImages[index];
48
66
  const base64Data = imgData.replace(/^data:image\/\w+;base64,/, "");
49
67
  const buffer = Buffer.from(base64Data, 'base64');
50
68
 
51
- const hash = this.generateHash(targetPrompt + '_' + index);
52
- const fileName = `${hash}.${extension}`;
69
+ let fileName;
70
+ if (filename) {
71
+ // Use custom filename, add index if multiple images
72
+ if (targetImages.length > 1) {
73
+ fileName = `${filename}_${index}.${fileExtension}`;
74
+ } else {
75
+ fileName = `${filename}.${fileExtension}`;
76
+ }
77
+ } else {
78
+ // Use hash-based filename
79
+ const hash = this.generateHash(targetPrompt + '_' + index);
80
+ fileName = `${hash}.${fileExtension}`;
81
+ }
82
+
53
83
  const outputPath = path.join(directory, fileName);
54
84
 
55
- fs.writeFileSync(outputPath, buffer);
56
- savedPaths.push(outputPath);
57
- });
85
+ // Convert image format using sharp
86
+ try {
87
+ await sharp(buffer)
88
+ .toFormat(sharpFormat)
89
+ .toFile(outputPath);
90
+
91
+ savedPaths.push(outputPath);
92
+ } catch (error) {
93
+ console.error(`Error saving image ${fileName}:`, error.message);
94
+ throw error;
95
+ }
96
+ }
58
97
 
59
98
  return savedPaths;
60
99
  }
package/package.json CHANGED
@@ -1,9 +1,23 @@
1
1
  {
2
2
  "name": "genmix",
3
- "version": "1.0.0",
4
- "description": "",
5
- "license": "ISC",
6
- "author": "",
3
+ "version": "1.0.2",
4
+ "description": "AI-powered image generator using Google Gemini API. Supports image generation from text prompts and image modification with reference images.",
5
+ "license": "MIT",
6
+ "author": "Martin Clasen",
7
+ "keywords": [
8
+ "nano",
9
+ "banana",
10
+ "pro",
11
+ "image-generator",
12
+ "google-gemini",
13
+ "gemini-api",
14
+ "text-to-image",
15
+ "image-modification",
16
+ "style-transfer",
17
+ "generative-ai",
18
+ "genmix",
19
+ "clasen"
20
+ ],
7
21
  "type": "commonjs",
8
22
  "main": "index.js",
9
23
  "scripts": {
@@ -11,6 +25,7 @@
11
25
  },
12
26
  "dependencies": {
13
27
  "axios": "^1.13.2",
14
- "hash-factory": "^1.1.2"
28
+ "hash-factory": "^1.1.2",
29
+ "sharp": "^0.33.5"
15
30
  }
16
31
  }
package/demo/.env DELETED
@@ -1 +0,0 @@
1
- GEMINI_API_KEY="AIzaSyDMy_iCPVzMHF3sSrbCYr2K9PO9lHkCPsg"
@@ -1,58 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const hashFactory = require('hash-factory');
4
-
5
- class BaseGenerator {
6
- constructor(config = {}) {
7
- this.config = config;
8
- }
9
-
10
- /**
11
- * Generates a hash from the text prompt.
12
- * @param {string} prompt
13
- * @param {Object} options
14
- * @returns {string}
15
- */
16
- generateHash(prompt, options = { length: 10 }) {
17
- return hashFactory(prompt, options);
18
- }
19
-
20
- /**
21
- * Saves generated images to the specified directory using hashed filenames.
22
- * @param {string[]} images - Array of base64 image strings.
23
- * @param {string} directory - Target directory path.
24
- * @param {string} prompt - The prompt used for generation (to create hash).
25
- * @param {string} [extension='png'] - File extension.
26
- * @returns {string[]} Array of saved file paths.
27
- */
28
- saveImages(images, directory, prompt, extension = 'png') {
29
- if (!images || !Array.isArray(images) || images.length === 0) {
30
- return [];
31
- }
32
-
33
- // Ensure directory exists
34
- if (!fs.existsSync(directory)) {
35
- fs.mkdirSync(directory, { recursive: true });
36
- }
37
-
38
- const savedPaths = [];
39
- const hash = this.generateHash(prompt);
40
-
41
- images.forEach((imgData, index) => {
42
- const base64Data = imgData.replace(/^data:image\/\w+;base64,/, "");
43
- const buffer = Buffer.from(base64Data, 'base64');
44
-
45
- // Using format: hash_index.ext
46
- const fileName = `${hash}_${index + 1}.${extension}`;
47
- const outputPath = path.join(directory, fileName);
48
-
49
- fs.writeFileSync(outputPath, buffer);
50
- savedPaths.push(outputPath);
51
- });
52
-
53
- return savedPaths;
54
- }
55
- }
56
-
57
- module.exports = BaseGenerator;
58
-