Skip to content

Commit f3f7822

Browse files
committed
fix: add validation config after discover and rename components
1 parent 3dd78c8 commit f3f7822

File tree

4 files changed

+71
-96
lines changed

4 files changed

+71
-96
lines changed

custom/imageGenerationCarousel.vue renamed to custom/ImageGenerationCarousel.vue

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,6 @@
175175
</div>
176176
</div>
177177
</div>
178-
179-
180-
181-
182178
</template>
183179

184180
<script setup lang="ts">

custom/visionAction.vue renamed to custom/VisionAction.vue

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
<VisionTable
2626
:checkbox="props.checkboxes"
2727
:records="records"
28-
:index="0"
2928
:meta="props.meta"
3029
:images="images"
3130
:tableHeaders="tableHeaders"
@@ -68,13 +67,11 @@
6867
import { callAdminForthApi } from '@/utils';
6968
import { Ref, ref, watch } from 'vue'
7069
import { Dialog, Button } from '@/afcl';
71-
import VisionTable from './visionTable.vue'
70+
import VisionTable from './VisionTable.vue'
7271
import adminforth from '@/adminforth';
7372
import { useI18n } from 'vue-i18n';
74-
import { useRoute } from 'vue-router';
7573
import { AdminUser, type AdminForthResourceCommon } from '@/types';
7674
77-
const route = useRoute();
7875
const { t } = useI18n();
7976
8077
const props = defineProps<{
@@ -270,7 +267,6 @@ async function getRecords() {
270267
console.error('Failed to get records:', error);
271268
isError.value = true;
272269
errorMessage.value = `Failed to fetch records. Please, try to re-run the action.`;
273-
// Handle error appropriately
274270
}
275271
}
276272
@@ -288,7 +284,6 @@ async function getImages() {
288284
console.error('Failed to get images:', error);
289285
isError.value = true;
290286
errorMessage.value = `Failed to fetch images. Please, try to re-run the action.`;
291-
// Handle error appropriately
292287
}
293288
}
294289

custom/visionTable.vue renamed to custom/VisionTable.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@
119119
import { ref, nextTick, watch } from 'vue'
120120
import mediumZoom from 'medium-zoom'
121121
import { Select, Input, Textarea, Table, Checkbox, Skeleton, Toggle } from '@/afcl'
122-
import GenerationCarousel from './imageGenerationCarousel.vue'
122+
import GenerationCarousel from './ImageGenerationCarousel.vue'
123123
124124
const props = defineProps<{
125125
meta: any,

index.ts

Lines changed: 69 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -73,58 +73,30 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
7373
const columns = this.resourceConfig.columns;
7474
let columnEnums = [];
7575
if (this.options.fillFieldsFromImages) {
76-
if (!this.options.attachFiles) {
77-
throw new Error('⚠️ attachFiles function must be provided in options when fillFieldsFromImages is used');
78-
}
79-
if (!this.options.visionAdapter) {
80-
throw new Error('⚠️ visionAdapter must be provided in options when fillFieldsFromImages is used');
81-
}
82-
8376
for (const [key, value] of Object.entries((this.options.fillFieldsFromImages ))) {
8477
const column = columns.find(c => c.name.toLowerCase() === key.toLowerCase());
85-
if (column) {
86-
if(column.enum){
87-
(this.options.fillFieldsFromImages as any)[key] = `${value} Select ${key} from the list (USE ONLY VALUE FIELD. USE ONLY VALUES FROM THIS LIST): ${JSON.stringify(column.enum)}`;
88-
columnEnums.push({
89-
name: key,
90-
enum: column.enum,
91-
});
92-
}
93-
} else {
94-
throw new Error(`⚠️ No column found for key "${key}"`);
78+
if (column && column.enum) {
79+
(this.options.fillFieldsFromImages as any)[key] = `${value} Select ${key} from the list (USE ONLY VALUE FIELD. USE ONLY VALUES FROM THIS LIST): ${JSON.stringify(column.enum)}`;
80+
columnEnums.push({
81+
name: key,
82+
enum: column.enum,
83+
});
9584
}
9685
}
9786
}
9887

9988
if (this.options.fillPlainFields) {
100-
if (!this.options.textCompleteAdapter) {
101-
throw new Error('⚠️ textCompleteAdapter must be provided in options when fillPlainFields is used');
102-
}
103-
10489
for (const [key, value] of Object.entries((this.options.fillPlainFields))) {
10590
const column = columns.find(c => c.name.toLowerCase() === key.toLowerCase());
106-
if (column) {
107-
if(column.enum){
108-
(this.options.fillPlainFields as any)[key] = `${value} Select ${key} from the list (USE ONLY VALUE FIELD. USE ONLY VALUES FROM THIS LIST): ${JSON.stringify(column.enum)}`;
109-
columnEnums.push({
110-
name: key,
111-
enum: column.enum,
112-
});
113-
}
114-
} else {
115-
throw new Error(`⚠️ No column found for key "${key}"`);
116-
}
117-
}
118-
}
119-
120-
if (this.options.generateImages && !this.options.imageGenerationAdapter) {
121-
for (const [key, value] of Object.entries(this.options.generateImages)) {
122-
if (!this.options.generateImages[key].adapter) {
123-
throw new Error(`⚠️ No image generation adapter found for key "${key}"`);
91+
if (column && column.enum) {
92+
(this.options.fillPlainFields as any)[key] = `${value} Select ${key} from the list (USE ONLY VALUE FIELD. USE ONLY VALUES FROM THIS LIST): ${JSON.stringify(column.enum)}`;
93+
columnEnums.push({
94+
name: key,
95+
enum: column.enum,
96+
});
12497
}
12598
}
126-
}
127-
99+
}
128100

129101
const outputImageFields = [];
130102
if (this.options.generateImages) {
@@ -136,25 +108,13 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
136108
//check if Upload plugin is installed on all attachment fields
137109
if (this.options.generateImages) {
138110
for (const [key, value] of Object.entries(this.options.generateImages)) {
139-
const column = columns.find(c => c.name.toLowerCase() === key.toLowerCase());
140-
if (!column) {
141-
throw new Error(`⚠️ No column found for key "${key}"`);
142-
}
143111
const plugin = adminforth.activatedPlugins.find(p =>
144112
p.resourceConfig!.resourceId === this.resourceConfig.resourceId &&
145113
p.pluginOptions.pathColumnName === key
146114
);
147-
if (!plugin) {
148-
throw new Error(`Plugin for attachment field '${key}' not found in resource '${this.resourceConfig.resourceId}', please check if Upload Plugin is installed on the field ${key}`);
115+
if (plugin && plugin.pluginOptions.storageAdapter.objectCanBeAccesedPublicly()) {
116+
outputImagesPluginInstanceIds[key] = plugin.pluginInstanceId;
149117
}
150-
if (!plugin.pluginOptions.storageAdapter.objectCanBeAccesedPublicly()) {
151-
throw new Error(`Upload Plugin for attachment field '${key}' in resource '${this.resourceConfig.resourceId}'
152-
uses adapter which is not configured to store objects in public way, so it will produce only signed private URLs which can not be used in HTML text of blog posts.
153-
Please configure adapter in such way that it will store objects publicly (e.g. for S3 use 'public-read' ACL).
154-
`);
155-
}
156-
157-
outputImagesPluginInstanceIds[key] = plugin.pluginInstanceId;
158118
}
159119
}
160120

@@ -168,7 +128,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
168128
const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
169129

170130
const pageInjection = {
171-
file: this.componentPath('visionAction.vue'),
131+
file: this.componentPath('VisionAction.vue'),
172132
meta: {
173133
pluginInstanceId: this.pluginInstanceId,
174134
outputFields: outputFields,
@@ -199,18 +159,65 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
199159
}
200160

201161
validateConfigAfterDiscover(adminforth: IAdminForth, resourceConfig: AdminForthResource) {
202-
// optional method where you can safely check field types after database discovery was performed
162+
const columns = this.resourceConfig.columns;
163+
if (this.options.fillFieldsFromImages) {
164+
if (!this.options.attachFiles) {
165+
throw new Error('⚠️ attachFiles function must be provided when fillFieldsFromImages is used');
166+
}
167+
if (!this.options.visionAdapter) {
168+
throw new Error('⚠️ visionAdapter must be provided when fillFieldsFromImages is used');
169+
}
170+
for (const key of Object.keys(this.options.fillFieldsFromImages)) {
171+
const column = columns.find(c => c.name.toLowerCase() === key.toLowerCase());
172+
if (!column) {
173+
throw new Error(`⚠️ No column found for key "${key}"`);
174+
}
175+
}
176+
}
177+
if (this.options.fillPlainFields) {
178+
if (!this.options.textCompleteAdapter) {
179+
throw new Error('⚠️ textCompleteAdapter must be provided when fillPlainFields is used');
180+
}
181+
for (const key of Object.keys(this.options.fillPlainFields)) {
182+
const column = columns.find(c => c.name.toLowerCase() === key.toLowerCase());
183+
if (!column) {
184+
throw new Error(`⚠️ No column found for key "${key}"`);
185+
}
186+
}
187+
}
188+
if (this.options.generateImages) {
189+
for (const key of Object.keys(this.options.generateImages)) {
190+
const column = columns.find(c => c.name.toLowerCase() === key.toLowerCase());
191+
if (!column) {
192+
throw new Error(`⚠️ No column found for key "${key}"`);
193+
}
194+
const perKeyAdapter = this.options.generateImages[key].adapter;
195+
if (!perKeyAdapter && !this.options.imageGenerationAdapter) {
196+
throw new Error(`⚠️ No image generation adapter provided for key "${key}"`);
197+
}
198+
199+
const plugin = adminforth.activatedPlugins.find(p =>
200+
p.resourceConfig!.resourceId === this.resourceConfig.resourceId &&
201+
p.pluginOptions.pathColumnName === key
202+
);
203+
if (!plugin) {
204+
throw new Error(`Plugin for attachment field '${key}' not found in resource '${this.resourceConfig.resourceId}', please check if Upload Plugin is installed on the field ${key}`);
205+
}
206+
if (!plugin.pluginOptions.storageAdapter.objectCanBeAccesedPublicly()) {
207+
throw new Error(`Upload Plugin for attachment field '${key}' in resource '${this.resourceConfig.resourceId}'
208+
uses adapter which is not configured to store objects in public way, so it will produce only signed private URLs which can not be used in HTML text of blog posts.
209+
Please configure adapter in such way that it will store objects publicly (e.g. for S3 use 'public-read' ACL).
210+
`);
211+
}
212+
}
213+
}
203214
}
204215

205216
instanceUniqueRepresentation(pluginOptions: any) : string {
206-
// optional method to return unique string representation of plugin instance.
207-
// Needed if plugin can have multiple instances on one resource
208217
return `${this.pluginOptions.actionName}`;
209218
}
210219

211220
setupEndpoints(server: IHttpServer) {
212-
213-
214221
server.endpoint({
215222
method: 'POST',
216223
path: `/plugin/${this.pluginInstanceId}/analyze`,
@@ -224,7 +231,7 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
224231
const tasks = selectedIds.map(async (ID) => {
225232
// Fetch the record using the provided ID
226233
const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
227-
const record = await this.adminforth.resource(this.resourceConfig.resourceId).get( [Filters.EQ(primaryKeyColumn.name, ID)] );
234+
const record = await this.adminforth.resource(this.resourceConfig.resourceId).get([Filters.EQ(primaryKeyColumn.name, ID)] );
228235

229236
//recieve image URLs to analyze
230237
const attachmentFiles = await this.options.attachFiles({ record: record });
@@ -274,26 +281,20 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
274281
}
275282
}
276283
const tasks = selectedIds.map(async (ID) => {
277-
// Fetch the record using the provided ID
278284
const primaryKeyColumn = this.resourceConfig.columns.find((col) => col.primaryKey);
279285
const record = await this.adminforth.resource(this.resourceConfig.resourceId).get( [Filters.EQ(primaryKeyColumn.name, ID)] );
280286

281-
//create prompt for OpenAI
282287
const compiledOutputFields = this.compileOutputFieldsTemplatesNoImage(record);
283288
const prompt = `Analyze the following fields and return a single JSON in format like: {'param1': 'value1', 'param2': 'value2'}.
284289
Do NOT return array of objects. Do NOT include any Markdown, code blocks, explanations, or extra text. Only return valid JSON.
285290
Each object must contain the following fields: ${JSON.stringify(compiledOutputFields)} Use the exact field names.
286291
If it's number field - return only number.`;
287-
//send prompt to OpenAI and get response
288292
const { content: chatResponse } = await this.options.textCompleteAdapter.complete(prompt, [], 500);
289-
290293
const resp: any = (chatResponse as any).response;
291294
const topLevelError = (chatResponse as any).error;
292295
if (topLevelError || resp?.error) {
293296
throw new Error(`ERROR: ${JSON.stringify(topLevelError || resp?.error)}`);
294297
}
295-
296-
//parse response and update record
297298
const resData = JSON.parse(chatResponse);
298299

299300
return resData;
@@ -304,8 +305,6 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
304305
return { result };
305306
}
306307
});
307-
308-
309308
server.endpoint({
310309
method: 'POST',
311310
path: `/plugin/${this.pluginInstanceId}/get_records`,
@@ -321,8 +320,6 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
321320
};
322321
}
323322
});
324-
325-
326323
server.endpoint({
327324
method: 'POST',
328325
path: `/plugin/${this.pluginInstanceId}/get_images`,
@@ -340,8 +337,6 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
340337
};
341338
}
342339
});
343-
344-
345340
server.endpoint({
346341
method: 'POST',
347342
path: `/plugin/${this.pluginInstanceId}/update_fields`,
@@ -396,8 +391,6 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
396391
}
397392
}
398393
});
399-
400-
401394
server.endpoint({
402395
method: 'POST',
403396
path: `/plugin/${this.pluginInstanceId}/regenerate_images`,
@@ -449,8 +442,6 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
449442
return { images };
450443
}
451444
});
452-
453-
454445
server.endpoint({
455446
method: 'POST',
456447
path: `/plugin/${this.pluginInstanceId}/initial_image_generate`,
@@ -518,8 +509,6 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
518509
return { result };
519510
}
520511
});
521-
522-
523512
server.endpoint({
524513
method: 'POST',
525514
path: `/plugin/${this.pluginInstanceId}/get_generation_prompts`,
@@ -530,8 +519,6 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
530519
return { generationOptions: compiledGenerationOptions };
531520
}
532521
});
533-
534-
535522
server.endpoint({
536523
method: 'GET',
537524
path: `/plugin/${this.pluginInstanceId}/averageDuration`,
@@ -543,8 +530,5 @@ export default class BulkAiFlowPlugin extends AdminForthPlugin {
543530
};
544531
}
545532
});
546-
547-
548-
549533
}
550534
}

0 commit comments

Comments
 (0)