AnnotationFlow is a local software tool for building YOLO object-detection datasets from raw image folders. It normalizes image files, removes exact duplicates, runs images through a configurable Roboflow Workflow, converts detections into YOLO labels, splits the result into train/valid/test, and exports a ready-to-train dataset ZIP.
AnnotationFlow turns image batches into clean object-detection datasets:
raw images
-> image validation and JPG normalization
-> exact duplicate detection
-> Roboflow Workflow inference
-> detection extraction
-> YOLO label writing
-> train / valid / test split
-> downloadable dataset ZIP
The application includes a FastAPI backend and a React/Vite frontend. Jobs run in the background, while the UI shows live command-style logs and a four-step progress roadmap.
AnnotationFlow uses Roboflow Workflows as the inference layer. This keeps dataset generation flexible: you can update the model, workflow graph, confidence behavior, and output structure in Roboflow while keeping the local export pipeline stable.
The UI can optionally override these values per run:
ROBOFLOW_API_KEY
ROBOFLOW_WORKSPACE_NAME
ROBOFLOW_WORKFLOW_ID
ROBOFLOW_USE_CACHE
ROBOFLOW_CONFIDENCE
TRAIN_RATIO
VAL_RATIO
TEST_RATIOIf a field is left empty in the UI, the backend falls back to .env. This allows repeatable default settings while still supporting one-off experiments from the browser.
For every processed image, AnnotationFlow writes a matching .txt label file. Each detection is exported as:
class_id x_center y_center width height
All coordinates are normalized to 0..1:
x_center = prediction.x / image.width
y_center = prediction.y / image.height
width = prediction.width / image.width
height = prediction.height / image.height
The exported dataset has the standard YOLO layout:
dataset/
├── train/
│ ├── images/
│ └── labels/
├── valid/
│ ├── images/
│ └── labels/
├── test/
│ ├── images/
│ └── labels/
└── data.yaml
Example data.yaml:
train: ../train/images
val: ../valid/images
test: ../test/images
nc: 1
names: ['stair']- Python
>=3.12,<3.13 - Node.js compatible with Vite
7.x uvfor backend dependency management- npm for frontend dependency management
- A Roboflow API key with access to the selected workspace and workflow
Backend runtime dependencies:
- FastAPI
- Uvicorn
- python-multipart
- pydantic-settings
- Pillow
- pillow-heif
- inference-sdk
Frontend runtime dependencies:
- React
- React DOM
- Vite
Create a local .env file:
cp .env.example .envRequired Roboflow settings:
ROBOFLOW_API_URL=https://serverless.roboflow.com
ROBOFLOW_API_KEY=replace_with_your_roboflow_api_key
ROBOFLOW_WORKSPACE_NAME=your_workspace
ROBOFLOW_WORKFLOW_ID=your_workflow
ROBOFLOW_USE_CACHE=true
ROBOFLOW_CONFIDENCE=0.4Dataset split settings:
TRAIN_RATIO=0.8
VAL_RATIO=0.1
TEST_RATIO=0.1
SPLIT_SEED=42The split ratios must add up to 1.0.
Install dependencies:
./setup.shRun the full application:
./run.shOpen:
Frontend: http://127.0.0.1:8081
Backend: http://127.0.0.1:8000
Run backend tests:
cd backend
uv run pytestRun frontend checks:
cd frontend
npm testContributions are welcome. Good first areas include:
- Additional Roboflow Workflow response parsers
- Better validation and reporting for failed images
- Dataset export options
- UI improvements for large image batches
- More tests around edge cases and workflow outputs
Before opening a pull request, run:
cd backend && uv run pytest
cd ../frontend && npm testPlease keep API keys, private datasets, and generated runtime output out of source control.
