@@ -4,7 +4,6 @@ import type { PluginOptions } from './types.js';
4
4
import Handlebars from 'handlebars' ;
5
5
import { RateLimiter } from "adminforth" ;
6
6
import { randomUUID } from "crypto" ;
7
- import { ref } from "process" ;
8
7
9
8
const STUB_MODE = false ;
10
9
const jobs = new Map ( ) ;
@@ -70,6 +69,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
70
69
71
70
private async analyze_image ( jobId : string , recordId : string , adminUser : any , headers : Record < string , string | string [ ] | undefined > ) {
72
71
const selectedId = recordId ;
72
+ let isError = false ;
73
73
if ( typeof ( this . options . rateLimits ?. fillFieldsFromImages ) === 'string' ) {
74
74
if ( this . checkRateLimit ( "fillFieldsFromImages" , this . options . rateLimits . fillFieldsFromImages , headers ) ) {
75
75
jobs . set ( jobId , { status : 'failed' , error : "Rate limit exceeded" } ) ;
@@ -96,39 +96,46 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
96
96
Image URLs:` ;
97
97
98
98
//send prompt to OpenAI and get response
99
- const chatResponse = await this . options . visionAdapter . generate ( { prompt , inputFileUrls : attachmentFiles } ) ;
100
-
101
- const resp : any = ( chatResponse as any ) . response ;
102
- const topLevelError = ( chatResponse as any ) . error ;
103
- if ( topLevelError || resp ?. error ) {
104
- jobs . set ( jobId , { status : 'failed' , error : topLevelError || resp ?. error } ) ;
105
- throw new Error ( `ERROR: ${ JSON . stringify ( topLevelError || resp ?. error ) } ` ) ;
99
+ let chatResponse ;
100
+ try {
101
+ chatResponse = await this . options . visionAdapter . generate ( { prompt , inputFileUrls : attachmentFiles } ) ;
102
+ } catch ( e ) {
103
+ isError = true ;
104
+ jobs . set ( jobId , { status : 'failed' , error : 'AI provider refused to analize images' } ) ;
105
+ return { ok : false , error : 'AI provider refused to analize images' } ;
106
106
}
107
+ if ( ! isError ) {
108
+ const resp : any = ( chatResponse as any ) . response ;
109
+ const topLevelError = ( chatResponse as any ) . error ;
110
+ if ( topLevelError || resp ?. error ) {
111
+ jobs . set ( jobId , { status : 'failed' , error : `ERROR: ${ JSON . stringify ( topLevelError || resp ?. error ) } ` } ) ;
112
+ }
107
113
108
- const textOutput = resp ?. output ?. [ 0 ] ?. content ?. [ 0 ] ?. text ?? resp ?. output_text ?? resp ?. choices ?. [ 0 ] ?. message ?. content ;
109
- if ( ! textOutput || typeof textOutput !== 'string' ) {
110
- jobs . set ( jobId , { status : 'failed' , error : 'Unexpected AI response format' } ) ;
111
- throw new Error ( 'Unexpected AI response format' ) ;
112
- }
114
+ const textOutput = resp ?. output ?. [ 0 ] ?. content ?. [ 0 ] ?. text ?? resp ?. output_text ?? resp ?. choices ?. [ 0 ] ?. message ?. content ;
115
+ if ( ! textOutput || typeof textOutput !== 'string' ) {
116
+ jobs . set ( jobId , { status : 'failed' , error : 'Unexpected AI response format' } ) ;
117
+ }
113
118
114
- //parse response and update record
115
- const resData = JSON . parse ( textOutput ) ;
116
- const result = resData ;
117
- jobs . set ( jobId , { status : 'completed' , result } ) ;
118
- return { ok : true } ;
119
+ //parse response and update record
120
+ const resData = JSON . parse ( textOutput ) ;
121
+ const result = resData ;
122
+ jobs . set ( jobId , { status : 'completed' , result } ) ;
123
+ return { ok : true } ;
124
+ }
119
125
} ;
120
126
}
121
127
122
128
private async analyzeNoImages ( jobId : string , recordId : string , adminUser : any , headers : Record < string , string | string [ ] | undefined > ) {
123
129
const selectedId = recordId ;
130
+ let isError = false ;
124
131
if ( typeof ( this . options . rateLimits ?. fillPlainFields ) === 'string' ) {
125
132
if ( this . checkRateLimit ( "fillPlainFields" , this . options . rateLimits . fillPlainFields , headers ) ) {
126
133
jobs . set ( jobId , { status : 'failed' , error : "Rate limit exceeded" } ) ;
127
134
return { error : "Rate limit exceeded" } ;
128
135
}
129
136
}
130
137
if ( STUB_MODE ) {
131
- await new Promise ( ( resolve ) => setTimeout ( resolve , Math . floor ( Math . random ( ) * 2000 ) + 1000 ) ) ;
138
+ await new Promise ( ( resolve ) => setTimeout ( resolve , Math . floor ( Math . random ( ) * 20000 ) + 1000 ) ) ;
132
139
jobs . set ( jobId , { status : 'completed' , result : { } } ) ;
133
140
return { } ;
134
141
} else {
@@ -142,15 +149,22 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
142
149
If it's number field - return only number.` ;
143
150
//send prompt to OpenAI and get response
144
151
const numberOfTokens = this . options . fillPlainFieldsMaxTokens ? this . options . fillPlainFieldsMaxTokens : 1000 ;
145
- const { content : chatResponse } = await this . options . textCompleteAdapter . complete ( prompt , [ ] , numberOfTokens ) ;
146
-
147
- const resp : any = ( chatResponse as any ) . response ;
148
- const topLevelError = ( chatResponse as any ) . error ;
149
- if ( topLevelError || resp ?. error ) {
150
- jobs . set ( jobId , { status : 'failed' , error : topLevelError || resp ?. error } ) ;
151
- throw new Error ( `ERROR: ${ JSON . stringify ( topLevelError || resp ?. error ) } ` ) ;
152
+ let resp : any ;
153
+ try {
154
+ const { content : chatResponse } = await this . options . textCompleteAdapter . complete ( prompt , [ ] , numberOfTokens ) ;
155
+ resp = ( chatResponse as any ) . response ;
156
+ const topLevelError = ( chatResponse as any ) . error ;
157
+ if ( topLevelError || resp ?. error ) {
158
+ isError = true ;
159
+ jobs . set ( jobId , { status : 'failed' , error : `ERROR: ${ JSON . stringify ( topLevelError || resp ?. error ) } ` } ) ;
160
+ }
161
+ resp = chatResponse
162
+ } catch ( e ) {
163
+ isError = true ;
164
+ jobs . set ( jobId , { status : 'failed' , error : 'AI provider refused to fill fields' } ) ;
165
+ return { ok : false , error : 'AI provider refused to fill fields' } ;
152
166
}
153
- const resData = JSON . parse ( chatResponse ) ;
167
+ const resData = JSON . parse ( resp ) ;
154
168
155
169
//return resData;
156
170
const result = resData ;
@@ -161,6 +175,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
161
175
162
176
private async initialImageGenerate ( jobId : string , recordId : string , adminUser : any , headers : Record < string , string | string [ ] | undefined > ) {
163
177
const selectedId = recordId ;
178
+ let isError = false ;
164
179
if ( typeof ( this . options . rateLimits ?. generateImages ) === 'string' ) {
165
180
if ( this . checkRateLimit ( "generateImages" , this . options . rateLimits . generateImages , headers ) ) {
166
181
jobs . set ( jobId , { status : 'failed' , error : "Rate limit exceeded" } ) ;
@@ -184,7 +199,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
184
199
return { key, images : [ ] } ;
185
200
} else {
186
201
if ( STUB_MODE ) {
187
- await new Promise ( ( resolve ) => setTimeout ( resolve , Math . floor ( Math . random ( ) * 8000 ) + 1000 ) ) ;
202
+ await new Promise ( ( resolve ) => setTimeout ( resolve , Math . floor ( Math . random ( ) * 20000 ) + 1000 ) ) ;
188
203
images = `https://pic.re/image` ;
189
204
} else {
190
205
let generationAdapter ;
@@ -193,14 +208,21 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
193
208
} else {
194
209
generationAdapter = this . options . imageGenerationAdapter ;
195
210
}
196
- const resp = await generationAdapter . generate (
197
- {
198
- prompt,
199
- inputFiles : attachmentFiles ,
200
- n : 1 ,
201
- size : this . options . generateImages [ key ] . outputSize ,
202
- }
203
- )
211
+ let resp ;
212
+ try {
213
+ resp = await generationAdapter . generate (
214
+ {
215
+ prompt,
216
+ inputFiles : attachmentFiles ,
217
+ n : 1 ,
218
+ size : this . options . generateImages [ key ] . outputSize ,
219
+ }
220
+ )
221
+ } catch ( e ) {
222
+ jobs . set ( jobId , { status : 'failed' , error : "AI provider refused to generate image" } ) ;
223
+ isError = true ;
224
+ return { key, images : [ ] } ;
225
+ }
204
226
images = resp . imageURLs [ 0 ] ;
205
227
}
206
228
return { key, images } ;
@@ -219,12 +241,17 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
219
241
220
242
this . totalCalls ++ ;
221
243
this . totalDuration += ( + new Date ( ) - start ) / 1000 ;
244
+ if ( ! isError ) {
222
245
jobs . set ( jobId , { status : 'completed' , result } ) ;
223
- return { ok : true } ;
246
+ return { ok : true }
247
+ } else {
248
+ return { ok : false , error : 'Error during image generation' } ;
249
+ }
224
250
}
225
251
226
252
private async regenerateImage ( jobId : string , recordId : string , fieldName : string , prompt : string , adminUser : any , headers : Record < string , string | string [ ] | undefined > ) {
227
253
const Id = recordId ;
254
+ let isError = false ;
228
255
if ( this . checkRateLimit ( fieldName , this . options . generateImages [ fieldName ] . rateLimit , headers ) ) {
229
256
jobs . set ( jobId , { status : 'failed' , error : "Rate limit exceeded" } ) ;
230
257
return { error : "Rate limit exceeded" } ;
@@ -255,21 +282,32 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
255
282
} else {
256
283
generationAdapter = this . options . imageGenerationAdapter ;
257
284
}
258
- const resp = await generationAdapter . generate (
259
- {
260
- prompt,
261
- inputFiles : attachmentFiles ,
262
- n : 1 ,
263
- size : this . options . generateImages [ fieldName ] . outputSize ,
264
- }
265
- )
285
+ let resp ;
286
+ try {
287
+ resp = await generationAdapter . generate (
288
+ {
289
+ prompt,
290
+ inputFiles : attachmentFiles ,
291
+ n : 1 ,
292
+ size : this . options . generateImages [ fieldName ] . outputSize ,
293
+ }
294
+ )
295
+ } catch ( e ) {
296
+ jobs . set ( jobId , { status : 'failed' , error : "AI provider refused to generate image" } ) ;
297
+ isError = true ;
298
+ return [ ] ;
299
+ }
266
300
return resp . imageURLs [ 0 ]
267
301
} )
268
302
) ;
269
303
this . totalCalls ++ ;
270
304
this . totalDuration += ( + new Date ( ) - start ) / 1000 ;
271
- jobs . set ( jobId , { status : 'completed' , result : { [ fieldName ] : images } } ) ;
272
- return { ok : true } ;
305
+ if ( ! isError ) {
306
+ jobs . set ( jobId , { status : 'completed' , result : { [ fieldName ] : images } } ) ;
307
+ return { ok : true } ;
308
+ } else {
309
+ return { ok : false , error : 'Error during image generation' } ;
310
+ }
273
311
}
274
312
275
313
async modifyResourceConfig ( adminforth : IAdminForth , resourceConfig : AdminForthResource ) {
0 commit comments