save changes
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,7 @@ import puppeteer from 'puppeteer';
|
|||||||
import { VideoModel } from './lib/db/video';
|
import { VideoModel } from './lib/db/video';
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
const RUN_ONCE = (process.env.RUN_ONCE || 'false').toLowerCase() === 'true';
|
||||||
|
|
||||||
const USE_REFERENCE_IMAGE = (process.env.USE_REFERENCE_IMAGE || 'true').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;
|
return null;
|
||||||
}
|
}
|
||||||
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,
|
||||||
},
|
},
|
||||||
*/
|
|
||||||
].filter((s): s is { baseUrl: string; outputDir: string } => !!s.baseUrl && !!s.outputDir);
|
].filter((s): s is { baseUrl: string; outputDir: string } => !!s.baseUrl && !!s.outputDir);
|
||||||
|
|
||||||
interface GenerationTask {
|
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)
|
- micro animation (animate object but small movement)
|
||||||
- big movement
|
- big movement
|
||||||
- impossible movement
|
- impossible movement
|
||||||
|
- Dance ( if its woman portrait )
|
||||||
|
|
||||||
Return exactly one JSON object and nothing else: { "actiontype": "..." }.
|
Return exactly one JSON object and nothing else: { "actiontype": "..." }.
|
||||||
Do not add commentary. Choose the single best option from the list above.
|
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,
|
imageFileName,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
outputDir,
|
outputDir,
|
||||||
{ width: 720, height: 1280 }
|
{ width: 1280, height: 720 }
|
||||||
);
|
);
|
||||||
return generatedImagePath;
|
return generatedImagePath;
|
||||||
} else {
|
} else {
|
||||||
@ -283,7 +284,7 @@ async function generateImageForTask(task: GenerationTask, server: { baseUrl: str
|
|||||||
baseUrl,
|
baseUrl,
|
||||||
outputDir,
|
outputDir,
|
||||||
'qwen',
|
'qwen',
|
||||||
{ width: 720, height: 1280 }
|
{ width: 1280, height: 720 }
|
||||||
);
|
);
|
||||||
return generatedImagePath;
|
return generatedImagePath;
|
||||||
}
|
}
|
||||||
@ -379,7 +380,7 @@ async function getPinUrlFromPinterest(keyword: string): Promise<string | null> {
|
|||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
allKeywords = allKeywords.filter(a => {
|
allKeywords = allKeywords.filter(a => {
|
||||||
return (a.genre == "city")
|
return (a.genre == "epic")
|
||||||
});
|
});
|
||||||
|
|
||||||
function shuffle<T>(arr: T[]): T[] {
|
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
|
// Build keywords list with single chosen pinId per selected subGenre
|
||||||
const keywords: {
|
const keywords: {
|
||||||
genre: string; subGenre: string; pinIds: string[], videoInstructions?: string[]
|
genre: string; subGenre: string; pinIds: string[], videoInstructions?: string[]
|
||||||
@ -493,45 +494,64 @@ async function getPinUrlFromPinterest(keyword: string): Promise<string | null> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type pinIdsType = {
|
||||||
|
pinId: string,
|
||||||
|
genreSubGenre: { genre: string, subGenre: string, pinIds: string[], videoInstructions: string[] }
|
||||||
|
};
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
const generationTasks: GenerationTask[] = [];
|
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}/`;
|
const selectedImages = downloadedImagePaths.sort(() => 0.5 - Math.random()).slice(0, 2);
|
||||||
logger.info(`--- Starting processing for pin: ${pin} ---`);
|
logger.info(`--- Downloaded ${selectedImages.length} image(s) for processing ---`);
|
||||||
|
|
||||||
// download images from the pin page (pass desired count as second arg)
|
// proceed if we have at least one image
|
||||||
const downloadedImagePaths = await downloadOneImageFromPin(pin, 20);
|
if (selectedImages.length >= 1) {
|
||||||
if (!downloadedImagePaths || downloadedImagePaths.length === 0) {
|
const task = await getPromptsForImage(selectedImages, pin, genre, subGenre, genreSubGenre.videoInstructions);
|
||||||
logger.warn(`No images were downloaded for pin ${pin}. Skipping.`);
|
if (task) {
|
||||||
continue;
|
task.videoInstructions = genreSubGenre.videoInstructions;
|
||||||
|
generationTasks.push(task);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
const selectedImages = downloadedImagePaths.sort(() => 0.5 - Math.random()).slice(0, 2);
|
logger.warn(`Skipping pin ${pin} as it did not yield images.`);
|
||||||
logger.info(`--- Downloaded ${selectedImages.length} image(s) for processing ---`);
|
for (const imagePath of selectedImages) {
|
||||||
|
try {
|
||||||
// proceed if we have at least one image
|
await fs.unlink(imagePath);
|
||||||
if (selectedImages.length >= 1) {
|
} catch (error) {
|
||||||
const task = await getPromptsForImage(selectedImages, pin, genre, subGenre, genreSubGenre.videoInstructions);
|
logger.error(`Failed to delete image ${imagePath}:`, error);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -572,7 +592,7 @@ async function getPinUrlFromPinterest(keyword: string): Promise<string | null> {
|
|||||||
videoFileName,
|
videoFileName,
|
||||||
server.baseUrl,
|
server.baseUrl,
|
||||||
server.outputDir,
|
server.outputDir,
|
||||||
{ width: 720, height: 1280 }
|
{ width: 1280, height: 720 }
|
||||||
);
|
);
|
||||||
|
|
||||||
if (videoPath) {
|
if (videoPath) {
|
||||||
@ -618,5 +638,9 @@ async function getPinUrlFromPinterest(keyword: string): Promise<string | null> {
|
|||||||
}
|
}
|
||||||
logger.info("--- Finished video generation ---");
|
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