Architettura
Tre container principali, più un servizio mDNS, senza un message broker separato né servizi cloud obbligatori. Le foto vengono caricate o importate dalle cartelle del NAS, poi elaborate per metadati, miniature, vettori semantici, volti e testo. Il risultato è una fototeca ricercabile per linguaggio naturale, persona e luogo.
Backend in Go, servizio IA e PostgreSQL, più un servizio mDNS che annuncia il dominio locale
metadata, thumbnail, clip, face, ocr
Vettori immagine-testo Chinese-CLIP (512, 768 o 1024 a seconda del livello dei modelli); i tratti dei volti ArcFace hanno 512 dimensioni
Indice a distanza coseno di pgvector; ricerca e confronto dei volti avvengono nel database
Architettura del sistema
Il browser parla solo con il backend in Go, che gestisce caricamenti, pianificazione dei lavori, miniature e permessi, invia le anteprime al servizio IA per l’inferenza e scrive tutti i risultati in PostgreSQL. Il servizio IA è senza stato: non accede mai al database e non salva file, quindi può girare su una macchina più potente.
L’app web è incorporata nel programma, quindi l’installazione non richiede Node. Le migrazioni del database partono da sole all’avvio, e aggiornare significa solo cambiare immagine.
Il servizio IA integrato gira sulla rete interna di Docker e calcola sulla CPU. Inserisci un indirizzo remoto nelle impostazioni web per passare a un PC con scheda video o a un Mac di casa.
Dati delle foto, persone, impostazioni, coda di lavori e vettori stanno tutti in PostgreSQL, quindi dati dell’app e stato dei lavori si possono salvare insieme. I file delle foto richiedono un backup separato.
Pipeline di elaborazione delle foto
Dopo l’importazione, di ogni foto vengono prima estratti i metadati e generate le miniature, poi si calcolano in parallelo vettori semantici, volti e testo. Ogni passaggio va in coda separatamente, così un riavvio o un servizio IA offline non fa perdere lavoro: l’elaborazione riprende quando tutto torna.
ingest- Caricamenti web via tus, ripresi dopo le interruzioni
- Cartelle /photos scansionate ogni 15 minuti
- Checksum SHA-1 calcolato e salvato in assets
metadata- ExifTool legge dimensioni e data dello scatto
- GPS, fotocamera, obiettivo, diaframma e tempi
- Orari senza fuso: fuso impostato
thumbnail- libvips genera le miniature
- Poi un’anteprima da 1440 px
- FFmpeg estrae fotogrammi e converte i video
clip- Chinese-CLIP calcola vettori 1024-d
- Ricerca in linguaggio naturale, categorie
- Valutazione estetica, foto simili
face- SCRFD trova i volti, allinea su 5 punti
- ArcFace calcola tratti 512-d
- Raggruppati in persone man mano
ocr- PP-OCR legge il testo nelle foto
- Cerca le foto per testo
- Riconosce documenti e screenshot
Pianificazione dei lavori in background
Non c’è un message broker separato: la coda dei lavori è una tabella jobs in PostgreSQL, scritta nella stessa transazione dei dati della foto, così una foto salvata ha sempre i suoi lavori in coda. I worker prendono i lavori con SKIP LOCKED, i lease evitano blocchi e gli errori vengono ritentati con attesa quadratica.
-- Prendere un lavoro (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 -- worker concorrenti non prendono mai lo stesso
LIMIT 1
)
RETURNING id, type, asset_id, payload, attempts, max_attempts;- Un lavoro dello stesso tipo per la stessa foto non entra mai due volte in coda finché un altro è in attesa o in corso.
- Con la coda vuota si controlla ogni secondo; i lavori si prendono per priority (prima la più alta), poi per scadenza (prima la più vicina).
- Il lease di ogni lavoro (che è anche il suo timeout) è di 10 minuti; al riavvio, un processo rimette in coda i propri lavori non finiti.
- Mentre qualcuno carica foto, i lavori IA non vengono presi, così banda e CPU vanno prima al caricamento.
- Se il servizio IA non risponde, l’intero worker IA si ferma invece di prendere i lavori uno a uno per farli fallire e sprecare tentativi.
- Il livello «Automatico» rileva prima l’hardware del server IA e sceglie modelli adatti, poi prende i lavori: questo aiuta a evitare di caricare su un Raspberry Pi o simili modelli che superano la memoria disponibile.
Pianificazione dell’IA
Il servizio IA riceve solo anteprime e restituisce volti, vettori e testo. Il backend decide indirizzo del servizio, modelli e concorrenza; il servizio IA sceglie CUDA, CoreML / MPS, OpenVINO o CPU in base al suo hardware.
Con «Automatico» il livello dipende dall’hardware del server IA: Alta precisione con una scheda video utilizzabile; con sola CPU, Leggero sotto i 6 GB di memoria ed Equilibrato da 6 GB in su.
| Livello | Hardware adatto | Volti | Ricerca semantica |
|---|---|---|---|
| quality · Alta precisione | Mac con Apple Silicon, GPU NVIDIA | SCRFD-10G + ArcFace R100 (antelopev2) | Chinese-CLIP ViT-H/14 · 1024-d |
| balanced · Equilibrato | NAS classe Intel i5 | SCRFD-10G + ArcFace R100 (antelopev2) | Chinese-CLIP ViT-L/14 · 768-d |
| lite · Leggero | N100, Raspberry Pi 5 | SCRFD + ArcFace R50 (buffalo_l) | Chinese-CLIP ViT-B/16 · 512-d |
POST /predict (multipart: image + tasks)
Authorization: Bearer <token>
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 numeri], "yaw": 0.12, "blur": 340}],
"clip": {"embedding": [1024 numeri]},
"ocr": {"text": "...", "lines": [...]},
"model_ids": {"face": "antelopev2", "clip": "chinese-clip-vit-h-14"}
}Algoritmi chiave
I modelli, gli algoritmi e le soglie dietro ricerca, persone, raffiche e scelte dell’IA. Alcuni si basano su modelli di IA, altri su calcolo vettoriale e regole.
Chinese-CLIP mette foto e testo nello stesso spazio vettoriale. I vettori delle immagini si calcolano all’importazione; in fase di ricerca, una frase come «terzo compleanno del bimbo» diventa un vettore di testo e le foto più vicine si trovano per distanza coseno nell’indice HNSW di pgvector.
- Si uniscono tre fonti di risultati: prima le foto in cui sono state riconosciute le parole cercate, poi quelle scattate in un luogo con quel nome, infine le più vicine per significato.
- Vengono restituite solo corrispondenze nette: un risultato deve essere vicino quasi quanto il migliore e chiaramente più vicino di una foto qualsiasi. Questo aiuta a scartare le corrispondenze deboli invece di restituire foto poco pertinenti.
- Se la ricerca è esattamente il nome di una categoria (paesaggi, cibo, screenshot…), viene restituita direttamente quella categoria.
SCRFD trova ogni volto e i suoi 5 punti di riferimento, lo allinea e lo ritaglia a 112×112, e ArcFace calcola un vettore a 512 dimensioni (dopo la normalizzazione il prodotto scalare è la similarità coseno). Il raggruppamento avviene man mano, a ogni foto completata, senza aspettare l’intera fototeca.
- I «volti buoni», nitidi, frontali e abbastanza grandi, cercano i più simili: se alcuni appartengono già a una persona, il volto si unisce a lei a maggioranza; se nessuno è assegnato ma almeno 3 si somigliano, nasce una nuova persona.
- Volti sfocati, di profilo o troppo piccoli non creano mai una persona; si uniscono solo a qualcuno a cui somigliano molto. I passanti comparsi una volta non vengono aggiunti.
- I raggruppamenti concorrenti condividono lo stesso advisory lock del database, così nessuno viene creato due volte. Come copertina si preferiscono volti singoli nitidi (varianza del laplaciano), frontali (imbardata) e abbastanza grandi.
- Gli scatti consecutivi della stessa scena hanno di solito una similarità CLIP di 0,94–0,98, mentre un cambio di scena o di posa sta in genere fra 0,7 e 0,89; una soglia di similarità di 0,93 aiuta a individuare le probabili raffiche.
- La foto consigliata: con volti, quella in cui sono nitidi, a occhi aperti e rivolti all’obiettivo; senza volti, il file più grande (con la stessa fotocamera e le stesse impostazioni, le foto mosse hanno meno dettagli e si comprimono di più).
- Più copie dello stesso file finiscono in «Duplicati», senza nulla da scegliere. «Tieni» sposta il resto in «Eliminate di recente», da dove si può ripristinare finché non viene eliminato definitivamente.
Non si esegue alcun modello aggiuntivo: si riusano i vettori CLIP. La media dei vettori di un insieme di descrizioni di «opere fotografiche» meno quella di un insieme di «foto quotidiane» dà una direzione «bella». La proiezione di una foto su questa direzione è il suo punteggio.
- Serve solo per ordinare, mai come voto assoluto; il carosello delle scelte nella vista principale sceglie le foto in base a questo.
- Un altro insieme di descrizioni individua le foto venute male (mosse, sovraesposte e simili), valutate a parte rispetto a quanto è bella una foto.
Tecnologie usate
Solo componenti open source maturi, nessun servizio proprietario; ogni pezzo ha un’alternativa.
- GoAPI, coda di lavori, pianificazione miniature
- libvipsMiniature e anteprime
- FFmpegFotogrammi video, conversione
- ExifToolLettura e scrittura dei metadati
- tusCaricamenti riprendibili
- Python + FastAPIServizio HTTP senza stato
- ONNX RuntimeInferenza volti e testo
- PyTorchChinese-CLIP
- InsightFaceSCRFD + ArcFace
- RapidOCRRiconoscimento testo PP-OCR
- PostgreSQL 17Dati dell’app e coda di lavori
- pgvectorArchiviazione dei vettori
- HNSWIndice a distanza coseno
- ip2regionPosizione IP degli accessi (offline)
- NominatimGeocodifica inversa (disattivabile)
- React + TypeScriptApp web
- Vite + Tailwind CSSBuild e stili
- MapLibre GLGlobo satellitare
- Docker ComposeImmagini amd64 / arm64
- mDNSDominio locale wanmory.local
Privacy e sicurezza
Per impostazione predefinita, le foto e i risultati dell’IA restano nella tua rete privata. Se configuri un servizio IA remoto, le anteprime vengono inviate a quel server per l’elaborazione.
Il servizio IA riceve solo anteprime da 1440 pixel, non salva file e non tocca mai database, nomi né originali.
Il servizio IA integrato esiste solo sulla rete interna di Docker ed è raggiungibile solo dal backend; quando per un servizio IA remoto è impostato un token, ogni richiesta deve includere un token Bearer.
I membri possono eliminare solo le proprie foto, gli amministratori gestiscono tutto; le foto nascoste le vede solo chi le ha nascoste; la cronologia degli accessi mostra una posizione approssimativa dall’IP.
Le cartelle del NAS si possono montare in sola lettura con :ro, così l’app non può modificare né eliminare i loro file.
Scaricati i modelli, riconoscimento e ricerca avvengono in locale; le funzioni che richiedono internet, come geocodifica inversa e immagini satellitari, si possono disattivare.
I modelli per i volti InsightFace sono solo per uso non commerciale; i modelli non sono inclusi nell’immagine e prima del download le impostazioni mostrano la licenza di ciascuno.