make-mp-data 2.0.22 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dungeons/ai-chat-analytics-ed.js +274 -0
  2. package/dungeons/business.js +0 -1
  3. package/dungeons/complex.js +0 -1
  4. package/dungeons/experiments.js +0 -1
  5. package/dungeons/gaming.js +47 -14
  6. package/dungeons/media.js +5 -6
  7. package/dungeons/mil.js +296 -0
  8. package/dungeons/money2020-ed-also.js +277 -0
  9. package/dungeons/money2020-ed.js +579 -0
  10. package/dungeons/sanity.js +0 -1
  11. package/dungeons/scd.js +0 -1
  12. package/dungeons/simple.js +57 -18
  13. package/dungeons/student-teacher.js +0 -1
  14. package/dungeons/text-generation.js +706 -0
  15. package/dungeons/userAgent.js +1 -2
  16. package/entry.js +4 -0
  17. package/index.js +63 -38
  18. package/lib/cli/cli.js +7 -8
  19. package/lib/core/config-validator.js +11 -13
  20. package/lib/core/context.js +13 -1
  21. package/lib/core/storage.js +45 -13
  22. package/lib/generators/adspend.js +1 -1
  23. package/lib/generators/events.js +18 -17
  24. package/lib/generators/funnels.js +293 -240
  25. package/lib/generators/text-bak-old.js +1121 -0
  26. package/lib/generators/text.js +1173 -0
  27. package/lib/orchestrators/mixpanel-sender.js +1 -1
  28. package/lib/templates/abbreviated.d.ts +13 -3
  29. package/lib/templates/defaults.js +311 -169
  30. package/lib/templates/hooks-instructions.txt +434 -0
  31. package/lib/templates/phrases-bak.js +925 -0
  32. package/lib/templates/phrases.js +2066 -0
  33. package/lib/templates/{instructions.txt → schema-instructions.txt} +78 -1
  34. package/lib/templates/scratch-dungeon-template.js +1 -1
  35. package/lib/templates/textQuickTest.js +172 -0
  36. package/lib/utils/ai.js +51 -2
  37. package/lib/utils/utils.js +145 -7
  38. package/package.json +8 -5
  39. package/types.d.ts +322 -7
  40. package/lib/utils/chart.js +0 -206
package/types.d.ts CHANGED
@@ -20,7 +20,7 @@ export interface Dungeon {
20
20
  epochEnd?: number;
21
21
  numEvents?: number;
22
22
  numUsers?: number;
23
- format?: "csv" | "json" | string;
23
+ format?: "csv" | "json" | "parquet" | string;
24
24
  region?: "US" | "EU";
25
25
  concurrency?: number;
26
26
  batchSize?: number;
@@ -30,7 +30,6 @@ export interface Dungeon {
30
30
  projectId?: string;
31
31
 
32
32
  // ids
33
- simulationName?: string;
34
33
  name?: string;
35
34
 
36
35
  //switches
@@ -44,11 +43,11 @@ export interface Dungeon {
44
43
  hasDesktopDevices?: boolean;
45
44
  hasBrowser?: boolean;
46
45
  writeToDisk?: boolean | string;
46
+ gzip?: boolean;
47
47
  verbose?: boolean;
48
48
  hasAnonIds?: boolean;
49
49
  hasSessionIds?: boolean;
50
50
  alsoInferFunnels?: boolean;
51
- makeChart?: boolean | string;
52
51
  singleCountry?: string;
53
52
 
54
53
  //models
@@ -117,7 +116,7 @@ export interface hookArrayOptions<T> {
117
116
  hook?: Hook<T>;
118
117
  type?: hookTypes;
119
118
  filename?: string;
120
- format?: "csv" | "json" | string;
119
+ format?: "csv" | "json" | "parquet" | string;
121
120
  concurrency?: number;
122
121
  context?: Context;
123
122
  [key: string]: any;
@@ -179,6 +178,8 @@ export interface Defaults {
179
178
  desktopDevices: () => any[];
180
179
  browsers: () => any[];
181
180
  campaigns: () => any[];
181
+ devicePools: { android: any[]; ios: any[]; desktop: any[] };
182
+ allDevices:any[];
182
183
  }
183
184
 
184
185
  /**
@@ -311,11 +312,16 @@ export interface Funnel {
311
312
  * funnel properties go onto each event in the funnel and are held constant
312
313
  */
313
314
  props?: Record<string, ValueValid>;
315
+ /**
316
+ * funnel conditions (user properties) are used to filter users who are eligible for the funnel
317
+ * these conditions must match the current user's profile for the user to be eligible for the funnel
318
+ */
319
+ conditions?: Record<string, ValueValid>;
314
320
  /**
315
- * funnel conditions (user properties) are used to filter users who are eligible for the funnel
316
- * these conditions must match the current user's profile for the user to be eligible for the funnel
321
+ * If true, the funnel will be part of an experiment where we generate 3 variants of the funnel with different conversion rates
322
+ *
317
323
  */
318
- conditions?: Record<string, ValueValid>;
324
+ experiment?: boolean;
319
325
  }
320
326
 
321
327
  /**
@@ -430,3 +436,312 @@ export type Result = {
430
436
  declare function main(config: Dungeon): Promise<Result>;
431
437
 
432
438
  export default main;
439
+
440
+ // ============= Text Generator Types =============
441
+
442
+ /**
443
+ * Sentiment tone of generated text
444
+ */
445
+ export type TextTone = "pos" | "neg" | "neu";
446
+
447
+ /**
448
+ * Style of text generation
449
+ *
450
+ * Supported styles:
451
+ * - "support": Customer support tickets and requests
452
+ * - "review": Product reviews and ratings
453
+ * - "search": Search queries and keywords
454
+ * - "feedback": User feedback and suggestions
455
+ * - "chat": Casual chat messages and conversations
456
+ * - "email": Formal email communications
457
+ * - "forum": Forum posts and discussions
458
+ * - "comments": Social media comments and reactions
459
+ * - "tweet": Twitter-style social media posts
460
+ */
461
+ export type TextStyle = "support" | "review" | "search" | "feedback" | "chat" | "email" | "forum" | "comments" | "tweet";
462
+
463
+ /**
464
+ * Emotional intensity level
465
+ */
466
+ export type TextIntensity = "low" | "medium" | "high";
467
+
468
+ /**
469
+ * Language formality level
470
+ */
471
+ export type TextFormality = "casual" | "business" | "technical";
472
+
473
+ /**
474
+ * Output format for batch generation
475
+ */
476
+ export type TextReturnType = "strings" | "objects";
477
+
478
+ /**
479
+ * Domain-specific keywords to inject into generated text
480
+ *
481
+ * Common predefined categories include:
482
+ * - features: Product features to mention
483
+ * - products: Product/company names
484
+ * - competitors: Competitor names for comparisons
485
+ * - technical: Technical terms and jargon
486
+ * - versions: Version numbers and releases
487
+ * - errors: Specific error messages or codes
488
+ * - metrics: Business metrics or KPIs
489
+ * - events: Event types (e.g., 'wedding', 'celebration', 'conference')
490
+ * - emotions: Emotional descriptors (e.g., 'inspiring', 'heartwarming')
491
+ * - issues: Common problems or issues
492
+ * - team: Team or role references
493
+ * - business_impact: Business impact phrases
494
+ * - comparisons: Comparison phrases
495
+ * - credibility: Credibility markers
496
+ * - user_actions: User action descriptions
497
+ * - specific_praise: Specific positive details
498
+ * - specific_issues: Specific negative details
499
+ * - error_messages: Error message text
500
+ * - categories: General categories
501
+ * - brands: Brand names
502
+ * - vendors: Vendor references
503
+ * - services: Service types
504
+ * - locations: Location references
505
+ *
506
+ * Custom categories can be added as needed.
507
+ */
508
+ export interface TextKeywordSet {
509
+ /** Product features to mention */
510
+ features?: string[];
511
+ /** Product/company names */
512
+ products?: string[];
513
+ /** Competitor names for comparisons */
514
+ competitors?: string[];
515
+ /** Technical terms and jargon */
516
+ technical?: string[];
517
+ /** Version numbers and releases */
518
+ versions?: string[];
519
+ /** Specific error messages or codes */
520
+ errors?: string[];
521
+ /** Business metrics or KPIs */
522
+ metrics?: string[];
523
+ /** Event types (e.g., 'wedding', 'celebration', 'conference') */
524
+ events?: string[];
525
+ /** Emotional descriptors (e.g., 'inspiring', 'heartwarming') */
526
+ emotions?: string[];
527
+ /** Common problems or issues */
528
+ issues?: string[];
529
+ /** Team or role references */
530
+ team?: string[];
531
+ /** Business impact phrases */
532
+ business_impact?: string[];
533
+ /** Comparison phrases */
534
+ comparisons?: string[];
535
+ /** Credibility markers */
536
+ credibility?: string[];
537
+ /** User action descriptions */
538
+ user_actions?: string[];
539
+ /** Specific positive details */
540
+ specific_praise?: string[];
541
+ /** Specific negative details */
542
+ specific_issues?: string[];
543
+ /** Error message text */
544
+ error_messages?: string[];
545
+ /** General categories */
546
+ categories?: string[];
547
+ /** Brand names */
548
+ brands?: string[];
549
+ /** Vendor references */
550
+ vendors?: string[];
551
+ /** Service types */
552
+ services?: string[];
553
+ /** Location references */
554
+ locations?: string[];
555
+ /** Allow any custom keyword category */
556
+ [key: string]: string[] | undefined;
557
+ }
558
+
559
+ /**
560
+ * Configuration for text generator instance
561
+ */
562
+ export interface TextGeneratorConfig {
563
+ /** Default sentiment tone */
564
+ tone?: TextTone;
565
+ /** Type of text to generate */
566
+ style?: TextStyle;
567
+ /** Emotional intensity */
568
+ intensity?: TextIntensity;
569
+ /** Language formality */
570
+ formality?: TextFormality;
571
+ /** Minimum text length in characters */
572
+ min?: number;
573
+ /** Maximum text length in characters */
574
+ max?: number;
575
+ /** RNG seed for reproducibility */
576
+ seed?: string;
577
+ /** Domain-specific keywords to inject */
578
+ keywords?: TextKeywordSet;
579
+ /** Probability of keyword injection (0-1) */
580
+ keywordDensity?: number;
581
+ /** Enable realistic typos */
582
+ typos?: boolean;
583
+ /** Base typo probability per word */
584
+ typoRate?: number;
585
+ /** Allow sentiment mixing for realism */
586
+ mixedSentiment?: boolean;
587
+ /** Amount of authentic markers (0-1) */
588
+ authenticityLevel?: number;
589
+ /** Add timestamps to some messages */
590
+ timestamps?: boolean;
591
+ /** Include user role/experience markers */
592
+ userPersona?: boolean;
593
+ /** Allow sentiment to drift during generation (0-1) */
594
+ sentimentDrift?: number;
595
+ /** Add metadata to generated text */
596
+ includeMetadata?: boolean;
597
+ /** How specific/detailed to make claims (0-1) */
598
+ specificityLevel?: number;
599
+ /** Filter near-duplicates */
600
+ enableDeduplication?: boolean;
601
+ /** Max generation attempts per item */
602
+ maxAttempts?: number;
603
+ // performanceMode removed - system is always optimized for speed + uniqueness
604
+ }
605
+
606
+ /**
607
+ * Metadata for generated text
608
+ */
609
+ export interface TextMetadata {
610
+ /** Timestamp if enabled */
611
+ timestamp?: string;
612
+ /** Sentiment analysis score */
613
+ sentimentScore?: number;
614
+ /** Keywords that were injected */
615
+ injectedKeywords?: string[];
616
+ /** User persona information */
617
+ persona?: Record<string, any>;
618
+ /** Flesch reading ease score */
619
+ readabilityScore?: number;
620
+ /** Text style used */
621
+ style?: TextStyle | string;
622
+ /** Intensity level used */
623
+ intensity?: TextIntensity | string;
624
+ /** Formality level used */
625
+ formality?: TextFormality | string;
626
+ }
627
+
628
+ /**
629
+ * Simple generated text object (without metadata)
630
+ */
631
+ export interface SimpleGeneratedText {
632
+ /** The generated text */
633
+ text: string;
634
+ /** Actual tone of generated text */
635
+ tone: TextTone | string;
636
+ }
637
+
638
+ /**
639
+ * Generated text with metadata
640
+ */
641
+ export interface GeneratedText {
642
+ /** The generated text */
643
+ text: string;
644
+ /** Actual tone of generated text */
645
+ tone: TextTone | string;
646
+ /** Additional metadata */
647
+ metadata?: TextMetadata;
648
+ }
649
+
650
+ /**
651
+ * Options for batch text generation
652
+ */
653
+ export interface TextBatchOptions {
654
+ /** Number of items to generate */
655
+ n: number;
656
+ /** Output format */
657
+ returnType?: TextReturnType;
658
+ /** Override tone for this batch */
659
+ tone?: TextTone;
660
+ /** Generate related/coherent items */
661
+ related?: boolean;
662
+ /** Shared context/topic for related items */
663
+ sharedContext?: string;
664
+ }
665
+
666
+ /**
667
+ * Statistics for text generator performance
668
+ */
669
+ export interface TextGeneratorStats {
670
+ /** Configuration used */
671
+ config: TextGeneratorConfig;
672
+ /** Total items generated */
673
+ generatedCount: number;
674
+ /** Items that were duplicates */
675
+ duplicateCount: number;
676
+ /** Items that failed generation */
677
+ failedCount: number;
678
+ /** Average generation time per item */
679
+ avgGenerationTime: number;
680
+ /** Total generation time */
681
+ totalGenerationTime: number;
682
+ }
683
+
684
+ /**
685
+ * Text generator instance interface
686
+ */
687
+ export interface TextGenerator {
688
+ /** Generate a single text item */
689
+ generateOne(): string | GeneratedText | null;
690
+ /** Generate multiple text items in batch */
691
+ generateBatch(options: TextBatchOptions): (string | GeneratedText | SimpleGeneratedText)[];
692
+ /** Get generation statistics */
693
+ getStats(): TextGeneratorStats;
694
+ }
695
+
696
+ /**
697
+ * Creates a new text generator instance
698
+ * @param config - Configuration options for the generator
699
+ * @returns Text generator instance
700
+ */
701
+ export declare function createGenerator(config?: TextGeneratorConfig): TextGenerator;
702
+
703
+ /**
704
+ * Generate a batch of text items directly (standalone function)
705
+ * @param options - Combined generator config and batch options
706
+ * @returns Array of generated text items
707
+ */
708
+ export declare function generateBatch(options: TextGeneratorConfig & TextBatchOptions): (string | GeneratedText | SimpleGeneratedText)[];
709
+
710
+ // ============= Additional Utility Types =============
711
+
712
+ /**
713
+ * File path configuration for data generation output
714
+ */
715
+ export interface WritePaths {
716
+ eventFiles: string[];
717
+ userFiles: string[];
718
+ adSpendFiles: string[];
719
+ scdFiles: string[];
720
+ mirrorFiles: string[];
721
+ groupFiles: string[];
722
+ lookupFiles: string[];
723
+ folder: string;
724
+ }
725
+
726
+ /**
727
+ * Configuration for TimeSoup time distribution function
728
+ */
729
+ export interface TimeSoupOptions {
730
+ earliestTime?: number;
731
+ latestTime?: number;
732
+ peaks?: number;
733
+ deviation?: number;
734
+ mean?: number;
735
+ }
736
+
737
+ /**
738
+ * Test context configuration for unit/integration tests
739
+ */
740
+ export interface TestContext {
741
+ config: Dungeon;
742
+ storage: Storage | null;
743
+ defaults: Defaults;
744
+ campaigns: any[];
745
+ runtime: RuntimeState;
746
+ [key: string]: any;
747
+ }
@@ -1,206 +0,0 @@
1
- /** @typedef {import('../../types.js').EventSchema} EventSchema */
2
- /** @typedef {import('../../types.js').Result} Result */
3
- /** @typedef {import('../../types.js').Context} Context */
4
-
5
- import { ChartJSNodeCanvas } from 'chartjs-node-canvas';
6
- import fs from 'fs';
7
- import * as u from 'ak-tools';
8
- import dayjs from 'dayjs';
9
- import { openFinder } from './utils.js';
10
- const { existsSync } = fs;
11
- import path from 'path';
12
- import 'dotenv/config';
13
- const { NODE_ENV = "unknown" } = process.env;
14
-
15
-
16
- let tempDir;
17
- const dataFolder = path.resolve("./data");
18
- if (existsSync(dataFolder)) tempDir = dataFolder;
19
- else tempDir = path.resolve("./");
20
-
21
-
22
- // Function to count events per day
23
- function countDailyEvents(eventData) {
24
- const dailyCounts = {};
25
-
26
- eventData.forEach(event => {
27
- const date = dayjs(event.time).format('YYYY-MM-DD');
28
- if (!dailyCounts[date]) {
29
- dailyCounts[date] = 0;
30
- }
31
- dailyCounts[date]++;
32
- });
33
-
34
- return dailyCounts;
35
- }
36
-
37
- // Function to count daily users
38
- function countDailyUsers(eventData) {
39
- const dailyUsers = {};
40
-
41
- eventData.forEach(event => {
42
- const date = dayjs(event.time).format('YYYY-MM-DD');
43
- if (!dailyUsers[date]) {
44
- dailyUsers[date] = new Set();
45
- }
46
- dailyUsers[date].add(event.user_id);
47
- });
48
-
49
- return dailyUsers;
50
- }
51
-
52
- // Function to count daily new users based on signup events
53
- function countDailyNewUsers(eventData, signupEvents) {
54
- const dailyNewUsers = {};
55
- const seenUsers = new Set();
56
-
57
- eventData.forEach(event => {
58
- const date = dayjs(event.time).format('YYYY-MM-DD');
59
- if (!dailyNewUsers[date]) {
60
- dailyNewUsers[date] = new Set();
61
- }
62
- if (signupEvents.includes(event.event) && !seenUsers.has(event.user_id)) {
63
- dailyNewUsers[date].add(event.user_id);
64
- seenUsers.add(event.user_id);
65
- }
66
- });
67
-
68
- return dailyNewUsers;
69
- }
70
-
71
- // Function to generate line chart
72
- async function generateLineChart(rawData, signupEvents = ["sign up"], fileName) {
73
- const width = 1600;
74
- const height = 1200;
75
- const chartJSNodeCanvas = new ChartJSNodeCanvas({ width, height, backgroundColour: 'black' });
76
- const eventData = countDailyEvents(rawData);
77
- const userData = countDailyUsers(rawData);
78
- const newUserData = countDailyNewUsers(rawData, signupEvents);
79
-
80
- // @ts-ignore
81
- const sortedEventEntries = Object.entries(eventData).sort((a, b) => new Date(a[0]) - new Date(b[0]));
82
- const eventLabels = sortedEventEntries.map(entry => entry[0]);
83
- const eventValues = sortedEventEntries.map(entry => entry[1]);
84
-
85
- // @ts-ignore
86
- const sortedUserEntries = Object.entries(userData).sort((a, b) => new Date(a[0]) - new Date(b[0]));
87
- const userLabels = sortedUserEntries.map(entry => entry[0]);
88
- const userValues = sortedUserEntries.map(entry => entry[1].size);
89
-
90
- // @ts-ignore
91
- const sortedNewUserEntries = Object.entries(newUserData).sort((a, b) => new Date(a[0]) - new Date(b[0]));
92
- const newUserLabels = sortedNewUserEntries.map(entry => entry[0]);
93
- const newUserValues = sortedNewUserEntries.map(entry => entry[1].size);
94
-
95
- const configuration = {
96
- type: 'line',
97
- data: {
98
- labels: eventLabels,
99
- datasets: [
100
- {
101
- label: '# EVENTS',
102
- data: eventValues,
103
- yAxisID: 'y1',
104
- fill: true,
105
- borderColor: '#4F44E0',
106
- tension: 0.1
107
- },
108
- // {
109
- // label: '# USERS',
110
- // data: userValues,
111
- // yAxisID: 'y2',
112
- // fill: true,
113
- // borderColor: '#E34F2F',
114
- // tension: 0.1
115
- // },
116
- {
117
- label: '# NEW',
118
- data: newUserValues,
119
- yAxisID: 'y3',
120
- fill: true,
121
- borderColor: '#219464',
122
- tension: 0.1
123
- }
124
- ]
125
- },
126
- options: {
127
- scales: {
128
- x: {
129
- title: {
130
- display: true,
131
- text: 'Date',
132
- color: 'white'
133
- },
134
- ticks: {
135
- color: 'white'
136
- }
137
- },
138
- y1: {
139
- type: 'linear',
140
- display: true,
141
- position: 'left',
142
- title: {
143
- display: true,
144
- text: 'Count of Events',
145
- color: '#4F44E0'
146
- },
147
- ticks: {
148
- color: '#4F44E0'
149
- }
150
- },
151
- y3: {
152
- type: 'linear',
153
- display: true,
154
- position: 'right',
155
- offset: true,
156
- title: {
157
- display: true,
158
- text: 'Count of New Users',
159
- color: '#219464'
160
- },
161
- ticks: {
162
- color: '#219464'
163
- },
164
- grid: {
165
- drawOnChartArea: false
166
- }
167
- }
168
- },
169
- plugins: {
170
- legend: {
171
- labels: {
172
- color: 'white'
173
- }
174
- }
175
- }
176
- }
177
- };
178
-
179
- // @ts-ignore
180
- if (typeof fileName === undefined) fileName = 'chart';
181
- if (typeof fileName !== 'string') fileName = 'chart';
182
- // @ts-ignore
183
- const imageBuffer = await chartJSNodeCanvas.renderToBuffer(configuration);
184
- const filePath = path.join(tempDir, `${fileName}.png`);
185
- const removed = await u.rm(filePath);
186
- // @ts-ignore - imageBuffer is a Buffer but touch accepts it
187
- const file = await u.touch(filePath, imageBuffer);
188
-
189
- console.log(`Chart saved as ${fileName}.png`);
190
- openFinder(path)
191
- return file;
192
- }
193
-
194
- export { generateLineChart };
195
-
196
-
197
-
198
- if (import.meta.url === `file://${process.argv[1]}`) {
199
- generateLineChart()
200
- .then((result)=>{
201
- if (NODE_ENV === "dev") debugger;
202
- })
203
- .catch((error)=>{
204
- if (NODE_ENV === "dev") debugger;
205
- })
206
- }