Skip to content

Commit 7c2bdfa

Browse files
authored
Merge branch 'kennethkutyn:main' into main
2 parents 54212fe + d373254 commit 7c2bdfa

File tree

3 files changed

+54
-13
lines changed

3 files changed

+54
-13
lines changed

assets/favicon.svg

Lines changed: 1 addition & 0 deletions
Loading

js/ai.js

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,20 +75,40 @@ function normalizeLayer(layer) {
7575
return VALID_LAYERS.has(lower) ? lower : null;
7676
}
7777

78-
function upsertCustomEntry({ id, label, layer, icon = 'custom' }) {
78+
function ensureCategoryContainers(category) {
79+
if (!category) return;
80+
if (!customEntries[category]) customEntries[category] = [];
81+
if (!addedItems[category]) addedItems[category] = new Set();
82+
}
83+
84+
function isItemAlreadyAdded(itemId) {
85+
return Object.values(addedItems).some(set => set.has(itemId));
86+
}
87+
88+
function guessLayerFromKind(kind) {
89+
const lower = (kind || '').toString().trim().toLowerCase();
90+
if (!lower) return null;
91+
if (lower === 'activation') return 'activation';
92+
if (lower === 'warehouse' || lower === 'analysis') return 'analysis';
93+
if (lower === 'amplitude') return 'analysis';
94+
if (lower === 'datasource' || lower === 'source') return 'sources';
95+
return null;
96+
}
97+
98+
function upsertCustomEntry({ id, label, layer, kind, icon = 'custom' }) {
7999
const safeId = id || slugify(label);
80100
const name = label || safeId;
81101

82102
const existingCategory = itemCategoryIndex[safeId];
83103
const normalizedLayer = normalizeLayer(layer);
104+
const kindLayer = guessLayerFromKind(kind);
84105
const defaultLayer = AI_NODE_DEFAULTS[safeId]?.layer;
85-
const category = normalizedLayer || existingCategory || defaultLayer;
106+
// Prefer the catalog category if it exists; otherwise use AI layer, kind hint, then defaults.
107+
const category = existingCategory || normalizedLayer || kindLayer || defaultLayer;
86108
const resolvedIcon = AI_NODE_DEFAULTS[safeId]?.icon || icon;
87109

88-
if (existingCategory && category && existingCategory !== category) {
89-
return null;
90-
}
91110
if (!category) return null;
111+
ensureCategoryContainers(category);
92112

93113
// If this is a known, pre-defined item (e.g., amplitude-sdk, s3), just add it.
94114
if (existingCategory) {
@@ -126,13 +146,38 @@ function applyDiagramFromAi(result) {
126146
id: node?.id,
127147
label: node?.label || node?.name,
128148
layer: node?.layer,
149+
kind: node?.kind,
129150
icon: 'custom'
130151
});
131152
if (id) {
132153
createdIds.add(id);
133154
}
134155
});
135156

157+
// Safety net: if any node failed to add (missing category resolution, etc.), try once more with a fallback.
158+
nodes.forEach(node => {
159+
const nodeId = node?.id;
160+
if (!nodeId || isItemAlreadyAdded(nodeId)) return;
161+
const normalizedLayer = normalizeLayer(node?.layer);
162+
const kindLayer = guessLayerFromKind(node?.kind);
163+
const defaultLayer = AI_NODE_DEFAULTS[nodeId]?.layer || AI_NODE_DEFAULTS[slugify(node?.label)]?.layer;
164+
const category = itemCategoryIndex[nodeId] || normalizedLayer || kindLayer || defaultLayer || 'analysis';
165+
ensureCategoryContainers(category);
166+
const existsInCustom = customEntries[category].some(entry => entry.id === nodeId);
167+
if (!existsInCustom) {
168+
customEntries[category].push({
169+
id: nodeId,
170+
name: node?.label || nodeId,
171+
icon: AI_NODE_DEFAULTS[nodeId]?.icon || 'custom',
172+
isCustom: true
173+
});
174+
}
175+
itemCategoryIndex[nodeId] = category;
176+
if (!addedItems[category].has(nodeId)) {
177+
addItemToLayer(nodeId, node?.label || nodeId, AI_NODE_DEFAULTS[nodeId]?.icon || 'custom', category);
178+
}
179+
});
180+
136181
edges.forEach(edge => {
137182
const sourceId = edge?.sourceId;
138183
const targetId = edge?.targetId;

proxy/index.js

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ const defaultAllowed = [
3131
'http://127.0.0.1:5500',
3232
// Hosted client (custom domain + GH Pages fallback)
3333
'https://amplistack.amplitude.com',
34-
'https://amplitude.github.io'
34+
'https://amplitude.github.io',
35+
'https://kennethkutyn.github.io'
3536
];
3637

3738
const envAllowed = (ALLOWED_ORIGINS || '')
@@ -55,15 +56,9 @@ You are an Amplitude analytics solutions architect. Given a call transcript, ext
5556
Return ONLY valid JSON with this shape:
5657
{
5758
"architecture": { "goal": string, "scope": string },
58-
"entities": [
59-
{ "name": string, "type": "product|datasource|activation|warehouse|pipeline|other", "layer": "marketing|experiences|sources|analysis|activation", "notes": string }
60-
],
6159
"events": [
6260
{ "name": string, "properties": [string], "notes": string }
6361
],
64-
"flows": [
65-
{ "from": string, "to": string, "description": string, "direction": "uni|bi" }
66-
],
6762
"risks": [string],
6863
"assumptions": [string],
6964
"diagramNodes": [
@@ -82,7 +77,7 @@ Rules:
8277
- Pay special attention to mention of Amplitude SDK. If they mention Mobile or Web app, assume an AMplitude SDK will be present unless the specifically say otherwise or mention a CDP.
8378
- Prefer concise labels; derive stable ids from names (lowercase, dashes).
8479
- Map AmpliStack layers: marketing, experiences (owned surfaces/apps), sources (ingest), analysis (warehouse/BI/Amplitude), activation (destinations/engagement).
85-
- For flows, keep edge labels descriptive (e.g., "track events", "sync audiences").
80+
- For diagramEdges, keep labels descriptive (e.g., "track events", "sync audiences").
8681
- If there is a mention of push, email, ads or similar, make sure to add the appropriate node to the "marketing channesl" layer
8782
- If something is unknown, use an empty array or empty string rather than guessing.
8883
`;

0 commit comments

Comments
 (0)