hotgaze 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.
- hotgaze-0.1.0/.github/workflows/ci.yml +42 -0
- hotgaze-0.1.0/.github/workflows/nightly.yml +48 -0
- hotgaze-0.1.0/.github/workflows/release.yml +41 -0
- hotgaze-0.1.0/.gitignore +46 -0
- hotgaze-0.1.0/CHANGELOG.md +19 -0
- hotgaze-0.1.0/LICENSE +21 -0
- hotgaze-0.1.0/LICENSES-THIRD-PARTY.md +132 -0
- hotgaze-0.1.0/PKG-INFO +157 -0
- hotgaze-0.1.0/README.md +118 -0
- hotgaze-0.1.0/docs/demo.png +0 -0
- hotgaze-0.1.0/pyproject.toml +114 -0
- hotgaze-0.1.0/scripts/generate_fixtures.py +90 -0
- hotgaze-0.1.0/src/hotgaze/__init__.py +3 -0
- hotgaze-0.1.0/src/hotgaze/_imageops.py +91 -0
- hotgaze-0.1.0/src/hotgaze/_unisal/__init__.py +5 -0
- hotgaze-0.1.0/src/hotgaze/_unisal/_cgru.py +441 -0
- hotgaze-0.1.0/src/hotgaze/_unisal/_mobilenet.py +239 -0
- hotgaze-0.1.0/src/hotgaze/_unisal/_model.py +412 -0
- hotgaze-0.1.0/src/hotgaze/attention_map.py +98 -0
- hotgaze-0.1.0/src/hotgaze/cli.py +439 -0
- hotgaze-0.1.0/src/hotgaze/config.py +53 -0
- hotgaze-0.1.0/src/hotgaze/engine.py +197 -0
- hotgaze-0.1.0/src/hotgaze/layers/__init__.py +25 -0
- hotgaze-0.1.0/src/hotgaze/layers/base.py +31 -0
- hotgaze-0.1.0/src/hotgaze/layers/center_bias.py +47 -0
- hotgaze-0.1.0/src/hotgaze/layers/contrast.py +51 -0
- hotgaze-0.1.0/src/hotgaze/layers/faces.py +85 -0
- hotgaze-0.1.0/src/hotgaze/layers/gaze_flow.py +48 -0
- hotgaze-0.1.0/src/hotgaze/layers/saliency_deep.py +103 -0
- hotgaze-0.1.0/src/hotgaze/layers/saliency_fast.py +68 -0
- hotgaze-0.1.0/src/hotgaze/render.py +199 -0
- hotgaze-0.1.0/src/hotgaze/schemas/__init__.py +0 -0
- hotgaze-0.1.0/src/hotgaze/schemas/score.schema.json +162 -0
- hotgaze-0.1.0/src/hotgaze/scoring.py +444 -0
- hotgaze-0.1.0/src/hotgaze/weights.py +188 -0
- hotgaze-0.1.0/tests/__init__.py +0 -0
- hotgaze-0.1.0/tests/conftest.py +44 -0
- hotgaze-0.1.0/tests/test_cli.py +196 -0
- hotgaze-0.1.0/tests/test_compare.py +223 -0
- hotgaze-0.1.0/tests/test_deep.py +162 -0
- hotgaze-0.1.0/tests/test_engine.py +180 -0
- hotgaze-0.1.0/tests/test_integration.py +94 -0
- hotgaze-0.1.0/tests/test_layers.py +214 -0
- hotgaze-0.1.0/tests/test_optional.py +220 -0
- hotgaze-0.1.0/tests/test_perf.py +29 -0
- hotgaze-0.1.0/tests/test_scoring.py +288 -0
- hotgaze-0.1.0/tests/test_trivial.py +9 -0
- hotgaze-0.1.0/tests/test_weights.py +193 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# HotGaze CI
|
|
2
|
+
|
|
3
|
+
name: CI
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
pull_request:
|
|
9
|
+
branches: [main]
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
os: [ubuntu-latest, macos-latest]
|
|
17
|
+
python-version: ["3.10", "3.12"]
|
|
18
|
+
runs-on: ${{ matrix.os }}
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
23
|
+
uses: actions/setup-python@v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: ${{ matrix.python-version }}
|
|
26
|
+
|
|
27
|
+
- name: Install package with dev deps
|
|
28
|
+
run: |
|
|
29
|
+
python3 -m pip install --upgrade pip
|
|
30
|
+
python3 -m pip install -e ".[dev]"
|
|
31
|
+
|
|
32
|
+
- name: Ruff lint
|
|
33
|
+
run: ruff check src/ tests/
|
|
34
|
+
|
|
35
|
+
- name: Ruff format check
|
|
36
|
+
run: ruff format --check src/ tests/
|
|
37
|
+
|
|
38
|
+
- name: Mypy type check
|
|
39
|
+
run: mypy src/
|
|
40
|
+
|
|
41
|
+
- name: Pytest (no perf, no deep)
|
|
42
|
+
run: pytest -m "not perf and not deep"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# HotGaze nightly — deep backend tests
|
|
2
|
+
#
|
|
3
|
+
# Runs pytest -m deep on a schedule. Because UNISAL weights are not yet
|
|
4
|
+
# published (see PROGRESS.md Orchestrator TODOs), deep tests skip with a
|
|
5
|
+
# reason — nightly is expected to be green-by-skip until weights are live.
|
|
6
|
+
# Once weights are published, this workflow will exercise the full deep
|
|
7
|
+
# pipeline nightly.
|
|
8
|
+
#
|
|
9
|
+
# Weight cache is persisted via actions/cache, keyed by the checksums
|
|
10
|
+
# recorded in LICENSES-THIRD-PARTY.md.
|
|
11
|
+
|
|
12
|
+
name: Nightly
|
|
13
|
+
|
|
14
|
+
on:
|
|
15
|
+
schedule:
|
|
16
|
+
- cron: "0 3 * * *" # 3 AM UTC daily
|
|
17
|
+
workflow_dispatch: # allow manual trigger
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
deep:
|
|
21
|
+
strategy:
|
|
22
|
+
fail-fast: false
|
|
23
|
+
matrix:
|
|
24
|
+
os: [ubuntu-latest, macos-latest]
|
|
25
|
+
python-version: ["3.10", "3.12"]
|
|
26
|
+
runs-on: ${{ matrix.os }}
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v4
|
|
29
|
+
|
|
30
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
31
|
+
uses: actions/setup-python@v5
|
|
32
|
+
with:
|
|
33
|
+
python-version: ${{ matrix.python-version }}
|
|
34
|
+
|
|
35
|
+
- name: Cache weight files
|
|
36
|
+
uses: actions/cache@v4
|
|
37
|
+
with:
|
|
38
|
+
path: ~/.cache/hotgaze
|
|
39
|
+
key: hotgaze-weights-${{ hashFiles('LICENSES-THIRD-PARTY.md') }}
|
|
40
|
+
restore-keys: hotgaze-weights-
|
|
41
|
+
|
|
42
|
+
- name: Install package with deep deps
|
|
43
|
+
run: |
|
|
44
|
+
python3 -m pip install --upgrade pip
|
|
45
|
+
python3 -m pip install -e ".[deep,dev]"
|
|
46
|
+
|
|
47
|
+
- name: Pytest deep
|
|
48
|
+
run: pytest -m deep -v
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# HotGaze release pipeline
|
|
2
|
+
#
|
|
3
|
+
# On tag push (v*), builds sdist + wheel and publishes to PyPI via
|
|
4
|
+
# trusted publishing. No tokens or secrets needed — PyPI trusts this
|
|
5
|
+
# repo + workflow combination after one-time setup by the orchestrator.
|
|
6
|
+
#
|
|
7
|
+
# Prerequisites (orchestrator, do before first tag push):
|
|
8
|
+
# 1. Create the weights-v1 GitHub Release with 4 assets.
|
|
9
|
+
# 2. Configure PyPI trusted publishing:
|
|
10
|
+
# PyPI → Settings → Publishing → Add → repo: suryakosaraju/hotgaze,
|
|
11
|
+
# workflow: release.yml, environment: (leave blank).
|
|
12
|
+
# 3. Push a v* tag (e.g. v0.1.0).
|
|
13
|
+
|
|
14
|
+
name: Release
|
|
15
|
+
|
|
16
|
+
on:
|
|
17
|
+
push:
|
|
18
|
+
tags: ["v*"]
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
build:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
permissions:
|
|
24
|
+
id-token: write # required for trusted publishing
|
|
25
|
+
contents: read
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v4
|
|
28
|
+
|
|
29
|
+
- name: Set up Python
|
|
30
|
+
uses: actions/setup-python@v5
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.10"
|
|
33
|
+
|
|
34
|
+
- name: Install build tools
|
|
35
|
+
run: python3 -m pip install --upgrade pip build
|
|
36
|
+
|
|
37
|
+
- name: Build sdist + wheel
|
|
38
|
+
run: python -m build
|
|
39
|
+
|
|
40
|
+
- name: Publish to PyPI
|
|
41
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
hotgaze-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
*.egg
|
|
8
|
+
|
|
9
|
+
# Virtual environments
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
env/
|
|
13
|
+
.env
|
|
14
|
+
|
|
15
|
+
# IDE
|
|
16
|
+
.vscode/
|
|
17
|
+
.idea/
|
|
18
|
+
*.swp
|
|
19
|
+
*.swo
|
|
20
|
+
*~
|
|
21
|
+
|
|
22
|
+
# OS
|
|
23
|
+
.DS_Store
|
|
24
|
+
Thumbs.db
|
|
25
|
+
|
|
26
|
+
# Coverage
|
|
27
|
+
htmlcov/
|
|
28
|
+
.coverage
|
|
29
|
+
coverage.xml
|
|
30
|
+
|
|
31
|
+
# HotGaze cache (local testing)
|
|
32
|
+
.hotgaze-cache/
|
|
33
|
+
|
|
34
|
+
# Test fixtures (generated on demand by conftest.py)
|
|
35
|
+
tests/fixtures/*.png
|
|
36
|
+
|
|
37
|
+
# Vendored-model backbone weights (downloaded on first use, never committed)
|
|
38
|
+
src/hotgaze/_unisal/weights/
|
|
39
|
+
*.pth.tar
|
|
40
|
+
CLAUDE.md
|
|
41
|
+
DESIGN.md
|
|
42
|
+
PLAN.md
|
|
43
|
+
PROGRESS.md
|
|
44
|
+
CONTRIBUTING.md
|
|
45
|
+
CONTRIBUTING.md
|
|
46
|
+
docs/devlog*.md
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to HotGaze will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## v0.1.0 (2026-07-16)
|
|
6
|
+
|
|
7
|
+
Initial release.
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
- **Fast heuristic backend**: spectral-residual saliency + Sobel contrast + center-bias prior + F-pattern gaze flow. Zero downloads, fully offline, sub-second on CPU.
|
|
11
|
+
- **Deep saliency backend** (`--backend deep`): UNISAL pretrained model (Apache 2.0), CPU-only, deterministic per-machine. Requires `pip install hotgaze[deep]` and one-time weight download.
|
|
12
|
+
- **Region scoring**: `hotgaze score IMG --region name:x,y,w,h --json` → canonical JSON with attention share, peak value, and rank per region.
|
|
13
|
+
- **A/B comparison**: `hotgaze compare A.png B.png [--region ...]` → per-region attention-share deltas + 3×3 spatial grid + focal-point movement.
|
|
14
|
+
- **Focal points**: local maxima via OpenCV dilate-based max-filter, ranked by attention value.
|
|
15
|
+
- **Faces layer** (`--layers faces`): YuNet face detector (MIT) adds Gaussian attention blobs over detected faces. Default weight 0.50 — tuned so enabling the layer shifts the focal point onto detected faces on portraits; zero effect on faceless UI images.
|
|
16
|
+
- **Canonical JSON**: schema v1, sorted keys, floats rounded to 6 dp, byte-identical across runs on the same machine.
|
|
17
|
+
- **CLI**: `hotgaze run`, `hotgaze score`, `hotgaze compare`, `hotgaze info`.
|
|
18
|
+
- **Weight manager**: download-on-first-use with SHA-256 verification, atomic cache, `click.progressbar`.
|
|
19
|
+
- **Offline-first**: default pipeline works with zero network access; deep backend caches weights after one fetch.
|
hotgaze-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Surya Kosaraju
|
|
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.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Third-Party Licenses
|
|
2
|
+
|
|
3
|
+
This file records every third-party dependency bundled or used by HotGaze,
|
|
4
|
+
as required by the project's license-hygiene policy (see CLAUDE.md).
|
|
5
|
+
|
|
6
|
+
## Core runtime dependencies
|
|
7
|
+
|
|
8
|
+
| Package | Version (min) | URL | License | Notes |
|
|
9
|
+
|---------|--------------|-----|---------|-------|
|
|
10
|
+
| numpy | 1.24 | https://github.com/numpy/numpy | BSD-3-Clause | Array computation |
|
|
11
|
+
| opencv-python-headless | 4.8 | https://github.com/opencv/opencv-python | Apache-2.0 | Image I/O, base OpenCV (no contrib) |
|
|
12
|
+
| pillow | 10.0 | https://github.com/python-pillow/Pillow | HPND (historical) | Image loading |
|
|
13
|
+
| click | 8.1 | https://github.com/pallets/click | BSD-3-Clause | CLI framework |
|
|
14
|
+
| pydantic | 2.0 | https://github.com/pydantic/pydantic | MIT | Config models, validation |
|
|
15
|
+
|
|
16
|
+
## Optional runtime dependencies
|
|
17
|
+
|
|
18
|
+
| Package | Version (min) | URL | License | Notes |
|
|
19
|
+
|---------|--------------|-----|---------|-------|
|
|
20
|
+
| torch | 2.0 | https://github.com/pytorch/pytorch | BSD-3-Clause | Deep saliency backend (`hotgaze[deep]`) |
|
|
21
|
+
|
|
22
|
+
## Development dependencies
|
|
23
|
+
|
|
24
|
+
| Package | Version (min) | URL | License | Notes |
|
|
25
|
+
|---------|--------------|-----|---------|-------|
|
|
26
|
+
| ruff | 0.4 | https://github.com/astral-sh/ruff | MIT | Lint + format |
|
|
27
|
+
| pytest | 8.0 | https://github.com/pytest-dev/pytest | MIT | Test framework |
|
|
28
|
+
| pytest-cov | 5.0 | https://github.com/pytest-dev/pytest-cov | MIT | Coverage reporting |
|
|
29
|
+
| mypy | 1.8 | https://github.com/python/mypy | MIT | Static type checking |
|
|
30
|
+
| scikit-image | 0.22 | https://github.com/scikit-image/scikit-image | BSD-3-Clause | **TEST-ONLY** — astronaut face fixture (BSD). Must never be imported from `src/` |
|
|
31
|
+
| actionlint-py | 1.7 | https://github.com/Mateusz-Grzelinski/actionlint-py | MIT | CI workflow linting |
|
|
32
|
+
|
|
33
|
+
## Pretrained models
|
|
34
|
+
|
|
35
|
+
No pretrained model weights are bundled in the repository. The deep backend
|
|
36
|
+
downloads weights on first use (cached in `~/.cache/hotgaze/`). Model license
|
|
37
|
+
audit is conducted in T0.3 and will be appended below.
|
|
38
|
+
|
|
39
|
+
### Model audit (T0.3 — completed 2026-07-11)
|
|
40
|
+
|
|
41
|
+
#### Saliency backends (deep backend candidates)
|
|
42
|
+
|
|
43
|
+
##### 1. UNISAL — ✅ SELECTED as default deep backend
|
|
44
|
+
|
|
45
|
+
| Field | Value |
|
|
46
|
+
|-------|-------|
|
|
47
|
+
| URL | https://github.com/rdroste/unisal |
|
|
48
|
+
| Code license | Apache License 2.0 |
|
|
49
|
+
| Weights license | Apache License 2.0 (weights are part of the repo, same license) |
|
|
50
|
+
| Weights file 1 | `weights_best.pth` (14.7 MB) — trained on SALICON |
|
|
51
|
+
| Weights file 2 | `weights_ft_mit1003.pth` (14.7 MB) — fine-tuned on MIT1003 |
|
|
52
|
+
| Hosting | GitHub repo (`raw.githubusercontent.com`) — stable URL, not Google Drive |
|
|
53
|
+
| SHA-256 (weights_best) | `4a9157411f1741d588b15670d15295e998805648b8b6348599fe447298338481` |
|
|
54
|
+
| SHA-256 (weights_ft_mit1003) | `a6de8ea27d812cfc3fbc2b8cab59862a8e48aaf4d512e670468d3b6972a81262` |
|
|
55
|
+
| Framework | PyTorch (native) |
|
|
56
|
+
| Redistribution | ✅ YES — Apache 2.0 Section 4 permits reproduction + distribution |
|
|
57
|
+
| **Final verdict** | **OK** — permissive license, stable URL, redistribution-allowed |
|
|
58
|
+
|
|
59
|
+
##### 2. DeepGaze IIE — ❌ REJECTED (no license)
|
|
60
|
+
|
|
61
|
+
| Field | Value |
|
|
62
|
+
|-------|-------|
|
|
63
|
+
| URL | https://github.com/matthias-k/DeepGaze |
|
|
64
|
+
| Code license | **None** — no LICENSE file; `setup.py` license fields commented out; defaults to "all rights reserved" |
|
|
65
|
+
| Weights license | None (same as code) |
|
|
66
|
+
| Weights URL | GitHub Releases (`v1.0.0` tag) — stable URL |
|
|
67
|
+
| Weights files | `deepgaze2e.pth` (~400 MB), `centerbias_mit1003.npy` (~8 MB) |
|
|
68
|
+
| Framework | PyTorch (native) |
|
|
69
|
+
| Redistribution | ❌ NO — no license grants redistribution rights |
|
|
70
|
+
| **Final verdict** | **needs-author-contact** — contact matthias.kuemmerer@bethgelab.org; GitHub issue #15 (commercial use) unanswered since Oct 2023 |
|
|
71
|
+
|
|
72
|
+
##### 3. MSI-Net — ✅ OK (fallback, TF → ONNX path)
|
|
73
|
+
|
|
74
|
+
| Field | Value |
|
|
75
|
+
|-------|-------|
|
|
76
|
+
| URL | https://github.com/alexanderkroner/saliency |
|
|
77
|
+
| Code license | MIT |
|
|
78
|
+
| Weights license | MIT (HuggingFace model card confirms) |
|
|
79
|
+
| Weights URL | https://huggingface.co/alexanderkroner/MSI-Net |
|
|
80
|
+
| Framework | TensorFlow (original); foveacast-training provides PyTorch port + ONNX export |
|
|
81
|
+
| Redistribution | ✅ YES — MIT permits use, copy, modify, merge, publish, distribute |
|
|
82
|
+
| **Final verdict** | **OK** — MIT-licensed, but TF dependency adds complexity; eligible only via ONNX export per CLAUDE.md |
|
|
83
|
+
|
|
84
|
+
#### Face detection candidates
|
|
85
|
+
|
|
86
|
+
##### 1. YuNet — ✅ SELECTED
|
|
87
|
+
|
|
88
|
+
| Field | Value |
|
|
89
|
+
|-------|-------|
|
|
90
|
+
| URL | https://github.com/opencv/opencv_zoo (models/face_detection_yunet) |
|
|
91
|
+
| Code license | MIT |
|
|
92
|
+
| Weights license | MIT |
|
|
93
|
+
| Weights URL | https://huggingface.co/opencv-zoo/face-detection-yunet (227 KB ONNX) |
|
|
94
|
+
| SHA-256 | `8f2383e4dd3cfbb4553ea8718107fc0423210dc964f9f4280604804ed2552fa4` |
|
|
95
|
+
| Integration | Native `cv2.FaceDetectorYN` API (OpenCV ≥ 4.5) |
|
|
96
|
+
| Redistribution | ✅ YES — MIT-licensed |
|
|
97
|
+
| **Final verdict** | **OK** — tiny (232 KB), native OpenCV API, MIT |
|
|
98
|
+
|
|
99
|
+
##### 2. UltraFace — ✅ OK (fallback)
|
|
100
|
+
|
|
101
|
+
| Field | Value |
|
|
102
|
+
|-------|-------|
|
|
103
|
+
| URL | https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB |
|
|
104
|
+
| Code license | MIT |
|
|
105
|
+
| Weights license | MIT |
|
|
106
|
+
| Weights URL | ONNX weights available (~1.2 MB) |
|
|
107
|
+
| Integration | `cv2.dnn.readNetFromONNX` (standard OpenCV DNN) |
|
|
108
|
+
| Redistribution | ✅ YES — MIT-licensed |
|
|
109
|
+
| **Final verdict** | **OK** — lightweight, standard DNN integration |
|
|
110
|
+
|
|
111
|
+
#### Exclusion notes
|
|
112
|
+
|
|
113
|
+
- **RetinaFace / InsightFace / SCRFD**: Code MIT, but pretrained models carry **non-commercial** restriction explicitly in README → **REJECTED**
|
|
114
|
+
- **DBFace**: No license specified → **REJECTED** (all rights reserved)
|
|
115
|
+
- **BlazeFace**: Apache 2.0 but TFLite format → excluded (no TFLite in deps)
|
|
116
|
+
|
|
117
|
+
#### Hosting plan
|
|
118
|
+
|
|
119
|
+
- UNISAL weights will be re-hosted from our own GitHub Release with pinned SHA-256 checksums (required by CLAUDE.md — original hosting is not Google Drive, but we re-host to control checksumming and availability)
|
|
120
|
+
- YuNet weights will be re-hosted from our own GitHub Release (232 KB, trivial)
|
|
121
|
+
- Download-on-first-use, cached in `~/.cache/hotgaze/` with `HOTGAZE_CACHE` env override
|
|
122
|
+
|
|
123
|
+
#### Default deep backend
|
|
124
|
+
|
|
125
|
+
**UNISAL** — best quality among PyTorch-native models with permissive license (Apache 2.0) AND redistribution rights. PyTorch-native (no TF/ONNX complexity). Two weight variants available (SALICON-trained and MIT1003-fine-tuned).
|
|
126
|
+
|
|
127
|
+
#### Vendored code
|
|
128
|
+
|
|
129
|
+
| Source | Files | License | Commit | Notes |
|
|
130
|
+
|--------|-------|---------|--------|-------|
|
|
131
|
+
| https://github.com/rdroste/unisal | `_unisal/_model.py`, `_unisal/_mobilenet.py`, `_unisal/_cgru.py` | Apache 2.0 | HEAD (2026-07-12) | Inference-only subset; training/dataset code removed. `_model.py` modified to remove training methods and KwConfigClass; `_mobilenet.py` and `_cgru.py` are unmodified except for the license header.
|
|
132
|
+
| https://github.com/rdroste/unisal | `mobilenet_v2.pth.tar` (14,205,652 B, SHA-256 `ecbe2b56…`) | Apache 2.0 | Bundled in UNISAL repo | ImageNet-pretrained MobileNetV2 backbone. Bundled in UNISAL under same Apache 2.0 license; no separate NOTICE in the upstream. Redistribution: ✅ per Apache 2.0.
|
hotgaze-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hotgaze
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Predict visual attention on UI screenshots — heatmap overlays and machine-readable attention scores
|
|
5
|
+
Project-URL: Homepage, https://github.com/suryakosaraju/hotgaze
|
|
6
|
+
Project-URL: Repository, https://github.com/suryakosaraju/hotgaze
|
|
7
|
+
Author: Surya Kosaraju
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
License-File: LICENSES-THIRD-PARTY.md
|
|
11
|
+
Keywords: attention,eye-tracking,heatmap,saliency,ui,ux
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Requires-Dist: click>=8.1
|
|
25
|
+
Requires-Dist: numpy>=1.24
|
|
26
|
+
Requires-Dist: opencv-python-headless>=4.8
|
|
27
|
+
Requires-Dist: pillow>=10.0
|
|
28
|
+
Requires-Dist: pydantic>=2.0
|
|
29
|
+
Provides-Extra: deep
|
|
30
|
+
Requires-Dist: torch>=2.0; extra == 'deep'
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: actionlint-py>=1.7; extra == 'dev'
|
|
33
|
+
Requires-Dist: mypy>=1.8; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
37
|
+
Requires-Dist: scikit-image>=0.22; extra == 'dev'
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
# HotGaze ⏿
|
|
41
|
+
|
|
42
|
+
[](https://github.com/suryakosaraju/hotgaze/actions/workflows/ci.yml)
|
|
43
|
+
[](https://github.com/suryakosaraju/hotgaze/blob/main/LICENSE)
|
|
44
|
+
[](https://github.com/suryakosaraju/hotgaze/blob/main/pyproject.toml)
|
|
45
|
+
|
|
46
|
+
Attention heatmaps for UI screenshots — with **numeric scores and A/B compare**, not just pretty pictures.
|
|
47
|
+
|
|
48
|
+
Predict where users' eyes land on a design, get a machine-readable attention share for any region, and diff two variants to see which one wins and by how much. Local, offline, MIT-licensed.
|
|
49
|
+
|
|
50
|
+

|
|
51
|
+
|
|
52
|
+
> **Status: v0.1 alpha.** The fast heuristic backend, region scoring, A/B compare, and deep UNISAL backend are shipping. Faces layer (YuNet) is available via `--layers faces`. API and CLI may change before v1.
|
|
53
|
+
|
|
54
|
+
## Why this exists
|
|
55
|
+
|
|
56
|
+
Every existing attention-prediction tool — paid ([HeatScope](https://heatscope.space), Attention Insight, EyeQuant) and free ([Foveacast](https://www.allaboutken.com/posts/20260503-foveacast/)) — stops at a colored overlay for a human to eyeball. That's fine for a designer squinting at a mockup. It's useless when you want to:
|
|
57
|
+
|
|
58
|
+
- Compare two design variants and *quantify* which one draws more attention to the CTA.
|
|
59
|
+
- Wire attention checks into CI ("your button just lost 23% of its attention").
|
|
60
|
+
- Script or automate any part of the design-review loop.
|
|
61
|
+
|
|
62
|
+
HotGaze outputs the picture too, but the picture isn't the point. The **numbers** are.
|
|
63
|
+
|
|
64
|
+
## Install
|
|
65
|
+
|
|
66
|
+
Not on PyPI yet (v0.1 is a working-directory install):
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
git clone https://github.com/suryakosaraju/hotgaze
|
|
70
|
+
cd hotgaze
|
|
71
|
+
pip install -e .
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Python 3.10+. Runs on macOS and Linux. No cloud, no API keys, no telemetry.
|
|
75
|
+
|
|
76
|
+
## Quickstart
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Generate an attention overlay
|
|
80
|
+
hotgaze run screenshot.png -o overlay.png
|
|
81
|
+
|
|
82
|
+
# Score a specific region — how much attention does the CTA get?
|
|
83
|
+
hotgaze score screenshot.png --region cta:250,200,200,35 --json
|
|
84
|
+
|
|
85
|
+
# Compare two variants — which one wins?
|
|
86
|
+
hotgaze compare landing_a.png landing_b.png --region cta:250,200,200,35
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## The differentiator: numbers, not just pictures
|
|
90
|
+
|
|
91
|
+
**Score any region.** Attention share, peak value, rank — canonical JSON, deterministic on the same machine:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
$ hotgaze score design.png --region cta:250,200,200,35 --json
|
|
95
|
+
{
|
|
96
|
+
"schema": 1,
|
|
97
|
+
"regions": [
|
|
98
|
+
{"name": "cta", "share": 0.035, "peak_value": 0.769, "rank": 1}
|
|
99
|
+
],
|
|
100
|
+
"focal_points": [...]
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Compare two variants.** Per-region deltas, plus a 3×3 spatial grid showing where attention *moved*:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
$ hotgaze compare landing_a.png landing_b.png --region cta:250,200,200,35 --json
|
|
108
|
+
{
|
|
109
|
+
"compare": {
|
|
110
|
+
"per_region_deltas": [
|
|
111
|
+
{"name": "cta", "share_a": 0.035, "share_b": 0.022, "delta": -0.013}
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Variant B lost 37% of the CTA's attention share. That's an actionable number, not "the heatmap looks about the same."
|
|
118
|
+
|
|
119
|
+
## What's in the box
|
|
120
|
+
|
|
121
|
+
- **CLI**: `hotgaze run`, `hotgaze score`, `hotgaze compare`, `hotgaze info`.
|
|
122
|
+
- **Fast heuristic backend** (default): spectral-residual saliency + contrast + center bias + F-pattern reading prior. No downloads, works offline, sub-second on CPU.
|
|
123
|
+
- **Deep saliency backend** (`--backend deep`): [UNISAL](https://github.com/rdroste/unisal) (Apache-2.0), CPU-only, deterministic per-machine. Install: `pip install hotgaze[deep]`. Weights download on first use (one-time, ~30 MB).
|
|
124
|
+
- **Faces layer** (`--layers faces`): [YuNet](https://github.com/opencv/opencv_zoo) (MIT) face detection adds attention blobs over detected faces.
|
|
125
|
+
- **Versioned JSON output**: schema v1 covers both score and compare modes so downstream tools don't break on new features.
|
|
126
|
+
- **Deterministic**: same image + same config + same machine → byte-identical JSON.
|
|
127
|
+
|
|
128
|
+
## Backends
|
|
129
|
+
|
|
130
|
+
| Backend | Default | What it uses | Quality |
|
|
131
|
+
|---------|---------|-------------|---------|
|
|
132
|
+
| `fast` | ✅ | Spectral residual + contrast + center bias + gaze flow | Strong on flat UI screenshots; zero downloads |
|
|
133
|
+
| `deep` | | UNISAL pretrained saliency model (PyTorch) | Better on natural images; on flat UIs the fast backend often matches or exceeds it — the domain gap is real. |
|
|
134
|
+
|
|
135
|
+
`--backend deep` requires `pip install hotgaze[deep]` and a one-time weight download on first use. Both backends are fully offline after the initial fetch.
|
|
136
|
+
|
|
137
|
+
## What HotGaze isn't
|
|
138
|
+
|
|
139
|
+
- **Not real eye-tracking.** It's a prediction from computer-vision priors. Useful for early design review; not a substitute for a user study.
|
|
140
|
+
- **Not a conversion oracle.** Attention share correlates with visibility, not with conversion — high attention on a bad CTA still doesn't sell.
|
|
141
|
+
- **Not a designer GUI.** It's a scriptable tool for developers. A GUI/Figma plugin is roadmap, not v1.
|
|
142
|
+
|
|
143
|
+
## Roadmap
|
|
144
|
+
|
|
145
|
+
- **v0.2** — PyPI release, GitHub Action for attention regression testing on PR screenshots.
|
|
146
|
+
- **v0.3+** — UI-tuned text/saliency models, Figma plugin, macOS wrapper, benchmarking against public saliency datasets.
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
## License
|
|
150
|
+
|
|
151
|
+
MIT. See [LICENSE](https://github.com/suryakosaraju/hotgaze/blob/main/LICENSE).
|
|
152
|
+
|
|
153
|
+
Third-party models and dependencies are recorded with their licenses and redistribution status in [LICENSES-THIRD-PARTY.md](https://github.com/suryakosaraju/hotgaze/blob/main/LICENSES-THIRD-PARTY.md).
|
|
154
|
+
|
|
155
|
+
## Credits
|
|
156
|
+
|
|
157
|
+
Predictive saliency stands on decades of vision research. The deep backend builds on [UNISAL](https://github.com/rdroste/unisal) (Droste et al.). The fast backend implements [Hou & Zhang's spectral-residual approach (2007)](https://www.cv-foundation.org/openaccess/content_cvpr_2007/papers/Hou_Saliency_Detection_A_Spectral_Residual_Approach_CVPR_2007_paper.pdf). Face detection uses [YuNet](https://github.com/opencv/opencv_zoo).
|
hotgaze-0.1.0/README.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# HotGaze ⏿
|
|
2
|
+
|
|
3
|
+
[](https://github.com/suryakosaraju/hotgaze/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/suryakosaraju/hotgaze/blob/main/LICENSE)
|
|
5
|
+
[](https://github.com/suryakosaraju/hotgaze/blob/main/pyproject.toml)
|
|
6
|
+
|
|
7
|
+
Attention heatmaps for UI screenshots — with **numeric scores and A/B compare**, not just pretty pictures.
|
|
8
|
+
|
|
9
|
+
Predict where users' eyes land on a design, get a machine-readable attention share for any region, and diff two variants to see which one wins and by how much. Local, offline, MIT-licensed.
|
|
10
|
+
|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
> **Status: v0.1 alpha.** The fast heuristic backend, region scoring, A/B compare, and deep UNISAL backend are shipping. Faces layer (YuNet) is available via `--layers faces`. API and CLI may change before v1.
|
|
14
|
+
|
|
15
|
+
## Why this exists
|
|
16
|
+
|
|
17
|
+
Every existing attention-prediction tool — paid ([HeatScope](https://heatscope.space), Attention Insight, EyeQuant) and free ([Foveacast](https://www.allaboutken.com/posts/20260503-foveacast/)) — stops at a colored overlay for a human to eyeball. That's fine for a designer squinting at a mockup. It's useless when you want to:
|
|
18
|
+
|
|
19
|
+
- Compare two design variants and *quantify* which one draws more attention to the CTA.
|
|
20
|
+
- Wire attention checks into CI ("your button just lost 23% of its attention").
|
|
21
|
+
- Script or automate any part of the design-review loop.
|
|
22
|
+
|
|
23
|
+
HotGaze outputs the picture too, but the picture isn't the point. The **numbers** are.
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
Not on PyPI yet (v0.1 is a working-directory install):
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
git clone https://github.com/suryakosaraju/hotgaze
|
|
31
|
+
cd hotgaze
|
|
32
|
+
pip install -e .
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Python 3.10+. Runs on macOS and Linux. No cloud, no API keys, no telemetry.
|
|
36
|
+
|
|
37
|
+
## Quickstart
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Generate an attention overlay
|
|
41
|
+
hotgaze run screenshot.png -o overlay.png
|
|
42
|
+
|
|
43
|
+
# Score a specific region — how much attention does the CTA get?
|
|
44
|
+
hotgaze score screenshot.png --region cta:250,200,200,35 --json
|
|
45
|
+
|
|
46
|
+
# Compare two variants — which one wins?
|
|
47
|
+
hotgaze compare landing_a.png landing_b.png --region cta:250,200,200,35
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## The differentiator: numbers, not just pictures
|
|
51
|
+
|
|
52
|
+
**Score any region.** Attention share, peak value, rank — canonical JSON, deterministic on the same machine:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
$ hotgaze score design.png --region cta:250,200,200,35 --json
|
|
56
|
+
{
|
|
57
|
+
"schema": 1,
|
|
58
|
+
"regions": [
|
|
59
|
+
{"name": "cta", "share": 0.035, "peak_value": 0.769, "rank": 1}
|
|
60
|
+
],
|
|
61
|
+
"focal_points": [...]
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Compare two variants.** Per-region deltas, plus a 3×3 spatial grid showing where attention *moved*:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
$ hotgaze compare landing_a.png landing_b.png --region cta:250,200,200,35 --json
|
|
69
|
+
{
|
|
70
|
+
"compare": {
|
|
71
|
+
"per_region_deltas": [
|
|
72
|
+
{"name": "cta", "share_a": 0.035, "share_b": 0.022, "delta": -0.013}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Variant B lost 37% of the CTA's attention share. That's an actionable number, not "the heatmap looks about the same."
|
|
79
|
+
|
|
80
|
+
## What's in the box
|
|
81
|
+
|
|
82
|
+
- **CLI**: `hotgaze run`, `hotgaze score`, `hotgaze compare`, `hotgaze info`.
|
|
83
|
+
- **Fast heuristic backend** (default): spectral-residual saliency + contrast + center bias + F-pattern reading prior. No downloads, works offline, sub-second on CPU.
|
|
84
|
+
- **Deep saliency backend** (`--backend deep`): [UNISAL](https://github.com/rdroste/unisal) (Apache-2.0), CPU-only, deterministic per-machine. Install: `pip install hotgaze[deep]`. Weights download on first use (one-time, ~30 MB).
|
|
85
|
+
- **Faces layer** (`--layers faces`): [YuNet](https://github.com/opencv/opencv_zoo) (MIT) face detection adds attention blobs over detected faces.
|
|
86
|
+
- **Versioned JSON output**: schema v1 covers both score and compare modes so downstream tools don't break on new features.
|
|
87
|
+
- **Deterministic**: same image + same config + same machine → byte-identical JSON.
|
|
88
|
+
|
|
89
|
+
## Backends
|
|
90
|
+
|
|
91
|
+
| Backend | Default | What it uses | Quality |
|
|
92
|
+
|---------|---------|-------------|---------|
|
|
93
|
+
| `fast` | ✅ | Spectral residual + contrast + center bias + gaze flow | Strong on flat UI screenshots; zero downloads |
|
|
94
|
+
| `deep` | | UNISAL pretrained saliency model (PyTorch) | Better on natural images; on flat UIs the fast backend often matches or exceeds it — the domain gap is real. |
|
|
95
|
+
|
|
96
|
+
`--backend deep` requires `pip install hotgaze[deep]` and a one-time weight download on first use. Both backends are fully offline after the initial fetch.
|
|
97
|
+
|
|
98
|
+
## What HotGaze isn't
|
|
99
|
+
|
|
100
|
+
- **Not real eye-tracking.** It's a prediction from computer-vision priors. Useful for early design review; not a substitute for a user study.
|
|
101
|
+
- **Not a conversion oracle.** Attention share correlates with visibility, not with conversion — high attention on a bad CTA still doesn't sell.
|
|
102
|
+
- **Not a designer GUI.** It's a scriptable tool for developers. A GUI/Figma plugin is roadmap, not v1.
|
|
103
|
+
|
|
104
|
+
## Roadmap
|
|
105
|
+
|
|
106
|
+
- **v0.2** — PyPI release, GitHub Action for attention regression testing on PR screenshots.
|
|
107
|
+
- **v0.3+** — UI-tuned text/saliency models, Figma plugin, macOS wrapper, benchmarking against public saliency datasets.
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
MIT. See [LICENSE](https://github.com/suryakosaraju/hotgaze/blob/main/LICENSE).
|
|
113
|
+
|
|
114
|
+
Third-party models and dependencies are recorded with their licenses and redistribution status in [LICENSES-THIRD-PARTY.md](https://github.com/suryakosaraju/hotgaze/blob/main/LICENSES-THIRD-PARTY.md).
|
|
115
|
+
|
|
116
|
+
## Credits
|
|
117
|
+
|
|
118
|
+
Predictive saliency stands on decades of vision research. The deep backend builds on [UNISAL](https://github.com/rdroste/unisal) (Droste et al.). The fast backend implements [Hou & Zhang's spectral-residual approach (2007)](https://www.cv-foundation.org/openaccess/content_cvpr_2007/papers/Hou_Saliency_Detection_A_Spectral_Residual_Approach_CVPR_2007_paper.pdf). Face detection uses [YuNet](https://github.com/opencv/opencv_zoo).
|
|
Binary file
|