@flisk/analyze-tracking 0.3.0 → 0.3.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/package.json +1 -1
- package/schema.json +8 -0
- package/src/generateDescriptions.js +83 -27
package/package.json
CHANGED
package/schema.json
CHANGED
|
@@ -71,6 +71,10 @@
|
|
|
71
71
|
"unknown"
|
|
72
72
|
],
|
|
73
73
|
"description": "Name of the platform where the event is sent"
|
|
74
|
+
},
|
|
75
|
+
"description": {
|
|
76
|
+
"type": "string",
|
|
77
|
+
"description": "Description of how the event is triggered"
|
|
74
78
|
}
|
|
75
79
|
},
|
|
76
80
|
"required": [
|
|
@@ -89,6 +93,10 @@
|
|
|
89
93
|
"$ref": "#/definitions/property"
|
|
90
94
|
}
|
|
91
95
|
}
|
|
96
|
+
},
|
|
97
|
+
"description": {
|
|
98
|
+
"type": "string",
|
|
99
|
+
"description": "Description of the event"
|
|
92
100
|
}
|
|
93
101
|
},
|
|
94
102
|
"required": [
|
|
@@ -7,21 +7,25 @@ const { zodResponseFormat } = require('openai/helpers/zod');
|
|
|
7
7
|
const openai = new OpenAI({
|
|
8
8
|
apiKey: process.env.OPENAI_API_KEY,
|
|
9
9
|
});
|
|
10
|
+
const model = 'gpt-4o-mini';
|
|
10
11
|
|
|
11
12
|
function createPrompt(eventName, properties, implementations, codebaseDir) {
|
|
12
|
-
|
|
13
|
-
let prompt = `You are an expert at structured data extraction. Generate detailed descriptions for the following analytics event, its properties, and implementations.\n\n`;
|
|
14
|
-
|
|
15
|
-
// Add event name
|
|
16
|
-
prompt += `Event Name: "${eventName}"\n\n`;
|
|
17
|
-
|
|
18
|
-
// Add properties
|
|
13
|
+
let prompt = `Event Name: "${eventName}"\n\n`;
|
|
19
14
|
prompt += `Properties:\n`;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
|
|
16
|
+
function appendPropertiesToPrompt(properties, indent = '') {
|
|
17
|
+
for (const propName in properties) {
|
|
18
|
+
const prop = properties[propName];
|
|
19
|
+
prompt += `${indent}- "${propName}" (type: ${prop.type})\n`;
|
|
20
|
+
if (prop.properties) {
|
|
21
|
+
prompt += `${indent} Sub-properties:\n`;
|
|
22
|
+
appendPropertiesToPrompt(prop.properties, indent + ' ');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
23
25
|
}
|
|
24
26
|
|
|
27
|
+
appendPropertiesToPrompt(properties);
|
|
28
|
+
|
|
25
29
|
// Add implementations with code snippets
|
|
26
30
|
prompt += `\nImplementations:\n`;
|
|
27
31
|
for (const impl of implementations) {
|
|
@@ -53,18 +57,39 @@ function getCodeSnippet(filePath, lineNumber, contextLines = 5) {
|
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
function createEventDescriptionSchema(properties) {
|
|
60
|
+
function buildPropertySchema(prop) {
|
|
61
|
+
if (prop.properties) {
|
|
62
|
+
const subPropertiesSchema = {};
|
|
63
|
+
for (const subPropName in prop.properties) {
|
|
64
|
+
subPropertiesSchema[subPropName] = buildPropertySchema(prop.properties[subPropName]);
|
|
65
|
+
}
|
|
66
|
+
return z.object({
|
|
67
|
+
description: z
|
|
68
|
+
.string()
|
|
69
|
+
.describe('A maximum of 10 words describing the property and what it means'),
|
|
70
|
+
properties: z.object(subPropertiesSchema),
|
|
71
|
+
});
|
|
72
|
+
} else {
|
|
73
|
+
return z.object({
|
|
74
|
+
description: z
|
|
75
|
+
.string()
|
|
76
|
+
.describe('A maximum of 10 words describing the property and what it means'),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
56
81
|
// Define the schema for properties
|
|
57
82
|
const propertiesSchema = {};
|
|
58
83
|
for (const propName in properties) {
|
|
59
|
-
propertiesSchema[propName] =
|
|
60
|
-
description: z.string().describe('A maximum of 10 words describing the property and what it means'),
|
|
61
|
-
});
|
|
84
|
+
propertiesSchema[propName] = buildPropertySchema(properties[propName]);
|
|
62
85
|
}
|
|
63
86
|
|
|
64
87
|
// Define the schema for implementations
|
|
65
88
|
const implementationsSchema = z.array(
|
|
66
89
|
z.object({
|
|
67
|
-
description: z
|
|
90
|
+
description: z
|
|
91
|
+
.string()
|
|
92
|
+
.describe('A maximum of 10 words describing how this event is triggered without using the word "triggered"'),
|
|
68
93
|
path: z.string(),
|
|
69
94
|
line: z.number(),
|
|
70
95
|
})
|
|
@@ -72,7 +97,9 @@ function createEventDescriptionSchema(properties) {
|
|
|
72
97
|
|
|
73
98
|
// Construct the full schema
|
|
74
99
|
const eventDescriptionSchema = z.object({
|
|
75
|
-
eventDescription: z
|
|
100
|
+
eventDescription: z
|
|
101
|
+
.string()
|
|
102
|
+
.describe('A maximum of 10 words describing the event and what it tracks without using the word "tracks"'),
|
|
76
103
|
properties: z.object(propertiesSchema),
|
|
77
104
|
implementations: implementationsSchema,
|
|
78
105
|
});
|
|
@@ -83,11 +110,11 @@ function createEventDescriptionSchema(properties) {
|
|
|
83
110
|
async function sendPromptToLLM(prompt, schema) {
|
|
84
111
|
try {
|
|
85
112
|
const completion = await openai.beta.chat.completions.parse({
|
|
86
|
-
model
|
|
113
|
+
model,
|
|
87
114
|
messages: [
|
|
88
115
|
{
|
|
89
116
|
role: 'system',
|
|
90
|
-
content: 'You are an expert at structured data extraction. Generate detailed descriptions for the following analytics event, its properties, and implementations',
|
|
117
|
+
content: 'You are an expert at structured data extraction. Generate detailed descriptions for the following analytics event, its properties, and implementations.',
|
|
91
118
|
},
|
|
92
119
|
{
|
|
93
120
|
role: 'user',
|
|
@@ -97,7 +124,10 @@ async function sendPromptToLLM(prompt, schema) {
|
|
|
97
124
|
response_format: zodResponseFormat(schema, 'event_description'),
|
|
98
125
|
});
|
|
99
126
|
|
|
100
|
-
return
|
|
127
|
+
return {
|
|
128
|
+
descriptions: completion.choices[0].message.parsed,
|
|
129
|
+
usage: completion.usage,
|
|
130
|
+
};
|
|
101
131
|
} catch (error) {
|
|
102
132
|
console.error('Error during LLM response parsing:', error);
|
|
103
133
|
return null;
|
|
@@ -115,36 +145,58 @@ async function generateEventDescription(eventName, event, codebaseDir) {
|
|
|
115
145
|
const eventDescriptionSchema = createEventDescriptionSchema(properties);
|
|
116
146
|
|
|
117
147
|
// Send prompt to the LLM and get the structured response
|
|
118
|
-
const descriptions = await sendPromptToLLM(prompt, eventDescriptionSchema);
|
|
148
|
+
const { descriptions, usage } = await sendPromptToLLM(prompt, eventDescriptionSchema);
|
|
119
149
|
|
|
120
|
-
return { eventName, descriptions };
|
|
150
|
+
return { eventName, descriptions, usage };
|
|
121
151
|
}
|
|
122
152
|
|
|
123
153
|
async function generateDescriptions(events, codebaseDir) {
|
|
154
|
+
console.log(`Generating descriptions using ${model}`);
|
|
155
|
+
|
|
124
156
|
const eventPromises = Object.entries(events).map(([eventName, event]) =>
|
|
125
157
|
generateEventDescription(eventName, event, codebaseDir)
|
|
126
158
|
);
|
|
127
159
|
|
|
160
|
+
console.log(`Running ${eventPromises.length} prompts in parallel...`);
|
|
161
|
+
|
|
128
162
|
const results = await Promise.all(eventPromises);
|
|
129
163
|
|
|
164
|
+
let promptTokens = 0;
|
|
165
|
+
let completionTokens = 0;
|
|
166
|
+
|
|
130
167
|
// Process results and update the events object
|
|
131
|
-
results.forEach(({ eventName, descriptions }) => {
|
|
168
|
+
results.forEach(({ eventName, descriptions, usage }) => {
|
|
132
169
|
if (descriptions) {
|
|
170
|
+
promptTokens += usage.prompt_tokens;
|
|
171
|
+
completionTokens += usage.completion_tokens;
|
|
172
|
+
|
|
133
173
|
const event = events[eventName];
|
|
134
174
|
event.description = descriptions.eventDescription;
|
|
135
175
|
|
|
136
|
-
// Update property descriptions
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
176
|
+
// Update property descriptions recursively
|
|
177
|
+
function updatePropertyDescriptions(eventProperties, descriptionProperties) {
|
|
178
|
+
for (const propName in descriptionProperties) {
|
|
179
|
+
if (eventProperties[propName]) {
|
|
180
|
+
eventProperties[propName].description = descriptionProperties[propName].description;
|
|
181
|
+
if (eventProperties[propName].properties && descriptionProperties[propName].properties) {
|
|
182
|
+
updatePropertyDescriptions(
|
|
183
|
+
eventProperties[propName].properties,
|
|
184
|
+
descriptionProperties[propName].properties
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
140
188
|
}
|
|
141
189
|
}
|
|
142
190
|
|
|
191
|
+
updatePropertyDescriptions(event.properties, descriptions.properties);
|
|
192
|
+
|
|
143
193
|
// Update implementations with descriptions
|
|
144
194
|
for (let i = 0; i < descriptions.implementations.length; i++) {
|
|
145
195
|
if (event.implementations[i]) {
|
|
146
|
-
if (
|
|
147
|
-
|
|
196
|
+
if (
|
|
197
|
+
event.implementations[i].path === descriptions.implementations[i].path &&
|
|
198
|
+
event.implementations[i].line === descriptions.implementations[i].line
|
|
199
|
+
) {
|
|
148
200
|
event.implementations[i].description = descriptions.implementations[i].description;
|
|
149
201
|
} else {
|
|
150
202
|
console.error(`Returned implementation description does not match path or line for event: ${eventName}`);
|
|
@@ -156,6 +208,10 @@ async function generateDescriptions(events, codebaseDir) {
|
|
|
156
208
|
}
|
|
157
209
|
});
|
|
158
210
|
|
|
211
|
+
console.log(`Prompt tokens used: ${promptTokens}`);
|
|
212
|
+
console.log(`Completion tokens used: ${completionTokens}`);
|
|
213
|
+
console.log(`Total tokens used: ${promptTokens + completionTokens}`);
|
|
214
|
+
|
|
159
215
|
return events;
|
|
160
216
|
}
|
|
161
217
|
|