Coming soon/api/model-swapping/

Swap the model, keep the workflow.

Bring your own detector, embedding extractor, InsightFace provider settings, or grouping algorithm while keeping Sort Moments' local folder workflow.

Python API status: coming soon.

These docs describe the intended package surface. Do not treat the PyPI install path as live until the package, wheel metadata, and import surface are verified. For now, use the CLI from source.

Swap the face detector

A detector can be an object with get(image_rgb) or a callable. Return objects compatible with FaceModel: bbox, det_score, and optionally embedding.

from sortmoments import DetectedFace, SortMomentsOrganizer

class MyDetector:
    def get(self, image_rgb):
        boxes = run_my_local_detector(image_rgb)
        return [DetectedFace(bbox=box, det_score=0.98) for box in boxes]

organizer = SortMomentsOrganizer(face_model=MyDetector())

Swap the embedding model

If your detector does not produce embeddings, supply a separate embedder. It can expose embed(image_rgb, face) or be a callable.

class MyEmbedder:
    def embed(self, image_rgb, face):
        crop = crop_face(image_rgb, face.bbox)
        return my_embedding_model.encode(crop)

Control the default InsightFace provider

organizer = SortMomentsOrganizer(SortMomentsConfig(
    model_name="buffalo_l",
    det_size=(512, 512),
    prefer_gpu=False,
))

Swap the grouping strategy

A grouping strategy receives FaceRecord objects. Use this to enforce stricter clustering, known identities, album-specific rules, or a completely different algorithm.

class MyGrouping:
    def group(self, face_records, similarity_threshold=0.5):
        groups = {}
        for record in face_records:
            person_id = assign_with_my_clusterer(record.embedding)
            groups.setdefault(person_id, []).append(record)
        return groups

Known-person matching

If you already have labeled reference embeddings, use a grouping model that compares every face to your known index before falling back to rename_N.

class KnownPeopleGrouping:
    def __init__(self, reference_embeddings):
        self.reference_embeddings = reference_embeddings

    def group(self, face_records, similarity_threshold=0.62):
        groups = {}
        for record in face_records:
            name, score = nearest_known_person(record.embedding, self.reference_embeddings)
            person_id = name if score >= similarity_threshold else "review_unknown"
            groups.setdefault(person_id, []).append(record)
        return groups

Debugging custom models

  • Set keep_intermediate=True so crops and embeddings stay on disk.
  • Start with a tiny folder of 5–10 images before batch processing thousands.
  • Use two-pass workflows to avoid rerunning detection while tuning grouping.
  • Use the CLI dry-run for path/config validation before launching expensive jobs.

Contract and privacy assumptions

Sort Moments is local-first. Custom models should stay local unless the user explicitly chooses a remote model. Do not silently upload photos or crops.
  • Detectors return face boxes in image pixel coordinates.
  • Embedders return numeric vectors or set face.embedding.
  • Grouping strategies return stable folder-safe person IDs.
  • Source images should not be mutated.