@@ -17,13 +17,18 @@ export default class UploadPlugin extends AdminForthPlugin {
1717
1818 resourceConfig : AdminForthResource ;
1919
20+ rateLimiter : RateLimiter ;
21+
2022 constructor ( options : PluginOptions ) {
2123 super ( options , import . meta. url ) ;
2224 this . options = options ;
2325
2426 // for calcualting average time
2527 this . totalCalls = 0 ;
2628 this . totalDuration = 0 ;
29+ if ( this . options . generation ?. rateLimit ?. limit ) {
30+ this . rateLimiter = new RateLimiter ( this . options . generation . rateLimit ?. limit )
31+ }
2732 }
2833
2934 private async generateImages ( jobId : string , prompt : string , recordId : any , adminUser : any , headers : any ) {
@@ -358,7 +363,7 @@ export default class UploadPlugin extends AdminForthPlugin {
358363 handler : async ( { body } ) => {
359364 const { originalFilename, contentType, size, originalExtension, recordPk } = body ;
360365
361- if ( this . options . allowedFileExtensions && ! this . options . allowedFileExtensions . includes ( originalExtension ) ) {
366+ if ( this . options . allowedFileExtensions && ! this . options . allowedFileExtensions . includes ( originalExtension . toLowerCase ( ) ) ) {
362367 return {
363368 error : `File extension "${ originalExtension } " is not allowed, allowed extensions are: ${ this . options . allowedFileExtensions . join ( ', ' ) } `
364369 } ;
@@ -421,6 +426,62 @@ export default class UploadPlugin extends AdminForthPlugin {
421426 path : `/plugin/${ this . pluginInstanceId } /create-image-generation-job` ,
422427 handler : async ( { body, adminUser, headers } ) => {
423428 const { prompt, recordId } = body ;
429+ if ( this . rateLimiter ) {
430+ // rate limit
431+ // const { error } = RateLimiter.checkRateLimit(
432+ // this.pluginInstanceId,
433+ // this.options.generation.rateLimit?.limit,
434+ // this.adminforth.auth.getClientIp(headers),
435+ // );
436+ if ( ! await this . rateLimiter . consume ( `${ this . pluginInstanceId } -${ this . adminforth . auth . getClientIp ( headers ) } ` ) ) {
437+ return { error : this . options . generation . rateLimit . errorMessage } ;
438+ }
439+ }
440+ let attachmentFiles = [ ] ;
441+ if ( this . options . generation . attachFiles ) {
442+ // TODO - does it require additional allowed action to check this record id has access to get the image?
443+ // or should we mention in docs that user should do validation in method itself
444+ const record = await this . adminforth . resource ( this . resourceConfig . resourceId ) . get (
445+ [ Filters . EQ ( this . resourceConfig . columns . find ( ( column : any ) => column . primaryKey ) ?. name , recordId ) ]
446+ ) ;
447+
448+ if ( ! record ) {
449+ return { error : `Record with id ${ recordId } not found` } ;
450+ }
451+
452+ attachmentFiles = await this . options . generation . attachFiles ( { record, adminUser } ) ;
453+ // if files is not array, make it array
454+ if ( ! Array . isArray ( attachmentFiles ) ) {
455+ attachmentFiles = [ attachmentFiles ] ;
456+ }
457+
458+ }
459+
460+ let error : string | undefined = undefined ;
461+
462+ const STUB_MODE = false ;
463+
464+ const images = await Promise . all (
465+ ( new Array ( this . options . generation . countToGenerate ) ) . fill ( 0 ) . map ( async ( ) => {
466+ if ( STUB_MODE ) {
467+ await new Promise ( ( resolve ) => setTimeout ( resolve , 2000 ) ) ;
468+ return `https://picsum.photos/200/300?random=${ Math . floor ( Math . random ( ) * 1000 ) } ` ;
469+ }
470+ const start = + new Date ( ) ;
471+ let resp ;
472+ try {
473+ resp = await this . options . generation . adapter . generate (
474+ {
475+ prompt,
476+ inputFiles : attachmentFiles ,
477+ n : 1 ,
478+ size : this . options . generation . outputSize ,
479+ }
480+ )
481+ } catch ( e : any ) {
482+ error = `No response from image generation provider: ${ e . message } . Please check your prompt or try again later.` ;
483+ return ;
484+ }
424485
425486 const jobId = randomUUID ( ) ;
426487 jobs . set ( jobId , { status : "in_progress" } ) ;
0 commit comments