@adminforth/bulk-ai-flow 1.14.5 → 1.15.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/ImageCompare.vue +5 -5
- package/custom/ImageGenerationCarousel.vue +13 -5
- package/custom/VisionAction.vue +183 -26
- package/custom/VisionTable.vue +11 -9
- package/custom/tsconfig.json +14 -3
- package/dist/custom/ImageCompare.vue +5 -5
- package/dist/custom/ImageGenerationCarousel.vue +13 -5
- package/dist/custom/VisionAction.vue +183 -26
- package/dist/custom/VisionTable.vue +11 -9
- package/dist/custom/tsconfig.json +14 -3
- package/dist/index.js +49 -30
- package/index.ts +34 -24
- package/package.json +1 -1
- package/types.ts +12 -2
package/index.ts
CHANGED
|
@@ -25,11 +25,15 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// Compile Handlebars templates in outputFields using record fields as context
|
|
28
|
-
private compileTemplates<T extends Record<string, any>>(
|
|
28
|
+
private async compileTemplates<T extends Record<string, any>>(
|
|
29
29
|
source: T,
|
|
30
30
|
record: any,
|
|
31
31
|
valueSelector: (value: T[keyof T]) => string
|
|
32
|
-
): Record<string, string
|
|
32
|
+
): Promise<Record<string, string>> {
|
|
33
|
+
if (this.options.provideAdditionalContextForRecord) {
|
|
34
|
+
const additionalFields = await this.options.provideAdditionalContextForRecord({ record, adminUser: null, resource: this.resourceConfig });
|
|
35
|
+
record = { ...record, ...additionalFields };
|
|
36
|
+
}
|
|
33
37
|
const compiled: Record<string, string> = {};
|
|
34
38
|
for (const [key, value] of Object.entries(source)) {
|
|
35
39
|
const templateStr = valueSelector(value);
|
|
@@ -43,16 +47,16 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
43
47
|
return compiled;
|
|
44
48
|
}
|
|
45
49
|
|
|
46
|
-
private compileOutputFieldsTemplates(record: any) {
|
|
47
|
-
return this.compileTemplates(this.options.fillFieldsFromImages, record, v => String(v));
|
|
50
|
+
private async compileOutputFieldsTemplates(record: any, customPrompt? : string) {
|
|
51
|
+
return await this.compileTemplates(customPrompt ? JSON.parse(customPrompt) :this.options.fillFieldsFromImages, record, v => String(v));
|
|
48
52
|
}
|
|
49
53
|
|
|
50
|
-
private compileOutputFieldsTemplatesNoImage(record: any) {
|
|
51
|
-
return this.compileTemplates(this.options.fillPlainFields, record, v => String(v));
|
|
54
|
+
private async compileOutputFieldsTemplatesNoImage(record: any, customPrompt? : string) {
|
|
55
|
+
return await this.compileTemplates(customPrompt ? JSON.parse(customPrompt) : this.options.fillPlainFields, record, v => String(v));
|
|
52
56
|
}
|
|
53
57
|
|
|
54
|
-
private compileGenerationFieldTemplates(record: any) {
|
|
55
|
-
return this.compileTemplates(this.options.generateImages, record, v => String(v.prompt));
|
|
58
|
+
private async compileGenerationFieldTemplates(record: any, customPrompt? : string) {
|
|
59
|
+
return await this.compileTemplates(customPrompt ? JSON.parse(customPrompt) : this.options.generateImages, record, v => String(customPrompt ? v : v.prompt));
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
private async checkRateLimit(field: string, fieldNameRateLimit: string | undefined, headers: Record<string, string | string[] | undefined>): Promise<void | { error?: string; }> {
|
|
@@ -72,7 +76,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
72
76
|
}
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
private async analyze_image(jobId: string, recordId: string, adminUser: any, headers: Record<string, string | string[] | undefined
|
|
79
|
+
private async analyze_image(jobId: string, recordId: string, adminUser: any, headers: Record<string, string | string[] | undefined>, customPrompt? : string) {
|
|
76
80
|
const selectedId = recordId;
|
|
77
81
|
let isError = false;
|
|
78
82
|
// Fetch the record using the provided ID
|
|
@@ -102,7 +106,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
102
106
|
return { ok: false, error: 'One of the image URLs is not valid' };
|
|
103
107
|
}
|
|
104
108
|
//create prompt for OpenAI
|
|
105
|
-
const compiledOutputFields = this.compileOutputFieldsTemplates(record);
|
|
109
|
+
const compiledOutputFields = await this.compileOutputFieldsTemplates(record, customPrompt);
|
|
106
110
|
const prompt = `Analyze the following image(s) and return a single JSON in format like: {'param1': 'value1', 'param2': 'value2'}.
|
|
107
111
|
Do NOT return array of objects. Do NOT include any Markdown, code blocks, explanations, or extra text. Only return valid JSON.
|
|
108
112
|
Each object must contain the following fields: ${JSON.stringify(compiledOutputFields)} Use the exact field names. If it's number field - return only number.
|
|
@@ -148,7 +152,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
148
152
|
|
|
149
153
|
}
|
|
150
154
|
|
|
151
|
-
private async analyzeNoImages(jobId: string, recordId: string, adminUser: any, headers: Record<string, string | string[] | undefined
|
|
155
|
+
private async analyzeNoImages(jobId: string, recordId: string, adminUser: any, headers: Record<string, string | string[] | undefined>, customPrompt? : string) {
|
|
152
156
|
const selectedId = recordId;
|
|
153
157
|
let isError = false;
|
|
154
158
|
if (STUB_MODE) {
|
|
@@ -159,7 +163,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
159
163
|
const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
|
|
160
164
|
const record = await this.adminforth.resource(this.resourceConfig.resourceId).get( [Filters.EQ(primaryKeyColumn.name, selectedId)] );
|
|
161
165
|
|
|
162
|
-
const compiledOutputFields = this.compileOutputFieldsTemplatesNoImage(record);
|
|
166
|
+
const compiledOutputFields = await this.compileOutputFieldsTemplatesNoImage(record, customPrompt);
|
|
163
167
|
const prompt = `Analyze the following fields and return a single JSON in format like: {'param1': 'value1', 'param2': 'value2'}.
|
|
164
168
|
Do NOT return array of objects. Do NOT include any Markdown, code blocks, explanations, or extra text. Only return valid JSON.
|
|
165
169
|
Each object must contain the following fields: ${JSON.stringify(compiledOutputFields)} Use the exact field names.
|
|
@@ -188,7 +192,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
188
192
|
}
|
|
189
193
|
}
|
|
190
194
|
|
|
191
|
-
private async initialImageGenerate(jobId: string, recordId: string, adminUser: any, headers: Record<string, string | string[] | undefined
|
|
195
|
+
private async initialImageGenerate(jobId: string, recordId: string, adminUser: any, headers: Record<string, string | string[] | undefined>, customPrompt? : string) {
|
|
192
196
|
const selectedId = recordId;
|
|
193
197
|
let isError = false;
|
|
194
198
|
const start = +new Date();
|
|
@@ -208,7 +212,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
208
212
|
}
|
|
209
213
|
}
|
|
210
214
|
const fieldTasks = Object.keys(this.options?.generateImages || {}).map(async (key) => {
|
|
211
|
-
const prompt = this.compileGenerationFieldTemplates(record)[key];
|
|
215
|
+
const prompt = (await this.compileGenerationFieldTemplates(record, customPrompt))[key];
|
|
212
216
|
let images;
|
|
213
217
|
if (this.options.attachFiles && attachmentFiles.length === 0) {
|
|
214
218
|
isError = true;
|
|
@@ -391,7 +395,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
391
395
|
};
|
|
392
396
|
|
|
393
397
|
const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
|
|
394
|
-
|
|
398
|
+
|
|
395
399
|
const pageInjection = {
|
|
396
400
|
file: this.componentPath('VisionAction.vue'),
|
|
397
401
|
meta: {
|
|
@@ -413,6 +417,12 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
413
417
|
fillPlainFields: this.options.refreshRates?.fillPlainFields || 1_000,
|
|
414
418
|
generateImages: this.options.refreshRates?.generateImages || 5_000,
|
|
415
419
|
regenerateImages: this.options.refreshRates?.regenerateImages || 5_000,
|
|
420
|
+
},
|
|
421
|
+
askConfirmationBeforeGenerating: this.options.askConfirmationBeforeGenerating || false,
|
|
422
|
+
generationPrompts: {
|
|
423
|
+
plainFieldsPrompts: this.options.fillPlainFields || {},
|
|
424
|
+
imageFieldsPrompts: this.options.fillFieldsFromImages || {},
|
|
425
|
+
imageGenerationPrompts: this.options.generateImages || {},
|
|
416
426
|
}
|
|
417
427
|
}
|
|
418
428
|
}
|
|
@@ -489,7 +499,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
489
499
|
}
|
|
490
500
|
}
|
|
491
501
|
}
|
|
492
|
-
if (this.options.fillFieldsFromImages || this.options.fillPlainFields || this.options.generateImages) {
|
|
502
|
+
if ((this.options.fillFieldsFromImages || this.options.fillPlainFields || this.options.generateImages) && !this.options.provideAdditionalContextForRecord) {
|
|
493
503
|
let matches: string[] = [];
|
|
494
504
|
const regex = /{{(.*?)}}/g;
|
|
495
505
|
|
|
@@ -652,12 +662,13 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
652
662
|
|
|
653
663
|
server.endpoint({
|
|
654
664
|
method: 'POST',
|
|
655
|
-
path: `/plugin/${this.pluginInstanceId}/
|
|
665
|
+
path: `/plugin/${this.pluginInstanceId}/get_image_generation_prompts`,
|
|
656
666
|
handler: async ({ body, headers }) => {
|
|
657
667
|
const Id = body.recordId || [];
|
|
668
|
+
const customPrompt = body.customPrompt || null;
|
|
658
669
|
const record = await this.adminforth.resource(this.resourceConfig.resourceId).get([Filters.EQ(this.resourceConfig.columns.find(c => c.primaryKey)?.name, Id)]);
|
|
659
|
-
const compiledGenerationOptions = this.compileGenerationFieldTemplates(record);
|
|
660
|
-
return
|
|
670
|
+
const compiledGenerationOptions = await this.compileGenerationFieldTemplates(record, JSON.stringify({"prompt": customPrompt}));
|
|
671
|
+
return compiledGenerationOptions;
|
|
661
672
|
}
|
|
662
673
|
});
|
|
663
674
|
|
|
@@ -679,10 +690,9 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
679
690
|
method: 'POST',
|
|
680
691
|
path: `/plugin/${this.pluginInstanceId}/create-job`,
|
|
681
692
|
handler: async ({ body, adminUser, headers }) => {
|
|
682
|
-
const { actionType, recordId } = body;
|
|
693
|
+
const { actionType, recordId, customPrompt } = body;
|
|
683
694
|
const jobId = randomUUID();
|
|
684
695
|
jobs.set(jobId, { status: "in_progress" });
|
|
685
|
-
|
|
686
696
|
if (!actionType) {
|
|
687
697
|
jobs.set(jobId, { status: "failed", error: "Missing action type" });
|
|
688
698
|
//return { error: "Missing action type" };
|
|
@@ -693,13 +703,13 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
|
|
|
693
703
|
} else {
|
|
694
704
|
switch(actionType) {
|
|
695
705
|
case 'generate_images':
|
|
696
|
-
this.initialImageGenerate(jobId, recordId, adminUser, headers);
|
|
706
|
+
this.initialImageGenerate(jobId, recordId, adminUser, headers, customPrompt);
|
|
697
707
|
break;
|
|
698
708
|
case 'analyze_no_images':
|
|
699
|
-
this.analyzeNoImages(jobId, recordId, adminUser, headers);
|
|
709
|
+
this.analyzeNoImages(jobId, recordId, adminUser, headers, customPrompt);
|
|
700
710
|
break;
|
|
701
711
|
case 'analyze':
|
|
702
|
-
this.analyze_image(jobId, recordId, adminUser, headers);
|
|
712
|
+
this.analyze_image(jobId, recordId, adminUser, headers, customPrompt);
|
|
703
713
|
break;
|
|
704
714
|
case 'regenerate_images':
|
|
705
715
|
if (!body.prompt || !body.fieldName) {
|
package/package.json
CHANGED
package/types.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { ImageVisionAdapter, ImageGenerationAdapter, CompletionAdapter } from "adminforth";
|
|
2
|
-
|
|
1
|
+
import AdminForth, { ImageVisionAdapter, ImageGenerationAdapter, CompletionAdapter } from "adminforth";
|
|
3
2
|
|
|
4
3
|
export interface PluginOptions {
|
|
5
4
|
/**
|
|
@@ -109,4 +108,15 @@ export interface PluginOptions {
|
|
|
109
108
|
ok: boolean;
|
|
110
109
|
error?: undefined;
|
|
111
110
|
}>
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Custom message for the context shown to the user when performing the action
|
|
114
|
+
*/
|
|
115
|
+
provideAdditionalContextForRecord?: ({record, adminUser, resource}: {
|
|
116
|
+
record: any;
|
|
117
|
+
adminUser: any;
|
|
118
|
+
resource: any;
|
|
119
|
+
}) => Record<string, any> | Promise<Record<string, any>>;
|
|
120
|
+
|
|
121
|
+
askConfirmationBeforeGenerating?: boolean;
|
|
112
122
|
}
|