lare 0.1.0__tar.gz
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.
- lare-0.1.0/.gitignore +77 -0
- lare-0.1.0/LICENSE +21 -0
- lare-0.1.0/PKG-INFO +189 -0
- lare-0.1.0/README.md +166 -0
- lare-0.1.0/assets/wordmark-inkscape.svg +175 -0
- lare-0.1.0/assets/wordmark.svg +140 -0
- lare-0.1.0/pyproject.toml +34 -0
- lare-0.1.0/setup.cfg +4 -0
- lare-0.1.0/src/lare/__init__.py +1 -0
- lare-0.1.0/src/lare/cli.py +135 -0
- lare-0.1.0/src/lare/config.py +134 -0
- lare-0.1.0/src/lare/console.py +96 -0
- lare-0.1.0/src/lare/database.py +231 -0
- lare-0.1.0/src/lare/export.py +98 -0
- lare-0.1.0/src/lare/imaging.py +163 -0
- lare-0.1.0/src/lare/interactive.py +287 -0
- lare-0.1.0/src/lare/pipeline.py +92 -0
- lare-0.1.0/src/lare/server.py +207 -0
- lare-0.1.0/src/lare/static/assets/EBGaramond-jRkwfIhC.ttf +0 -0
- lare-0.1.0/src/lare/static/assets/Inter-c8O0ljhh.ttf +0 -0
- lare-0.1.0/src/lare/static/assets/JetBrainsMono-BrlcHZ7m.ttf +0 -0
- lare-0.1.0/src/lare/static/assets/index-D4HzesMy.js +71 -0
- lare-0.1.0/src/lare/static/assets/index-oCWIDgZQ.css +1 -0
- lare-0.1.0/src/lare/static/index.html +17 -0
- lare-0.1.0/src/lare.egg-info/PKG-INFO +189 -0
- lare-0.1.0/src/lare.egg-info/SOURCES.txt +48 -0
- lare-0.1.0/src/lare.egg-info/dependency_links.txt +1 -0
- lare-0.1.0/src/lare.egg-info/entry_points.txt +2 -0
- lare-0.1.0/src/lare.egg-info/requires.txt +16 -0
- lare-0.1.0/src/lare.egg-info/top_level.txt +1 -0
- lare-0.1.0/webapp/index.html +16 -0
- lare-0.1.0/webapp/package-lock.json +2428 -0
- lare-0.1.0/webapp/package.json +23 -0
- lare-0.1.0/webapp/src/App.tsx +111 -0
- lare-0.1.0/webapp/src/api.ts +97 -0
- lare-0.1.0/webapp/src/assets/fonts/EBGaramond.ttf +0 -0
- lare-0.1.0/webapp/src/assets/fonts/Inter.ttf +0 -0
- lare-0.1.0/webapp/src/assets/fonts/JetBrainsMono.ttf +0 -0
- lare-0.1.0/webapp/src/components/ControlPanel.tsx +109 -0
- lare-0.1.0/webapp/src/components/ImageGrid.tsx +69 -0
- lare-0.1.0/webapp/src/components/JumpToInput.tsx +147 -0
- lare-0.1.0/webapp/src/components/LabelButton.tsx +68 -0
- lare-0.1.0/webapp/src/hooks/useKeyboardShortcuts.ts +50 -0
- lare-0.1.0/webapp/src/hooks/useNavigationStack.ts +23 -0
- lare-0.1.0/webapp/src/index.css +79 -0
- lare-0.1.0/webapp/src/main.tsx +10 -0
- lare-0.1.0/webapp/src/vite-env.d.ts +1 -0
- lare-0.1.0/webapp/tsconfig.json +21 -0
- lare-0.1.0/webapp/tsconfig.tsbuildinfo +1 -0
- lare-0.1.0/webapp/vite.config.ts +18 -0
lare-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
share/python-wheels/
|
|
20
|
+
*.egg-info/
|
|
21
|
+
.installed.cfg
|
|
22
|
+
*.egg
|
|
23
|
+
MANIFEST
|
|
24
|
+
|
|
25
|
+
# Testing & Linting
|
|
26
|
+
htmlcov/
|
|
27
|
+
.tox/
|
|
28
|
+
.nox/
|
|
29
|
+
.coverage
|
|
30
|
+
.coverage.*
|
|
31
|
+
.cache
|
|
32
|
+
.hypothesis/
|
|
33
|
+
.pytest_cache/
|
|
34
|
+
.mypy_cache/
|
|
35
|
+
.ruff_cache/
|
|
36
|
+
|
|
37
|
+
# Jupyter
|
|
38
|
+
.ipynb_checkpoints
|
|
39
|
+
|
|
40
|
+
# Environments
|
|
41
|
+
.env
|
|
42
|
+
.env.local
|
|
43
|
+
.venv
|
|
44
|
+
env/
|
|
45
|
+
venv/
|
|
46
|
+
ENV/
|
|
47
|
+
|
|
48
|
+
# Node.js & Webapp
|
|
49
|
+
node_modules/
|
|
50
|
+
npm-debug.log*
|
|
51
|
+
yarn-debug.log*
|
|
52
|
+
yarn-error.log*
|
|
53
|
+
pnpm-debug.log*
|
|
54
|
+
.next/
|
|
55
|
+
out/
|
|
56
|
+
dist/
|
|
57
|
+
.astro/
|
|
58
|
+
static/
|
|
59
|
+
|
|
60
|
+
# Astronomy & Data Files
|
|
61
|
+
*.fits
|
|
62
|
+
*.fits.gz
|
|
63
|
+
*.fit
|
|
64
|
+
*.h5
|
|
65
|
+
*.hdf5
|
|
66
|
+
*.log
|
|
67
|
+
|
|
68
|
+
# OS & Editors
|
|
69
|
+
.DS_Store
|
|
70
|
+
.DS_Store?
|
|
71
|
+
._*
|
|
72
|
+
.Spotlight-V100
|
|
73
|
+
.Trashes
|
|
74
|
+
.idea/
|
|
75
|
+
.vscode/
|
|
76
|
+
*.swp
|
|
77
|
+
*.swo
|
lare-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 William Roque
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
lare-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lare
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Label And Review Engine — high-velocity image classification auditing
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: click>=8.1
|
|
10
|
+
Requires-Dist: polars>=1.0
|
|
11
|
+
Requires-Dist: fastapi>=0.111
|
|
12
|
+
Requires-Dist: uvicorn[standard]>=0.30
|
|
13
|
+
Requires-Dist: pydantic>=2.0
|
|
14
|
+
Requires-Dist: tomli>=2.0; python_version < "3.11"
|
|
15
|
+
Requires-Dist: tomli-w>=1.0
|
|
16
|
+
Requires-Dist: rich>=13.0
|
|
17
|
+
Requires-Dist: questionary>=2.0
|
|
18
|
+
Provides-Extra: fits
|
|
19
|
+
Requires-Dist: astropy>=6.1.0; extra == "fits"
|
|
20
|
+
Requires-Dist: numpy>=1.26; extra == "fits"
|
|
21
|
+
Requires-Dist: matplotlib>=3.8; extra == "fits"
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
<h1 align="center">
|
|
25
|
+
<img src="https://raw.githubusercontent.com/williamroque/LARE/refs/heads/main/assets/wordmark.svg" width="500">
|
|
26
|
+
</h1>
|
|
27
|
+
|
|
28
|
+
A high-velocity, self-contained inference auditing and dataset labeling tool. LARE provides a highly optimized pipeline for reviewing and classifying multimodal data (e.g., FITS images and attention maps) using a structured, keyboard-driven web interface and a robust SQLite-backed queuing system.
|
|
29
|
+
|
|
30
|
+
## Table of Contents
|
|
31
|
+
- [Architecture & Lifecycle](#architecture--lifecycle)
|
|
32
|
+
- [CLI Commands](#cli-commands)
|
|
33
|
+
- [Configuration Model](#configuration-model)
|
|
34
|
+
- [Database Schema](#database-schema)
|
|
35
|
+
- [Web UI & Ergonomics](#web-ui--ergonomics)
|
|
36
|
+
- [Installation](#installation)
|
|
37
|
+
|
|
38
|
+
## Architecture & Lifecycle
|
|
39
|
+
|
|
40
|
+
LARE operates on a reproducible, self-contained architecture. The entire workflow is governed by a declarative template configuration (`lare_config.toml`) which compiles source data into an immutable, frozen SQLite database state (`project.lare`).
|
|
41
|
+
|
|
42
|
+
```mermaid
|
|
43
|
+
flowchart TD
|
|
44
|
+
Config[lare_config.toml<br>Pure template / Project recipe]
|
|
45
|
+
CSV[Source CSV]
|
|
46
|
+
DB[(project.lare<br>Self-Contained DB)]
|
|
47
|
+
Run(lare run)
|
|
48
|
+
Export(lare export)
|
|
49
|
+
|
|
50
|
+
Config --> |lare create| DB
|
|
51
|
+
CSV --> |lare create| DB
|
|
52
|
+
DB --> |Reads Only| Run
|
|
53
|
+
DB --> |Reads Only| Export
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## CLI Commands
|
|
57
|
+
|
|
58
|
+
### `lare create`
|
|
59
|
+
The initialization and pipeline seeding engine.
|
|
60
|
+
|
|
61
|
+
- **Interactive Guide:** Walks users through creating a `lare_config.toml` if one is not provided.
|
|
62
|
+
- **Template Fallback:** Prompts to use an existing `lare_config.toml` if found in the current directory.
|
|
63
|
+
- **Safety Lock:** Prevents accidental overwriting of an existing `project.lare` database file.
|
|
64
|
+
- `--config PATH`: Bypasses interactive prompts to use a specified external configuration file.
|
|
65
|
+
- `--no-project`: Authors the configuration file interactively without compiling the data or creating the database.
|
|
66
|
+
- **Collision Check Constraint:** Enforces namespace uniqueness when using the `stem` extraction method, raising a validation error on duplicate file names.
|
|
67
|
+
- **Freezing State:** Serializes evaluated configuration parameters into `project_metadata.config_json` inside the database.
|
|
68
|
+
|
|
69
|
+
### `lare run [PROJECT]`
|
|
70
|
+
Starts the runtime engine using the `.lare` database file as the absolute source of truth.
|
|
71
|
+
|
|
72
|
+
- **Isolation:** Ignores any local or external `.toml` files on disk, reading all shortcuts, paths, and rendering properties directly from the internal `config_json`.
|
|
73
|
+
- **Execution:** Launches a local FastAPI server, mounts static image assets, serves the compiled React production client, and automatically opens the user's default web browser.
|
|
74
|
+
|
|
75
|
+
### `lare export [PROJECT]`
|
|
76
|
+
Extracts classifications based on internal schema instructions.
|
|
77
|
+
|
|
78
|
+
- **Strategies:**
|
|
79
|
+
- `csv`: Dumps a flat table containing audited rows to a target path.
|
|
80
|
+
- `copy`: Aggregates the raw image files that received classifications and copies them to an organized target subdirectory pattern.
|
|
81
|
+
- **Flags:** Requires `--strategy csv|copy` and `--output PATH`.
|
|
82
|
+
- **Audit Metric Guard:** Validates the number of audited rows against the total queue and flashes a warning if the audit is incomplete.
|
|
83
|
+
|
|
84
|
+
## Configuration Model
|
|
85
|
+
|
|
86
|
+
Projects are defined via a declarative `lare_config.toml` recipe.
|
|
87
|
+
|
|
88
|
+
```toml
|
|
89
|
+
[paths]
|
|
90
|
+
# The SQLite database containing labeling progress
|
|
91
|
+
project = "project.lare"
|
|
92
|
+
# When set, paths in the CSV are overridden to be image_directory + basename
|
|
93
|
+
image_directory = "images/"
|
|
94
|
+
|
|
95
|
+
[rules]
|
|
96
|
+
# SQL expressions for use with Polars
|
|
97
|
+
filter_method = "GREATEST(sim_class_0, sim_class_1, sim_class_2) > 0.1"
|
|
98
|
+
ranking_score = "GREATEST(sim_class_0, sim_class_1, sim_class_2)"
|
|
99
|
+
|
|
100
|
+
# Which column in the CSV to use as the entry ID
|
|
101
|
+
id_column = "filepath"
|
|
102
|
+
# Can also be "raw" or "basename"
|
|
103
|
+
id_display_method = "stem"
|
|
104
|
+
|
|
105
|
+
[[images]]
|
|
106
|
+
column = "filepath"
|
|
107
|
+
title = "Galaxy"
|
|
108
|
+
format = "fits"
|
|
109
|
+
stretching = "asinh"
|
|
110
|
+
min_threshold = 0.5
|
|
111
|
+
max_threshold = 99.5
|
|
112
|
+
subdirectory = "galaxies"
|
|
113
|
+
|
|
114
|
+
[[images]]
|
|
115
|
+
column = "attention_png"
|
|
116
|
+
title = "Attention map (CBAM)"
|
|
117
|
+
format = "png"
|
|
118
|
+
subdirectory = "attention_maps"
|
|
119
|
+
|
|
120
|
+
[[labels]]
|
|
121
|
+
label = "sim_class_0"
|
|
122
|
+
title = "PSG"
|
|
123
|
+
shortcut = "s"
|
|
124
|
+
|
|
125
|
+
[[labels]]
|
|
126
|
+
label = "sim_class_1"
|
|
127
|
+
title = "PTS"
|
|
128
|
+
shortcut = "t"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Database Schema
|
|
132
|
+
|
|
133
|
+
Table structures are built dynamically at runtime by cross-referencing Polars DataFrame schemas with target SQLite columns.
|
|
134
|
+
|
|
135
|
+
```sql
|
|
136
|
+
-- Table 1: Complete project footprint and frozen configurations
|
|
137
|
+
CREATE TABLE project_metadata (
|
|
138
|
+
project_id TEXT PRIMARY KEY, -- Random UUIDv4 generated during `lare create`
|
|
139
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
140
|
+
config_json TEXT NOT NULL -- Entire evaluated TOML structure frozen as JSON
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
-- Table 2: High-throughput labeling queue
|
|
144
|
+
CREATE TABLE labeling_queue (
|
|
145
|
+
queue_order INTEGER PRIMARY KEY, -- Strictly enforces the frozen Polars ranking
|
|
146
|
+
entry_id TEXT UNIQUE NOT NULL, -- Absolute identifier (e.g. true raw csv filepath/hash)
|
|
147
|
+
display_id TEXT NOT NULL, -- Extracted target identifier mapped to config rules
|
|
148
|
+
final_label TEXT DEFAULT NULL, -- The ONLY mutable state column in the app
|
|
149
|
+
|
|
150
|
+
-- Real columns dynamically injected from the CSV fields at creation
|
|
151
|
+
filepath TEXT,
|
|
152
|
+
attention_png TEXT,
|
|
153
|
+
sim_class_0 REAL,
|
|
154
|
+
sim_class_1 REAL,
|
|
155
|
+
sim_class_2 REAL
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
-- Optimization Performance Indexes
|
|
159
|
+
CREATE INDEX idx_display_id ON labeling_queue(display_id);
|
|
160
|
+
CREATE INDEX idx_final_label ON labeling_queue(final_label);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Web UI & Ergonomics
|
|
164
|
+
|
|
165
|
+
The user interface balances structural minimization with optimal keyboard tracking for high-velocity inference auditing.
|
|
166
|
+
|
|
167
|
+
### Left Panel: Universal Aspect-Ratio Grid
|
|
168
|
+
- Renders assets side-by-side using a clean CSS grid wrapper.
|
|
169
|
+
- Enforces standard row heights matching the viewport while allowing flexible widths to preserve physical aspect ratios across multimodal formats (e.g., wide FITS plots next to square attention maps).
|
|
170
|
+
|
|
171
|
+
### Right Panel: Information & Controls Hub
|
|
172
|
+
- **Title Anchor:** Displays the current entry's clean `display_id`.
|
|
173
|
+
- **Inference Action Targets:** Block buttons mapped to explicit classification shortcuts (e.g., `PSG (s)`). Displays structural supporting labels indicating prediction weight (`SCORE: {score}`).
|
|
174
|
+
- **Mutations & Queue Advancement:** Clicking an action target or invoking a shortcut writes the choice to `final_label` in SQLite, appends the ID to a session stack, and immediately transitions the view state to the next row where `final_label IS NULL`.
|
|
175
|
+
|
|
176
|
+
### Navigation Safety Features
|
|
177
|
+
- **Active Field Input Trap:** Bypasses single-letter global shortcuts when `document.activeElement` matches a text input (e.g., the "Jump To" field) to avoid accidental triggers.
|
|
178
|
+
- **"Previous Entry" Stack:** Allows users to step backward, overwriting previously registered tags or fixing rapid misclicks cleanly.
|
|
179
|
+
- **"Jump To" Processing Logic:** Resolves queries against indexed database fields. On namespace collisions, a structured conflict layout provides a clean micro-dropdown to select the desired target.
|
|
180
|
+
|
|
181
|
+
### Image Serving Pipeline
|
|
182
|
+
- **Decoupled Asset Threading:** The FastAPI backend manages standard static local asset streaming.
|
|
183
|
+
- **Pre-rendering:** Avoids computing complex transformations (asinh arrays, thresholds) iteratively on-the-fly. The server pre-processes image arrays, dumping lightweight web-friendly representations into a hidden footprint directory, which is purged when LARE closes (capped at a 25-image lookahead).
|
|
184
|
+
|
|
185
|
+
## Installation
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
pip install lare
|
|
189
|
+
```
|
lare-0.1.0/README.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/williamroque/LARE/refs/heads/main/assets/wordmark.svg" width="500">
|
|
3
|
+
</h1>
|
|
4
|
+
|
|
5
|
+
A high-velocity, self-contained inference auditing and dataset labeling tool. LARE provides a highly optimized pipeline for reviewing and classifying multimodal data (e.g., FITS images and attention maps) using a structured, keyboard-driven web interface and a robust SQLite-backed queuing system.
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
- [Architecture & Lifecycle](#architecture--lifecycle)
|
|
9
|
+
- [CLI Commands](#cli-commands)
|
|
10
|
+
- [Configuration Model](#configuration-model)
|
|
11
|
+
- [Database Schema](#database-schema)
|
|
12
|
+
- [Web UI & Ergonomics](#web-ui--ergonomics)
|
|
13
|
+
- [Installation](#installation)
|
|
14
|
+
|
|
15
|
+
## Architecture & Lifecycle
|
|
16
|
+
|
|
17
|
+
LARE operates on a reproducible, self-contained architecture. The entire workflow is governed by a declarative template configuration (`lare_config.toml`) which compiles source data into an immutable, frozen SQLite database state (`project.lare`).
|
|
18
|
+
|
|
19
|
+
```mermaid
|
|
20
|
+
flowchart TD
|
|
21
|
+
Config[lare_config.toml<br>Pure template / Project recipe]
|
|
22
|
+
CSV[Source CSV]
|
|
23
|
+
DB[(project.lare<br>Self-Contained DB)]
|
|
24
|
+
Run(lare run)
|
|
25
|
+
Export(lare export)
|
|
26
|
+
|
|
27
|
+
Config --> |lare create| DB
|
|
28
|
+
CSV --> |lare create| DB
|
|
29
|
+
DB --> |Reads Only| Run
|
|
30
|
+
DB --> |Reads Only| Export
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## CLI Commands
|
|
34
|
+
|
|
35
|
+
### `lare create`
|
|
36
|
+
The initialization and pipeline seeding engine.
|
|
37
|
+
|
|
38
|
+
- **Interactive Guide:** Walks users through creating a `lare_config.toml` if one is not provided.
|
|
39
|
+
- **Template Fallback:** Prompts to use an existing `lare_config.toml` if found in the current directory.
|
|
40
|
+
- **Safety Lock:** Prevents accidental overwriting of an existing `project.lare` database file.
|
|
41
|
+
- `--config PATH`: Bypasses interactive prompts to use a specified external configuration file.
|
|
42
|
+
- `--no-project`: Authors the configuration file interactively without compiling the data or creating the database.
|
|
43
|
+
- **Collision Check Constraint:** Enforces namespace uniqueness when using the `stem` extraction method, raising a validation error on duplicate file names.
|
|
44
|
+
- **Freezing State:** Serializes evaluated configuration parameters into `project_metadata.config_json` inside the database.
|
|
45
|
+
|
|
46
|
+
### `lare run [PROJECT]`
|
|
47
|
+
Starts the runtime engine using the `.lare` database file as the absolute source of truth.
|
|
48
|
+
|
|
49
|
+
- **Isolation:** Ignores any local or external `.toml` files on disk, reading all shortcuts, paths, and rendering properties directly from the internal `config_json`.
|
|
50
|
+
- **Execution:** Launches a local FastAPI server, mounts static image assets, serves the compiled React production client, and automatically opens the user's default web browser.
|
|
51
|
+
|
|
52
|
+
### `lare export [PROJECT]`
|
|
53
|
+
Extracts classifications based on internal schema instructions.
|
|
54
|
+
|
|
55
|
+
- **Strategies:**
|
|
56
|
+
- `csv`: Dumps a flat table containing audited rows to a target path.
|
|
57
|
+
- `copy`: Aggregates the raw image files that received classifications and copies them to an organized target subdirectory pattern.
|
|
58
|
+
- **Flags:** Requires `--strategy csv|copy` and `--output PATH`.
|
|
59
|
+
- **Audit Metric Guard:** Validates the number of audited rows against the total queue and flashes a warning if the audit is incomplete.
|
|
60
|
+
|
|
61
|
+
## Configuration Model
|
|
62
|
+
|
|
63
|
+
Projects are defined via a declarative `lare_config.toml` recipe.
|
|
64
|
+
|
|
65
|
+
```toml
|
|
66
|
+
[paths]
|
|
67
|
+
# The SQLite database containing labeling progress
|
|
68
|
+
project = "project.lare"
|
|
69
|
+
# When set, paths in the CSV are overridden to be image_directory + basename
|
|
70
|
+
image_directory = "images/"
|
|
71
|
+
|
|
72
|
+
[rules]
|
|
73
|
+
# SQL expressions for use with Polars
|
|
74
|
+
filter_method = "GREATEST(sim_class_0, sim_class_1, sim_class_2) > 0.1"
|
|
75
|
+
ranking_score = "GREATEST(sim_class_0, sim_class_1, sim_class_2)"
|
|
76
|
+
|
|
77
|
+
# Which column in the CSV to use as the entry ID
|
|
78
|
+
id_column = "filepath"
|
|
79
|
+
# Can also be "raw" or "basename"
|
|
80
|
+
id_display_method = "stem"
|
|
81
|
+
|
|
82
|
+
[[images]]
|
|
83
|
+
column = "filepath"
|
|
84
|
+
title = "Galaxy"
|
|
85
|
+
format = "fits"
|
|
86
|
+
stretching = "asinh"
|
|
87
|
+
min_threshold = 0.5
|
|
88
|
+
max_threshold = 99.5
|
|
89
|
+
subdirectory = "galaxies"
|
|
90
|
+
|
|
91
|
+
[[images]]
|
|
92
|
+
column = "attention_png"
|
|
93
|
+
title = "Attention map (CBAM)"
|
|
94
|
+
format = "png"
|
|
95
|
+
subdirectory = "attention_maps"
|
|
96
|
+
|
|
97
|
+
[[labels]]
|
|
98
|
+
label = "sim_class_0"
|
|
99
|
+
title = "PSG"
|
|
100
|
+
shortcut = "s"
|
|
101
|
+
|
|
102
|
+
[[labels]]
|
|
103
|
+
label = "sim_class_1"
|
|
104
|
+
title = "PTS"
|
|
105
|
+
shortcut = "t"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Database Schema
|
|
109
|
+
|
|
110
|
+
Table structures are built dynamically at runtime by cross-referencing Polars DataFrame schemas with target SQLite columns.
|
|
111
|
+
|
|
112
|
+
```sql
|
|
113
|
+
-- Table 1: Complete project footprint and frozen configurations
|
|
114
|
+
CREATE TABLE project_metadata (
|
|
115
|
+
project_id TEXT PRIMARY KEY, -- Random UUIDv4 generated during `lare create`
|
|
116
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
117
|
+
config_json TEXT NOT NULL -- Entire evaluated TOML structure frozen as JSON
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
-- Table 2: High-throughput labeling queue
|
|
121
|
+
CREATE TABLE labeling_queue (
|
|
122
|
+
queue_order INTEGER PRIMARY KEY, -- Strictly enforces the frozen Polars ranking
|
|
123
|
+
entry_id TEXT UNIQUE NOT NULL, -- Absolute identifier (e.g. true raw csv filepath/hash)
|
|
124
|
+
display_id TEXT NOT NULL, -- Extracted target identifier mapped to config rules
|
|
125
|
+
final_label TEXT DEFAULT NULL, -- The ONLY mutable state column in the app
|
|
126
|
+
|
|
127
|
+
-- Real columns dynamically injected from the CSV fields at creation
|
|
128
|
+
filepath TEXT,
|
|
129
|
+
attention_png TEXT,
|
|
130
|
+
sim_class_0 REAL,
|
|
131
|
+
sim_class_1 REAL,
|
|
132
|
+
sim_class_2 REAL
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
-- Optimization Performance Indexes
|
|
136
|
+
CREATE INDEX idx_display_id ON labeling_queue(display_id);
|
|
137
|
+
CREATE INDEX idx_final_label ON labeling_queue(final_label);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Web UI & Ergonomics
|
|
141
|
+
|
|
142
|
+
The user interface balances structural minimization with optimal keyboard tracking for high-velocity inference auditing.
|
|
143
|
+
|
|
144
|
+
### Left Panel: Universal Aspect-Ratio Grid
|
|
145
|
+
- Renders assets side-by-side using a clean CSS grid wrapper.
|
|
146
|
+
- Enforces standard row heights matching the viewport while allowing flexible widths to preserve physical aspect ratios across multimodal formats (e.g., wide FITS plots next to square attention maps).
|
|
147
|
+
|
|
148
|
+
### Right Panel: Information & Controls Hub
|
|
149
|
+
- **Title Anchor:** Displays the current entry's clean `display_id`.
|
|
150
|
+
- **Inference Action Targets:** Block buttons mapped to explicit classification shortcuts (e.g., `PSG (s)`). Displays structural supporting labels indicating prediction weight (`SCORE: {score}`).
|
|
151
|
+
- **Mutations & Queue Advancement:** Clicking an action target or invoking a shortcut writes the choice to `final_label` in SQLite, appends the ID to a session stack, and immediately transitions the view state to the next row where `final_label IS NULL`.
|
|
152
|
+
|
|
153
|
+
### Navigation Safety Features
|
|
154
|
+
- **Active Field Input Trap:** Bypasses single-letter global shortcuts when `document.activeElement` matches a text input (e.g., the "Jump To" field) to avoid accidental triggers.
|
|
155
|
+
- **"Previous Entry" Stack:** Allows users to step backward, overwriting previously registered tags or fixing rapid misclicks cleanly.
|
|
156
|
+
- **"Jump To" Processing Logic:** Resolves queries against indexed database fields. On namespace collisions, a structured conflict layout provides a clean micro-dropdown to select the desired target.
|
|
157
|
+
|
|
158
|
+
### Image Serving Pipeline
|
|
159
|
+
- **Decoupled Asset Threading:** The FastAPI backend manages standard static local asset streaming.
|
|
160
|
+
- **Pre-rendering:** Avoids computing complex transformations (asinh arrays, thresholds) iteratively on-the-fly. The server pre-processes image arrays, dumping lightweight web-friendly representations into a hidden footprint directory, which is purged when LARE closes (capped at a 25-image lookahead).
|
|
161
|
+
|
|
162
|
+
## Installation
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
pip install lare
|
|
166
|
+
```
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
+
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
3
|
+
|
|
4
|
+
<svg
|
|
5
|
+
width="640"
|
|
6
|
+
height="230"
|
|
7
|
+
viewBox="0 0 169.33332 60.854166"
|
|
8
|
+
version="1.1"
|
|
9
|
+
id="svg1"
|
|
10
|
+
xml:space="preserve"
|
|
11
|
+
inkscape:version="1.4.2 (ebf0e940, 2025-05-08)"
|
|
12
|
+
sodipodi:docname="wordmark.svg"
|
|
13
|
+
inkscape:export-filename="wordmar.svg"
|
|
14
|
+
inkscape:export-xdpi="96"
|
|
15
|
+
inkscape:export-ydpi="96"
|
|
16
|
+
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
17
|
+
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
18
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
19
|
+
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
|
20
|
+
id="namedview1"
|
|
21
|
+
pagecolor="#ffffff"
|
|
22
|
+
bordercolor="#000000"
|
|
23
|
+
borderopacity="0.25"
|
|
24
|
+
inkscape:showpageshadow="2"
|
|
25
|
+
inkscape:pageopacity="0.0"
|
|
26
|
+
inkscape:pagecheckerboard="0"
|
|
27
|
+
inkscape:deskcolor="#d1d1d1"
|
|
28
|
+
inkscape:document-units="mm"
|
|
29
|
+
inkscape:zoom="0.66003527"
|
|
30
|
+
inkscape:cx="282.56066"
|
|
31
|
+
inkscape:cy="229.53319"
|
|
32
|
+
inkscape:window-width="1328"
|
|
33
|
+
inkscape:window-height="740"
|
|
34
|
+
inkscape:window-x="0"
|
|
35
|
+
inkscape:window-y="33"
|
|
36
|
+
inkscape:window-maximized="0"
|
|
37
|
+
inkscape:current-layer="layer1" /><defs
|
|
38
|
+
id="defs1" /><g
|
|
39
|
+
inkscape:label="Layer 1"
|
|
40
|
+
inkscape:groupmode="layer"
|
|
41
|
+
id="layer1"><g
|
|
42
|
+
id="g7"
|
|
43
|
+
transform="scale(2.0000001)"><rect
|
|
44
|
+
style="fill:#292b32;fill-opacity:1;stroke:none;stroke-width:1.32882"
|
|
45
|
+
id="rect1"
|
|
46
|
+
width="21.166666"
|
|
47
|
+
height="21.166666"
|
|
48
|
+
x="-21.166666"
|
|
49
|
+
y="-21.166796"
|
|
50
|
+
transform="scale(-1)" /><rect
|
|
51
|
+
style="fill:#4c4c56;fill-opacity:1;stroke:none;stroke-width:1.32882"
|
|
52
|
+
id="rect1-9"
|
|
53
|
+
width="21.166666"
|
|
54
|
+
height="21.166666"
|
|
55
|
+
x="-42.333332"
|
|
56
|
+
y="-21.166666"
|
|
57
|
+
transform="scale(-1)" /><rect
|
|
58
|
+
style="fill:#7b747c;fill-opacity:1;stroke:none;stroke-width:1.32882"
|
|
59
|
+
id="rect1-9-7"
|
|
60
|
+
width="21.166666"
|
|
61
|
+
height="21.166666"
|
|
62
|
+
x="-63.5"
|
|
63
|
+
y="-21.166666"
|
|
64
|
+
transform="scale(-1)" /><rect
|
|
65
|
+
style="fill:#bca9a6;fill-opacity:1;stroke:none;stroke-width:1.32882"
|
|
66
|
+
id="rect1-9-7-6"
|
|
67
|
+
width="21.166666"
|
|
68
|
+
height="21.166666"
|
|
69
|
+
x="-84.666664"
|
|
70
|
+
y="-21.166666"
|
|
71
|
+
transform="scale(-1)" /><text
|
|
72
|
+
xml:space="preserve"
|
|
73
|
+
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:10.5833px;font-family:'Avenir Next';-inkscape-font-specification:'Avenir Next, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#8caac5;fill-opacity:1;stroke:none;stroke-width:0.262378"
|
|
74
|
+
x="10.243526"
|
|
75
|
+
y="14.228662"
|
|
76
|
+
id="text1"><tspan
|
|
77
|
+
sodipodi:role="line"
|
|
78
|
+
id="tspan1"
|
|
79
|
+
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:10.5833px;font-family:'Avenir Next';-inkscape-font-specification:'Avenir Next, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#8caac5;fill-opacity:1;stroke-width:0.262378"
|
|
80
|
+
x="10.243526"
|
|
81
|
+
y="14.228662">L</tspan></text><text
|
|
82
|
+
xml:space="preserve"
|
|
83
|
+
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:10.5833px;font-family:'Avenir Next';-inkscape-font-specification:'Avenir Next, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#8d9dab;fill-opacity:1;stroke:none;stroke-width:0.262378"
|
|
84
|
+
x="31.410191"
|
|
85
|
+
y="14.228533"
|
|
86
|
+
id="text1-8"><tspan
|
|
87
|
+
sodipodi:role="line"
|
|
88
|
+
id="tspan1-2"
|
|
89
|
+
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:10.5833px;font-family:'Avenir Next';-inkscape-font-specification:'Avenir Next, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#8d9dab;fill-opacity:1;stroke-width:0.262378"
|
|
90
|
+
x="31.410191"
|
|
91
|
+
y="14.228533">A</tspan></text><text
|
|
92
|
+
xml:space="preserve"
|
|
93
|
+
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:10.5833px;font-family:'Avenir Next';-inkscape-font-specification:'Avenir Next, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#a4b7c8;fill-opacity:1;stroke:none;stroke-width:1.3"
|
|
94
|
+
x="52.597454"
|
|
95
|
+
y="14.228533"
|
|
96
|
+
id="text2"><tspan
|
|
97
|
+
sodipodi:role="line"
|
|
98
|
+
id="tspan2"
|
|
99
|
+
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:10.5833px;font-family:'Avenir Next';-inkscape-font-specification:'Avenir Next, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#a4b7c8;fill-opacity:1;stroke-width:1.3"
|
|
100
|
+
x="52.597454"
|
|
101
|
+
y="14.228533">R</tspan></text><text
|
|
102
|
+
xml:space="preserve"
|
|
103
|
+
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:10.5833px;font-family:'Avenir Next';-inkscape-font-specification:'Avenir Next, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#647789;fill-opacity:1;stroke:none;stroke-width:1.3"
|
|
104
|
+
x="73.913422"
|
|
105
|
+
y="14.228533"
|
|
106
|
+
id="text3"><tspan
|
|
107
|
+
sodipodi:role="line"
|
|
108
|
+
id="tspan3"
|
|
109
|
+
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:10.5833px;font-family:'Avenir Next';-inkscape-font-specification:'Avenir Next, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#647789;fill-opacity:1;stroke-width:1.3"
|
|
110
|
+
x="73.913422"
|
|
111
|
+
y="14.228533">E</tspan></text><rect
|
|
112
|
+
style="fill:#292b32;fill-opacity:1;stroke:none;stroke-width:0.81373"
|
|
113
|
+
id="rect1-3"
|
|
114
|
+
width="21.166666"
|
|
115
|
+
height="7.9374514"
|
|
116
|
+
x="-21.166666"
|
|
117
|
+
y="-30.427084"
|
|
118
|
+
transform="scale(-1)" /><rect
|
|
119
|
+
style="fill:#4c4c56;fill-opacity:1;stroke:none;stroke-width:0.81373"
|
|
120
|
+
id="rect1-9-2"
|
|
121
|
+
width="21.166666"
|
|
122
|
+
height="7.9374514"
|
|
123
|
+
x="-42.333328"
|
|
124
|
+
y="-30.427034"
|
|
125
|
+
transform="scale(-1)" /><rect
|
|
126
|
+
style="fill:#7b747c;fill-opacity:1;stroke:none;stroke-width:0.81373"
|
|
127
|
+
id="rect1-9-7-1"
|
|
128
|
+
width="21.166666"
|
|
129
|
+
height="7.9374514"
|
|
130
|
+
x="-63.5"
|
|
131
|
+
y="-30.427034"
|
|
132
|
+
transform="scale(-1)" /><rect
|
|
133
|
+
style="fill:#bca9a6;fill-opacity:1;stroke:none;stroke-width:0.81373"
|
|
134
|
+
id="rect1-9-7-6-4"
|
|
135
|
+
width="21.166666"
|
|
136
|
+
height="7.9374514"
|
|
137
|
+
x="-84.666664"
|
|
138
|
+
y="-30.427034"
|
|
139
|
+
transform="scale(-1)" /><text
|
|
140
|
+
xml:space="preserve"
|
|
141
|
+
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:2.46944px;font-family:'Avenir Next';-inkscape-font-specification:'Avenir Next, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#8caac5;fill-opacity:1;stroke:none;stroke-width:0.262378"
|
|
142
|
+
x="10.579631"
|
|
143
|
+
y="27.375755"
|
|
144
|
+
id="text1-0"><tspan
|
|
145
|
+
sodipodi:role="line"
|
|
146
|
+
id="tspan4"
|
|
147
|
+
x="10.579631"
|
|
148
|
+
y="27.375755">Label</tspan></text><text
|
|
149
|
+
xml:space="preserve"
|
|
150
|
+
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:2.46944px;font-family:'Avenir Next';-inkscape-font-specification:'Avenir Next, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#8d9dab;fill-opacity:1;stroke:none;stroke-width:0.262378"
|
|
151
|
+
x="31.757402"
|
|
152
|
+
y="27.095423"
|
|
153
|
+
id="text1-8-8"><tspan
|
|
154
|
+
sodipodi:role="line"
|
|
155
|
+
id="tspan5"
|
|
156
|
+
x="31.757402"
|
|
157
|
+
y="27.095423">Auditing &</tspan></text><text
|
|
158
|
+
xml:space="preserve"
|
|
159
|
+
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:2.46944px;font-family:'Avenir Next';-inkscape-font-specification:'Avenir Next, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#a4b7c8;fill-opacity:1;stroke:none;stroke-width:1.3"
|
|
160
|
+
x="52.906792"
|
|
161
|
+
y="27.390524"
|
|
162
|
+
id="text2-3"><tspan
|
|
163
|
+
sodipodi:role="line"
|
|
164
|
+
id="tspan6"
|
|
165
|
+
x="52.906792"
|
|
166
|
+
y="27.390524">Reclassification</tspan></text><text
|
|
167
|
+
xml:space="preserve"
|
|
168
|
+
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:2.46944px;font-family:'Avenir Next';-inkscape-font-specification:'Avenir Next, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#647789;fill-opacity:1;stroke:none;stroke-width:1.3"
|
|
169
|
+
x="73.996902"
|
|
170
|
+
y="27.316439"
|
|
171
|
+
id="text3-4"><tspan
|
|
172
|
+
sodipodi:role="line"
|
|
173
|
+
id="tspan7"
|
|
174
|
+
x="73.996902"
|
|
175
|
+
y="27.316439">Environment</tspan></text></g></g></svg>
|