Skip to content

Commit 090b6f8

Browse files
authored
Merge branch 'main' into AdminForth/802
2 parents a345171 + bfe2fa8 commit 090b6f8

File tree

5 files changed

+2916
-141
lines changed

5 files changed

+2916
-141
lines changed

custom/tsconfig.json

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,27 @@
44
"paths": {
55
"@/*": [
66
// "node_modules/adminforth/dist/spa/src/*"
7-
"../../../spa/src/*"
7+
"../../../adminforth/spa/src/*"
88
],
99
"*": [
1010
// "node_modules/adminforth/dist/spa/node_modules/*"
11-
"../../../spa/node_modules/*"
11+
"../../../adminforth/spa/node_modules/*"
1212
],
1313
"@@/*": [
1414
// "node_modules/adminforth/dist/spa/src/*"
1515
"."
1616
]
1717
}
18-
}
18+
},
19+
"include": [
20+
"./**/*.ts",
21+
"./**/*.tsx",
22+
"./**/*.vue",
23+
"../**/*.ts",
24+
"../**/*.tsx",
25+
"../**/*.vue",
26+
"../*.vue",
27+
"../*.ts",
28+
"../*.tsx"
29+
]
1930
}

custom/uploader.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ const onFileChange = async (e) => {
194194
console.log('File details:', { name, extension, size, type });
195195
// validate file extension
196196
const allowedExtensions = props.meta.allowedExtensions || []
197-
if (allowedExtensions.length > 0 && !allowedExtensions.includes(extension)) {
197+
if (allowedExtensions.length > 0 && !allowedExtensions.includes(extension.toLowerCase())) {
198198
adminforth.alert({
199199
message: t('Sorry but the file type {extension} is not allowed. Please upload a file with one of the following extensions: {allowedExtensionsLabel}', {
200200
extension,

index.ts

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)