- Python 95.7%
- PowerShell 4%
- Mako 0.3%
|
|
||
|---|---|---|
| alembic | ||
| app | ||
| deploy | ||
| docs/adr | ||
| tests | ||
| .env.example | ||
| .gitignore | ||
| alembic.ini | ||
| CLAUDE.md | ||
| compute_embeddings.py | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
| run_classifier.py | ||
| run_import.py | ||
| run_train.py | ||
reperio.Parts ML-Service
FastAPI-basierter ML-Service für visuelle Ähnlichkeitssuche von CAD-Werkstücken (CLIP + FAISS).
Überblick
Der reperio.Parts ML-Service ist ein eigenständiger HTTP-Dienst (siehe ADR-011 in reperio-parts) für alle ML-Operationen der reperio.Parts-Plattform. Er extrahiert visuelle Embeddings aus CAD-Ansichten mittels CLIP, indiziert diese in einem FAISS-Index und bietet eine REST-API für Ähnlichkeitssuche, Tagging und Training.
Kernfunktionen:
- CLIP ViT-B/32 Embeddings -- 512-dimensionale, L2-normalisierte Feature-Vektoren aus ISO-Ansichten
- FAISS IndexFlatIP -- Cosine-Similarity-Suche über Inner Product auf normalisierten Vektoren
- Tag-Classifier -- Pro-Tag LogisticRegression für automatische Klassifikation
- Auto-Tagging -- Versionierte automatische Tag-Vergabe (
auto:v1) - Shared SQLite DB -- WAL-Modus, gemeinsam genutzt mit dem C# Backend (reperio-parts)
- Windows-Service -- Läuft in Produktion als Windows-Dienst via NSSM
Tech Stack
| Komponente | Version |
|---|---|
| Python | 3.12+ |
| FastAPI | 0.115+ |
| Uvicorn | 0.34+ (Standard) |
| PyTorch | 2.0+ (ROCm / CUDA / CPU) |
| open-clip-torch | 2.29+ |
| FAISS | faiss-cpu 1.9+ |
| scikit-learn | 1.6+ |
| SQLAlchemy | 2.0+ |
| Alembic | 1.14+ |
| Pydantic Settings | 2.7+ |
| Pillow | 11.0+ |
| NumPy | 2.0+ |
Schnellstart
# Repository klonen
git clone https://github.com/swissYoshi/reperio-embedding-service.git
cd reperio-embedding-service
# Virtual Environment erstellen und aktivieren
python -m venv .venv
source .venv/bin/activate # Linux
# .venv\Scripts\activate # Windows
# Dependencies installieren (inkl. ML und Dev-Tools)
pip install -e ".[ml,dev]"
# .env erstellen und anpassen
cp .env.example .env
# REPERIO_DATA_DIR auf den Pfad zu CADAnsichten setzen
# Datenbank-Migrationen ausführen
alembic upgrade head
# Embeddings berechnen (Erststart, dauert je nach Kataloggrösse)
python compute_embeddings.py
# Service starten (Entwicklung)
uvicorn app.main:create_app --factory --reload --port 8100
Nach dem Start ist die Swagger-Dokumentation unter http://localhost:8100/docs erreichbar.
Konfiguration
Alle Einstellungen werden über Umgebungsvariablen mit dem Prefix REPERIO_ konfiguriert.
Alternativ können sie in einer .env-Datei im Projektverzeichnis hinterlegt werden.
Umgebungsvariablen
| Variable | Default | Beschreibung |
|---|---|---|
REPERIO_DATA_DIR |
-- | Pfad zu CADAnsichten (Pflicht) |
REPERIO_OUTPUT_DIR |
./outputs |
Basisverzeichnis für Embeddings, FAISS, DB, Models |
REPERIO_EMBEDDING_MODEL |
ViT-B-32 |
OpenCLIP-Modellname |
REPERIO_EMBEDDING_PRETRAINED |
laion2b_s34b_b79k |
Pretrained Checkpoint |
REPERIO_EMBEDDING_DIM |
512 |
Embedding-Dimension |
REPERIO_BATCH_SIZE |
32 |
Batch-Grösse für Embedding-Extraktion |
REPERIO_DEVICE |
auto |
Rechengerät: cpu, cuda oder auto |
REPERIO_HOST |
0.0.0.0 |
Bind-Adresse des HTTP-Servers |
REPERIO_PORT |
8100 |
HTTP-Port |
REPERIO_LOG_LEVEL |
INFO |
Log-Level (DEBUG, INFO, WARNING, ERROR) |
REPERIO_AUTH_ENABLED |
false |
S2S-Authentifizierung (derzeit nicht aktiv) |
REPERIO_S2S_SECRET |
-- | Shared Secret für S2S-Auth |
REPERIO_FINETUNE_LR |
1e-6 |
Learning Rate für CLIP Fine-Tuning |
REPERIO_FINETUNE_EPOCHS |
10 |
Epochen für CLIP Fine-Tuning |
REPERIO_FINETUNE_MARGIN |
0.2 |
Triplet-Margin für kontrastives Lernen |
REPERIO_FINETUNE_BATCH_SIZE |
16 |
Batch-Grösse für Fine-Tuning |
REPERIO_AUTOTAG_CONFIDENCE |
0.8 |
Confidence-Schwelle für Auto-Tagging |
REPERIO_AUTOTAG_MAX_TAGS |
5 |
Maximale Auto-Tags pro Teil |
REPERIO_AUTOTAG_VERSION |
v1 |
Versions-String für Auto-Tags |
REPERIO_CLASSIFIER_MIN_EXAMPLES |
3 |
Minimum Beispiele pro Tag für Classifier-Training |
REPERIO_CLASSIFIER_CONFIDENCE |
0.8 |
Confidence-Schwelle für Classifier |
Abgeleitete Pfade
Alle abgeleiteten Pfade basieren auf REPERIO_OUTPUT_DIR:
| Pfad | Inhalt |
|---|---|
{output_dir}/embeddings/ |
NumPy-Dateien mit Embedding-Vektoren und Metadaten |
{output_dir}/faiss_index.bin |
Serialisierter FAISS-Index |
{output_dir}/models/ |
Fine-Tuned CLIP-Modelle |
{output_dir}/classifiers/ |
Gespeicherte Tag-Klassifikatoren (joblib) |
{output_dir}/evaluations/ |
Evaluations-Ergebnisse (JSON) |
{output_dir}/reperio.db |
SQLite-Datenbank (shared mit reperio-parts) |
API-Endpunkte
Alle Endpunkte befinden sich unter dem Prefix /api. Interaktive Dokumentation: http://localhost:8100/docs
System
| Methode | Pfad | Beschreibung |
|---|---|---|
GET |
/api/health |
Health-Check für Load-Balancer und Monitoring |
GET |
/api/status |
System-Info: Konfiguration, Katalog- und Index-Status |
POST |
/api/reload |
Katalog, Embeddings und FAISS-Index neu laden |
GET |
/api/settings |
UI-konfigurierbare Settings aus der Datenbank lesen |
PUT |
/api/settings |
Settings aktualisieren |
Suche
| Methode | Pfad | Beschreibung |
|---|---|---|
GET |
/api/search/bmn/{bmn}?k=200 |
Ähnlichkeitssuche ausgehend von einer Bauteilnummer |
POST |
/api/search/image?k=200 |
Ähnlichkeitssuche via Bild-Upload (Multipart) |
Teile
| Methode | Pfad | Beschreibung |
|---|---|---|
GET |
/api/parts?offset=0&limit=80&q=&tags=&tags_neg= |
Teile-Katalog mit Filterung und Pagination |
GET |
/api/parts/{bmn} |
Detail-Ansicht eines einzelnen Teils |
GET |
/api/suggestions?q=&limit=10 |
BEZ-Vorschläge für Autocomplete |
Tags
| Methode | Pfad | Beschreibung |
|---|---|---|
GET |
/api/tags |
Alle Tags mit Häufigkeit und Typ |
PUT |
/api/tags/types |
Tag-Typen setzen (visual / attribute) |
GET |
/api/search/tags?q=&limit=20 |
Fuzzy Tag-Suche |
POST |
/api/annotations/tags |
Tags zu Teilen hinzufügen |
DELETE |
/api/annotations/tags |
Tags von Teilen entfernen |
Training
| Methode | Pfad | Beschreibung |
|---|---|---|
POST |
/api/train/clip |
CLIP Fine-Tuning starten |
POST |
/api/train/classifier |
Tag-Klassifikator trainieren |
POST |
/api/train/evaluate |
Retrieval-Evaluation starten |
POST |
/api/train/autotag-classifier |
Auto-Tagging mit Klassifikator starten |
GET |
/api/train/status |
Aktueller Trainings-Status |
GET |
/api/train/stream |
SSE-Stream für Live-Trainingsfortschritt |
POST |
/api/train/stop |
Laufendes Training abbrechen |
Projektstruktur
reperio-embedding-service/
├── app/
│ ├── api/ REST-Endpoints
│ │ ├── system.py Health, Status, Reload, Settings
│ │ ├── search.py BMN-Suche, Bild-Upload-Suche
│ │ ├── parts.py Browse, Detail, BEZ-Vorschläge
│ │ ├── tags.py Tag-CRUD, Typ-Verwaltung, Tag-Suche
│ │ └── training.py Training-Steuerung, SSE-Stream
│ ├── core/ Infrastruktur
│ │ ├── config.py Pydantic Settings (Umgebungsvariablen)
│ │ ├── database.py SQLAlchemy Engine + Session Factory
│ │ ├── auth.py S2S-Authentifizierung (Dependency)
│ │ └── events.py Lifespan Events (Startup/Shutdown)
│ ├── models/ Daten-Modelle
│ │ ├── db.py SQLAlchemy ORM (Annotation, Tag, Pair, ...)
│ │ └── schemas.py Pydantic Request/Response Schemas
│ ├── services/ Business-Logik
│ │ ├── search.py SearchService (Katalog, Embeddings, FAISS)
│ │ ├── feedback.py FeedbackService (Tags, Annotations, Settings)
│ │ └── training.py TrainingManager (ThreadPoolExecutor)
│ ├── ml/ Machine Learning
│ │ ├── clip/ CLIP-Modell
│ │ │ ├── extract.py Embedding-Extraktion aus Bildern
│ │ │ ├── recompute.py Alle Embeddings neu berechnen
│ │ │ └── finetune.py Kontrastives Fine-Tuning (Triplet Loss)
│ │ ├── faiss/ FAISS-Index
│ │ │ └── index.py Index-Aufbau und Suche
│ │ ├── classifier/ Tag-Klassifikation
│ │ │ ├── classifier.py Pro-Tag LogisticRegression
│ │ │ ├── predict.py Batch-Prediction für Auto-Tagging
│ │ │ └── review.py Classifier-Review und Statistiken
│ │ ├── triplets/ Trainings-Daten
│ │ │ └── generator.py Triplet-Generierung für kontrastives Lernen
│ │ ├── evaluation/ Metriken
│ │ │ └── evaluate.py Retrieval-Evaluation (Recall@K, NDCG)
│ │ └── data/ Daten-Zugriff
│ │ └── loader.py Katalog-Scanner, Bild-Loader
│ ├── dependencies.py FastAPI Dependency Injection
│ └── main.py App-Factory (create_app)
├── tests/ 22 Testmodule (pytest + pytest-asyncio)
├── alembic/ Datenbank-Migrationen
│ └── versions/
│ ├── 001_initial_schema.py
│ └── 002_settings_updated_at_default.py
├── deploy/ Deployment-Scripts
│ ├── Build-OfflinePackage.ps1 Offline-Paket für Air-Gapped Server
│ └── Setup-Service.ps1 Windows-Service via NSSM installieren
├── compute_embeddings.py Standalone: Embeddings + FAISS-Index berechnen
├── run_train.py Standalone: CLIP Fine-Tuning / Recompute
├── run_classifier.py Standalone: Classifier trainieren + Auto-Taggen
├── run_import.py Standalone: Katalog scannen, neue Embeddings
├── pyproject.toml Projekt-Konfiguration und Dependencies
├── alembic.ini Alembic-Konfiguration
└── .env.example Vorlage für Umgebungsvariablen
Standalone-Scripts
Die Scripts können unabhängig vom HTTP-Service ausgeführt werden.
| Script | Zweck | Aufruf |
|---|---|---|
compute_embeddings.py |
Alle Embeddings berechnen und FAISS-Index aufbauen (Erststart) | python compute_embeddings.py |
run_train.py |
CLIP Fine-Tuning oder Recompute | python run_train.py --evaluate-only --device auto |
run_classifier.py |
Tag-Classifier trainieren, optional mit Auto-Tagging | python run_classifier.py --auto-tag --threshold 0.7 |
run_import.py |
Katalog scannen und Embeddings für neue Teile berechnen | python run_import.py --device auto |
Alle Scripts geben JSON-Progress an stdout aus (--json-progress), sodass das C# Backend
den Fortschritt über SSE an die UI weiterleiten kann.
Datenbank
Der Service nutzt SQLAlchemy ORM mit SQLite als Backend. Die Datenbank liegt unter
{output_dir}/reperio.db und wird im WAL-Modus betrieben, damit sowohl der ML-Service
als auch das C# Backend (reperio-parts) gleichzeitig lesen und schreiben können.
Tabellen
| Tabelle | Beschreibung |
|---|---|
annotations |
Pro-Teil Metadaten (BMN, Bezeichnung, Beschreibung) |
tags |
Tag-Zuordnungen zu Teilen (BMN, Tag, Source) |
tag_types |
Tag-Klassifikation: visual oder attribute |
pairs |
Ähnlichkeitspaare zwischen zwei Teilen (manuelles Feedback) |
groups |
Gruppen (Legacy) |
group_members |
Gruppenmitgliedschaft |
training_runs |
Audit Trail für Trainingsläufe |
settings |
UI-konfigurierbare Einstellungen (Key-Value) |
Migrationen
# Auf neuesten Stand bringen
alembic upgrade head
# Neue Migration erstellen (nach ORM-Änderung)
alembic revision --autogenerate -m "beschreibung"
ML-Pipeline
CLIP-Embeddings
Für jedes Teil im Katalog wird die ISO-Ansicht (Fallback: ~ISO, Front, beliebig verfügbar) durch das CLIP ViT-B/32 Modell geschickt. Das Ergebnis ist ein 512-dimensionaler Feature-Vektor, der L2-normalisiert gespeichert wird.
FAISS-Index
Der FAISS IndexFlatIP (Inner Product) arbeitet auf L2-normalisierten Vektoren.
Das Inner Product normalisierter Vektoren entspricht der Cosine Similarity.
Die Suche liefert die k ähnlichsten Teile mit einem Score zwischen 0 und 1.
Tag-Classifier
Für jeden Tag vom Typ visual wird ein eigener LogisticRegression-Classifier
auf den CLIP-Embeddings trainiert. Voraussetzung: mindestens REPERIO_CLASSIFIER_MIN_EXAMPLES
Beispiele pro Tag (Default: 3).
Auto-Tagging
Auto-Tags werden versioniert gespeichert (z.B. auto:v1 als Source). Bei einem Retrain
werden alle Auto-Tags der jeweiligen Version komplett gelöscht und neu berechnet.
Manuelle Tags werden dabei nicht berührt -- bei Konflikten zwischen manuellen und
automatischen Tags hat der Mensch immer die Entscheidungshoheit.
Training-Steuerung
Alle Trainings-Operationen laufen in einem ThreadPoolExecutor mit max_workers=1,
sodass immer nur ein Training gleichzeitig aktiv ist. Der Fortschritt wird über
SSE (Server-Sent Events) an die UI gestreamt.
Tests
# Alle Tests ausführen
pytest tests/
# Verbose-Ausgabe
pytest tests/ -v
# Einzelnes Testmodul
pytest tests/test_classifier.py
# Pattern-Matching
pytest -k "classifier"
# Coverage (falls installiert)
pytest tests/ --cov=app
22 Testmodule mit pytest und pytest-asyncio. Die Tests nutzen SQLite In-Memory-Datenbanken und gemockte ML-Komponenten, sodass kein GPU oder CLIP-Modell für die Testausführung benötigt wird.
Deployment (Produktion)
Windows-Service via NSSM
Auf dem Zielserver (Windows Server 2019+, Air-Gapped) wird der Service als Windows-Dienst via NSSM betrieben:
.\deploy\Setup-Service.ps1 -DataDir "\\fileserver\CADAnsichten" -Port 8100
Der Service bindet in Produktion auf 127.0.0.1 (nur localhost), da er ausschliesslich
vom C# Backend auf demselben Server aufgerufen wird.
Offline-Paket
Für Air-Gapped Umgebungen ohne Internetzugang:
# Auf dem Entwicklungsrechner (mit Internetzugang)
.\deploy\Build-OfflinePackage.ps1
Das Script erstellt ein vollständiges Paket mit allen Python-Wheels und dem CLIP-Modell-Cache.
CLIP-Modell offline bereitstellen
Da der Zielserver keinen Internetzugang hat, muss das CLIP-Modell manuell
im HuggingFace-Cache abgelegt werden. Die Umgebungsvariable HF_HOME zeigt
auf das lokale Verzeichnis mit dem vorinstallierten Modell.
Log-Dateien
In Produktion schreibt NSSM die stdout/stderr-Ausgabe in:
{InstallDir}\logs\stdout.log
Integration mit reperio-parts
Der ML-Service wird vom C# ASP.NET Core Backend (reperio-parts) als HTTP-Dienst aufgerufen. Die Kommunikation erfolgt über die REST-API.
Konfiguration im C# Backend
In appsettings.json:
{
"MlService": {
"BaseUrl": "http://127.0.0.1:8100"
}
}
Die Anbindung erfolgt über MlServiceClient.cs im reperio-parts Projekt.
Shared Database
Beide Services teilen sich dieselbe SQLite-Datenbank (reperio.db).
Der WAL-Modus erlaubt gleichzeitige Lese- und Schreibzugriffe.
REPERIO_OUTPUT_DIR im ML-Service muss auf dasselbe Verzeichnis zeigen,
das auch das C# Backend als Datenbankpfad nutzt.
Authentifizierung
Beide Services laufen auf demselben Server (localhost). Eine S2S-Authentifizierung
ist vorbereitet (REPERIO_AUTH_ENABLED), aber derzeit nicht aktiviert.
Lizenz
Proprietär -- Interne Unternehmensanwendung.