save changes

This commit is contained in:
2025-09-10 12:59:50 +02:00
parent 9e056b752d
commit 0521b28626
5 changed files with 109 additions and 85 deletions

View File

@ -23,8 +23,8 @@
}, },
"3": { "3": {
"inputs": { "inputs": {
"width": 320, "width": 720,
"height": 640, "height": 1280,
"batch_size": 1 "batch_size": 1
}, },
"class_type": "EmptySD3LatentImage", "class_type": "EmptySD3LatentImage",
@ -34,7 +34,7 @@
}, },
"4": { "4": {
"inputs": { "inputs": {
"seed": 803508963683741, "seed": 844515265883614,
"steps": 20, "steps": 20,
"cfg": 1, "cfg": 1,
"sampler_name": "euler", "sampler_name": "euler",
@ -45,7 +45,7 @@
0 0
], ],
"positive": [ "positive": [
"18", "11",
0 0
], ],
"negative": [ "negative": [
@ -127,7 +127,7 @@
}, },
"11": { "11": {
"inputs": { "inputs": {
"strength": 0.20000000000000004, "strength": 0.6000000000000001,
"conditioning": [ "conditioning": [
"14", "14",
0 0
@ -157,7 +157,7 @@
}, },
"13": { "13": {
"inputs": { "inputs": {
"image": "fd2dc3bbc879703b03abf892d4189667.jpg" "image": "7a103725df2576b79c7306f0d3050991.jpg"
}, },
"class_type": "LoadImage", "class_type": "LoadImage",
"_meta": { "_meta": {
@ -166,7 +166,7 @@
}, },
"14": { "14": {
"inputs": { "inputs": {
"text": "Ethereal realistic girl with flowing blue hair, glowing sparkles and stardust, elegant backless dress shimmering with cosmic light, dreamy profile pose, soft glowing skin, fantasy night atmosphere, luminous and magical aesthetic", "text": "scify movie scene",
"clip": [ "clip": [
"1", "1",
0 0
@ -189,52 +189,5 @@
"_meta": { "_meta": {
"title": "Save Image" "title": "Save Image"
} }
},
"16": {
"inputs": {
"image": "a09ee3d44fff05f20c88976555f8fa10.jpg"
},
"class_type": "LoadImage",
"_meta": {
"title": "Load Image 2"
}
},
"17": {
"inputs": {
"crop": "center",
"clip_vision": [
"10",
0
],
"image": [
"16",
0
]
},
"class_type": "CLIPVisionEncode",
"_meta": {
"title": "CLIP Vision Encode"
}
},
"18": {
"inputs": {
"strength": 0.20000000000000004,
"conditioning": [
"11",
0
],
"style_model": [
"8",
0
],
"clip_vision_output": [
"17",
0
]
},
"class_type": "ApplyStyleModelAdjust",
"_meta": {
"title": "Apply Style Model (Adjusted)"
}
} }
} }

View File

@ -14,10 +14,10 @@ interface VideoRecord {
} }
const servers = [ const servers = [
/*{ {
baseUrl: process.env.SERVER1_COMFY_BASE_URL, baseUrl: process.env.SERVER1_COMFY_BASE_URL,
outputDir: process.env.SERVER1_COMFY_OUTPUT_DIR, outputDir: process.env.SERVER1_COMFY_OUTPUT_DIR,
},*/ },
{ {
baseUrl: process.env.SERVER2_COMFY_BASE_URL, baseUrl: process.env.SERVER2_COMFY_BASE_URL,
outputDir: process.env.SERVER2_COMFY_OUTPUT_DIR, outputDir: process.env.SERVER2_COMFY_OUTPUT_DIR,
@ -61,7 +61,7 @@ async function worker(server: any) {
while (true) { while (true) {
await sleep(Math.random() * 3000); // Random delay await sleep(Math.random() * 3000); // Random delay
const videosToProcess = (await query( const videosToProcess = (await query(
"SELECT * FROM video WHERE (video_path IS NULL OR video_path = '') AND modified_at < '2025-08-22' LIMIT 1" "SELECT * FROM video WHERE (image_path IS NULL OR image_path = '') LIMIT 1"
)) as any[]; )) as any[];
if (videosToProcess.length === 0) { if (videosToProcess.length === 0) {

View File

@ -30,7 +30,7 @@ async function generateImage(
workflow['13']['inputs']['image'] = imageName1; workflow['13']['inputs']['image'] = imageName1;
// Set image name // Set image name
workflow['16']['inputs']['image'] = imageName2; //workflow['16']['inputs']['image'] = imageName2;
workflow['3']['inputs']['width'] = size.width; workflow['3']['inputs']['width'] = size.width;
workflow['3']['inputs']['height'] = size.height; workflow['3']['inputs']['height'] = size.height;

View File

@ -3043,7 +3043,7 @@
}, },
{ {
"genre": "fantasy", "genre": "fantasy",
"subGenre": "ddreamy room", "subGenre": "dreamy room",
"pinIds": [ "pinIds": [
"2533343538161690", "2533343538161690",
"22236591907669199", "22236591907669199",
@ -3645,6 +3645,34 @@
"64387469667053244" "64387469667053244"
] ]
}, },
{
"genre": "fantasy",
"subGenre": "Magics",
"pinIds": [
"44332377578826021",
"914862421098890",
"105201341292428725",
"396035361002191644",
"41517627812390162",
"1618549864404055",
"31877109857926612",
"3518505954100471",
"35114072091147253",
"716846465726941759",
"17170042324986575",
"492649953385330",
"2111131072434296",
"11329436558460911",
"281543723928763",
"6122149487574205",
"1337074889544820",
"8655424281626310",
"4292562140536462",
"1970393583505897",
"37436240649695593",
"44332377578826021"
]
},
{ {
"genre": "fashion", "genre": "fashion",
"subGenre": "Accessories", "subGenre": "Accessories",

View File

@ -1,7 +1,8 @@
import { downloadImagesFromPinterestPin } from './lib/downloader'; import { downloadImagesFromPinterestPin } from './lib/downloader';
import { callOpenAIWithFile } from './lib/openai'; import { callOpenAIWithFile } from './lib/openai';
import { generateVideo } from './lib/video-generator'; import { generateVideo } from './lib/video-generator';
import { generateImage } from './lib/image-generator-mix-style'; import { generateImage as generateImageMixStyle } from './lib/image-generator-mix-style';
import { generateImage as generateImage } from './lib/image-generator';
import { logger } from './lib/logger'; import { logger } from './lib/logger';
import * as fs from 'fs/promises'; import * as fs from 'fs/promises';
import dotenv from 'dotenv'; import dotenv from 'dotenv';
@ -11,6 +12,8 @@ import { VideoModel } from './lib/db/video';
dotenv.config(); dotenv.config();
const USE_REFERENCE_IMAGE = (process.env.USE_REFERENCE_IMAGE || 'true').toLowerCase() === 'true';
// Utility: extract JSON substring from a text. // Utility: extract JSON substring from a text.
// Tries fenced ```json``` blocks first, otherwise extracts first {...} span. // Tries fenced ```json``` blocks first, otherwise extracts first {...} span.
@ -248,6 +251,8 @@ async function generateImageForTask(task: GenerationTask, server: { baseUrl: str
const sourceFileNames: string[] = []; const sourceFileNames: string[] = [];
try { try {
if (USE_REFERENCE_IMAGE) {
// Copy renamed source images to the server input directory
for (const sourcePath of renamedImagePaths) { for (const sourcePath of renamedImagePaths) {
const fileName = path.basename(sourcePath); const fileName = path.basename(sourcePath);
const destPath = path.join(inputDir, fileName); const destPath = path.join(inputDir, fileName);
@ -256,11 +261,11 @@ async function generateImageForTask(task: GenerationTask, server: { baseUrl: str
logger.info(`Copied ${sourcePath} to ${destPath}`); logger.info(`Copied ${sourcePath} to ${destPath}`);
} }
// generateImage expects two source files; if we only have one, pass the same one twice // generateImageMixStyle expects two source files; if we only have one, pass the same one twice
const srcA = sourceFileNames[0]; const srcA = sourceFileNames[0];
const srcB = sourceFileNames[1] || sourceFileNames[0]; const srcB = sourceFileNames[1] || sourceFileNames[0];
const generatedImagePath = await generateImage( const generatedImagePath = await generateImageMixStyle(
imagePrompt, imagePrompt,
srcA, srcA,
srcB, srcB,
@ -270,10 +275,23 @@ async function generateImageForTask(task: GenerationTask, server: { baseUrl: str
{ width: 720, height: 1280 } { width: 720, height: 1280 }
); );
return generatedImagePath; return generatedImagePath;
} else {
// Use Pinterest images only to create the prompt; generate final image using the single-image generator
const generatedImagePath = await generateImage(
imagePrompt,
imageFileName,
baseUrl,
outputDir,
'qwen',
{ width: 720, height: 1280 }
);
return generatedImagePath;
}
} catch (error) { } catch (error) {
logger.error(`Failed to generate image for ${imageFileName} on server ${baseUrl}:`, error); logger.error(`Failed to generate image for ${imageFileName} on server ${baseUrl}:`, error);
return null; return null;
} finally { } finally {
// cleanup local renamed images and any files copied to the server input dir
for (const sourcePath of renamedImagePaths) { for (const sourcePath of renamedImagePaths) {
try { try {
await fs.unlink(sourcePath); await fs.unlink(sourcePath);
@ -338,8 +356,30 @@ async function getPinUrlFromPinterest(keyword: string): Promise<string | null> {
return; return;
} }
/*
allKeywords = allKeywords.filter(a => { allKeywords = allKeywords.filter(a => {
return (a.genre == "sports" && a.subGenre == "Motocross") return (a.genre == "city" && a.subGenre == "Bridges") ||
(a.genre == "city" && a.subGenre == "Castles") ||
(a.genre == "city" && a.subGenre == "Cathedrals") ||
(a.genre == "city" && a.subGenre == "Factories") ||
(a.genre == "city" && a.subGenre == "Futuristic Cities") ||
(a.genre == "city" && a.subGenre == "Historic Towns") ||
(a.genre == "city" && a.subGenre == "Libraries") ||
(a.genre == "city" && a.subGenre == "Markets") ||
(a.genre == "city" && a.subGenre == "Modern Plazas") ||
(a.genre == "city" && a.subGenre == "Museums") ||
(a.genre == "city" && a.subGenre == "Palaces") ||
(a.genre == "city" && a.subGenre == "Residential Blocks") ||
(a.genre == "city" && a.subGenre == "Skylines") ||
(a.genre == "city" && a.subGenre == "Stadiums") ||
(a.genre == "city" && a.subGenre == "Street Cafes") ||
(a.genre == "city" && a.subGenre == "Urban Parks") ||
(a.genre == "city" && a.subGenre == "Skyscrapers") ||
(a.genre == "city" && a.subGenre == "Slums")
});
*/
allKeywords = allKeywords.filter(a => {
return (a.genre == "city")
}); });
function shuffle<T>(arr: T[]): T[] { function shuffle<T>(arr: T[]): T[] {
@ -350,7 +390,8 @@ async function getPinUrlFromPinterest(keyword: string): Promise<string | null> {
return arr; return arr;
} }
const selectedEntries = shuffle(allKeywords.slice()).slice(0, Math.min(20, allKeywords.length)); //const selectedEntries = shuffle(allKeywords.slice()).slice(0, Math.min(20, allKeywords.length));
const selectedEntries = allKeywords;
// Download up to `count` images from a pin URL by opening the pin page and scro lling up to 5 times to trigger lazy loading // Download up to `count` images from a pin URL by opening the pin page and scro lling up to 5 times to trigger lazy loading
// Returns an array of saved image paths (may be empty) // Returns an array of saved image paths (may be empty)
@ -459,7 +500,9 @@ async function getPinUrlFromPinterest(keyword: string): Promise<string | null> {
const { genre, subGenre } = genreSubGenre; const { genre, subGenre } = genreSubGenre;
for (const pinId of genreSubGenre.pinIds) { const pickedUpPinIds = shuffle<string>(genreSubGenre.pinIds).slice(0, 2);
for (const pinId of pickedUpPinIds) {
const pin = `https://www.pinterest.com/pin/${pinId}/`; const pin = `https://www.pinterest.com/pin/${pinId}/`;
logger.info(`--- Starting processing for pin: ${pin} ---`); logger.info(`--- Starting processing for pin: ${pin} ---`);