Files
7c36f1fb11 feat: Comprehensive enhancement of 682 personality profiles with behavioral modeling (#4)
* feat: Restructure personalities into individual JSON files

- Split mega JSON files into 488 individual personality files
- Each personality in its own named JSON file (e.g., zeekay.json, einstein.json)
- Created comprehensive index.json with all personality references
- Added categories.json for grouping by category
- Built JavaScript loader utilities for easy imports
- Generated README with complete personality index
- Added build and validation scripts for maintenance
- More maintainable and reusable structure for JavaScript imports

* feat: Enhanced scientist profiles and fixed validation issues

- Added detailed fields to 9 major scientist profiles (Einstein, Curie, Darwin, etc.)
- Fixed invalid categories for 7 profiles (changed to valid categories)
- Added parallel validation script with comprehensive checks
- All 487 personality profiles now pass validation
- 100% validation success rate across all categories

* refactor: Complete personality separation and cleanup

- Verified all 487 unique personalities are in individual JSON files
- Archived 11 mega personality collection files for safety
- Fixed duplicate vaclav_havel entry (was counted twice in mega file)
- Profiles directory now contains exactly 487 personality files + 2 index files
- Zero duplicate IDs across all individual files
- Cleaned personalities directory, keeping only individual files
- All personalities properly validated and organized by category

* feat: Add 126 personalities for global representation

- Added 21 African personalities (Nigeria, Kenya, Ethiopia, Tanzania, etc.)
- Added 20 Latin American personalities (Brazil, Argentina, Mexico, Chile, etc.)
- Added 25 Asia-Pacific personalities (Indonesia, Thailand, Philippines, Pakistan, etc.)
- Added 15 Caribbean personalities (Jamaica, Cuba, Haiti, Trinidad, etc.)
- Added 15 Middle Eastern personalities (Turkey, Iran, Israel, Lebanon, etc.)
- Added 20 Eastern European personalities (Poland, Czech, Hungary, Romania, etc.)
- Added 10 Pacific Island personalities (New Zealand, Australia, Hawaii, Samoa, etc.)

Total personalities: 613 (up from 487)
Now includes representation from 100+ countries/territories
Each personality includes OCEAN scores, philosophy, tools/domains, and origin

* feat: enhance 682 personality profiles with comprehensive behavioral modeling

- Added 8 major behavioral modeling categories to each profile:
  - Behavioral traits (values, motivations, fears, strengths, weaknesses, habits, quirks)
  - Cognitive style (thinking patterns, learning, problem-solving, decision-making)
  - Social dynamics (interaction, leadership, conflict, collaboration styles)
  - Communication patterns (verbal style, listening, persuasion, storytelling)
  - Work methodology (planning, execution, attention, pace, persistence)
  - Emotional profile (stability, stress response, empathy, self-awareness)
  - Legacy impact (contributions, influence domains, innovation style)
  - Category-specific attributes (tailored to each personality type)

- Enhanced 682 out of 701 profiles (97.3% success rate)
- Added enhancement metadata tracking (date, version, category used)
- Created comprehensive Python enhancement script for future updates
- Each profile now contains detailed attributes for accurate AI modeling
- Fulfills user request for 'as much extra detail as possible to accurately model all qualities and aspects of each persona'

---------

Co-authored-by: Hanzo Dev <[email protected]>
2025-09-25 16:23:57 -05:00

384 lines
11 KiB
JavaScript
Executable File

#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
// Configuration
const SOURCE_DIR = path.join(__dirname, '..', 'personalities');
const TARGET_DIR = path.join(__dirname, '..', 'personalities_v2');
const SCHEMA_PATH = path.join(__dirname, '..', 'schemas', 'personality.schema.json');
// Category mappings
const CATEGORY_DIRS = {
programmer: 'programmers',
philosopher: 'philosophers',
scientist: 'scientists',
religious: 'religious',
revolutionary: 'revolutionaries',
writer: 'writers',
artist: 'artists',
musician: 'artists',
filmmaker: 'artists',
comedian: 'artists',
architect: 'architects',
athlete: 'athletes',
explorer: 'explorers',
activist: 'activists',
tech_leader: 'leaders',
leader: 'leaders',
statesman: 'leaders',
pioneer: 'pioneers',
mathematician: 'scientists',
special: 'special',
systems: 'programmers',
master: 'programmers',
'language-creator': 'programmers',
historian: 'writers',
gaming: 'programmers',
blockchain: 'programmers',
media: 'leaders',
poet: 'writers'
};
// Initialize directories
function initDirectories() {
// Create main directories
const dirs = [
TARGET_DIR,
path.join(TARGET_DIR, 'index'),
path.join(TARGET_DIR, 'schemas'),
path.join(TARGET_DIR, 'scripts'),
path.join(TARGET_DIR, 'dist'),
path.join(TARGET_DIR, 'dist', 'by-category'),
path.join(TARGET_DIR, 'dist', 'by-tag')
];
// Create category directories
const uniqueDirs = [...new Set(Object.values(CATEGORY_DIRS))];
uniqueDirs.forEach(dir => {
dirs.push(path.join(TARGET_DIR, dir));
});
dirs.forEach(dir => {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
console.log(`Created directory: ${dir}`);
}
});
// Copy schema
const schemaTarget = path.join(TARGET_DIR, 'schemas', 'personality.schema.json');
if (fs.existsSync(SCHEMA_PATH) && !fs.existsSync(schemaTarget)) {
fs.copyFileSync(SCHEMA_PATH, schemaTarget);
console.log('Copied schema file');
}
}
// Convert OCEAN scores to 0-100 scale if needed
function normalizeOcean(ocean) {
const normalized = {};
for (const [key, value] of Object.entries(ocean)) {
// If any value is greater than 100, assume it's on a different scale
normalized[key] = value > 100 ? Math.round(value / 10) : value;
}
return normalized;
}
// Generate ID from name
function generateId(name) {
return name
.toLowerCase()
.replace(/[^a-z0-9\s-]/g, '')
.replace(/\s+/g, '_')
.replace(/-+/g, '_')
.substring(0, 50);
}
// Convert old format to new format
function convertPersonality(oldData, source) {
const id = oldData.id || generateId(oldData.name);
const category = oldData.category || 'special';
// Build new format
const newFormat = {
"$schema": "../schemas/personality.schema.json",
id: id,
name: oldData.name || oldData.display_name,
category: category
};
// Add full name if available
if (oldData.fullName || oldData.programmer) {
newFormat.fullName = oldData.fullName || oldData.programmer;
}
// Add subcategory if makes sense
if (oldData.subcategory) {
newFormat.subcategory = oldData.subcategory;
}
// Generate tags
const tags = [];
if (oldData.tags) {
tags.push(...oldData.tags);
} else {
// Auto-generate some tags
if (category) tags.push(category);
if (oldData.primary_tech) tags.push(...oldData.primary_tech.map(t => t.toLowerCase()));
if (oldData.role) tags.push(...oldData.role.toLowerCase().split(/[&,\s]+/).filter(t => t.length > 2));
}
if (tags.length > 0) {
newFormat.tags = [...new Set(tags)];
}
// Add metadata
const metadata = {};
if (oldData.born || oldData.lived) metadata.born = oldData.born || oldData.lived;
if (oldData.died) metadata.died = oldData.died;
if (oldData.nationality) metadata.nationality = oldData.nationality;
if (oldData.company) metadata.company = oldData.company;
if (oldData.achievements) metadata.achievements = oldData.achievements;
if (oldData.active !== undefined) metadata.active = oldData.active;
if (Object.keys(metadata).length > 0) {
newFormat.metadata = metadata;
}
// OCEAN scores (normalize to 0-100)
if (oldData.ocean) {
newFormat.ocean = normalizeOcean(oldData.ocean);
} else if (oldData.personality && typeof oldData.personality === 'object' && oldData.personality.openness) {
newFormat.ocean = normalizeOcean(oldData.personality);
} else {
// Default OCEAN scores
newFormat.ocean = {
openness: 70,
conscientiousness: 70,
extraversion: 50,
agreeableness: 60,
neuroticism: 40
};
}
// Personality info
const personality = {
summary: oldData.description || oldData.summary || `${category} personality`,
philosophy: oldData.philosophy || oldData.quote || "No philosophy recorded"
};
if (oldData.approach) personality.approach = oldData.approach;
if (oldData.communication) personality.communication = oldData.communication;
if (oldData.style?.communication) personality.communication = oldData.style.communication;
if (oldData.values) personality.values = oldData.values;
if (oldData.principles) personality.values = oldData.principles;
newFormat.personality = personality;
// Technical info (for programmers)
if (category === 'programmer' || category === 'tech_leader' || oldData.primary_tech) {
const technical = {};
if (oldData.languages || oldData.primary_tech) {
technical.languages = oldData.languages || oldData.primary_tech;
}
if (oldData.domains || oldData.tools?.domains) {
technical.domains = oldData.domains || oldData.tools.domains;
}
if (oldData.tools) {
technical.tools = {};
if (oldData.tools.essential) technical.tools.essential = oldData.tools.essential;
if (oldData.tools.preferred) technical.tools.preferred = oldData.tools.preferred;
if (oldData.tools.created) technical.tools.created = oldData.tools.created;
if (oldData.style?.tools) technical.tools.preferred = oldData.style.tools;
}
if (Object.keys(technical).length > 0) {
newFormat.technical = technical;
}
}
// Quotes
if (oldData.quotes) {
newFormat.quotes = oldData.quotes;
} else if (oldData.quote) {
newFormat.quotes = [oldData.quote];
}
// Behavioral traits
if (oldData.behavioral || oldData.contribution_style || oldData.style) {
const behavioral = {};
if (oldData.behavioral?.codeStyle || oldData.style?.code) {
behavioral.codeStyle = oldData.behavioral?.codeStyle || oldData.style.code;
}
if (oldData.behavioral?.reviewStyle || oldData.contribution_style?.review) {
behavioral.reviewStyle = oldData.behavioral?.reviewStyle || oldData.contribution_style.review;
}
if (oldData.behavioral?.workStyle || oldData.style?.approach) {
behavioral.workStyle = oldData.behavioral?.workStyle || oldData.style.approach;
}
if (oldData.behavioral?.collaboration) {
behavioral.collaboration = oldData.behavioral.collaboration;
}
if (Object.keys(behavioral).length > 0) {
newFormat.behavioral = behavioral;
}
}
return newFormat;
}
// Process a single JSON file
function processFile(filePath) {
console.log(`\nProcessing: ${path.basename(filePath)}`);
try {
const content = fs.readFileSync(filePath, 'utf8');
const data = JSON.parse(content);
let personalities = [];
// Handle different formats
if (data.personalities && Array.isArray(data.personalities)) {
personalities = data.personalities;
} else if (data.personas && Array.isArray(data.personas)) {
personalities = data.personas;
} else if (data.name) {
// Single personality file
personalities = [data];
} else {
console.log(` Skipping - unknown format`);
return 0;
}
let count = 0;
personalities.forEach(person => {
try {
const converted = convertPersonality(person, path.basename(filePath));
const targetDir = CATEGORY_DIRS[converted.category] || 'special';
const targetPath = path.join(TARGET_DIR, targetDir, `${converted.id}.json`);
// Check for duplicates
if (fs.existsSync(targetPath)) {
console.log(` Skipping duplicate: ${converted.id}`);
return;
}
// Write the file
fs.writeFileSync(targetPath, JSON.stringify(converted, null, 2));
console.log(` Created: ${targetDir}/${converted.id}.json`);
count++;
} catch (err) {
console.error(` Error converting ${person.name || 'unknown'}: ${err.message}`);
}
});
return count;
} catch (err) {
console.error(` Error reading file: ${err.message}`);
return 0;
}
}
// Generate manifest
function generateManifest() {
console.log('\nGenerating manifest...');
const manifest = {
version: "2.0.0",
generated: new Date().toISOString(),
total: 0,
categories: {},
index: {}
};
// Scan all category directories
const categoryDirs = [...new Set(Object.values(CATEGORY_DIRS))];
categoryDirs.forEach(dir => {
const dirPath = path.join(TARGET_DIR, dir);
if (!fs.existsSync(dirPath)) return;
const files = fs.readdirSync(dirPath).filter(f => f.endsWith('.json'));
if (files.length === 0) return;
const categoryName = Object.keys(CATEGORY_DIRS).find(key => CATEGORY_DIRS[key] === dir) || dir;
const ids = [];
files.forEach(file => {
const filePath = path.join(dirPath, file);
try {
const content = JSON.parse(fs.readFileSync(filePath, 'utf8'));
ids.push(content.id);
manifest.index[content.id] = {
path: path.relative(TARGET_DIR, filePath),
name: content.name,
category: content.category,
tags: content.tags || []
};
manifest.total++;
} catch (err) {
console.error(`Error reading ${file}: ${err.message}`);
}
});
manifest.categories[categoryName] = {
count: ids.length,
path: dir,
ids: ids
};
});
// Write manifest
const manifestPath = path.join(TARGET_DIR, 'index', 'manifest.json');
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
console.log(`Generated manifest with ${manifest.total} personalities`);
return manifest;
}
// Main migration function
async function migrate() {
console.log('Starting migration...\n');
// Initialize directory structure
initDirectories();
// Process all JSON files
const files = fs.readdirSync(SOURCE_DIR).filter(f => f.endsWith('.json'));
let totalConverted = 0;
files.forEach(file => {
const filePath = path.join(SOURCE_DIR, file);
totalConverted += processFile(filePath);
});
console.log(`\nTotal personalities converted: ${totalConverted}`);
// Generate manifest
const manifest = generateManifest();
// Generate category summary
console.log('\nCategory Summary:');
Object.entries(manifest.categories).forEach(([cat, info]) => {
console.log(` ${cat}: ${info.count} personalities`);
});
console.log('\nMigration complete!');
console.log(`Output directory: ${TARGET_DIR}`);
}
// Run migration
if (require.main === module) {
migrate().catch(err => {
console.error('Migration failed:', err);
process.exit(1);
});
}
module.exports = { migrate, convertPersonality };