ARCHITECTURE

Architecture

Trois conteneurs principaux, plus un service mDNS, sans courtier de messages séparé ni service cloud obligatoire. Les photos sont importées par envoi ou depuis des dossiers du NAS, puis traitées pour les métadonnées, les miniatures, les vecteurs sémantiques, les visages et le texte. Le résultat : une photothèque interrogeable en langage naturel, par personne et par lieu.

3 + 1conteneurs

Backend Go, service IA et PostgreSQL, plus un service mDNS qui annonce le domaine local

5types de tâches

metadata, thumbnail, clip, face, ocr

512–1024dimensions

Vecteurs image-texte Chinese-CLIP (512, 768 ou 1024 selon le niveau de modèles) ; les empreintes de visage ArcFace font 512 dimensions

HNSWindex vectoriel

Index pgvector en distance cosinus ; recherche et comparaison des visages se font dans la base

SYSTEM

Architecture du système

Le navigateur ne parle qu’au backend Go. Celui-ci gère les imports, l’ordonnancement des tâches, les miniatures et les droits, envoie les aperçus au service IA pour l’inférence et écrit tous les résultats dans PostgreSQL. Le service IA est sans état : il n’accède jamais à la base et ne stocke aucun fichier, il peut donc tourner sur une machine plus puissante.

CLIENTSNavigateur de bureauApplication web intégrée au binaire GoNavigateur mobileiPhone · Androidwanmory.localDomaine local, aucune IP à retenirHTTP :8080DOCKER COMPOSEBackend Go · serverAPI, imports, file de tâches, miniatures, droits, app webAPI RESTImports tusWorkers de tâchesComptes · ConnexionsMiniatures libvipsMétadonnées ExifToolVidéo FFmpegGéocodage (option)Albums · IntelligentsRafales · SimilairesSélection IA · Ce jourScan toutes 15 minmdnsAnnonce wanmory.localService IA · mlFastAPI + ONNX Runtime / PyTorch, sans étatDétection SCRFDEmpreintes ArcFaceChinese-CLIPTexte PP-OCRPostgreSQL 17 + pgvectorDonnées, file de tâches et vecteurs dans une seule base, sans Redisassetsfaces · peoplefile jobssettingsindex HNSWSQL/predict · aperçus 1440 pxSTOCKAGE · EXTENSIONS/dataOriginaux importés, miniatures, aperçus 1440 px/photos/* (lecture seule :ro possible)Dossiers photo existants du NAS, autant que voulu./modelsFichiers de modèles, téléchargés depuis les réglages webService IA distant (optionnel)Mac (CoreML / MPS) · NVIDIA CUDAAuthentification par jeton, aperçus 1440 px uniquement, jamais les originauxlecture/écriturescan · lecture seulechargementHTTP + jeton
Le backend est un seul binaire Go

L’application web est intégrée au binaire : le déploiement ne nécessite pas Node. Les migrations de la base s’exécutent automatiquement au démarrage, et mettre à jour revient à changer d’image.

Le service IA peut tourner ailleurs

Le service IA intégré tourne sur le réseau interne de Docker et calcule sur le processeur. Saisissez une adresse distante dans les réglages web pour passer à un PC avec carte graphique ou à un Mac à la maison.

Une seule base pour toutes les données

Informations des photos, personnes, réglages, file de tâches et vecteurs sont tous dans PostgreSQL : les données applicatives et l’état des tâches peuvent être sauvegardés ensemble. Les fichiers photo nécessitent une sauvegarde à part.

PIPELINE

Pipeline de traitement des photos

Après l’import, chaque photo voit d’abord ses métadonnées extraites et ses miniatures générées, puis ses vecteurs sémantiques, visages et textes sont calculés en parallèle. Chaque étape est mise en file séparément : un redémarrage ou une panne du service IA ne fait perdre aucune tâche, et le traitement reprend ensuite.

01ingest
Import
  • Imports web via tus, reprise après coupure
  • Dossiers /photos analysés toutes les 15 minutes
  • Somme SHA-1 calculée et enregistrée dans assets
Backend
02metadata
Métadonnées
  • ExifTool lit dimensions et date de prise
  • GPS, appareil, objectif, ouverture et vitesse
  • Heures sans fuseau : fuseau configuré
Backend
03thumbnail
Miniatures
  • libvips génère les miniatures
  • Puis un aperçu de 1440 px
  • FFmpeg extrait les images et transcode les vidéos
Backend
04clip
Vecteurs
  • Chinese-CLIP calcule des vecteurs 1024-d
  • Recherche en langage naturel, catégories
  • Note esthétique, photos similaires
IA · parallèle
05face
Visages
  • SCRFD détecte et aligne sur 5 points
  • ArcFace calcule des empreintes 512-d
  • Regroupement progressif en personnes
IA · parallèle
06ocr
Texte
  • PP-OCR lit le texte des photos
  • Rechercher des photos par leur texte
  • Repère papiers, documents, captures
IA · parallèle
SCHEDULING

Ordonnancement des tâches de fond

Pas de courtier de messages séparé : la file de tâches est une table jobs dans PostgreSQL, écrite dans la même transaction que les données de la photo. Une photo enregistrée a donc toujours ses tâches en file. Les workers prennent les tâches avec SKIP LOCKED, un bail évite les blocages, et les échecs sont relancés avec un délai quadratique.

pendingen attenterunningprise par un workerdoneterminéefailedessais épuisésprise avec SKIP LOCKEDsuccèsrelances épuiséeséchec : relance après n² × 30 sIA injoignable : relance dans 15 s, sans compter d’échecBail de 10 min : sans résultat à temps, récupérée toutes les 30 s et remise en pending
jobs/worker.go · claim
-- Prendre une tâche (server/internal/jobs/worker.go)
UPDATE jobs SET status = 'running', attempts = attempts + 1,
       locked_by = $1, locked_until = now() + $2::interval
WHERE id = (
  SELECT id FROM jobs
  WHERE status = 'pending' AND run_after <= now() AND type = ANY($3)
  ORDER BY priority DESC, run_after
  FOR UPDATE SKIP LOCKED   -- des workers simultanés ne prennent jamais la même
  LIMIT 1
)
RETURNING id, type, asset_id, payload, attempts, max_attempts;
Règles d’ordonnancement
  • Une tâche du même type pour la même photo n’est jamais mise en file deux fois tant qu’une autre attend ou s’exécute.
  • Une file vide est consultée chaque seconde ; les tâches sont prises par priorité décroissante, puis par échéance la plus proche.
  • Le bail de chaque tâche (qui sert aussi de délai maximal) est de 10 minutes ; au redémarrage, un processus remet en file ses propres tâches inachevées.
Priorités et régulation
  • Pendant qu’une personne importe des photos, plus aucune tâche IA n’est prise afin de laisser la bande passante et le processeur à l’import.
  • Quand le service IA est injoignable, tout le worker IA se met en pause au lieu de prendre les tâches une à une pour les faire échouer et gaspiller les relances.
  • Le niveau « Automatique » détecte d’abord le matériel du serveur IA et choisit des modèles adaptés avant de prendre des tâches, ce qui aide à éviter de charger sur un Raspberry Pi ou un appareil similaire des modèles qui dépassent la mémoire disponible.
AI SCHEDULING

Pilotage de l’IA

Le service IA reçoit uniquement des aperçus et renvoie visages, vecteurs et texte. Le backend décide de l’adresse du service, des modèles et du parallélisme ; le service IA choisit CUDA, CoreML / MPS, OpenVINO ou le processeur selon son matériel.

File de tâches IAclip · face · ocrParallélisme selon les réglages, régulation ajustableBackend Go · client IAChoisit service et niveau, vérifie model_ids· Vérifie /health toutes les 15 s· Injoignable → tâches en attente· Niveau auto → selon le matérielpriseService IA intégréRéseau interne Docker · CPUService IA distantMac ou PC à carte graphiqueNœud de travail distantPrend lui-même des tâches (prévu)l’un ou l’autreCPUONNX RuntimeCoreML / MPS · CUDAChoisit l’accélération disponibleOpenVINOGPU intégré Intel
Trois niveaux de modèles

En « Automatique », le niveau dépend du matériel du serveur IA : Précision avec une carte graphique exploitable ; sur processeur seul, Léger sous 6 Go de mémoire et Équilibré à partir de 6 Go.

NiveauMatériel adaptéVisagesRecherche sémantique
quality · PrécisionMac Apple Silicon, GPU NVIDIASCRFD-10G + ArcFace R100 (antelopev2)Chinese-CLIP ViT-H/14 · 1024-d
balanced · ÉquilibréNAS de classe Intel i5SCRFD-10G + ArcFace R100 (antelopev2)Chinese-CLIP ViT-L/14 · 768-d
lite · LégerN100, Raspberry Pi 5SCRFD + ArcFace R50 (buffalo_l)Chinese-CLIP ViT-B/16 · 512-d
API du service IA · /predict
POST /predict   (multipart: image + tasks)
Authorization: Bearer <jeton>

tasks = {
  "face": {"model": "antelopev2", "min_score": 0.5},
  "clip": {"model": "chinese-clip-vit-h-14"},
  "ocr":  {}
}

→ {
  "face": [{"box": [x, y, w, h], "score": 0.93,
            "embedding": [512 nombres], "yaw": 0.12, "blur": 340}],
  "clip": {"embedding": [1024 nombres]},
  "ocr":  {"text": "...", "lines": [...]},
  "model_ids": {"face": "antelopev2", "clip": "chinese-clip-vit-h-14"}
}
ALGORITHMS

Algorithmes clés

Les modèles, algorithmes et seuils derrière la recherche, les personnes, les rafales et la sélection IA. Certains reposent sur des modèles d’IA, d’autres sur du calcul vectoriel et des règles.

Recherche en langage naturel

Chinese-CLIP place photos et texte dans le même espace vectoriel. Les vecteurs d’image sont calculés à l’import ; au moment de la recherche, une phrase comme « troisième anniversaire de bébé » devient un vecteur de texte, et les photos les plus proches sont trouvées par distance cosinus dans l’index HNSW de pgvector.

sim(q, p) = q · p / (‖q‖ ‖p‖)
  • Trois sources de résultats sont fusionnées : d’abord les photos où les mots cherchés ont été reconnus, puis celles prises en un lieu correspondant, enfin les plus proches par le sens.
  • Seules les correspondances nettes sont renvoyées : un résultat doit être presque aussi proche que le meilleur et nettement plus proche qu’une photo moyenne. Cela aide à écarter les correspondances faibles au lieu de renvoyer des photos vaguement liées.
  • Si la requête est exactement un nom de catégorie (paysages, cuisine, captures d’écran…), cette catégorie est renvoyée directement.
Regroupement des visages

SCRFD détecte chaque visage et ses 5 points caractéristiques, l’aligne et le recadre en 112×112, puis ArcFace calcule une empreinte de 512 dimensions (après normalisation, le produit scalaire est la similarité cosinus). Le regroupement se fait au fil de l’eau, photo après photo, sans attendre la fin du calcul.

d(a, b) = 1 − a · b bon visage d < 0.55 · flou/profil d < 0.45
  • Les « bons visages », nets, de face et assez grands, cherchent leurs plus proches voisins : si certains appartiennent déjà à une personne, le visage la rejoint à la majorité ; si aucun n’est classé mais qu’au moins 3 se ressemblent, une nouvelle personne est créée.
  • Les visages flous, de profil ou trop petits ne créent jamais de personne ; ils rejoignent seulement quelqu’un à qui ils ressemblent beaucoup. Les passants vus une seule fois ne sont pas ajoutés.
  • Les regroupements simultanés partagent un même verrou consultatif de la base, si bien qu’une personne n’est jamais créée en double. Les vignettes privilégient les visages seuls nets (variance du laplacien), de face (lacet) et assez grands.
Rafales et photos similaires
même appareil Δt ≤ 2s ou Δt ≤ 60s et sim ≥ 0.93
  • Des prises successives de la même scène ont en général une similarité CLIP de 0,94 à 0,98, tandis qu’un changement de scène ou de pose tombe le plus souvent entre 0,7 et 0,89 ; un seuil de similarité de 0,93 aide à repérer les rafales probables.
  • La photo conseillée : avec des visages, celle où les visages sont nets, les yeux ouverts tournés vers l’objectif ; sans visage, le fichier le plus lourd (avec le même appareil et les mêmes réglages, une photo floue a moins de détails et se compresse davantage).
  • Les copies multiples d’un même fichier vont dans « Doublons », sans choix à faire. « Garder » déplace le reste vers « Supprimées récemment », d’où il reste restaurable jusqu’à sa suppression définitive.
Note esthétique de la sélection IA

Aucun modèle supplémentaire n’est lancé : les vecteurs CLIP sont réutilisés. En moyennant les vecteurs d’un ensemble de descriptions d’« œuvres photographiques » et d’un ensemble décrivant des « photos ordinaires », puis en les soustrayant, on obtient une direction « réussie ». La projection d’une photo sur cette direction est sa note.

score(p) = p · (μ_œuvre − μ_ordinaire)
  • Sert uniquement à classer, jamais de note absolue ; le carrousel de sélection de l’accueil choisit ses photos selon elle.
  • Un autre ensemble de descriptions repère les photos ratées (floues, surexposées, etc.), évaluées indépendamment de leur qualité esthétique.
TECH STACK

Technologies utilisées

Uniquement des composants open source éprouvés, sans service propriétaire ; chaque brique a son équivalent.

BACKEND
  • Go
    API, file de tâches, planification des miniatures
  • libvips
    Miniatures et aperçus
  • FFmpeg
    Extraction d’images vidéo, transcodage
  • ExifTool
    Lecture et écriture des métadonnées
  • tus
    Imports avec reprise
SERVICE IA
  • Python + FastAPI
    Service HTTP sans état
  • ONNX Runtime
    Inférence visages et texte
  • PyTorch
    Chinese-CLIP
  • InsightFace
    SCRFD + ArcFace
  • RapidOCR
    Reconnaissance de texte PP-OCR
DONNÉES
  • PostgreSQL 17
    Données applicatives et file de tâches
  • pgvector
    Stockage des vecteurs
  • HNSW
    Index en distance cosinus
  • ip2region
    Position IP des connexions (hors ligne)
  • Nominatim
    Géocodage inverse (désactivable)
INTERFACE & DÉPLOIEMENT
  • React + TypeScript
    Application web
  • Vite + Tailwind CSS
    Build et styles
  • MapLibre GL
    Globe satellite
  • Docker Compose
    Images amd64 / arm64
  • mDNS
    Domaine local wanmory.local
PRIVACY

Confidentialité et sécurité

Par défaut, les photos et les résultats de l’IA restent dans votre réseau privé. Si vous configurez un service IA distant, les aperçus sont envoyés à ce serveur pour être traités.

Données minimales

Le service IA ne reçoit que des aperçus de 1440 pixels, ne stocke aucun fichier et n’accède ni à la base, ni aux noms, ni aux originaux.

Authentification

Le service IA intégré n’existe que sur le réseau interne de Docker, joignable par le seul backend ; dès qu’un jeton est défini pour un service IA distant, chaque requête doit porter un jeton Bearer.

Droits

Les membres ne peuvent supprimer que leurs propres imports, les administrateurs gèrent tout ; les photos masquées ne sont visibles que de leur propriétaire ; l’historique des connexions indique une position approximative d’après l’IP.

Originaux en lecture seule

Les dossiers du NAS peuvent être montés en lecture seule avec :ro, l’application ne peut alors ni modifier ni supprimer leurs fichiers.

Fonctionne hors ligne

Une fois les modèles téléchargés, reconnaissance et recherche se font en local ; les fonctions qui exigent Internet, comme le géocodage inverse et les images satellite, peuvent être désactivées.

Licences des modèles

Les modèles de visages InsightFace sont réservés à un usage non commercial ; les modèles ne sont pas inclus dans l’image, et la licence de chacun est affichée dans les réglages avant téléchargement.