mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-31 13:38:14 -06:00
Faces: nothing is bundled, so YuNet is not reported as installed
The model list marked the YuNet detector as bundled with LightCraft and installed, but no model ships inside LightCraft (the weights are opt-in downloads or files the user adds). Drop the notion: a model is installed when its folder is, it can be removed like any other, and the licence notice no longer says it is bundled. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
cb34bb4842
commit
7845d515e8
@@ -88,7 +88,6 @@ fn installed_models(dir: &Path) -> Vec<Installed> {
|
||||
}
|
||||
|
||||
fn row(m: &ModelManifest, installed: bool, selected: bool, accepted: &Value) -> Value {
|
||||
let bundled = known::BUNDLED.contains(&m.id.as_str());
|
||||
json!({
|
||||
"id": m.id,
|
||||
"name": m.name,
|
||||
@@ -99,8 +98,7 @@ fn row(m: &ModelManifest, installed: bool, selected: bool, accepted: &Value) ->
|
||||
"sizeBytes": m.size_bytes,
|
||||
"sha256": m.sha256,
|
||||
"known": known::all().iter().any(|k| k.id == m.id),
|
||||
"bundled": bundled,
|
||||
"installed": installed || bundled,
|
||||
"installed": installed,
|
||||
"selected": selected,
|
||||
"accepted": accepted,
|
||||
})
|
||||
@@ -192,9 +190,6 @@ fn install(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
Suggestion::Known(m) | Suggestion::Draft { manifest: m, .. } => m,
|
||||
Suggestion::Unsupported(why) => return Err(bad(C, format!("this model cannot be used yet: {why}"))),
|
||||
};
|
||||
if known::BUNDLED.contains(&m.id.as_str()) {
|
||||
return Err(bad(C, "this model is already included with LightCraft"));
|
||||
}
|
||||
if m.role != Role::Embedder {
|
||||
return Err(bad(C, "only face recognition models can be installed for now"));
|
||||
}
|
||||
@@ -228,9 +223,6 @@ fn remove(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
if !manifest::valid_id(id) {
|
||||
return Err(bad(C, "not a model id"));
|
||||
}
|
||||
if known::BUNDLED.contains(&id) {
|
||||
return Err(bad(C, "this model is part of LightCraft and cannot be removed"));
|
||||
}
|
||||
let home = dir.join(id);
|
||||
// only a folder that is a model (it has a manifest) is ever deleted
|
||||
if !home.join("face-model.json").is_file() {
|
||||
@@ -274,7 +266,7 @@ fn enable(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
|
||||
pub fn specs() -> Vec<CommandSpec> {
|
||||
vec![
|
||||
cmd!(query "faces.models.list", "Face Models", [], None, "{} → {dir, enabled, embedder, runtime, models: [{id, name, role, licence{name, commercial, url, notice}, provenance, source, sizeBytes, known, bundled, installed, selected}]}", always, list),
|
||||
cmd!(query "faces.models.list", "Face Models", [], None, "{} → {dir, enabled, embedder, runtime, models: [{id, name, role, licence{name, commercial, url, notice}, provenance, source, sizeBytes, known, installed, selected}]}", always, list),
|
||||
cmd!(query "faces.models.inspect", "Inspect Face Model File", [], None, "{path} → what a .onnx file is: {kind: known | draft | unsupported, model, assumptions, reason, alreadyInstalled}; installs nothing", always, inspect),
|
||||
cmd!(query "faces.models.install", "Install Face Model", [], None, "{path, acknowledged: true} — copy a .onnx face recognition model into the models folder. `acknowledged` must be true: the user has been shown its licence (see inspect) and accepted it", always, install),
|
||||
cmd!(query "faces.models.remove", "Remove Face Model", [], None, "{id} — delete an installed model", always, remove),
|
||||
|
||||
@@ -37,8 +37,7 @@ fn the_list_knows_the_known_models_and_is_honest_about_the_runtime() {
|
||||
let l = s.execute("faces.models.list", &json!({})).unwrap();
|
||||
assert_eq!(l["enabled"], false);
|
||||
assert_eq!(l["runtime"], false);
|
||||
assert_eq!(find(&l, "yunet-2023mar")["bundled"], true);
|
||||
assert_eq!(find(&l, "yunet-2023mar")["installed"], true);
|
||||
assert_eq!(find(&l, "yunet-2023mar")["installed"], false, "nothing ships with LightCraft");
|
||||
assert_eq!(find(&l, "auraface-v1")["installed"], false);
|
||||
assert_eq!(find(&l, "auraface-v1")["licence"]["commercial"], "yes");
|
||||
assert_eq!(find(&l, "sface-2021dec")["licence"]["commercial"], "unknown");
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
//! The models LightCraft recognises by their SHA-256, with what is honestly known about each.
|
||||
//!
|
||||
//! The licence and provenance texts here are what the user reads before enabling a model, so they say what
|
||||
//! is *not* known too. Weights are never bundled except where the bundling decision says so (the YuNet
|
||||
//! detector, 232 KB, MIT); everything else is an opt-in the user installs themselves.
|
||||
//! is *not* known too. Weights are never part of LightCraft: every model is an opt-in the user installs.
|
||||
|
||||
use crate::manifest::{Colour, Commercial, InputSpec, Licence, ModelManifest, OutputSpec, Resize, Role, Thresholds};
|
||||
|
||||
/// Detector output decoders built into LightCraft.
|
||||
pub const DECODERS: &[&str] = &["yunet-v2"];
|
||||
|
||||
/// Models that ship inside LightCraft (they are not installed by the user).
|
||||
pub const BUNDLED: &[&str] = &["yunet-2023mar"];
|
||||
|
||||
pub const YUNET_SHA256: &str = "8f2383e4dd3cfbb4553ea8718107fc0423210dc964f9f4280604804ed2552fa4";
|
||||
pub const SFACE_SHA256: &str = "0ba9fbfa01b5270c96627c4ef784da859931e02f04419c829e83484087c34e79";
|
||||
pub const AURAFACE_SHA256: &str = "a7933ea5330113b01c9b60351d8f4c33003f145d8470ac5f0e52ee2effe25c60";
|
||||
@@ -20,7 +16,7 @@ fn licence(name: &str, commercial: Commercial, url: &str, notice: &str) -> Licen
|
||||
Licence { name: name.into(), commercial, url: Some(url.into()), notice: notice.into() }
|
||||
}
|
||||
|
||||
/// YuNet 2023mar (OpenCV Zoo): the face detector LightCraft bundles.
|
||||
/// YuNet 2023mar (OpenCV Zoo): a small face detector.
|
||||
pub fn yunet() -> ModelManifest {
|
||||
ModelManifest {
|
||||
id: "yunet-2023mar".into(),
|
||||
@@ -31,7 +27,7 @@ pub fn yunet() -> ModelManifest {
|
||||
"MIT",
|
||||
Commercial::Yes,
|
||||
"https://github.com/opencv/opencv_zoo/blob/main/models/face_detection_yunet/LICENSE",
|
||||
"MIT licence, copyright Shiqi Yu. Bundled with LightCraft.",
|
||||
"MIT licence, copyright Shiqi Yu.",
|
||||
),
|
||||
source: Some("https://github.com/opencv/opencv_zoo/tree/main/models/face_detection_yunet".into()),
|
||||
sha256: Some(YUNET_SHA256.into()),
|
||||
|
||||
@@ -145,13 +145,11 @@ fn model_row(app: &mut LightcraftApp, ui: &mut egui::Ui, t: &Tokens, m: &Value)
|
||||
});
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
if installed {
|
||||
if m["bundled"] != true {
|
||||
let r = ui.button("Remove");
|
||||
register(ui.ctx(), format!("faces:remove:{id}"), r.rect);
|
||||
if r.clicked() {
|
||||
let _ = app.run("faces.models.remove", json!({"id": id}));
|
||||
app.caches.faces_epoch += 1;
|
||||
}
|
||||
let r = ui.button("Remove");
|
||||
register(ui.ctx(), format!("faces:remove:{id}"), r.rect);
|
||||
if r.clicked() {
|
||||
let _ = app.run("faces.models.remove", json!({"id": id}));
|
||||
app.caches.faces_epoch += 1;
|
||||
}
|
||||
if !selected {
|
||||
let r = ui.button("Use");
|
||||
|
||||
Reference in New Issue
Block a user