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
@@ -0,0 +1,296 @@
1
+
2
+ const SEED = "my-seed";
3
+ import dayjs from 'dayjs';
4
+ import utc from 'dayjs/plugin/utc.js';
5
+ dayjs.extend(utc);
6
+ import 'dotenv/config';
7
+ import * as u from '../lib/utils/utils.js';
8
+ import * as v from 'ak-tools';
9
+ const chance = u.initChance(SEED);
10
+ const num_users = 10_000;
11
+ const days = 125;
12
+
13
+ /** @typedef {import("../types.js").Dungeon} Config */
14
+
15
+ function genIds(numIds = 1000) {
16
+ const ids = [];
17
+ for (let i = 0; i < numIds; i++) {
18
+ ids.push(v.uid());
19
+ }
20
+ return ids;
21
+ }
22
+
23
+ const videoIds = genIds();
24
+ const channelIds = genIds(100);
25
+
26
+ /** @type {Config} */
27
+ const config = {
28
+ token: "",
29
+ seed: `LFG!`, //,
30
+ numDays: days,
31
+ numEvents: num_users * 62,
32
+ numUsers: num_users,
33
+ hasAnonIds: false,
34
+ hasSessionIds: false,
35
+ format: "parquet",
36
+ alsoInferFunnels: false,
37
+ hasLocation: false,
38
+ hasAndroidDevices: true,
39
+ hasIOSDevices: true,
40
+ hasDesktopDevices: true,
41
+ hasBrowser: false,
42
+ hasCampaigns: false,
43
+ isAnonymous: false,
44
+ hasAdSpend: false,
45
+
46
+ hasAvatar: false,
47
+
48
+ batchSize: 1_500_000,
49
+ concurrency: 10,
50
+ writeToDisk: true,
51
+
52
+ funnels: [],
53
+
54
+ events: [
55
+ {
56
+ event: "watch video",
57
+ weight: 55,
58
+ properties: {
59
+ video_id: u.pickAWinner(videoIds),
60
+ "watch percent": u.pickAWinner([
61
+ 25,
62
+ 50,
63
+ 75,
64
+ 100,
65
+ ]),
66
+ "watch time": u.weighNumRange(1, 65, .89, 100),
67
+
68
+ "category": u.pickAWinner([
69
+ "comedy",
70
+ "educational",
71
+ "music",
72
+ "sports",
73
+ "news",
74
+ "gaming",
75
+ "travel",
76
+ ]),
77
+ quality: u.pickAWinner([
78
+ "240p",
79
+ "360p",
80
+ "480p",
81
+ "720p",
82
+ "1080p",
83
+ "4k",
84
+ ], 4),
85
+ autoplay: [
86
+ true,
87
+ false,
88
+ ],
89
+ fullscreen: [
90
+ true,
91
+ false,
92
+ ],
93
+ "ads?": [
94
+ true, true,
95
+ false,
96
+ ],
97
+ },
98
+ },
99
+ {
100
+ event: "like",
101
+ weight: 10,
102
+ properties: {
103
+ video_id: u.pickAWinner(videoIds),
104
+ },
105
+ },
106
+ {
107
+ event: "comment",
108
+ weight: 5,
109
+ properties: {
110
+ video_id: u.pickAWinner(videoIds),
111
+ comment_length: [
112
+ "short",
113
+ "medium",
114
+ "long",
115
+ ],
116
+ },
117
+ },
118
+ {
119
+ event: "share",
120
+ weight: 3,
121
+ properties: {
122
+ video_id: u.pickAWinner(videoIds),
123
+ "share network": u.pickAWinner([
124
+ "facebook",
125
+ "twitter",
126
+ "reddit",
127
+ "email",
128
+ "whatsapp",
129
+ ]),
130
+ },
131
+ },
132
+ {
133
+ event: "search",
134
+ weight: 25,
135
+ properties: {
136
+ search_term: [
137
+ "cats",
138
+ "dogs",
139
+ "tutorial",
140
+ "news",
141
+ "music",
142
+ ],
143
+ "results count": u.pickAWinner([
144
+ 0,
145
+ 1,
146
+ 2,
147
+ 3,
148
+ 4,
149
+ 5,
150
+ 6, 7, 8, 9, 10
151
+ ], 5),
152
+ "search category": [
153
+ "all",
154
+ "channels",
155
+ "playlists",
156
+ ],
157
+ },
158
+ },
159
+ {
160
+ event: "subscribe",
161
+ weight: 7,
162
+ properties: {
163
+ channel_id: u.pickAWinner(genIds()),
164
+ },
165
+ },
166
+ {
167
+ event: "unsubscribe",
168
+ weight: 2,
169
+ properties: {
170
+ channel_id: u.pickAWinner(genIds()),
171
+ },
172
+ },
173
+ {
174
+ event: "create playlist",
175
+ weight: 4,
176
+ properties: {
177
+ "play list name": u.pickAWinner([
178
+ "favorites",
179
+ "watch later",
180
+ "my music",
181
+ "funny videos",
182
+ "educational",
183
+ ]),
184
+ privacy: u.pickAWinner([
185
+ "public",
186
+ "private",
187
+ "unlisted",
188
+ ]),
189
+ },
190
+ },
191
+ {
192
+ event: "account signup",
193
+ weight: 1,
194
+ isFirstEvent: true,
195
+ properties: {
196
+ "sign up method": [
197
+ "email",
198
+ "google",
199
+ "facebook",
200
+ ],
201
+ },
202
+ },
203
+ {
204
+ event: "account login",
205
+ weight: 9,
206
+ properties: {
207
+ "log in method": u.pickAWinner([
208
+ "email",
209
+ "google",
210
+ "facebook",
211
+ ]),
212
+ success: [
213
+ true,
214
+ false,
215
+ ],
216
+ error_message: [
217
+ "incorrect password",
218
+ "user not found",
219
+ "account locked",
220
+ ],
221
+ },
222
+ },
223
+ {
224
+ event: "$experiment_started",
225
+ weight: 5,
226
+ isSessionStartEvent: true,
227
+ properties: {
228
+ "$experiment_type": "ak_ad_hoc",
229
+ "Experiment name": "show results on empty search",
230
+ "Variant name": ["feature enabled", "feature disabled"],
231
+ }
232
+ }
233
+ ],
234
+ superProps: {
235
+ platform: u.pickAWinner([
236
+ "web",
237
+ "ios",
238
+ "android",
239
+ ]),
240
+ network_type: [
241
+ "wifi",
242
+ "cellular",
243
+ ],
244
+ },
245
+ userProps: {
246
+ subscription_status: [
247
+ "free",
248
+ "free",
249
+ "premium",
250
+ ],
251
+ age_range: [
252
+ "13-17",
253
+ "18-24",
254
+ "25-34",
255
+ "35-44",
256
+ "45-54",
257
+ "55+",
258
+ ],
259
+ preferred_genre: u.pickAWinner([
260
+ "comedy",
261
+ "action",
262
+ "drama",
263
+ "sci-fi",
264
+ "horror",
265
+ ]),
266
+ upload_count: [
267
+ 0,
268
+ 1,
269
+ 5,
270
+ 10,
271
+ 20,
272
+ ],
273
+ following_count: [
274
+ 0,
275
+ 10,
276
+ 50,
277
+ 100,
278
+ 500,
279
+ ],
280
+ dark_mode_enabled: [
281
+ true,
282
+ false,
283
+ ],
284
+ },
285
+
286
+ scdProps: {},
287
+ mirrorProps: {},
288
+ groupKeys: [],
289
+ groupProps: {},
290
+ lookupTables: [],
291
+ hook: function (record, type, meta) {
292
+ return record;
293
+ }
294
+ };
295
+
296
+ export default config;
@@ -0,0 +1,277 @@
1
+
2
+
3
+ import dayjs from "dayjs";
4
+ import utc from "dayjs/plugin/utc.js";
5
+ import "dotenv/config";
6
+ import { weighNumRange, range, date, initChance, exhaust, choose, integer, decimal } from "../lib/utils/utils.js";
7
+
8
+ const SEED = "thfdgdsdfsdfdffgdfgank sup hello 2020 money!!!";
9
+ dayjs.extend(utc);
10
+ const chance = initChance(SEED);
11
+ const num_users = 2_000;
12
+ const days = 60;
13
+
14
+ /** @typedef {import("../types.js").Dungeon} Dungeon */
15
+
16
+ /** @type {Dungeon} */
17
+ const dungeon = {
18
+ token: "",
19
+ seed: SEED,
20
+ numDays: days,
21
+ numEvents: num_users * 120,
22
+ numUsers: num_users,
23
+ hasAnonIds: false,
24
+ hasSessionIds: false,
25
+ format: "json",
26
+ alsoInferFunnels: false,
27
+ hasLocation: true,
28
+ hasAndroidDevices: false,
29
+ hasIOSDevices: false,
30
+ hasDesktopDevices: true,
31
+ hasBrowser: true,
32
+ hasCampaigns: true,
33
+ isAnonymous: false,
34
+ hasAdSpend: false,
35
+ percentUsersBornInDataset: 40,
36
+ hasAvatar: true,
37
+
38
+
39
+ batchSize: 1_500_000,
40
+ concurrency: 1,
41
+ writeToDisk: false,
42
+ superProps: {
43
+ version: "3"
44
+ },
45
+ // AI-generated schema content:
46
+ funnels: [
47
+ {
48
+ name: "AI Interaction",
49
+ sequence: [
50
+ "AI: Launch",
51
+ "AI: Prompt Sent",
52
+ "AI: Response Sent",
53
+ "AI: Dismissed"
54
+ ],
55
+ isFirstFunnel: false,
56
+ conversionRate: 38,
57
+ timeToConvert: 5,
58
+ order: "sequential",
59
+ weight: 7,
60
+ props: { "AI Model": ["5-turbo", "5-flash", "5-flagship", "homegrown"] }
61
+ },
62
+ {
63
+ name: "AI Interaction Errors",
64
+ sequence: [
65
+ "AI: Launch",
66
+ "AI: Prompt Sent",
67
+ "AI: Response Sent",
68
+ "AI: API Error",
69
+ "AI: Dismissed"
70
+ ],
71
+ isFirstFunnel: false,
72
+ conversionRate: 27,
73
+ timeToConvert: 5,
74
+ order: "sequential",
75
+ weight: 3,
76
+ props: { "AI Model": ["5-turbo", "5-flash", "5-flagship", "homegrown"] }
77
+ }
78
+ ],
79
+ events: [
80
+ {
81
+ event: "AI: Launch",
82
+ weight: 2,
83
+ properties: {
84
+ entry_point: [
85
+ "dashboard_widget",
86
+ "header_button",
87
+ "in_app_prompt"
88
+ ]
89
+ }
90
+ },
91
+ {
92
+ event: "AI: Prompt Sent",
93
+ weight: 10,
94
+ properties: {
95
+ prompt: [
96
+ "how can I make a dashboard?",
97
+ "what is a funnel?",
98
+ "what drives new users?",
99
+ "show me my top performing campaigns",
100
+ "compare user retention by country"
101
+ ],
102
+ prompt_length: weighNumRange(15, 150)
103
+ }
104
+ },
105
+ {
106
+ event: "AI: Response Sent",
107
+ weight: 10,
108
+ properties: {
109
+ cost: weighNumRange(1, 10, 0.2),
110
+ tokens: weighNumRange(100, 1000, 0.4),
111
+ time_to_generate_ms: weighNumRange(1000, 10000, 0.2)
112
+ }
113
+ },
114
+ {
115
+ event: "AI: Dismissed",
116
+ weight: 2,
117
+ properties: {
118
+ reason: [
119
+ "finished",
120
+ "clicked_away",
121
+ "new_prompt",
122
+ "error"
123
+ ]
124
+ }
125
+ },
126
+ {
127
+ event: "AI: API Error",
128
+ weight: 2,
129
+ properties: {
130
+ error_code: [
131
+ 400,
132
+ 401,
133
+ 429,
134
+ 500,
135
+ 503
136
+ ],
137
+ error_message: [
138
+ "Bad Request",
139
+ "Unauthorized",
140
+ "Too Many Requests",
141
+ "Internal Server Error",
142
+ "Service Unavailable"
143
+ ]
144
+ }
145
+ }
146
+ ],
147
+ userProps: {
148
+ plan_type: [
149
+ "free",
150
+ "pro",
151
+ "pro",
152
+ "enterprise",
153
+ "free"
154
+ ],
155
+ company_size: [
156
+ "1-10",
157
+ "11-50",
158
+ "51-200",
159
+ "201-1000",
160
+ "1000+"
161
+ ],
162
+ account_tier: [
163
+ "Basic",
164
+ "Plus",
165
+ "Premium",
166
+ ],
167
+ created_date: date(365, true, 'YYYY-MM-DD')
168
+ },
169
+
170
+ hook: function (record, type, meta) {
171
+ const NOW = dayjs();
172
+ const FLASH_LAUNCH = NOW.subtract(50, 'day');
173
+ const TURBO_LAUNCH = NOW.subtract(20, 'day');
174
+ const HOMEGROWN_LAUNCH = NOW.subtract(10, 'day');
175
+ const DATE_HOMEGROWN_LAUNCH = NOW.subtract(10, 'day');
176
+ const DATE_HOMEGROWN_IMPROVEMENT = NOW.subtract(5, 'day');
177
+ const OVER_THINGS_GET_BETTER = NOW.subtract(30, 'day');
178
+
179
+ if (type === "event") {
180
+ const EVENT_TIME = dayjs(record.time);
181
+
182
+ if (record.prompt) {
183
+ // calculate prompt length
184
+ record.prompt_length = record.prompt.length;
185
+ }
186
+ // models: "5-turbo", "5-flash", "5-flagship", "homegrown"
187
+ if (record?.["AI Model"]) {
188
+ let modelPool = ["5-flagship"];
189
+ if (EVENT_TIME.isAfter(FLASH_LAUNCH)) modelPool.push("5-flash");
190
+ if (EVENT_TIME.isAfter(TURBO_LAUNCH)) modelPool.push("5-turbo");
191
+ if (EVENT_TIME.isAfter(HOMEGROWN_LAUNCH)) modelPool.push("homegrown");
192
+
193
+ const chosenModel = chance.pickone(modelPool);
194
+ record["AI Model"] = chosenModel;
195
+
196
+ // choose which model based on date + weights
197
+ if (EVENT_TIME.isBefore(DATE_HOMEGROWN_LAUNCH)) {
198
+ if (chosenModel === "homegrown") {
199
+ if (chance.bool({ likelihood: 75 })) {
200
+ record["AI Model"] = "5-flagship";
201
+ }
202
+ }
203
+ }
204
+
205
+ if (EVENT_TIME.isAfter(DATE_HOMEGROWN_LAUNCH)) {
206
+ if (chosenModel !== "homegrown") {
207
+ if (chance.bool({ likelihood: 27 })) {
208
+ record["AI Model"] = "homegrown";
209
+ }
210
+ }
211
+
212
+ if (record["AI Model"] && record["cost"] && record["tokens"]) {
213
+
214
+ // update params
215
+ switch (record["AI Model"]) {
216
+ // 5 turbo is most expensive and slowest
217
+ case "5-turbo":
218
+ record["cost"] *= decimal(1.2, 1.7, 3);
219
+ record["tokens"] *= decimal(1.2, 1.7, 3);
220
+ break;
221
+ // 5 flash is least expensive and fastest
222
+ case "5-flash":
223
+ record["cost"] *= decimal(0.8, 0.8, 3);
224
+ record["tokens"] *= decimal(0.8, 0.8, 3);
225
+ break;
226
+ // 5 flagship is in between in both areas
227
+ case "5-flagship":
228
+ record["cost"] *= decimal(1.0, 1.0, 3);
229
+ record["tokens"] *= decimal(1.0, 1.0, 3);
230
+ break;
231
+ // homegrown is chaotic is chaotic
232
+ case "homegrown":
233
+
234
+ record["cost"] *= decimal(0.5, 2.5, 3);
235
+ record["tokens"] *= decimal(0.5, 2.5, 3);
236
+ if (EVENT_TIME.isBefore(DATE_HOMEGROWN_IMPROVEMENT)) {
237
+ record["cost"] *= decimal(1.2, 5.0, 3);
238
+ record["tokens"] *= decimal(1.2, 3.0, 3);
239
+ }
240
+ if (EVENT_TIME.isAfter(DATE_HOMEGROWN_IMPROVEMENT)) {
241
+ record["cost"] *= decimal(0.5, 1.0, 3);
242
+ record["tokens"] *= decimal(0.5, 0.75, 3);
243
+ }
244
+ break;
245
+ default:
246
+ break;
247
+ }
248
+ }
249
+
250
+ }
251
+ }
252
+
253
+
254
+
255
+ }
256
+ if (type === "funnel-pre") {
257
+ const parsedFirstEventTime = dayjs.unix(meta.firstEventTime);
258
+ if (!parsedFirstEventTime.isValid()) debugger;
259
+ //stupid offset thing we need to do...
260
+ const actualFunnelTime = parsedFirstEventTime.add(NOW.diff(dayjs.unix(global.FIXED_NOW), 'h'), 'h');
261
+ if (actualFunnelTime.isBefore(OVER_THINGS_GET_BETTER)) {
262
+ record.conversionRate *= decimal(0.5, 0.9, 3);
263
+ // record.timeToConvert *= decimal(1.5, 3.0, 3);
264
+ }
265
+ if (actualFunnelTime.isAfter(OVER_THINGS_GET_BETTER)) {
266
+ const distanceDays = Math.min(30, actualFunnelTime.diff(OVER_THINGS_GET_BETTER, 'day'));
267
+ const improvementFactor = 1.0 + (distanceDays / 30) * 0.5;
268
+ // record.timeToConvert *= decimal(0.5, 0.75, 3) / improvementFactor;
269
+ record.conversionRate *= decimal(1.0, 2.0, 4) * improvementFactor;
270
+ }
271
+ }
272
+ return record;
273
+ }
274
+ };
275
+
276
+ export default dungeon;
277
+