@memberjunction/server 0.9.20 → 0.9.22

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.
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.UserViewEntity_Server = void 0;
10
+ const global_1 = require("@memberjunction/global");
11
+ const core_1 = require("@memberjunction/core");
12
+ const core_entities_1 = require("@memberjunction/core-entities");
13
+ const ai_1 = require("@memberjunction/ai");
14
+ let UserViewEntity_Server = class UserViewEntity_Server extends core_entities_1.UserViewEntityExtended {
15
+ get SmartFilterImplemented() {
16
+ return true;
17
+ }
18
+ async GenerateSmartFilterWhereClause(prompt, entityInfo) {
19
+ try {
20
+ const llm = new ai_1.OpenAILLM();
21
+ const chatParams = {
22
+ model: 'gpt-3.5-turbo',
23
+ systemPrompt: this.GenerateSysPrompt(entityInfo),
24
+ userMessage: '',
25
+ messages: [
26
+ {
27
+ role: 'user',
28
+ content: `${prompt}`,
29
+ },
30
+ ],
31
+ };
32
+ const result = await llm.ChatCompletion(chatParams);
33
+ if (result && result.data)
34
+ return result.data.choices[0].message.content;
35
+ else
36
+ throw new Error('No result returned from AI');
37
+ }
38
+ catch (e) {
39
+ (0, core_1.LogError)(e);
40
+ throw e;
41
+ }
42
+ }
43
+ GenerateSysPrompt(entityInfo) {
44
+ const md = new core_1.Metadata();
45
+ const gptSysPrompt = `You are an expert in SQL and Microsoft SQL Server.
46
+ You will be provided a user prompt representing how they want to filter the data.
47
+ You may *NOT* use JOINS, only sub-queries for related tables.
48
+
49
+ I am a bot and can only understand JSON. Your response must be parsable into this type:
50
+ const returnType = {
51
+ whereClause: string,
52
+ orderByClause: string
53
+ };
54
+
55
+ The view that the user is querying is called ${entityInfo.BaseView} and has these fields:
56
+ ${entityInfo.Fields.map(f => {
57
+ let ret = `${f.Name} (${f.Type})`;
58
+ if (f.RelatedEntity) {
59
+ ret += ` (fkey to ${f.RelatedEntityBaseView})`;
60
+ }
61
+ return ret;
62
+ }).join(',')}`;
63
+ const fkeyFields = entityInfo.Fields.filter(f => f.RelatedEntity && f.RelatedEntity.length > 0);
64
+ const fkeyBaseViewsDistinct = fkeyFields.map(f => f.RelatedEntityBaseView).filter((v, i, a) => a.indexOf(v) === i);
65
+ const relationships = `
66
+ In addition, ${entityInfo.BaseView} has links to other views, as shown here, you can use these views in sub-queries to achieve the request from the user.
67
+ If there are multiple filters related to a single related view, attempt to combine them into a single sub-query for efficiency.
68
+ ${fkeyBaseViewsDistinct.map(v => {
69
+ const e = md.Entities.find(e => e.BaseView === v);
70
+ if (e)
71
+ return `* ${e.Name}: ${e.Fields.map(ef => ef.Name).join(',')}`;
72
+ else
73
+ return '';
74
+ }).join('\n')}
75
+ ${entityInfo.RelatedEntities.map(r => {
76
+ const e = md.Entities.find(e => e.Name === r.Entity);
77
+ if (e)
78
+ return `* ${e.Name}: ${e.Fields.map(ef => {
79
+ let ret = `${ef.Name} (${ef.Type})`;
80
+ if (ef.RelatedEntity) {
81
+ ret += ` (fkey to ${ef.RelatedEntityBaseView})`;
82
+ }
83
+ return ret;
84
+ }).join(',')}`;
85
+ else
86
+ return '';
87
+ }).join('\n')}`;
88
+ return gptSysPrompt + (entityInfo.RelatedEntities.length > 0 || fkeyFields.length > 0 ? relationships : '');
89
+ }
90
+ };
91
+ UserViewEntity_Server = __decorate([
92
+ (0, global_1.RegisterClass)(core_1.BaseEntity, 'User Views', 3)
93
+ ], UserViewEntity_Server);
94
+ exports.UserViewEntity_Server = UserViewEntity_Server;
95
+ //# sourceMappingURL=userViewEntity.server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"userViewEntity.server.js","sourceRoot":"","sources":["../../src/entitySubclasses/userViewEntity.server.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/server",
3
- "version": "0.9.20",
3
+ "version": "0.9.22",
4
4
  "description": "MemberJunction: This project provides API access via GraphQL to the common data store.",
5
5
  "main": "dist/index.js",
6
6
  "types": "src/index.ts",
@@ -21,12 +21,12 @@
21
21
  "dependencies": {
22
22
  "@apollo/server": "^4.9.1",
23
23
  "@graphql-tools/utils": "^10.0.1",
24
- "@memberjunction/ai": "^0.9.33",
25
- "@memberjunction/core": "^0.9.36",
26
- "@memberjunction/core-entities": "^0.9.9",
27
- "@memberjunction/global": "^0.9.35",
28
- "@memberjunction/queue": "^0.9.33",
29
- "@memberjunction/sqlserver-dataprovider": "^0.9.33",
24
+ "@memberjunction/ai": "^0.9.35",
25
+ "@memberjunction/core": "^0.9.38",
26
+ "@memberjunction/core-entities": "^0.9.11",
27
+ "@memberjunction/global": "^0.9.37",
28
+ "@memberjunction/queue": "^0.9.35",
29
+ "@memberjunction/sqlserver-dataprovider": "^0.9.35",
30
30
  "@types/axios": "^0.14.0",
31
31
  "@types/cors": "^2.8.13",
32
32
  "@types/jsonwebtoken": "^8.5.9",
@@ -0,0 +1,102 @@
1
+ import { MJGlobal, RegisterClass } from "@memberjunction/global";
2
+ import { BaseEntity, EntityInfo, LogError, Metadata } from "@memberjunction/core";
3
+ import { UserViewEntityExtended } from '@memberjunction/core-entities'
4
+ import { BaseLLM, BaseModel, ChatParams, IChat, OpenAILLM } from "@memberjunction/ai";
5
+
6
+ @RegisterClass(BaseEntity, 'User Views', 3) // high priority to ensure this is used ahead of the UserViewEntityExtended in the @memberjunction/core-entities package (which has priority of 2)
7
+ export class UserViewEntity_Server extends UserViewEntityExtended {
8
+ /**
9
+ * This property is hard-coded to true in this class because we DO support smart filters in this class. If you want to disable smart filters for a specific view you can override this property in your subclass and set it to false.
10
+ */
11
+ protected override get SmartFilterImplemented(): boolean {
12
+ return true;
13
+ }
14
+
15
+ /**
16
+ * This method will use AI to return a valid WHERE clause based on the provided prompt. This is automatically called at the right time if the view has SmartFilterEnabled turned on and the SmartFilterPrompt is set. If you want
17
+ * to call this directly to get back a WHERE clause for other purposes you can call this method directly and provide both a prompt and the entity that the view is based on.
18
+ * @param prompt
19
+ */
20
+ public async GenerateSmartFilterWhereClause(prompt: string, entityInfo: EntityInfo): Promise<string> {
21
+ try {
22
+ const llm = <IChat> new OpenAILLM(); // for now, hardcoded to use OpenAI
23
+
24
+ const chatParams: ChatParams = {
25
+ model: 'gpt-3.5-turbo',
26
+ systemPrompt: this.GenerateSysPrompt(entityInfo),
27
+ userMessage: '',
28
+ messages: [
29
+ {
30
+ role: 'user',
31
+ content: `${prompt}`,
32
+ },
33
+ ],
34
+ }
35
+ const result = await llm.ChatCompletion(chatParams);
36
+ if (result && result.data)
37
+ return result.data.choices[0].message.content;
38
+ else
39
+ throw new Error('No result returned from AI');
40
+ }
41
+ catch (e) {
42
+ LogError(e);
43
+ throw e;
44
+ }
45
+ }
46
+
47
+ public GenerateSysPrompt(entityInfo: EntityInfo): string {
48
+ const md = new Metadata();
49
+ const gptSysPrompt: string = `You are an expert in SQL and Microsoft SQL Server.
50
+ You will be provided a user prompt representing how they want to filter the data.
51
+ You may *NOT* use JOINS, only sub-queries for related tables.
52
+
53
+ I am a bot and can only understand JSON. Your response must be parsable into this type:
54
+ const returnType = {
55
+ whereClause: string,
56
+ orderByClause: string
57
+ };
58
+
59
+ The view that the user is querying is called ${entityInfo.BaseView} and has these fields:
60
+ ${entityInfo.Fields.map(f => {
61
+ let ret: string = `${f.Name} (${f.Type})`;
62
+ if (f.RelatedEntity) {
63
+ ret += ` (fkey to ${f.RelatedEntityBaseView})`;
64
+ }
65
+ return ret;
66
+ }).join(',')}`
67
+
68
+ const fkeyFields = entityInfo.Fields.filter(f => f.RelatedEntity && f.RelatedEntity.length > 0);
69
+ const fkeyBaseViewsDistinct = fkeyFields.map(f => f.RelatedEntityBaseView).filter((v, i, a) => a.indexOf(v) === i);
70
+ const relationships: string = `
71
+ In addition, ${entityInfo.BaseView} has links to other views, as shown here, you can use these views in sub-queries to achieve the request from the user.
72
+ If there are multiple filters related to a single related view, attempt to combine them into a single sub-query for efficiency.
73
+ ${
74
+ // this part returns a list of all the related views and the fields that are related to the current view via fkeys in the current view
75
+ fkeyBaseViewsDistinct.map(v => {
76
+ const e = md.Entities.find(e => e.BaseView === v);
77
+ if (e)
78
+ return `* ${e.Name}: ${e.Fields.map(ef => ef.Name).join(',') }`
79
+ else
80
+ return '';
81
+ }).join('\n')
82
+ }
83
+ ${
84
+ // this part returns a list of all the related views and the fields that are related to the current view fkeys in THOSE views
85
+ entityInfo.RelatedEntities.map(r => {
86
+ const e = md.Entities.find(e => e.Name === r.Entity);
87
+ if (e)
88
+ return `* ${e.Name}: ${e.Fields.map(ef => {
89
+ let ret: string = `${ef.Name} (${ef.Type})`;
90
+ if (ef.RelatedEntity) {
91
+ ret += ` (fkey to ${ef.RelatedEntityBaseView})`;
92
+ }
93
+ return ret;
94
+ }).join(',') }`
95
+ else
96
+ return '';
97
+ }).join('\n')
98
+ }`
99
+
100
+ return gptSysPrompt + (entityInfo.RelatedEntities.length > 0 || fkeyFields.length > 0 ? relationships : '');
101
+ }
102
+ }
@@ -1,19 +0,0 @@
1
- "use strict";
2
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
- return c > 3 && r && Object.defineProperty(target, key, r), r;
7
- };
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.UserViewEntity_Server = void 0;
10
- const global_1 = require("@memberjunction/global");
11
- const core_1 = require("@memberjunction/core");
12
- const core_entities_1 = require("@memberjunction/core-entities");
13
- let UserViewEntity_Server = class UserViewEntity_Server extends core_entities_1.UserViewEntityExtended {
14
- };
15
- UserViewEntity_Server = __decorate([
16
- (0, global_1.RegisterClass)(core_1.BaseEntity, 'User Views', -1)
17
- ], UserViewEntity_Server);
18
- exports.UserViewEntity_Server = UserViewEntity_Server;
19
- //# sourceMappingURL=userViewEntity_Server.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"userViewEntity_Server.js","sourceRoot":"","sources":["../../src/entitySubclasses/userViewEntity_Server.ts"],"names":[],"mappings":";;;;;;;;;AAAA,mDAAuD;AACvD,+CAAkD;AAClD,iEAAsE;AAG/D,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,sCAAsB;CAEhE,CAAA;AAFY,qBAAqB;IADjC,IAAA,sBAAa,EAAC,iBAAU,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC;GAC/B,qBAAqB,CAEjC;AAFY,sDAAqB"}
@@ -1,8 +0,0 @@
1
- import { RegisterClass } from "@memberjunction/global";
2
- import { BaseEntity } from "@memberjunction/core";
3
- import { UserViewEntityExtended } from '@memberjunction/core-entities'
4
-
5
- @RegisterClass(BaseEntity, 'User Views', -1) // -1 priority because we want the generated UserViewEntity class to be used ahead of this and it gets generated with a priority of 0 by default
6
- export class UserViewEntity_Server extends UserViewEntityExtended {
7
-
8
- }