git: 9ad2b8676f01 - main - www/immich-ml: Add New Port
Jochen Neumeister <[email protected]>
| Newsgroups | gmane.os.freebsd.devel.cvs.ports |
|---|---|
| Message-ID | <[email protected]> |
The branch main has been updated by joneum: URL: https://cgit.FreeBSD.org/ports/commit/?id=9ad2b8676f01e5368d93550b8304ad8d552b0cde commit 9ad2b8676f01e5368d93550b8304ad8d552b0cde Author: Jochen Neumeister <[email protected]> AuthorDate: 2026-08-16 17:59:55 +0000 Commit: Jochen Neumeister <[email protected]> CommitDate: 2026-08-16 18:03:16 +0000 www/immich-ml: Add New Port Machine-learning service for Immich providing smart search (CLIP), duplicate detection and facial recognition via onnxruntime on the CPU. Models are downloaded on first use into the cache directory. OCR is not yet available as rapidocr has no FreeBSD port. WWW: https://immich.app/ Sponsored by: Netzkommune GmbH --- www/Makefile | 1 + www/immich-ml/Makefile | 57 +++++++++++++++++++ www/immich-ml/distinfo | 3 + www/immich-ml/files/immich_ml.in | 65 ++++++++++++++++++++++ .../files/patch-immich__ml_models_____init____.py | 31 +++++++++++ www/immich-ml/pkg-descr | 10 ++++ 6 files changed, 167 insertions(+) diff --git a/www/Makefile b/www/Makefile index 745bd04552eb..b807784824d2 100644 --- a/www/Makefile +++ b/www/Makefile @@ -311,6 +311,7 @@ SUBDIR += ilias SUBDIR += imaginary SUBDIR += immich + SUBDIR += immich-ml SUBDIR += iocaine SUBDIR += iridium SUBDIR += janus diff --git a/www/immich-ml/Makefile b/www/immich-ml/Makefile new file mode 100644 index 000000000000..3d9a1057d3b2 --- /dev/null +++ b/www/immich-ml/Makefile @@ -0,0 +1,57 @@ +PORTNAME= immich-ml +DISTVERSIONPREFIX= v +DISTVERSION= 3.1.0 +CATEGORIES= www python + +MAINTAINER= [email protected] +COMMENT= Machine-learning service for Immich +WWW= https://immich.app/ + +LICENSE= AGPLv3 +LICENSE_FILE= ${WRKSRC:H}/LICENSE + +BUILD_DEPENDS= ${PYTHON_PKGNAMEPREFIX}hatchling>0:devel/py-hatchling@${PY_FLAVOR} +RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}aiocache>0:devel/py-aiocache@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}fastapi>0:www/py-fastapi@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}ftfy>0:textproc/py-ftfy@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}gunicorn>0:www/py-gunicorn@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}huggingface-hub>0:misc/py-huggingface-hub@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}insightface>0:misc/py-insightface@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}ml-dtypes>0:math/py-ml-dtypes@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}numpy>0:math/py-numpy@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}onnxruntime>0:misc/py-onnxruntime@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}orjson>0:devel/py-orjson@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}pillow>0:graphics/py-pillow@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}pydantic-settings>0:devel/py-pydantic-settings@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}pydantic2>0:devel/py-pydantic2@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}python-multipart>0:www/py-python-multipart@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}rich>0:textproc/py-rich@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}tokenizers>0:textproc/py-tokenizers@${PY_FLAVOR} \ + ${PYTHON_PKGNAMEPREFIX}uvicorn>0:www/py-uvicorn@${PY_FLAVOR} \ + opencv>0:graphics/opencv + +USES= python + +USE_GITHUB= yes +GH_ACCOUNT= immich-app +GH_PROJECT= immich + +USE_PYTHON= autoplist pep517 +USE_RC_SUBR= immich_ml + +SUB_LIST= PYTHON_CMD=${PYTHON_CMD} + +WRKSRC_SUBDIR= machine-learning + +USERS= immich +GROUPS= immich + +post-patch: + @${REINPLACE_CMD} -e "s|uvicorn\[standard\]|uvicorn|" \ + -e "/opencv-python-headless/d" \ + -e "/rapidocr/d" \ + ${WRKSRC}/pyproject.toml + @${REINPLACE_CMD} -e 's|"python",|"${PYTHON_CMD}",|' \ + ${WRKSRC}/immich_ml/__main__.py + +.include <bsd.port.mk> diff --git a/www/immich-ml/distinfo b/www/immich-ml/distinfo new file mode 100644 index 000000000000..0a863ce782aa --- /dev/null +++ b/www/immich-ml/distinfo @@ -0,0 +1,3 @@ +TIMESTAMP = 1786859142 +SHA256 (immich-app-immich-v3.1.0_GH0.tar.gz) = af0fba69cc5830093392de4f5576eeb7f2ccf28ba55154b7598e10f596fdfb40 +SIZE (immich-app-immich-v3.1.0_GH0.tar.gz) = 74961232 diff --git a/www/immich-ml/files/immich_ml.in b/www/immich-ml/files/immich_ml.in new file mode 100644 index 000000000000..15db43dcd488 --- /dev/null +++ b/www/immich-ml/files/immich_ml.in @@ -0,0 +1,65 @@ +#!/bin/sh + +# PROVIDE: immich_ml +# REQUIRE: LOGIN +# KEYWORD: shutdown +# +# Add these lines to /etc/rc.conf.local or /etc/rc.conf +# to enable this service: +# +# immich_ml_enable (bool): Set to NO by default. +# Set it to YES to enable immich-ml. +# immich_ml_cache_folder (str): Model cache directory. +# Default: /var/db/immich-ml +# immich_ml_host (str): Listen address. Default: 127.0.0.1 +# immich_ml_port (int): Listen port. Default: 3003 + +. /etc/rc.subr + +name=immich_ml +rcvar=immich_ml_enable + +load_rc_config $name + +: ${immich_ml_enable:=NO} +: ${immich_ml_user:=immich} +: ${immich_ml_group:=immich} +: ${immich_ml_cache_folder:=/var/db/immich-ml} +: ${immich_ml_host:=127.0.0.1} +: ${immich_ml_port:=3003} +: ${immich_ml_env:="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \ + HOME=${immich_ml_cache_folder} \ + MACHINE_LEARNING_CACHE_FOLDER=${immich_ml_cache_folder} \ + IMMICH_HOST=${immich_ml_host} \ + IMMICH_PORT=${immich_ml_port}"} + +pidfile=/var/run/immich/${name}.pid + +start_precmd=immich_ml_precmd +stop_cmd=immich_ml_stop +command=/usr/sbin/daemon +command_args="-f -S -P ${pidfile} \ + -o /var/log/immich/${name}.log \ + %%PYTHON_CMD%% -m immich_ml" + +immich_ml_stop() +{ + local pid + pid=$(check_pidfile ${pidfile} ${command}) + if [ -z "$pid" ]; then + echo "${name} not running? (check ${pidfile})." + return 1 + fi + echo "Stopping ${name}." + kill -TERM -- -${pid} 2>/dev/null || kill -TERM ${pid} + wait_for_pids ${pid} + rm -f ${pidfile} +} + +immich_ml_precmd() +{ + install -d -o ${immich_ml_user} -g ${immich_ml_group} \ + /var/run/immich /var/log/immich ${immich_ml_cache_folder} +} + +run_rc_command "$1" diff --git a/www/immich-ml/files/patch-immich__ml_models_____init____.py b/www/immich-ml/files/patch-immich__ml_models_____init____.py new file mode 100644 index 000000000000..4194c4d22c4b --- /dev/null +++ b/www/immich-ml/files/patch-immich__ml_models_____init____.py @@ -0,0 +1,31 @@ +--- immich_ml/models/__init__.py.orig 2026-08-16 16:21:56 UTC ++++ immich_ml/models/__init__.py +@@ -3,8 +3,12 @@ from immich_ml.models.clip.visual import OpenClipVisua + from immich_ml.models.base import InferenceModel + from immich_ml.models.clip.textual import MClipTextualEncoder, OpenClipTextualEncoder + from immich_ml.models.clip.visual import OpenClipVisualEncoder +-from immich_ml.models.ocr.detection import TextDetector +-from immich_ml.models.ocr.recognition import TextRecognizer ++try: ++ from immich_ml.models.ocr.detection import TextDetector ++ from immich_ml.models.ocr.recognition import TextRecognizer ++except ImportError: # rapidocr has not been ported to FreeBSD yet ++ TextDetector = None # type: ignore[assignment,misc] ++ TextRecognizer = None # type: ignore[assignment,misc] + from immich_ml.schemas import ModelSource, ModelTask, ModelType + + from .constants import get_model_source +@@ -31,9 +35,13 @@ def get_model_class(model_name: str, model_type: Model + return FaceRecognizer + + case ModelSource.PADDLE, ModelType.DETECTION, ModelTask.OCR: ++ if TextDetector is None: ++ raise ValueError("OCR models require rapidocr, which is not available") + return TextDetector + + case ModelSource.PADDLE, ModelType.RECOGNITION, ModelTask.OCR: ++ if TextRecognizer is None: ++ raise ValueError("OCR models require rapidocr, which is not available") + return TextRecognizer + + case _: diff --git a/www/immich-ml/pkg-descr b/www/immich-ml/pkg-descr new file mode 100644 index 000000000000..26fac63e8a1a --- /dev/null +++ b/www/immich-ml/pkg-descr @@ -0,0 +1,10 @@ +The Immich machine-learning service provides smart search (CLIP), +duplicate detection and facial recognition for an Immich server. +It is a FastAPI application that executes ONNX models with +onnxruntime on the CPU. Models are downloaded automatically on +first use into the cache directory. + +The service listens on port 3003 by default and is consumed by +www/immich; point the Immich server at it via its machine-learning +URL setting. OCR (text search in images) is currently not +available on FreeBSD because rapidocr is not ported yet.