Files
scene-actor-extraction/scripts/artifacts/pull_artifacts.sh
T
dtourolle 6f0ad83a55 feat(tooling): X-Ray threshold optimizer, gallery utilities, artifact registry, docs build
Optimizer (scripts/optimizer/): replay.py runs the real C++ tracker/matcher/
scene_tracker chain over a dumped-embeddings HDF5 via sae_kpn, so a threshold
sweep never re-decodes video or re-embeds faces. optimize.py drives scipy's
differential_evolution over the knob space, with DE-level parallelism
(multiple population candidates evaluated concurrently via a ThreadPoolExecutor)
on top of per-film replay parallelism. second_score.py is the per-second X-Ray
scoring metric (TPI/FPI/FN, out-of-cast misID weighted 10x, fair recall masked
to gallery-known cast) that superseded an earlier scene-union metric.
dump_error_frames.py / dump_scene_montage.py extract annotated video frames
(bounding boxes, TPI/FPI/FN captions, onscreen-vs-offscreen split) for visual
review of a replay against ground truth. Gallery utilities: cast_restrict.py,
gallery_membership.py, fetch_missing_actors.py, reembed_gallery.py.

scripts/validation/: X-Ray ground-truth loading and provider-agnostic identity
matching (identity.py's keys_for — an actor is the union of every id we can
derive, since pipeline output and ground truth don't share one id space).

scripts/artifacts/: push/pull scripts for the Gitea generic package registry —
galleries, montage frames, and experiment data (manifests/trajectories/results)
are pushed there instead of committed, since none are needed to run the app,
only benchmarks. Versioned by git short-SHA.

scripts/docs/: MkDocs site build (build_site.sh) and the calibration-curve
comparison chart (calibration_chart.py, matplotlib, reads each gallery's
embedded calibration).

Gallery-building scripts (make_jellyfin_gallery.py, make_gallery.py,
filter_gallery.py, run_from_jellyfin.py, movienet_eval.py, movienet_prep.py,
sae_gallery.py) updated to read/write HDF5 galleries exclusively, matching the
engine-side format switch. run_from_jellyfin.py and the optimizer no longer
carry movie source paths in shared manifests (some source filenames include
scene-release tags) — resolved locally via a gitignored file-lut.json instead.
2026-07-19 19:06:48 +02:00

107 lines
3.9 KiB
Bash
Executable File

#!/bin/bash
# pull_artifacts.sh — download benchmark artifacts (galleries, montage frames) from
# the Gitea generic package registry. Counterpart to push_artifacts.sh.
#
# Downloads are public (no token needed) as long as the repo/packages are public.
# Resolving "latest" needs GITEA_TOKEN (the list-packages endpoint requires auth
# on this instance even for a public account) — export it before using "latest".
#
# Usage:
# scripts/artifacts/pull_artifacts.sh galleries [version]
# scripts/artifacts/pull_artifacts.sh montage-frames <film-slug> [version]
# scripts/artifacts/pull_artifacts.sh experiment-data [version]
# version defaults to "latest" (newest uploaded version, by created_at).
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
OWNER="dtourolle"
# NOTE: file download lives under /api/packages/ (no /v1/); listing/metadata
# lives under the regular /api/v1/packages/ REST API. Different base paths,
# both real — see push_artifacts.sh's comment.
DL_BASE="https://gitea.tourolle.paris/api/packages/${OWNER}"
resolve_latest_version() {
local package="$1"
if [ -z "${GITEA_TOKEN:-}" ]; then
echo "error: resolving 'latest' needs GITEA_TOKEN (list-packages requires auth here)." >&2
echo " export GITEA_TOKEN=... or pass an explicit version instead of 'latest'." >&2
exit 1
fi
curl -sf "https://gitea.tourolle.paris/api/v1/packages/${OWNER}" \
-H "Authorization: token ${GITEA_TOKEN}" \
| python3 -c "
import json, sys
d = json.load(sys.stdin)
matches = [p for p in d if p['name'] == '$package' and p['type'] == 'generic']
if not matches:
sys.exit('no versions found for package \'$package\'')
matches.sort(key=lambda p: p['created_at'])
print(matches[-1]['version'])
"
}
pull_galleries() {
local version="$1"
local dest="${REPO_ROOT}/experiments/galleries"
mkdir -p "$dest"
echo "=== galleries (version ${version}) ==="
for model in arcface_w600k_r50 arcface_r18 arcface_w600k_mbf LVFace-B_Glint360K; do
local f="gallery_${model}.h5"
echo " fetching ${f}..."
curl -sf "${DL_BASE}/generic/galleries/${version}/${f}" \
-o "${dest}/${f}" || echo " [warn] ${f} not found at version ${version}"
done
}
pull_montage_frames() {
local version="$1" film="$2"
local dest="${REPO_ROOT}/experiments/results/holdout/montage_bestworst"
mkdir -p "$dest"
echo "=== montage-frames/${film} (version ${version}) ==="
local tmp; tmp="$(mktemp)"
curl -sf "${DL_BASE}/generic/montage-frames/${version}/${film}.zip" -o "$tmp"
mkdir -p "${dest}/${film}"
unzip -qo "$tmp" -d "${dest}/${film}"
rm "$tmp"
}
pull_experiment_data() {
local version="$1"
echo "=== experiment-data (version ${version}) ==="
local tmp; tmp="$(mktemp)"
curl -sf "${DL_BASE}/generic/experiment-data/${version}/experiment-data.zip" -o "$tmp"
unzip -qo "$tmp" -d "$REPO_ROOT"
rm "$tmp"
}
if [ $# -eq 0 ]; then
echo "usage: $0 galleries [version]" >&2
echo " $0 montage-frames <film-slug> [version]" >&2
echo " $0 experiment-data [version]" >&2
exit 1
fi
TARGET="$1"
case "$TARGET" in
galleries)
VERSION="${2:-latest}"
[ "$VERSION" = "latest" ] && VERSION="$(resolve_latest_version galleries)"
pull_galleries "$VERSION"
;;
montage-frames)
FILM="${2:?usage: $0 montage-frames <film-slug> [version]}"
VERSION="${3:-latest}"
[ "$VERSION" = "latest" ] && VERSION="$(resolve_latest_version montage-frames)"
pull_montage_frames "$VERSION" "$FILM"
;;
experiment-data)
VERSION="${2:-latest}"
[ "$VERSION" = "latest" ] && VERSION="$(resolve_latest_version experiment-data)"
pull_experiment_data "$VERSION"
;;
*)
echo "unknown target: $TARGET (expected galleries, montage-frames, or experiment-data)" >&2
exit 1
;;
esac