Explore advanced patterns for custom distributions, validation, serialization, and extending the Persona SDK for complex use cases.
Custom Distributions
Create your own distribution classes by extending BaseDistribution:
custom-distribution.ts
1import { BaseDistribution } from '@jamesaphoenix/persona-sdk';2
3// Custom triangular distribution4export class TriangularDistribution extends BaseDistribution<number> {5 constructor(6 private readonly min: number,7 private readonly max: number,8 private readonly mode: number,9 seed?: number10 ) {11 super(seed);12 if (min >= max || mode < min || mode > max) {13 throw new Error('Invalid triangular distribution parameters');14 }15 }16
17 sample(): number {18 const u = this.random.real(0, 1, false);19 const F = (this.mode - this.min) / (this.max - this.min);20 21 if (u < F) {22 return this.min + Math.sqrt(u * (this.max - this.min) * (this.mode - this.min));23 } else {24 return this.max - Math.sqrt((1 - u) * (this.max - this.min) * (this.max - this.mode));25 }26 }27
28 mean(): number {29 return (this.min + this.max + this.mode) / 3;30 }31
32 variance(): number {33 const a = this.min, b = this.max, c = this.mode;34 return (a*a + b*b + c*c - a*b - a*c - b*c) / 18;35 }36
37 toString(): string {38 return `Triangular(${this.min}, ${this.max}, ${this.mode})`;39 }40}41
42// Use in PersonaBuilder43const persona = PersonaBuilder.create()44 .withAge(new TriangularDistribution(22, 65, 35)) // Most people around 3545 .withName('Professional')46 .build();
Validation & Constraints
Add validation rules and constraints to ensure data quality:
validation.ts
1import { PersonaBuilder, ValidationRule } from '@jamesaphoenix/persona-sdk';2
3// Custom validation rules4const ageValidation: ValidationRule = {5 attribute: 'age',6 validate: (value: any) => {7 if (typeof value !== 'number' || value < 0 || value > 120) {8 throw new Error('Age must be between 0 and 120');9 }10 return true;11 }12};13
14const emailValidation: ValidationRule = {15 attribute: 'email',16 validate: (value: any) => {17 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;18 if (typeof value !== 'string' || !emailRegex.test(value)) {19 throw new Error('Invalid email format');20 }21 return true;22 }23};24
25// Builder with validation26const persona = PersonaBuilder.create()27 .withValidation([ageValidation, emailValidation])28 .withAge(28)29 .withAttribute('email', 'alice@example.com')30 .withAttribute('salary', 75000)31 .addConstraint('salary', (value) => value > 0 && value < 1000000)32 .build();33
34// Validation runs automatically during build()35console.log('Persona created with valid data:', persona.toObject());
Serialization & Persistence
Save and load personas with complete state preservation:
serialization.ts
1import { PersonaGroup, PersonaSerializer } from '@jamesaphoenix/persona-sdk';2
3// Create and populate group4const group = new PersonaGroup('Engineering Team');5group.add(PersonaBuilder.create()6 .withName('Alice')7 .withAge(28)8 .withOccupation('Developer')9 .build()10);11
12// Serialize to JSON13const serialized = PersonaSerializer.serialize(group);14console.log('Serialized:', JSON.stringify(serialized, null, 2));15
16// Save to file17await PersonaSerializer.saveToFile(group, 'team.json');18
19// Load from file20const loadedGroup = await PersonaSerializer.loadFromFile('team.json');21console.log('Loaded group:', loadedGroup.name, loadedGroup.size);22
23// Serialize with distributions (preserves random state)24const builderWithDistribution = PersonaBuilder.create()25 .withAge(new NormalDistribution(35, 5, 12345)) // with seed26 .withName('Random Employee');27
28const serializedBuilder = PersonaSerializer.serializeBuilder(builderWithDistribution);29const restoredBuilder = PersonaSerializer.deserializeBuilder(serializedBuilder);30
31// Both builders will generate identical personas32const persona1 = builderWithDistribution.build();33const persona2 = restoredBuilder.build();34console.log('Ages match:', persona1.age === persona2.age);
Performance Optimization
Optimize for large-scale persona generation:
performance.ts
1import { PersonaGroup, BatchGenerator } from '@jamesaphoenix/persona-sdk';2
3// Batch generation for performance4const batchGenerator = new BatchGenerator({5 batchSize: 1000,6 parallelWorkers: 4,7 memoryLimit: '512MB'8});9
10// Generate 100,000 personas efficiently11const largeGroup = await batchGenerator.generate(100000, {12 template: PersonaBuilder.create()13 .withAge(new NormalDistribution(35, 10))14 .withOccupation(new CategoricalDistribution([15 { value: 'Engineer', probability: 0.4 },16 { value: 'Designer', probability: 0.3 },17 { value: 'Manager', probability: 0.3 }18 ])),19 nameTemplate: 'Employee',20 correlations: [21 { attribute1: 'age', attribute2: 'salary', correlation: 0.6 }22 ]23});24
25console.log(`Generated ${largeGroup.size} personas in batches`);26
27// Stream processing for memory efficiency28const stream = batchGenerator.createStream(PersonaBuilder.create()29 .withAge(new UniformDistribution(25, 65))30 .withName('Streamed Persona')31);32
33let count = 0;34for await (const persona of stream) {35 // Process each persona without storing all in memory36 console.log(`Processing persona ${++count}: ${persona.name}`);37 38 if (count >= 10000) break; // Process 10k personas39}
Plugin System
Extend functionality with custom plugins:
plugins.ts
1import { PersonaPlugin, PersonaBuilder } from '@jamesaphoenix/persona-sdk';2
3// Create a plugin for generating realistic names4class RealisticNamesPlugin implements PersonaPlugin {5 name = 'realistic-names';6 7 async install(builder: PersonaBuilder) {8 // Add methods to builder9 builder.withRealisticName = (demographics: {10 ethnicity?: string;11 gender?: string;12 region?: string;13 }) => {14 const name = this.generateRealisticName(demographics);15 return builder.withName(name);16 };17 }18 19 private generateRealisticName(demographics: any): string {20 // Implementation would use name databases21 // This is a simplified example22 const firstNames = {23 'male': ['James', 'John', 'Robert', 'Michael'],24 'female': ['Mary', 'Patricia', 'Jennifer', 'Linda']25 };26 27 const lastNames = ['Smith', 'Johnson', 'Williams', 'Brown'];28 29 const first = firstNames[demographics.gender]?.[0] || 'Alex';30 const last = lastNames[0];31 32 return `${first} ${last}`;33 }34}35
36// Register and use plugin37PersonaBuilder.use(new RealisticNamesPlugin());38
39const persona = PersonaBuilder.create()40 .withRealisticName({ gender: 'female', ethnicity: 'hispanic' })41 .withAge(30)42 .build();43
44console.log('Generated realistic persona:', persona.name);
⚡ Performance Tips
- • Use seeded distributions for reproducible results
- • Batch generate for large datasets (>1000 personas)
- • Stream processing for memory-constrained environments
- • Cache compiled distributions for repeated use
- • Use Web Workers for client-side parallel generation
🔒 Security & Privacy
- • Never include real PII in synthetic personas
- • Use differential privacy for sensitive correlations
- • Validate all inputs in custom distributions
- • Sanitize generated data before persistence
- • Audit persona data for potential privacy leaks