diff options
| author | Ken D'Ambrosio <ken@jots.org> | 2026-06-09 13:09:23 +0000 |
|---|---|---|
| committer | Ken D'Ambrosio <ken@jots.org> | 2026-06-09 13:09:23 +0000 |
| commit | c13a40a970be156a231200c20362636b198d32ec (patch) | |
| tree | 9e7c0103d861bbd4dd5877d244431ca5ae07327f /scripts | |
| parent | cf1385bbd6d88a8db9f615512564e150c85a0b5f (diff) | |
Add face pool, blacklisting, and action explanations to people admin
Removed faces now go to an "Unidentified pool" cluster rather than
disappearing. Deleting a cluster blacklists all its members so they are
skipped by future re-clustering runs. Pool faces can be assigned to a
named person or individually blacklisted. A plain-English info box on
the detail page explains what each action does and that no photo files
are ever modified.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/cluster_faces.py | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/scripts/cluster_faces.py b/scripts/cluster_faces.py index 92c64fe..a9492a9 100644 --- a/scripts/cluster_faces.py +++ b/scripts/cluster_faces.py @@ -35,7 +35,24 @@ MEDIA_ROOT = os.environ.get('MEDIA_ROOT', '/var/albumen') def collect_faces(media_root): - """Return list of {rel, box, encoding} for all processed face instances.""" + """Return list of {rel, box, encoding} for all processed face instances. + + Faces that are in the pool or blacklist in people.json are skipped — + the user has explicitly handled them and they should not be re-clustered. + """ + skip = set() + people_path = os.path.join(media_root, 'people.json') + if os.path.exists(people_path): + try: + pd = json.load(open(people_path)) + for entry in pd.get('blacklist', []): + skip.add((entry['rel'], tuple(entry['box']))) + pool = pd.get('people', {}).get('__pool__', {}) + for m in pool.get('members', []): + skip.add((m['rel'], tuple(m['box']))) + except Exception: + pass + faces = [] for path in sorted(glob.glob(os.path.join(media_root, '**', 'faces.json'), recursive=True)): dir_abs = os.path.dirname(path) @@ -53,6 +70,8 @@ def collect_faces(media_root): if not enc or not box or len(enc) != 128: continue rel = f"{dir_rel}/{filename}" if dir_rel else filename + if (rel, tuple(box)) in skip: + continue faces.append({'rel': rel, 'box': box, 'encoding': enc}) return faces |
