This commit is contained in:
2025-10-02 07:35:44 +02:00
8 changed files with 1078 additions and 3116 deletions

View File

@ -57,7 +57,7 @@
}, },
"7": { "7": {
"inputs": { "inputs": {
"seed": 838097333311955, "seed": 920668017513581,
"steps": 8, "steps": 8,
"cfg": 1, "cfg": 1,
"sampler_name": "euler", "sampler_name": "euler",
@ -101,14 +101,56 @@
"title": "VAE Decode" "title": "VAE Decode"
} }
}, },
"9": {
"inputs": {
"font_file": "Alibaba-PuHuiTi-Heavy.ttf",
"font_size": 40,
"border": 32,
"color_theme": "light",
"reel_1": [
"10",
0
]
},
"class_type": "LayerUtility: ImageReelComposit",
"_meta": {
"title": "LayerUtility: Image Reel Composit"
}
},
"10": {
"inputs": {
"image1_text": "Original image",
"image2_text": "Reference",
"image3_text": "Result",
"image4_text": "image4",
"reel_height": 512,
"border": 32,
"image1": [
"11",
1
],
"image2": [
"11",
2
],
"image3": [
"8",
0
]
},
"class_type": "LayerUtility: ImageReel",
"_meta": {
"title": "LayerUtility: Image Reel"
}
},
"11": { "11": {
"inputs": { "inputs": {
"prompt": [ "prompt": [
"21", "21",
0 0
], ],
"enable_resize": true, "enable_resize": false,
"enable_vl_resize": true, "enable_vl_resize": false,
"upscale_method": "lanczos", "upscale_method": "lanczos",
"crop": "disabled", "crop": "disabled",
"instruction": "<|im_start|>system\nDescribe the key features of the input image (color, shape, size, texture, objects, background), then explain how the user's text instruction should alter or modify the image. Generate a new image that meets the user's requirements while maintaining consistency with the original input where appropriate.<|im_end|>\n<|im_start|>user\n{}<|im_end|>\n<|im_start|>assistant\n", "instruction": "<|im_start|>system\nDescribe the key features of the input image (color, shape, size, texture, objects, background), then explain how the user's text instruction should alter or modify the image. Generate a new image that meets the user's requirements while maintaining consistency with the original input where appropriate.<|im_end|>\n<|im_start|>user\n{}<|im_end|>\n<|im_start|>assistant\n",
@ -121,11 +163,11 @@
0 0
], ],
"image1": [ "image1": [
"24", "23",
0 0
], ],
"image2": [ "image2": [
"15", "24",
0 0
] ]
}, },
@ -134,9 +176,18 @@
"title": "TextEncodeQwenImageEditPlus 小志Jason(xiaozhijason)" "title": "TextEncodeQwenImageEditPlus 小志Jason(xiaozhijason)"
} }
}, },
"14": {
"inputs": {
"image": "f81662775bd0e7950e4794933ef4b3d973fbb9c2db397c8b46809797954d0074.png"
},
"class_type": "LoadImage",
"_meta": {
"title": "Load Image"
}
},
"15": { "15": {
"inputs": { "inputs": {
"image": "ComfyUI_00067_.png" "image": "monster_554.png"
}, },
"class_type": "LoadImage", "class_type": "LoadImage",
"_meta": { "_meta": {
@ -145,7 +196,7 @@
}, },
"20": { "20": {
"inputs": { "inputs": {
"filename_prefix": "qwenedit", "filename_prefix": "combined",
"images": [ "images": [
"8", "8",
0 0
@ -158,49 +209,94 @@
}, },
"21": { "21": {
"inputs": { "inputs": {
"value": "change camera angle to closeup face from image1, change background to light gray with faing gradient, change face angle to look at directry look at camera" "value": "只提取图2中的怪物怪物站在图1的女生身后使用图1的背景并调整怪物的光线以符合图1。\n\n\n\n\n\n\n"
}, },
"class_type": "PrimitiveStringMultiline", "class_type": "PrimitiveStringMultiline",
"_meta": { "_meta": {
"title": "String (Multiline)" "title": "String (Multiline)"
} }
}, },
"22": {
"inputs": {
"filename_prefix": "ComfyUI",
"images": [
"9",
0
]
},
"class_type": "SaveImage",
"_meta": {
"title": "Save Image"
}
},
"23": {
"inputs": {
"width": [
"25",
0
],
"height": [
"26",
0
],
"upscale_method": "nearest-exact",
"keep_proportion": "stretch",
"pad_color": "0, 0, 0",
"crop_position": "center",
"divisible_by": 2,
"device": "cpu",
"image": [
"14",
0
]
},
"class_type": "ImageResizeKJv2",
"_meta": {
"title": "Resize Image v2"
}
},
"24": { "24": {
"inputs": { "inputs": {
"measurement": "pixels", "width": [
"width": 720, "25",
"height": 1280, 0
"fit": "contain", ],
"method": "nearest-exact", "height": [
"26",
0
],
"upscale_method": "nearest-exact",
"keep_proportion": "stretch",
"pad_color": "0, 0, 0",
"crop_position": "center",
"divisible_by": 2,
"device": "cpu",
"image": [ "image": [
"64", "15",
0 0
] ]
}, },
"class_type": "Image Resize (rgthree)", "class_type": "ImageResizeKJv2",
"_meta": { "_meta": {
"title": "Image Resize (rgthree)" "title": "Resize Image v2"
} }
}, },
"64": { "25": {
"inputs": { "inputs": {
"image": "1337074888177434_1758776251440_2.png" "Number": "1280"
}, },
"class_type": "LoadImage", "class_type": "Int",
"_meta": { "_meta": {
"title": "Load Image" "title": "width"
} }
}, },
"65": { "26": {
"inputs": { "inputs": {
"images": [ "Number": "720"
"24",
0
]
}, },
"class_type": "PreviewImage", "class_type": "Int",
"_meta": { "_meta": {
"title": "Preview Image" "title": "height"
} }
} }
} }

View File

@ -81,9 +81,9 @@ async function convertImageWithFile(
workflow = JSON.parse(await fs.readFile('src/comfyworkflows/edit_image_2_qwen.json', 'utf-8')); workflow = JSON.parse(await fs.readFile('src/comfyworkflows/edit_image_2_qwen.json', 'utf-8'));
workflow['21']['inputs']['value'] = prompt; workflow['21']['inputs']['value'] = prompt;
workflow['24']['inputs']['width'] = size.width; workflow['25']['inputs']['width'] = size.width;
workflow['24']['inputs']['height'] = size.height; workflow['26']['inputs']['height'] = size.height;
workflow['64']['inputs']['image'] = baseFileName; workflow['14']['inputs']['image'] = baseFileName;
workflow['15']['inputs']['image'] = secondFileName; workflow['15']['inputs']['image'] = secondFileName;
const response = await axios.post(`${COMFY_BASE_URL}/prompt`, { prompt: workflow }); const response = await axios.post(`${COMFY_BASE_URL}/prompt`, { prompt: workflow });
@ -97,7 +97,7 @@ async function convertImageWithFile(
} while (!history || Object.keys(history.outputs).length === 0); } while (!history || Object.keys(history.outputs).length === 0);
const files = await fs.readdir(COMFY_OUTPUT_DIR!); const files = await fs.readdir(COMFY_OUTPUT_DIR!);
const generatedFiles = files.filter(file => file.startsWith('qwenedit')); const generatedFiles = files.filter(file => file.startsWith('combined'));
const fileStats = await Promise.all( const fileStats = await Promise.all(
generatedFiles.map(async (file) => { generatedFiles.map(async (file) => {

View File

@ -0,0 +1,78 @@
import * as fs from 'fs';
import * as path from 'path';
import { convertImageWithFile } from '../../lib/image-converter';
import dotenv from 'dotenv';
dotenv.config();
const girlDir = path.join(__dirname, '../../../input/girl');
const monsterDir = path.join(__dirname, '../../../input/monster');
const outputDir = path.join(__dirname, '../../../generated');
const prompt = "只提取图1中的女生把她放在图2的怪物之间。";
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
const comfyBaseUrl = process.env.SERVER2_COMFY_BASE_URL;
const comfyOutputDir = process.env.SERVER2_COMFY_OUTPUT_DIR;
if (!comfyBaseUrl || !comfyOutputDir) {
console.error("Please define SERVER1_COMFY_BASE_URL and SERVER1_COMFY_OUTPUT_DIR in your .env file");
process.exit(1);
}
const comfyInputDir = comfyOutputDir.replace("output", "input");
if (!fs.existsSync(comfyInputDir)) {
fs.mkdirSync(comfyInputDir, { recursive: true });
}
async function combineImages() {
while (true) {
try {
const girlImages = fs.readdirSync(girlDir).filter(file => /\.(jpg|jpeg|png)$/i.test(file));
const monsterImages = fs.readdirSync(monsterDir).filter(file => /\.(jpg|jpeg|png)$/i.test(file));
if (girlImages.length === 0 || monsterImages.length === 0) {
console.log('Input directories are empty. Waiting...');
await new Promise(resolve => setTimeout(resolve, 5000));
continue;
}
const randomGirlImage = girlImages[Math.floor(Math.random() * girlImages.length)];
const randomMonsterImage = monsterImages[Math.floor(Math.random() * monsterImages.length)];
const image1Path = path.join(girlDir, randomGirlImage);
const image2Path = path.join(monsterDir, randomMonsterImage);
// Copy files to comfy input directory
const destImage1Path = path.join(comfyInputDir, randomGirlImage);
const destImage2Path = path.join(comfyInputDir, randomMonsterImage);
fs.copyFileSync(image1Path, destImage1Path);
fs.copyFileSync(image2Path, destImage2Path);
console.log(`Combining ${randomGirlImage} and ${randomMonsterImage}`);
const generatedFilePath = await convertImageWithFile(prompt, randomGirlImage, randomMonsterImage, comfyBaseUrl!, comfyOutputDir!);
if (generatedFilePath && fs.existsSync(generatedFilePath)) {
const timestamp = new Date().getTime();
const newFileName = `combined_${timestamp}.png`;
const newFilePath = path.join(outputDir, newFileName);
fs.renameSync(generatedFilePath, newFilePath);
console.log(`Renamed generated file to ${newFilePath}`);
} else {
console.log("Failed to generate or find the image file.");
}
} catch (error) {
console.error('An error occurred:', error);
}
// Wait for a bit before the next iteration
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
combineImages();

View File

@ -52,7 +52,7 @@ async function generatePhotos() {
try { try {
await generateImage( await generateImage(
`realistic photo of woman, wavy long brown hair, fullbody shot, ${scene.imagePrompt.location},${scene.imagePrompt.angle},${scene.imagePrompt.lighting},${scene.imagePrompt.outfit}`, `Scary realistic photo, ${scene.imagePrompt.location},${scene.imagePrompt.angle},${scene.imagePrompt.lighting},${scene.imagePrompt.outfit}`,
faceFilePath, faceFilePath,
scene.baseImagePath, scene.baseImagePath,
imgFileName, imgFileName,

View File

@ -7,7 +7,7 @@ const promptInstructions = `
Video prompt: No slowmotion, Be creative and generate gengle action scene. Video prompt: No slowmotion, Be creative and generate gengle action scene.
`; `;
6 6
const inputDir = path.resolve(process.cwd(), 'input'); const inputDir = path.resolve(process.cwd(), 'input/static');
const outputFilePath = path.resolve(process.cwd(), 'src/musicspot_generator/v2/scenes.json'); const outputFilePath = path.resolve(process.cwd(), 'src/musicspot_generator/v2/scenes.json');
interface Scene { interface Scene {

View File

@ -7,7 +7,7 @@ import dotenv from 'dotenv';
dotenv.config(); dotenv.config();
const inputFolderPath = path.join(__dirname, '..', '..', '..', 'input'); const inputFolderPath = path.join(__dirname, '..', '..', '..', 'input/static');
const generatedFolderPath = path.join(__dirname, '..', '..', '..', 'generated'); const generatedFolderPath = path.join(__dirname, '..', '..', '..', 'generated');
async function processImages() { async function processImages() {

View File

@ -13,8 +13,8 @@ const PINS_TO_COLLECT = 5;
// Hard-coded user prompt // Hard-coded user prompt
const HARDCODED_USER_PROMPT = process.env.HARDCODED_USER_PROMPT || ` const HARDCODED_USER_PROMPT = process.env.HARDCODED_USER_PROMPT || `
Generate 20 keywords for photos of a girl in scary scene for music video for haloween. All keywords should containe girl in a scene. Generate 20 keywords for photos of a ghotst or monster from all over the world. "Cute Japanese yokai" is mandatory, also add "Realistic photo cute" keyword to all genearated keywords first.
Example output : ["a girl in grave yard,"a girl in scary forest","",... and 20 items in array] Example output : ["Cute Japanese yokai","Realistic photo Cute ghost","Realistic photo cute monster","Realistic photo cute haloween monster","Realistic photo cute haloween ghost"... and 20 items in array]
`; `;
async function getPinUrlsFromPinterest(keyword: string, scrollCount = SCROLL_SEARCH, limit = PINS_TO_COLLECT): Promise<string[]> { async function getPinUrlsFromPinterest(keyword: string, scrollCount = SCROLL_SEARCH, limit = PINS_TO_COLLECT): Promise<string[]> {

File diff suppressed because it is too large Load Diff