@adminforth/bulk-ai-flow 1.9.1 → 1.10.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.
- package/build.log +2 -2
- package/custom/VisionAction.vue +50 -3
- package/dist/custom/VisionAction.vue +50 -3
- package/dist/index.js +56 -30
- package/index.ts +54 -24
- package/package.json +1 -1
package/build.log
CHANGED
|
@@ -11,5 +11,5 @@ custom/package-lock.json
|
|
|
11
11
|
custom/package.json
|
|
12
12
|
custom/tsconfig.json
|
|
13
13
|
|
|
14
|
-
sent
|
|
15
|
-
total size is
|
|
14
|
+
sent 186,334 bytes received 134 bytes 372,936.00 bytes/sec
|
|
15
|
+
total size is 185,801 speedup is 1.00
|
package/custom/VisionAction.vue
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
ref="confirmDialog"
|
|
10
10
|
header="Bulk AI Flow"
|
|
11
11
|
class="!max-w-full w-full lg:w-[1600px] !lg:max-w-[1600px]"
|
|
12
|
+
:beforeCloseFunction="closeDialog"
|
|
12
13
|
:buttons="[
|
|
13
14
|
{ label: checkedCount > 1 ? 'Save fields' : 'Save field', options: { disabled: isLoading || checkedCount < 1 || isCriticalError || isFetchingRecords || isGeneratingImages || isAnalizingFields || isAnalizingImages, loader: isLoading, class: 'w-fit sm:w-40' }, onclick: (dialog) => { saveData(); dialog.hide(); } },
|
|
14
15
|
{ label: 'Cancel', onclick: (dialog) => dialog.hide() },
|
|
@@ -91,9 +92,10 @@ const checkedCount = ref(0);
|
|
|
91
92
|
const isGeneratingImages = ref(false);
|
|
92
93
|
const isAnalizingFields = ref(false);
|
|
93
94
|
const isAnalizingImages = ref(false);
|
|
94
|
-
|
|
95
|
+
const isDialogOpen = ref(false);
|
|
95
96
|
|
|
96
97
|
const openDialog = async () => {
|
|
98
|
+
isDialogOpen.value = true;
|
|
97
99
|
confirmDialog.value.open();
|
|
98
100
|
isFetchingRecords.value = true;
|
|
99
101
|
await getRecords();
|
|
@@ -143,6 +145,23 @@ const openDialog = async () => {
|
|
|
143
145
|
}
|
|
144
146
|
}
|
|
145
147
|
|
|
148
|
+
const closeDialog = () => {
|
|
149
|
+
confirmDialog.value.close();
|
|
150
|
+
isAiResponseReceivedAnalize.value = [];
|
|
151
|
+
isAiResponseReceivedImage.value = [];
|
|
152
|
+
|
|
153
|
+
records.value = [];
|
|
154
|
+
images.value = [];
|
|
155
|
+
selected.value = [];
|
|
156
|
+
tableColumns.value = [];
|
|
157
|
+
tableColumnsIndexes.value = [];
|
|
158
|
+
isError.value = false;
|
|
159
|
+
isCriticalError.value = false;
|
|
160
|
+
isImageGenerationError.value = false;
|
|
161
|
+
errorMessage.value = '';
|
|
162
|
+
isDialogOpen.value = false;
|
|
163
|
+
}
|
|
164
|
+
|
|
146
165
|
watch(selected, (val) => {
|
|
147
166
|
//console.log('Selected changed:', val);
|
|
148
167
|
checkedCount.value = val.filter(item => item.isChecked === true).length;
|
|
@@ -406,7 +425,35 @@ async function runAiAction({
|
|
|
406
425
|
let errorMessage = '';
|
|
407
426
|
const jobsIds: { jobId: any; recordId: any; }[] = [];
|
|
408
427
|
responseFlag.value = props.checkboxes.map(() => false);
|
|
409
|
-
|
|
428
|
+
let isRateLimitExceeded = false;
|
|
429
|
+
try {
|
|
430
|
+
const rateLimitRes = await callAdminForthApi({
|
|
431
|
+
path: `/plugin/${props.meta.pluginInstanceId}/update-rate-limits`,
|
|
432
|
+
method: 'POST',
|
|
433
|
+
body: {
|
|
434
|
+
actionType: actionType,
|
|
435
|
+
},
|
|
436
|
+
});
|
|
437
|
+
if (rateLimitRes?.error) {
|
|
438
|
+
isRateLimitExceeded = true;
|
|
439
|
+
adminforth.alert({
|
|
440
|
+
message: `Rate limit exceeded for "${actionType.replace('_', ' ')}" action. Please try again later.`,
|
|
441
|
+
variant: 'danger',
|
|
442
|
+
timeout: 'unlimited',
|
|
443
|
+
});
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
} catch (e) {
|
|
447
|
+
adminforth.alert({
|
|
448
|
+
message: `Error checking rate limit for "${actionType.replace('_', ' ')}" action.`,
|
|
449
|
+
variant: 'danger',
|
|
450
|
+
timeout: 'unlimited',
|
|
451
|
+
});
|
|
452
|
+
isRateLimitExceeded = true;
|
|
453
|
+
}
|
|
454
|
+
if (isRateLimitExceeded) {
|
|
455
|
+
return;
|
|
456
|
+
};
|
|
410
457
|
//creating jobs
|
|
411
458
|
const tasks = props.checkboxes.map(async (checkbox, i) => {
|
|
412
459
|
try {
|
|
@@ -440,7 +487,7 @@ async function runAiAction({
|
|
|
440
487
|
//polling jobs
|
|
441
488
|
let isInProgress = true;
|
|
442
489
|
//if no jobs were created, skip polling
|
|
443
|
-
while (isInProgress) {
|
|
490
|
+
while (isInProgress && isDialogOpen.value) {
|
|
444
491
|
//check if at least one job is still in progress
|
|
445
492
|
let isAtLeastOneInProgress = false;
|
|
446
493
|
//checking status of each job
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
ref="confirmDialog"
|
|
10
10
|
header="Bulk AI Flow"
|
|
11
11
|
class="!max-w-full w-full lg:w-[1600px] !lg:max-w-[1600px]"
|
|
12
|
+
:beforeCloseFunction="closeDialog"
|
|
12
13
|
:buttons="[
|
|
13
14
|
{ label: checkedCount > 1 ? 'Save fields' : 'Save field', options: { disabled: isLoading || checkedCount < 1 || isCriticalError || isFetchingRecords || isGeneratingImages || isAnalizingFields || isAnalizingImages, loader: isLoading, class: 'w-fit sm:w-40' }, onclick: (dialog) => { saveData(); dialog.hide(); } },
|
|
14
15
|
{ label: 'Cancel', onclick: (dialog) => dialog.hide() },
|
|
@@ -91,9 +92,10 @@ const checkedCount = ref(0);
|
|
|
91
92
|
const isGeneratingImages = ref(false);
|
|
92
93
|
const isAnalizingFields = ref(false);
|
|
93
94
|
const isAnalizingImages = ref(false);
|
|
94
|
-
|
|
95
|
+
const isDialogOpen = ref(false);
|
|
95
96
|
|
|
96
97
|
const openDialog = async () => {
|
|
98
|
+
isDialogOpen.value = true;
|
|
97
99
|
confirmDialog.value.open();
|
|
98
100
|
isFetchingRecords.value = true;
|
|
99
101
|
await getRecords();
|
|
@@ -143,6 +145,23 @@ const openDialog = async () => {
|
|
|
143
145
|
}
|
|
144
146
|
}
|
|
145
147
|
|
|
148
|
+
const closeDialog = () => {
|
|
149
|
+
confirmDialog.value.close();
|
|
150
|
+
isAiResponseReceivedAnalize.value = [];
|
|
151
|
+
isAiResponseReceivedImage.value = [];
|
|
152
|
+
|
|
153
|
+
records.value = [];
|
|
154
|
+
images.value = [];
|
|
155
|
+
selected.value = [];
|
|
156
|
+
tableColumns.value = [];
|
|
157
|
+
tableColumnsIndexes.value = [];
|
|
158
|
+
isError.value = false;
|
|
159
|
+
isCriticalError.value = false;
|
|
160
|
+
isImageGenerationError.value = false;
|
|
161
|
+
errorMessage.value = '';
|
|
162
|
+
isDialogOpen.value = false;
|
|
163
|
+
}
|
|
164
|
+
|
|
146
165
|
watch(selected, (val) => {
|
|
147
166
|
//console.log('Selected changed:', val);
|
|
148
167
|
checkedCount.value = val.filter(item => item.isChecked === true).length;
|
|
@@ -406,7 +425,35 @@ async function runAiAction({
|
|
|
406
425
|
let errorMessage = '';
|
|
407
426
|
const jobsIds: { jobId: any; recordId: any; }[] = [];
|
|
408
427
|
responseFlag.value = props.checkboxes.map(() => false);
|
|
409
|
-
|
|
428
|
+
let isRateLimitExceeded = false;
|
|
429
|
+
try {
|
|
430
|
+
const rateLimitRes = await callAdminForthApi({
|
|
431
|
+
path: `/plugin/${props.meta.pluginInstanceId}/update-rate-limits`,
|
|
432
|
+
method: 'POST',
|
|
433
|
+
body: {
|
|
434
|
+
actionType: actionType,
|
|
435
|
+
},
|
|
436
|
+
});
|
|
437
|
+
if (rateLimitRes?.error) {
|
|
438
|
+
isRateLimitExceeded = true;
|
|
439
|
+
adminforth.alert({
|
|
440
|
+
message: `Rate limit exceeded for "${actionType.replace('_', ' ')}" action. Please try again later.`,
|
|
441
|
+
variant: 'danger',
|
|
442
|
+
timeout: 'unlimited',
|
|
443
|
+
});
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
} catch (e) {
|
|
447
|
+
adminforth.alert({
|
|
448
|
+
message: `Error checking rate limit for "${actionType.replace('_', ' ')}" action.`,
|
|
449
|
+
variant: 'danger',
|
|
450
|
+
timeout: 'unlimited',
|
|
451
|
+
});
|
|
452
|
+
isRateLimitExceeded = true;
|
|
453
|
+
}
|
|
454
|
+
if (isRateLimitExceeded) {
|
|
455
|
+
return;
|
|
456
|
+
};
|
|
410
457
|
//creating jobs
|
|
411
458
|
const tasks = props.checkboxes.map(async (checkbox, i) => {
|
|
412
459
|
try {
|
|
@@ -440,7 +487,7 @@ async function runAiAction({
|
|
|
440
487
|
//polling jobs
|
|
441
488
|
let isInProgress = true;
|
|
442
489
|
//if no jobs were created, skip polling
|
|
443
|
-
while (isInProgress) {
|
|
490
|
+
while (isInProgress && isDialogOpen.value) {
|
|
444
491
|
//check if at least one job is still in progress
|
|
445
492
|
let isAtLeastOneInProgress = false;
|
|
446
493
|
//checking status of each job
|
package/dist/index.js
CHANGED
|
@@ -56,15 +56,15 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
56
56
|
}
|
|
57
57
|
analyze_image(jobId, recordId, adminUser, headers) {
|
|
58
58
|
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j
|
|
59
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
60
60
|
const selectedId = recordId;
|
|
61
61
|
let isError = false;
|
|
62
|
-
if (typeof
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
62
|
+
// if (typeof(this.options.rateLimits?.fillFieldsFromImages) === 'string'){
|
|
63
|
+
// if (this.checkRateLimit("fillFieldsFromImages" ,this.options.rateLimits.fillFieldsFromImages, headers)) {
|
|
64
|
+
// jobs.set(jobId, { status: 'failed', error: "Rate limit exceeded" });
|
|
65
|
+
// return { error: "Rate limit exceeded" };
|
|
66
|
+
// }
|
|
67
|
+
// }
|
|
68
68
|
// Fetch the record using the provided ID
|
|
69
69
|
const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
|
|
70
70
|
const record = yield this.adminforth.resource(this.resourceConfig.resourceId).get([Filters.EQ(primaryKeyColumn.name, selectedId)]);
|
|
@@ -98,7 +98,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
98
98
|
if (topLevelError || (resp === null || resp === void 0 ? void 0 : resp.error)) {
|
|
99
99
|
jobs.set(jobId, { status: 'failed', error: `ERROR: ${JSON.stringify(topLevelError || (resp === null || resp === void 0 ? void 0 : resp.error))}` });
|
|
100
100
|
}
|
|
101
|
-
const textOutput = (
|
|
101
|
+
const textOutput = (_f = (_e = (_d = (_c = (_b = (_a = resp === null || resp === void 0 ? void 0 : resp.output) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.content) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.text) !== null && _e !== void 0 ? _e : resp === null || resp === void 0 ? void 0 : resp.output_text) !== null && _f !== void 0 ? _f : (_j = (_h = (_g = resp === null || resp === void 0 ? void 0 : resp.choices) === null || _g === void 0 ? void 0 : _g[0]) === null || _h === void 0 ? void 0 : _h.message) === null || _j === void 0 ? void 0 : _j.content;
|
|
102
102
|
if (!textOutput || typeof textOutput !== 'string') {
|
|
103
103
|
jobs.set(jobId, { status: 'failed', error: 'Unexpected AI response format' });
|
|
104
104
|
}
|
|
@@ -109,20 +109,22 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
109
109
|
return { ok: true };
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
-
|
|
112
|
+
else {
|
|
113
|
+
jobs.set(jobId, { status: 'failed', error: "No attachment files found" });
|
|
114
|
+
return { ok: false, error: "No attachment files found" };
|
|
115
|
+
}
|
|
113
116
|
});
|
|
114
117
|
}
|
|
115
118
|
analyzeNoImages(jobId, recordId, adminUser, headers) {
|
|
116
119
|
return __awaiter(this, void 0, void 0, function* () {
|
|
117
|
-
var _a;
|
|
118
120
|
const selectedId = recordId;
|
|
119
121
|
let isError = false;
|
|
120
|
-
if (typeof
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
122
|
+
// if (typeof(this.options.rateLimits?.fillPlainFields) === 'string'){
|
|
123
|
+
// if (this.checkRateLimit("fillPlainFields", this.options.rateLimits.fillPlainFields, headers)) {
|
|
124
|
+
// jobs.set(jobId, { status: 'failed', error: "Rate limit exceeded" });
|
|
125
|
+
// return { error: "Rate limit exceeded" };
|
|
126
|
+
// }
|
|
127
|
+
// }
|
|
126
128
|
if (STUB_MODE) {
|
|
127
129
|
yield new Promise((resolve) => setTimeout(resolve, Math.floor(Math.random() * 20000) + 1000));
|
|
128
130
|
jobs.set(jobId, { status: 'completed', result: {} });
|
|
@@ -163,17 +165,17 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
163
165
|
}
|
|
164
166
|
initialImageGenerate(jobId, recordId, adminUser, headers) {
|
|
165
167
|
return __awaiter(this, void 0, void 0, function* () {
|
|
166
|
-
var _a, _b
|
|
168
|
+
var _a, _b;
|
|
167
169
|
const selectedId = recordId;
|
|
168
170
|
let isError = false;
|
|
169
|
-
if (typeof
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
171
|
+
// if (typeof(this.options.rateLimits?.generateImages) === 'string'){
|
|
172
|
+
// if (this.checkRateLimit("generateImages", this.options.rateLimits.generateImages, headers)) {
|
|
173
|
+
// jobs.set(jobId, { status: 'failed', error: "Rate limit exceeded" });
|
|
174
|
+
// return { error: "Rate limit exceeded" };
|
|
175
|
+
// }
|
|
176
|
+
// }
|
|
175
177
|
const start = +new Date();
|
|
176
|
-
const record = yield this.adminforth.resource(this.resourceConfig.resourceId).get([Filters.EQ((
|
|
178
|
+
const record = yield this.adminforth.resource(this.resourceConfig.resourceId).get([Filters.EQ((_a = this.resourceConfig.columns.find(c => c.primaryKey)) === null || _a === void 0 ? void 0 : _a.name, selectedId)]);
|
|
177
179
|
let attachmentFiles;
|
|
178
180
|
if (!this.options.attachFiles) {
|
|
179
181
|
attachmentFiles = [];
|
|
@@ -181,7 +183,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
181
183
|
else {
|
|
182
184
|
attachmentFiles = yield this.options.attachFiles({ record });
|
|
183
185
|
}
|
|
184
|
-
const fieldTasks = Object.keys(((
|
|
186
|
+
const fieldTasks = Object.keys(((_b = this.options) === null || _b === void 0 ? void 0 : _b.generateImages) || {}).map((key) => __awaiter(this, void 0, void 0, function* () {
|
|
185
187
|
const prompt = this.compileGenerationFieldTemplates(record)[key];
|
|
186
188
|
let images;
|
|
187
189
|
if (this.options.attachFiles && attachmentFiles.length === 0) {
|
|
@@ -600,25 +602,25 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
600
602
|
}
|
|
601
603
|
switch (actionType) {
|
|
602
604
|
case 'generate_images':
|
|
603
|
-
|
|
605
|
+
this.initialImageGenerate(jobId, recordId, adminUser, headers);
|
|
604
606
|
break;
|
|
605
607
|
case 'analyze_no_images':
|
|
606
|
-
|
|
608
|
+
this.analyzeNoImages(jobId, recordId, adminUser, headers);
|
|
607
609
|
break;
|
|
608
610
|
case 'analyze':
|
|
609
|
-
|
|
611
|
+
this.analyze_image(jobId, recordId, adminUser, headers);
|
|
610
612
|
break;
|
|
611
613
|
case 'regenerate_images':
|
|
612
614
|
if (!body.prompt || !body.fieldName) {
|
|
613
615
|
jobs.set(jobId, { status: "failed", error: "Missing prompt or field name" });
|
|
614
616
|
break;
|
|
615
617
|
}
|
|
616
|
-
|
|
618
|
+
this.regenerateImage(jobId, recordId, body.fieldName, body.prompt, adminUser, headers);
|
|
617
619
|
break;
|
|
618
620
|
default:
|
|
619
621
|
jobs.set(jobId, { status: "failed", error: "Unknown action type" });
|
|
620
622
|
}
|
|
621
|
-
setTimeout(() => jobs.delete(jobId),
|
|
623
|
+
setTimeout(() => jobs.delete(jobId), 1800000);
|
|
622
624
|
return { ok: true, jobId };
|
|
623
625
|
})
|
|
624
626
|
});
|
|
@@ -637,5 +639,29 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
637
639
|
return { ok: true, job };
|
|
638
640
|
})
|
|
639
641
|
});
|
|
642
|
+
server.endpoint({
|
|
643
|
+
method: 'POST',
|
|
644
|
+
path: `/plugin/${this.pluginInstanceId}/update-rate-limits`,
|
|
645
|
+
handler: (_a) => __awaiter(this, [_a], void 0, function* ({ body, adminUser, headers }) {
|
|
646
|
+
var _b, _c, _d;
|
|
647
|
+
const actionType = body.actionType;
|
|
648
|
+
if (actionType === 'analyze' && ((_b = this.options.rateLimits) === null || _b === void 0 ? void 0 : _b.fillFieldsFromImages)) {
|
|
649
|
+
if (this.checkRateLimit("fillFieldsFromImages", this.options.rateLimits.fillFieldsFromImages, headers)) {
|
|
650
|
+
return { ok: false, error: "Rate limit exceeded for image analyze" };
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
if (actionType === 'analyze_no_images' && ((_c = this.options.rateLimits) === null || _c === void 0 ? void 0 : _c.fillPlainFields)) {
|
|
654
|
+
if (this.checkRateLimit("fillPlainFields", this.options.rateLimits.fillPlainFields, headers)) {
|
|
655
|
+
return { ok: false, error: "Rate limit exceeded for plain field analyze" };
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
if (actionType === 'generate_images' && ((_d = this.options.rateLimits) === null || _d === void 0 ? void 0 : _d.generateImages)) {
|
|
659
|
+
if (this.checkRateLimit("generateImages", this.options.rateLimits.generateImages, headers)) {
|
|
660
|
+
return { ok: false, error: "Rate limit exceeded for image generation" };
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return { ok: true };
|
|
664
|
+
})
|
|
665
|
+
});
|
|
640
666
|
}
|
|
641
667
|
}
|
package/index.ts
CHANGED
|
@@ -70,12 +70,12 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
70
70
|
private async analyze_image(jobId: string, recordId: string, adminUser: any, headers: Record<string, string | string[] | undefined>) {
|
|
71
71
|
const selectedId = recordId;
|
|
72
72
|
let isError = false;
|
|
73
|
-
if (typeof(this.options.rateLimits?.fillFieldsFromImages) === 'string'){
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
73
|
+
// if (typeof(this.options.rateLimits?.fillFieldsFromImages) === 'string'){
|
|
74
|
+
// if (this.checkRateLimit("fillFieldsFromImages" ,this.options.rateLimits.fillFieldsFromImages, headers)) {
|
|
75
|
+
// jobs.set(jobId, { status: 'failed', error: "Rate limit exceeded" });
|
|
76
|
+
// return { error: "Rate limit exceeded" };
|
|
77
|
+
// }
|
|
78
|
+
// }
|
|
79
79
|
// Fetch the record using the provided ID
|
|
80
80
|
const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
|
|
81
81
|
const record = await this.adminforth.resource(this.resourceConfig.resourceId).get([Filters.EQ(primaryKeyColumn.name, selectedId)] );
|
|
@@ -121,18 +121,22 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
121
121
|
jobs.set(jobId, { status: 'completed', result });
|
|
122
122
|
return { ok: true };
|
|
123
123
|
}
|
|
124
|
-
}
|
|
124
|
+
} else {
|
|
125
|
+
jobs.set(jobId, { status: 'failed', error: "No attachment files found" });
|
|
126
|
+
return { ok: false, error: "No attachment files found" };
|
|
127
|
+
}
|
|
128
|
+
|
|
125
129
|
}
|
|
126
130
|
|
|
127
131
|
private async analyzeNoImages(jobId: string, recordId: string, adminUser: any, headers: Record<string, string | string[] | undefined>) {
|
|
128
132
|
const selectedId = recordId;
|
|
129
133
|
let isError = false;
|
|
130
|
-
if (typeof(this.options.rateLimits?.fillPlainFields) === 'string'){
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
134
|
+
// if (typeof(this.options.rateLimits?.fillPlainFields) === 'string'){
|
|
135
|
+
// if (this.checkRateLimit("fillPlainFields", this.options.rateLimits.fillPlainFields, headers)) {
|
|
136
|
+
// jobs.set(jobId, { status: 'failed', error: "Rate limit exceeded" });
|
|
137
|
+
// return { error: "Rate limit exceeded" };
|
|
138
|
+
// }
|
|
139
|
+
// }
|
|
136
140
|
if (STUB_MODE) {
|
|
137
141
|
await new Promise((resolve) => setTimeout(resolve, Math.floor(Math.random() * 20000) + 1000));
|
|
138
142
|
jobs.set(jobId, { status: 'completed', result: {} });
|
|
@@ -173,12 +177,12 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
173
177
|
private async initialImageGenerate(jobId: string, recordId: string, adminUser: any, headers: Record<string, string | string[] | undefined>) {
|
|
174
178
|
const selectedId = recordId;
|
|
175
179
|
let isError = false;
|
|
176
|
-
if (typeof(this.options.rateLimits?.generateImages) === 'string'){
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
180
|
+
// if (typeof(this.options.rateLimits?.generateImages) === 'string'){
|
|
181
|
+
// if (this.checkRateLimit("generateImages", this.options.rateLimits.generateImages, headers)) {
|
|
182
|
+
// jobs.set(jobId, { status: 'failed', error: "Rate limit exceeded" });
|
|
183
|
+
// return { error: "Rate limit exceeded" };
|
|
184
|
+
// }
|
|
185
|
+
// }
|
|
182
186
|
const start = +new Date();
|
|
183
187
|
const record = await this.adminforth.resource(this.resourceConfig.resourceId).get([Filters.EQ(this.resourceConfig.columns.find(c => c.primaryKey)?.name, selectedId)]);
|
|
184
188
|
let attachmentFiles
|
|
@@ -638,25 +642,25 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
638
642
|
|
|
639
643
|
switch(actionType) {
|
|
640
644
|
case 'generate_images':
|
|
641
|
-
|
|
645
|
+
this.initialImageGenerate(jobId, recordId, adminUser, headers);
|
|
642
646
|
break;
|
|
643
647
|
case 'analyze_no_images':
|
|
644
|
-
|
|
648
|
+
this.analyzeNoImages(jobId, recordId, adminUser, headers);
|
|
645
649
|
break;
|
|
646
650
|
case 'analyze':
|
|
647
|
-
|
|
651
|
+
this.analyze_image(jobId, recordId, adminUser, headers);
|
|
648
652
|
break;
|
|
649
653
|
case 'regenerate_images':
|
|
650
654
|
if (!body.prompt || !body.fieldName) {
|
|
651
655
|
jobs.set(jobId, { status: "failed", error: "Missing prompt or field name" });
|
|
652
656
|
break;
|
|
653
657
|
}
|
|
654
|
-
|
|
658
|
+
this.regenerateImage(jobId, recordId, body.fieldName, body.prompt, adminUser, headers);
|
|
655
659
|
break;
|
|
656
660
|
default:
|
|
657
661
|
jobs.set(jobId, { status: "failed", error: "Unknown action type" });
|
|
658
662
|
}
|
|
659
|
-
setTimeout(() => jobs.delete(jobId),
|
|
663
|
+
setTimeout(() => jobs.delete(jobId), 1_800_000);
|
|
660
664
|
return { ok: true, jobId };
|
|
661
665
|
}
|
|
662
666
|
});
|
|
@@ -679,5 +683,31 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
679
683
|
});
|
|
680
684
|
|
|
681
685
|
|
|
686
|
+
server.endpoint({
|
|
687
|
+
method: 'POST',
|
|
688
|
+
path: `/plugin/${this.pluginInstanceId}/update-rate-limits`,
|
|
689
|
+
handler: async ({ body, adminUser, headers }) => {
|
|
690
|
+
const actionType = body.actionType;
|
|
691
|
+
if (actionType === 'analyze' && this.options.rateLimits?.fillFieldsFromImages) {
|
|
692
|
+
if (this.checkRateLimit("fillFieldsFromImages" ,this.options.rateLimits.fillFieldsFromImages, headers)) {
|
|
693
|
+
return {ok: false, error: "Rate limit exceeded for image analyze" };
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
if (actionType === 'analyze_no_images' && this.options.rateLimits?.fillPlainFields) {
|
|
697
|
+
if (this.checkRateLimit("fillPlainFields" ,this.options.rateLimits.fillPlainFields, headers)) {
|
|
698
|
+
return {ok: false, error: "Rate limit exceeded for plain field analyze" };
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
if (actionType === 'generate_images' && this.options.rateLimits?.generateImages) {
|
|
702
|
+
if (this.checkRateLimit("generateImages" ,this.options.rateLimits.generateImages, headers)) {
|
|
703
|
+
return {ok: false, error: "Rate limit exceeded for image generation" };
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
return { ok: true };
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
|
|
682
712
|
}
|
|
683
713
|
}
|