The cross-source study needs two 4K recordings and a hand-sorted set of face crops, neither of which belongs in git. Adds an xsource target to both artifact scripts. Push uploads the clips as-is (already compressed) and zips labelling/. Pull fetches both and regenerates frames with ffmpeg rather than downloading them: ~320 MB of PNG that is deterministic from the clips. The extraction settings are pinned in the script, not left to the caller, because the manifests key on frame filenames and on detection order within each frame — verify_labels.py runs afterwards and fails loudly if they drift. Pull refuses to overwrite an existing labelling/. It is human ground truth: somebody looked at 167 crops and placed each one, and silently replacing that with a remote copy would destroy the expensive half of the study. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> TRACES: VR-013
189 lines
7.3 KiB
Bash
Executable File
189 lines
7.3 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]
|
|
# scripts/artifacts/pull_artifacts.sh report-highlights <name> [version]
|
|
# scripts/artifacts/pull_artifacts.sh xsource [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"
|
|
}
|
|
|
|
pull_report_highlight() {
|
|
local version="$1" name="$2"
|
|
local dest="${REPO_ROOT}/docs/assets/images"
|
|
mkdir -p "$dest"
|
|
echo "=== report-highlights/${name} (version ${version}) ==="
|
|
curl -sf "${DL_BASE}/generic/report-highlights/${version}/${name}" -o "${dest}/${name}"
|
|
}
|
|
|
|
pull_xsource() {
|
|
local version="$1"
|
|
local dest="${REPO_ROOT}/experiments/xsource"
|
|
echo "=== xsource (version ${version}) ==="
|
|
mkdir -p "${dest}/clips" "${dest}/frames"
|
|
|
|
for clip in 5157339 5157344; do
|
|
if [ -f "${dest}/clips/${clip}.mp4" ]; then
|
|
echo " ${clip}.mp4 already present, skipping"
|
|
else
|
|
echo " fetching ${clip}.mp4..."
|
|
curl -sf "${DL_BASE}/generic/xsource/${version}/${clip}.mp4" \
|
|
-o "${dest}/clips/${clip}.mp4" \
|
|
|| { echo " [warn] ${clip}.mp4 not found at version ${version}" >&2; continue; }
|
|
fi
|
|
done
|
|
|
|
if [ -d "${dest}/labelling" ]; then
|
|
echo " labelling/ already present — NOT overwriting (it is hand-sorted"
|
|
echo " ground truth; move it aside first if you really want the remote copy)"
|
|
else
|
|
echo " fetching labelling.zip..."
|
|
local tmp; tmp="$(mktemp)"
|
|
curl -sf "${DL_BASE}/generic/xsource/${version}/labelling.zip" -o "$tmp"
|
|
unzip -qo "$tmp" -d "$dest"
|
|
rm "$tmp"
|
|
fi
|
|
|
|
# Frames are regenerated rather than shipped: they are ~320 MB of PNG that
|
|
# ffmpeg reproduces exactly from the clips. The manifests key on these
|
|
# filenames and on detection order within each frame, so the extraction
|
|
# settings must match the ones dump_faces.py ran against — hence fps and
|
|
# frame count are pinned here rather than left to the caller.
|
|
if ! command -v ffmpeg >/dev/null; then
|
|
echo " [warn] ffmpeg not found — frames not regenerated; the study" >&2
|
|
echo " scripts will fail until you extract them" >&2
|
|
return
|
|
fi
|
|
for clip in 5157339 5157344; do
|
|
[ -f "${dest}/clips/${clip}.mp4" ] || continue
|
|
if [ -f "${dest}/frames/d${clip}_001.png" ]; then
|
|
echo " frames for ${clip} already present, skipping"
|
|
continue
|
|
fi
|
|
echo " extracting frames for ${clip}..."
|
|
ffmpeg -v error -i "${dest}/clips/${clip}.mp4" -vf fps=2 -frames:v 24 \
|
|
"${dest}/frames/d${clip}_%03d.png"
|
|
done
|
|
|
|
echo " verifying the labelled set..."
|
|
if (cd "$dest" && python3 verify_labels.py >/dev/null 2>&1); then
|
|
echo " verify_labels.py passed"
|
|
else
|
|
echo " [warn] verify_labels.py failed — run it directly to see why." >&2
|
|
echo " A frame/manifest mismatch means the extraction settings" >&2
|
|
echo " differ from the ones the crops were dumped against." >&2
|
|
fi
|
|
}
|
|
|
|
if [ $# -eq 0 ]; then
|
|
echo "usage: $0 galleries [version]" >&2
|
|
echo " $0 montage-frames <film-slug> [version]" >&2
|
|
echo " $0 experiment-data [version]" >&2
|
|
echo " $0 report-highlights <name> [version]" >&2
|
|
echo " $0 xsource [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"
|
|
;;
|
|
report-highlights)
|
|
NAME="${2:?usage: $0 report-highlights <name> [version]}"
|
|
VERSION="${3:-latest}"
|
|
[ "$VERSION" = "latest" ] && VERSION="$(resolve_latest_version report-highlights)"
|
|
pull_report_highlight "$VERSION" "$NAME"
|
|
;;
|
|
xsource)
|
|
VERSION="${2:-latest}"
|
|
[ "$VERSION" = "latest" ] && VERSION="$(resolve_latest_version xsource)"
|
|
pull_xsource "$VERSION"
|
|
;;
|
|
*)
|
|
echo "unknown target: $TARGET (expected galleries, montage-frames, experiment-data, report-highlights, or xsource)" >&2
|
|
exit 1
|
|
;;
|
|
esac
|