Skip to content

Commit e81b0c9

Browse files
committed
Publish as AI labeling block
1 parent 3a2da75 commit e81b0c9

File tree

6 files changed

+74
-83
lines changed

6 files changed

+74
-83
lines changed

Diff for: README.md

+47-26
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,66 @@
1-
# Validate Object Detection Datasets Using GPT-4o
1+
# AI labeling block: Bounding box validation Using GPT-4o
22

3-
Let GPT-4o look at every image in your object detection dataset and check against up to three validation prompts you provide. If images are not compliant they will be disabled and reasoning will be put into the metadata. The block passes each image's bounding boxes and labels to GPT-4o so you can for example check if "The bounding boxes and labels do not correspond to to the objects in the image" among other things.
3+
Let GPT-4o look at every image in your object detection dataset and check against a validation prompt you provide. If images are not compliant they will be disabled and reasoning will be put into the metadata. The block passes each image's bounding boxes and labels to GPT-4o so you can for example check if "The bounding boxes and labels do not correspond to to the objects in the image" among other things.
44

5-
You must pass an OPENAI API key either in the field below or via a secret which you can add from the Custom Blocks->Transformation page in your org with the name OPENAI_API_KEY.
5+
![Demo](images/demo.png)
66

7-
![image](https://github.com/user-attachments/assets/47544b24-f16f-4a84-ac7b-53ca9159e581)
8-
## How to run (Edge Impulse) (Enterprise Only)
7+
## Use this from Edge Impulse
98

10-
1. Go to an Enterprise project, upload an Object Detection dataset which you wish to validatae
11-
2. Choose **Data acquisition->Data Sources->Add new data source**.
12-
3. Select Transformation Block and the 'Validate Object Detection Datasets Using GPT-4o' block, fill in your prompts and and run the block.
9+
If you just want to use GPT-4o as a data validation tool in your Edge Impulse project you don't need this repo. Just go to any project, select **Data acquisition > AI labeling**, choose **Bounding box validation Using GPT-4o**.
1310

14-
> You need an OPENAI API Key to run the GPT4o model
11+
> You'll need an OpenAI API Key, see [OpenAI Platform > API Keys](https://platform.openai.com/api-keys).
1512
16-
4. Any items which are invalid will be disabled. Reasoning will be provided in the metadata for each data item
17-
![image](https://github.com/user-attachments/assets/5c042831-4301-46e6-8431-f209f09f1694)
13+
## Developing your own block
1814

15+
You can use this repository to develop your own block that uses GPT-4o (or some other LLM) to help you do data curation (or other tasks).
1916

20-
### Customizing this repository (enterprise only)
17+
1. Create a new Edge Impulse project, and add some images.
18+
2. Create a file called `ids.json` and add the IDs of the samples you want to label. You can find the sample ID by clicking the 'expand' button on **Data acquisiton**.
2119

22-
You can modify this repository and push it as a new custom transformation block.
20+
![Finding IDs](images/find_ids.png)
2321

24-
1. Install the [Edge Impulse CLI](https://docs.edgeimpulse.com/docs/tools/edge-impulse-cli).
25-
2. Open a command prompt or terminal, and navigate to this folder.
26-
3. Create a new transformation block:
22+
Add these IDs to the `ids.json` file as an array of numbers, e.g.:
2723

24+
```json
25+
[1299267659, 1299267609, 1299267606]
2826
```
29-
$ edge-impulse-blocks init
3027

31-
? Choose a type of block: Transformation block
32-
? Choose an option: Create a new block
33-
? Enter the name of your block: Custom Validate Object Detection Datasets Using GPT-4o
34-
? Enter the description of your block: Use GPT4o to validate a dataset
35-
? What type of data does this block operate on? Standalone (runs the container, but no files / data items passed in)
36-
? Which buckets do you want to mount into this block (will be mounted under /mnt/s3fs/BUCKET_NAME, you can change these mount points in the St
37-
udio)?
38-
? Would you like to download and load the example repository? no
28+
3. Load your API keys (both Edge Impulse and OpenAI):
29+
3930
```
31+
export OPENAI_API_KEY=sk-M...
32+
export EI_PROJECT_API_KEY=ei_44...
33+
```
34+
35+
> You can find your OpenAI API key on the [OpenAI API Keys](https://platform.openai.com/api-keys) page. You can find your Edge Impulse API Key via **Dashboard > Keys**.
4036

41-
4. Push the block:
37+
4. Install Node.js 20.
38+
5. Build and run this project to label your data:
4239

4340
```
41+
npm run build
42+
node build/llm-validation.js \
43+
--validation-prompt "- The bounding boxes and labels do not correspond to to the objects in the image\n- The image is not clear enough to determine the objects in the image" \
44+
--concurrency 10 \
45+
--data-ids-file ids.json
46+
```
47+
48+
6. Afterwards you'll have labeled data in your project.
49+
50+
### Pushing block to Edge Impulse (enterprise only)
51+
52+
If you've modified this block, you can push it back to Edge Impulse so it's available to everyone in your organization.
53+
54+
1. Update `parameters.json` to update the name and description of your block.
55+
2. Initialize and push the block:
56+
57+
```
58+
$ edge-impulse-blocks init
4459
$ edge-impulse-blocks push
4560
```
61+
62+
3. Afterwards, you can run your block through **Data acquisition > AI labeling** in any Edge Impulse project.
63+
64+
### Proposed changes
65+
66+
AI labeling blocks should be able to run in 'preview' mode (triggered when you click *Label preview data* in the Studio) - where changes are _staged_ but not directly applied. If this is the case `--propose-actions <job-id>` is passed into your block. When you see this flag you should not apply changes directly (e.g. via `api.rawData.editLabel`) but rather use the `setSampleProposedChanges` API. Search for this API in [llm-validation.ts](llm-validation.ts) to see how this should be used.

Diff for: images/demo.png

1.32 MB
Loading

Diff for: images/find_ids.png

36.4 KB
Loading

Diff for: llm-validation.ts

+15-21
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,9 @@ program
2727
.description('Label using an LLM ' + packageVersion)
2828
.version(packageVersion)
2929

30-
.requiredOption('--validation1 <prompt>',
30+
.requiredOption('--validation-prompt <prompt>',
3131
`Disable the sample if this prompt is true` +
32-
`E.g. "The bounding boxes and labels do not correspond to to the objects in the image" `)
33-
.requiredOption('--validation2 <prompt>',
34-
`Disable the sample if this prompt is true` +
35-
`E.g. "The bounding boxes and labels do not correspond to to the objects in the image" `)
36-
.requiredOption('--validation3 <prompt>',
37-
`Disable the sample if this prompt is true` +
38-
`E.g. "The bounding boxes and labels do not correspond to to the objects in the image" `)
32+
`E.g. "- The bounding boxes and labels do not correspond to to the objects in the image" `)
3933
.option('--limit <n>', `Max number of samples to process`)
4034
.option('--image-quality <quality>', 'Quality of the image to send to GPT. Either "auto", "low" or "high" (default "auto")')
4135
.option('--concurrency <n>', `Concurrency (default: 1)`)
@@ -47,9 +41,10 @@ program
4741

4842
const api = new EdgeImpulseApi({ endpoint: API_URL });
4943

50-
const validation1Argv = <string>program.validation1;
51-
const validation2Argv = <string>program.validation2;
52-
const validation3Argv = <string>program.validation3;
44+
// the replacement looks weird; but if calling this from CLI like
45+
// "--prompt 'test\nanother line'" we'll get this still escaped
46+
// (you could use $'test\nanotherline' but we won't do that in the Edge Impulse backend)
47+
const validationPromptArgv = (<string>program.validationPrompt).replaceAll('\\n', '\n');
5348
const disableLabelsArgv = ["invalid"];
5449
const imageQualityArgv = (<'auto' | 'low' | 'high'>program.imageQuality) || 'auto';
5550
const limitArgv = program.limit ? Number(program.limit) : undefined;
@@ -100,9 +95,11 @@ if (dataIdsFile) {
10095
const project = (await api.projects.listProjects()).projects[0];
10196

10297
console.log(`Validating data for "${project.owner} / ${project.name}"`);
103-
console.log(` Validation1: "${validation1Argv}"`);
104-
console.log(` Validation2: "${validation2Argv}"`);
105-
console.log(` Validation3: "${validation3Argv}"`);
98+
console.log(` Prompt:`);
99+
for (let prompt of validationPromptArgv.split('\n')) {
100+
if (!prompt.trim()) continue;
101+
console.log(` ${prompt.trim()}`);
102+
}
106103
console.log(` Image quality: ${imageQualityArgv}`);
107104
console.log(` Limit no. of samples to label to: ${typeof limitArgv === 'number' ? limitArgv.toLocaleString() : 'No limit'}`);
108105
console.log(` Concurrency: ${concurrencyArgv}`);
@@ -181,13 +178,11 @@ if (dataIdsFile) {
181178
content: [{
182179
type: 'text',
183180
text: `The following image is from a dataset with these possible labels: \`${Array.from(uniqueLabels).join(', ')}\`. ` +
184-
`This image has labeled bounding boxes consisting of: \`${formattedBoundingBoxes}\`. ` +
185-
`Respond with \"invalid\" if:
186-
- \`${validation1Argv}\`
187-
- \`${validation2Argv}\`
188-
- \`${validation3Argv}\`
181+
`This image has labeled bounding boxes consisting of: \`${formattedBoundingBoxes}\`. ` +
182+
`Respond with "invalid" if:
183+
${validationPromptArgv}
189184
190-
Otherwise respond with \"valid\".`,
185+
Otherwise respond with "valid".`,
191186
}, {
192187
type: 'image_url',
193188
image_url: {
@@ -261,7 +256,6 @@ if (dataIdsFile) {
261256
sample.metadata = sample.metadata || {};
262257
sample.metadata.reason = json.reason;
263258
sample.metadata.validation = json.label;
264-
sample.metadata.formattedBoundingBoxes = formattedBoundingBoxes;
265259

266260
// dry-run, only propose?
267261
if (proposeActionsJobId) {

Diff for: parameters.json

+11-35
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
{
22
"version": 1,
3-
"type": "transform",
3+
"type": "ai-action",
44
"info": {
5-
"name": "Validate Object Detection Datasets Using GPT-4o",
6-
"description": "Let GPT-4o look at every image in your object detection dataset and check against up to three validation prompts you provide. If images are not compliant they will be disabled and reasoning will be put into the metadata. The block passes each image's bounding boxes and labels to GPT-4o so you can for example check if \"The bounding boxes and labels do not correspond to the objects in the image\".",
7-
"operatesOn": "standalone",
8-
"transformMountpoints": [],
9-
"allowExtraCliArguments": false,
10-
"cliArguments": "",
11-
"indMetadata": true,
12-
"showInCreateTransformationJob": false,
13-
"showInDataSources": true
5+
"name": "Bounding box validation Using GPT-4o",
6+
"description": "Use GPT-4o to validate that your bounding boxes are correct. If images are not compliant they will be disabled and reasoning will be put into the metadata. The block passes each image's bounding boxes and labels to GPT-4o so you can for example check if \"The bounding boxes and labels do not correspond to the objects in the image\".",
7+
"operatesOn": [
8+
"images_object_detection"
9+
]
1410
},
1511
"parameters": [
1612
{
@@ -21,33 +17,13 @@
2117
"param": "OPENAI_API_KEY"
2218
},
2319
{
24-
"name": "Validation Prompt 1",
25-
"value": "The bounding boxes and labels do not correspond to to the objects in the image",
20+
"name": "Validation prompt",
21+
"value": "- The bounding boxes and labels do not correspond to to the objects in the image\n- The image is not clear enough to determine the objects in the image\n- There is text overlay visible on this image",
2622
"type": "string",
2723
"help": "Disable the sample if this prompt is true",
28-
"param": "validation1"
29-
},
30-
{
31-
"name": "Validation Prompt 2",
32-
"value": "The image is not clear enough to determine the objects in the image.",
33-
"type": "string",
34-
"help": "Disable the sample if this prompt is true",
35-
"param": "validation2"
36-
},
37-
{
38-
"name": "Validation Prompt 3",
39-
"value": "There is text overlay visible on this image.",
40-
"type": "string",
41-
"help": "Disable the sample if this prompt is true",
42-
"param": "validation3"
43-
},
44-
{
45-
"name": "Max. no. of samples to label",
46-
"value": "",
47-
"type": "int",
48-
"optional": true,
49-
"help": "Number of samples to label",
50-
"param": "limit"
24+
"param": "validation-prompt",
25+
"multiline": true,
26+
"hint": "Put each prompt on a new line, and start with a -"
5127
},
5228
{
5329
"name": "Image quality",

Diff for: tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"compilerOptions": {
3-
"target": "es2019",
3+
"target": "es2021",
44
"module": "commonjs",
55
"esModuleInterop": true,
66
"outDir": "./build",

0 commit comments

Comments
 (0)