An extremely fast, lightweight, and hardware-accelerated AI microservice built specifically as an External App (ExApp) for Nextcloud Recognize. It serves object detection, facial recognition/embeddings, and semantic image embeddings using ONNX Runtime with automatic execution provider selection (e.g., CUDA for Nvidia GPUs, or highly optimized CPU threads).
+-----------------------------+
| Nextcloud Recognize (App) |
+--------------+--------------+
|
REST API / | 1. Upload Image
HTTP POST | 2. Get JSON Results
v
+-------------------+--------------------+
| FastAPI ExApp Backend (Port 8000) |
+-------------------+--------------------+
|
+------------------------+------------------------+
| | |
v v v
+------------------+ +------------------+ +------------------+
| YOLOv8n | | ArcFace | | CLIP |
| (Object Det.) | | (Face Embeddings)| | (Semantic Search)|
+--------+---------+ +--------+---------+ +--------+---------+
| | |
+------------------------+------------------------+
|
v
+-------------+-------------+
| ONNX Runtime Engine |
| - CUDA (GPU Accelerated) |
| - CPU (Fallback / Native) |
+---------------------------+
ModelManager, with on-the-fly fallback loading if needed.recognize-ai-backend/
├── config.py # Global settings, class lists, thresholds, env vars
├── main.py # FastAPI server entrypoint and endpoint routes
├── inference.py # Image preprocessing, NMS, and ONNX execution pipelines
├── utils.py # Lazy ModelManager and ONNX session initialization
├── nc_app.py # Nextcloud ExApp lifecycle (nc-py-api registration)
├── scanner.py # Background file scanner for automatic media classification
├── download_models.py # Unified downloader/exporter for YOLO, ArcFace, and CLIP
├── export_clip.py # Standalone CLIP exporter (legacy, use download_models.py)
├── test_client.py # Functional testing client (sends test requests)
├── models/ # ONNX model storage (.onnx files, gitignored)
├── appinfo/
│ └── info.xml # Nextcloud ExApp manifest (app ID, version, deploy config)
├── src/
│ └── main.js # Vue.js admin settings panel (webpack-built frontend)
├── requirements.txt # Runtime dependencies
├── requirements-dev.txt # Development & model export dependencies
├── Dockerfile # Multi-stage CPU/GPU production container
├── .env.example # Environment variable reference
├── .gitignore # Git ignore rules
├── ai_instructions.md # Detailed AI agent & vibe coding guidelines
├── GEMINI.md # Gemini CLI / Antigravity agent rules
├── .cursorrules # Cursor AI agent rules
├── .clinerules # Cline / Roo-Code agent rules
└── .github/
├── copilot-instructions.md # GitHub Copilot agent rules
└── workflows/
└── build-docker.yml # CI/CD: build & push Docker image to ghcr.io
We recommend using a virtual environment (Python 3.10+):
# Clone the repository and navigate inside
cd recognize-ai-backend
# Create and activate a virtual environment
python -m venv .venv
# On Windows (PowerShell):
.venv\Scripts\Activate.ps1
# On Linux / macOS:
source .venv/bin/activate
# Install core runtime dependencies
pip install -r requirements.txt
# Install development & model export dependencies
pip install -r requirements-dev.txt
Download and export all three .onnx models into the models/ directory with a single command:
python download_models.py
Or download models selectively:
python download_models.py yolo # YOLOv8n only (~12 MB)
python download_models.py arcface # ArcFace only (~260 MB)
python download_models.py clip # CLIP ViT-B/32 only (~605 MB)
Start the FastAPI server:
python main.py
The server will start on http://127.0.0.1:8000. The startup lifespan will attempt to pre-load all configured ONNX models.
Build and run with Docker:
# CPU build
docker build -t recognize-backend .
docker run -p 8000:8000 -v ./models:/app/models recognize-backend
# GPU build (requires NVIDIA Container Toolkit)
docker build --build-arg GPU=true -t recognize-backend-gpu .
docker run --gpus all -p 8000:8000 -v ./models:/app/models recognize-backend-gpu
This backend can run as a Nextcloud External App (ExApp) via the AppAPI framework, giving Nextcloud full lifecycle control over the container.
In your Nextcloud Admin settings, navigate to AppAPI → Deploy Daemons and configure a Docker-based daemon. This tells AppAPI how to pull and manage ExApp containers.
Register and deploy the ExApp using the Nextcloud occ CLI:
sudo -u www-data php occ app_api:app:register recognize_ai \
--info-xml https://raw.githubusercontent.com/pener/recognize-ai-backend/main/appinfo/info.xml \
--json-info "{\"appid\":\"recognize_ai\",\"name\":\"Recognize AI\",\"daemon_config_name\":\"docker_install\",\"version\":\"1.0.0\",\"secret\":\"auto\",\"port\":8000,\"routes\":[{\"url\":\".*\",\"verb\":\"GET,POST,PUT,DELETE\",\"access_level\":\"ADMIN\",\"headers_to_exclude\":[]}]}" \
--force-scopes \
--wait-finish
AppAPI will automatically:
ghcr.io/pener/recognize-ai-backend:latestAPP_ID, APP_SECRET, and NEXTCLOUD_URL environment variablesAfter installation, navigate to Admin Settings → Recognize AI to:
| Feature | Standalone | ExApp |
|---|---|---|
| Startup | python main.py | Managed by AppAPI |
| Auth | None (open API) | AppAPI shared secret |
| Scanner | Not available | Background file scanning |
| Admin Panel | Not available | Vue.js settings UI |
| Config | .env file | Nextcloud Admin Settings |
Note: When developing locally, use standalone mode (
python main.py). The ExApp lifecycle hooks innc_app.pyare only active whenAPP_IDandAPP_SECRETenvironment variables are present.
The ExApp includes a Vue.js admin settings panel (src/) providing:
Checks if the backend microservice is alive.
GET /health{ "status": "ok", "message": "Recognize ExApp is running." }
Returns the active state and loading status of all backend models.
GET /models/status{
"yolov8n": { "loaded": true, "error": null },
"arcface": { "loaded": true, "error": null },
"clip_visual": { "loaded": true, "error": null }
}
Detects 80 classes of objects within an image.
POST /analyze/objectsfile (image bytes).200):
[
{ "class": "person", "score": 0.8942, "box": [120, 45, 340, 580] },
{ "class": "tie", "score": 0.7612, "box": [210, 150, 245, 310] }
]
(Bounding boxes are [x_min, y_min, x_max, y_max] in original image pixel coordinates).Crops faces using person detections and extracts 512-dimensional L2-normalized face embeddings.
POST /analyze/facesfile (image bytes).200):
[
{ "embedding": [0.0241, -0.0152, "... 512 values ..."], "box": [120, 45, 340, 580] }
]
Generates high-fidelity visual embeddings for semantic cataloging and text-to-image queries.
POST /analyze/semanticfile (image bytes).200):
[ { "embedding": [-0.0118, 0.0345, "... 512 values ..."] } ]
| HTTP Code | Condition |
|---|---|
413 | File exceeds MAX_UPLOAD_SIZE (default 20 MB) |
422 | Bad input (empty file, missing field) |
500 | Unexpected inference crash |
503 | Model unavailable (not loaded) |
Verify the entire setup using the built-in test_client.py script. It tests all 5 endpoints (/health, /models/status, and all three analysis routes):
python test_client.py
Customize the runtime via environment variables (see .env.example):
| Variable | Default | Description |
|---|---|---|
RECOGNIZE_MODELS_DIR | ./models | Directory storing .onnx models |
RECOGNIZE_HOST | 127.0.0.1 | Server host address |
RECOGNIZE_PORT | 8000 | Server port |
RECOGNIZE_MAX_UPLOAD_SIZE | 20971520 (20 MB) | Maximum upload file size in bytes |
RECOGNIZE_ONNX_PROVIDERS | CUDAExecutionProvider,CPUExecutionProvider | Ordered list of ONNX providers |
To run on GPU, ensure you have the appropriate CUDA Toolkit installed along with onnxruntime-gpu.
Before making changes to this codebase, read ai_instructions.md. It contains:
Agent-specific rule files are also available:
GEMINI.md.cursorrules.clinerules.github/copilot-instructions.md2 commits
Python
67.1%
Vue
28.2%
Dockerfile
3.5%
JavaScript
1.2%
An extremely fast, lightweight, and hardware-accelerated AI microservice built specifically as an External App (ExApp) for Nextcloud Recognize. It serves object detection, facial recognition/embeddings, and semantic image embeddings using ONNX Runtime with automatic execution provider selection (e.g., CUDA for Nvidia GPUs, or highly optimized CPU threads).
+-----------------------------+
| Nextcloud Recognize (App) |
+--------------+--------------+
|
REST API / | 1. Upload Image
HTTP POST | 2. Get JSON Results
v
+-------------------+--------------------+
| FastAPI ExApp Backend (Port 8000) |
+-------------------+--------------------+
|
+------------------------+------------------------+
| | |
v v v
+------------------+ +------------------+ +------------------+
| YOLOv8n | | ArcFace | | CLIP |
| (Object Det.) | | (Face Embeddings)| | (Semantic Search)|
+--------+---------+ +--------+---------+ +--------+---------+
| | |
+------------------------+------------------------+
|
v
+-------------+-------------+
| ONNX Runtime Engine |
| - CUDA (GPU Accelerated) |
| - CPU (Fallback / Native) |
+---------------------------+
ModelManager, with on-the-fly fallback loading if needed.recognize-ai-backend/
├── config.py # Global settings, class lists, thresholds, env vars
├── main.py # FastAPI server entrypoint and endpoint routes
├── inference.py # Image preprocessing, NMS, and ONNX execution pipelines
├── utils.py # Lazy ModelManager and ONNX session initialization
├── nc_app.py # Nextcloud ExApp lifecycle (nc-py-api registration)
├── scanner.py # Background file scanner for automatic media classification
├── download_models.py # Unified downloader/exporter for YOLO, ArcFace, and CLIP
├── export_clip.py # Standalone CLIP exporter (legacy, use download_models.py)
├── test_client.py # Functional testing client (sends test requests)
├── models/ # ONNX model storage (.onnx files, gitignored)
├── appinfo/
│ └── info.xml # Nextcloud ExApp manifest (app ID, version, deploy config)
├── src/
│ └── main.js # Vue.js admin settings panel (webpack-built frontend)
├── requirements.txt # Runtime dependencies
├── requirements-dev.txt # Development & model export dependencies
├── Dockerfile # Multi-stage CPU/GPU production container
├── .env.example # Environment variable reference
├── .gitignore # Git ignore rules
├── ai_instructions.md # Detailed AI agent & vibe coding guidelines
├── GEMINI.md # Gemini CLI / Antigravity agent rules
├── .cursorrules # Cursor AI agent rules
├── .clinerules # Cline / Roo-Code agent rules
└── .github/
├── copilot-instructions.md # GitHub Copilot agent rules
└── workflows/
└── build-docker.yml # CI/CD: build & push Docker image to ghcr.io
We recommend using a virtual environment (Python 3.10+):
# Clone the repository and navigate inside
cd recognize-ai-backend
# Create and activate a virtual environment
python -m venv .venv
# On Windows (PowerShell):
.venv\Scripts\Activate.ps1
# On Linux / macOS:
source .venv/bin/activate
# Install core runtime dependencies
pip install -r requirements.txt
# Install development & model export dependencies
pip install -r requirements-dev.txt
Download and export all three .onnx models into the models/ directory with a single command:
python download_models.py
Or download models selectively:
python download_models.py yolo # YOLOv8n only (~12 MB)
python download_models.py arcface # ArcFace only (~260 MB)
python download_models.py clip # CLIP ViT-B/32 only (~605 MB)
Start the FastAPI server:
python main.py
The server will start on http://127.0.0.1:8000. The startup lifespan will attempt to pre-load all configured ONNX models.
Build and run with Docker:
# CPU build
docker build -t recognize-backend .
docker run -p 8000:8000 -v ./models:/app/models recognize-backend
# GPU build (requires NVIDIA Container Toolkit)
docker build --build-arg GPU=true -t recognize-backend-gpu .
docker run --gpus all -p 8000:8000 -v ./models:/app/models recognize-backend-gpu
This backend can run as a Nextcloud External App (ExApp) via the AppAPI framework, giving Nextcloud full lifecycle control over the container.
In your Nextcloud Admin settings, navigate to AppAPI → Deploy Daemons and configure a Docker-based daemon. This tells AppAPI how to pull and manage ExApp containers.
Register and deploy the ExApp using the Nextcloud occ CLI:
sudo -u www-data php occ app_api:app:register recognize_ai \
--info-xml https://raw.githubusercontent.com/pener/recognize-ai-backend/main/appinfo/info.xml \
--json-info "{\"appid\":\"recognize_ai\",\"name\":\"Recognize AI\",\"daemon_config_name\":\"docker_install\",\"version\":\"1.0.0\",\"secret\":\"auto\",\"port\":8000,\"routes\":[{\"url\":\".*\",\"verb\":\"GET,POST,PUT,DELETE\",\"access_level\":\"ADMIN\",\"headers_to_exclude\":[]}]}" \
--force-scopes \
--wait-finish
AppAPI will automatically:
ghcr.io/pener/recognize-ai-backend:latestAPP_ID, APP_SECRET, and NEXTCLOUD_URL environment variablesAfter installation, navigate to Admin Settings → Recognize AI to:
| Feature | Standalone | ExApp |
|---|---|---|
| Startup | python main.py | Managed by AppAPI |
| Auth | None (open API) | AppAPI shared secret |
| Scanner | Not available | Background file scanning |
| Admin Panel | Not available | Vue.js settings UI |
| Config | .env file | Nextcloud Admin Settings |
Note: When developing locally, use standalone mode (
python main.py). The ExApp lifecycle hooks innc_app.pyare only active whenAPP_IDandAPP_SECRETenvironment variables are present.
The ExApp includes a Vue.js admin settings panel (src/) providing:
Checks if the backend microservice is alive.
GET /health{ "status": "ok", "message": "Recognize ExApp is running." }
Returns the active state and loading status of all backend models.
GET /models/status{
"yolov8n": { "loaded": true, "error": null },
"arcface": { "loaded": true, "error": null },
"clip_visual": { "loaded": true, "error": null }
}
Detects 80 classes of objects within an image.
POST /analyze/objectsfile (image bytes).200):
[
{ "class": "person", "score": 0.8942, "box": [120, 45, 340, 580] },
{ "class": "tie", "score": 0.7612, "box": [210, 150, 245, 310] }
]
(Bounding boxes are [x_min, y_min, x_max, y_max] in original image pixel coordinates).Crops faces using person detections and extracts 512-dimensional L2-normalized face embeddings.
POST /analyze/facesfile (image bytes).200):
[
{ "embedding": [0.0241, -0.0152, "... 512 values ..."], "box": [120, 45, 340, 580] }
]
Generates high-fidelity visual embeddings for semantic cataloging and text-to-image queries.
POST /analyze/semanticfile (image bytes).200):
[ { "embedding": [-0.0118, 0.0345, "... 512 values ..."] } ]
| HTTP Code | Condition |
|---|---|
413 | File exceeds MAX_UPLOAD_SIZE (default 20 MB) |
422 | Bad input (empty file, missing field) |
500 | Unexpected inference crash |
503 | Model unavailable (not loaded) |
Verify the entire setup using the built-in test_client.py script. It tests all 5 endpoints (/health, /models/status, and all three analysis routes):
python test_client.py
Customize the runtime via environment variables (see .env.example):
| Variable | Default | Description |
|---|---|---|
RECOGNIZE_MODELS_DIR | ./models | Directory storing .onnx models |
RECOGNIZE_HOST | 127.0.0.1 | Server host address |
RECOGNIZE_PORT | 8000 | Server port |
RECOGNIZE_MAX_UPLOAD_SIZE | 20971520 (20 MB) | Maximum upload file size in bytes |
RECOGNIZE_ONNX_PROVIDERS | CUDAExecutionProvider,CPUExecutionProvider | Ordered list of ONNX providers |
To run on GPU, ensure you have the appropriate CUDA Toolkit installed along with onnxruntime-gpu.
Before making changes to this codebase, read ai_instructions.md. It contains:
Agent-specific rule files are also available:
GEMINI.md.cursorrules.clinerules.github/copilot-instructions.md2 commits
Python
67.1%
Vue
28.2%
Dockerfile
3.5%
JavaScript
1.2%