make-mp-data 2.1.11 → 3.0.2
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.
- package/README.md +31 -0
- package/dungeons/adspend.js +35 -1
- package/dungeons/anon.js +25 -1
- package/dungeons/array-of-object-lookup.js +201 -0
- package/dungeons/benchmark-heavy.js +241 -0
- package/dungeons/benchmark-light.js +141 -0
- package/dungeons/big.js +10 -9
- package/dungeons/business.js +60 -12
- package/dungeons/complex.js +35 -1
- package/dungeons/copilot.js +383 -0
- package/dungeons/education.js +1005 -0
- package/dungeons/experiments.js +18 -4
- package/dungeons/fintech.js +976 -0
- package/dungeons/foobar.js +32 -0
- package/dungeons/food.js +988 -0
- package/dungeons/funnels.js +38 -1
- package/dungeons/gaming.js +26 -5
- package/dungeons/media.js +861 -270
- package/dungeons/mil.js +31 -3
- package/dungeons/mirror.js +33 -1
- package/dungeons/retention-cadence.js +211 -0
- package/dungeons/rpg.js +1178 -0
- package/dungeons/sanity.js +32 -2
- package/dungeons/sass.js +923 -0
- package/dungeons/scd.js +47 -1
- package/dungeons/simple.js +29 -14
- package/dungeons/social.js +928 -0
- package/dungeons/streaming.js +373 -0
- package/dungeons/strict-event-test.js +30 -0
- package/dungeons/student-teacher.js +19 -5
- package/dungeons/text-generation.js +120 -84
- package/dungeons/too-big-events.js +203 -0
- package/dungeons/{userAgent.js → user-agent.js} +23 -2
- package/entry.js +5 -4
- package/index.js +41 -54
- package/lib/core/config-validator.js +122 -7
- package/lib/core/context.js +7 -14
- package/lib/core/storage.js +57 -25
- package/lib/generators/adspend.js +12 -12
- package/lib/generators/events.js +6 -5
- package/lib/generators/funnels.js +32 -10
- package/lib/generators/product-lookup.js +262 -0
- package/lib/generators/product-names.js +195 -0
- package/lib/generators/profiles.js +3 -3
- package/lib/generators/scd.js +13 -3
- package/lib/generators/text.js +17 -4
- package/lib/orchestrators/mixpanel-sender.js +244 -204
- package/lib/orchestrators/user-loop.js +54 -16
- package/lib/templates/phrases.js +473 -16
- package/lib/templates/schema.d.ts +173 -0
- package/lib/templates/verbose-schema.js +140 -206
- package/lib/utils/chart.js +210 -0
- package/lib/utils/function-registry.js +285 -0
- package/lib/utils/json-evaluator.js +172 -0
- package/lib/utils/logger.js +34 -0
- package/lib/utils/utils.js +41 -4
- package/package.json +12 -21
- package/types.d.ts +15 -5
- package/dungeons/ai-chat-analytics-ed.js +0 -274
- package/dungeons/money2020-ed-also.js +0 -277
- package/dungeons/money2020-ed.js +0 -579
- package/lib/generators/text-bak-old.js +0 -1121
- package/lib/orchestrators/worker-manager.js +0 -203
- package/lib/templates/hooks-instructions.txt +0 -434
- package/lib/templates/phrases-bak.js +0 -925
- package/lib/templates/prompt (old).txt +0 -98
- package/lib/templates/schema-instructions.txt +0 -155
- package/lib/templates/scratch-dungeon-template.js +0 -116
- package/lib/templates/textQuickTest.js +0 -172
- package/lib/utils/ai.js +0 -120
- package/lib/utils/project.js +0 -166
package/dungeons/mil.js
CHANGED
|
@@ -4,7 +4,7 @@ import dayjs from 'dayjs';
|
|
|
4
4
|
import utc from 'dayjs/plugin/utc.js';
|
|
5
5
|
dayjs.extend(utc);
|
|
6
6
|
import 'dotenv/config';
|
|
7
|
-
import * as u from
|
|
7
|
+
import * as u from "../lib/utils/utils.js";
|
|
8
8
|
import * as v from 'ak-tools';
|
|
9
9
|
const chance = u.initChance(SEED);
|
|
10
10
|
const num_users = 10_000;
|
|
@@ -44,10 +44,11 @@ const config = {
|
|
|
44
44
|
hasAdSpend: false,
|
|
45
45
|
|
|
46
46
|
hasAvatar: false,
|
|
47
|
+
makeChart: false,
|
|
47
48
|
|
|
48
|
-
batchSize:
|
|
49
|
+
batchSize: 2_500_000,
|
|
49
50
|
concurrency: 10,
|
|
50
|
-
writeToDisk:
|
|
51
|
+
writeToDisk: false,
|
|
51
52
|
|
|
52
53
|
funnels: [],
|
|
53
54
|
|
|
@@ -289,6 +290,33 @@ const config = {
|
|
|
289
290
|
groupProps: {},
|
|
290
291
|
lookupTables: [],
|
|
291
292
|
hook: function (record, type, meta) {
|
|
293
|
+
// event hook: tag events by frequency tier and enrich booleans
|
|
294
|
+
if (type === "event") {
|
|
295
|
+
const highFreq = ["foo", "bar", "baz"];
|
|
296
|
+
const lowFreq = ["crumn", "yak"];
|
|
297
|
+
if (highFreq.includes(record.event)) {
|
|
298
|
+
record.frequency_tier = "high";
|
|
299
|
+
} else if (lowFreq.includes(record.event)) {
|
|
300
|
+
record.frequency_tier = "low";
|
|
301
|
+
} else {
|
|
302
|
+
record.frequency_tier = "medium";
|
|
303
|
+
}
|
|
304
|
+
// boolean super prop drives a derived field
|
|
305
|
+
if (record.boolean === true) {
|
|
306
|
+
record.flag_status = "active";
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// everything hook: users with very few events are marked as churned
|
|
311
|
+
if (type === "everything") {
|
|
312
|
+
if (record.length <= 3) {
|
|
313
|
+
for (const e of record) {
|
|
314
|
+
e.is_churned_user = true;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return record;
|
|
318
|
+
}
|
|
319
|
+
|
|
292
320
|
return record;
|
|
293
321
|
}
|
|
294
322
|
};
|
package/dungeons/mirror.js
CHANGED
|
@@ -14,7 +14,7 @@ import dayjs from "dayjs";
|
|
|
14
14
|
import utc from "dayjs/plugin/utc.js";
|
|
15
15
|
dayjs.extend(utc);
|
|
16
16
|
import { uid, comma } from 'ak-tools';
|
|
17
|
-
import { pickAWinner, weighNumRange, date, integer } from
|
|
17
|
+
import { pickAWinner, weighNumRange, date, integer } from "../lib/utils/utils.js";
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
/** @type {import('../types').Dungeon} */
|
|
@@ -120,6 +120,38 @@ const config = {
|
|
|
120
120
|
groupProps: {},
|
|
121
121
|
lookupTables: [],
|
|
122
122
|
hook: function (record, type, meta) {
|
|
123
|
+
// --- user hook: segment users by spirit animal ---
|
|
124
|
+
if (type === "user") {
|
|
125
|
+
const aquatic = ["whale", "dolphin", "shark", "octopus", "squid", "jellyfish", "seahorse", "crab", "lobster", "shrimp"];
|
|
126
|
+
record.segment = aquatic.includes(record.spiritAnimal) ? "aquatic" : "terrestrial";
|
|
127
|
+
return record;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// --- event hook: color-based property boost ---
|
|
131
|
+
if (type === "event") {
|
|
132
|
+
// warm-colored events get a higher updateMe value
|
|
133
|
+
const warmColors = ["red", "orange", "yellow"];
|
|
134
|
+
if (warmColors.includes(record.color)) {
|
|
135
|
+
record.updateMe = (record.updateMe || 5) + 10;
|
|
136
|
+
}
|
|
137
|
+
return record;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// --- everything hook: inject a "milestone" event for users with 8+ events ---
|
|
141
|
+
if (type === "everything") {
|
|
142
|
+
if (record.length >= 8) {
|
|
143
|
+
const lastEvent = record[record.length - 1];
|
|
144
|
+
record.push({
|
|
145
|
+
event: "milestone_reached",
|
|
146
|
+
time: lastEvent.time,
|
|
147
|
+
user_id: lastEvent.user_id,
|
|
148
|
+
color: lastEvent.color,
|
|
149
|
+
milestone: record.length
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
return record;
|
|
153
|
+
}
|
|
154
|
+
|
|
123
155
|
return record;
|
|
124
156
|
}
|
|
125
157
|
};
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
|
|
2
|
+
const SEED = "kurby-retention";
|
|
3
|
+
import dayjs from 'dayjs';
|
|
4
|
+
import utc from 'dayjs/plugin/utc.js';
|
|
5
|
+
dayjs.extend(utc);
|
|
6
|
+
import * as u from "../lib/utils/utils.js";
|
|
7
|
+
import * as v from 'ak-tools';
|
|
8
|
+
const chance = u.initChance(SEED);
|
|
9
|
+
|
|
10
|
+
const num_users = 100;
|
|
11
|
+
const days = 360;
|
|
12
|
+
|
|
13
|
+
/** @typedef {import("../types.js").Dungeon} Config */
|
|
14
|
+
|
|
15
|
+
// Churn rates by favorite color per behavior type (percentage likelihood)
|
|
16
|
+
const CHURN_RATES = {
|
|
17
|
+
red: { hourly: 15, daily: 40, weekly: 15, monthly: 10 },
|
|
18
|
+
blue: { hourly: 15, daily: 15, weekly: 40, monthly: 10 },
|
|
19
|
+
green: { hourly: 5, daily: 5, weekly: 5, monthly: 5 },
|
|
20
|
+
yellow: { hourly: 15, daily: 15, weekly: 15, monthly: 40 },
|
|
21
|
+
purple: { hourly: 40, daily: 15, weekly: 15, monthly: 10 },
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Behavior cadence definitions: [intervalAmount, intervalUnit, jitterMax, jitterUnit]
|
|
25
|
+
const BEHAVIORS = {
|
|
26
|
+
hourly: { interval: 1, unit: 'hour', jitterMax: 10, jitterUnit: 'minute' },
|
|
27
|
+
daily: { interval: 1, unit: 'day', jitterMax: 2, jitterUnit: 'hour' },
|
|
28
|
+
weekly: { interval: 7, unit: 'day', jitterMax: 12, jitterUnit: 'hour' },
|
|
29
|
+
monthly: { interval: 30, unit: 'day', jitterMax: 2, jitterUnit: 'day' },
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function generateCadencedEvents(behaviorName, cadence, startTime, endTime, churnTime, userId) {
|
|
33
|
+
const events = [];
|
|
34
|
+
let cursor = dayjs(startTime);
|
|
35
|
+
const end = dayjs(endTime);
|
|
36
|
+
|
|
37
|
+
while (cursor.isBefore(end)) {
|
|
38
|
+
if (churnTime && cursor.isAfter(churnTime)) break;
|
|
39
|
+
|
|
40
|
+
const jitter = chance.integer({ min: -cadence.jitterMax, max: cadence.jitterMax });
|
|
41
|
+
const eventTime = cursor.add(jitter, cadence.jitterUnit);
|
|
42
|
+
|
|
43
|
+
if (eventTime.isBefore(end) && eventTime.isAfter(startTime)) {
|
|
44
|
+
events.push({
|
|
45
|
+
event: `${behaviorName} behavior`,
|
|
46
|
+
time: eventTime.toISOString(),
|
|
47
|
+
user_id: userId,
|
|
48
|
+
insert_id: v.uid(12),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
cursor = cursor.add(cadence.interval, cadence.unit);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Insert churn event if user churns on this behavior
|
|
56
|
+
if (churnTime && dayjs(churnTime).isBefore(end)) {
|
|
57
|
+
events.push({
|
|
58
|
+
event: `churn - ${behaviorName} behavior`,
|
|
59
|
+
time: dayjs(churnTime).toISOString(),
|
|
60
|
+
user_id: userId,
|
|
61
|
+
insert_id: v.uid(12),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return events;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** @type {Config} */
|
|
69
|
+
const config = {
|
|
70
|
+
token: "",
|
|
71
|
+
seed: "lets go",
|
|
72
|
+
numDays: days,
|
|
73
|
+
numEvents: num_users * 50,
|
|
74
|
+
numUsers: num_users,
|
|
75
|
+
hasAnonIds: false,
|
|
76
|
+
hasSessionIds: false,
|
|
77
|
+
format: "json",
|
|
78
|
+
alsoInferFunnels: false,
|
|
79
|
+
hasLocation: false,
|
|
80
|
+
hasAndroidDevices: false,
|
|
81
|
+
hasIOSDevices: false,
|
|
82
|
+
hasDesktopDevices: false,
|
|
83
|
+
hasBrowser: false,
|
|
84
|
+
hasCampaigns: false,
|
|
85
|
+
isAnonymous: false,
|
|
86
|
+
hasAdSpend: false,
|
|
87
|
+
hasAvatar: false,
|
|
88
|
+
makeChart: false,
|
|
89
|
+
batchSize: 5_500_000,
|
|
90
|
+
concurrency: 10,
|
|
91
|
+
writeToDisk: false,
|
|
92
|
+
percentUsersBornInDataset: 100,
|
|
93
|
+
|
|
94
|
+
funnels: [],
|
|
95
|
+
|
|
96
|
+
events: [
|
|
97
|
+
{
|
|
98
|
+
event: "first behavior",
|
|
99
|
+
weight: 1,
|
|
100
|
+
isFirstEvent: true,
|
|
101
|
+
properties: {},
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
event: "hourly behavior",
|
|
105
|
+
weight: 40,
|
|
106
|
+
properties: {},
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
event: "daily behavior",
|
|
110
|
+
weight: 30,
|
|
111
|
+
properties: {},
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
event: "weekly behavior",
|
|
115
|
+
weight: 15,
|
|
116
|
+
properties: {},
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
event: "monthly behavior",
|
|
120
|
+
weight: 10,
|
|
121
|
+
properties: {},
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
event: "placeholder",
|
|
125
|
+
weight: 50,
|
|
126
|
+
properties: {},
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
|
|
130
|
+
superProps: {},
|
|
131
|
+
|
|
132
|
+
userProps: {
|
|
133
|
+
"favorite color": ["red", "blue", "green", "yellow", "purple"],
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
scdProps: {},
|
|
137
|
+
mirrorProps: {},
|
|
138
|
+
groupKeys: [],
|
|
139
|
+
groupProps: {},
|
|
140
|
+
lookupTables: [],
|
|
141
|
+
|
|
142
|
+
hook: function (record, type, meta) {
|
|
143
|
+
if (type === "everything") {
|
|
144
|
+
if (!record.length) return record;
|
|
145
|
+
|
|
146
|
+
const userId = record[0].user_id || record[0].device_id;
|
|
147
|
+
if (!userId) return record;
|
|
148
|
+
|
|
149
|
+
const favoriteColor = meta.profile?.["favorite color"] || "green";
|
|
150
|
+
const colorChurnRates = CHURN_RATES[favoriteColor] || CHURN_RATES.green;
|
|
151
|
+
|
|
152
|
+
// Find the time range from the raw events
|
|
153
|
+
const times = record.map(e => new Date(e.time).getTime()).filter(t => !isNaN(t));
|
|
154
|
+
if (!times.length) return record;
|
|
155
|
+
const startTime = dayjs(Math.min(...times));
|
|
156
|
+
const endTime = dayjs(Math.max(...times));
|
|
157
|
+
const totalSpanHours = endTime.diff(startTime, 'hour');
|
|
158
|
+
|
|
159
|
+
if (totalSpanHours < 1) return record;
|
|
160
|
+
|
|
161
|
+
// Keep the "first behavior" event from the original stream
|
|
162
|
+
const firstBehavior = record.find(e => e.event === "first behavior");
|
|
163
|
+
const newEvents = [];
|
|
164
|
+
|
|
165
|
+
if (firstBehavior) {
|
|
166
|
+
newEvents.push(firstBehavior);
|
|
167
|
+
} else {
|
|
168
|
+
// Create a first behavior event at the start
|
|
169
|
+
newEvents.push({
|
|
170
|
+
event: "first behavior",
|
|
171
|
+
time: startTime.toISOString(),
|
|
172
|
+
user_id: userId,
|
|
173
|
+
insert_id: v.uid(12),
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// For each behavior type, determine churn and generate cadenced events
|
|
178
|
+
for (const [behaviorKey, cadence] of Object.entries(BEHAVIORS)) {
|
|
179
|
+
const churnRate = colorChurnRates[behaviorKey];
|
|
180
|
+
let churnTime = null;
|
|
181
|
+
|
|
182
|
+
if (chance.bool({ likelihood: churnRate })) {
|
|
183
|
+
// Pick churn time between 20% and 80% into the active period
|
|
184
|
+
const churnOffsetHours = chance.integer({
|
|
185
|
+
min: Math.floor(totalSpanHours * 0.2),
|
|
186
|
+
max: Math.floor(totalSpanHours * 0.8),
|
|
187
|
+
});
|
|
188
|
+
churnTime = startTime.add(churnOffsetHours, 'hour');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const behaviorEvents = generateCadencedEvents(
|
|
192
|
+
behaviorKey,
|
|
193
|
+
cadence,
|
|
194
|
+
startTime,
|
|
195
|
+
endTime,
|
|
196
|
+
churnTime,
|
|
197
|
+
userId
|
|
198
|
+
);
|
|
199
|
+
newEvents.push(...behaviorEvents);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Sort all events by time
|
|
203
|
+
newEvents.sort((a, b) => new Date(a.time) - new Date(b.time));
|
|
204
|
+
return newEvents;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return record;
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
export default config;
|