make-mp-data 2.1.11 → 3.0.1
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 +2 -2
- package/dungeons/ai-chat-analytics-ed.js +3 -2
- package/dungeons/anon.js +2 -2
- package/dungeons/array-of-object-loopup.js +181 -0
- package/dungeons/benchmark-heavy.js +241 -0
- package/dungeons/benchmark-light.js +141 -0
- package/dungeons/big.js +9 -8
- package/dungeons/business.js +2 -1
- package/dungeons/clinch-agi.js +632 -0
- package/dungeons/complex.js +3 -2
- package/dungeons/copilot.js +383 -0
- package/dungeons/ecommerce-store.js +0 -0
- package/dungeons/experiments.js +5 -4
- package/dungeons/foobar.js +1 -1
- package/dungeons/funnels.js +2 -2
- package/dungeons/gaming.js +3 -2
- package/dungeons/harness/harness-education.js +988 -0
- package/dungeons/harness/harness-fintech.js +976 -0
- package/dungeons/harness/harness-food.js +985 -0
- package/dungeons/harness/harness-gaming.js +1178 -0
- package/dungeons/harness/harness-media.js +961 -0
- package/dungeons/harness/harness-sass.js +923 -0
- package/dungeons/harness/harness-social.js +928 -0
- package/dungeons/kurby.js +211 -0
- package/dungeons/media.js +5 -4
- package/dungeons/mil.js +4 -3
- package/dungeons/mirror.js +2 -2
- package/dungeons/money2020-ed.js +8 -7
- package/dungeons/sanity.js +3 -2
- package/dungeons/scd.js +3 -2
- package/dungeons/simple.js +30 -15
- package/dungeons/strict-event-test.js +30 -0
- package/dungeons/student-teacher.js +3 -2
- package/dungeons/text-generation.js +84 -85
- package/dungeons/too-big-events.js +166 -0
- package/dungeons/uday-schema.json +220 -0
- package/dungeons/userAgent.js +4 -3
- 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/funnels-instructions.txt +272 -0
- package/lib/templates/hook-examples.json +187 -0
- package/lib/templates/hooks-instructions.txt +295 -8
- package/lib/templates/phrases.js +473 -16
- package/lib/templates/refine-instructions.txt +485 -0
- package/lib/templates/schema-instructions.txt +239 -109
- package/lib/templates/schema.d.ts +173 -0
- package/lib/templates/verbose-schema.js +140 -206
- package/lib/utils/ai.js +853 -77
- 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 +38 -0
- package/lib/utils/mixpanel.js +101 -0
- package/lib/utils/project.js +3 -2
- package/lib/utils/utils.js +41 -4
- package/package.json +15 -21
- package/types.d.ts +15 -5
- package/lib/generators/text-bak-old.js +0 -1121
- package/lib/orchestrators/worker-manager.js +0 -203
- package/lib/templates/phrases-bak.js +0 -925
- package/lib/templates/prompt (old).txt +0 -98
- package/lib/templates/scratch-dungeon-template.js +0 -116
- package/lib/templates/textQuickTest.js +0 -172
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side Mixpanel wrapper for AI observability
|
|
3
|
+
*
|
|
4
|
+
* Provides a clean interface for tracking AI job events and usage metrics.
|
|
5
|
+
* Non-blocking - tracking failures are logged but don't affect application flow.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import Mixpanel from 'mixpanel';
|
|
9
|
+
import { serverLogger as logger } from './logger.js';
|
|
10
|
+
|
|
11
|
+
const MIXPANEL_TOKEN = '7608bedf7495b09ac092209387facb52';
|
|
12
|
+
const { NODE_ENV = 'unknown' } = process.env;
|
|
13
|
+
|
|
14
|
+
// Initialize Mixpanel
|
|
15
|
+
let mixpanel = null;
|
|
16
|
+
try {
|
|
17
|
+
mixpanel = Mixpanel.init(MIXPANEL_TOKEN);
|
|
18
|
+
logger.debug('Mixpanel initialized for server-side tracking');
|
|
19
|
+
} catch (error) {
|
|
20
|
+
logger.error({ err: error }, 'Failed to initialize Mixpanel');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Track an event to Mixpanel (server-side)
|
|
25
|
+
* @param {string} eventName - Event name
|
|
26
|
+
* @param {object} properties - Event properties
|
|
27
|
+
* @param {string} [userId] - Optional user ID for distinct_id
|
|
28
|
+
*/
|
|
29
|
+
export function track(eventName, properties = {}, userId = null) {
|
|
30
|
+
if (!mixpanel) {
|
|
31
|
+
logger.warn({ eventName }, 'Mixpanel not initialized, skipping track');
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const trackProps = {
|
|
37
|
+
...properties,
|
|
38
|
+
distinct_id: userId || 'anonymous',
|
|
39
|
+
source: 'dm4-server',
|
|
40
|
+
$insert_id: `${eventName}-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
mixpanel.track(eventName, trackProps);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
// Non-blocking - log but don't throw
|
|
46
|
+
logger.error({ err: error, eventName }, 'Failed to track Mixpanel event');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Track an AI job completion event with structured metadata
|
|
52
|
+
* @param {object} params - AI job parameters
|
|
53
|
+
* @param {string} params.component - AI component (schema, hooks, refine, funnels, generic)
|
|
54
|
+
* @param {string} params.prompt - The prompt sent to the AI
|
|
55
|
+
* @param {object|string} params.response - The AI response
|
|
56
|
+
* @param {number} params.duration_ms - Duration in milliseconds
|
|
57
|
+
* @param {boolean} params.success - Whether the job succeeded
|
|
58
|
+
* @param {string} [params.error] - Error message if failed
|
|
59
|
+
* @param {object} [params.usage] - Token usage from ai.getLastUsage()
|
|
60
|
+
* @param {string} [params.user_id] - User ID for distinct_id
|
|
61
|
+
*/
|
|
62
|
+
export function trackAIJob(params) {
|
|
63
|
+
const {
|
|
64
|
+
component,
|
|
65
|
+
prompt,
|
|
66
|
+
response,
|
|
67
|
+
duration_ms,
|
|
68
|
+
success,
|
|
69
|
+
error = null,
|
|
70
|
+
usage = null,
|
|
71
|
+
user_id = null
|
|
72
|
+
} = params;
|
|
73
|
+
|
|
74
|
+
const responseStr = typeof response === 'string' ? response : JSON.stringify(response);
|
|
75
|
+
|
|
76
|
+
const eventProps = {
|
|
77
|
+
component: `ai-${component}`,
|
|
78
|
+
prompt_preview: prompt?.substring(0, 200) || '',
|
|
79
|
+
prompt_length: prompt?.length || 0,
|
|
80
|
+
output_length: responseStr?.length || 0,
|
|
81
|
+
duration_ms,
|
|
82
|
+
duration_human: `${(duration_ms / 1000).toFixed(2)} seconds`,
|
|
83
|
+
runtime: process.env.RUNTIME_CONTEXT || 'dm4',
|
|
84
|
+
environment: NODE_ENV,
|
|
85
|
+
success,
|
|
86
|
+
error,
|
|
87
|
+
// Token usage (all fields from getLastUsage)
|
|
88
|
+
...(usage && {
|
|
89
|
+
promptTokens: usage.promptTokens,
|
|
90
|
+
responseTokens: usage.responseTokens,
|
|
91
|
+
totalTokens: usage.totalTokens,
|
|
92
|
+
attempts: usage.attempts,
|
|
93
|
+
modelVersion: usage.modelVersion,
|
|
94
|
+
requestedModel: usage.requestedModel,
|
|
95
|
+
}),
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
track('AI Job', eventProps, user_id);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export default { track, trackAIJob };
|
package/lib/utils/project.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import 'dotenv/config';
|
|
2
2
|
import * as akTools from 'ak-tools';
|
|
3
|
+
import { dataLogger as logger } from './logger.js';
|
|
3
4
|
const { rand, makeName } = akTools;
|
|
4
5
|
let { OAUTH_TOKEN = "" } = process.env;
|
|
5
6
|
const { NODE_ENV = "unknown" } = process.env;
|
|
@@ -114,7 +115,7 @@ async function getUser(oauthToken = OAUTH_TOKEN) {
|
|
|
114
115
|
}
|
|
115
116
|
}
|
|
116
117
|
catch (err) {
|
|
117
|
-
|
|
118
|
+
logger.error({ err }, 'Error getting user information');
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
return user;
|
|
@@ -144,7 +145,7 @@ async function addGroupKeys(groupKeyDfns = [], projectId, oauthToken = OAUTH_TOK
|
|
|
144
145
|
results.push(data?.results);
|
|
145
146
|
}
|
|
146
147
|
catch (err) {
|
|
147
|
-
|
|
148
|
+
logger.error({ err, property_name }, 'Error adding group key');
|
|
148
149
|
continue loopKeys;
|
|
149
150
|
}
|
|
150
151
|
|
package/lib/utils/utils.js
CHANGED
|
@@ -208,10 +208,10 @@ function choose(value) {
|
|
|
208
208
|
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
// if the thing has a .next() method, call that
|
|
211
|
+
// if the thing has a .next() method, call that (e.g., generators/iterators)
|
|
212
212
|
try {
|
|
213
|
-
if (value && typeof value.next === 'function') {
|
|
214
|
-
return value.next();
|
|
213
|
+
if (value && typeof /** @type {any} */ (value).next === 'function') {
|
|
214
|
+
return /** @type {any} */ (value).next();
|
|
215
215
|
}
|
|
216
216
|
} catch (e) {
|
|
217
217
|
console.error(`Error occurred while calling next(): ${e}`);
|
|
@@ -1070,7 +1070,42 @@ function buildFileNames(config) {
|
|
|
1070
1070
|
}
|
|
1071
1071
|
|
|
1072
1072
|
/**
|
|
1073
|
-
*
|
|
1073
|
+
* Human-readable byte size
|
|
1074
|
+
* @param {number} bytes
|
|
1075
|
+
* @param {number} dp - decimal places
|
|
1076
|
+
* @param {boolean} si - use SI units
|
|
1077
|
+
* @returns {string}
|
|
1078
|
+
*/
|
|
1079
|
+
function bytesHuman(bytes, dp = 2, si = true) {
|
|
1080
|
+
const thresh = si ? 1000 : 1024;
|
|
1081
|
+
if (Math.abs(bytes) < thresh) {
|
|
1082
|
+
return bytes + ' B';
|
|
1083
|
+
}
|
|
1084
|
+
const units = si ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
|
|
1085
|
+
let u = -1;
|
|
1086
|
+
const r = 10 ** dp;
|
|
1087
|
+
do {
|
|
1088
|
+
bytes /= thresh;
|
|
1089
|
+
++u;
|
|
1090
|
+
} while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);
|
|
1091
|
+
return bytes.toFixed(dp) + ' ' + units[u];
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
/**
|
|
1095
|
+
* Format milliseconds as HH:MM:SS
|
|
1096
|
+
* @param {number} ms - Milliseconds
|
|
1097
|
+
* @returns {string} Formatted duration string
|
|
1098
|
+
*/
|
|
1099
|
+
function formatDuration(ms) {
|
|
1100
|
+
const seconds = Math.floor(ms / 1000);
|
|
1101
|
+
const hours = Math.floor(seconds / 3600);
|
|
1102
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
1103
|
+
const secs = seconds % 60;
|
|
1104
|
+
return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
/**
|
|
1108
|
+
* @param {[string, string | number][]} arrayOfArrays
|
|
1074
1109
|
*/
|
|
1075
1110
|
function progress(arrayOfArrays) {
|
|
1076
1111
|
const terminalWidth = process.stdout.columns || 120;
|
|
@@ -1503,4 +1538,6 @@ export {
|
|
|
1503
1538
|
datesBetween,
|
|
1504
1539
|
weighChoices,
|
|
1505
1540
|
wrapFunc,
|
|
1541
|
+
bytesHuman,
|
|
1542
|
+
formatDuration,
|
|
1506
1543
|
};
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "make-mp-data",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "builds all mixpanel primitives for a given project",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"types": "types.d.ts",
|
|
8
8
|
"files": [
|
|
9
9
|
"index.js",
|
|
10
|
-
"
|
|
10
|
+
"entry.js",
|
|
11
11
|
"types.d.ts",
|
|
12
12
|
"lib/",
|
|
13
13
|
"dungeons/",
|
|
@@ -16,23 +16,16 @@
|
|
|
16
16
|
"README.md"
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
|
-
"new:dungeon": "node ./scripts/create-dungeon.mjs",
|
|
20
|
-
"start": "node ./index.js",
|
|
21
|
-
"dev": "nodemon scratch.mjs --ignore ./data/*",
|
|
22
|
-
"prune": "rm -f ./data/* && rm -f ./tmp/* && rm -f vscode-profile-*",
|
|
23
19
|
"post": "npm publish",
|
|
24
|
-
"deps": "./scripts/update-deps.sh",
|
|
25
20
|
"test": "NODE_ENV=test vitest run",
|
|
26
|
-
"coverage": "vitest run --coverage && open ./coverage/index.html",
|
|
27
21
|
"typecheck": "tsc --noEmit",
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"textGen": "node ./lib/templates/textQuickTest.js"
|
|
22
|
+
"dev": "nodemon scratch.mjs --ignore ./data/*",
|
|
23
|
+
"prune": "rm -f ./data/* && rm -f ./tmp/* && rm -f vscode-profile-*",
|
|
24
|
+
"deps": "./scripts/update-deps.sh",
|
|
25
|
+
"dungeon:new": "node ./scripts/create-dungeon.mjs",
|
|
26
|
+
"dungeon:run": "node ./scripts/run-dungeon.mjs",
|
|
27
|
+
"dungeon:to-json": "node ./scripts/dungeon-to-json.mjs",
|
|
28
|
+
"dungeon:from-json": "node ./scripts/json-to-dungeon.mjs"
|
|
36
29
|
},
|
|
37
30
|
"repository": {
|
|
38
31
|
"type": "git",
|
|
@@ -60,18 +53,19 @@
|
|
|
60
53
|
},
|
|
61
54
|
"homepage": "https://github.com/ak--47/make-mp-data#readme",
|
|
62
55
|
"dependencies": {
|
|
63
|
-
"@google-cloud/functions-framework": "^3.4.2",
|
|
64
56
|
"@google-cloud/storage": "^7.14.0",
|
|
65
|
-
"ak-fetch": "^2.0.
|
|
66
|
-
"ak-gemini": "^1.
|
|
57
|
+
"ak-fetch": "^2.0.15",
|
|
58
|
+
"ak-gemini": "^1.1.13",
|
|
67
59
|
"ak-tools": "^1.1.12",
|
|
68
60
|
"chance": "^1.1.11",
|
|
69
61
|
"dayjs": "^1.11.11",
|
|
70
62
|
"dotenv": "^16.4.5",
|
|
71
|
-
"google-auth-library": "^9.15.0",
|
|
72
63
|
"hyparquet-writer": "^0.6.1",
|
|
73
|
-
"mixpanel
|
|
64
|
+
"mixpanel": "^0.18.0",
|
|
65
|
+
"mixpanel-import": "^3.2.8",
|
|
74
66
|
"p-limit": "^3.1.0",
|
|
67
|
+
"pino": "^9.0.0",
|
|
68
|
+
"pino-pretty": "^11.0.0",
|
|
75
69
|
"seedrandom": "^3.0.5",
|
|
76
70
|
"sentiment": "^5.0.2",
|
|
77
71
|
"tracery-grammar": "^2.8.4",
|
package/types.d.ts
CHANGED
|
@@ -48,7 +48,10 @@ export interface Dungeon {
|
|
|
48
48
|
hasAnonIds?: boolean;
|
|
49
49
|
hasSessionIds?: boolean;
|
|
50
50
|
alsoInferFunnels?: boolean;
|
|
51
|
+
makeChart?: boolean | string;
|
|
51
52
|
singleCountry?: string;
|
|
53
|
+
strictEventCount?: boolean;
|
|
54
|
+
isUIJob?: boolean;
|
|
52
55
|
|
|
53
56
|
//models
|
|
54
57
|
events?: EventConfig[]; //| string[]; //can also be a array of strings
|
|
@@ -69,13 +72,15 @@ export interface Dungeon {
|
|
|
69
72
|
|
|
70
73
|
//probabilities
|
|
71
74
|
percentUsersBornInDataset?: number;
|
|
75
|
+
/** Bias toward recent birth dates for users born in dataset (0 = uniform, 1 = heavily recent). Default: 0.3 */
|
|
76
|
+
bornRecentBias?: number;
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
export type SCDProp = {
|
|
75
80
|
type?: string | "user" | "company_id" | "team_id" | "department_id";
|
|
76
|
-
frequency
|
|
81
|
+
frequency?: "day" | "week" | "month" | "year";
|
|
77
82
|
values: ValueValid;
|
|
78
|
-
timing
|
|
83
|
+
timing?: "fixed" | "fuzzy";
|
|
79
84
|
max?: number;
|
|
80
85
|
};
|
|
81
86
|
|
|
@@ -164,7 +169,6 @@ export interface RuntimeState {
|
|
|
164
169
|
userCount: number;
|
|
165
170
|
isBatchMode: boolean;
|
|
166
171
|
verbose: boolean;
|
|
167
|
-
isCLI: boolean;
|
|
168
172
|
}
|
|
169
173
|
|
|
170
174
|
/**
|
|
@@ -209,7 +213,6 @@ export interface Context {
|
|
|
209
213
|
incrementUserCount(): void;
|
|
210
214
|
incrementEventCount(): void;
|
|
211
215
|
isBatchMode(): boolean;
|
|
212
|
-
isCLI(): boolean;
|
|
213
216
|
|
|
214
217
|
// Time helper methods
|
|
215
218
|
getTimeShift(): number;
|
|
@@ -227,6 +230,7 @@ export interface EventConfig {
|
|
|
227
230
|
isChurnEvent?: boolean;
|
|
228
231
|
isSessionStartEvent?: boolean;
|
|
229
232
|
relativeTimeMs?: number;
|
|
233
|
+
isStrictEvent?: boolean;
|
|
230
234
|
}
|
|
231
235
|
|
|
232
236
|
export interface GroupEventConfig extends EventConfig {
|
|
@@ -322,6 +326,10 @@ export interface Funnel {
|
|
|
322
326
|
*
|
|
323
327
|
*/
|
|
324
328
|
experiment?: boolean;
|
|
329
|
+
/**
|
|
330
|
+
* optional: if set, in sequential funnels, this will determine WHEN the property is bound to the rest of the events in the funnel
|
|
331
|
+
*/
|
|
332
|
+
bindPropsIndex?: number;
|
|
325
333
|
}
|
|
326
334
|
|
|
327
335
|
/**
|
|
@@ -424,6 +432,8 @@ export type Result = {
|
|
|
424
432
|
operations?: number;
|
|
425
433
|
eventCount?: number;
|
|
426
434
|
userCount?: number;
|
|
435
|
+
groupCount?: number;
|
|
436
|
+
avgEPS?: number;
|
|
427
437
|
};
|
|
428
438
|
|
|
429
439
|
/**
|
|
@@ -698,7 +708,7 @@ export interface TextGenerator {
|
|
|
698
708
|
* @param config - Configuration options for the generator
|
|
699
709
|
* @returns Text generator instance
|
|
700
710
|
*/
|
|
701
|
-
export declare function
|
|
711
|
+
export declare function createTextGenerator(config?: TextGeneratorConfig): TextGenerator;
|
|
702
712
|
|
|
703
713
|
/**
|
|
704
714
|
* Generate a batch of text items directly (standalone function)
|