ARCHITECTURE

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.

3 + 1container

Backend in Go, servizio IA e PostgreSQL, più un servizio mDNS che annuncia il dominio locale

5tipi di lavoro

metadata, thumbnail, clip, face, ocr

512–1024dimensioni

Vettori immagine-testo Chinese-CLIP (512, 768 o 1024 a seconda del livello dei modelli); i tratti dei volti ArcFace hanno 512 dimensioni

HNSWindice vettoriale

Indice a distanza coseno di pgvector; ricerca e confronto dei volti avvengono nel database

SYSTEM

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.

CLIENTBrowser desktopApp web integrata nel programma GoBrowser mobileiPhone · Androidwanmory.localDominio locale, nessun IP da ricordareHTTP :8080DOCKER COMPOSEBackend Go · serverAPI, caricamenti, coda di lavori, miniature, permessi, webAPI RESTCaricamenti tusWorker dei lavoriAccount · AccessiMiniature libvipsMetadati ExifToolVideo FFmpegGeocodifica (opz.)Album · IntelligentiRaffiche · SimiliScelte IA · OggiScansione ogni 15 minmdnsAnnuncia wanmory.localServizio IA · mlFastAPI + ONNX Runtime / PyTorch, senza statoRilevamento SCRFDTratti ArcFaceChinese-CLIPTesto PP-OCRPostgreSQL 17 + pgvectorDati, coda di lavori e vettori in un unico database, niente Redisassetsfaces · peoplecoda jobssettingsindice HNSWSQL/predict · anteprime 1440 pxARCHIVIAZIONE · ESTENSIONI/dataOriginali caricati, miniature, anteprime 1440 px/photos/* (anche sola lettura :ro)Cartelle foto esistenti sul NAS, quante vuoi./modelsFile dei modelli, scaricati dalle impostazioni webServizio IA remoto (facoltativo)Mac (CoreML / MPS) · NVIDIA CUDAAutenticazione con token; riceve solo anteprime 1440 px, mai gli originalilettura/scritturascansione · sola letturacaricamentoHTTP + token
Il backend è un unico programma Go

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 può stare altrove

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.

Un solo database per tutto

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

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.

01ingest
Importazione
  • Caricamenti web via tus, ripresi dopo le interruzioni
  • Cartelle /photos scansionate ogni 15 minuti
  • Checksum SHA-1 calcolato e salvato in assets
Backend
02metadata
Metadati
  • ExifTool legge dimensioni e data dello scatto
  • GPS, fotocamera, obiettivo, diaframma e tempi
  • Orari senza fuso: fuso impostato
Backend
03thumbnail
Miniature
  • libvips genera le miniature
  • Poi un’anteprima da 1440 px
  • FFmpeg estrae fotogrammi e converte i video
Backend
04clip
Vettori
  • Chinese-CLIP calcola vettori 1024-d
  • Ricerca in linguaggio naturale, categorie
  • Valutazione estetica, foto simili
IA · in parallelo
05face
Volti
  • SCRFD trova i volti, allinea su 5 punti
  • ArcFace calcola tratti 512-d
  • Raggruppati in persone man mano
IA · in parallelo
06ocr
Testo
  • PP-OCR legge il testo nelle foto
  • Cerca le foto per testo
  • Riconosce documenti e screenshot
IA · in parallelo
SCHEDULING

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.

pendingin codarunningpreso da un workerdonecompletatofailedtentativi esauritipresa con SKIP LOCKEDsuccessotentativi esauritierrore: nuovo tentativo dopo n² × 30 sIA irraggiungibile: riprova tra 15 s, non conta come erroreLease di 10 min: senza risultato in tempo, ogni 30 s torna in pending
jobs/worker.go · claim
-- 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;
Regole di pianificazione
  • 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.
Precedenza e limitazione
  • 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.
AI SCHEDULING

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.

Coda dei lavori IAclip · face · ocrConcorrenza da impostazioni, limitazione regolabileBackend Go · client IASceglie servizio e livello, verifica model_ids· Controlla /health ogni 15 s· Irraggiungibile → lavori in attesa· Livello automatico → da hardwarepresaServizio IA integratoRete interna Docker · CPUServizio IA remotoMac o PC con GPU di casaNodo di lavoro remotoPrende i lavori da sé (previsto)uno dei dueCPUONNX RuntimeCoreML / MPS · CUDASceglie l’accelerazione disponibileOpenVINOGPU integrata Intel
Tre livelli di modelli

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.

LivelloHardware adattoVoltiRicerca semantica
quality · Alta precisioneMac con Apple Silicon, GPU NVIDIASCRFD-10G + ArcFace R100 (antelopev2)Chinese-CLIP ViT-H/14 · 1024-d
balanced · EquilibratoNAS classe Intel i5SCRFD-10G + ArcFace R100 (antelopev2)Chinese-CLIP ViT-L/14 · 768-d
lite · LeggeroN100, Raspberry Pi 5SCRFD + ArcFace R50 (buffalo_l)Chinese-CLIP ViT-B/16 · 512-d
API del servizio IA · /predict
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"}
}
ALGORITHMS

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.

Ricerca in linguaggio naturale

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.

sim(q, p) = q · p / (‖q‖ ‖p‖)
  • 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.
Raggruppamento dei volti

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.

d(a, b) = 1 − a · b volto buono d < 0.55 · sfocato/profilo d < 0.45
  • 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.
Raffiche e foto simili
stessa fotocamera Δt ≤ 2s oppure Δt ≤ 60s e sim ≥ 0.93
  • 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.
Valutazione estetica delle scelte IA

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.

score(p) = p · (μ_opera − μ_quotidiana)
  • 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.
TECH STACK

Tecnologie usate

Solo componenti open source maturi, nessun servizio proprietario; ogni pezzo ha un’alternativa.

BACKEND
  • Go
    API, coda di lavori, pianificazione miniature
  • libvips
    Miniature e anteprime
  • FFmpeg
    Fotogrammi video, conversione
  • ExifTool
    Lettura e scrittura dei metadati
  • tus
    Caricamenti riprendibili
SERVIZIO IA
  • Python + FastAPI
    Servizio HTTP senza stato
  • ONNX Runtime
    Inferenza volti e testo
  • PyTorch
    Chinese-CLIP
  • InsightFace
    SCRFD + ArcFace
  • RapidOCR
    Riconoscimento testo PP-OCR
DATI
  • PostgreSQL 17
    Dati dell’app e coda di lavori
  • pgvector
    Archiviazione dei vettori
  • HNSW
    Indice a distanza coseno
  • ip2region
    Posizione IP degli accessi (offline)
  • Nominatim
    Geocodifica inversa (disattivabile)
INTERFACCIA E INSTALLAZIONE
  • React + TypeScript
    App web
  • Vite + Tailwind CSS
    Build e stili
  • MapLibre GL
    Globo satellitare
  • Docker Compose
    Immagini amd64 / arm64
  • mDNS
    Dominio locale wanmory.local
PRIVACY

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.

Dati minimi

Il servizio IA riceve solo anteprime da 1440 pixel, non salva file e non tocca mai database, nomi né originali.

Autenticazione

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.

Permessi

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.

Originali in sola lettura

Le cartelle del NAS si possono montare in sola lettura con :ro, così l’app non può modificare né eliminare i loro file.

Funziona offline

Scaricati i modelli, riconoscimento e ricerca avvengono in locale; le funzioni che richiedono internet, come geocodifica inversa e immagini satellitari, si possono disattivare.

Licenze dei modelli

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.