updates
This commit is contained in:
@@ -962,6 +962,68 @@ async function generateSocialPost(npcContent, objectId) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes NPC content and reassigns the biome if needed based on the description
|
||||
* @param {Object} npcContent - The generated NPC content
|
||||
* @returns {Object} The appropriate biome for this NPC
|
||||
*/
|
||||
function matchBiomeToNpcDescription(npcContent) {
|
||||
// Get all textual content to analyze
|
||||
const textToAnalyze = [
|
||||
npcContent.description,
|
||||
npcContent.backstory,
|
||||
npcContent.culturalBackground,
|
||||
npcContent.currentRole
|
||||
].join(' ').toLowerCase();
|
||||
|
||||
// Define environment keywords for each biome
|
||||
const biomeKeywords = {
|
||||
'tropical rainforest': ['jungle', 'rainforest', 'tropical', 'humid', 'lush vegetation', 'tropical forest', 'canopy'],
|
||||
'desert': ['desert', 'sand', 'dune', 'arid', 'dry', 'barren', 'cactus', 'oasis', 'sandstorm'],
|
||||
'savanna': ['savanna', 'grassland', 'prairie', 'plains', 'open field', 'savannah'],
|
||||
'mountain range': ['mountain', 'peak', 'alpine', 'cliff', 'rocky', 'summit', 'highland', 'cave', 'cavern'],
|
||||
'taiga/boreal forest': ['taiga', 'boreal', 'pine forest', 'coniferous', 'pine', 'spruce', 'fir', 'evergreen'],
|
||||
'temperate forest': ['temperate forest', 'woodland', 'deciduous', 'oak', 'maple', 'forest', 'woods'],
|
||||
'coastal region': ['coast', 'beach', 'shore', 'ocean', 'sea', 'aquatic', 'maritime', 'marine', 'underwater', 'coral', 'tide', 'island', 'bay'],
|
||||
'island': ['island', 'archipelago', 'atoll', 'isolated', 'surrounded by water'],
|
||||
'tundra': ['tundra', 'snow', 'ice', 'frozen', 'arctic', 'cold', 'frost', 'glacier', 'blizzard', 'winter', 'icy'],
|
||||
'ancient ruins': ['ruins', 'ancient', 'temple', 'forgotten', 'archaeological', 'historic', 'abandoned', 'stone', 'crumbling']
|
||||
};
|
||||
|
||||
// Count keyword matches for each biome
|
||||
const biomeScores = {};
|
||||
Object.keys(biomeKeywords).forEach(biomeName => {
|
||||
biomeScores[biomeName] = 0;
|
||||
biomeKeywords[biomeName].forEach(keyword => {
|
||||
if (textToAnalyze.includes(keyword)) {
|
||||
biomeScores[biomeName]++;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Find the biome with the highest score
|
||||
let bestMatch = null;
|
||||
let highestScore = 0;
|
||||
|
||||
Object.keys(biomeScores).forEach(biomeName => {
|
||||
if (biomeScores[biomeName] > highestScore) {
|
||||
highestScore = biomeScores[biomeName];
|
||||
bestMatch = biomeName;
|
||||
}
|
||||
});
|
||||
|
||||
// If we have a match with at least one keyword, return that biome
|
||||
if (bestMatch && highestScore > 0) {
|
||||
const matchedBiome = EARTH_BIOMES.find(biome => biome.name === bestMatch);
|
||||
if (matchedBiome) {
|
||||
return matchedBiome;
|
||||
}
|
||||
}
|
||||
|
||||
// If no environmental cues found, return a random biome (original behavior)
|
||||
return EARTH_BIOMES[Math.floor(Math.random() * EARTH_BIOMES.length)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Main job for generating a single NPC
|
||||
* Can be triggered daily or on demand
|
||||
@@ -970,9 +1032,9 @@ Parse.Cloud.job('generateDailyNPC', async (request) => {
|
||||
try {
|
||||
logger.info('🚀 Starting daily NPC generation...');
|
||||
|
||||
// Select a random biome and location for the NPC
|
||||
const selectedBiome = EARTH_BIOMES[Math.floor(Math.random() * EARTH_BIOMES.length)];
|
||||
logger.info(`🌍 Selected biome: ${chalk.green(selectedBiome.name)}`);
|
||||
// Select a random biome initially - this may be updated later based on NPC description
|
||||
const initialBiome = EARTH_BIOMES[Math.floor(Math.random() * EARTH_BIOMES.length)];
|
||||
logger.info(`🌍 Initial biome selection: ${chalk.green(initialBiome.name)}`);
|
||||
|
||||
// Balance villager and magical NPC types - Increase the chance of villager NPCs
|
||||
// Use a weighted selection to ensure we get more villagers
|
||||
@@ -991,56 +1053,33 @@ Parse.Cloud.job('generateDailyNPC', async (request) => {
|
||||
totalWeight += categoryWeights[category];
|
||||
}
|
||||
|
||||
let randomWeight = Math.random() * totalWeight;
|
||||
let selectedCategory = null;
|
||||
// Generate the NPC content initially using the random biome
|
||||
const npcContent = await generateNPCContent(initialBiome);
|
||||
|
||||
for (const category in categoryWeights) {
|
||||
randomWeight -= categoryWeights[category];
|
||||
if (randomWeight <= 0) {
|
||||
selectedCategory = category;
|
||||
break;
|
||||
}
|
||||
// Now analyze the content and match to the appropriate biome
|
||||
const matchedBiome = matchBiomeToNpcDescription(npcContent);
|
||||
|
||||
if (matchedBiome.name !== initialBiome.name) {
|
||||
logger.info(`🔄 Updated biome based on NPC description: ${chalk.yellow(initialBiome.name)} → ${chalk.green(matchedBiome.name)}`);
|
||||
|
||||
// Update the location data to match the new biome
|
||||
npcContent.location = generateLocationInBiome(matchedBiome);
|
||||
} else {
|
||||
logger.info(`✅ Initial biome ${chalk.green(initialBiome.name)} matches NPC description`);
|
||||
}
|
||||
|
||||
// Find the category index in NPC_TYPES
|
||||
const categoryIndex = NPC_TYPES.findIndex(cat => cat.category === selectedCategory);
|
||||
// Continue with the rest of the process using the matched biome
|
||||
const imageFile = await generateNPCImage(npcContent, matchedBiome);
|
||||
const npcObject = await saveNPCToDatabase(npcContent, imageFile);
|
||||
|
||||
// Select a random type from that category
|
||||
const type = NPC_TYPES[categoryIndex].types[Math.floor(Math.random() * NPC_TYPES[categoryIndex].types.length)];
|
||||
// Generate and post to social media with appropriate hashtags
|
||||
await generateSocialPost(npcContent, npcObject.id);
|
||||
|
||||
logger.info(`👤 Selected NPC type: ${chalk.cyan(type)} (${selectedCategory} category)`);
|
||||
|
||||
// Generate NPC content with specified category and type
|
||||
logger.progress('🧠 Generating NPC content with OpenAI...');
|
||||
const npcContent = await generateNPCContent(selectedBiome, {
|
||||
type: type,
|
||||
category: selectedCategory
|
||||
});
|
||||
logger.npc(`✨ Generated NPC: ${chalk.cyan(npcContent.name)} - ${npcContent.title}`);
|
||||
|
||||
// Generate NPC image
|
||||
logger.progress('🎨 Generating NPC image with DALL-E...');
|
||||
const imageFile = await generateNPCImage(npcContent, selectedBiome);
|
||||
logger.image('🖼️ Image generation complete');
|
||||
|
||||
// Save to database
|
||||
logger.progress('💾 Saving NPC to database...');
|
||||
const savedItem = await saveNPCToDatabase(npcContent, imageFile);
|
||||
|
||||
// Trigger social media post if enabled
|
||||
if (process.env.ENABLE_SOCIAL_POSTS === 'true') {
|
||||
logger.webhook('📤 Triggering IFTTT webhook...');
|
||||
await triggerIFTTTWebhook(savedItem);
|
||||
}
|
||||
|
||||
logger.success(`✨ Daily NPC generation complete: ${chalk.cyan(npcContent.name)} - ${chalk.yellow(npcContent.title)}`);
|
||||
return {
|
||||
success: true,
|
||||
name: npcContent.name,
|
||||
title: npcContent.title,
|
||||
socialPost: savedItem.get("socialPost")
|
||||
message: `Generated NPC '${npcContent.name}' in ${matchedBiome.name}`,
|
||||
npcId: npcObject.id
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
logger.error(`Daily NPC generation failed: ${error.message}`);
|
||||
logger.error(`Stack trace: ${error.stack}`);
|
||||
|
||||
@@ -17,7 +17,8 @@ Parse.Cloud.define("searchAssets", async (request) => {
|
||||
.toLowerCase()
|
||||
.split(/\s+/)
|
||||
.filter(term => term.length > 0)
|
||||
.map(term => term.trim());
|
||||
.map(term => term.trim()
|
||||
);
|
||||
|
||||
console.log(`Processing search terms: ${searchTerms.join(', ')}`);
|
||||
|
||||
|
||||
2
h origin new-main:main -f
Normal file
2
h origin new-main:main -f
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
SSUUMMMMAARRYY OOFF LLEESSSS CCOOMMMMAANNDDSS
|
||||
Reference in New Issue
Block a user