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:
+38
-5
@@ -2934,17 +2934,50 @@ pub fn shared_face_models_dir() -> PathBuf {
|
||||
/// `tools/fix-face-model-shapes.sh` has to run over the originals first,
|
||||
/// because tract cannot parse either graph with a dynamic input.
|
||||
///
|
||||
/// The per-account directory wins over the shared one so a library can be
|
||||
/// pinned to its own weights — a re-index after a model swap is a `model_id`
|
||||
/// change, and someone mid-migration needs the old pair to stay put for one
|
||||
/// account without holding back the other.
|
||||
/// Searched in three places, most specific first:
|
||||
///
|
||||
/// 1. **The account's own directory.** A library can be pinned to its own
|
||||
/// weights — a model swap is a `model_id` change and a re-index, and someone
|
||||
/// mid-migration needs one account's pair to stay put without holding the
|
||||
/// other back.
|
||||
/// 2. **The shared user directory.** Where a user drops a pair by hand, and
|
||||
/// where the Android entry point unpacks the copy the APK carries.
|
||||
/// 3. **The system directories.** Where a package installs them — the Arch
|
||||
/// package puts the pair in `/usr/share/darkroom/models`. Last, so anything
|
||||
/// the user placed themselves outranks what the package shipped.
|
||||
pub fn face_models(server: &str, user_id: &str) -> Option<(PathBuf, PathBuf)> {
|
||||
fn pair(dir: PathBuf) -> Option<(PathBuf, PathBuf)> {
|
||||
let detector = dir.join("scrfd_500m_640.onnx");
|
||||
let embedder = dir.join("arcface_mbf_b1.onnx");
|
||||
(detector.is_file() && embedder.is_file()).then_some((detector, embedder))
|
||||
}
|
||||
pair(face_models_dir(server, user_id)).or_else(|| pair(shared_face_models_dir()))
|
||||
pair(face_models_dir(server, user_id))
|
||||
.or_else(|| pair(shared_face_models_dir()))
|
||||
.or_else(|| system_face_models_dirs().into_iter().find_map(pair))
|
||||
}
|
||||
|
||||
/// Where a *package* may have installed the models.
|
||||
///
|
||||
/// `$XDG_DATA_DIRS` rather than a hard-coded `/usr/share`, because that is the
|
||||
/// variable a distribution, a prefix install, or a Nix-style store sets to say
|
||||
/// where its data went, and the default it falls back to is exactly the pair of
|
||||
/// 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 (ARCH §6.9).
|
||||
fn system_face_models_dirs() -> Vec<PathBuf> {
|
||||
if cfg!(target_os = "android") {
|
||||
return Vec::new();
|
||||
}
|
||||
let dirs = std::env::var("XDG_DATA_DIRS")
|
||||
.ok()
|
||||
.filter(|v| !v.is_empty())
|
||||
.unwrap_or_else(|| "/usr/local/share:/usr/share".into());
|
||||
dirs.split(':')
|
||||
.filter(|d| !d.is_empty())
|
||||
.map(|d| PathBuf::from(d).join("darkroom").join("models"))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// One grid cell's data, read from the catalog.
|
||||
|
||||
Reference in New Issue
Block a user