@adminforth/bulk-ai-flow 1.5.6 → 1.7.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/imageGenerationCarousel.vue +2 -3
- package/custom/visionAction.vue +83 -158
- package/custom/visionTable.vue +2 -1
- package/dist/custom/imageGenerationCarousel.vue +2 -3
- package/dist/custom/visionAction.vue +83 -158
- package/dist/custom/visionTable.vue +2 -1
- package/dist/index.js +12 -29
- package/index.ts +21 -31
- package/package.json +1 -1
package/build.log
CHANGED
|
@@ -11,5 +11,5 @@ custom/tsconfig.json
|
|
|
11
11
|
custom/visionAction.vue
|
|
12
12
|
custom/visionTable.vue
|
|
13
13
|
|
|
14
|
-
sent
|
|
15
|
-
total size is
|
|
14
|
+
sent 180,778 bytes received 134 bytes 361,824.00 bytes/sec
|
|
15
|
+
total size is 180,250 speedup is 1.00
|
|
@@ -183,7 +183,7 @@
|
|
|
183
183
|
|
|
184
184
|
<script setup lang="ts">
|
|
185
185
|
|
|
186
|
-
import { ref, onMounted, nextTick, Ref,
|
|
186
|
+
import { ref, onMounted, nextTick, Ref, watch } from 'vue'
|
|
187
187
|
import { Carousel } from 'flowbite';
|
|
188
188
|
import { callAdminForthApi } from '@/utils';
|
|
189
189
|
import { useI18n } from 'vue-i18n';
|
|
@@ -267,9 +267,8 @@ onMounted(async () => {
|
|
|
267
267
|
return context[field.trim()] || '';
|
|
268
268
|
});
|
|
269
269
|
|
|
270
|
-
if (props.record[props.record[props.meta.recorPkFieldName]]) {
|
|
271
270
|
const recordId = props.record[props.meta.recorPkFieldName];
|
|
272
|
-
|
|
271
|
+
if (!recordId) {
|
|
273
272
|
emit('error', {
|
|
274
273
|
isError: true,
|
|
275
274
|
errorMessage: 'Record ID not found, cannot generate images'
|
package/custom/visionAction.vue
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="flex items-end justify-start gap-2" @click="openDialog">
|
|
2
|
+
<div class="flex items-end justify-start gap-2 cursor-pointer" @click="openDialog">
|
|
3
3
|
<div class="flex items-center justify-center text-white bg-gradient-to-r h-[18px] from-purple-500 via-purple-600 to-purple-700 hover:bg-gradient-to-br focus:ring-4 focus:outline-none focus:ring-purple-300 dark:focus:ring-purple-800 font-medium rounded-md text-sm px-1 text-center">
|
|
4
4
|
AI
|
|
5
5
|
</div>
|
|
6
|
-
<p class="text-justify max-h-[18px]">{{ props.meta.actionName }}</p>
|
|
6
|
+
<p class="text-justify max-h-[18px] truncate max-w-[60vw] md:max-w-none">{{ props.meta.actionName }}</p>
|
|
7
7
|
</div>
|
|
8
8
|
<Dialog ref="confirmDialog">
|
|
9
9
|
<div
|
|
10
10
|
class="fixed inset-0 z-20 flex items-center justify-center bg-black/40"
|
|
11
11
|
>
|
|
12
12
|
<div
|
|
13
|
-
class="bulk-vision-dialog flex items-center justify-center relative max-w-[95vw] min-w-[640px] max-h-[90vh] bg-white dark:bg-gray-900 rounded-md shadow-2xl overflow-hidden"
|
|
13
|
+
class="bulk-vision-dialog flex items-center justify-center relative w-[100vw] h-[100vh] max-h-[100vh] md:w-auto md:max-w-[95vw] md:min-w-[640px] md:h-auto md:max-h-[90vh] bg-white dark:bg-gray-900 rounded-none md:rounded-md shadow-2xl overflow-hidden"
|
|
14
14
|
@click.stop
|
|
15
15
|
>
|
|
16
|
-
<div class="bulk-vision-table flex flex-col items-center justify-evenly gap-4 w-full h-full p-6 overflow-y-auto">
|
|
16
|
+
<div class="bulk-vision-table flex flex-col items-center justify-evenly gap-3 md:gap-4 w-full h-full p-4 md:p-6 overflow-y-auto overflow-x-auto">
|
|
17
17
|
<button type="button"
|
|
18
18
|
@click="closeDialog"
|
|
19
19
|
class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white" >
|
|
@@ -22,35 +22,36 @@
|
|
|
22
22
|
</svg>
|
|
23
23
|
</button>
|
|
24
24
|
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
25
|
+
<div v-if="records && props.checkboxes.length" class="w-full overflow-x-auto">
|
|
26
|
+
<VisionTable
|
|
27
|
+
:checkbox="props.checkboxes"
|
|
28
|
+
:records="records"
|
|
29
|
+
:index="0"
|
|
30
|
+
:meta="props.meta"
|
|
31
|
+
:images="images"
|
|
32
|
+
:tableHeaders="tableHeaders"
|
|
33
|
+
:tableColumns="tableColumns"
|
|
34
|
+
:customFieldNames="customFieldNames"
|
|
35
|
+
:tableColumnsIndexes="tableColumnsIndexes"
|
|
36
|
+
:selected="selected"
|
|
37
|
+
:isAiResponseReceivedAnalize="isAiResponseReceivedAnalize"
|
|
38
|
+
:isAiResponseReceivedImage="isAiResponseReceivedImage"
|
|
39
|
+
:primaryKey="primaryKey"
|
|
40
|
+
:openGenerationCarousel="openGenerationCarousel"
|
|
41
|
+
@error="handleTableError"
|
|
42
|
+
/>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="flex w-full flex-col md:flex-row items-stretch md:items-end justify-end gap-3 md:gap-4">
|
|
45
|
+
<div class="h-full text-red-600 font-semibold flex items-center justify-center md:mb-2">
|
|
45
46
|
<p v-if="isError === true">{{ errorMessage }}</p>
|
|
46
47
|
</div>
|
|
47
|
-
<button type="button" class="py-2.5 px-5
|
|
48
|
+
<button type="button" class="w-full md:w-auto py-2.5 px-5 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
|
|
48
49
|
@click="closeDialog"
|
|
49
50
|
>
|
|
50
51
|
{{'Cancel'}}
|
|
51
52
|
</button>
|
|
52
53
|
<Button
|
|
53
|
-
class="w-64"
|
|
54
|
+
class="w-full md:w-64"
|
|
54
55
|
@click="saveData"
|
|
55
56
|
:disabled="isLoading || checkedCount < 1 || isCriticalError"
|
|
56
57
|
:loader="isLoading"
|
|
@@ -66,7 +67,7 @@
|
|
|
66
67
|
|
|
67
68
|
<script lang="ts" setup>
|
|
68
69
|
import { callAdminForthApi } from '@/utils';
|
|
69
|
-
import { ref, watch } from 'vue'
|
|
70
|
+
import { Ref, ref, watch } from 'vue'
|
|
70
71
|
import { Dialog, Button } from '@/afcl';
|
|
71
72
|
import VisionTable from './visionTable.vue'
|
|
72
73
|
import adminforth from '@/adminforth';
|
|
@@ -131,13 +132,25 @@ const openDialog = async () => {
|
|
|
131
132
|
isLoading.value = true;
|
|
132
133
|
const tasks = [];
|
|
133
134
|
if (props.meta.isFieldsForAnalizeFromImages) {
|
|
134
|
-
tasks.push(
|
|
135
|
+
tasks.push(runAiAction({
|
|
136
|
+
endpoint: 'analyze',
|
|
137
|
+
actionType: 'analyze',
|
|
138
|
+
responseFlag: isAiResponseReceivedAnalize,
|
|
139
|
+
}));
|
|
135
140
|
}
|
|
136
141
|
if (props.meta.isFieldsForAnalizePlain) {
|
|
137
|
-
tasks.push(
|
|
142
|
+
tasks.push(runAiAction({
|
|
143
|
+
endpoint: 'analyze_no_images',
|
|
144
|
+
actionType: 'analyze_no_images',
|
|
145
|
+
responseFlag: isAiResponseReceivedAnalize,
|
|
146
|
+
}));
|
|
138
147
|
}
|
|
139
148
|
if (props.meta.isImageGeneration) {
|
|
140
|
-
tasks.push(
|
|
149
|
+
tasks.push(runAiAction({
|
|
150
|
+
endpoint: 'initial_image_generate',
|
|
151
|
+
actionType: 'generate_images',
|
|
152
|
+
responseFlag: isAiResponseReceivedImage,
|
|
153
|
+
}));
|
|
141
154
|
}
|
|
142
155
|
await Promise.all(tasks);
|
|
143
156
|
isLoading.value = false;
|
|
@@ -160,6 +173,7 @@ const closeDialog = () => {
|
|
|
160
173
|
tableColumnsIndexes.value = [];
|
|
161
174
|
isError.value = false;
|
|
162
175
|
isCriticalError.value = false;
|
|
176
|
+
isImageGenerationError.value = false;
|
|
163
177
|
errorMessage.value = '';
|
|
164
178
|
}
|
|
165
179
|
|
|
@@ -329,111 +343,6 @@ async function convertImages(fieldName, img) {
|
|
|
329
343
|
}
|
|
330
344
|
|
|
331
345
|
|
|
332
|
-
async function analyzeFields() {
|
|
333
|
-
isAiResponseReceivedAnalize.value = props.checkboxes.map(() => false);
|
|
334
|
-
try {
|
|
335
|
-
const res = await callAdminForthApi({
|
|
336
|
-
path: `/plugin/${props.meta.pluginInstanceId}/analyze`,
|
|
337
|
-
method: 'POST',
|
|
338
|
-
body: {
|
|
339
|
-
selectedIds: props.checkboxes,
|
|
340
|
-
},
|
|
341
|
-
});
|
|
342
|
-
|
|
343
|
-
if (res?.error) {
|
|
344
|
-
adminforth.alert({
|
|
345
|
-
message: res.error,
|
|
346
|
-
variant: 'danger',
|
|
347
|
-
timeout: 'unlimited',
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
console.error('Failed to analyze image(s):', res.error);
|
|
351
|
-
isError.value = true;
|
|
352
|
-
//isCriticalError.value = true;
|
|
353
|
-
errorMessage.value = `Failed to fetch analyze image(s). Please, try to re-run the action.`;
|
|
354
|
-
} else {
|
|
355
|
-
res.result.forEach((item, idx) => {
|
|
356
|
-
const pk = selected.value[idx]?.[primaryKey]
|
|
357
|
-
|
|
358
|
-
if (pk) {
|
|
359
|
-
selected.value[idx] = {
|
|
360
|
-
...selected.value[idx],
|
|
361
|
-
...item,
|
|
362
|
-
isChecked: true,
|
|
363
|
-
[primaryKey]: pk
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
})
|
|
367
|
-
}
|
|
368
|
-
} catch (error) {
|
|
369
|
-
adminforth.alert({
|
|
370
|
-
message: error,
|
|
371
|
-
variant: 'danger',
|
|
372
|
-
timeout: 'unlimited',
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
console.error('Failed to analyze image(s):', error);
|
|
376
|
-
isError.value = true;
|
|
377
|
-
//isCriticalError.value = true;
|
|
378
|
-
errorMessage.value = res.error;
|
|
379
|
-
}
|
|
380
|
-
isAiResponseReceivedAnalize.value = props.checkboxes.map(() => true);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
async function analyzeFieldsNoImages() {
|
|
385
|
-
isAiResponseReceivedAnalize.value = props.checkboxes.map(() => false);
|
|
386
|
-
try {
|
|
387
|
-
const res = await callAdminForthApi({
|
|
388
|
-
path: `/plugin/${props.meta.pluginInstanceId}/analyze_no_images`,
|
|
389
|
-
method: 'POST',
|
|
390
|
-
body: {
|
|
391
|
-
selectedIds: props.checkboxes,
|
|
392
|
-
},
|
|
393
|
-
});
|
|
394
|
-
if(res?.error) {
|
|
395
|
-
adminforth.alert({
|
|
396
|
-
message: res.error,
|
|
397
|
-
variant: 'danger',
|
|
398
|
-
timeout: 'unlimited',
|
|
399
|
-
});
|
|
400
|
-
console.error('Failed to analyze fields:', res.error);
|
|
401
|
-
isError.value = true;
|
|
402
|
-
//isCriticalError.value = true;
|
|
403
|
-
errorMessage.value = res.error;
|
|
404
|
-
} else {
|
|
405
|
-
res.result.forEach((item, idx) => {
|
|
406
|
-
const pk = selected.value[idx]?.[primaryKey]
|
|
407
|
-
|
|
408
|
-
if (pk) {
|
|
409
|
-
selected.value[idx] = {
|
|
410
|
-
...selected.value[idx],
|
|
411
|
-
...item,
|
|
412
|
-
isChecked: true,
|
|
413
|
-
[primaryKey]: pk
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
})
|
|
417
|
-
}
|
|
418
|
-
} catch (error) {
|
|
419
|
-
adminforth.alert({
|
|
420
|
-
message: error,
|
|
421
|
-
variant: 'danger',
|
|
422
|
-
timeout: 'unlimited',
|
|
423
|
-
});
|
|
424
|
-
console.error('Failed to analyze fields:', error);
|
|
425
|
-
isError.value = true;
|
|
426
|
-
//isCriticalError.value = true;
|
|
427
|
-
errorMessage.value = `Failed to analyze fields. Please, try to re-run the action.`;
|
|
428
|
-
}
|
|
429
|
-
if(!props.meta.isFieldsForAnalizeFromImages) {
|
|
430
|
-
isAiResponseReceivedAnalize.value = props.checkboxes.map(() => true);
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
346
|
async function saveData() {
|
|
438
347
|
if (!selected.value?.length) {
|
|
439
348
|
adminforth.alert({ message: 'No items selected', variant: 'warning' });
|
|
@@ -496,57 +405,73 @@ async function saveData() {
|
|
|
496
405
|
}
|
|
497
406
|
}
|
|
498
407
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
408
|
+
|
|
409
|
+
async function runAiAction({
|
|
410
|
+
endpoint,
|
|
411
|
+
actionType,
|
|
412
|
+
responseFlag,
|
|
413
|
+
updateOnSuccess = true,
|
|
414
|
+
}: {
|
|
415
|
+
endpoint: string;
|
|
416
|
+
actionType: 'analyze' | 'analyze_no_images' | 'generate_images';
|
|
417
|
+
responseFlag: Ref<boolean[]>;
|
|
418
|
+
updateOnSuccess?: boolean;
|
|
419
|
+
}) {
|
|
420
|
+
let res: any;
|
|
421
|
+
let error: any = null;
|
|
503
422
|
|
|
504
423
|
try {
|
|
424
|
+
responseFlag.value = props.checkboxes.map(() => false);
|
|
425
|
+
|
|
505
426
|
res = await callAdminForthApi({
|
|
506
|
-
path: `/plugin/${props.meta.pluginInstanceId}
|
|
427
|
+
path: `/plugin/${props.meta.pluginInstanceId}/${endpoint}`,
|
|
507
428
|
method: 'POST',
|
|
508
429
|
body: {
|
|
509
430
|
selectedIds: props.checkboxes,
|
|
510
431
|
},
|
|
511
432
|
});
|
|
433
|
+
|
|
434
|
+
if (actionType !== 'analyze_no_images' || !props.meta.isFieldsForAnalizeFromImages) {
|
|
435
|
+
responseFlag.value = props.checkboxes.map(() => true);
|
|
436
|
+
}
|
|
512
437
|
} catch (e) {
|
|
513
|
-
console.error(
|
|
514
|
-
|
|
515
|
-
isImageGenerationError.value = true;
|
|
516
|
-
errorMessage.value = `Failed to generate images. Please, try to re-run the action.`;
|
|
438
|
+
console.error(`Error during ${actionType}:`, e);
|
|
439
|
+
error = `Failed to ${actionType.replace('_', ' ')}. Please, try to re-run the action.`;
|
|
517
440
|
}
|
|
518
|
-
isAiResponseReceivedImage.value = props.checkboxes.map(() => true);
|
|
519
441
|
|
|
520
442
|
if (res?.error) {
|
|
521
443
|
error = res.error;
|
|
522
444
|
}
|
|
523
|
-
if (!res) {
|
|
524
|
-
error =
|
|
525
|
-
isError.value = true;
|
|
526
|
-
isImageGenerationError.value = true;
|
|
527
|
-
errorMessage.value = `Failed to generate images. Please, try to re-run the action.`;
|
|
445
|
+
if (!res && !error) {
|
|
446
|
+
error = `Error: ${actionType} request returned empty response.`;
|
|
528
447
|
}
|
|
529
448
|
|
|
530
|
-
if (error) {
|
|
449
|
+
if (error) {
|
|
531
450
|
adminforth.alert({
|
|
532
451
|
message: error,
|
|
533
452
|
variant: 'danger',
|
|
534
453
|
timeout: 'unlimited',
|
|
535
454
|
});
|
|
536
455
|
isError.value = true;
|
|
537
|
-
|
|
456
|
+
if (actionType === 'generate_images') {
|
|
457
|
+
isImageGenerationError.value = true;
|
|
458
|
+
}
|
|
538
459
|
errorMessage.value = error;
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (updateOnSuccess) {
|
|
464
|
+
res.result.forEach((item: any, idx: number) => {
|
|
465
|
+
const pk = selected.value[idx]?.[primaryKey];
|
|
542
466
|
if (pk) {
|
|
543
467
|
selected.value[idx] = {
|
|
544
468
|
...selected.value[idx],
|
|
545
469
|
...item,
|
|
546
|
-
|
|
547
|
-
|
|
470
|
+
isChecked: true,
|
|
471
|
+
[primaryKey]: pk,
|
|
472
|
+
};
|
|
548
473
|
}
|
|
549
|
-
})
|
|
474
|
+
});
|
|
550
475
|
}
|
|
551
476
|
}
|
|
552
477
|
|
package/custom/visionTable.vue
CHANGED
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
<div v-if="isAiResponseReceivedAnalize[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])] && !isInColumnImage(n)">
|
|
48
48
|
<div v-if="isInColumnEnum(n)">
|
|
49
49
|
<Select
|
|
50
|
+
class="min-w-[150px] "
|
|
50
51
|
:options="convertColumnEnumToSelectOptions(props.meta.columnEnums, n)"
|
|
51
52
|
v-model="selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n]"
|
|
52
53
|
:teleportToTop="true"
|
|
@@ -56,7 +57,7 @@
|
|
|
56
57
|
</div>
|
|
57
58
|
<div v-else-if="typeof selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] === 'string' || typeof selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] === 'object'">
|
|
58
59
|
<Textarea
|
|
59
|
-
class="w-full h-full"
|
|
60
|
+
class="min-w-[150px] w-full h-full"
|
|
60
61
|
type="text"
|
|
61
62
|
v-model="selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n]"
|
|
62
63
|
>
|
|
@@ -183,7 +183,7 @@
|
|
|
183
183
|
|
|
184
184
|
<script setup lang="ts">
|
|
185
185
|
|
|
186
|
-
import { ref, onMounted, nextTick, Ref,
|
|
186
|
+
import { ref, onMounted, nextTick, Ref, watch } from 'vue'
|
|
187
187
|
import { Carousel } from 'flowbite';
|
|
188
188
|
import { callAdminForthApi } from '@/utils';
|
|
189
189
|
import { useI18n } from 'vue-i18n';
|
|
@@ -267,9 +267,8 @@ onMounted(async () => {
|
|
|
267
267
|
return context[field.trim()] || '';
|
|
268
268
|
});
|
|
269
269
|
|
|
270
|
-
if (props.record[props.record[props.meta.recorPkFieldName]]) {
|
|
271
270
|
const recordId = props.record[props.meta.recorPkFieldName];
|
|
272
|
-
|
|
271
|
+
if (!recordId) {
|
|
273
272
|
emit('error', {
|
|
274
273
|
isError: true,
|
|
275
274
|
errorMessage: 'Record ID not found, cannot generate images'
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="flex items-end justify-start gap-2" @click="openDialog">
|
|
2
|
+
<div class="flex items-end justify-start gap-2 cursor-pointer" @click="openDialog">
|
|
3
3
|
<div class="flex items-center justify-center text-white bg-gradient-to-r h-[18px] from-purple-500 via-purple-600 to-purple-700 hover:bg-gradient-to-br focus:ring-4 focus:outline-none focus:ring-purple-300 dark:focus:ring-purple-800 font-medium rounded-md text-sm px-1 text-center">
|
|
4
4
|
AI
|
|
5
5
|
</div>
|
|
6
|
-
<p class="text-justify max-h-[18px]">{{ props.meta.actionName }}</p>
|
|
6
|
+
<p class="text-justify max-h-[18px] truncate max-w-[60vw] md:max-w-none">{{ props.meta.actionName }}</p>
|
|
7
7
|
</div>
|
|
8
8
|
<Dialog ref="confirmDialog">
|
|
9
9
|
<div
|
|
10
10
|
class="fixed inset-0 z-20 flex items-center justify-center bg-black/40"
|
|
11
11
|
>
|
|
12
12
|
<div
|
|
13
|
-
class="bulk-vision-dialog flex items-center justify-center relative max-w-[95vw] min-w-[640px] max-h-[90vh] bg-white dark:bg-gray-900 rounded-md shadow-2xl overflow-hidden"
|
|
13
|
+
class="bulk-vision-dialog flex items-center justify-center relative w-[100vw] h-[100vh] max-h-[100vh] md:w-auto md:max-w-[95vw] md:min-w-[640px] md:h-auto md:max-h-[90vh] bg-white dark:bg-gray-900 rounded-none md:rounded-md shadow-2xl overflow-hidden"
|
|
14
14
|
@click.stop
|
|
15
15
|
>
|
|
16
|
-
<div class="bulk-vision-table flex flex-col items-center justify-evenly gap-4 w-full h-full p-6 overflow-y-auto">
|
|
16
|
+
<div class="bulk-vision-table flex flex-col items-center justify-evenly gap-3 md:gap-4 w-full h-full p-4 md:p-6 overflow-y-auto overflow-x-auto">
|
|
17
17
|
<button type="button"
|
|
18
18
|
@click="closeDialog"
|
|
19
19
|
class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white" >
|
|
@@ -22,35 +22,36 @@
|
|
|
22
22
|
</svg>
|
|
23
23
|
</button>
|
|
24
24
|
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
25
|
+
<div v-if="records && props.checkboxes.length" class="w-full overflow-x-auto">
|
|
26
|
+
<VisionTable
|
|
27
|
+
:checkbox="props.checkboxes"
|
|
28
|
+
:records="records"
|
|
29
|
+
:index="0"
|
|
30
|
+
:meta="props.meta"
|
|
31
|
+
:images="images"
|
|
32
|
+
:tableHeaders="tableHeaders"
|
|
33
|
+
:tableColumns="tableColumns"
|
|
34
|
+
:customFieldNames="customFieldNames"
|
|
35
|
+
:tableColumnsIndexes="tableColumnsIndexes"
|
|
36
|
+
:selected="selected"
|
|
37
|
+
:isAiResponseReceivedAnalize="isAiResponseReceivedAnalize"
|
|
38
|
+
:isAiResponseReceivedImage="isAiResponseReceivedImage"
|
|
39
|
+
:primaryKey="primaryKey"
|
|
40
|
+
:openGenerationCarousel="openGenerationCarousel"
|
|
41
|
+
@error="handleTableError"
|
|
42
|
+
/>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="flex w-full flex-col md:flex-row items-stretch md:items-end justify-end gap-3 md:gap-4">
|
|
45
|
+
<div class="h-full text-red-600 font-semibold flex items-center justify-center md:mb-2">
|
|
45
46
|
<p v-if="isError === true">{{ errorMessage }}</p>
|
|
46
47
|
</div>
|
|
47
|
-
<button type="button" class="py-2.5 px-5
|
|
48
|
+
<button type="button" class="w-full md:w-auto py-2.5 px-5 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"
|
|
48
49
|
@click="closeDialog"
|
|
49
50
|
>
|
|
50
51
|
{{'Cancel'}}
|
|
51
52
|
</button>
|
|
52
53
|
<Button
|
|
53
|
-
class="w-64"
|
|
54
|
+
class="w-full md:w-64"
|
|
54
55
|
@click="saveData"
|
|
55
56
|
:disabled="isLoading || checkedCount < 1 || isCriticalError"
|
|
56
57
|
:loader="isLoading"
|
|
@@ -66,7 +67,7 @@
|
|
|
66
67
|
|
|
67
68
|
<script lang="ts" setup>
|
|
68
69
|
import { callAdminForthApi } from '@/utils';
|
|
69
|
-
import { ref, watch } from 'vue'
|
|
70
|
+
import { Ref, ref, watch } from 'vue'
|
|
70
71
|
import { Dialog, Button } from '@/afcl';
|
|
71
72
|
import VisionTable from './visionTable.vue'
|
|
72
73
|
import adminforth from '@/adminforth';
|
|
@@ -131,13 +132,25 @@ const openDialog = async () => {
|
|
|
131
132
|
isLoading.value = true;
|
|
132
133
|
const tasks = [];
|
|
133
134
|
if (props.meta.isFieldsForAnalizeFromImages) {
|
|
134
|
-
tasks.push(
|
|
135
|
+
tasks.push(runAiAction({
|
|
136
|
+
endpoint: 'analyze',
|
|
137
|
+
actionType: 'analyze',
|
|
138
|
+
responseFlag: isAiResponseReceivedAnalize,
|
|
139
|
+
}));
|
|
135
140
|
}
|
|
136
141
|
if (props.meta.isFieldsForAnalizePlain) {
|
|
137
|
-
tasks.push(
|
|
142
|
+
tasks.push(runAiAction({
|
|
143
|
+
endpoint: 'analyze_no_images',
|
|
144
|
+
actionType: 'analyze_no_images',
|
|
145
|
+
responseFlag: isAiResponseReceivedAnalize,
|
|
146
|
+
}));
|
|
138
147
|
}
|
|
139
148
|
if (props.meta.isImageGeneration) {
|
|
140
|
-
tasks.push(
|
|
149
|
+
tasks.push(runAiAction({
|
|
150
|
+
endpoint: 'initial_image_generate',
|
|
151
|
+
actionType: 'generate_images',
|
|
152
|
+
responseFlag: isAiResponseReceivedImage,
|
|
153
|
+
}));
|
|
141
154
|
}
|
|
142
155
|
await Promise.all(tasks);
|
|
143
156
|
isLoading.value = false;
|
|
@@ -160,6 +173,7 @@ const closeDialog = () => {
|
|
|
160
173
|
tableColumnsIndexes.value = [];
|
|
161
174
|
isError.value = false;
|
|
162
175
|
isCriticalError.value = false;
|
|
176
|
+
isImageGenerationError.value = false;
|
|
163
177
|
errorMessage.value = '';
|
|
164
178
|
}
|
|
165
179
|
|
|
@@ -329,111 +343,6 @@ async function convertImages(fieldName, img) {
|
|
|
329
343
|
}
|
|
330
344
|
|
|
331
345
|
|
|
332
|
-
async function analyzeFields() {
|
|
333
|
-
isAiResponseReceivedAnalize.value = props.checkboxes.map(() => false);
|
|
334
|
-
try {
|
|
335
|
-
const res = await callAdminForthApi({
|
|
336
|
-
path: `/plugin/${props.meta.pluginInstanceId}/analyze`,
|
|
337
|
-
method: 'POST',
|
|
338
|
-
body: {
|
|
339
|
-
selectedIds: props.checkboxes,
|
|
340
|
-
},
|
|
341
|
-
});
|
|
342
|
-
|
|
343
|
-
if (res?.error) {
|
|
344
|
-
adminforth.alert({
|
|
345
|
-
message: res.error,
|
|
346
|
-
variant: 'danger',
|
|
347
|
-
timeout: 'unlimited',
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
console.error('Failed to analyze image(s):', res.error);
|
|
351
|
-
isError.value = true;
|
|
352
|
-
//isCriticalError.value = true;
|
|
353
|
-
errorMessage.value = `Failed to fetch analyze image(s). Please, try to re-run the action.`;
|
|
354
|
-
} else {
|
|
355
|
-
res.result.forEach((item, idx) => {
|
|
356
|
-
const pk = selected.value[idx]?.[primaryKey]
|
|
357
|
-
|
|
358
|
-
if (pk) {
|
|
359
|
-
selected.value[idx] = {
|
|
360
|
-
...selected.value[idx],
|
|
361
|
-
...item,
|
|
362
|
-
isChecked: true,
|
|
363
|
-
[primaryKey]: pk
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
})
|
|
367
|
-
}
|
|
368
|
-
} catch (error) {
|
|
369
|
-
adminforth.alert({
|
|
370
|
-
message: error,
|
|
371
|
-
variant: 'danger',
|
|
372
|
-
timeout: 'unlimited',
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
console.error('Failed to analyze image(s):', error);
|
|
376
|
-
isError.value = true;
|
|
377
|
-
//isCriticalError.value = true;
|
|
378
|
-
errorMessage.value = res.error;
|
|
379
|
-
}
|
|
380
|
-
isAiResponseReceivedAnalize.value = props.checkboxes.map(() => true);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
async function analyzeFieldsNoImages() {
|
|
385
|
-
isAiResponseReceivedAnalize.value = props.checkboxes.map(() => false);
|
|
386
|
-
try {
|
|
387
|
-
const res = await callAdminForthApi({
|
|
388
|
-
path: `/plugin/${props.meta.pluginInstanceId}/analyze_no_images`,
|
|
389
|
-
method: 'POST',
|
|
390
|
-
body: {
|
|
391
|
-
selectedIds: props.checkboxes,
|
|
392
|
-
},
|
|
393
|
-
});
|
|
394
|
-
if(res?.error) {
|
|
395
|
-
adminforth.alert({
|
|
396
|
-
message: res.error,
|
|
397
|
-
variant: 'danger',
|
|
398
|
-
timeout: 'unlimited',
|
|
399
|
-
});
|
|
400
|
-
console.error('Failed to analyze fields:', res.error);
|
|
401
|
-
isError.value = true;
|
|
402
|
-
//isCriticalError.value = true;
|
|
403
|
-
errorMessage.value = res.error;
|
|
404
|
-
} else {
|
|
405
|
-
res.result.forEach((item, idx) => {
|
|
406
|
-
const pk = selected.value[idx]?.[primaryKey]
|
|
407
|
-
|
|
408
|
-
if (pk) {
|
|
409
|
-
selected.value[idx] = {
|
|
410
|
-
...selected.value[idx],
|
|
411
|
-
...item,
|
|
412
|
-
isChecked: true,
|
|
413
|
-
[primaryKey]: pk
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
})
|
|
417
|
-
}
|
|
418
|
-
} catch (error) {
|
|
419
|
-
adminforth.alert({
|
|
420
|
-
message: error,
|
|
421
|
-
variant: 'danger',
|
|
422
|
-
timeout: 'unlimited',
|
|
423
|
-
});
|
|
424
|
-
console.error('Failed to analyze fields:', error);
|
|
425
|
-
isError.value = true;
|
|
426
|
-
//isCriticalError.value = true;
|
|
427
|
-
errorMessage.value = `Failed to analyze fields. Please, try to re-run the action.`;
|
|
428
|
-
}
|
|
429
|
-
if(!props.meta.isFieldsForAnalizeFromImages) {
|
|
430
|
-
isAiResponseReceivedAnalize.value = props.checkboxes.map(() => true);
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
346
|
async function saveData() {
|
|
438
347
|
if (!selected.value?.length) {
|
|
439
348
|
adminforth.alert({ message: 'No items selected', variant: 'warning' });
|
|
@@ -496,57 +405,73 @@ async function saveData() {
|
|
|
496
405
|
}
|
|
497
406
|
}
|
|
498
407
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
408
|
+
|
|
409
|
+
async function runAiAction({
|
|
410
|
+
endpoint,
|
|
411
|
+
actionType,
|
|
412
|
+
responseFlag,
|
|
413
|
+
updateOnSuccess = true,
|
|
414
|
+
}: {
|
|
415
|
+
endpoint: string;
|
|
416
|
+
actionType: 'analyze' | 'analyze_no_images' | 'generate_images';
|
|
417
|
+
responseFlag: Ref<boolean[]>;
|
|
418
|
+
updateOnSuccess?: boolean;
|
|
419
|
+
}) {
|
|
420
|
+
let res: any;
|
|
421
|
+
let error: any = null;
|
|
503
422
|
|
|
504
423
|
try {
|
|
424
|
+
responseFlag.value = props.checkboxes.map(() => false);
|
|
425
|
+
|
|
505
426
|
res = await callAdminForthApi({
|
|
506
|
-
path: `/plugin/${props.meta.pluginInstanceId}
|
|
427
|
+
path: `/plugin/${props.meta.pluginInstanceId}/${endpoint}`,
|
|
507
428
|
method: 'POST',
|
|
508
429
|
body: {
|
|
509
430
|
selectedIds: props.checkboxes,
|
|
510
431
|
},
|
|
511
432
|
});
|
|
433
|
+
|
|
434
|
+
if (actionType !== 'analyze_no_images' || !props.meta.isFieldsForAnalizeFromImages) {
|
|
435
|
+
responseFlag.value = props.checkboxes.map(() => true);
|
|
436
|
+
}
|
|
512
437
|
} catch (e) {
|
|
513
|
-
console.error(
|
|
514
|
-
|
|
515
|
-
isImageGenerationError.value = true;
|
|
516
|
-
errorMessage.value = `Failed to generate images. Please, try to re-run the action.`;
|
|
438
|
+
console.error(`Error during ${actionType}:`, e);
|
|
439
|
+
error = `Failed to ${actionType.replace('_', ' ')}. Please, try to re-run the action.`;
|
|
517
440
|
}
|
|
518
|
-
isAiResponseReceivedImage.value = props.checkboxes.map(() => true);
|
|
519
441
|
|
|
520
442
|
if (res?.error) {
|
|
521
443
|
error = res.error;
|
|
522
444
|
}
|
|
523
|
-
if (!res) {
|
|
524
|
-
error =
|
|
525
|
-
isError.value = true;
|
|
526
|
-
isImageGenerationError.value = true;
|
|
527
|
-
errorMessage.value = `Failed to generate images. Please, try to re-run the action.`;
|
|
445
|
+
if (!res && !error) {
|
|
446
|
+
error = `Error: ${actionType} request returned empty response.`;
|
|
528
447
|
}
|
|
529
448
|
|
|
530
|
-
if (error) {
|
|
449
|
+
if (error) {
|
|
531
450
|
adminforth.alert({
|
|
532
451
|
message: error,
|
|
533
452
|
variant: 'danger',
|
|
534
453
|
timeout: 'unlimited',
|
|
535
454
|
});
|
|
536
455
|
isError.value = true;
|
|
537
|
-
|
|
456
|
+
if (actionType === 'generate_images') {
|
|
457
|
+
isImageGenerationError.value = true;
|
|
458
|
+
}
|
|
538
459
|
errorMessage.value = error;
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (updateOnSuccess) {
|
|
464
|
+
res.result.forEach((item: any, idx: number) => {
|
|
465
|
+
const pk = selected.value[idx]?.[primaryKey];
|
|
542
466
|
if (pk) {
|
|
543
467
|
selected.value[idx] = {
|
|
544
468
|
...selected.value[idx],
|
|
545
469
|
...item,
|
|
546
|
-
|
|
547
|
-
|
|
470
|
+
isChecked: true,
|
|
471
|
+
[primaryKey]: pk,
|
|
472
|
+
};
|
|
548
473
|
}
|
|
549
|
-
})
|
|
474
|
+
});
|
|
550
475
|
}
|
|
551
476
|
}
|
|
552
477
|
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
<div v-if="isAiResponseReceivedAnalize[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])] && !isInColumnImage(n)">
|
|
48
48
|
<div v-if="isInColumnEnum(n)">
|
|
49
49
|
<Select
|
|
50
|
+
class="min-w-[150px] "
|
|
50
51
|
:options="convertColumnEnumToSelectOptions(props.meta.columnEnums, n)"
|
|
51
52
|
v-model="selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n]"
|
|
52
53
|
:teleportToTop="true"
|
|
@@ -56,7 +57,7 @@
|
|
|
56
57
|
</div>
|
|
57
58
|
<div v-else-if="typeof selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] === 'string' || typeof selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n] === 'object'">
|
|
58
59
|
<Textarea
|
|
59
|
-
class="w-full h-full"
|
|
60
|
+
class="min-w-[150px] w-full h-full"
|
|
60
61
|
type="text"
|
|
61
62
|
v-model="selected[tableColumnsIndexes.findIndex(el => el[primaryKey] === item[primaryKey])][n]"
|
|
62
63
|
>
|
package/dist/index.js
CHANGED
|
@@ -19,44 +19,28 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
19
19
|
this.totalDuration = 0;
|
|
20
20
|
}
|
|
21
21
|
// Compile Handlebars templates in outputFields using record fields as context
|
|
22
|
-
|
|
22
|
+
compileTemplates(source, record, valueSelector) {
|
|
23
23
|
const compiled = {};
|
|
24
|
-
for (const [key,
|
|
24
|
+
for (const [key, value] of Object.entries(source)) {
|
|
25
|
+
const templateStr = valueSelector(value);
|
|
25
26
|
try {
|
|
26
|
-
const tpl = Handlebars.compile(
|
|
27
|
+
const tpl = Handlebars.compile(templateStr);
|
|
27
28
|
compiled[key] = tpl(record);
|
|
28
29
|
}
|
|
29
30
|
catch (_a) {
|
|
30
|
-
compiled[key] =
|
|
31
|
+
compiled[key] = templateStr;
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
return compiled;
|
|
34
35
|
}
|
|
36
|
+
compileOutputFieldsTemplates(record) {
|
|
37
|
+
return this.compileTemplates(this.options.fillFieldsFromImages, record, v => String(v));
|
|
38
|
+
}
|
|
35
39
|
compileOutputFieldsTemplatesNoImage(record) {
|
|
36
|
-
|
|
37
|
-
for (const [key, templateStr] of Object.entries(this.options.fillPlainFields)) {
|
|
38
|
-
try {
|
|
39
|
-
const tpl = Handlebars.compile(String(templateStr));
|
|
40
|
-
compiled[key] = tpl(record);
|
|
41
|
-
}
|
|
42
|
-
catch (_a) {
|
|
43
|
-
compiled[key] = String(templateStr);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return compiled;
|
|
40
|
+
return this.compileTemplates(this.options.fillPlainFields, record, v => String(v));
|
|
47
41
|
}
|
|
48
42
|
compileGenerationFieldTemplates(record) {
|
|
49
|
-
|
|
50
|
-
for (const key in this.options.generateImages) {
|
|
51
|
-
try {
|
|
52
|
-
const tpl = Handlebars.compile(String(this.options.generateImages[key].prompt));
|
|
53
|
-
compiled[key] = tpl(record);
|
|
54
|
-
}
|
|
55
|
-
catch (_a) {
|
|
56
|
-
compiled[key] = String(this.options.generateImages[key].prompt);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return compiled;
|
|
43
|
+
return this.compileTemplates(this.options.generateImages, record, v => String(v.prompt));
|
|
60
44
|
}
|
|
61
45
|
checkRateLimit(field, fieldNameRateLimit, headers) {
|
|
62
46
|
if (fieldNameRateLimit) {
|
|
@@ -190,7 +174,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
190
174
|
instanceUniqueRepresentation(pluginOptions) {
|
|
191
175
|
// optional method to return unique string representation of plugin instance.
|
|
192
176
|
// Needed if plugin can have multiple instances on one resource
|
|
193
|
-
return
|
|
177
|
+
return `${this.pluginOptions.actionName}`;
|
|
194
178
|
}
|
|
195
179
|
setupEndpoints(server) {
|
|
196
180
|
server.endpoint({
|
|
@@ -261,7 +245,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
261
245
|
Each object must contain the following fields: ${JSON.stringify(compiledOutputFields)} Use the exact field names.
|
|
262
246
|
If it's number field - return only number.`;
|
|
263
247
|
//send prompt to OpenAI and get response
|
|
264
|
-
const { content: chatResponse
|
|
248
|
+
const { content: chatResponse } = yield this.options.textCompleteAdapter.complete(prompt, [], 500);
|
|
265
249
|
const resp = chatResponse.response;
|
|
266
250
|
const topLevelError = chatResponse.error;
|
|
267
251
|
if (topLevelError || (resp === null || resp === void 0 ? void 0 : resp.error)) {
|
|
@@ -451,7 +435,6 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
451
435
|
}
|
|
452
436
|
else {
|
|
453
437
|
generationAdapter = this.options.imageGenerationAdapter;
|
|
454
|
-
``;
|
|
455
438
|
}
|
|
456
439
|
const resp = yield generationAdapter.generate({
|
|
457
440
|
prompt,
|
package/index.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { AdminForthPlugin, Filters } from "adminforth";
|
|
2
|
-
import type { IAdminForth, IHttpServer, AdminForthComponentDeclaration,
|
|
2
|
+
import type { IAdminForth, IHttpServer, AdminForthComponentDeclaration, AdminForthResource } from "adminforth";
|
|
3
3
|
import type { PluginOptions } from './types.js';
|
|
4
|
-
import
|
|
5
|
-
import Handlebars, { compile } from 'handlebars';
|
|
4
|
+
import Handlebars from 'handlebars';
|
|
6
5
|
import { RateLimiter } from "adminforth";
|
|
7
6
|
|
|
8
7
|
|
|
@@ -22,43 +21,34 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
// Compile Handlebars templates in outputFields using record fields as context
|
|
25
|
-
private
|
|
24
|
+
private compileTemplates<T extends Record<string, any>>(
|
|
25
|
+
source: T,
|
|
26
|
+
record: any,
|
|
27
|
+
valueSelector: (value: T[keyof T]) => string
|
|
28
|
+
): Record<string, string> {
|
|
26
29
|
const compiled: Record<string, string> = {};
|
|
27
|
-
for (const [key,
|
|
30
|
+
for (const [key, value] of Object.entries(source)) {
|
|
31
|
+
const templateStr = valueSelector(value);
|
|
28
32
|
try {
|
|
29
|
-
const tpl = Handlebars.compile(
|
|
33
|
+
const tpl = Handlebars.compile(templateStr);
|
|
30
34
|
compiled[key] = tpl(record);
|
|
31
35
|
} catch {
|
|
32
|
-
compiled[key] =
|
|
36
|
+
compiled[key] = templateStr;
|
|
33
37
|
}
|
|
34
38
|
}
|
|
35
39
|
return compiled;
|
|
36
40
|
}
|
|
37
41
|
|
|
38
|
-
private
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
} catch {
|
|
45
|
-
compiled[key] = String(templateStr);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return compiled;
|
|
42
|
+
private compileOutputFieldsTemplates(record: any) {
|
|
43
|
+
return this.compileTemplates(this.options.fillFieldsFromImages, record, v => String(v));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private compileOutputFieldsTemplatesNoImage(record: any) {
|
|
47
|
+
return this.compileTemplates(this.options.fillPlainFields, record, v => String(v));
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
private compileGenerationFieldTemplates(record: any) {
|
|
52
|
-
|
|
53
|
-
for (const key in this.options.generateImages) {
|
|
54
|
-
try {
|
|
55
|
-
const tpl = Handlebars.compile(String(this.options.generateImages[key].prompt));
|
|
56
|
-
compiled[key] = tpl(record);
|
|
57
|
-
} catch {
|
|
58
|
-
compiled[key] = String(this.options.generateImages[key].prompt);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return compiled;
|
|
51
|
+
return this.compileTemplates(this.options.generateImages, record, v => String(v.prompt));
|
|
62
52
|
}
|
|
63
53
|
|
|
64
54
|
private checkRateLimit(field: string,fieldNameRateLimit: string | undefined, headers: Record<string, string | string[] | undefined>): { error?: string } | void {
|
|
@@ -214,7 +204,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
214
204
|
instanceUniqueRepresentation(pluginOptions: any) : string {
|
|
215
205
|
// optional method to return unique string representation of plugin instance.
|
|
216
206
|
// Needed if plugin can have multiple instances on one resource
|
|
217
|
-
return
|
|
207
|
+
return `${this.pluginOptions.actionName}`;
|
|
218
208
|
}
|
|
219
209
|
|
|
220
210
|
setupEndpoints(server: IHttpServer) {
|
|
@@ -294,7 +284,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
294
284
|
Each object must contain the following fields: ${JSON.stringify(compiledOutputFields)} Use the exact field names.
|
|
295
285
|
If it's number field - return only number.`;
|
|
296
286
|
//send prompt to OpenAI and get response
|
|
297
|
-
const { content: chatResponse
|
|
287
|
+
const { content: chatResponse } = await this.options.textCompleteAdapter.complete(prompt, [], 500);
|
|
298
288
|
|
|
299
289
|
const resp: any = (chatResponse as any).response;
|
|
300
290
|
const topLevelError = (chatResponse as any).error;
|
|
@@ -494,7 +484,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
494
484
|
if (this.options.generateImages[key].adapter) {
|
|
495
485
|
generationAdapter = this.options.generateImages[key].adapter;
|
|
496
486
|
} else {
|
|
497
|
-
generationAdapter = this.options.imageGenerationAdapter
|
|
487
|
+
generationAdapter = this.options.imageGenerationAdapter;
|
|
498
488
|
}
|
|
499
489
|
const resp = await generationAdapter.generate(
|
|
500
490
|
{
|