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.
Files changed (50) hide show
  1. lare-0.1.0/.gitignore +77 -0
  2. lare-0.1.0/LICENSE +21 -0
  3. lare-0.1.0/PKG-INFO +189 -0
  4. lare-0.1.0/README.md +166 -0
  5. lare-0.1.0/assets/wordmark-inkscape.svg +175 -0
  6. lare-0.1.0/assets/wordmark.svg +140 -0
  7. lare-0.1.0/pyproject.toml +34 -0
  8. lare-0.1.0/setup.cfg +4 -0
  9. lare-0.1.0/src/lare/__init__.py +1 -0
  10. lare-0.1.0/src/lare/cli.py +135 -0
  11. lare-0.1.0/src/lare/config.py +134 -0
  12. lare-0.1.0/src/lare/console.py +96 -0
  13. lare-0.1.0/src/lare/database.py +231 -0
  14. lare-0.1.0/src/lare/export.py +98 -0
  15. lare-0.1.0/src/lare/imaging.py +163 -0
  16. lare-0.1.0/src/lare/interactive.py +287 -0
  17. lare-0.1.0/src/lare/pipeline.py +92 -0
  18. lare-0.1.0/src/lare/server.py +207 -0
  19. lare-0.1.0/src/lare/static/assets/EBGaramond-jRkwfIhC.ttf +0 -0
  20. lare-0.1.0/src/lare/static/assets/Inter-c8O0ljhh.ttf +0 -0
  21. lare-0.1.0/src/lare/static/assets/JetBrainsMono-BrlcHZ7m.ttf +0 -0
  22. lare-0.1.0/src/lare/static/assets/index-D4HzesMy.js +71 -0
  23. lare-0.1.0/src/lare/static/assets/index-oCWIDgZQ.css +1 -0
  24. lare-0.1.0/src/lare/static/index.html +17 -0
  25. lare-0.1.0/src/lare.egg-info/PKG-INFO +189 -0
  26. lare-0.1.0/src/lare.egg-info/SOURCES.txt +48 -0
  27. lare-0.1.0/src/lare.egg-info/dependency_links.txt +1 -0
  28. lare-0.1.0/src/lare.egg-info/entry_points.txt +2 -0
  29. lare-0.1.0/src/lare.egg-info/requires.txt +16 -0
  30. lare-0.1.0/src/lare.egg-info/top_level.txt +1 -0
  31. lare-0.1.0/webapp/index.html +16 -0
  32. lare-0.1.0/webapp/package-lock.json +2428 -0
  33. lare-0.1.0/webapp/package.json +23 -0
  34. lare-0.1.0/webapp/src/App.tsx +111 -0
  35. lare-0.1.0/webapp/src/api.ts +97 -0
  36. lare-0.1.0/webapp/src/assets/fonts/EBGaramond.ttf +0 -0
  37. lare-0.1.0/webapp/src/assets/fonts/Inter.ttf +0 -0
  38. lare-0.1.0/webapp/src/assets/fonts/JetBrainsMono.ttf +0 -0
  39. lare-0.1.0/webapp/src/components/ControlPanel.tsx +109 -0
  40. lare-0.1.0/webapp/src/components/ImageGrid.tsx +69 -0
  41. lare-0.1.0/webapp/src/components/JumpToInput.tsx +147 -0
  42. lare-0.1.0/webapp/src/components/LabelButton.tsx +68 -0
  43. lare-0.1.0/webapp/src/hooks/useKeyboardShortcuts.ts +50 -0
  44. lare-0.1.0/webapp/src/hooks/useNavigationStack.ts +23 -0
  45. lare-0.1.0/webapp/src/index.css +79 -0
  46. lare-0.1.0/webapp/src/main.tsx +10 -0
  47. lare-0.1.0/webapp/src/vite-env.d.ts +1 -0
  48. lare-0.1.0/webapp/tsconfig.json +21 -0
  49. lare-0.1.0/webapp/tsconfig.tsbuildinfo +1 -0
  50. 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 &amp;</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>