save changes
This commit is contained in:
@ -11,6 +11,7 @@ import puppeteer from 'puppeteer';
|
||||
import { VideoModel } from './lib/db/video';
|
||||
|
||||
dotenv.config();
|
||||
const RUN_ONCE = (process.env.RUN_ONCE || 'false').toLowerCase() === 'true';
|
||||
|
||||
const USE_REFERENCE_IMAGE = (process.env.USE_REFERENCE_IMAGE || 'true').toLowerCase() === 'true';
|
||||
|
||||
@ -69,16 +70,15 @@ async function callOpenAIWithFileAndExtract(imagePath: string, prompt: string, m
|
||||
return null;
|
||||
}
|
||||
const servers = [
|
||||
|
||||
{
|
||||
baseUrl: process.env.SERVER1_COMFY_BASE_URL,
|
||||
outputDir: process.env.SERVER1_COMFY_OUTPUT_DIR,
|
||||
},
|
||||
/*
|
||||
{
|
||||
baseUrl: process.env.SERVER2_COMFY_BASE_URL,
|
||||
outputDir: process.env.SERVER2_COMFY_OUTPUT_DIR,
|
||||
},
|
||||
*/
|
||||
].filter((s): s is { baseUrl: string; outputDir: string } => !!s.baseUrl && !!s.outputDir);
|
||||
|
||||
interface GenerationTask {
|
||||
@ -135,6 +135,7 @@ Decide which single action type best fits this scene from the list:
|
||||
- micro animation (animate object but small movement)
|
||||
- big movement
|
||||
- impossible movement
|
||||
- Dance ( if its woman portrait )
|
||||
|
||||
Return exactly one JSON object and nothing else: { "actiontype": "..." }.
|
||||
Do not add commentary. Choose the single best option from the list above.
|
||||
@ -272,7 +273,7 @@ async function generateImageForTask(task: GenerationTask, server: { baseUrl: str
|
||||
imageFileName,
|
||||
baseUrl,
|
||||
outputDir,
|
||||
{ width: 720, height: 1280 }
|
||||
{ width: 1280, height: 720 }
|
||||
);
|
||||
return generatedImagePath;
|
||||
} else {
|
||||
@ -283,7 +284,7 @@ async function generateImageForTask(task: GenerationTask, server: { baseUrl: str
|
||||
baseUrl,
|
||||
outputDir,
|
||||
'qwen',
|
||||
{ width: 720, height: 1280 }
|
||||
{ width: 1280, height: 720 }
|
||||
);
|
||||
return generatedImagePath;
|
||||
}
|
||||
@ -379,7 +380,7 @@ async function getPinUrlFromPinterest(keyword: string): Promise<string | null> {
|
||||
});
|
||||
*/
|
||||
allKeywords = allKeywords.filter(a => {
|
||||
return (a.genre == "city")
|
||||
return (a.genre == "epic")
|
||||
});
|
||||
|
||||
function shuffle<T>(arr: T[]): T[] {
|
||||
@ -471,7 +472,7 @@ async function getPinUrlFromPinterest(keyword: string): Promise<string | null> {
|
||||
}
|
||||
}
|
||||
|
||||
const numberOfPinIds = 20;
|
||||
const numberOfPinIds = Number(process.env.NUMBER_OF_PINIDS) || 20;
|
||||
// Build keywords list with single chosen pinId per selected subGenre
|
||||
const keywords: {
|
||||
genre: string; subGenre: string; pinIds: string[], videoInstructions?: string[]
|
||||
@ -493,45 +494,64 @@ async function getPinUrlFromPinterest(keyword: string): Promise<string | null> {
|
||||
return;
|
||||
}
|
||||
|
||||
type pinIdsType = {
|
||||
pinId: string,
|
||||
genreSubGenre: { genre: string, subGenre: string, pinIds: string[], videoInstructions: string[] }
|
||||
};
|
||||
|
||||
while (true) {
|
||||
|
||||
const generationTasks: GenerationTask[] = [];
|
||||
const allPinIds: pinIdsType[] = keywords.reduce<pinIdsType[]>((acc, curr) => {
|
||||
const videoInstructions = curr.videoInstructions ?? [];
|
||||
for (const id of curr.pinIds ?? []) {
|
||||
acc.push({
|
||||
pinId: id,
|
||||
genreSubGenre: {
|
||||
genre: curr.genre,
|
||||
subGenre: curr.subGenre,
|
||||
pinIds: curr.pinIds,
|
||||
videoInstructions,
|
||||
},
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
const pickedUpPinIds: pinIdsType[] = shuffle(allPinIds).slice(0, 30);
|
||||
|
||||
for (const genreSubGenre of keywords) {
|
||||
for (const row of pickedUpPinIds) {
|
||||
|
||||
const { genre, subGenre } = genreSubGenre;
|
||||
const { genreSubGenre, pinId } = row;
|
||||
const genre = genreSubGenre.genre;
|
||||
const subGenre = genreSubGenre.subGenre;
|
||||
|
||||
const pickedUpPinIds = shuffle<string>(genreSubGenre.pinIds).slice(0, 2);
|
||||
const pin = `https://www.pinterest.com/pin/${pinId}/`;
|
||||
logger.info(`--- Starting processing for pin: ${pin} ---`);
|
||||
|
||||
for (const pinId of pickedUpPinIds) {
|
||||
// download images from the pin page (pass desired count as second arg)
|
||||
const downloadedImagePaths = await downloadOneImageFromPin(pin, 20);
|
||||
if (!downloadedImagePaths || downloadedImagePaths.length === 0) {
|
||||
logger.warn(`No images were downloaded for pin ${pin}. Skipping.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const pin = `https://www.pinterest.com/pin/${pinId}/`;
|
||||
logger.info(`--- Starting processing for pin: ${pin} ---`);
|
||||
const selectedImages = downloadedImagePaths.sort(() => 0.5 - Math.random()).slice(0, 2);
|
||||
logger.info(`--- Downloaded ${selectedImages.length} image(s) for processing ---`);
|
||||
|
||||
// download images from the pin page (pass desired count as second arg)
|
||||
const downloadedImagePaths = await downloadOneImageFromPin(pin, 20);
|
||||
if (!downloadedImagePaths || downloadedImagePaths.length === 0) {
|
||||
logger.warn(`No images were downloaded for pin ${pin}. Skipping.`);
|
||||
continue;
|
||||
// proceed if we have at least one image
|
||||
if (selectedImages.length >= 1) {
|
||||
const task = await getPromptsForImage(selectedImages, pin, genre, subGenre, genreSubGenre.videoInstructions);
|
||||
if (task) {
|
||||
task.videoInstructions = genreSubGenre.videoInstructions;
|
||||
generationTasks.push(task);
|
||||
}
|
||||
|
||||
const selectedImages = downloadedImagePaths.sort(() => 0.5 - Math.random()).slice(0, 2);
|
||||
logger.info(`--- Downloaded ${selectedImages.length} image(s) for processing ---`);
|
||||
|
||||
// proceed if we have at least one image
|
||||
if (selectedImages.length >= 1) {
|
||||
const task = await getPromptsForImage(selectedImages, pin, genre, subGenre, genreSubGenre.videoInstructions);
|
||||
if (task) {
|
||||
task.videoInstructions = genreSubGenre.videoInstructions;
|
||||
generationTasks.push(task);
|
||||
}
|
||||
} else {
|
||||
logger.warn(`Skipping pin ${pin} as it did not yield images.`);
|
||||
for (const imagePath of selectedImages) {
|
||||
try {
|
||||
await fs.unlink(imagePath);
|
||||
} catch (error) {
|
||||
logger.error(`Failed to delete image ${imagePath}:`, error);
|
||||
}
|
||||
} else {
|
||||
logger.warn(`Skipping pin ${pin} as it did not yield images.`);
|
||||
for (const imagePath of selectedImages) {
|
||||
try {
|
||||
await fs.unlink(imagePath);
|
||||
} catch (error) {
|
||||
logger.error(`Failed to delete image ${imagePath}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -572,7 +592,7 @@ async function getPinUrlFromPinterest(keyword: string): Promise<string | null> {
|
||||
videoFileName,
|
||||
server.baseUrl,
|
||||
server.outputDir,
|
||||
{ width: 720, height: 1280 }
|
||||
{ width: 1280, height: 720 }
|
||||
);
|
||||
|
||||
if (videoPath) {
|
||||
@ -618,5 +638,9 @@ async function getPinUrlFromPinterest(keyword: string): Promise<string | null> {
|
||||
}
|
||||
logger.info("--- Finished video generation ---");
|
||||
|
||||
if (RUN_ONCE) {
|
||||
logger.info('RUN_ONCE=true - exiting after a single iteration of generation.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user