Package the models on every platform, not just the phone

The Android bundling landed the weights under that platform's asset directory,
which was the wrong home the moment a second packager wanted them. `makepkg -si`
produced a desktop install with no model at all — the same "no face model is
installed" the phone used to show, for the same reason: nothing put the files
anywhere the app looks.

So `models/face/` at the root is the one copy, and both packagers read it:
assemble-apk.sh bundles it as APK assets, and the PKGBUILD installs it to
/usr/share/darkroom/models. Both refuse an LFS pointer rather than shipping a
130-byte file that fails inside the graph loader on a user's machine.

`face_models` now searches three places, most specific first: the account's own
directory, the shared user directory, then $XDG_DATA_DIRS. So a packaged pair is
found automatically and a pair the user placed by hand still outranks it — which
is what keeps a deliberate choice of weights from being overridden by an
upgrade.

$XDG_DATA_DIRS rather than a hard-coded /usr/share: that is the variable a
distribution, a prefix install or a Nix-style store already sets to say where
its data went, and its documented default is exactly the two paths that would
otherwise have been hard-coded. Empty on Android, which has no such directories
— there the APK's copy is unpacked into the shared user directory instead,
because an asset inside a package is not a path anything can read from.

Verified: the APK still carries both models at assets/models/, the PKGBUILD
parses and installs from the new path, 467 tests pass.

Includes the pkgver 0.6.0 → 0.7.0 bump that was already sitting uncommitted in
the working tree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-27 18:05:23 +02:00
co-authored by Claude Opus 5
parent 725f7bf77f
commit 2d95807542
9 changed files with 101 additions and 45 deletions
@@ -1,25 +0,0 @@
# APK assets
`models/` holds the two face models, in LFS. `docker/android/assemble-apk.sh` copies them into the
APK and `android_main` unpacks them to the shared models directory on first launch, which is the only
way a phone can be handed a model at all — app-private storage has no user-reachable route into it,
and the in-app fetch docs/faces.md §2.2 specifies is unbuilt.
models/scrfd_500m_640.onnx 2.5 MB
models/arcface_mbf_b1.onnx 13 MB
**A clone without git-lfs gets a ~130-byte pointer file where each model should be.** `assemble-apk.sh`
checks for exactly that and refuses, rather than bundling the pointer and failing inside tract on the
device — the same guard `dr-segment`'s build script applies to `yolo26n-seg.onnx`. Fix it with
`git lfs pull`.
These are not what InsightFace ships. They came from `buffalo_sc.zip` and `buffalo_s.zip` on the
InsightFace v0.7 release with their input dimensions pinned, because tract cannot parse either graph
while they are dynamic:
./tools/fix-face-model-shapes.sh det_500m.onnx models/scrfd_500m_640.onnx --input input.1=1,3,640,640
./tools/fix-face-model-shapes.sh w600k_mbf.onnx models/arcface_mbf_b1.onnx --dim None=1
The weights carry a non-commercial research-only grant. They are here because this is a private
repository and a self-installed build; they come back out before anything is published, and the
restriction binds whoever uses the app, not only the project. docs/faces.md §2.2a is the decision.