@drax/ai-back 2.0.0 → 3.16.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 (64) hide show
  1. package/dist/config/OpenAiConfig.js +1 -0
  2. package/dist/controllers/AILogController.js +18 -0
  3. package/dist/factory/OpenAiProviderFactory.js +2 -1
  4. package/dist/factory/services/AILogServiceFactory.js +30 -0
  5. package/dist/index.js +10 -1
  6. package/dist/interfaces/IAILog.js +1 -0
  7. package/dist/interfaces/IAILogRepository.js +1 -0
  8. package/dist/models/AILogModel.js +50 -0
  9. package/dist/permissions/AILogPermissions.js +10 -0
  10. package/dist/providers/OpenAiProvider.js +176 -26
  11. package/dist/repository/mongo/AILogMongoRepository.js +13 -0
  12. package/dist/repository/sqlite/AILogSqliteRepository.js +45 -0
  13. package/dist/routes/AILogRoutes.js +21 -0
  14. package/dist/schemas/AILogSchema.js +44 -0
  15. package/dist/services/AILogService.js +9 -0
  16. package/package.json +8 -2
  17. package/src/config/OpenAiConfig.ts +1 -0
  18. package/src/controllers/AILogController.ts +29 -0
  19. package/src/factory/OpenAiProviderFactory.ts +4 -2
  20. package/src/factory/services/AILogServiceFactory.ts +41 -0
  21. package/src/index.ts +39 -1
  22. package/src/interfaces/IAILogRepository.ts +11 -0
  23. package/src/interfaces/IAIProvider.ts +48 -2
  24. package/src/models/AILogModel.ts +65 -0
  25. package/src/permissions/AILogPermissions.ts +14 -0
  26. package/src/providers/OpenAiProvider.ts +231 -29
  27. package/src/repository/mongo/AILogMongoRepository.ts +22 -0
  28. package/src/repository/sqlite/AILogSqliteRepository.ts +53 -0
  29. package/src/routes/AILogRoutes.ts +38 -0
  30. package/src/schemas/AILogSchema.ts +52 -0
  31. package/src/services/AILogService.ts +20 -0
  32. package/test/OpenAiProvider.test.ts +91 -0
  33. package/tsconfig.tsbuildinfo +1 -1
  34. package/types/config/OpenAiConfig.d.ts +2 -1
  35. package/types/config/OpenAiConfig.d.ts.map +1 -1
  36. package/types/controllers/AILogController.d.ts +8 -0
  37. package/types/controllers/AILogController.d.ts.map +1 -0
  38. package/types/factory/OpenAiProviderFactory.d.ts.map +1 -1
  39. package/types/factory/services/AILogServiceFactory.d.ts +8 -0
  40. package/types/factory/services/AILogServiceFactory.d.ts.map +1 -0
  41. package/types/index.d.ts +13 -3
  42. package/types/index.d.ts.map +1 -1
  43. package/types/interfaces/IAILog.d.ts +77 -0
  44. package/types/interfaces/IAILog.d.ts.map +1 -0
  45. package/types/interfaces/IAILogRepository.d.ts +6 -0
  46. package/types/interfaces/IAILogRepository.d.ts.map +1 -0
  47. package/types/interfaces/IAIProvider.d.ts +32 -2
  48. package/types/interfaces/IAIProvider.d.ts.map +1 -1
  49. package/types/models/AILogModel.d.ts +15 -0
  50. package/types/models/AILogModel.d.ts.map +1 -0
  51. package/types/permissions/AILogPermissions.d.ts +10 -0
  52. package/types/permissions/AILogPermissions.d.ts.map +1 -0
  53. package/types/providers/OpenAiProvider.d.ts +71 -2
  54. package/types/providers/OpenAiProvider.d.ts.map +1 -1
  55. package/types/repository/mongo/AILogMongoRepository.d.ts +9 -0
  56. package/types/repository/mongo/AILogMongoRepository.d.ts.map +1 -0
  57. package/types/repository/sqlite/AILogSqliteRepository.d.ts +23 -0
  58. package/types/repository/sqlite/AILogSqliteRepository.d.ts.map +1 -0
  59. package/types/routes/AILogRoutes.d.ts +4 -0
  60. package/types/routes/AILogRoutes.d.ts.map +1 -0
  61. package/types/schemas/AILogSchema.d.ts +81 -0
  62. package/types/schemas/AILogSchema.d.ts.map +1 -0
  63. package/types/services/AILogService.d.ts +10 -0
  64. package/types/services/AILogService.d.ts.map +1 -0
@@ -0,0 +1,41 @@
1
+
2
+ import AILogMongoRepository from '../../repository/mongo/AILogMongoRepository.js'
3
+ import AILogSqliteRepository from '../../repository/sqlite/AILogSqliteRepository.js'
4
+ import type {IAILogRepository} from "../../interfaces/IAILogRepository";
5
+ import {AILogService} from '../../services/AILogService.js'
6
+ import {AILogBaseSchema, AILogSchema} from "../../schemas/AILogSchema.js";
7
+ import {COMMON, CommonConfig, DraxConfig} from "@drax/common-back";
8
+
9
+ class AILogServiceFactory {
10
+ private static service: AILogService;
11
+
12
+ public static get instance(): AILogService {
13
+ if (!AILogServiceFactory.service) {
14
+
15
+ let repository: IAILogRepository
16
+ switch (DraxConfig.getOrLoad(CommonConfig.DbEngine)) {
17
+ case COMMON.DB_ENGINES.MONGODB:
18
+ repository = new AILogMongoRepository()
19
+ break;
20
+ case COMMON.DB_ENGINES.SQLITE:
21
+ const dbFile = DraxConfig.getOrLoad(CommonConfig.SqliteDbFile)
22
+ repository = new AILogSqliteRepository(dbFile, false)
23
+ repository.build()
24
+ break;
25
+ default:
26
+ throw new Error("DraxConfig.DB_ENGINE must be one of " + Object.values(COMMON.DB_ENGINES).join(", "));
27
+ }
28
+
29
+ const baseSchema = AILogBaseSchema;
30
+ const fullSchema = AILogSchema;
31
+ AILogServiceFactory.service = new AILogService(repository, baseSchema, fullSchema);
32
+ }
33
+ return AILogServiceFactory.service;
34
+ }
35
+ }
36
+
37
+ export default AILogServiceFactory
38
+ export {
39
+ AILogServiceFactory
40
+ }
41
+
package/src/index.ts CHANGED
@@ -1,20 +1,58 @@
1
1
  import {OpenAiConfig} from "./config/OpenAiConfig.js";
2
+ import {AILogSchema, AILogBaseSchema} from "./schemas/AILogSchema.js";
3
+ import AILogModel from "./models/AILogModel.js";
4
+ import AILogMongoRepository from "./repository/mongo/AILogMongoRepository.js";
5
+ import AILogSqliteRepository from "./repository/sqlite/AILogSqliteRepository.js";
2
6
  import {OpenAiProviderFactory} from "./factory/OpenAiProviderFactory.js";
7
+ import AILogServiceFactory from "./factory/services/AILogServiceFactory.js";
3
8
  import {OpenAiProvider} from "./providers/OpenAiProvider.js";
4
9
  import {KnowledgeService} from "./services/KnowledgeService.js";
5
- import type {IAIProvider, IPromptResponse, IPromptParams, IPromptMessage, IPromptMemory} from "./interfaces/IAIProvider.js";
10
+ import {AILogService} from "./services/AILogService.js";
11
+ import AILogPermissions from "./permissions/AILogPermissions.js";
12
+ import AILogController from "./controllers/AILogController.js";
13
+ import AILogRoutes from "./routes/AILogRoutes.js";
14
+ import type {IAILogRepository} from "./interfaces/IAILogRepository.js";
15
+ import type {
16
+ IAIProvider,
17
+ IPromptContentPart,
18
+ IPromptContentPartImage,
19
+ IPromptContentPartText,
20
+ IPromptImage,
21
+ IPromptImageDetail,
22
+ IPromptMessage,
23
+ IPromptMemory,
24
+ IPromptParams,
25
+ IPromptResponse
26
+ } from "./interfaces/IAIProvider.js";
6
27
 
7
28
  export type {
29
+
30
+ IAILogRepository,
8
31
  IAIProvider,
9
32
  IPromptParams,
10
33
  IPromptMessage,
11
34
  IPromptMemory,
35
+ IPromptImage,
36
+ IPromptImageDetail,
37
+ IPromptContentPart,
38
+ IPromptContentPartImage,
39
+ IPromptContentPartText,
12
40
  IPromptResponse,
13
41
  }
14
42
 
15
43
  export {
16
44
  OpenAiConfig,
45
+ AILogSchema,
46
+ AILogBaseSchema,
47
+ AILogModel,
48
+ AILogMongoRepository,
49
+ AILogSqliteRepository,
17
50
  OpenAiProviderFactory,
51
+ AILogServiceFactory,
18
52
  OpenAiProvider,
19
53
  KnowledgeService,
54
+ AILogService,
55
+ AILogPermissions,
56
+ AILogController,
57
+ AILogRoutes,
20
58
  }
@@ -0,0 +1,11 @@
1
+
2
+ import type {IAILog, IAILogBase} from '@drax/ai-share'
3
+ import {IDraxCrudRepository} from "@drax/crud-share";
4
+
5
+ interface IAILogRepository extends IDraxCrudRepository<IAILog, IAILogBase, IAILogBase>{
6
+
7
+ }
8
+
9
+ export {IAILogRepository}
10
+
11
+
@@ -2,9 +2,29 @@ import { ZodSchema } from 'zod'
2
2
 
3
3
  type Role = 'user' | 'assistant' | 'system';
4
4
 
5
+ type IPromptImageDetail = 'auto' | 'low' | 'high';
6
+
7
+ interface IPromptImage {
8
+ url: string;
9
+ detail?: IPromptImageDetail;
10
+ }
11
+
12
+ interface IPromptContentPartText {
13
+ type: 'text';
14
+ text: string;
15
+ }
16
+
17
+ interface IPromptContentPartImage {
18
+ type: 'image';
19
+ imageUrl: string;
20
+ detail?: IPromptImageDetail;
21
+ }
22
+
23
+ type IPromptContentPart = IPromptContentPartText | IPromptContentPartImage;
24
+
5
25
  interface IPromptMessage {
6
26
  role: Role;
7
- content: string;
27
+ content: string | IPromptContentPart[];
8
28
  }
9
29
 
10
30
  interface IPromptMemory {
@@ -15,6 +35,15 @@ interface IPromptMemory {
15
35
  interface IPromptParams {
16
36
  systemPrompt: string,
17
37
  userInput?: string,
38
+ userImages?: IPromptImage[],
39
+ inputFiles?: Array<{
40
+ filename?: string,
41
+ filepath?: string,
42
+ size?: number | null,
43
+ mimetype?: string,
44
+ url?: string
45
+ }>,
46
+ userContent?: IPromptContentPart[],
18
47
  history?: IPromptMessage[],
19
48
  memory?: IPromptMemory[],
20
49
  memoryHeader?: string | '[MEMORY]' | '[MEMORIA]'
@@ -23,6 +52,12 @@ interface IPromptParams {
23
52
  zodSchema?: ZodSchema<any>,
24
53
  jsonSchema?: object,
25
54
  model?: string,
55
+ operationTitle?: string,
56
+ operationGroup?: string,
57
+ ip?: string,
58
+ userAgent?: string,
59
+ tenant?: string | null,
60
+ user?: string | null,
26
61
  }
27
62
 
28
63
  interface IPromptResponse {
@@ -37,4 +72,15 @@ interface IAIProvider {
37
72
  prompt(input: IPromptParams): Promise<IPromptResponse>
38
73
  }
39
74
 
40
- export type {IAIProvider, IPromptParams, IPromptResponse, IPromptMessage, IPromptMemory}
75
+ export type {
76
+ IAIProvider,
77
+ IPromptParams,
78
+ IPromptResponse,
79
+ IPromptMessage,
80
+ IPromptMemory,
81
+ IPromptImage,
82
+ IPromptImageDetail,
83
+ IPromptContentPart,
84
+ IPromptContentPartImage,
85
+ IPromptContentPartText,
86
+ }
@@ -0,0 +1,65 @@
1
+
2
+ import {mongoose} from '@drax/common-back';
3
+ import {PaginateModel} from "mongoose";
4
+ import uniqueValidator from 'mongoose-unique-validator';
5
+ import mongoosePaginate from 'mongoose-paginate-v2'
6
+ import type {IAILog} from '@drax/ai-share'
7
+
8
+ const AILogSchema = new mongoose.Schema<IAILog>({
9
+ provider: {type: String, required: false, index: true, unique: false },
10
+ model: {type: String, required: false, index: true, unique: false },
11
+ operationTitle: {type: String, required: false, index: false, unique: false },
12
+ operationGroup: {type: String, required: false, index: false, unique: false },
13
+ ip: {type: String, required: false, index: false, unique: false },
14
+ userAgent: {type: String, required: false, index: false, unique: false },
15
+ input: {type: String, required: false, index: false, unique: false },
16
+ inputImages: [{
17
+ filename: {type: String, required: false, index: false, unique: false },
18
+ filepath: {type: String, required: false, index: false, unique: false },
19
+ size: {type: Number, required: false, index: false, unique: false },
20
+ mimetype: {type: String, required: false, index: false, unique: false },
21
+ url: {type: String, required: false, index: false, unique: false }
22
+ }],
23
+ inputFiles: [{
24
+ filename: {type: String, required: false, index: false, unique: false },
25
+ filepath: {type: String, required: false, index: false, unique: false },
26
+ size: {type: Number, required: false, index: false, unique: false },
27
+ mimetype: {type: String, required: false, index: false, unique: false },
28
+ url: {type: String, required: false, index: false, unique: false }
29
+ }],
30
+ inputTokens: {type: Number, required: false, index: false, unique: false },
31
+ outputTokens: {type: Number, required: false, index: false, unique: false },
32
+ tokens: {type: Number, required: false, index: false, unique: false },
33
+ startedAt: {type: Date, required: false, index: false, unique: false },
34
+ endedAt: {type: Date, required: false, index: false, unique: false },
35
+ responseTime: {type: String, required: false, index: false, unique: false },
36
+ output: {type: String, required: false, index: false, unique: false },
37
+ success: {type: Boolean, required: false, index: false, unique: false },
38
+ statusCode: {type: Number, required: false, index: false, unique: false },
39
+ errorMessage: {type: String, required: false, index: false, unique: false },
40
+ tenant: {type: mongoose.Schema.Types.ObjectId, ref: 'Tenant', required: false, index: false, unique: false },
41
+ user: {type: mongoose.Schema.Types.ObjectId, ref: 'User', required: false, index: false, unique: false }
42
+ }, {timestamps: true});
43
+
44
+ AILogSchema.plugin(uniqueValidator, {message: 'validation.unique'});
45
+ AILogSchema.plugin(mongoosePaginate);
46
+
47
+ AILogSchema.virtual("id").get(function () {
48
+ return this._id.toString();
49
+ });
50
+
51
+
52
+ AILogSchema.set('toJSON', {getters: true, virtuals: true});
53
+
54
+ AILogSchema.set('toObject', {getters: true, virtuals: true});
55
+
56
+ const MODEL_NAME = 'AILog';
57
+ const COLLECTION_NAME = 'AILog';
58
+ const AILogModel = mongoose.model<IAILog, PaginateModel<IAILog>>(MODEL_NAME, AILogSchema,COLLECTION_NAME);
59
+
60
+ export {
61
+ AILogSchema,
62
+ AILogModel
63
+ }
64
+
65
+ export default AILogModel
@@ -0,0 +1,14 @@
1
+
2
+ enum AILogPermissions {
3
+
4
+ Create = "ailog:create",
5
+ Update = "ailog:update",
6
+ Delete = "ailog:delete",
7
+ View = "ailog:view",
8
+ Manage = "ailog:manage"
9
+
10
+ }
11
+
12
+ export { AILogPermissions };
13
+ export default AILogPermissions;
14
+
@@ -1,14 +1,23 @@
1
1
  import OpenAI from "openai";
2
- import type {ZodTypeAny} from "zod"
3
2
  import { zodResponseFormat } from "openai/helpers/zod";
4
- import type {IAIProvider, IPromptParams, IPromptResponse} from "../interfaces/IAIProvider";
3
+ import type {
4
+ IAIProvider,
5
+ IPromptContentPart,
6
+ IPromptMessage,
7
+ IPromptParams,
8
+ IPromptResponse
9
+ } from "../interfaces/IAIProvider";
10
+ import type {AILogService} from "../services/AILogService";
11
+ import type {IAILogBase} from "@drax/ai-share";
5
12
 
6
13
  class OpenAiProvider implements IAIProvider{
7
14
  protected _apiKey: string
8
15
  protected _model: any
16
+ protected _visionModel?: string
9
17
  protected _client: any
18
+ protected _aiLogService?: AILogService
10
19
 
11
- constructor(apiKey: string, model: string) {
20
+ constructor(apiKey: string, model: string, visionModel?: string, aiLogService?: AILogService) {
12
21
 
13
22
  if (!apiKey) {
14
23
  throw new Error("OpenAI apiKey required")
@@ -19,6 +28,8 @@ class OpenAiProvider implements IAIProvider{
19
28
 
20
29
  this._apiKey = apiKey
21
30
  this._model = model
31
+ this._visionModel = visionModel
32
+ this._aiLogService = aiLogService
22
33
  }
23
34
 
24
35
  get model(){
@@ -38,6 +49,170 @@ class OpenAiProvider implements IAIProvider{
38
49
  return this._client
39
50
  }
40
51
 
52
+ protected get visionModel(){
53
+ return this._visionModel
54
+ }
55
+
56
+ protected buildUserContent(input: IPromptParams): string | Array<{type: 'text', text: string} | {type: 'image_url', image_url: {url: string, detail?: 'auto' | 'low' | 'high'}}> {
57
+ if(input.userContent && input.userContent.length > 0){
58
+ return this.mapContentParts(input.userContent)
59
+ }
60
+
61
+ if(input.userImages && input.userImages.length > 0){
62
+ const content: Array<{type: 'text', text: string} | {type: 'image_url', image_url: {url: string, detail?: 'auto' | 'low' | 'high'}}> = []
63
+
64
+ if(input.userInput){
65
+ content.push({type: 'text', text: input.userInput})
66
+ }
67
+
68
+ content.push(...input.userImages.map(image => ({
69
+ type: 'image_url' as const,
70
+ image_url: {
71
+ url: image.url,
72
+ ...(image.detail ? {detail: image.detail} : {}),
73
+ }
74
+ })))
75
+
76
+ return content
77
+ }
78
+
79
+ return input.userInput ?? ""
80
+ }
81
+
82
+ protected mapContentParts(content: IPromptContentPart[]){
83
+ return content.map(part => {
84
+ if(part.type === 'text'){
85
+ return {
86
+ type: 'text' as const,
87
+ text: part.text
88
+ }
89
+ }
90
+
91
+ return {
92
+ type: 'image_url' as const,
93
+ image_url: {
94
+ url: part.imageUrl,
95
+ ...(part.detail ? {detail: part.detail} : {}),
96
+ }
97
+ }
98
+ })
99
+ }
100
+
101
+ protected mapHistory(history: IPromptMessage[] = []){
102
+ return history.map(message => ({
103
+ role: message.role,
104
+ content: typeof message.content === 'string'
105
+ ? message.content
106
+ : this.mapContentParts(message.content)
107
+ }))
108
+ }
109
+
110
+ protected hasImageInput(input: IPromptParams){
111
+ if(input.userImages && input.userImages.length > 0){
112
+ return true
113
+ }
114
+
115
+ if(input.userContent?.some(part => part.type === 'image')){
116
+ return true
117
+ }
118
+
119
+ return input.history?.some(message =>
120
+ Array.isArray(message.content) && message.content.some(part => part.type === 'image')
121
+ ) ?? false
122
+ }
123
+
124
+ protected serializePromptInput(input: IPromptParams, systemPrompt: string){
125
+ return JSON.stringify({
126
+ systemPrompt,
127
+ history: input.history,
128
+ userInput: input.userInput,
129
+ userContent: input.userContent,
130
+ memory: input.memory,
131
+ knowledgeBase: input.knowledgeBase,
132
+ })
133
+ }
134
+
135
+ protected serializePromptOutput(output: unknown){
136
+ if (typeof output === "string") {
137
+ return output
138
+ }
139
+
140
+ if (output === null || output === undefined) {
141
+ return undefined
142
+ }
143
+
144
+ return JSON.stringify(output)
145
+ }
146
+
147
+ protected buildLogPayload(input: IPromptParams, params: {
148
+ model: string,
149
+ systemPrompt: string,
150
+ startedAt: Date,
151
+ endedAt?: Date,
152
+ inputTokens?: number,
153
+ outputTokens?: number,
154
+ tokens?: number,
155
+ output?: unknown,
156
+ success: boolean,
157
+ errorMessage?: string,
158
+ }): IAILogBase {
159
+ return {
160
+ provider: "openai",
161
+ model: params.model,
162
+ operationTitle: input.operationTitle,
163
+ operationGroup: input.operationGroup,
164
+ ip: input.ip,
165
+ userAgent: input.userAgent,
166
+ input: this.serializePromptInput(input, params.systemPrompt),
167
+ inputImages: input.userImages?.map(image => ({
168
+ url: image.url,
169
+ })) ?? input.userContent
170
+ ?.filter(part => part.type === "image")
171
+ .map(part => ({
172
+ url: part.imageUrl,
173
+ })),
174
+ inputFiles: input.inputFiles,
175
+ inputTokens: params.inputTokens,
176
+ outputTokens: params.outputTokens,
177
+ tokens: params.tokens,
178
+ startedAt: params.startedAt,
179
+ endedAt: params.endedAt,
180
+ responseTime: params.endedAt ? `${params.endedAt.getTime() - params.startedAt.getTime()}ms` : undefined,
181
+ output: this.serializePromptOutput(params.output),
182
+ success: params.success,
183
+ errorMessage: params.errorMessage,
184
+ tenant: input.tenant,
185
+ user: input.user,
186
+ }
187
+ }
188
+
189
+ protected async registerPromptLog(input: IPromptParams, params: {
190
+ model: string,
191
+ systemPrompt: string,
192
+ startedAt: Date,
193
+ endedAt?: Date,
194
+ inputTokens?: number,
195
+ outputTokens?: number,
196
+ tokens?: number,
197
+ output?: unknown,
198
+ success: boolean,
199
+ errorMessage?: string,
200
+ }){
201
+ if(!this._aiLogService){
202
+ return
203
+ }
204
+
205
+ try{
206
+ await this._aiLogService.create(this.buildLogPayload(input, params))
207
+ }catch(e: any){
208
+ console.error("Error registerPromptLog", {
209
+ name: e?.name,
210
+ message: e?.message,
211
+ stack: e?.stack,
212
+ })
213
+ }
214
+ }
215
+
41
216
  async generateEmbedding({text, model="text-embedding-ada-002"}: {text:string,model:string }): Promise<number[]> {
42
217
  const response = await this.client.embeddings.create({
43
218
  model: model,
@@ -52,8 +227,6 @@ class OpenAiProvider implements IAIProvider{
52
227
  throw new Error("systemPrompt required")
53
228
  }
54
229
 
55
- const model = input.model ?? this.model
56
-
57
230
  let systemPrompt = input.systemPrompt
58
231
 
59
232
  if(input.memory && input.memory.length > 0){
@@ -65,37 +238,66 @@ class OpenAiProvider implements IAIProvider{
65
238
  }
66
239
 
67
240
 
68
- let userInput = input.userInput
69
-
241
+ const userInput = this.buildUserContent(input)
242
+ const model = input.model ?? (this.hasImageInput(input) ? this.visionModel ?? this.model : this.model)
243
+ const startedAt = new Date()
70
244
  const startTime = performance.now()
71
245
 
72
- const chatCompletion = await this.client.chat.completions.create({
73
- messages: [
74
- {role: 'system', content: systemPrompt},
75
- ...(input.history ? input.history : []),
76
- {role: 'user', content: userInput},
77
- ],
246
+ try {
247
+ const chatCompletion = await this.client.chat.completions.create({
248
+ messages: [
249
+ {role: 'system', content: systemPrompt},
250
+ ...this.mapHistory(input.history),
251
+ {role: 'user', content: userInput},
252
+ ],
78
253
 
79
- ...(input.zodSchema ? {response_format: zodResponseFormat(input.zodSchema, "event")} : {}),
80
- ...(input.jsonSchema ? {response_format: input.jsonSchema} : {}),
81
- model: model,
82
- });
254
+ ...(input.zodSchema ? {response_format: zodResponseFormat(input.zodSchema, "event")} : {}),
255
+ ...(input.jsonSchema ? {response_format: input.jsonSchema} : {}),
256
+ model: model,
257
+ });
83
258
 
84
259
 
85
- const output = chatCompletion.choices[0].message.content
86
- const tokens = chatCompletion.usage.total_tokens
87
- const inputTokens = chatCompletion.usage.prompt_tokens
88
- const outputTokens = chatCompletion.usage.completion_tokens
260
+ const output = chatCompletion.choices[0].message.content
261
+ const tokens = chatCompletion.usage.total_tokens
262
+ const inputTokens = chatCompletion.usage.prompt_tokens
263
+ const outputTokens = chatCompletion.usage.completion_tokens
89
264
 
90
- const endTime = performance.now()
91
- const time = endTime - startTime
265
+ const endTime = performance.now()
266
+ const time = endTime - startTime
267
+ const endedAt = new Date()
92
268
 
93
- return {
94
- output,
95
- tokens,
96
- inputTokens,
97
- outputTokens,
98
- time
269
+ await this.registerPromptLog(input, {
270
+ model,
271
+ systemPrompt,
272
+ startedAt,
273
+ endedAt,
274
+ inputTokens,
275
+ outputTokens,
276
+ tokens,
277
+ output,
278
+ success: true,
279
+ })
280
+
281
+ return {
282
+ output,
283
+ tokens,
284
+ inputTokens,
285
+ outputTokens,
286
+ time
287
+ }
288
+ } catch (e: any) {
289
+ const endedAt = new Date()
290
+
291
+ await this.registerPromptLog(input, {
292
+ model,
293
+ systemPrompt,
294
+ startedAt,
295
+ endedAt,
296
+ success: false,
297
+ errorMessage: e?.message,
298
+ })
299
+
300
+ throw e
99
301
  }
100
302
  }
101
303
 
@@ -0,0 +1,22 @@
1
+
2
+ import {AbstractMongoRepository} from "@drax/crud-back";
3
+ import {AILogModel} from "../../models/AILogModel.js";
4
+ import type {IAILogRepository} from '../../interfaces/IAILogRepository'
5
+ import type {IAILog, IAILogBase} from "@drax/ai-share";
6
+
7
+
8
+ class AILogMongoRepository extends AbstractMongoRepository<IAILog, IAILogBase, IAILogBase> implements IAILogRepository {
9
+
10
+ constructor() {
11
+ super();
12
+ this._model = AILogModel;
13
+ this._searchFields = ['provider', 'model', 'operationTitle', 'operationGroup', 'ip', 'userAgent', 'input', 'output', 'errorMessage'];
14
+ this._populateFields = ['tenant', 'user'];
15
+ this._lean = true
16
+ }
17
+
18
+ }
19
+
20
+ export default AILogMongoRepository
21
+ export {AILogMongoRepository}
22
+
@@ -0,0 +1,53 @@
1
+
2
+ import {AbstractSqliteRepository} from "@drax/crud-back";
3
+ import type {IAILogRepository} from '../../interfaces/IAILogRepository'
4
+ import type {IAILog, IAILogBase} from "@drax/ai-share";
5
+ import {SqliteTableField} from "@drax/common-back";
6
+
7
+ class AILogSqliteRepository extends AbstractSqliteRepository<IAILog, IAILogBase, IAILogBase> implements IAILogRepository {
8
+
9
+ protected db: any;
10
+ protected tableName: string = 'AILog';
11
+ protected dataBaseFile: string;
12
+ protected searchFields: string[] = ['provider', 'model', 'operationTitle', 'operationGroup', 'ip', 'userAgent', 'input', 'output', 'errorMessage'];
13
+ protected booleanFields: string[] = ['success'];
14
+ protected jsonFields: string[] = ['inputImages', 'inputFiles'];
15
+ protected identifier: string = '_id';
16
+ protected populateFields = [
17
+ { field: 'tenant', table: 'tenant', identifier: '_id' },
18
+ { field: 'user', table: 'user', identifier: '_id' }
19
+ ]
20
+ protected verbose: boolean = false;
21
+ protected tableFields: SqliteTableField[] = [
22
+ {name: "provider", type: "TEXT", unique: false, primary: false},
23
+ {name: "model", type: "TEXT", unique: false, primary: false},
24
+ {name: "operationTitle", type: "TEXT", unique: false, primary: false},
25
+ {name: "operationGroup", type: "TEXT", unique: false, primary: false},
26
+ {name: "ip", type: "TEXT", unique: false, primary: false},
27
+ {name: "userAgent", type: "TEXT", unique: false, primary: false},
28
+ {name: "input", type: "TEXT", unique: false, primary: false},
29
+ {name: "inputImages", type: "TEXT", unique: false, primary: false},
30
+ {name: "inputFiles", type: "TEXT", unique: false, primary: false},
31
+ {name: "inputTokens", type: "INTEGER", unique: false, primary: false},
32
+ {name: "inputTokens", type: "TEXT", unique: false, primary: false},
33
+ {name: "outputTokens", type: "INTEGER", unique: false, primary: false},
34
+ {name: "outputTokens", type: "TEXT", unique: false, primary: false},
35
+ {name: "tokens", type: "INTEGER", unique: false, primary: false},
36
+ {name: "tokens", type: "TEXT", unique: false, primary: false},
37
+ {name: "startedAt", type: "TEXT", unique: false, primary: false},
38
+ {name: "endedAt", type: "TEXT", unique: false, primary: false},
39
+ {name: "responseTime", type: "TEXT", unique: false, primary: false},
40
+ {name: "output", type: "TEXT", unique: false, primary: false},
41
+ {name: "success", type: "TEXT", unique: false, primary: false},
42
+ {name: "statusCode", type: "INTEGER", unique: false, primary: false},
43
+ {name: "statusCode", type: "TEXT", unique: false, primary: false},
44
+ {name: "errorMessage", type: "TEXT", unique: false, primary: false},
45
+ {name: "tenant", type: "TEXT", unique: false, primary: false},
46
+ {name: "user", type: "TEXT", unique: false, primary: false}
47
+ ]
48
+
49
+ }
50
+
51
+ export default AILogSqliteRepository
52
+ export {AILogSqliteRepository}
53
+