Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
21a630e
Refactor data_service to separate GetDataSamples and GetMetadata into…
guillaume-byte Jun 19, 2026
9c4b798
Refactor value proxy (#212)
guillaume-byte Jun 19, 2026
1994426
docs: document BB_THUMB_RENDER / BB_MODAL_RENDER env vars [force ci] …
guillaume-byte Jun 19, 2026
0be0e94
Manual weights dump (#210)
guillaume-byte Jun 19, 2026
28ed7eb
DuckDB integratiion (#209)
guillaume-byte Jun 19, 2026
cd068d6
Fix duplicate SaveCheckpointOperation in proto; document Studio featu…
guillaume-byte Jun 19, 2026
93eb100
Server-side histogram binning + grid/sort perf fixes (#216)
AlexGrayBox Jun 19, 2026
50df577
Add explore actions for weightslab, i.e., run weightslab in limited m…
guillaume-byte Jun 22, 2026
204a36f
Merge branch 'v1.2.3---UI-Optimization-and-new-features' of https://g…
guillaume-byte Jun 22, 2026
082b201
Server-side histogram binning + grid/sort perf fixes (#221)
AlexGrayBox Jun 22, 2026
9d14377
Fix UL YAMML and JSON export with custom Cpython functions of ledgere…
guillaume-byte Jun 22, 2026
cb98a66
Fix instance wise segmentation bugs and modal view sync with the UI
guillaume-byte Jun 22, 2026
a0a09a9
Remove all emoji from source code
guillaume-byte Jun 22, 2026
43daa75
Add weightslab logdir CLI command for offline explore mode
guillaume-byte Jun 22, 2026
30518b3
Add wl.write_history/write_dataframe to PyTorch examples (ratio=100)
guillaume-byte Jun 22, 2026
b562fff
Add ws-multitask PyTorch example + fix GuardContext unresolved Proxy …
guillaume-byte Jun 22, 2026
d1201ae
Fix GuardContext stale model ref across tests (always resolve from le…
guillaume-byte Jun 22, 2026
b1aa6a5
Skip UI launch in logdir if stack containers are already running
guillaume-byte Jun 23, 2026
e0e2972
remove Claude md
guillaume-byte Jun 23, 2026
9831f81
Remove weightslab logdir CLI command and explore mode
guillaume-byte Jun 23, 2026
9c8e3cc
Fix eg bugs and opt (#227)
guillaume-byte Jun 25, 2026
274f000
Add telemetry information into the package (#226)
guillaume-byte Jun 25, 2026
ba09a6f
Add runtime env vars for grid/cache/PC tuning in weightslab/ui
guillaume-byte Jun 26, 2026
69ee6b1
fix yml file
guillaume-byte Jun 26, 2026
3199a4f
Fix CI gate to run on v* release branches
guillaume-byte Jun 26, 2026
0f4aff9
Add synchronize to pull_request trigger so CI runs on PR pushes
guillaume-byte Jun 26, 2026
f00290e
Remove unused imports flagged by ruff (MagicMock, pandas, time)
guillaume-byte Jun 26, 2026
57e1c9c
Bump GitHub Actions to Node.js 24-compatible versions
guillaume-byte Jun 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 9 additions & 28 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
branches: [ '**' ]
tags: [ 'v*' ]
pull_request:
types: [ opened, reopened, ready_for_review ]
types: [ opened, reopened, ready_for_review, synchronize ]
workflow_dispatch:

jobs:
Expand All @@ -32,8 +32,8 @@ jobs:
run_ci=true # PRs and manual dispatch always run
elif [[ "${{ github.ref }}" == refs/tags/* ]]; then
run_ci=false # tag pushes are handled by the release workflow
elif [ "${{ github.ref }}" = "refs/heads/main" ] || [ "${{ github.ref }}" = "refs/heads/dev" ]; then
run_ci=true # default branches always run
elif [ "${{ github.ref }}" = "refs/heads/main" ] || [ "${{ github.ref }}" = "refs/heads/dev" ] || [[ "${{ github.ref }}" == refs/heads/v* ]]; then
run_ci=true # default branches and release branches (v*) always run
elif [ "${FORCE_CI}" = "true" ]; then
run_ci=true # custom branch opted in via [force ci]
else
Expand All @@ -57,7 +57,7 @@ jobs:

- name: Set up Python
id: setup-python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: '3.11'

Expand Down Expand Up @@ -141,7 +141,7 @@ jobs:
uses: actions/checkout@v4

- name: Set up Python 3.11
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: '3.11'

Expand Down Expand Up @@ -179,7 +179,7 @@ jobs:
uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: ${{ matrix.allow-prereleases || false }}
Expand All @@ -204,7 +204,7 @@ jobs:
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: '3.11'

Expand All @@ -223,25 +223,6 @@ jobs:
# A per-test timeout guards against any regression that hangs a test.
python -m pytest ./weightslab/tests -v --timeout=300

# TODO (GP): WL CI do not find WS CI for now; token or visibility problem ??
# - name: Trigger WeightsStudio CI
# env:
# WS_TOKEN: ${{ secrets.WEIGHTS_STUDIO_API_TOKEN }}
# run: |
# if [ -z "${WS_TOKEN}" ]; then
# echo "WEIGHTS_STUDIO_API_TOKEN not set; skipping WeightsStudio trigger."
# exit 0
# fi

# # Trigger the ws-ci workflow in the weights_studio repository on main.
# curl -fSs -X POST "https://api.github.com/repos/GrayboxTech/weights_studio/actions/workflows/ws-ci.yml/dispatches" \
# -H "Authorization: Bearer ${WS_TOKEN}" \
# -H "Accept: application/vnd.github+json" \
# -H "Content-Type: application/json" \
# -d '{"ref":"main"}'

# echo "WeightsStudio workflow dispatch requested successfully."

build-and-publish-dev:
# Only publish to TestPyPI when pushing to main (not on PRs or dev branch pushes).
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
Expand All @@ -259,7 +240,7 @@ jobs:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: '3.11'

Expand Down Expand Up @@ -351,7 +332,7 @@ jobs:
contents: read
steps:
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: ${{ matrix.allow-prereleases || false }}
Expand Down
81 changes: 66 additions & 15 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,18 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: '3.11'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install . --extra-index-url https://download.pytorch.org/whl/cpu
# Install the test extra so pytest, graphviz, torchmetrics,
# pytorch-lightning and tensorboard are available (several test modules
# import pytest / use pytest fixtures and cannot run under bare unittest).
python -m pip install .[utest] --extra-index-url https://download.pytorch.org/whl/cpu
python -m pip install pytest-timeout

- name: Run tests
run: |
Expand All @@ -74,7 +78,7 @@ jobs:
with:
fetch-depth: 0

- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: '3.11'

Expand Down Expand Up @@ -108,7 +112,7 @@ jobs:
python -m twine upload --repository-url https://test.pypi.org/legacy/ --verbose dist/*

- name: Upload build artifacts for release
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: dev-release-dist
path: dist/
Expand All @@ -133,7 +137,7 @@ jobs:
permissions:
contents: read
steps:
- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: ${{ matrix.allow-prereleases || false }}
Expand Down Expand Up @@ -195,7 +199,7 @@ jobs:
fetch-depth: 0

- name: Download build artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v7
with:
name: dev-release-dist
path: dist/
Expand Down Expand Up @@ -226,7 +230,7 @@ jobs:

export PRS_JSON
PRS_JSON=$(gh pr list --state merged --base "dev" --limit 100 \
--json number,title,mergedAt,url,author,body \
--json number,title,mergedAt,url,author,body,commits \
2>/dev/null || echo "[]")

python3 << 'PYEOF'
Expand All @@ -249,6 +253,29 @@ jobs:
line += f"\n\n > {desc}"
return line
filtered = [pr for pr in prs_data if pr.get("mergedAt", "") > prev_date]
# "What's Changed precisely": list each merged PR's own developer commits,
# NOT the squashed/merge/chore commits that land on the release branch
# (those are redundant with the PR list above and not useful).
_seen_commits = set()
_commit_blocks = []
for pr in filtered:
_commit_lines = []
for c in (pr.get("commits") or []):
oid = (c.get("oid") or "")[:7]
head = (c.get("messageHeadline") or "").strip()
if not head or head.startswith("Merge "):
continue
key = (oid, head)
if key in _seen_commits:
continue
_seen_commits.add(key)
_commit_lines.append(f" - `{oid}` {head}")
if _commit_lines:
_commit_blocks.append(
f"**[#{pr['number']}]({pr['url']}) {pr['title']}**\n" + "\n".join(_commit_lines)
)
# Fall back to the raw git log only when no PR commits are available.
commits_section = "\n\n".join(_commit_blocks) if _commit_blocks else commits
if filtered:
prs_lines = "\n".join(_pr_entry(pr) for pr in filtered)
seen, clabels = set(), []
Expand Down Expand Up @@ -276,7 +303,7 @@ jobs:
"Happy Training!\n\n"
"---\n\n"
"### What's Changed precisely:\n\n"
f"{commits}\n\n"
f"{commits_section}\n\n"
"---\n\n"
"### Thank you!\n\n"
f"{contributors}\n"
Expand All @@ -303,7 +330,8 @@ jobs:

build-and-publish-main:
name: Build & Publish Main (PyPI)
needs: [detect-target]
needs: [detect-target,test]
# needs: [detect-target]
runs-on: ubuntu-latest
if: ${{ needs.detect-target.outputs.is_main == 'true' }}
permissions:
Expand All @@ -315,7 +343,7 @@ jobs:
with:
fetch-depth: 0

- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: '3.11'

Expand Down Expand Up @@ -349,7 +377,7 @@ jobs:
python -m twine upload dist/* --non-interactive --verbose

- name: Upload build artifacts for release
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: main-release-dist
path: dist/
Expand All @@ -367,7 +395,7 @@ jobs:
permissions:
contents: read
steps:
- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}

Expand Down Expand Up @@ -427,7 +455,7 @@ jobs:
fetch-depth: 0

- name: Download build artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@v7
with:
name: main-release-dist
path: dist/
Expand Down Expand Up @@ -458,7 +486,7 @@ jobs:

export PRS_JSON
PRS_JSON=$(gh pr list --state merged --base "main" --limit 100 \
--json number,title,mergedAt,url,author,body \
--json number,title,mergedAt,url,author,body,commits \
2>/dev/null || echo "[]")

python3 << 'PYEOF'
Expand All @@ -481,6 +509,29 @@ jobs:
line += f"\n\n > {desc}"
return line
filtered = [pr for pr in prs_data if pr.get("mergedAt", "") > prev_date]
# "What's Changed precisely": list each merged PR's own developer commits,
# NOT the squashed/merge/chore commits that land on the release branch
# (those are redundant with the PR list above and not useful).
_seen_commits = set()
_commit_blocks = []
for pr in filtered:
_commit_lines = []
for c in (pr.get("commits") or []):
oid = (c.get("oid") or "")[:7]
head = (c.get("messageHeadline") or "").strip()
if not head or head.startswith("Merge "):
continue
key = (oid, head)
if key in _seen_commits:
continue
_seen_commits.add(key)
_commit_lines.append(f" - `{oid}` {head}")
if _commit_lines:
_commit_blocks.append(
f"**[#{pr['number']}]({pr['url']}) {pr['title']}**\n" + "\n".join(_commit_lines)
)
# Fall back to the raw git log only when no PR commits are available.
commits_section = "\n\n".join(_commit_blocks) if _commit_blocks else commits
if filtered:
prs_lines = "\n".join(_pr_entry(pr) for pr in filtered)
seen, clabels = set(), []
Expand Down Expand Up @@ -508,7 +559,7 @@ jobs:
"Happy Training!\n\n"
"---\n\n"
"### What's Changed precisely:\n\n"
f"{commits}\n\n"
f"{commits_section}\n\n"
"---\n\n"
"### Thank you!\n\n"
f"{contributors}\n"
Expand Down
17 changes: 12 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,18 @@ ones when debugging:
| `WS_HISTOGRAM_MAX_BINS` | `512` | Cap on metadata histogram bars. |
| `BB_THUMB_RENDER` | `10` | Max bounding boxes drawn per **thumbnail**, per overlay (GT and PRED capped independently). |
| `BB_MODAL_RENDER` | `100` | Max bounding boxes drawn per **modal** image, per overlay. A `?` button in the modal shows the active limit. |

> **VITE_ vs WS_/BB_:** `VITE_*` variables are baked at **build time** (changing
> them needs a rebuild). `WS_*` / `BB_*` are injected at **container start** into
> `config.js` and read as `window.*` globals — changing them needs only a
> container restart + browser reload (see the caching note in §5).
| `ENABLE_PLOTS` | `1` | `0`/`false` removes the plots board + Signals card and stops plot auto-refresh. |
| `ENABLE_DATA_EXPLORATION` | `1` | `0`/`false` removes the data grid + metadata/details panel and stops the data/metadata auto-refresh. |
| `ENABLE_HYPERPARAMETERS_OPTIMIZATION` | `1` | `0`/`false` removes the Hyperparameters section, makes HP inputs read-only, and stops the HP poll. |
| `ENABLE_AGENT` | `1` | `0`/`false` removes the agent chat bar + history panel and stops the agent health poll. |

> **VITE_ vs WS_/BB_/ENABLE_:** `VITE_*` variables are baked at **build time**
> (changing them needs a rebuild). `WS_*` / `BB_*` / `ENABLE_*` are injected at
> **container start** into `config.js` and read as `window.*` globals (the
> toggles as `window.WS_ENABLE_*`) — changing them needs only a container restart
> + browser reload (see the caching note in §5). Each `ENABLE_*` defaults to on;
> set it to `0`/`false`/`no`/`off` to disable. Full reference:
> `weightslab/docs/configuration.rst` (“Feature toggles”).

---

Expand Down
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,29 @@ def main():

total_loss += loss.item()

# Write the history of these samples every x steps
if model.get_age() % 100 == 0:
print(f'Dump signals history and dataframe at age {model.get_age()}')
wl.write_history(
# path=None, # Use root_log_dir by default, filename generated from parameters md5 hash
type_of_history="all",
graph_name=[
'train/clsf_instance',
'val/clsf_instance'
],
# experiment_hash=None, Default is 'last', i.e., current experiment hash
sample_id=['11', '29', '28', '27', '22'],
instance_id=[1, 2, 3]
)

# Dump the sample dataframe: all signals plus the loss_shape categorical tag,
wl.write_dataframe(
columns=["signals", "tag:loss_shape"],
format='csv'
# sample_id=['0', '28']
# instance_id=[1, 2],
)

avg_loss = total_loss / len(dataloader)
print(f"Epoch {epoch+1}/5 - Loss: {avg_loss:.4f}")

Expand Down
Loading
Loading