@memberjunction/ng-dashboards 6.1.3 → 6.2.0-edge.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.
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts +6 -1
- package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
- package/dist/AI/components/vectors/vector-management-resource.component.js +99 -45
- package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.d.ts +4 -0
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.d.ts.map +1 -1
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js +16 -6
- package/dist/DataExplorer/components/navigation-panel/navigation-panel.component.js.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +4 -0
- package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
- package/dist/DataExplorer/data-explorer-dashboard.component.js +14 -4
- package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
- package/dist/DataExplorer/services/explorer-state.service.js +2 -2
- package/dist/DataExplorer/services/explorer-state.service.js.map +1 -1
- package/dist/DevTools/graphql-console.component.d.ts.map +1 -1
- package/dist/DevTools/graphql-console.component.js +2 -0
- package/dist/DevTools/graphql-console.component.js.map +1 -1
- package/dist/Integration/components/connections/connections.component.d.ts.map +1 -1
- package/dist/Integration/components/connections/connections.component.js +2 -0
- package/dist/Integration/components/connections/connections.component.js.map +1 -1
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.d.ts +4 -12
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.d.ts.map +1 -1
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js +39 -78
- package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.d.ts +3 -0
- package/dist/Lists/components/lists-browse-resource.component.d.ts.map +1 -1
- package/dist/Lists/components/lists-browse-resource.component.js +7 -6
- package/dist/Lists/components/lists-browse-resource.component.js.map +1 -1
- package/dist/Lists/components/lists-my-lists-resource.component.d.ts +3 -0
- package/dist/Lists/components/lists-my-lists-resource.component.d.ts.map +1 -1
- package/dist/Lists/components/lists-my-lists-resource.component.js +7 -6
- package/dist/Lists/components/lists-my-lists-resource.component.js.map +1 -1
- package/dist/PredictiveStudio/at-risk.view-models.d.ts +41 -3
- package/dist/PredictiveStudio/at-risk.view-models.d.ts.map +1 -1
- package/dist/PredictiveStudio/at-risk.view-models.js +99 -6
- package/dist/PredictiveStudio/at-risk.view-models.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-catalog.component.d.ts +4 -1
- package/dist/PredictiveStudio/components/ps-catalog.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-catalog.component.js +61 -37
- package/dist/PredictiveStudio/components/ps-catalog.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-experiments.component.d.ts +12 -0
- package/dist/PredictiveStudio/components/ps-experiments.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-experiments.component.js +426 -184
- package/dist/PredictiveStudio/components/ps-experiments.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.d.ts +84 -0
- package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.d.ts.map +1 -0
- package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.js +1397 -0
- package/dist/PredictiveStudio/components/ps-pipeline-wizard.component.js.map +1 -0
- package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts +66 -34
- package/dist/PredictiveStudio/components/ps-pipelines.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-pipelines.component.js +2456 -743
- package/dist/PredictiveStudio/components/ps-pipelines.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-predictions-grid.component.d.ts +194 -0
- package/dist/PredictiveStudio/components/ps-predictions-grid.component.d.ts.map +1 -0
- package/dist/PredictiveStudio/components/ps-predictions-grid.component.js +1902 -0
- package/dist/PredictiveStudio/components/ps-predictions-grid.component.js.map +1 -0
- package/dist/PredictiveStudio/components/ps-production.component.d.ts +17 -1
- package/dist/PredictiveStudio/components/ps-production.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-production.component.js +653 -372
- package/dist/PredictiveStudio/components/ps-production.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-registry.component.d.ts +21 -61
- package/dist/PredictiveStudio/components/ps-registry.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/components/ps-registry.component.js +214 -681
- package/dist/PredictiveStudio/components/ps-registry.component.js.map +1 -1
- package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.d.ts +49 -0
- package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.d.ts.map +1 -0
- package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.js +658 -0
- package/dist/PredictiveStudio/components/ps-run-experiment-modal.component.js.map +1 -0
- package/dist/PredictiveStudio/predictive-studio-score-history.service.d.ts +42 -0
- package/dist/PredictiveStudio/predictive-studio-score-history.service.d.ts.map +1 -0
- package/dist/PredictiveStudio/predictive-studio-score-history.service.js +90 -0
- package/dist/PredictiveStudio/predictive-studio-score-history.service.js.map +1 -0
- package/dist/PredictiveStudio/predictive-studio.view-models.d.ts +14 -2
- package/dist/PredictiveStudio/predictive-studio.view-models.d.ts.map +1 -1
- package/dist/PredictiveStudio/predictive-studio.view-models.js +41 -5
- package/dist/PredictiveStudio/predictive-studio.view-models.js.map +1 -1
- package/dist/PredictiveStudio/resources/ps-models-resource.component.d.ts +9 -1
- package/dist/PredictiveStudio/resources/ps-models-resource.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/resources/ps-models-resource.component.js +178 -65
- package/dist/PredictiveStudio/resources/ps-models-resource.component.js.map +1 -1
- package/dist/PredictiveStudio/resources/ps-predictions-resource.component.d.ts +9 -1
- package/dist/PredictiveStudio/resources/ps-predictions-resource.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/resources/ps-predictions-resource.component.js +307 -369
- package/dist/PredictiveStudio/resources/ps-predictions-resource.component.js.map +1 -1
- package/dist/PredictiveStudio/resources/ps-resource-base.js +1 -1
- package/dist/PredictiveStudio/resources/ps-resource-base.js.map +1 -1
- package/dist/PredictiveStudio/resources/ps-studio-resource.component.d.ts +17 -1
- package/dist/PredictiveStudio/resources/ps-studio-resource.component.d.ts.map +1 -1
- package/dist/PredictiveStudio/resources/ps-studio-resource.component.js +309 -138
- package/dist/PredictiveStudio/resources/ps-studio-resource.component.js.map +1 -1
- package/dist/VersionHistory/components/graph-resource.component.d.ts +1 -0
- package/dist/VersionHistory/components/graph-resource.component.d.ts.map +1 -1
- package/dist/VersionHistory/components/graph-resource.component.js +6 -5
- package/dist/VersionHistory/components/graph-resource.component.js.map +1 -1
- package/dist/predictive-studio-dashboards.module.d.ts +10 -8
- package/dist/predictive-studio-dashboards.module.d.ts.map +1 -1
- package/dist/predictive-studio-dashboards.module.js +13 -3
- package/dist/predictive-studio-dashboards.module.js.map +1 -1
- package/package.json +64 -63
|
@@ -8,14 +8,16 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Framework-free + deterministic → unit-tested with no Angular.
|
|
10
10
|
*/
|
|
11
|
+
import { resolveScoreBand, } from '@memberjunction/predictive-studio-core';
|
|
11
12
|
/** Parse + humanize the raw per-record `drivers` (post-preprocessing `feature`/`value`) into {@link RowDriver}s. */
|
|
12
|
-
function parseRowDrivers(raw) {
|
|
13
|
+
export function parseRowDrivers(raw) {
|
|
13
14
|
if (!Array.isArray(raw) || raw.length === 0)
|
|
14
15
|
return null;
|
|
15
16
|
const out = [];
|
|
16
17
|
for (const d of raw) {
|
|
17
18
|
const feature = typeof d?.feature === 'string' ? d.feature : '';
|
|
18
|
-
const
|
|
19
|
+
const rawVal = typeof d?.value === 'number' ? d.value : typeof d?.importance === 'number' ? d.importance : typeof d?.weight === 'number' ? d.weight : NaN;
|
|
20
|
+
const value = Number(rawVal);
|
|
19
21
|
if (!feature || !Number.isFinite(value))
|
|
20
22
|
continue;
|
|
21
23
|
// Keep the one-hot category: for a per-record "why", the category IS the story — "Membership Type =
|
|
@@ -34,6 +36,9 @@ export function labelFromRecord(row) {
|
|
|
34
36
|
if (!row)
|
|
35
37
|
return null;
|
|
36
38
|
const str = (v) => (typeof v === 'string' ? v.trim() : '');
|
|
39
|
+
const member = str(row['MemberName'] || row['Member'] || row['FullName']);
|
|
40
|
+
if (member)
|
|
41
|
+
return member;
|
|
37
42
|
const name = str(row['Name']);
|
|
38
43
|
if (name)
|
|
39
44
|
return name;
|
|
@@ -52,12 +57,73 @@ export function labelFromRecord(row) {
|
|
|
52
57
|
}
|
|
53
58
|
return null;
|
|
54
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Robustly inspects model metadata and sample scoring payloads to determine:
|
|
62
|
+
* 1. Whether this is a renewal/retention/churn model (`isRenewalModel`)
|
|
63
|
+
* 2. Whether the raw payload `score` represents adverse lapse risk (P(Lapse)) or positive outcome (P(Renewed))
|
|
64
|
+
*/
|
|
65
|
+
export function resolveRenewalPolarity(rawPayloads, targetVariable, modelName) {
|
|
66
|
+
const target = (targetVariable ?? '').toLowerCase();
|
|
67
|
+
const name = (modelName ?? '').toLowerCase();
|
|
68
|
+
const isTargetRenewal = target.includes('renew') ||
|
|
69
|
+
target.includes('lapse') ||
|
|
70
|
+
target.includes('retention') ||
|
|
71
|
+
target.includes('churn') ||
|
|
72
|
+
target === 'status' ||
|
|
73
|
+
name.includes('renew') ||
|
|
74
|
+
name.includes('retention') ||
|
|
75
|
+
name.includes('churn');
|
|
76
|
+
let hasRenewalKeywords = false;
|
|
77
|
+
const sampleScoresForRenewed = [];
|
|
78
|
+
for (const p of rawPayloads.slice(0, 50)) {
|
|
79
|
+
if (!p)
|
|
80
|
+
continue;
|
|
81
|
+
if (p.includes('"Renewed"') ||
|
|
82
|
+
p.includes('"renewed"') ||
|
|
83
|
+
p.includes('"Lapsed"') ||
|
|
84
|
+
p.includes('"lapsed"') ||
|
|
85
|
+
p.includes('Renewal Risk')) {
|
|
86
|
+
hasRenewalKeywords = true;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const parsed = JSON.parse(p);
|
|
90
|
+
const out = (parsed.output ?? parsed);
|
|
91
|
+
if (typeof out.score === 'number' && typeof out.class === 'string') {
|
|
92
|
+
const cls = out.class.toLowerCase();
|
|
93
|
+
if (cls === 'renewed' || cls === 'active') {
|
|
94
|
+
sampleScoresForRenewed.push(out.score);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// skip invalid json
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const isRenewalModel = isTargetRenewal || hasRenewalKeywords;
|
|
103
|
+
if (!isRenewalModel) {
|
|
104
|
+
return { isRenewalModel: false, scoreIsLapseRisk: false };
|
|
105
|
+
}
|
|
106
|
+
if (sampleScoresForRenewed.length > 0) {
|
|
107
|
+
const avg = sampleScoresForRenewed.reduce((a, b) => a + b, 0) / sampleScoresForRenewed.length;
|
|
108
|
+
// If members predicted 'Renewed' have small scores (< 0.5), the score represents Lapse Risk (P(Lapse))
|
|
109
|
+
return { isRenewalModel: true, scoreIsLapseRisk: avg < 0.5 };
|
|
110
|
+
}
|
|
111
|
+
// Fallback: target or name containing "risk", "lapse", or "churn" outputs lapse probability
|
|
112
|
+
const scoreIsLapseRisk = target.includes('risk') ||
|
|
113
|
+
target.includes('lapse') ||
|
|
114
|
+
target.includes('churn') ||
|
|
115
|
+
name.includes('risk') ||
|
|
116
|
+
name.includes('churn');
|
|
117
|
+
return { isRenewalModel: true, scoreIsLapseRisk };
|
|
118
|
+
}
|
|
55
119
|
function bandFor(score) {
|
|
56
120
|
return score >= 0.7 ? 'high' : score >= 0.4 ? 'medium' : 'low';
|
|
57
121
|
}
|
|
58
122
|
/** Parse + rank the per-record predictions into the at-risk list (highest risk first). */
|
|
59
|
-
export function parseAtRiskRows(details) {
|
|
123
|
+
export function parseAtRiskRows(details, options) {
|
|
60
124
|
const rows = [];
|
|
125
|
+
const isInverted = options?.invertedRisk === true;
|
|
126
|
+
const outcomeConfig = options?.outcomeConfig;
|
|
61
127
|
for (const d of details) {
|
|
62
128
|
if (!d.ResultPayload)
|
|
63
129
|
continue;
|
|
@@ -73,17 +139,44 @@ export function parseAtRiskRows(details) {
|
|
|
73
139
|
if (typeof p.score !== 'number' || !Number.isFinite(p.score))
|
|
74
140
|
continue;
|
|
75
141
|
const score = p.score;
|
|
142
|
+
const effectiveRisk = isInverted ? Math.max(0, Math.min(1, 1 - score)) : score;
|
|
143
|
+
const riskPct = Math.round(effectiveRisk * 100);
|
|
144
|
+
let bandKey;
|
|
145
|
+
let status = p.status;
|
|
146
|
+
let badgeColor = p.badgeColor;
|
|
147
|
+
let icon = p.icon;
|
|
148
|
+
if (outcomeConfig) {
|
|
149
|
+
const resolved = resolveScoreBand(score, outcomeConfig);
|
|
150
|
+
if (resolved) {
|
|
151
|
+
bandKey = resolved.Key;
|
|
152
|
+
status = status ?? resolved.Label;
|
|
153
|
+
badgeColor = badgeColor ?? resolved.BadgeColor;
|
|
154
|
+
icon = icon ?? resolved.Icon;
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
bandKey = p.band ?? bandFor(effectiveRisk);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else if (p.band) {
|
|
161
|
+
bandKey = p.band;
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
bandKey = bandFor(effectiveRisk);
|
|
165
|
+
}
|
|
76
166
|
rows.push({
|
|
77
167
|
recordId: d.recordId,
|
|
78
168
|
label: null,
|
|
79
169
|
score,
|
|
80
|
-
riskPct
|
|
170
|
+
riskPct,
|
|
81
171
|
class: p.class ?? null,
|
|
82
|
-
band:
|
|
172
|
+
band: bandKey,
|
|
173
|
+
status,
|
|
174
|
+
badgeColor,
|
|
175
|
+
icon,
|
|
83
176
|
drivers: parseRowDrivers(p.drivers),
|
|
84
177
|
});
|
|
85
178
|
}
|
|
86
|
-
return rows.sort((a, b) => b.
|
|
179
|
+
return rows.sort((a, b) => b.riskPct - a.riskPct);
|
|
87
180
|
}
|
|
88
181
|
/**
|
|
89
182
|
* The top plain-language drivers for the whole prediction, from the model's global feature importance.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"at-risk.view-models.js","sourceRoot":"","sources":["../../src/PredictiveStudio/at-risk.view-models.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAoCH,oHAAoH;AACpH,SAAS,eAAe,CAAC,GAAY;IACnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzD,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,GAAoD,EAAE,CAAC;QACrE,MAAM,OAAO,GAAG,OAAO,CAAC,EAAE,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,MAAM,KAAK,GAAG,OAAO,CAAC,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;QAC3D,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,SAAS;QAClD,oGAAoG;QACpG,kGAAkG;QAClG,6FAA6F;QAC7F,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAA+C;IAC7E,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,GAAG,GAAG,CAAC,CAAU,EAAU,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC5E,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9B,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,IAAI,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;IACvE,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IAChC,IAAI,IAAI,IAAI,KAAK;QAAE,OAAO,GAAG,IAAI,KAAK,KAAK,GAAG,CAAC;IAC/C,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACjB,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG;YAAE,OAAO,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAQD,SAAS,OAAO,CAAC,KAAa;IAC5B,OAAO,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AACjE,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,eAAe,CAAC,OAAwB;IACtD,MAAM,IAAI,GAAgB,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC,CAAC,CAAC,aAAa;YAAE,SAAS;QAC/B,IAAI,MAKH,CAAC;QACF,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,8FAA8F;QAC9F,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC;QAClC,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;YAAE,SAAS;QACvE,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC;YACR,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,KAAK,EAAE,IAAI;YACX,KAAK;YACL,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC;YAChC,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI;YACtB,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC;YACpB,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC;SACpC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;AAChD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,qBAAgD,EAAE,CAAC,GAAG,CAAC;IACtF,IAAI,CAAC,qBAAqB;QAAE,OAAO,EAAE,CAAC;IACtC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,KAAK,GAA4C,EAAE,CAAC;IAC1D,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,KAAK,MAAM,CAAC,IAAI,MAAwC,EAAE,CAAC;YACzD,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAuB,CAAC;YACzD,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,KAAK,CAAuB,CAAC;YAC/D,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,MAAM,KAAK,QAAQ;gBAAE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC7G,CAAC;IACH,CAAC;SAAM,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAChD,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAiC,CAAC,EAAE,CAAC;YAC/E,IAAI,OAAO,MAAM,KAAK,QAAQ;gBAAE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;IACD,6FAA6F;IAC7F,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACvC,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,CAAC,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;AACrH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,IAAI;SACR,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC;SAC1B,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE;SACN,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC5C,CAAC","sourcesContent":["/**\n * Pure derivations for the business workspace's **ranked at-risk list** — turning a model's per-record\n * scoring results (`MJ: Process Run Details` payloads) into a \"who to focus on\" list sorted by risk, and\n * the model's global feature importance into plain-language \"what's driving this\" drivers.\n *\n * Honest about the gap: MJ stores only GLOBAL feature importance (not per-record/SHAP), so we surface the\n * top global drivers once for the whole prediction rather than fabricating per-member attribution.\n *\n * Framework-free + deterministic → unit-tested with no Angular.\n */\n\n/** A scored record in the at-risk list. */\nexport interface AtRiskRow {\n recordId: string;\n /**\n * Human-readable label for the record (e.g. the member's name/email), resolved from the model's\n * target entity. Null until resolved; the UI falls back to {@link recordId} so the row is never blank.\n */\n label: string | null;\n /** 0–1 prediction score (probability / risk). */\n score: number;\n /** Risk as a 0–100 integer, for display. */\n riskPct: number;\n /** Predicted class label, when present (classification). */\n class: string | null;\n /** Risk band, for color. */\n band: 'high' | 'medium' | 'low';\n /**\n * Top signed per-record drivers behind THIS row's prediction (P1-5), humanized + one-hot-collapsed for\n * display. `up: true` pushed the risk up, `false` down. Null when the model doesn't produce per-record\n * attribution (tree/ensemble/multiclass) — the UI then shows the model's global drivers instead.\n */\n drivers: RowDriver[] | null;\n}\n\n/** A humanized, signed per-record driver for the at-risk row's inline \"why\". */\nexport interface RowDriver {\n /** Display label (humanized, one-hot base collapsed). */\n label: string;\n /** Signed contribution magnitude for this row. */\n value: number;\n /** Whether this pushed the risk UP (value > 0) or down. */\n up: boolean;\n}\n\n/** Parse + humanize the raw per-record `drivers` (post-preprocessing `feature`/`value`) into {@link RowDriver}s. */\nfunction parseRowDrivers(raw: unknown): RowDriver[] | null {\n if (!Array.isArray(raw) || raw.length === 0) return null;\n const out: RowDriver[] = [];\n for (const d of raw as Array<{ feature?: unknown; value?: unknown }>) {\n const feature = typeof d?.feature === 'string' ? d.feature : '';\n const value = typeof d?.value === 'number' ? d.value : NaN;\n if (!feature || !Number.isFinite(value)) continue;\n // Keep the one-hot category: for a per-record \"why\", the category IS the story — \"Membership Type =\n // Student lowers risk\" is actionable where a collapsed \"Membership Type\" is close to meaningless.\n // (Collapsing across categories is only right for GLOBAL importance — see topGlobalDrivers.)\n out.push({ label: humanizeFeatureName(feature), value, up: value > 0 });\n }\n return out.length > 0 ? out : null;\n}\n\n/**\n * Build a human-readable label for a record from its (simple) row of the target entity — preferring a\n * single `Name`, else `FirstName`+`LastName`, else `Email`, else any first non-empty string field.\n * Returns null when nothing usable is found (caller falls back to the record id).\n */\nexport function labelFromRecord(row: Record<string, unknown> | undefined | null): string | null {\n if (!row) return null;\n const str = (v: unknown): string => (typeof v === 'string' ? v.trim() : '');\n const name = str(row['Name']);\n if (name) return name;\n const full = `${str(row['FirstName'])} ${str(row['LastName'])}`.trim();\n const email = str(row['Email']);\n if (full && email) return `${full} (${email})`;\n if (full) return full;\n if (email) return email;\n for (const v of Object.values(row)) {\n const s = str(v);\n if (s && s.length <= 120) return s;\n }\n return null;\n}\n\n/** The raw per-record detail the list is built from (a slice of `MJ: Process Run Details`). */\nexport interface RunDetailLike {\n recordId: string;\n ResultPayload?: string | null;\n}\n\nfunction bandFor(score: number): AtRiskRow['band'] {\n return score >= 0.7 ? 'high' : score >= 0.4 ? 'medium' : 'low';\n}\n\n/** Parse + rank the per-record predictions into the at-risk list (highest risk first). */\nexport function parseAtRiskRows(details: RunDetailLike[]): AtRiskRow[] {\n const rows: AtRiskRow[] = [];\n for (const d of details) {\n if (!d.ResultPayload) continue;\n let parsed: {\n score?: number;\n class?: string;\n drivers?: unknown;\n output?: { score?: number; class?: string; drivers?: unknown };\n };\n try {\n parsed = JSON.parse(d.ResultPayload);\n } catch {\n continue;\n }\n // Write-back runs nest the prediction under `output`; generic runs carry it at the top level.\n const p = parsed.output ?? parsed;\n if (typeof p.score !== 'number' || !Number.isFinite(p.score)) continue;\n const score = p.score;\n rows.push({\n recordId: d.recordId,\n label: null,\n score,\n riskPct: Math.round(score * 100),\n class: p.class ?? null,\n band: bandFor(score),\n drivers: parseRowDrivers(p.drivers),\n });\n }\n return rows.sort((a, b) => b.score - a.score);\n}\n\n/**\n * The top plain-language drivers for the whole prediction, from the model's global feature importance.\n * Accepts the object form (`{\"MembershipType=Student\": 0.9, ...}`) or the array form\n * (`[{feature, importance}]`), strips one-hot `=value` suffixes, de-duplicates, and returns the\n * highest-importance feature names — so a business user sees \"what's driving this\", not raw weights.\n */\nexport function topGlobalDrivers(featureImportanceJson: string | null | undefined, n = 3): string[] {\n if (!featureImportanceJson) return [];\n let parsed: unknown;\n try {\n parsed = JSON.parse(featureImportanceJson);\n } catch {\n return [];\n }\n const pairs: Array<{ name: string; weight: number }> = [];\n if (Array.isArray(parsed)) {\n for (const e of parsed as Array<Record<string, unknown>>) {\n const name = (e.feature ?? e.name) as string | undefined;\n const weight = (e.importance ?? e.value) as number | undefined;\n if (typeof name === 'string' && typeof weight === 'number') pairs.push({ name, weight: Math.abs(weight) });\n }\n } else if (parsed && typeof parsed === 'object') {\n for (const [name, weight] of Object.entries(parsed as Record<string, unknown>)) {\n if (typeof weight === 'number') pairs.push({ name, weight: Math.abs(weight) });\n }\n }\n // Collapse one-hot columns (\"Feature=Value\" → \"Feature\"), keeping each feature's max weight.\n const byFeature = new Map<string, number>();\n for (const { name, weight } of pairs) {\n const base = name.split('=')[0].trim();\n if (!base) continue;\n byFeature.set(base, Math.max(byFeature.get(base) ?? 0, weight));\n }\n return [...byFeature.entries()].sort((a, b) => b[1] - a[1]).slice(0, n).map(([name]) => humanizeFeatureName(name));\n}\n\n/**\n * Turn a raw feature/column name into a readable label — `RetentionOverdueInvoices` → `Retention Overdue\n * Invoices`, `overdue_invoices` → `Overdue Invoices`, and a one-hot `MembershipType=Student` →\n * `Membership Type = Student`. Splits camelCase + snake/kebab, spaces one-hot `=`, collapses whitespace,\n * and capitalizes the first letter. Already-spaced labels pass through unchanged.\n */\nexport function humanizeFeatureName(name: string): string {\n return name\n .replace(/[_-]+/g, ' ')\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/\\s*=\\s*/g, ' = ')\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/^\\w/, (c) => c.toUpperCase());\n}\n"]}
|
|
1
|
+
{"version":3,"file":"at-risk.view-models.js","sourceRoot":"","sources":["../../src/PredictiveStudio/at-risk.view-models.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure derivations for the business workspace's **ranked at-risk list** — turning a model's per-record\n * scoring results (`MJ: Process Run Details` payloads) into a \"who to focus on\" list sorted by risk, and\n * the model's global feature importance into plain-language \"what's driving this\" drivers.\n *\n * Honest about the gap: MJ stores only GLOBAL feature importance (not per-record/SHAP), so we surface the\n * top global drivers once for the whole prediction rather than fabricating per-member attribution.\n *\n * Framework-free + deterministic → unit-tested with no Angular.\n */\n\nimport {\n type OutcomeConfig,\n resolveScoreBand,\n} from '@memberjunction/predictive-studio-core';\n\n/** A scored record in the at-risk list. */\nexport interface AtRiskRow {\n recordId: string;\n /**\n * Human-readable label for the record (e.g. the member's name/email), resolved from the model's\n * target entity. Null until resolved; the UI falls back to {@link recordId} so the row is never blank.\n */\n label: string | null;\n /** 0–1 prediction score (probability / risk). */\n score: number;\n /** Risk as a 0–100 integer, for display. */\n riskPct: number;\n /** Predicted class label, when present (classification). */\n class: string | null;\n /** Risk band, for color / filtering. */\n band: 'high' | 'medium' | 'low' | string;\n /** Qualitative status label (e.g. \"High\", \"Critical\", \"Low Risk\"). */\n status?: string;\n /** Semantic badge color. */\n badgeColor?: string;\n /** Icon class. */\n icon?: string;\n /**\n * Top signed per-record drivers behind THIS row's prediction (P1-5), humanized + one-hot-collapsed for\n * display. `up: true` pushed the risk up, `false` down. Null when the model doesn't produce per-record\n * attribution (tree/ensemble/multiclass) — the UI then shows the model's global drivers instead.\n */\n drivers: RowDriver[] | null;\n}\n\n/** A humanized, signed per-record driver for the at-risk row's inline \"why\". */\nexport interface RowDriver {\n /** Display label (humanized, one-hot base collapsed). */\n label: string;\n /** Signed contribution magnitude for this row. */\n value: number;\n /** Whether this pushed the risk UP (value > 0) or down. */\n up: boolean;\n}\n\n/** Parse + humanize the raw per-record `drivers` (post-preprocessing `feature`/`value`) into {@link RowDriver}s. */\nexport function parseRowDrivers(raw: unknown): RowDriver[] | null {\n if (!Array.isArray(raw) || raw.length === 0) return null;\n const out: RowDriver[] = [];\n for (const d of raw as Array<{ feature?: unknown; value?: unknown; importance?: unknown; weight?: unknown }>) {\n const feature = typeof d?.feature === 'string' ? d.feature : '';\n const rawVal = typeof d?.value === 'number' ? d.value : typeof d?.importance === 'number' ? d.importance : typeof d?.weight === 'number' ? d.weight : NaN;\n const value = Number(rawVal);\n if (!feature || !Number.isFinite(value)) continue;\n // Keep the one-hot category: for a per-record \"why\", the category IS the story — \"Membership Type =\n // Student lowers risk\" is actionable where a collapsed \"Membership Type\" is close to meaningless.\n // (Collapsing across categories is only right for GLOBAL importance — see topGlobalDrivers.)\n out.push({ label: humanizeFeatureName(feature), value, up: value > 0 });\n }\n return out.length > 0 ? out : null;\n}\n\n/**\n * Build a human-readable label for a record from its (simple) row of the target entity — preferring a\n * single `Name`, else `FirstName`+`LastName`, else `Email`, else any first non-empty string field.\n * Returns null when nothing usable is found (caller falls back to the record id).\n */\nexport function labelFromRecord(row: Record<string, unknown> | undefined | null): string | null {\n if (!row) return null;\n const str = (v: unknown): string => (typeof v === 'string' ? v.trim() : '');\n const member = str(row['MemberName'] || row['Member'] || row['FullName']);\n if (member) return member;\n const name = str(row['Name']);\n if (name) return name;\n const full = `${str(row['FirstName'])} ${str(row['LastName'])}`.trim();\n const email = str(row['Email']);\n if (full && email) return `${full} (${email})`;\n if (full) return full;\n if (email) return email;\n for (const v of Object.values(row)) {\n const s = str(v);\n if (s && s.length <= 120) return s;\n }\n return null;\n}\n\n/** The raw per-record detail the list is built from (a slice of `MJ: Process Run Details`). */\nexport interface RunDetailLike {\n recordId: string;\n ResultPayload?: string | null;\n}\n\n/** Options for parsing predictions into at-risk rows. */\nexport interface ParseAtRiskOptions {\n /**\n * When true, the model predicts probability of a positive outcome (e.g. `P(Renewed)`).\n * Churn / adverse risk is therefore inverted: `riskScore = 1.0 - score`.\n * High score (0.99) -> Low Risk (1%, green). Low score (0.10) -> High Risk (90%, red).\n */\n invertedRisk?: boolean;\n /**\n * Configured outcome metadata for the model (labels, thresholds, colors, icons).\n * When provided, `resolveScoreBand()` evaluates the dynamic band, status, badgeColor, and icon.\n */\n outcomeConfig?: OutcomeConfig;\n}\n\n/** Result of detecting whether a model is a renewal model and what its output score represents. */\nexport interface RenewalPolarityResult {\n isRenewalModel: boolean;\n /**\n * True if `score` represents adverse lapse risk (P(Lapse) / Churn Risk), e.g. 0.01 = 1% risk.\n * False if `score` represents positive outcome probability (P(Renewed)), e.g. 0.99 = 99% renewal chance.\n */\n scoreIsLapseRisk: boolean;\n}\n\n/**\n * Robustly inspects model metadata and sample scoring payloads to determine:\n * 1. Whether this is a renewal/retention/churn model (`isRenewalModel`)\n * 2. Whether the raw payload `score` represents adverse lapse risk (P(Lapse)) or positive outcome (P(Renewed))\n */\nexport function resolveRenewalPolarity(\n rawPayloads: Array<string | null | undefined>,\n targetVariable?: string | null,\n modelName?: string | null,\n): RenewalPolarityResult {\n const target = (targetVariable ?? '').toLowerCase();\n const name = (modelName ?? '').toLowerCase();\n const isTargetRenewal =\n target.includes('renew') ||\n target.includes('lapse') ||\n target.includes('retention') ||\n target.includes('churn') ||\n target === 'status' ||\n name.includes('renew') ||\n name.includes('retention') ||\n name.includes('churn');\n\n let hasRenewalKeywords = false;\n const sampleScoresForRenewed: number[] = [];\n\n for (const p of rawPayloads.slice(0, 50)) {\n if (!p) continue;\n if (\n p.includes('\"Renewed\"') ||\n p.includes('\"renewed\"') ||\n p.includes('\"Lapsed\"') ||\n p.includes('\"lapsed\"') ||\n p.includes('Renewal Risk')\n ) {\n hasRenewalKeywords = true;\n }\n try {\n const parsed = JSON.parse(p);\n const out = (parsed.output ?? parsed) as { score?: number; class?: string };\n if (typeof out.score === 'number' && typeof out.class === 'string') {\n const cls = out.class.toLowerCase();\n if (cls === 'renewed' || cls === 'active') {\n sampleScoresForRenewed.push(out.score);\n }\n }\n } catch {\n // skip invalid json\n }\n }\n\n const isRenewalModel = isTargetRenewal || hasRenewalKeywords;\n if (!isRenewalModel) {\n return { isRenewalModel: false, scoreIsLapseRisk: false };\n }\n\n if (sampleScoresForRenewed.length > 0) {\n const avg = sampleScoresForRenewed.reduce((a, b) => a + b, 0) / sampleScoresForRenewed.length;\n // If members predicted 'Renewed' have small scores (< 0.5), the score represents Lapse Risk (P(Lapse))\n return { isRenewalModel: true, scoreIsLapseRisk: avg < 0.5 };\n }\n\n // Fallback: target or name containing \"risk\", \"lapse\", or \"churn\" outputs lapse probability\n const scoreIsLapseRisk =\n target.includes('risk') ||\n target.includes('lapse') ||\n target.includes('churn') ||\n name.includes('risk') ||\n name.includes('churn');\n return { isRenewalModel: true, scoreIsLapseRisk };\n}\n\nfunction bandFor(score: number): AtRiskRow['band'] {\n return score >= 0.7 ? 'high' : score >= 0.4 ? 'medium' : 'low';\n}\n\n/** Parse + rank the per-record predictions into the at-risk list (highest risk first). */\nexport function parseAtRiskRows(details: RunDetailLike[], options?: ParseAtRiskOptions): AtRiskRow[] {\n const rows: AtRiskRow[] = [];\n const isInverted = options?.invertedRisk === true;\n const outcomeConfig = options?.outcomeConfig;\n\n for (const d of details) {\n if (!d.ResultPayload) continue;\n let parsed: {\n score?: number;\n class?: string;\n status?: string;\n band?: string;\n badgeColor?: string;\n icon?: string;\n drivers?: unknown;\n output?: {\n score?: number;\n class?: string;\n status?: string;\n band?: string;\n badgeColor?: string;\n icon?: string;\n drivers?: unknown;\n };\n };\n try {\n parsed = JSON.parse(d.ResultPayload);\n } catch {\n continue;\n }\n // Write-back runs nest the prediction under `output`; generic runs carry it at the top level.\n const p = parsed.output ?? parsed;\n if (typeof p.score !== 'number' || !Number.isFinite(p.score)) continue;\n const score = p.score;\n const effectiveRisk = isInverted ? Math.max(0, Math.min(1, 1 - score)) : score;\n const riskPct = Math.round(effectiveRisk * 100);\n\n let bandKey: string;\n let status: string | undefined = p.status;\n let badgeColor: string | undefined = p.badgeColor;\n let icon: string | undefined = p.icon;\n\n if (outcomeConfig) {\n const resolved = resolveScoreBand(score, outcomeConfig);\n if (resolved) {\n bandKey = resolved.Key;\n status = status ?? resolved.Label;\n badgeColor = badgeColor ?? resolved.BadgeColor;\n icon = icon ?? resolved.Icon;\n } else {\n bandKey = p.band ?? bandFor(effectiveRisk);\n }\n } else if (p.band) {\n bandKey = p.band;\n } else {\n bandKey = bandFor(effectiveRisk);\n }\n\n rows.push({\n recordId: d.recordId,\n label: null,\n score,\n riskPct,\n class: p.class ?? null,\n band: bandKey,\n status,\n badgeColor,\n icon,\n drivers: parseRowDrivers(p.drivers),\n });\n }\n return rows.sort((a, b) => b.riskPct - a.riskPct);\n}\n\n/**\n * The top plain-language drivers for the whole prediction, from the model's global feature importance.\n * Accepts the object form (`{\"MembershipType=Student\": 0.9, ...}`) or the array form\n * (`[{feature, importance}]`), strips one-hot `=value` suffixes, de-duplicates, and returns the\n * highest-importance feature names — so a business user sees \"what's driving this\", not raw weights.\n */\nexport function topGlobalDrivers(featureImportanceJson: string | null | undefined, n = 3): string[] {\n if (!featureImportanceJson) return [];\n let parsed: unknown;\n try {\n parsed = JSON.parse(featureImportanceJson);\n } catch {\n return [];\n }\n const pairs: Array<{ name: string; weight: number }> = [];\n if (Array.isArray(parsed)) {\n for (const e of parsed as Array<Record<string, unknown>>) {\n const name = (e.feature ?? e.name) as string | undefined;\n const weight = (e.importance ?? e.value) as number | undefined;\n if (typeof name === 'string' && typeof weight === 'number') pairs.push({ name, weight: Math.abs(weight) });\n }\n } else if (parsed && typeof parsed === 'object') {\n for (const [name, weight] of Object.entries(parsed as Record<string, unknown>)) {\n if (typeof weight === 'number') pairs.push({ name, weight: Math.abs(weight) });\n }\n }\n // Collapse one-hot columns (\"Feature=Value\" → \"Feature\"), keeping each feature's max weight.\n const byFeature = new Map<string, number>();\n for (const { name, weight } of pairs) {\n const base = name.split('=')[0].trim();\n if (!base) continue;\n byFeature.set(base, Math.max(byFeature.get(base) ?? 0, weight));\n }\n return [...byFeature.entries()].sort((a, b) => b[1] - a[1]).slice(0, n).map(([name]) => humanizeFeatureName(name));\n}\n\n/**\n * Turn a raw feature/column name into a readable label — `RetentionOverdueInvoices` → `Retention Overdue\n * Invoices`, `overdue_invoices` → `Overdue Invoices`, and a one-hot `MembershipType=Student` →\n * `Membership Type = Student`. Splits camelCase + snake/kebab, spaces one-hot `=`, collapses whitespace,\n * and capitalizes the first letter. Already-spaced labels pass through unchanged.\n */\nexport function humanizeFeatureName(name: string): string {\n return name\n .replace(/[_-]+/g, ' ')\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/\\s*=\\s*/g, ' = ')\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/^\\w/, (c) => c.toUpperCase());\n}\n"]}
|
|
@@ -18,6 +18,9 @@ export declare class PSCatalogComponent implements OnInit {
|
|
|
18
18
|
engine: PredictiveStudioEngine;
|
|
19
19
|
/** Emitted with a starter prompt to open + seed the Model Development Agent chat. */
|
|
20
20
|
askAgent: EventEmitter<string>;
|
|
21
|
+
/** Emitted when the user chooses to build a new training pipeline with this algorithm. */
|
|
22
|
+
createPipeline: EventEmitter<MJMLAlgorithmEntity>;
|
|
23
|
+
onCreatePipeline(algo: MJMLAlgorithmEntity): void;
|
|
21
24
|
selectedUseCaseIds: string[];
|
|
22
25
|
cards: AlgoCardVM[];
|
|
23
26
|
/** The algorithm whose inline detail panel is expanded (null = none). */
|
|
@@ -50,7 +53,7 @@ export declare class PSCatalogComponent implements OnInit {
|
|
|
50
53
|
};
|
|
51
54
|
private rebuildCards;
|
|
52
55
|
static ɵfac: i0.ɵɵFactoryDeclaration<PSCatalogComponent, never>;
|
|
53
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<PSCatalogComponent, "ps-catalog", never, { "engine": { "alias": "engine"; "required": false; }; }, { "askAgent": "askAgent"; }, never, never, true, never>;
|
|
56
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<PSCatalogComponent, "ps-catalog", never, { "engine": { "alias": "engine"; "required": false; }; }, { "askAgent": "askAgent"; "createPipeline": "createPipeline"; }, never, never, true, never>;
|
|
54
57
|
}
|
|
55
58
|
export {};
|
|
56
59
|
//# sourceMappingURL=ps-catalog.component.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ps-catalog.component.d.ts","sourceRoot":"","sources":["../../../src/PredictiveStudio/components/ps-catalog.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAS,MAAM,EAA6B,MAAM,eAAe,CAAC;AAIlG,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAChG,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAuB,MAAM,oCAAoC,CAAC;;AAEtH,UAAU,UAAU;IAClB,IAAI,EAAE,mBAAmB,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,mBAAmB,GAAG,IAAI,CAAC;CACvC;AAsBD;;;;;GAKG;AACH,
|
|
1
|
+
{"version":3,"file":"ps-catalog.component.d.ts","sourceRoot":"","sources":["../../../src/PredictiveStudio/components/ps-catalog.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAS,MAAM,EAA6B,MAAM,eAAe,CAAC;AAIlG,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAChG,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAuB,MAAM,oCAAoC,CAAC;;AAEtH,UAAU,UAAU;IAClB,IAAI,EAAE,mBAAmB,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,mBAAmB,GAAG,IAAI,CAAC;CACvC;AAsBD;;;;;GAKG;AACH,qBAyIa,kBAAmB,YAAW,MAAM;IACtC,MAAM,EAAG,sBAAsB,CAAC;IAEzC,qFAAqF;IAC3E,QAAQ,uBAA8B;IAChD,0FAA0F;IAChF,cAAc,oCAA2C;IAE5D,gBAAgB,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI;IAIjD,kBAAkB,EAAE,MAAM,EAAE,CAAM;IAClC,KAAK,EAAE,UAAU,EAAE,CAAM;IAChC,yEAAyE;IAClE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEtC,QAAQ,IAAI,IAAI;IAIhB,IAAW,QAAQ,IAAI,0BAA0B,EAAE,CAElD;IAEM,WAAW,CAAC,EAAE,EAAE,0BAA0B,GAAG,MAAM;IAYnD,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAI/B,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAS/B,cAAc,IAAI,IAAI;IAO7B,4DAA4D;IACrD,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIrC,mFAAmF;IAC5E,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI;IAOpD,gGAAgG;IACzF,WAAW,CAAC,IAAI,EAAE,mBAAmB,GAAG;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE;IAkBlE,IAAI,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM;IAIxC,UAAU,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM;IAUrD;;;;OAIG;IACH,IAAW,cAAc,IAAI;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,CAQ1E;IAED,OAAO,CAAC,YAAY;yCAtHT,kBAAkB;2CAAlB,kBAAkB;CAuI9B"}
|
|
@@ -79,7 +79,7 @@ function PSCatalogComponent_Conditional_16_Template(rf, ctx) { if (rf & 1) {
|
|
|
79
79
|
i0.ɵɵelementEnd()();
|
|
80
80
|
} }
|
|
81
81
|
function PSCatalogComponent_Conditional_17_For_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
82
|
-
i0.ɵɵelementStart(0, "div", 20)(1, "span",
|
|
82
|
+
i0.ɵɵelementStart(0, "div", 20)(1, "span", 42);
|
|
83
83
|
i0.ɵɵtext(2, "Primary");
|
|
84
84
|
i0.ɵɵelementEnd()();
|
|
85
85
|
} }
|
|
@@ -103,18 +103,18 @@ function PSCatalogComponent_Conditional_17_For_2_For_16_Template(rf, ctx) { if (
|
|
|
103
103
|
} }
|
|
104
104
|
function PSCatalogComponent_Conditional_17_For_2_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
105
105
|
i0.ɵɵelementStart(0, "span", 30);
|
|
106
|
-
i0.ɵɵelement(1, "i",
|
|
106
|
+
i0.ɵɵelement(1, "i", 43);
|
|
107
107
|
i0.ɵɵtext(2, " Feature importance");
|
|
108
108
|
i0.ɵɵelementEnd();
|
|
109
109
|
} }
|
|
110
110
|
function PSCatalogComponent_Conditional_17_For_2_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
111
111
|
i0.ɵɵelementStart(0, "span", 31);
|
|
112
|
-
i0.ɵɵelement(1, "i",
|
|
112
|
+
i0.ɵɵelement(1, "i", 44);
|
|
113
113
|
i0.ɵɵtext(2, " No importance");
|
|
114
114
|
i0.ɵɵelementEnd();
|
|
115
115
|
} }
|
|
116
116
|
function PSCatalogComponent_Conditional_17_For_2_Conditional_21_Template(rf, ctx) { if (rf & 1) {
|
|
117
|
-
i0.ɵɵelementStart(0, "span",
|
|
117
|
+
i0.ɵɵelementStart(0, "span", 45);
|
|
118
118
|
i0.ɵɵtext(1);
|
|
119
119
|
i0.ɵɵelementEnd();
|
|
120
120
|
} if (rf & 2) {
|
|
@@ -124,8 +124,8 @@ function PSCatalogComponent_Conditional_17_For_2_Conditional_21_Template(rf, ctx
|
|
|
124
124
|
i0.ɵɵadvance();
|
|
125
125
|
i0.ɵɵtextInterpolate(ctx_r2.levelLabel(card_r6.bestLevel));
|
|
126
126
|
} }
|
|
127
|
-
function
|
|
128
|
-
i0.ɵɵelementStart(0, "p",
|
|
127
|
+
function PSCatalogComponent_Conditional_17_For_2_Conditional_32_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
128
|
+
i0.ɵɵelementStart(0, "p", 46);
|
|
129
129
|
i0.ɵɵtext(1);
|
|
130
130
|
i0.ɵɵelementEnd();
|
|
131
131
|
} if (rf & 2) {
|
|
@@ -133,11 +133,11 @@ function PSCatalogComponent_Conditional_17_For_2_Conditional_29_Conditional_1_Te
|
|
|
133
133
|
i0.ɵɵadvance();
|
|
134
134
|
i0.ɵɵtextInterpolate(card_r6.algo.Description);
|
|
135
135
|
} }
|
|
136
|
-
function
|
|
137
|
-
i0.ɵɵelementStart(0, "div",
|
|
136
|
+
function PSCatalogComponent_Conditional_17_For_2_Conditional_32_Conditional_12_For_4_Template(rf, ctx) { if (rf & 1) {
|
|
137
|
+
i0.ɵɵelementStart(0, "div", 57)(1, "span", 58);
|
|
138
138
|
i0.ɵɵtext(2);
|
|
139
139
|
i0.ɵɵelementEnd();
|
|
140
|
-
i0.ɵɵelementStart(3, "span",
|
|
140
|
+
i0.ɵɵelementStart(3, "span", 59);
|
|
141
141
|
i0.ɵɵtext(4);
|
|
142
142
|
i0.ɵɵelementEnd()();
|
|
143
143
|
} if (rf & 2) {
|
|
@@ -147,12 +147,12 @@ function PSCatalogComponent_Conditional_17_For_2_Conditional_29_Conditional_12_F
|
|
|
147
147
|
i0.ɵɵadvance(2);
|
|
148
148
|
i0.ɵɵtextInterpolate(hp_r9.v);
|
|
149
149
|
} }
|
|
150
|
-
function
|
|
151
|
-
i0.ɵɵelementStart(0, "div",
|
|
150
|
+
function PSCatalogComponent_Conditional_17_For_2_Conditional_32_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
151
|
+
i0.ɵɵelementStart(0, "div", 55);
|
|
152
152
|
i0.ɵɵtext(1, "Default hyperparameters");
|
|
153
153
|
i0.ɵɵelementEnd();
|
|
154
|
-
i0.ɵɵelementStart(2, "div",
|
|
155
|
-
i0.ɵɵrepeaterCreate(3,
|
|
154
|
+
i0.ɵɵelementStart(2, "div", 56);
|
|
155
|
+
i0.ɵɵrepeaterCreate(3, PSCatalogComponent_Conditional_17_For_2_Conditional_32_Conditional_12_For_4_Template, 5, 2, "div", 57, _forTrack2);
|
|
156
156
|
i0.ɵɵelementEnd();
|
|
157
157
|
} if (rf & 2) {
|
|
158
158
|
const card_r6 = i0.ɵɵnextContext(2).$implicit;
|
|
@@ -160,32 +160,37 @@ function PSCatalogComponent_Conditional_17_For_2_Conditional_29_Conditional_12_T
|
|
|
160
160
|
i0.ɵɵadvance(3);
|
|
161
161
|
i0.ɵɵrepeater(ctx_r2.hyperparams(card_r6.algo));
|
|
162
162
|
} }
|
|
163
|
-
function
|
|
164
|
-
i0.ɵɵelementStart(0, "div",
|
|
163
|
+
function PSCatalogComponent_Conditional_17_For_2_Conditional_32_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
164
|
+
i0.ɵɵelementStart(0, "div", 51);
|
|
165
165
|
i0.ɵɵtext(1, "Sensible defaults are applied at training time.");
|
|
166
166
|
i0.ɵɵelementEnd();
|
|
167
167
|
} }
|
|
168
|
-
function
|
|
168
|
+
function PSCatalogComponent_Conditional_17_For_2_Conditional_32_Template(rf, ctx) { if (rf & 1) {
|
|
169
169
|
const _r8 = i0.ɵɵgetCurrentView();
|
|
170
|
-
i0.ɵɵelementStart(0, "div",
|
|
171
|
-
i0.ɵɵconditionalCreate(1,
|
|
172
|
-
i0.ɵɵelementStart(2, "div",
|
|
170
|
+
i0.ɵɵelementStart(0, "div", 41);
|
|
171
|
+
i0.ɵɵconditionalCreate(1, PSCatalogComponent_Conditional_17_For_2_Conditional_32_Conditional_1_Template, 2, 1, "p", 46);
|
|
172
|
+
i0.ɵɵelementStart(2, "div", 47)(3, "span", 48);
|
|
173
173
|
i0.ɵɵtext(4, "Problem types");
|
|
174
174
|
i0.ɵɵelementEnd();
|
|
175
|
-
i0.ɵɵelementStart(5, "span",
|
|
175
|
+
i0.ɵɵelementStart(5, "span", 49);
|
|
176
176
|
i0.ɵɵtext(6);
|
|
177
177
|
i0.ɵɵelementEnd()();
|
|
178
|
-
i0.ɵɵelementStart(7, "div",
|
|
178
|
+
i0.ɵɵelementStart(7, "div", 47)(8, "span", 48);
|
|
179
179
|
i0.ɵɵtext(9, "Driver class");
|
|
180
180
|
i0.ɵɵelementEnd();
|
|
181
|
-
i0.ɵɵelementStart(10, "span",
|
|
181
|
+
i0.ɵɵelementStart(10, "span", 50);
|
|
182
182
|
i0.ɵɵtext(11);
|
|
183
183
|
i0.ɵɵelementEnd()();
|
|
184
|
-
i0.ɵɵconditionalCreate(12,
|
|
185
|
-
i0.ɵɵelementStart(14, "div",
|
|
186
|
-
i0.ɵɵlistener("click", function
|
|
184
|
+
i0.ɵɵconditionalCreate(12, PSCatalogComponent_Conditional_17_For_2_Conditional_32_Conditional_12_Template, 5, 0)(13, PSCatalogComponent_Conditional_17_For_2_Conditional_32_Conditional_13_Template, 2, 0, "div", 51);
|
|
185
|
+
i0.ɵɵelementStart(14, "div", 52)(15, "button", 53);
|
|
186
|
+
i0.ɵɵlistener("click", function PSCatalogComponent_Conditional_17_For_2_Conditional_32_Template_button_click_15_listener() { i0.ɵɵrestoreView(_r8); const card_r6 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onCreatePipeline(card_r6.algo)); });
|
|
187
187
|
i0.ɵɵelement(16, "i", 38);
|
|
188
|
-
i0.ɵɵtext(17, "
|
|
188
|
+
i0.ɵɵtext(17, " Create Pipeline with this algorithm ");
|
|
189
|
+
i0.ɵɵelementEnd();
|
|
190
|
+
i0.ɵɵelementStart(18, "button", 54);
|
|
191
|
+
i0.ɵɵlistener("click", function PSCatalogComponent_Conditional_17_For_2_Conditional_32_Template_button_click_18_listener() { i0.ɵɵrestoreView(_r8); const card_r6 = i0.ɵɵnextContext().$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.useAlgorithm(card_r6.algo)); });
|
|
192
|
+
i0.ɵɵelement(19, "i", 40);
|
|
193
|
+
i0.ɵɵtext(20, " Ask Agent ");
|
|
189
194
|
i0.ɵɵelementEnd()()();
|
|
190
195
|
} if (rf & 2) {
|
|
191
196
|
const card_r6 = i0.ɵɵnextContext().$implicit;
|
|
@@ -232,11 +237,16 @@ function PSCatalogComponent_Conditional_17_For_2_Template(rf, ctx) { if (rf & 1)
|
|
|
232
237
|
i0.ɵɵtext(25, " Details ");
|
|
233
238
|
i0.ɵɵelementEnd();
|
|
234
239
|
i0.ɵɵelementStart(26, "button", 37);
|
|
235
|
-
i0.ɵɵlistener("click", function PSCatalogComponent_Conditional_17_For_2_Template_button_click_26_listener() { const card_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.
|
|
240
|
+
i0.ɵɵlistener("click", function PSCatalogComponent_Conditional_17_For_2_Template_button_click_26_listener() { const card_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.onCreatePipeline(card_r6.algo)); });
|
|
236
241
|
i0.ɵɵelement(27, "i", 38);
|
|
237
|
-
i0.ɵɵtext(28, "
|
|
242
|
+
i0.ɵɵtext(28, " Pipeline ");
|
|
243
|
+
i0.ɵɵelementEnd();
|
|
244
|
+
i0.ɵɵelementStart(29, "button", 39);
|
|
245
|
+
i0.ɵɵlistener("click", function PSCatalogComponent_Conditional_17_For_2_Template_button_click_29_listener() { const card_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r2 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r2.useAlgorithm(card_r6.algo)); });
|
|
246
|
+
i0.ɵɵelement(30, "i", 40);
|
|
247
|
+
i0.ɵɵtext(31, " Agent ");
|
|
238
248
|
i0.ɵɵelementEnd()();
|
|
239
|
-
i0.ɵɵconditionalCreate(
|
|
249
|
+
i0.ɵɵconditionalCreate(32, PSCatalogComponent_Conditional_17_For_2_Conditional_32_Template, 21, 4, "div", 41);
|
|
240
250
|
i0.ɵɵelementEnd();
|
|
241
251
|
} if (rf & 2) {
|
|
242
252
|
const card_r6 = ctx.$implicit;
|
|
@@ -260,12 +270,12 @@ function PSCatalogComponent_Conditional_17_For_2_Template(rf, ctx) { if (rf & 1)
|
|
|
260
270
|
i0.ɵɵconditional(card_r6.bestLevel ? 21 : -1);
|
|
261
271
|
i0.ɵɵadvance(2);
|
|
262
272
|
i0.ɵɵclassProp("on", ctx_r2.detailId === card_r6.algo.ID);
|
|
263
|
-
i0.ɵɵadvance(
|
|
264
|
-
i0.ɵɵconditional(ctx_r2.detailId === card_r6.algo.ID ?
|
|
273
|
+
i0.ɵɵadvance(9);
|
|
274
|
+
i0.ɵɵconditional(ctx_r2.detailId === card_r6.algo.ID ? 32 : -1);
|
|
265
275
|
} }
|
|
266
276
|
function PSCatalogComponent_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
267
277
|
i0.ɵɵelementStart(0, "div", 12);
|
|
268
|
-
i0.ɵɵrepeaterCreate(1, PSCatalogComponent_Conditional_17_For_2_Template,
|
|
278
|
+
i0.ɵɵrepeaterCreate(1, PSCatalogComponent_Conditional_17_For_2_Template, 33, 15, "div", 18, _forTrack1);
|
|
269
279
|
i0.ɵɵelementEnd();
|
|
270
280
|
} if (rf & 2) {
|
|
271
281
|
const ctx_r2 = i0.ɵɵnextContext();
|
|
@@ -300,6 +310,11 @@ export class PSCatalogComponent {
|
|
|
300
310
|
engine;
|
|
301
311
|
/** Emitted with a starter prompt to open + seed the Model Development Agent chat. */
|
|
302
312
|
askAgent = new EventEmitter();
|
|
313
|
+
/** Emitted when the user chooses to build a new training pipeline with this algorithm. */
|
|
314
|
+
createPipeline = new EventEmitter();
|
|
315
|
+
onCreatePipeline(algo) {
|
|
316
|
+
this.createPipeline.emit(algo);
|
|
317
|
+
}
|
|
303
318
|
selectedUseCaseIds = [];
|
|
304
319
|
cards = [];
|
|
305
320
|
/** The algorithm whose inline detail panel is expanded (null = none). */
|
|
@@ -416,7 +431,7 @@ export class PSCatalogComponent {
|
|
|
416
431
|
this.cards = cards;
|
|
417
432
|
}
|
|
418
433
|
static ɵfac = function PSCatalogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PSCatalogComponent)(); };
|
|
419
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PSCatalogComponent, selectors: [["ps-catalog"]], inputs: { engine: "engine" }, outputs: { askAgent: "askAgent" }, decls: 18, vars: 3, consts: [["data-testid", "ps-catalog-panel", 1, "ps-panel", "ps-catalog"], [1, "ps-card", "guide-card"], [1, "ps-card-body"], [1, "guide-head"], [1, "fa-solid", "fa-compass", 2, "color", "var(--mj-brand-primary)"], [1, "ps-muted", "ps-small"], [1, "chips-row"], ["data-testid", "ps-catalog-scenarios", 1, "chips"], ["data-testid", "ps-catalog-scenario-chip", 1, "chip", 3, "on"], [1, "clearx"], ["data-testid", "ps-catalog-reco-banner", 1, "ps-callout", "info", "reco-banner"], [1, "ps-card"], ["data-testid", "ps-catalog-gallery", 1, "gallery"], ["data-testid", "ps-catalog-scenario-chip", 1, "chip", 3, "click"], [1, "clearx", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "fa-solid", "fa-wand-magic-sparkles"], [1, "ps-card-body", "ps-muted"], ["data-testid", "ps-catalog-card", 1, "acard", 3, "hit", "dim"], ["data-testid", "ps-catalog-card", 1, "acard"], [1, "ribbon"], [1, "ah"], [1, "ic"], [1, "title"], [1, "nm"], [1, "ps-mono", "key"], [1, "ab"], [1, "kv-title"], [1, "meta-row"], [1, "ps-tag"], [1, "ps-badge", "green"], [1, "ps-badge", "red"], [1, "af"], [1, "ps-lvl", 3, "class"], [1, "ps-spacer"], ["mjButton", "", "variant", "secondary", "size", "sm", "data-testid", "ps-catalog-details", 3, "click"], [1, "fa-solid", "fa-circle-info"], ["mjButton", "", "variant", "primary", "size", "sm", "data-testid", "ps-catalog-use", 3, "click"], [1, "fa-solid", "fa-
|
|
434
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PSCatalogComponent, selectors: [["ps-catalog"]], inputs: { engine: "engine" }, outputs: { askAgent: "askAgent", createPipeline: "createPipeline" }, decls: 18, vars: 3, consts: [["data-testid", "ps-catalog-panel", 1, "ps-panel", "ps-catalog"], [1, "ps-card", "guide-card"], [1, "ps-card-body"], [1, "guide-head"], [1, "fa-solid", "fa-compass", 2, "color", "var(--mj-brand-primary)"], [1, "ps-muted", "ps-small"], [1, "chips-row"], ["data-testid", "ps-catalog-scenarios", 1, "chips"], ["data-testid", "ps-catalog-scenario-chip", 1, "chip", 3, "on"], [1, "clearx"], ["data-testid", "ps-catalog-reco-banner", 1, "ps-callout", "info", "reco-banner"], [1, "ps-card"], ["data-testid", "ps-catalog-gallery", 1, "gallery"], ["data-testid", "ps-catalog-scenario-chip", 1, "chip", 3, "click"], [1, "clearx", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "fa-solid", "fa-wand-magic-sparkles"], [1, "ps-card-body", "ps-muted"], ["data-testid", "ps-catalog-card", 1, "acard", 3, "hit", "dim"], ["data-testid", "ps-catalog-card", 1, "acard"], [1, "ribbon"], [1, "ah"], [1, "ic"], [1, "title"], [1, "nm"], [1, "ps-mono", "key"], [1, "ab"], [1, "kv-title"], [1, "meta-row"], [1, "ps-tag"], [1, "ps-badge", "green"], [1, "ps-badge", "red"], [1, "af"], [1, "ps-lvl", 3, "class"], [1, "ps-spacer"], ["mjButton", "", "variant", "secondary", "size", "sm", "data-testid", "ps-catalog-details", 3, "click"], [1, "fa-solid", "fa-circle-info"], ["mjButton", "", "variant", "secondary", "size", "sm", "data-testid", "ps-catalog-create-pipeline", 3, "click"], [1, "fa-solid", "fa-plus"], ["mjButton", "", "variant", "primary", "size", "sm", "data-testid", "ps-catalog-use", 3, "click"], [1, "fa-solid", "fa-robot"], ["data-testid", "ps-catalog-detail", 1, "adetail"], [1, "ps-lvl", "ps-lvl-Primary"], [1, "fa-solid", "fa-chart-column"], [1, "fa-solid", "fa-ban"], [1, "ps-lvl"], [1, "ps-small", "adetail-desc"], [1, "dkv"], [1, "dk"], [1, "dv"], [1, "dv", "ps-mono"], [1, "ps-small", "ps-muted", 2, "margin-top", "6px"], [1, "adetail-foot", 2, "display", "flex", "gap", "8px"], ["mjButton", "", "variant", "secondary", "size", "sm", 3, "click"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click"], [1, "dk", 2, "margin-top", "8px"], [1, "hp-list"], [1, "hp"], [1, "ps-mono"], [1, "ps-mono", "ps-muted"]], template: function PSCatalogComponent_Template(rf, ctx) { if (rf & 1) {
|
|
420
435
|
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div", 2)(3, "div", 3);
|
|
421
436
|
i0.ɵɵelement(4, "i", 4);
|
|
422
437
|
i0.ɵɵelementStart(5, "div")(6, "h3");
|
|
@@ -535,9 +550,13 @@ export class PSCatalogComponent {
|
|
|
535
550
|
[class.on]="detailId === card.algo.ID" (click)="toggleDetail(card.algo.ID)">
|
|
536
551
|
<i class="fa-solid fa-circle-info"></i> Details
|
|
537
552
|
</button>
|
|
553
|
+
<button mjButton variant="secondary" size="sm" data-testid="ps-catalog-create-pipeline"
|
|
554
|
+
(click)="onCreatePipeline(card.algo)">
|
|
555
|
+
<i class="fa-solid fa-plus"></i> Pipeline
|
|
556
|
+
</button>
|
|
538
557
|
<button mjButton variant="primary" size="sm" data-testid="ps-catalog-use"
|
|
539
558
|
(click)="useAlgorithm(card.algo)">
|
|
540
|
-
<i class="fa-solid fa-
|
|
559
|
+
<i class="fa-solid fa-robot"></i> Agent
|
|
541
560
|
</button>
|
|
542
561
|
</div>
|
|
543
562
|
@if (detailId === card.algo.ID) {
|
|
@@ -557,9 +576,12 @@ export class PSCatalogComponent {
|
|
|
557
576
|
} @else {
|
|
558
577
|
<div class="ps-small ps-muted" style="margin-top:6px">Sensible defaults are applied at training time.</div>
|
|
559
578
|
}
|
|
560
|
-
<div class="adetail-foot">
|
|
579
|
+
<div class="adetail-foot" style="display: flex; gap: 8px;">
|
|
580
|
+
<button mjButton variant="secondary" size="sm" (click)="onCreatePipeline(card.algo)">
|
|
581
|
+
<i class="fa-solid fa-plus"></i> Create Pipeline with this algorithm
|
|
582
|
+
</button>
|
|
561
583
|
<button mjButton variant="primary" size="sm" (click)="useAlgorithm(card.algo)">
|
|
562
|
-
<i class="fa-solid fa-
|
|
584
|
+
<i class="fa-solid fa-robot"></i> Ask Agent
|
|
563
585
|
</button>
|
|
564
586
|
</div>
|
|
565
587
|
</div>
|
|
@@ -574,6 +596,8 @@ export class PSCatalogComponent {
|
|
|
574
596
|
type: Input
|
|
575
597
|
}], askAgent: [{
|
|
576
598
|
type: Output
|
|
599
|
+
}], createPipeline: [{
|
|
600
|
+
type: Output
|
|
577
601
|
}] }); })();
|
|
578
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PSCatalogComponent, { className: "PSCatalogComponent", filePath: "src/PredictiveStudio/components/ps-catalog.component.ts", lineNumber:
|
|
602
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PSCatalogComponent, { className: "PSCatalogComponent", filePath: "src/PredictiveStudio/components/ps-catalog.component.ts", lineNumber: 178 }); })();
|
|
579
603
|
//# sourceMappingURL=ps-catalog.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ps-catalog.component.js","sourceRoot":"","sources":["../../../src/PredictiveStudio/components/ps-catalog.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { MJButtonDirective } from '@memberjunction/ng-ui-components';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { MJMLAlgorithmEntity, MJMLAlgorithmUseCaseEntity } from '@memberjunction/core-entities';\nimport { PredictiveStudioEngine, RecommendationLevel, RECOMMENDATION_RANK } from '../engine/predictive-studio.engine';\n\ninterface AlgoCardVM {\n algo: MJMLAlgorithmEntity;\n icon: string;\n problemTypes: string[];\n bestLevel: RecommendationLevel | null;\n}\n\nconst ALGO_ICONS: Record<string, string> = {\n xgboost: 'fa-solid fa-bolt',\n lightgbm: 'fa-solid fa-feather',\n logistic_regression: 'fa-solid fa-wave-square',\n random_forest: 'fa-solid fa-tree',\n ridge: 'fa-solid fa-ruler',\n linear_regression: 'fa-solid fa-ruler',\n mlp: 'fa-solid fa-network-wired',\n};\n\nconst USE_CASE_ICONS: Record<string, string> = {\n binary: 'fa-solid fa-circle-half-stroke',\n regression: 'fa-solid fa-arrow-trend-up',\n interpret: 'fa-solid fa-magnifying-glass-chart',\n tuning: 'fa-solid fa-sliders',\n large: 'fa-solid fa-gauge-high',\n embedding: 'fa-solid fa-vector-square',\n small: 'fa-solid fa-compress',\n};\n\n/**\n * Algorithm Catalog panel (mockup algorithms-2): a card gallery of the fixed algorithm catalog plus\n * a \"Guide me\" scenario picker. Selecting use-case chips highlights and re-sorts the algorithm cards\n * by each algorithm's best RecommendationLevel across the chosen scenarios — driven entirely by the\n * cached MJ: ML Algorithm Use Case Rankings matrix.\n */\n@Component({\n standalone: true,\n selector: 'ps-catalog',\n imports: [CommonModule, MJButtonDirective],\n encapsulation: ViewEncapsulation.None,\n styleUrls: ['../predictive-studio.shared.css', './ps-catalog.component.css'],\n template: `\n <div class=\"ps-panel ps-catalog\" data-testid=\"ps-catalog-panel\">\n <!-- Guide me scenario picker -->\n <div class=\"ps-card guide-card\">\n <div class=\"ps-card-body\">\n <div class=\"guide-head\">\n <i class=\"fa-solid fa-compass\" style=\"color: var(--mj-brand-primary)\"></i>\n <div>\n <h3>Guide me — what does your problem look like?</h3>\n <div class=\"ps-muted ps-small\">\n Tap the scenarios that describe your data and goals. We'll highlight the algorithms that fit\n and pull the best matches to the front. Pick one or several.\n </div>\n </div>\n </div>\n <div class=\"chips-row\">\n <div class=\"chips\" data-testid=\"ps-catalog-scenarios\">\n @for (uc of useCases; track uc.ID) {\n <button class=\"chip\" [class.on]=\"isSelected(uc.ID)\" data-testid=\"ps-catalog-scenario-chip\" (click)=\"toggleUseCase(uc.ID)\">\n <i [class]=\"useCaseIcon(uc)\"></i> {{ uc.Name }}\n </button>\n }\n </div>\n @if (selectedUseCaseIds.length > 0) {\n <button class=\"clearx\" (click)=\"clearScenarios()\"><i class=\"fa-solid fa-xmark\"></i> Clear</button>\n }\n </div>\n @if (selectedUseCaseIds.length > 0) {\n <div class=\"ps-callout info reco-banner\" data-testid=\"ps-catalog-reco-banner\">\n <i class=\"fa-solid fa-wand-magic-sparkles\"></i>\n @if (recommendation.primaries.length > 0) {\n <div>For <strong>{{ recommendation.scenarioLabel }}</strong>, your top pick(s):\n <strong>{{ recommendation.primaries.join(' & ') }}</strong>. Stronger fits are pulled to the front.</div>\n } @else {\n <div>For <strong>{{ recommendation.scenarioLabel }}</strong>, no single primary stands out —\n review the strong fits at the top.</div>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Card gallery -->\n @if (cards.length === 0) {\n <div class=\"ps-card\"><div class=\"ps-card-body ps-muted\">No algorithms in the catalog yet.</div></div>\n } @else {\n <div class=\"gallery\" data-testid=\"ps-catalog-gallery\">\n @for (card of cards; track card.algo.ID) {\n <div class=\"acard\" data-testid=\"ps-catalog-card\"\n [class.hit]=\"card.bestLevel === 'Primary'\"\n [class.dim]=\"card.bestLevel && rank(card.bestLevel) <= 1\">\n @if (card.bestLevel === 'Primary') {\n <div class=\"ribbon\"><span class=\"ps-lvl ps-lvl-Primary\">Primary</span></div>\n }\n <div class=\"ah\">\n <div class=\"ic\"><i [class]=\"card.icon\"></i></div>\n <div class=\"title\">\n <div class=\"nm\">{{ card.algo.Name }}</div>\n <div class=\"ps-mono key\">{{ card.algo.DriverClass }}</div>\n </div>\n </div>\n <div class=\"ab\">\n @if (card.algo.Description) {\n <div class=\"ps-muted ps-small\">{{ card.algo.Description }}</div>\n }\n <div class=\"kv-title\">Problem types</div>\n <div class=\"meta-row\">\n @for (pt of card.problemTypes; track pt) {\n <span class=\"ps-tag\">{{ pt }}</span>\n }\n </div>\n <div class=\"meta-row\">\n @if (card.algo.SupportsFeatureImportance) {\n <span class=\"ps-badge green\"><i class=\"fa-solid fa-chart-column\"></i> Feature importance</span>\n } @else {\n <span class=\"ps-badge red\"><i class=\"fa-solid fa-ban\"></i> No importance</span>\n }\n </div>\n </div>\n <div class=\"af\">\n @if (card.bestLevel) {\n <span class=\"ps-lvl\" [class]=\"'ps-lvl-' + card.bestLevel\">{{ levelLabel(card.bestLevel) }}</span>\n }\n <span class=\"ps-spacer\"></span>\n <button mjButton variant=\"secondary\" size=\"sm\" data-testid=\"ps-catalog-details\"\n [class.on]=\"detailId === card.algo.ID\" (click)=\"toggleDetail(card.algo.ID)\">\n <i class=\"fa-solid fa-circle-info\"></i> Details\n </button>\n <button mjButton variant=\"primary\" size=\"sm\" data-testid=\"ps-catalog-use\"\n (click)=\"useAlgorithm(card.algo)\">\n <i class=\"fa-solid fa-diagram-project\"></i> Use\n </button>\n </div>\n @if (detailId === card.algo.ID) {\n <div class=\"adetail\" data-testid=\"ps-catalog-detail\">\n @if (card.algo.Description) {\n <p class=\"ps-small adetail-desc\">{{ card.algo.Description }}</p>\n }\n <div class=\"dkv\"><span class=\"dk\">Problem types</span><span class=\"dv\">{{ card.problemTypes.join(', ') || '—' }}</span></div>\n <div class=\"dkv\"><span class=\"dk\">Driver class</span><span class=\"dv ps-mono\">{{ card.algo.DriverClass }}</span></div>\n @if (hyperparams(card.algo).length > 0) {\n <div class=\"dk\" style=\"margin-top:8px\">Default hyperparameters</div>\n <div class=\"hp-list\">\n @for (hp of hyperparams(card.algo); track hp.k) {\n <div class=\"hp\"><span class=\"ps-mono\">{{ hp.k }}</span><span class=\"ps-mono ps-muted\">{{ hp.v }}</span></div>\n }\n </div>\n } @else {\n <div class=\"ps-small ps-muted\" style=\"margin-top:6px\">Sensible defaults are applied at training time.</div>\n }\n <div class=\"adetail-foot\">\n <button mjButton variant=\"primary\" size=\"sm\" (click)=\"useAlgorithm(card.algo)\">\n <i class=\"fa-solid fa-diagram-project\"></i> Use this algorithm\n </button>\n </div>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n `,\n})\nexport class PSCatalogComponent implements OnInit {\n @Input() engine!: PredictiveStudioEngine;\n\n /** Emitted with a starter prompt to open + seed the Model Development Agent chat. */\n @Output() askAgent = new EventEmitter<string>();\n\n public selectedUseCaseIds: string[] = [];\n public cards: AlgoCardVM[] = [];\n /** The algorithm whose inline detail panel is expanded (null = none). */\n public detailId: string | null = null;\n\n ngOnInit(): void {\n this.rebuildCards();\n }\n\n public get useCases(): MJMLAlgorithmUseCaseEntity[] {\n return this.engine?.UseCases ?? [];\n }\n\n public useCaseIcon(uc: MJMLAlgorithmUseCaseEntity): string {\n const name = (uc.Name || '').toLowerCase();\n if (name.includes('binary')) return USE_CASE_ICONS['binary'];\n if (name.includes('regression')) return USE_CASE_ICONS['regression'];\n if (name.includes('interpret')) return USE_CASE_ICONS['interpret'];\n if (name.includes('tuning') || name.includes('minimal')) return USE_CASE_ICONS['tuning'];\n if (name.includes('large') || name.includes('wide') || name.includes('speed')) return USE_CASE_ICONS['large'];\n if (name.includes('embedding') || name.includes('llm')) return USE_CASE_ICONS['embedding'];\n if (name.includes('small')) return USE_CASE_ICONS['small'];\n return 'fa-solid fa-circle-dot';\n }\n\n public isSelected(id: string): boolean {\n return this.selectedUseCaseIds.some((s) => UUIDsEqual(s, id));\n }\n\n public toggleUseCase(id: string): void {\n if (this.isSelected(id)) {\n this.selectedUseCaseIds = this.selectedUseCaseIds.filter((s) => !UUIDsEqual(s, id));\n } else {\n this.selectedUseCaseIds = [...this.selectedUseCaseIds, id];\n }\n this.rebuildCards();\n }\n\n public clearScenarios(): void {\n this.selectedUseCaseIds = [];\n this.rebuildCards();\n }\n\n // ---- algorithm card actions ----\n\n /** Toggle the inline detail panel for an algorithm card. */\n public toggleDetail(id: string): void {\n this.detailId = this.detailId === id ? null : id;\n }\n\n /** Seed the Model Development Agent to build a model with the chosen algorithm. */\n public useAlgorithm(algo: MJMLAlgorithmEntity): void {\n this.askAgent.emit(\n `Help me build a predictive model using the ${algo.Name} algorithm. ` +\n `Walk me through choosing the entity, the outcome to predict, and the features to assemble.`,\n );\n }\n\n /** Parse an algorithm's `DefaultHyperparameters` JSON into a small key/value list (≤8 rows). */\n public hyperparams(algo: MJMLAlgorithmEntity): { k: string; v: string }[] {\n const raw = algo.DefaultHyperparameters;\n if (!raw) {\n return [];\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n if (!parsed || typeof parsed !== 'object') {\n return [];\n }\n return Object.entries(parsed as Record<string, unknown>)\n .map(([k, v]) => ({ k, v: String(v) }))\n .slice(0, 8);\n } catch {\n return [];\n }\n }\n\n public rank(level: RecommendationLevel): number {\n return RECOMMENDATION_RANK[level];\n }\n\n public levelLabel(level: RecommendationLevel): string {\n switch (level) {\n case 'Primary': return 'Primary fit';\n case 'Strong': return 'Strong fit';\n case 'Viable': return 'Viable';\n case 'Weak': return 'Weak fit';\n case 'NotRecommended': return 'N/A';\n }\n }\n\n /**\n * Structured recommendation data for the \"Guide me\" banner — rendered with plain template\n * interpolation + `<strong>` markup (no `[innerHTML]`). `scenarioLabel` is the human-readable\n * scenario name(s); `primaries` is the list of Primary-fit algorithm names.\n */\n public get recommendation(): { scenarioLabel: string; primaries: string[] } {\n const levels = this.engine.BestLevelsForScenarios(this.selectedUseCaseIds);\n const primaries = this.engine.Algorithms.filter((a) => levels.get(a.ID) === 'Primary').map((a) => a.Name);\n const scenarioLabel =\n this.selectedUseCaseIds.length === 1\n ? this.useCases.find((u) => UUIDsEqual(u.ID, this.selectedUseCaseIds[0]))?.Name ?? 'your scenario'\n : `${this.selectedUseCaseIds.length} scenarios`;\n return { scenarioLabel, primaries };\n }\n\n private rebuildCards(): void {\n const levels = this.engine.BestLevelsForScenarios(this.selectedUseCaseIds);\n const cards: AlgoCardVM[] = this.engine.Algorithms.map((algo) => ({\n algo,\n icon: ALGO_ICONS[algo.DriverClass] ?? 'fa-solid fa-shapes',\n problemTypes: (algo.ProblemTypes || '').split(',').map((p) => p.trim()).filter((p) => p.length > 0),\n bestLevel: levels.get(algo.ID) ?? null,\n }));\n if (this.selectedUseCaseIds.length > 0) {\n cards.sort((a, b) => {\n const ra = a.bestLevel ? RECOMMENDATION_RANK[a.bestLevel] : -1;\n const rb = b.bestLevel ? RECOMMENDATION_RANK[b.bestLevel] : -1;\n return rb - ra;\n });\n }\n this.cards = cards;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ps-catalog.component.js","sourceRoot":"","sources":["../../../src/PredictiveStudio/components/ps-catalog.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { MJButtonDirective } from '@memberjunction/ng-ui-components';\nimport { UUIDsEqual } from '@memberjunction/global';\nimport { MJMLAlgorithmEntity, MJMLAlgorithmUseCaseEntity } from '@memberjunction/core-entities';\nimport { PredictiveStudioEngine, RecommendationLevel, RECOMMENDATION_RANK } from '../engine/predictive-studio.engine';\n\ninterface AlgoCardVM {\n algo: MJMLAlgorithmEntity;\n icon: string;\n problemTypes: string[];\n bestLevel: RecommendationLevel | null;\n}\n\nconst ALGO_ICONS: Record<string, string> = {\n xgboost: 'fa-solid fa-bolt',\n lightgbm: 'fa-solid fa-feather',\n logistic_regression: 'fa-solid fa-wave-square',\n random_forest: 'fa-solid fa-tree',\n ridge: 'fa-solid fa-ruler',\n linear_regression: 'fa-solid fa-ruler',\n mlp: 'fa-solid fa-network-wired',\n};\n\nconst USE_CASE_ICONS: Record<string, string> = {\n binary: 'fa-solid fa-circle-half-stroke',\n regression: 'fa-solid fa-arrow-trend-up',\n interpret: 'fa-solid fa-magnifying-glass-chart',\n tuning: 'fa-solid fa-sliders',\n large: 'fa-solid fa-gauge-high',\n embedding: 'fa-solid fa-vector-square',\n small: 'fa-solid fa-compress',\n};\n\n/**\n * Algorithm Catalog panel (mockup algorithms-2): a card gallery of the fixed algorithm catalog plus\n * a \"Guide me\" scenario picker. Selecting use-case chips highlights and re-sorts the algorithm cards\n * by each algorithm's best RecommendationLevel across the chosen scenarios — driven entirely by the\n * cached MJ: ML Algorithm Use Case Rankings matrix.\n */\n@Component({\n standalone: true,\n selector: 'ps-catalog',\n imports: [CommonModule, MJButtonDirective],\n encapsulation: ViewEncapsulation.None,\n styleUrls: ['../predictive-studio.shared.css', './ps-catalog.component.css'],\n template: `\n <div class=\"ps-panel ps-catalog\" data-testid=\"ps-catalog-panel\">\n <!-- Guide me scenario picker -->\n <div class=\"ps-card guide-card\">\n <div class=\"ps-card-body\">\n <div class=\"guide-head\">\n <i class=\"fa-solid fa-compass\" style=\"color: var(--mj-brand-primary)\"></i>\n <div>\n <h3>Guide me — what does your problem look like?</h3>\n <div class=\"ps-muted ps-small\">\n Tap the scenarios that describe your data and goals. We'll highlight the algorithms that fit\n and pull the best matches to the front. Pick one or several.\n </div>\n </div>\n </div>\n <div class=\"chips-row\">\n <div class=\"chips\" data-testid=\"ps-catalog-scenarios\">\n @for (uc of useCases; track uc.ID) {\n <button class=\"chip\" [class.on]=\"isSelected(uc.ID)\" data-testid=\"ps-catalog-scenario-chip\" (click)=\"toggleUseCase(uc.ID)\">\n <i [class]=\"useCaseIcon(uc)\"></i> {{ uc.Name }}\n </button>\n }\n </div>\n @if (selectedUseCaseIds.length > 0) {\n <button class=\"clearx\" (click)=\"clearScenarios()\"><i class=\"fa-solid fa-xmark\"></i> Clear</button>\n }\n </div>\n @if (selectedUseCaseIds.length > 0) {\n <div class=\"ps-callout info reco-banner\" data-testid=\"ps-catalog-reco-banner\">\n <i class=\"fa-solid fa-wand-magic-sparkles\"></i>\n @if (recommendation.primaries.length > 0) {\n <div>For <strong>{{ recommendation.scenarioLabel }}</strong>, your top pick(s):\n <strong>{{ recommendation.primaries.join(' & ') }}</strong>. Stronger fits are pulled to the front.</div>\n } @else {\n <div>For <strong>{{ recommendation.scenarioLabel }}</strong>, no single primary stands out —\n review the strong fits at the top.</div>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Card gallery -->\n @if (cards.length === 0) {\n <div class=\"ps-card\"><div class=\"ps-card-body ps-muted\">No algorithms in the catalog yet.</div></div>\n } @else {\n <div class=\"gallery\" data-testid=\"ps-catalog-gallery\">\n @for (card of cards; track card.algo.ID) {\n <div class=\"acard\" data-testid=\"ps-catalog-card\"\n [class.hit]=\"card.bestLevel === 'Primary'\"\n [class.dim]=\"card.bestLevel && rank(card.bestLevel) <= 1\">\n @if (card.bestLevel === 'Primary') {\n <div class=\"ribbon\"><span class=\"ps-lvl ps-lvl-Primary\">Primary</span></div>\n }\n <div class=\"ah\">\n <div class=\"ic\"><i [class]=\"card.icon\"></i></div>\n <div class=\"title\">\n <div class=\"nm\">{{ card.algo.Name }}</div>\n <div class=\"ps-mono key\">{{ card.algo.DriverClass }}</div>\n </div>\n </div>\n <div class=\"ab\">\n @if (card.algo.Description) {\n <div class=\"ps-muted ps-small\">{{ card.algo.Description }}</div>\n }\n <div class=\"kv-title\">Problem types</div>\n <div class=\"meta-row\">\n @for (pt of card.problemTypes; track pt) {\n <span class=\"ps-tag\">{{ pt }}</span>\n }\n </div>\n <div class=\"meta-row\">\n @if (card.algo.SupportsFeatureImportance) {\n <span class=\"ps-badge green\"><i class=\"fa-solid fa-chart-column\"></i> Feature importance</span>\n } @else {\n <span class=\"ps-badge red\"><i class=\"fa-solid fa-ban\"></i> No importance</span>\n }\n </div>\n </div>\n <div class=\"af\">\n @if (card.bestLevel) {\n <span class=\"ps-lvl\" [class]=\"'ps-lvl-' + card.bestLevel\">{{ levelLabel(card.bestLevel) }}</span>\n }\n <span class=\"ps-spacer\"></span>\n <button mjButton variant=\"secondary\" size=\"sm\" data-testid=\"ps-catalog-details\"\n [class.on]=\"detailId === card.algo.ID\" (click)=\"toggleDetail(card.algo.ID)\">\n <i class=\"fa-solid fa-circle-info\"></i> Details\n </button>\n <button mjButton variant=\"secondary\" size=\"sm\" data-testid=\"ps-catalog-create-pipeline\"\n (click)=\"onCreatePipeline(card.algo)\">\n <i class=\"fa-solid fa-plus\"></i> Pipeline\n </button>\n <button mjButton variant=\"primary\" size=\"sm\" data-testid=\"ps-catalog-use\"\n (click)=\"useAlgorithm(card.algo)\">\n <i class=\"fa-solid fa-robot\"></i> Agent\n </button>\n </div>\n @if (detailId === card.algo.ID) {\n <div class=\"adetail\" data-testid=\"ps-catalog-detail\">\n @if (card.algo.Description) {\n <p class=\"ps-small adetail-desc\">{{ card.algo.Description }}</p>\n }\n <div class=\"dkv\"><span class=\"dk\">Problem types</span><span class=\"dv\">{{ card.problemTypes.join(', ') || '—' }}</span></div>\n <div class=\"dkv\"><span class=\"dk\">Driver class</span><span class=\"dv ps-mono\">{{ card.algo.DriverClass }}</span></div>\n @if (hyperparams(card.algo).length > 0) {\n <div class=\"dk\" style=\"margin-top:8px\">Default hyperparameters</div>\n <div class=\"hp-list\">\n @for (hp of hyperparams(card.algo); track hp.k) {\n <div class=\"hp\"><span class=\"ps-mono\">{{ hp.k }}</span><span class=\"ps-mono ps-muted\">{{ hp.v }}</span></div>\n }\n </div>\n } @else {\n <div class=\"ps-small ps-muted\" style=\"margin-top:6px\">Sensible defaults are applied at training time.</div>\n }\n <div class=\"adetail-foot\" style=\"display: flex; gap: 8px;\">\n <button mjButton variant=\"secondary\" size=\"sm\" (click)=\"onCreatePipeline(card.algo)\">\n <i class=\"fa-solid fa-plus\"></i> Create Pipeline with this algorithm\n </button>\n <button mjButton variant=\"primary\" size=\"sm\" (click)=\"useAlgorithm(card.algo)\">\n <i class=\"fa-solid fa-robot\"></i> Ask Agent\n </button>\n </div>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n `,\n})\nexport class PSCatalogComponent implements OnInit {\n @Input() engine!: PredictiveStudioEngine;\n\n /** Emitted with a starter prompt to open + seed the Model Development Agent chat. */\n @Output() askAgent = new EventEmitter<string>();\n /** Emitted when the user chooses to build a new training pipeline with this algorithm. */\n @Output() createPipeline = new EventEmitter<MJMLAlgorithmEntity>();\n\n public onCreatePipeline(algo: MJMLAlgorithmEntity): void {\n this.createPipeline.emit(algo);\n }\n\n public selectedUseCaseIds: string[] = [];\n public cards: AlgoCardVM[] = [];\n /** The algorithm whose inline detail panel is expanded (null = none). */\n public detailId: string | null = null;\n\n ngOnInit(): void {\n this.rebuildCards();\n }\n\n public get useCases(): MJMLAlgorithmUseCaseEntity[] {\n return this.engine?.UseCases ?? [];\n }\n\n public useCaseIcon(uc: MJMLAlgorithmUseCaseEntity): string {\n const name = (uc.Name || '').toLowerCase();\n if (name.includes('binary')) return USE_CASE_ICONS['binary'];\n if (name.includes('regression')) return USE_CASE_ICONS['regression'];\n if (name.includes('interpret')) return USE_CASE_ICONS['interpret'];\n if (name.includes('tuning') || name.includes('minimal')) return USE_CASE_ICONS['tuning'];\n if (name.includes('large') || name.includes('wide') || name.includes('speed')) return USE_CASE_ICONS['large'];\n if (name.includes('embedding') || name.includes('llm')) return USE_CASE_ICONS['embedding'];\n if (name.includes('small')) return USE_CASE_ICONS['small'];\n return 'fa-solid fa-circle-dot';\n }\n\n public isSelected(id: string): boolean {\n return this.selectedUseCaseIds.some((s) => UUIDsEqual(s, id));\n }\n\n public toggleUseCase(id: string): void {\n if (this.isSelected(id)) {\n this.selectedUseCaseIds = this.selectedUseCaseIds.filter((s) => !UUIDsEqual(s, id));\n } else {\n this.selectedUseCaseIds = [...this.selectedUseCaseIds, id];\n }\n this.rebuildCards();\n }\n\n public clearScenarios(): void {\n this.selectedUseCaseIds = [];\n this.rebuildCards();\n }\n\n // ---- algorithm card actions ----\n\n /** Toggle the inline detail panel for an algorithm card. */\n public toggleDetail(id: string): void {\n this.detailId = this.detailId === id ? null : id;\n }\n\n /** Seed the Model Development Agent to build a model with the chosen algorithm. */\n public useAlgorithm(algo: MJMLAlgorithmEntity): void {\n this.askAgent.emit(\n `Help me build a predictive model using the ${algo.Name} algorithm. ` +\n `Walk me through choosing the entity, the outcome to predict, and the features to assemble.`,\n );\n }\n\n /** Parse an algorithm's `DefaultHyperparameters` JSON into a small key/value list (≤8 rows). */\n public hyperparams(algo: MJMLAlgorithmEntity): { k: string; v: string }[] {\n const raw = algo.DefaultHyperparameters;\n if (!raw) {\n return [];\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n if (!parsed || typeof parsed !== 'object') {\n return [];\n }\n return Object.entries(parsed as Record<string, unknown>)\n .map(([k, v]) => ({ k, v: String(v) }))\n .slice(0, 8);\n } catch {\n return [];\n }\n }\n\n public rank(level: RecommendationLevel): number {\n return RECOMMENDATION_RANK[level];\n }\n\n public levelLabel(level: RecommendationLevel): string {\n switch (level) {\n case 'Primary': return 'Primary fit';\n case 'Strong': return 'Strong fit';\n case 'Viable': return 'Viable';\n case 'Weak': return 'Weak fit';\n case 'NotRecommended': return 'N/A';\n }\n }\n\n /**\n * Structured recommendation data for the \"Guide me\" banner — rendered with plain template\n * interpolation + `<strong>` markup (no `[innerHTML]`). `scenarioLabel` is the human-readable\n * scenario name(s); `primaries` is the list of Primary-fit algorithm names.\n */\n public get recommendation(): { scenarioLabel: string; primaries: string[] } {\n const levels = this.engine.BestLevelsForScenarios(this.selectedUseCaseIds);\n const primaries = this.engine.Algorithms.filter((a) => levels.get(a.ID) === 'Primary').map((a) => a.Name);\n const scenarioLabel =\n this.selectedUseCaseIds.length === 1\n ? this.useCases.find((u) => UUIDsEqual(u.ID, this.selectedUseCaseIds[0]))?.Name ?? 'your scenario'\n : `${this.selectedUseCaseIds.length} scenarios`;\n return { scenarioLabel, primaries };\n }\n\n private rebuildCards(): void {\n const levels = this.engine.BestLevelsForScenarios(this.selectedUseCaseIds);\n const cards: AlgoCardVM[] = this.engine.Algorithms.map((algo) => ({\n algo,\n icon: ALGO_ICONS[algo.DriverClass] ?? 'fa-solid fa-shapes',\n problemTypes: (algo.ProblemTypes || '').split(',').map((p) => p.trim()).filter((p) => p.length > 0),\n bestLevel: levels.get(algo.ID) ?? null,\n }));\n if (this.selectedUseCaseIds.length > 0) {\n cards.sort((a, b) => {\n const ra = a.bestLevel ? RECOMMENDATION_RANK[a.bestLevel] : -1;\n const rb = b.bestLevel ? RECOMMENDATION_RANK[b.bestLevel] : -1;\n return rb - ra;\n });\n }\n this.cards = cards;\n }\n}\n"]}
|