@memberjunction/ai-recommendations 4.0.0 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +376 -0
  2. package/package.json +5 -5
  3. package/readme.md +315 -176
package/README.md ADDED
@@ -0,0 +1,376 @@
1
+ # @memberjunction/ai-recommendations
2
+
3
+ A provider-based recommendation engine for MemberJunction. Manages recommendation runs, delegates to pluggable providers via the class factory, and tracks results through Recommendation, Recommendation Run, and Recommendation Item entities.
4
+
5
+ ## Architecture
6
+
7
+ ```mermaid
8
+ graph TD
9
+ subgraph Engine["@memberjunction/ai-recommendations"]
10
+ REB["RecommendationEngineBase<br/>(singleton BaseEngine)"]
11
+ RPB["RecommendationProviderBase<br/>(abstract)"]
12
+ RR["RecommendationRequest&lt;T&gt;"]
13
+ RRES["RecommendationResult"]
14
+ end
15
+
16
+ subgraph Providers["Registered Providers"]
17
+ P1["Provider A"]
18
+ P2["Provider B"]
19
+ end
20
+
21
+ subgraph MJEntities["MemberJunction Entities"]
22
+ RP["Recommendation Providers"]
23
+ RUN["Recommendation Runs"]
24
+ REC["Recommendations"]
25
+ RI["Recommendation Items"]
26
+ LIST["Lists / List Details"]
27
+ end
28
+
29
+ subgraph MJCore["MemberJunction Core"]
30
+ BE["BaseEngine"]
31
+ CF["ClassFactory"]
32
+ MD["Metadata"]
33
+ end
34
+
35
+ REB -->|extends| BE
36
+ REB -->|discovers| CF
37
+ CF -->|creates| P1
38
+ CF -->|creates| P2
39
+ P1 -->|extends| RPB
40
+ P2 -->|extends| RPB
41
+ REB --> RP
42
+ REB --> RUN
43
+ RPB --> REC
44
+ RPB --> RI
45
+ REB --> LIST
46
+
47
+ style Engine fill:#2d6a9f,stroke:#1a4971,color:#fff
48
+ style Providers fill:#2d8659,stroke:#1a5c3a,color:#fff
49
+ style MJEntities fill:#b8762f,stroke:#8a5722,color:#fff
50
+ style MJCore fill:#7c5295,stroke:#563a6b,color:#fff
51
+ ```
52
+
53
+ ## Installation
54
+
55
+ ```bash
56
+ npm install @memberjunction/ai-recommendations
57
+ ```
58
+
59
+ ## Overview
60
+
61
+ This package provides the framework for running recommendations in MemberJunction. It follows the engine/provider pattern used throughout the platform:
62
+
63
+ 1. **RecommendationEngineBase** -- a singleton engine (extending `BaseEngine`) that loads provider metadata, selects a provider, creates Recommendation Run tracking records, and delegates the actual recommendation logic
64
+ 2. **RecommendationProviderBase** -- an abstract class that concrete providers implement to generate recommendations for each source record
65
+ 3. **RecommendationRequest/RecommendationResult** -- typed request and response objects that flow through the pipeline
66
+
67
+ Providers are discovered at runtime through MemberJunction's `ClassFactory` using `@RegisterClass(RecommendationProviderBase, 'ProviderName')`.
68
+
69
+ ## Recommendation Flow
70
+
71
+ ```mermaid
72
+ sequenceDiagram
73
+ participant Caller
74
+ participant Engine as RecommendationEngineBase
75
+ participant CF as ClassFactory
76
+ participant Provider as RecommendationProvider
77
+ participant DB as MJ Database
78
+
79
+ Caller->>Engine: Recommend(request)
80
+ Engine->>Engine: TryThrowIfNotLoaded()
81
+
82
+ alt Provider specified
83
+ Engine->>Engine: Use request.Provider
84
+ else No provider
85
+ Engine->>Engine: Use first available
86
+ end
87
+
88
+ Engine->>Engine: GetRecommendationEntities(request)
89
+
90
+ alt From List
91
+ Engine->>DB: Load List + List Details
92
+ Engine->>DB: Load entity records by IDs
93
+ else From EntityAndRecordsInfo
94
+ Engine->>DB: Load records by entity name + IDs
95
+ else Pre-built
96
+ Engine->>Engine: Validate Recommendations array
97
+ end
98
+
99
+ Engine->>DB: Create Recommendation Run (Status: In Progress)
100
+
101
+ opt CreateErrorList = true
102
+ Engine->>DB: Create error tracking List
103
+ end
104
+
105
+ Engine->>CF: CreateInstance(provider.Name)
106
+ CF-->>Engine: Provider instance
107
+
108
+ Engine->>Provider: Recommend(request)
109
+
110
+ loop For each recommendation
111
+ Provider->>Provider: Call external API
112
+ Provider->>DB: SaveRecommendation + Items
113
+ end
114
+
115
+ Provider-->>Engine: RecommendationResult
116
+
117
+ Engine->>DB: Update Run (Completed/Error)
118
+ Engine-->>Caller: RecommendationResult
119
+ ```
120
+
121
+ ## Core Components
122
+
123
+ ### RecommendationEngineBase
124
+
125
+ A singleton engine that manages the recommendation lifecycle.
126
+
127
+ ```typescript
128
+ import { RecommendationEngineBase } from '@memberjunction/ai-recommendations';
129
+
130
+ // Access the singleton
131
+ const engine = RecommendationEngineBase.Instance;
132
+
133
+ // Initialize (loads Recommendation Providers metadata)
134
+ await engine.Config(false, contextUser);
135
+
136
+ // Run recommendations
137
+ const result = await engine.Recommend(request);
138
+ ```
139
+
140
+ **Key properties and methods:**
141
+
142
+ | Member | Description |
143
+ |---|---|
144
+ | `Instance` | Static getter for the singleton instance |
145
+ | `RecommendationProviders` | Array of `RecommendationProviderEntity` loaded from metadata |
146
+ | `Config(forceRefresh?, contextUser?, provider?)` | Loads provider metadata into cache |
147
+ | `Recommend<T>(request)` | Runs the full recommendation pipeline |
148
+
149
+ ### RecommendationProviderBase
150
+
151
+ Abstract base class for implementing recommendation providers.
152
+
153
+ ```mermaid
154
+ classDiagram
155
+ class RecommendationProviderBase {
156
+ <<abstract>>
157
+ -_md : Metadata
158
+ -_ContextUser : UserInfo
159
+ +ContextUser : UserInfo
160
+ +Recommend(request)* RecommendationResult
161
+ #SaveRecommendation(rec, runID, items) boolean
162
+ }
163
+
164
+ class ConcreteProvider {
165
+ +Recommend(request) RecommendationResult
166
+ }
167
+
168
+ RecommendationProviderBase <|-- ConcreteProvider
169
+
170
+ style RecommendationProviderBase fill:#2d6a9f,stroke:#1a4971,color:#fff
171
+ style ConcreteProvider fill:#2d8659,stroke:#1a5c3a,color:#fff
172
+ ```
173
+
174
+ The `SaveRecommendation` helper method handles:
175
+ 1. Setting the `RecommendationRunID` on the recommendation entity
176
+ 2. Saving the recommendation record
177
+ 3. Linking and saving all `RecommendationItemEntity` records
178
+
179
+ ### RecommendationRequest\<T\>
180
+
181
+ The request object supports three ways to specify source records:
182
+
183
+ ```mermaid
184
+ graph TD
185
+ RR["RecommendationRequest"]
186
+ OPT1["Recommendations[]<br/>Pre-built entities"]
187
+ OPT2["EntityAndRecordsInfo<br/>Entity name + Record IDs"]
188
+ OPT3["ListID<br/>MJ List reference"]
189
+
190
+ RR --> OPT1
191
+ RR --> OPT2
192
+ RR --> OPT3
193
+
194
+ style RR fill:#2d6a9f,stroke:#1a4971,color:#fff
195
+ style OPT1 fill:#2d8659,stroke:#1a5c3a,color:#fff
196
+ style OPT2 fill:#2d8659,stroke:#1a5c3a,color:#fff
197
+ style OPT3 fill:#2d8659,stroke:#1a5c3a,color:#fff
198
+ ```
199
+
200
+ | Field | Type | Description |
201
+ |---|---|---|
202
+ | `Recommendations` | `RecommendationEntity[]` | Pre-built unsaved recommendation entities |
203
+ | `EntityAndRecordsInfo` | `{ EntityName, RecordIDs }` | Entity name and array of record IDs to process |
204
+ | `ListID` | `string` | ID of a MJ List whose details become the source records |
205
+ | `Provider` | `RecommendationProviderEntity` | Specific provider to use (defaults to first available) |
206
+ | `CurrentUser` | `UserInfo` | User context |
207
+ | `Options` | `T` | Generic additional options passed to the provider |
208
+ | `CreateErrorList` | `boolean` | Whether to create an error tracking list |
209
+ | `RunID` | `string` | Set automatically by the engine |
210
+ | `ErrorListID` | `string` | Set automatically if error list is created |
211
+
212
+ ### RecommendationResult
213
+
214
+ ```typescript
215
+ class RecommendationResult {
216
+ Request: RecommendationRequest;
217
+ RecommendationRun?: RecommendationRunEntity;
218
+ RecommendationItems?: RecommendationItemEntity[];
219
+ Success: boolean;
220
+ ErrorMessage: string;
221
+
222
+ AppendWarning(message: string): void; // Adds warning without setting Success=false
223
+ AppendError(message: string): void; // Adds error and sets Success=false
224
+ GetErrorMessages(): string[]; // Splits ErrorMessage into array
225
+ }
226
+ ```
227
+
228
+ ## Usage
229
+
230
+ ### Running Recommendations from a List
231
+
232
+ ```typescript
233
+ import { RecommendationEngineBase } from '@memberjunction/ai-recommendations';
234
+ import { RecommendationRequest } from '@memberjunction/ai-recommendations';
235
+
236
+ const engine = RecommendationEngineBase.Instance;
237
+ await engine.Config(false, contextUser);
238
+
239
+ const request = new RecommendationRequest();
240
+ request.ListID = 'list-uuid';
241
+ request.CurrentUser = contextUser;
242
+ request.CreateErrorList = true;
243
+
244
+ const result = await engine.Recommend(request);
245
+
246
+ if (result.Success) {
247
+ console.log(`Generated ${result.RecommendationItems?.length ?? 0} items`);
248
+ } else {
249
+ console.error(result.ErrorMessage);
250
+ }
251
+ ```
252
+
253
+ ### Running Recommendations by Entity and Record IDs
254
+
255
+ ```typescript
256
+ const request = new RecommendationRequest();
257
+ request.EntityAndRecordsInfo = {
258
+ EntityName: 'Products',
259
+ RecordIDs: ['id-1', 'id-2', 'id-3']
260
+ };
261
+ request.CurrentUser = contextUser;
262
+
263
+ const result = await engine.Recommend(request);
264
+ ```
265
+
266
+ ### Implementing a Provider
267
+
268
+ ```typescript
269
+ import { RecommendationProviderBase } from '@memberjunction/ai-recommendations';
270
+ import { RecommendationRequest, RecommendationResult } from '@memberjunction/ai-recommendations';
271
+ import { RegisterClass } from '@memberjunction/global';
272
+ import { Metadata } from '@memberjunction/core';
273
+ import { RecommendationItemEntity } from '@memberjunction/core-entities';
274
+
275
+ @RegisterClass(RecommendationProviderBase, 'My Recommendation Provider')
276
+ export class MyProvider extends RecommendationProviderBase {
277
+ async Recommend(request: RecommendationRequest): Promise<RecommendationResult> {
278
+ const result = new RecommendationResult(request);
279
+ const md = new Metadata();
280
+
281
+ for (const rec of request.Recommendations) {
282
+ // Call your recommendation API/algorithm
283
+ const suggestions = await this.getSuggestions(rec.SourceEntityRecordID);
284
+
285
+ const items: RecommendationItemEntity[] = [];
286
+ for (const suggestion of suggestions) {
287
+ const item = await md.GetEntityObject<RecommendationItemEntity>(
288
+ 'Recommendation Items', request.CurrentUser
289
+ );
290
+ item.NewRecord();
291
+ item.DestinationEntityID = suggestion.entityID;
292
+ item.DestinationEntityRecordID = suggestion.recordID;
293
+ item.MatchProbability = suggestion.score;
294
+ items.push(item);
295
+ }
296
+
297
+ await this.SaveRecommendation(rec, request.RunID, items);
298
+ }
299
+
300
+ return result;
301
+ }
302
+
303
+ private async getSuggestions(recordID: string): Promise<Suggestion[]> {
304
+ // Your recommendation logic here
305
+ return [];
306
+ }
307
+ }
308
+ ```
309
+
310
+ ## Database Entities
311
+
312
+ ```mermaid
313
+ erDiagram
314
+ RECOMMENDATION_PROVIDERS {
315
+ string ID PK
316
+ string Name
317
+ string Description
318
+ }
319
+
320
+ RECOMMENDATION_RUNS {
321
+ string ID PK
322
+ string RecommendationProviderID FK
323
+ string RunByUserID FK
324
+ datetime StartDate
325
+ string Status
326
+ string Description
327
+ }
328
+
329
+ RECOMMENDATIONS {
330
+ string ID PK
331
+ string RecommendationRunID FK
332
+ string SourceEntityID FK
333
+ string SourceEntityRecordID
334
+ }
335
+
336
+ RECOMMENDATION_ITEMS {
337
+ string ID PK
338
+ string RecommendationID FK
339
+ string DestinationEntityID FK
340
+ string DestinationEntityRecordID
341
+ float MatchProbability
342
+ }
343
+
344
+ LISTS {
345
+ string ID PK
346
+ string Name
347
+ string EntityID FK
348
+ string UserID FK
349
+ }
350
+
351
+ RECOMMENDATION_PROVIDERS ||--o{ RECOMMENDATION_RUNS : has
352
+ RECOMMENDATION_RUNS ||--o{ RECOMMENDATIONS : contains
353
+ RECOMMENDATIONS ||--o{ RECOMMENDATION_ITEMS : produces
354
+ ```
355
+
356
+ ## Dependencies
357
+
358
+ | Package | Purpose |
359
+ |---|---|
360
+ | `@memberjunction/core` | `BaseEngine`, `Metadata`, `RunView`, `UserInfo`, `LogStatus` |
361
+ | `@memberjunction/core-entities` | `RecommendationEntity`, `RecommendationRunEntity`, `RecommendationItemEntity`, `RecommendationProviderEntity`, `ListEntity` |
362
+ | `@memberjunction/global` | `MJGlobal` class factory for provider discovery |
363
+
364
+ ## Development
365
+
366
+ ```bash
367
+ # Build
368
+ npm run build
369
+
370
+ # Development mode
371
+ npm run start
372
+ ```
373
+
374
+ ## License
375
+
376
+ ISC
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@memberjunction/ai-recommendations",
3
3
  "type": "module",
4
- "version": "4.0.0",
4
+ "version": "4.2.0",
5
5
  "description": "MemberJunction Recommendations Engine",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -20,10 +20,10 @@
20
20
  "typescript": "^5.9.3"
21
21
  },
22
22
  "dependencies": {
23
- "@memberjunction/global": "4.0.0",
24
- "@memberjunction/core": "4.0.0",
25
- "@memberjunction/core-entities": "4.0.0",
26
- "@memberjunction/ai": "4.0.0"
23
+ "@memberjunction/global": "4.2.0",
24
+ "@memberjunction/core": "4.2.0",
25
+ "@memberjunction/core-entities": "4.2.0",
26
+ "@memberjunction/ai": "4.2.0"
27
27
  },
28
28
  "repository": {
29
29
  "type": "git",
package/readme.md CHANGED
@@ -1,16 +1,54 @@
1
1
  # @memberjunction/ai-recommendations
2
2
 
3
- The MemberJunction Recommendations Engine provides a flexible and extensible framework for integrating with AI-powered recommendation systems. It handles the orchestration of recommendation requests, provider management, and the storage of recommendation results within the MemberJunction ecosystem.
4
-
5
- ## Features
6
-
7
- - **Extensible Provider Framework**: Support for multiple recommendation providers through a unified API
8
- - **Built-in Tracking**: Automatic tracking of recommendation runs and results
9
- - **Entity Integration**: Seamless integration with MemberJunction entities and records
10
- - **List Support**: Generate recommendations for records in a list
11
- - **Error Handling**: Comprehensive error tracking and reporting
12
- - **Batch Processing**: Process multiple recommendation requests efficiently
13
- - **Metadata Management**: Automatic management of recommendation metadata
3
+ A provider-based recommendation engine for MemberJunction. Manages recommendation runs, delegates to pluggable providers via the class factory, and tracks results through Recommendation, Recommendation Run, and Recommendation Item entities.
4
+
5
+ ## Architecture
6
+
7
+ ```mermaid
8
+ graph TD
9
+ subgraph Engine["@memberjunction/ai-recommendations"]
10
+ REB["RecommendationEngineBase<br/>(singleton BaseEngine)"]
11
+ RPB["RecommendationProviderBase<br/>(abstract)"]
12
+ RR["RecommendationRequest&lt;T&gt;"]
13
+ RRES["RecommendationResult"]
14
+ end
15
+
16
+ subgraph Providers["Registered Providers"]
17
+ P1["Provider A"]
18
+ P2["Provider B"]
19
+ end
20
+
21
+ subgraph MJEntities["MemberJunction Entities"]
22
+ RP["Recommendation Providers"]
23
+ RUN["Recommendation Runs"]
24
+ REC["Recommendations"]
25
+ RI["Recommendation Items"]
26
+ LIST["Lists / List Details"]
27
+ end
28
+
29
+ subgraph MJCore["MemberJunction Core"]
30
+ BE["BaseEngine"]
31
+ CF["ClassFactory"]
32
+ MD["Metadata"]
33
+ end
34
+
35
+ REB -->|extends| BE
36
+ REB -->|discovers| CF
37
+ CF -->|creates| P1
38
+ CF -->|creates| P2
39
+ P1 -->|extends| RPB
40
+ P2 -->|extends| RPB
41
+ REB --> RP
42
+ REB --> RUN
43
+ RPB --> REC
44
+ RPB --> RI
45
+ REB --> LIST
46
+
47
+ style Engine fill:#2d6a9f,stroke:#1a4971,color:#fff
48
+ style Providers fill:#2d8659,stroke:#1a5c3a,color:#fff
49
+ style MJEntities fill:#b8762f,stroke:#8a5722,color:#fff
50
+ style MJCore fill:#7c5295,stroke:#563a6b,color:#fff
51
+ ```
14
52
 
15
53
  ## Installation
16
54
 
@@ -18,220 +56,321 @@ The MemberJunction Recommendations Engine provides a flexible and extensible fra
18
56
  npm install @memberjunction/ai-recommendations
19
57
  ```
20
58
 
59
+ ## Overview
60
+
61
+ This package provides the framework for running recommendations in MemberJunction. It follows the engine/provider pattern used throughout the platform:
62
+
63
+ 1. **RecommendationEngineBase** -- a singleton engine (extending `BaseEngine`) that loads provider metadata, selects a provider, creates Recommendation Run tracking records, and delegates the actual recommendation logic
64
+ 2. **RecommendationProviderBase** -- an abstract class that concrete providers implement to generate recommendations for each source record
65
+ 3. **RecommendationRequest/RecommendationResult** -- typed request and response objects that flow through the pipeline
66
+
67
+ Providers are discovered at runtime through MemberJunction's `ClassFactory` using `@RegisterClass(RecommendationProviderBase, 'ProviderName')`.
68
+
69
+ ## Recommendation Flow
70
+
71
+ ```mermaid
72
+ sequenceDiagram
73
+ participant Caller
74
+ participant Engine as RecommendationEngineBase
75
+ participant CF as ClassFactory
76
+ participant Provider as RecommendationProvider
77
+ participant DB as MJ Database
78
+
79
+ Caller->>Engine: Recommend(request)
80
+ Engine->>Engine: TryThrowIfNotLoaded()
81
+
82
+ alt Provider specified
83
+ Engine->>Engine: Use request.Provider
84
+ else No provider
85
+ Engine->>Engine: Use first available
86
+ end
87
+
88
+ Engine->>Engine: GetRecommendationEntities(request)
89
+
90
+ alt From List
91
+ Engine->>DB: Load List + List Details
92
+ Engine->>DB: Load entity records by IDs
93
+ else From EntityAndRecordsInfo
94
+ Engine->>DB: Load records by entity name + IDs
95
+ else Pre-built
96
+ Engine->>Engine: Validate Recommendations array
97
+ end
98
+
99
+ Engine->>DB: Create Recommendation Run (Status: In Progress)
100
+
101
+ opt CreateErrorList = true
102
+ Engine->>DB: Create error tracking List
103
+ end
104
+
105
+ Engine->>CF: CreateInstance(provider.Name)
106
+ CF-->>Engine: Provider instance
107
+
108
+ Engine->>Provider: Recommend(request)
109
+
110
+ loop For each recommendation
111
+ Provider->>Provider: Call external API
112
+ Provider->>DB: SaveRecommendation + Items
113
+ end
114
+
115
+ Provider-->>Engine: RecommendationResult
116
+
117
+ Engine->>DB: Update Run (Completed/Error)
118
+ Engine-->>Caller: RecommendationResult
119
+ ```
120
+
21
121
  ## Core Components
22
122
 
23
123
  ### RecommendationEngineBase
24
124
 
25
- The main engine class that coordinates recommendation requests:
125
+ A singleton engine that manages the recommendation lifecycle.
26
126
 
27
127
  ```typescript
28
- import { RecommendationEngineBase, RecommendationRequest } from '@memberjunction/ai-recommendations';
128
+ import { RecommendationEngineBase } from '@memberjunction/ai-recommendations';
29
129
 
30
- // Initialize and load the engine
31
- await RecommendationEngineBase.Instance.Config();
32
-
33
- // Create a recommendation request
34
- const request = new RecommendationRequest();
130
+ // Access the singleton
131
+ const engine = RecommendationEngineBase.Instance;
35
132
 
36
- // Configure the request
37
- request.EntityAndRecordsInfo = {
38
- EntityName: 'Customers',
39
- RecordIDs: ['CUST001', 'CUST002']
40
- };
133
+ // Initialize (loads Recommendation Providers metadata)
134
+ await engine.Config(false, contextUser);
41
135
 
42
- // Execute the recommendation
43
- const result = await RecommendationEngineBase.Instance.Recommend(request);
136
+ // Run recommendations
137
+ const result = await engine.Recommend(request);
44
138
  ```
45
139
 
46
- ### RecommendationProviderBase
140
+ **Key properties and methods:**
47
141
 
48
- Abstract base class for implementing recommendation providers:
142
+ | Member | Description |
143
+ |---|---|
144
+ | `Instance` | Static getter for the singleton instance |
145
+ | `RecommendationProviders` | Array of `RecommendationProviderEntity` loaded from metadata |
146
+ | `Config(forceRefresh?, contextUser?, provider?)` | Loads provider metadata into cache |
147
+ | `Recommend<T>(request)` | Runs the full recommendation pipeline |
49
148
 
50
- ```typescript
51
- import { RecommendationProviderBase, RecommendationRequest, RecommendationResult } from '@memberjunction/ai-recommendations';
52
- import { UserInfo } from '@memberjunction/core';
53
- import { RecommendationItemEntity } from '@memberjunction/core-entities';
149
+ ### RecommendationProviderBase
54
150
 
55
- export class MyRecommendationProvider extends RecommendationProviderBase {
56
- constructor(contextUser: UserInfo) {
57
- super(contextUser);
58
- }
59
-
60
- public async Recommend(request: RecommendationRequest): Promise<RecommendationResult> {
61
- const result = new RecommendationResult(request);
62
-
63
- try {
64
- // Process each recommendation
65
- for (const recommendation of request.Recommendations) {
66
- // Generate items for this recommendation
67
- const items: RecommendationItemEntity[] = [];
68
-
69
- // Your recommendation logic here
70
- // ...
71
-
72
- // Save the recommendation and its items
73
- await this.SaveRecommendation(recommendation, request.RunID, items);
74
- }
75
- } catch (error) {
76
- result.AppendError(error.message);
151
+ Abstract base class for implementing recommendation providers.
152
+
153
+ ```mermaid
154
+ classDiagram
155
+ class RecommendationProviderBase {
156
+ <<abstract>>
157
+ -_md : Metadata
158
+ -_ContextUser : UserInfo
159
+ +ContextUser : UserInfo
160
+ +Recommend(request)* RecommendationResult
161
+ #SaveRecommendation(rec, runID, items) boolean
77
162
  }
78
-
79
- return result;
80
- }
81
- }
163
+
164
+ class ConcreteProvider {
165
+ +Recommend(request) RecommendationResult
166
+ }
167
+
168
+ RecommendationProviderBase <|-- ConcreteProvider
169
+
170
+ style RecommendationProviderBase fill:#2d6a9f,stroke:#1a4971,color:#fff
171
+ style ConcreteProvider fill:#2d8659,stroke:#1a5c3a,color:#fff
82
172
  ```
83
173
 
84
- ## Usage Examples
174
+ The `SaveRecommendation` helper method handles:
175
+ 1. Setting the `RecommendationRunID` on the recommendation entity
176
+ 2. Saving the recommendation record
177
+ 3. Linking and saving all `RecommendationItemEntity` records
85
178
 
86
- ### Generate Recommendations for Specific Records
179
+ ### RecommendationRequest\<T\>
87
180
 
88
- ```typescript
89
- import { RecommendationEngineBase, RecommendationRequest } from '@memberjunction/ai-recommendations';
90
-
91
- async function getCustomerRecommendations(customerIds: string[]) {
92
- // Ensure the engine is configured
93
- await RecommendationEngineBase.Instance.Config();
94
-
95
- // Create a request for specific customer records
96
- const request = new RecommendationRequest();
97
- request.EntityAndRecordsInfo = {
98
- EntityName: 'Customers',
99
- RecordIDs: customerIds
100
- };
101
-
102
- // Optionally specify a provider
103
- // request.Provider = RecommendationEngineBase.Instance.RecommendationProviders.find(p => p.Name === 'MyProvider');
104
-
105
- // Execute the recommendation
106
- const result = await RecommendationEngineBase.Instance.Recommend(request);
107
-
108
- if (result.Success) {
109
- console.log('Recommendations generated successfully!');
110
- return result.RecommendationItems;
111
- } else {
112
- console.error('Error generating recommendations:', result.ErrorMessage);
113
- return null;
114
- }
115
- }
181
+ The request object supports three ways to specify source records:
182
+
183
+ ```mermaid
184
+ graph TD
185
+ RR["RecommendationRequest"]
186
+ OPT1["Recommendations[]<br/>Pre-built entities"]
187
+ OPT2["EntityAndRecordsInfo<br/>Entity name + Record IDs"]
188
+ OPT3["ListID<br/>MJ List reference"]
189
+
190
+ RR --> OPT1
191
+ RR --> OPT2
192
+ RR --> OPT3
193
+
194
+ style RR fill:#2d6a9f,stroke:#1a4971,color:#fff
195
+ style OPT1 fill:#2d8659,stroke:#1a5c3a,color:#fff
196
+ style OPT2 fill:#2d8659,stroke:#1a5c3a,color:#fff
197
+ style OPT3 fill:#2d8659,stroke:#1a5c3a,color:#fff
116
198
  ```
117
199
 
118
- ### Generate Recommendations from a List
200
+ | Field | Type | Description |
201
+ |---|---|---|
202
+ | `Recommendations` | `RecommendationEntity[]` | Pre-built unsaved recommendation entities |
203
+ | `EntityAndRecordsInfo` | `{ EntityName, RecordIDs }` | Entity name and array of record IDs to process |
204
+ | `ListID` | `string` | ID of a MJ List whose details become the source records |
205
+ | `Provider` | `RecommendationProviderEntity` | Specific provider to use (defaults to first available) |
206
+ | `CurrentUser` | `UserInfo` | User context |
207
+ | `Options` | `T` | Generic additional options passed to the provider |
208
+ | `CreateErrorList` | `boolean` | Whether to create an error tracking list |
209
+ | `RunID` | `string` | Set automatically by the engine |
210
+ | `ErrorListID` | `string` | Set automatically if error list is created |
211
+
212
+ ### RecommendationResult
119
213
 
120
214
  ```typescript
121
- import { RecommendationEngineBase, RecommendationRequest } from '@memberjunction/ai-recommendations';
122
-
123
- async function getRecommendationsFromList(listId: string) {
124
- await RecommendationEngineBase.Instance.Config();
125
-
126
- // Create a request for records in a list
127
- const request = new RecommendationRequest();
128
- request.ListID = listId;
129
- request.CreateErrorList = true; // Create a list to track errors
130
-
131
- // Execute the recommendation
132
- const result = await RecommendationEngineBase.Instance.Recommend(request);
133
-
134
- if (result.Success) {
135
- console.log('Recommendations generated successfully!');
136
- console.log('Error list ID (if needed):', result.Request.ErrorListID);
137
- return result.RecommendationItems;
138
- } else {
139
- console.error('Error generating recommendations:', result.ErrorMessage);
140
- return null;
141
- }
215
+ class RecommendationResult {
216
+ Request: RecommendationRequest;
217
+ RecommendationRun?: RecommendationRunEntity;
218
+ RecommendationItems?: RecommendationItemEntity[];
219
+ Success: boolean;
220
+ ErrorMessage: string;
221
+
222
+ AppendWarning(message: string): void; // Adds warning without setting Success=false
223
+ AppendError(message: string): void; // Adds error and sets Success=false
224
+ GetErrorMessages(): string[]; // Splits ErrorMessage into array
142
225
  }
143
226
  ```
144
227
 
145
- ### Using Advanced Options
228
+ ## Usage
229
+
230
+ ### Running Recommendations from a List
146
231
 
147
232
  ```typescript
148
- import { RecommendationEngineBase, RecommendationRequest } from '@memberjunction/ai-recommendations';
233
+ import { RecommendationEngineBase } from '@memberjunction/ai-recommendations';
234
+ import { RecommendationRequest } from '@memberjunction/ai-recommendations';
149
235
 
150
- // Define a custom options interface for your provider
151
- interface MyProviderOptions {
152
- similarityThreshold: number;
153
- maxRecommendations: number;
154
- includeRatings: boolean;
155
- }
236
+ const engine = RecommendationEngineBase.Instance;
237
+ await engine.Config(false, contextUser);
238
+
239
+ const request = new RecommendationRequest();
240
+ request.ListID = 'list-uuid';
241
+ request.CurrentUser = contextUser;
242
+ request.CreateErrorList = true;
156
243
 
157
- async function getCustomizedRecommendations(customerId: string) {
158
- await RecommendationEngineBase.Instance.Config();
159
-
160
- // Create a request with custom options
161
- const request = new RecommendationRequest<MyProviderOptions>();
162
- request.EntityAndRecordsInfo = {
163
- EntityName: 'Customers',
164
- RecordIDs: [customerId]
165
- };
166
-
167
- // Add provider-specific options
168
- request.Options = {
169
- similarityThreshold: 0.75,
170
- maxRecommendations: 5,
171
- includeRatings: true
172
- };
173
-
174
- // Execute the recommendation
175
- return await RecommendationEngineBase.Instance.Recommend(request);
244
+ const result = await engine.Recommend(request);
245
+
246
+ if (result.Success) {
247
+ console.log(`Generated ${result.RecommendationItems?.length ?? 0} items`);
248
+ } else {
249
+ console.error(result.ErrorMessage);
176
250
  }
177
251
  ```
178
252
 
179
- ## Recommendation Flow
253
+ ### Running Recommendations by Entity and Record IDs
180
254
 
181
- The recommendation process follows these steps:
255
+ ```typescript
256
+ const request = new RecommendationRequest();
257
+ request.EntityAndRecordsInfo = {
258
+ EntityName: 'Products',
259
+ RecordIDs: ['id-1', 'id-2', 'id-3']
260
+ };
261
+ request.CurrentUser = contextUser;
182
262
 
183
- 1. **Request Creation**: A `RecommendationRequest` is created with entity records or a list
184
- 2. **Run Tracking**: A `RecommendationRun` entity is created to track the process
185
- 3. **Provider Selection**: The appropriate recommendation provider is selected
186
- 4. **Recommendation Generation**: The provider generates recommendations for each requested record
187
- 5. **Result Storage**: Recommendations and items are saved to the database
188
- 6. **Status Update**: The run status is updated (completed or error)
189
- 7. **Result Return**: The `RecommendationResult` is returned to the caller
263
+ const result = await engine.Recommend(request);
264
+ ```
190
265
 
191
- ## Data Model
266
+ ### Implementing a Provider
192
267
 
193
- The recommendation engine works with these key entities:
268
+ ```typescript
269
+ import { RecommendationProviderBase } from '@memberjunction/ai-recommendations';
270
+ import { RecommendationRequest, RecommendationResult } from '@memberjunction/ai-recommendations';
271
+ import { RegisterClass } from '@memberjunction/global';
272
+ import { Metadata } from '@memberjunction/core';
273
+ import { RecommendationItemEntity } from '@memberjunction/core-entities';
194
274
 
195
- - **RecommendationProviderEntity**: Configuration for recommendation providers
196
- - **RecommendationRunEntity**: Tracks each recommendation execution
197
- - **RecommendationEntity**: Represents a recommendation for a source record
198
- - **RecommendationItemEntity**: Individual recommendation items (products, content, etc.)
275
+ @RegisterClass(RecommendationProviderBase, 'My Recommendation Provider')
276
+ export class MyProvider extends RecommendationProviderBase {
277
+ async Recommend(request: RecommendationRequest): Promise<RecommendationResult> {
278
+ const result = new RecommendationResult(request);
279
+ const md = new Metadata();
280
+
281
+ for (const rec of request.Recommendations) {
282
+ // Call your recommendation API/algorithm
283
+ const suggestions = await this.getSuggestions(rec.SourceEntityRecordID);
284
+
285
+ const items: RecommendationItemEntity[] = [];
286
+ for (const suggestion of suggestions) {
287
+ const item = await md.GetEntityObject<RecommendationItemEntity>(
288
+ 'Recommendation Items', request.CurrentUser
289
+ );
290
+ item.NewRecord();
291
+ item.DestinationEntityID = suggestion.entityID;
292
+ item.DestinationEntityRecordID = suggestion.recordID;
293
+ item.MatchProbability = suggestion.score;
294
+ items.push(item);
295
+ }
296
+
297
+ await this.SaveRecommendation(rec, request.RunID, items);
298
+ }
299
+
300
+ return result;
301
+ }
199
302
 
200
- ## Provider Implementation
303
+ private async getSuggestions(recordID: string): Promise<Suggestion[]> {
304
+ // Your recommendation logic here
305
+ return [];
306
+ }
307
+ }
308
+ ```
201
309
 
202
- To create a custom recommendation provider:
310
+ ## Database Entities
203
311
 
204
- 1. Create a class that extends `RecommendationProviderBase`
205
- 2. Implement the `Recommend` method to generate recommendations
206
- 3. Register your provider implementation:
312
+ ```mermaid
313
+ erDiagram
314
+ RECOMMENDATION_PROVIDERS {
315
+ string ID PK
316
+ string Name
317
+ string Description
318
+ }
207
319
 
208
- ```typescript
209
- // Register your provider with MemberJunction's class factory
210
- import { MJGlobal } from '@memberjunction/global';
211
- import { RecommendationProviderBase } from '@memberjunction/ai-recommendations';
320
+ RECOMMENDATION_RUNS {
321
+ string ID PK
322
+ string RecommendationProviderID FK
323
+ string RunByUserID FK
324
+ datetime StartDate
325
+ string Status
326
+ string Description
327
+ }
212
328
 
213
- MJGlobal.Instance.ClassFactory.RegisterClass(
214
- RecommendationProviderBase,
215
- 'MyRecommendationProvider',
216
- MyRecommendationProvider
217
- );
218
- ```
329
+ RECOMMENDATIONS {
330
+ string ID PK
331
+ string RecommendationRunID FK
332
+ string SourceEntityID FK
333
+ string SourceEntityRecordID
334
+ }
219
335
 
220
- ## Integration with MemberJunction
336
+ RECOMMENDATION_ITEMS {
337
+ string ID PK
338
+ string RecommendationID FK
339
+ string DestinationEntityID FK
340
+ string DestinationEntityRecordID
341
+ float MatchProbability
342
+ }
221
343
 
222
- This package integrates with the MemberJunction ecosystem:
344
+ LISTS {
345
+ string ID PK
346
+ string Name
347
+ string EntityID FK
348
+ string UserID FK
349
+ }
223
350
 
224
- - Uses MemberJunction entities for data storage and retrieval
225
- - Works with MemberJunction lists for batch processing
226
- - Leverages MemberJunction's metadata system
351
+ RECOMMENDATION_PROVIDERS ||--o{ RECOMMENDATION_RUNS : has
352
+ RECOMMENDATION_RUNS ||--o{ RECOMMENDATIONS : contains
353
+ RECOMMENDATIONS ||--o{ RECOMMENDATION_ITEMS : produces
354
+ ```
227
355
 
228
356
  ## Dependencies
229
357
 
230
- - `@memberjunction/global`: MemberJunction global utilities
231
- - `@memberjunction/core`: MemberJunction core library
232
- - `@memberjunction/core-entities`: MemberJunction entity definitions
233
- - `@memberjunction/ai`: MemberJunction AI abstractions
358
+ | Package | Purpose |
359
+ |---|---|
360
+ | `@memberjunction/core` | `BaseEngine`, `Metadata`, `RunView`, `UserInfo`, `LogStatus` |
361
+ | `@memberjunction/core-entities` | `RecommendationEntity`, `RecommendationRunEntity`, `RecommendationItemEntity`, `RecommendationProviderEntity`, `ListEntity` |
362
+ | `@memberjunction/global` | `MJGlobal` class factory for provider discovery |
363
+
364
+ ## Development
365
+
366
+ ```bash
367
+ # Build
368
+ npm run build
369
+
370
+ # Development mode
371
+ npm run start
372
+ ```
234
373
 
235
374
  ## License
236
375
 
237
- ISC
376
+ ISC