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 +44 -4
- package/demo/example-translate.js +32 -20
- package/demo/example.js +1 -1
- package/demo/pt/camera_4126.jpg +0 -0
- package/generators/BaseGenerator.js +51 -12
- package/package.json +20 -5
- package/demo/.env +0 -1
- package/demo/genmix/generators/BaseGenerator.js +0 -58
- package/demo/mijb3y7u_transl_this_image_to_5bvpx7.png +0 -0
- package/demo/mijb4azh_add_a_vintag_film_1p04hum.png +0 -0
- package/demo/mijb4azj_add_a_vintag_film_igoidb.png +0 -0
- package/demo/mijb4azk_add_a_vintag_film_11ltrj0.png +0 -0
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: '
|
|
20
|
+
quality: '1K',
|
|
21
21
|
numberOfImages: 1
|
|
22
22
|
}
|
|
23
23
|
);
|
|
24
24
|
|
|
25
25
|
if (result1.images && result1.images.length > 0) {
|
|
26
|
-
|
|
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
|
-
|
|
46
|
+
// // === Option 3: Multiple variations of the same image ===
|
|
47
|
+
// if (fs.existsSync(localImagePath)) {
|
|
48
|
+
// console.log('🎨 Generating multiple variations...\n');
|
|
37
49
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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 {
|
|
25
|
-
* @
|
|
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
|
-
|
|
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
|
-
|
|
52
|
-
|
|
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
|
-
|
|
56
|
-
|
|
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.
|
|
4
|
-
"description": "",
|
|
5
|
-
"license": "
|
|
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
|
-
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|