mirror of
https://github.com/photoprism/photoprism.git
synced 2025-12-11 16:24:11 +01:00
AI: Add support for OLLAMA_BASE_URL env expansion in vision.yml #5361
Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
@@ -38,6 +38,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
GO111MODULE="on" \
|
GO111MODULE="on" \
|
||||||
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
S6_KEEP_ENV=1 \
|
S6_KEEP_ENV=1 \
|
||||||
S6_VERBOSITY=0 \
|
S6_VERBOSITY=0 \
|
||||||
S6_LOGGING=0
|
S6_LOGGING=0
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism"
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434"
|
||||||
|
|
||||||
# Copy scripts and package sources config.
|
# Copy scripts and package sources config.
|
||||||
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
GOBIN="/usr/local/bin" \
|
GOBIN="/usr/local/bin" \
|
||||||
GO111MODULE="on" \
|
GO111MODULE="on" \
|
||||||
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
||||||
PROG="photoprism"
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434"
|
||||||
|
|
||||||
# Copy scripts and package sources config.
|
# Copy scripts and package sources config.
|
||||||
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism"
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434"
|
||||||
|
|
||||||
# copy scripts and debian backports sources list
|
# copy scripts and debian backports sources list
|
||||||
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
GOBIN="/usr/local/bin" \
|
GOBIN="/usr/local/bin" \
|
||||||
GO111MODULE="on" \
|
GO111MODULE="on" \
|
||||||
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
||||||
PROG="photoprism"
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434"
|
||||||
|
|
||||||
# copy scripts and debian backports sources list
|
# copy scripts and debian backports sources list
|
||||||
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
GOBIN="/usr/local/bin" \
|
GOBIN="/usr/local/bin" \
|
||||||
GO111MODULE="on" \
|
GO111MODULE="on" \
|
||||||
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
||||||
PROG="photoprism"
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434"
|
||||||
|
|
||||||
# copy scripts and debian backports sources list
|
# copy scripts and debian backports sources list
|
||||||
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
GOBIN="/usr/local/bin" \
|
GOBIN="/usr/local/bin" \
|
||||||
GO111MODULE="on" \
|
GO111MODULE="on" \
|
||||||
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
||||||
PROG="photoprism"
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434"
|
||||||
|
|
||||||
# copy scripts and debian backports sources list
|
# copy scripts and debian backports sources list
|
||||||
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
S6_KEEP_ENV=0 \
|
S6_KEEP_ENV=0 \
|
||||||
S6_VERBOSITY=0 \
|
S6_VERBOSITY=0 \
|
||||||
S6_LOGGING=0
|
S6_LOGGING=0
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
GO111MODULE="on" \
|
GO111MODULE="on" \
|
||||||
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
S6_KEEP_ENV=1 \
|
S6_KEEP_ENV=1 \
|
||||||
S6_VERBOSITY=0 \
|
S6_VERBOSITY=0 \
|
||||||
S6_LOGGING=0
|
S6_LOGGING=0
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism"
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434"
|
||||||
|
|
||||||
# Copy scripts and package sources config.
|
# Copy scripts and package sources config.
|
||||||
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
GOBIN="/usr/local/bin" \
|
GOBIN="/usr/local/bin" \
|
||||||
GO111MODULE="on" \
|
GO111MODULE="on" \
|
||||||
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
||||||
PROG="photoprism"
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434"
|
||||||
|
|
||||||
# Copy scripts and package sources config.
|
# Copy scripts and package sources config.
|
||||||
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism"
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434"
|
||||||
|
|
||||||
# Copy scripts and package sources config.
|
# Copy scripts and package sources config.
|
||||||
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
GOBIN="/usr/local/bin" \
|
GOBIN="/usr/local/bin" \
|
||||||
GO111MODULE="on" \
|
GO111MODULE="on" \
|
||||||
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
||||||
PROG="photoprism"
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434"
|
||||||
|
|
||||||
# Copy scripts and package sources config.
|
# Copy scripts and package sources config.
|
||||||
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism"
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434"
|
||||||
|
|
||||||
# Copy scripts and package sources config.
|
# Copy scripts and package sources config.
|
||||||
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
GOBIN="/usr/local/bin" \
|
GOBIN="/usr/local/bin" \
|
||||||
GO111MODULE="on" \
|
GO111MODULE="on" \
|
||||||
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
||||||
PROG="photoprism"
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434"
|
||||||
|
|
||||||
# Copy scripts and package sources config.
|
# Copy scripts and package sources config.
|
||||||
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
COPY --chown=root:root --chmod=755 /scripts/dist/ /scripts/
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
S6_KEEP_ENV=0 \
|
S6_KEEP_ENV=0 \
|
||||||
S6_VERBOSITY=0 \
|
S6_VERBOSITY=0 \
|
||||||
S6_LOGGING=0
|
S6_LOGGING=0
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
GO111MODULE="on" \
|
GO111MODULE="on" \
|
||||||
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
S6_KEEP_ENV=1 \
|
S6_KEEP_ENV=1 \
|
||||||
S6_VERBOSITY=0 \
|
S6_VERBOSITY=0 \
|
||||||
S6_LOGGING=0
|
S6_LOGGING=0
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
S6_KEEP_ENV=0 \
|
S6_KEEP_ENV=0 \
|
||||||
S6_VERBOSITY=0 \
|
S6_VERBOSITY=0 \
|
||||||
S6_LOGGING=0
|
S6_LOGGING=0
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
GO111MODULE="on" \
|
GO111MODULE="on" \
|
||||||
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
S6_KEEP_ENV=1 \
|
S6_KEEP_ENV=1 \
|
||||||
S6_VERBOSITY=0 \
|
S6_VERBOSITY=0 \
|
||||||
S6_LOGGING=0
|
S6_LOGGING=0
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434"
|
||||||
S6_KEEP_ENV=0 \
|
S6_KEEP_ENV=0 \
|
||||||
S6_VERBOSITY=0 \
|
S6_VERBOSITY=0 \
|
||||||
S6_LOGGING=0
|
S6_LOGGING=0
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
GO111MODULE="on" \
|
GO111MODULE="on" \
|
||||||
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
CGO_CFLAGS="-g -O2 -Wno-return-local-addr" \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434"
|
||||||
S6_KEEP_ENV=1 \
|
S6_KEEP_ENV=1 \
|
||||||
S6_VERBOSITY=0 \
|
S6_VERBOSITY=0 \
|
||||||
S6_LOGGING=0
|
S6_LOGGING=0
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_CPP_MIN_LOG_LEVEL=4 \
|
TF_CPP_MIN_LOG_LEVEL=4 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434"
|
||||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||||
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||||
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||||
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||||
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||||
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||||
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||||
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||||
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||||
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||||
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||||
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ ENV PHOTOPRISM_ARCH=$TARGETARCH \
|
|||||||
TF_ENABLE_ONEDNN_OPTS=1 \
|
TF_ENABLE_ONEDNN_OPTS=1 \
|
||||||
MALLOC_ARENA_MAX=2 \
|
MALLOC_ARENA_MAX=2 \
|
||||||
PROG="photoprism" \
|
PROG="photoprism" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434" \
|
||||||
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
PHOTOPRISM_ASSETS_PATH="/opt/photoprism/assets" \
|
||||||
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
PHOTOPRISM_IMPORT_PATH="/photoprism/import" \
|
||||||
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
PHOTOPRISM_ORIGINALS_PATH="/photoprism/originals" \
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
## PhotoPrism — Vision Package
|
## PhotoPrism — Vision Package
|
||||||
|
|
||||||
**Last Updated:** December 2, 2025
|
**Last Updated:** December 10, 2025
|
||||||
|
|
||||||
### Overview
|
### Overview
|
||||||
|
|
||||||
`internal/ai/vision` provides the shared model registry, request builders, and parsers that power PhotoPrism’s caption, label, face, NSFW, and future generate workflows. It reads `vision.yml`, normalizes models, and dispatches calls to one of three engines:
|
`internal/ai/vision` provides the shared model registry, request builders, and parsers that power PhotoPrism’s caption, label, face, NSFW, and future generate workflows. It reads `vision.yml`, normalizes models, and dispatches calls to one of three engines:
|
||||||
|
|
||||||
- **TensorFlow (built‑in)** — default Nasnet / NSFW / Facenet models, no remote service required.
|
- **TensorFlow (built‑in)** — default Nasnet / NSFW / Facenet models, no remote service required.
|
||||||
- **Ollama** — local or proxied multimodal LLMs. See [`ollama/README.md`](ollama/README.md) for tuning and schema details.
|
- **Ollama** — local or proxied multimodal LLMs. See [`ollama/README.md`](ollama/README.md) for tuning and schema details. The engine defaults to `${OLLAMA_BASE_URL:-http://ollama:11434}/api/generate`, trimming any trailing slash on the base URL; set `OLLAMA_BASE_URL=https://ollama.com` to opt into cloud defaults.
|
||||||
- **OpenAI** — cloud Responses API. See [`openai/README.md`](openai/README.md) for prompts, schema variants, and header requirements.
|
- **OpenAI** — cloud Responses API. See [`openai/README.md`](openai/README.md) for prompts, schema variants, and header requirements.
|
||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
@@ -94,8 +94,8 @@ The model `Options` adjust model parameters such as temperature, top-p, and sche
|
|||||||
Configures the endpoint URL, method, format, and authentication for [Ollama](ollama/README.md), [OpenAI](openai/README.md), and other engines that perform remote HTTP requests:
|
Configures the endpoint URL, method, format, and authentication for [Ollama](ollama/README.md), [OpenAI](openai/README.md), and other engines that perform remote HTTP requests:
|
||||||
|
|
||||||
| Field | Default | Notes |
|
| Field | Default | Notes |
|
||||||
|------------------------------------|------------------------------------------|------------------------------------------------------------------------------------------|
|
|------------------------------------|------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `Uri` | required for remote | Endpoint base. Empty keeps model local (TensorFlow). |
|
| `Uri` | required for remote | Endpoint base. Empty keeps model local (TensorFlow). Ollama alias fills `${OLLAMA_BASE_URL}/api/generate`, defaulting to `http://ollama:11434`. |
|
||||||
| `Method` | `POST` | Override verb if provider needs it. |
|
| `Method` | `POST` | Override verb if provider needs it. |
|
||||||
| `Key` | `""` | Bearer token; prefer env expansion (OpenAI: `OPENAI_API_KEY`, Ollama: `OLLAMA_API_KEY`). |
|
| `Key` | `""` | Bearer token; prefer env expansion (OpenAI: `OPENAI_API_KEY`, Ollama: `OLLAMA_API_KEY`). |
|
||||||
| `Username` / `Password` | `""` | Injected as basic auth when URI lacks userinfo. |
|
| `Username` / `Password` | `""` | Injected as basic auth when URI lacks userinfo. |
|
||||||
@@ -142,7 +142,7 @@ Models:
|
|||||||
Engine: ollama
|
Engine: ollama
|
||||||
Run: newly-indexed
|
Run: newly-indexed
|
||||||
Service:
|
Service:
|
||||||
Uri: http://ollama:11434/api/generate
|
Uri: ${OLLAMA_BASE_URL}/api/generate
|
||||||
```
|
```
|
||||||
|
|
||||||
More Ollama guidance: [`internal/ai/vision/ollama/README.md`](ollama/README.md).
|
More Ollama guidance: [`internal/ai/vision/ollama/README.md`](ollama/README.md).
|
||||||
|
|||||||
@@ -28,25 +28,25 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// registerOllamaEngineDefaults selects the default Ollama endpoint based on the
|
// registerOllamaEngineDefaults selects the default Ollama endpoint based on the
|
||||||
// available credentials and registers the engine alias accordingly. When an
|
// configured base URL and registers the engine alias accordingly. When
|
||||||
// API key is configured, we default to the hosted Cloud endpoint; otherwise we
|
// OLLAMA_BASE_URL points at the cloud host we only switch the default model to
|
||||||
// assume a self-hosted instance reachable via the docker-compose default.
|
// the cloud preset; the actual base URL continues to come from
|
||||||
// This keeps the zero-config path fast for local dev while automatically using
|
// OLLAMA_BASE_URL (or falls back to the local compose default) so we don't
|
||||||
// the cloud service when credentials are present.
|
// accidentally talk to the hosted service without an explicit endpoint.
|
||||||
func registerOllamaEngineDefaults() {
|
func registerOllamaEngineDefaults() {
|
||||||
defaultModel := ollama.DefaultModel
|
ensureEnv()
|
||||||
defaultUri := ollama.DefaultUri
|
|
||||||
|
|
||||||
// Detect Ollama cloud API key.
|
defaultModel := ollama.DefaultModel
|
||||||
if key := os.Getenv(ollama.APIKeyEnv); len(key) > 50 && strings.Contains(key, ".") {
|
|
||||||
|
// Use different default model for the Ollama cloud service.
|
||||||
|
if baseUrl := os.Getenv(ollama.BaseUrlEnv); baseUrl == ollama.CloudBaseUrl {
|
||||||
defaultModel = ollama.CloudModel
|
defaultModel = ollama.CloudModel
|
||||||
defaultUri = ollama.CloudUri
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the human-friendly engine name so configuration can simply use
|
// Register the human-friendly engine name so configuration can simply use
|
||||||
// `Engine: "ollama"` and inherit adapter defaults.
|
// `Engine: "ollama"` and inherit adapter defaults.
|
||||||
RegisterEngineAlias(ollama.EngineName, EngineInfo{
|
RegisterEngineAlias(ollama.EngineName, EngineInfo{
|
||||||
Uri: defaultUri,
|
Uri: ollama.DefaultUri,
|
||||||
RequestFormat: ApiFormatOllama,
|
RequestFormat: ApiFormatOllama,
|
||||||
ResponseFormat: ApiFormatOllama,
|
ResponseFormat: ApiFormatOllama,
|
||||||
FileScheme: scheme.Base64,
|
FileScheme: scheme.Base64,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/ai/vision/ollama"
|
"github.com/photoprism/photoprism/internal/ai/vision/ollama"
|
||||||
@@ -29,6 +30,7 @@ func TestRegisterOllamaEngineDefaults(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("SelfHosted", func(t *testing.T) {
|
t.Run("SelfHosted", func(t *testing.T) {
|
||||||
|
ensureEnvOnce = sync.Once{}
|
||||||
CaptionModel = testCaptionModel.Clone()
|
CaptionModel = testCaptionModel.Clone()
|
||||||
_ = os.Unsetenv(ollama.APIKeyEnv)
|
_ = os.Unsetenv(ollama.APIKeyEnv)
|
||||||
|
|
||||||
@@ -56,8 +58,9 @@ func TestRegisterOllamaEngineDefaults(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
t.Run("Cloud", func(t *testing.T) {
|
t.Run("Cloud", func(t *testing.T) {
|
||||||
|
ensureEnvOnce = sync.Once{}
|
||||||
CaptionModel = testCaptionModel.Clone()
|
CaptionModel = testCaptionModel.Clone()
|
||||||
t.Setenv(ollama.APIKeyEnv, cloudToken)
|
t.Setenv(ollama.BaseUrlEnv, ollama.CloudBaseUrl+"/")
|
||||||
|
|
||||||
registerOllamaEngineDefaults()
|
registerOllamaEngineDefaults()
|
||||||
|
|
||||||
@@ -66,8 +69,8 @@ func TestRegisterOllamaEngineDefaults(t *testing.T) {
|
|||||||
t.Fatalf("expected engine info for %s", ollama.EngineName)
|
t.Fatalf("expected engine info for %s", ollama.EngineName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.Uri != ollama.CloudUri {
|
if info.Uri != ollama.DefaultUri {
|
||||||
t.Fatalf("expected cloud uri %s, got %s", ollama.CloudUri, info.Uri)
|
t.Fatalf("expected default uri %s, got %s", ollama.DefaultUri, info.Uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.DefaultModel != ollama.CloudModel {
|
if info.DefaultModel != ollama.CloudModel {
|
||||||
@@ -78,14 +81,31 @@ func TestRegisterOllamaEngineDefaults(t *testing.T) {
|
|||||||
t.Fatalf("expected caption model %s, got %s", ollama.CloudModel, CaptionModel.Model)
|
t.Fatalf("expected caption model %s, got %s", ollama.CloudModel, CaptionModel.Model)
|
||||||
}
|
}
|
||||||
|
|
||||||
if CaptionModel.Service.Uri != ollama.CloudUri {
|
if CaptionModel.Service.Uri != ollama.DefaultUri {
|
||||||
t.Fatalf("expected caption model uri %s, got %s", ollama.CloudUri, CaptionModel.Service.Uri)
|
t.Fatalf("expected caption model uri %s, got %s", ollama.DefaultUri, CaptionModel.Service.Uri)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("ApiKeyAloneKeepsLocalDefaults", func(t *testing.T) {
|
||||||
|
ensureEnvOnce = sync.Once{}
|
||||||
|
CaptionModel = testCaptionModel.Clone()
|
||||||
|
t.Setenv(ollama.APIKeyEnv, cloudToken)
|
||||||
|
|
||||||
|
registerOllamaEngineDefaults()
|
||||||
|
|
||||||
|
info, ok := EngineInfoFor(ollama.EngineName)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("expected engine info for %s", ollama.EngineName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.DefaultModel != ollama.DefaultModel {
|
||||||
|
t.Fatalf("expected default model %s, got %s", ollama.DefaultModel, info.DefaultModel)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
t.Run("NewModels", func(t *testing.T) {
|
t.Run("NewModels", func(t *testing.T) {
|
||||||
|
ensureEnvOnce = sync.Once{}
|
||||||
CaptionModel = testCaptionModel.Clone()
|
CaptionModel = testCaptionModel.Clone()
|
||||||
|
|
||||||
t.Setenv(ollama.APIKeyEnv, cloudToken)
|
t.Setenv(ollama.BaseUrlEnv, ollama.CloudBaseUrl)
|
||||||
registerOllamaEngineDefaults()
|
registerOllamaEngineDefaults()
|
||||||
|
|
||||||
model := &Model{Type: ModelTypeCaption, Engine: ollama.EngineName}
|
model := &Model{Type: ModelTypeCaption, Engine: ollama.EngineName}
|
||||||
@@ -95,8 +115,8 @@ func TestRegisterOllamaEngineDefaults(t *testing.T) {
|
|||||||
t.Fatalf("expected model %s, got %s", ollama.CloudModel, model.Model)
|
t.Fatalf("expected model %s, got %s", ollama.CloudModel, model.Model)
|
||||||
}
|
}
|
||||||
|
|
||||||
if model.Service.Uri != ollama.CloudUri {
|
if model.Service.Uri != ollama.DefaultUri {
|
||||||
t.Fatalf("expected service uri %s, got %s", ollama.CloudUri, model.Service.Uri)
|
t.Fatalf("expected service uri %s, got %s", ollama.DefaultUri, model.Service.Uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
if model.Service.RequestFormat != ApiFormatOllama || model.Service.ResponseFormat != ApiFormatOllama {
|
if model.Service.RequestFormat != ApiFormatOllama || model.Service.ResponseFormat != ApiFormatOllama {
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
## PhotoPrism — Ollama Engine Integration
|
## PhotoPrism — Ollama Engine Integration
|
||||||
|
|
||||||
**Last Updated:** November 14, 2025
|
**Last Updated:** December 10, 2025
|
||||||
|
|
||||||
### Overview
|
### Overview
|
||||||
|
|
||||||
This package provides PhotoPrism’s native adapter for Ollama-compatible multimodal models. It lets Caption, Labels, and future Generate workflows call locally hosted models without changing worker logic, reusing the shared API client (`internal/ai/vision/api_client.go`) and result types (`LabelResult`, `CaptionResult`). Requests stay inside your infrastructure, rely on base64 thumbnails, and honor the same ACL, timeout, and logging hooks as the default TensorFlow engines.
|
This package provides PhotoPrism’s native adapter for Ollama-compatible multimodal models. It lets Caption, Labels, and future Generate workflows call locally hosted models without changing worker logic, reusing the shared API client (`internal/ai/vision/api_client.go`) and result types (`LabelResult`, `CaptionResult`). Requests stay inside your infrastructure, rely on base64 thumbnails, and honor the same ACL, timeout, and logging hooks as the default TensorFlow engines. The adapter resolves `${OLLAMA_BASE_URL}/api/generate`, trimming trailing slashes and defaulting to `http://ollama:11434`; set `OLLAMA_BASE_URL=https://ollama.com` to opt into cloud defaults.
|
||||||
|
|
||||||
#### Context & Constraints
|
#### Context & Constraints
|
||||||
|
|
||||||
- Engine defaults live in `internal/ai/vision/ollama` and are applied whenever a model sets `Engine: ollama`. Aliases map to `ApiFormatOllama`, `scheme.Base64`, and a default 720 px thumbnail.
|
- Engine defaults live in `internal/ai/vision/ollama` and are applied whenever a model sets `Engine: ollama`. Aliases map to `ApiFormatOllama`, `scheme.Base64`, and a default 720 px thumbnail. Cloud defaults are only selected when `OLLAMA_BASE_URL` equals `https://ollama.com`.
|
||||||
- Responses may arrive as newline-delimited JSON chunks. `decodeOllamaResponse` keeps the most recent chunk, while `parseOllamaLabels` replays plain JSON strings found in `response`.
|
- Responses may arrive as newline-delimited JSON chunks. `decodeOllamaResponse` keeps the most recent chunk, while `parseOllamaLabels` replays plain JSON strings found in `response`.
|
||||||
- Structured JSON is optional for captions but enforced for labels when `Format: json` (default for label models targeting the Ollama engine).
|
- Structured JSON is optional for captions but enforced for labels when `Format: json` (default for label models targeting the Ollama engine).
|
||||||
- The adapter never overwrites TensorFlow defaults. If an Ollama call fails, downstream code still has Nasnet, NSFW, and Face models available.
|
- The adapter never overwrites TensorFlow defaults. If an Ollama call fails, downstream code still has Nasnet, NSFW, and Face models available.
|
||||||
@@ -73,6 +73,7 @@ This package provides PhotoPrism’s native adapter for Ollama-compatible multim
|
|||||||
- `PHOTOPRISM_VISION_YAML` — Custom `vision.yml` path. Keep it synced in Git if you automate deployments.
|
- `PHOTOPRISM_VISION_YAML` — Custom `vision.yml` path. Keep it synced in Git if you automate deployments.
|
||||||
- `OLLAMA_HOST`, `OLLAMA_MODELS`, `OLLAMA_MAX_QUEUE`, `OLLAMA_NUM_PARALLEL`, etc. — Provided in `compose*.yaml` to tune the Ollama daemon. Adjust `OLLAMA_KEEP_ALIVE` if you want models to stay loaded between worker batches.
|
- `OLLAMA_HOST`, `OLLAMA_MODELS`, `OLLAMA_MAX_QUEUE`, `OLLAMA_NUM_PARALLEL`, etc. — Provided in `compose*.yaml` to tune the Ollama daemon. Adjust `OLLAMA_KEEP_ALIVE` if you want models to stay loaded between worker batches.
|
||||||
- `OLLAMA_API_KEY` / `OLLAMA_API_KEY_FILE` — Default bearer token picked up when `Service.Key` is empty; useful for hosted Ollama services (e.g., Ollama Cloud).
|
- `OLLAMA_API_KEY` / `OLLAMA_API_KEY_FILE` — Default bearer token picked up when `Service.Key` is empty; useful for hosted Ollama services (e.g., Ollama Cloud).
|
||||||
|
- `OLLAMA_BASE_URL` — Base URL for the Ollama API; defaults to `http://ollama:11434`, trailing slashes are trimmed. Set to `https://ollama.com` to enable cloud defaults.
|
||||||
- `PHOTOPRISM_LOG_LEVEL=trace` — Enables verbose request/response previews (truncated to avoid leaking images). Use temporarily when debugging parsing issues.
|
- `PHOTOPRISM_LOG_LEVEL=trace` — Enables verbose request/response previews (truncated to avoid leaking images). Use temporarily when debugging parsing issues.
|
||||||
|
|
||||||
#### `vision.yml` Example
|
#### `vision.yml` Example
|
||||||
@@ -90,7 +91,7 @@ Models:
|
|||||||
Stop: ["\n\n"]
|
Stop: ["\n\n"]
|
||||||
ForceJson: true
|
ForceJson: true
|
||||||
Service:
|
Service:
|
||||||
Uri: http://ollama:11434/api/generate
|
Uri: ${OLLAMA_BASE_URL}/api/generate
|
||||||
RequestFormat: ollama
|
RequestFormat: ollama
|
||||||
ResponseFormat: ollama
|
ResponseFormat: ollama
|
||||||
FileScheme: base64
|
FileScheme: base64
|
||||||
@@ -102,7 +103,7 @@ Models:
|
|||||||
Options:
|
Options:
|
||||||
Temperature: 0.2
|
Temperature: 0.2
|
||||||
Service:
|
Service:
|
||||||
Uri: http://ollama:11434/api/generate
|
Uri: ${OLLAMA_BASE_URL}/api/generate
|
||||||
```
|
```
|
||||||
|
|
||||||
Guidelines:
|
Guidelines:
|
||||||
|
|||||||
@@ -11,10 +11,16 @@ const (
|
|||||||
APIKeyFileEnv = "OLLAMA_API_KEY_FILE" //nolint:gosec // environment variable name, not a secret
|
APIKeyFileEnv = "OLLAMA_API_KEY_FILE" //nolint:gosec // environment variable name, not a secret
|
||||||
// APIKeyPlaceholder is the `${VAR}` form injected when no explicit key is provided.
|
// APIKeyPlaceholder is the `${VAR}` form injected when no explicit key is provided.
|
||||||
APIKeyPlaceholder = "${" + APIKeyEnv + "}"
|
APIKeyPlaceholder = "${" + APIKeyEnv + "}"
|
||||||
|
// BaseUrlEnv defines the environment variable used for the Ollama base URL e.g. "https://ollama.com" or "http://ollama:11434".
|
||||||
|
BaseUrlEnv = "OLLAMA_BASE_URL" //nolint:gosec // environment variable name, not a secret
|
||||||
|
// BaseUrlPlaceholder is the `${VAR}` form injected when no explicit URL is provided.
|
||||||
|
BaseUrlPlaceholder = "${" + BaseUrlEnv + "}"
|
||||||
|
// DefaultBaseUrl is the local Ollama endpoint used when the environment variable is unset.
|
||||||
|
DefaultBaseUrl = "http://ollama:11434"
|
||||||
|
// CloudBaseUrl is the base URL for the Ollama Cloud service.
|
||||||
|
CloudBaseUrl = "https://ollama.com"
|
||||||
// DefaultUri is the default service URI for self-hosted Ollama instances.
|
// DefaultUri is the default service URI for self-hosted Ollama instances.
|
||||||
DefaultUri = "http://ollama:11434/api/generate"
|
DefaultUri = BaseUrlPlaceholder + "/api/generate"
|
||||||
// CloudUri is the Ollama cloud service URI
|
|
||||||
CloudUri = "https://ollama.com/api/generate"
|
|
||||||
// DefaultModel names the default caption model bundled with our adapter defaults.
|
// DefaultModel names the default caption model bundled with our adapter defaults.
|
||||||
DefaultModel = "gemma3:latest"
|
DefaultModel = "gemma3:latest"
|
||||||
// CloudModel names the default caption for the Ollama cloud service, see https://ollama.com/cloud.
|
// CloudModel names the default caption for the Ollama cloud service, see https://ollama.com/cloud.
|
||||||
|
|||||||
@@ -31,14 +31,18 @@ func (m *Service) Endpoint() (uri, method string) {
|
|||||||
return "", ""
|
return "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ensureEnv()
|
||||||
|
|
||||||
|
if uri = strings.TrimSpace(os.ExpandEnv(m.Uri)); strings.Contains(uri, "${") {
|
||||||
|
uri = ""
|
||||||
|
}
|
||||||
|
|
||||||
if m.Method != "" {
|
if m.Method != "" {
|
||||||
method = m.Method
|
method = m.Method
|
||||||
} else {
|
} else {
|
||||||
method = ServiceMethod
|
method = ServiceMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
uri = strings.TrimSpace(m.Uri)
|
|
||||||
|
|
||||||
if username, password := m.BasicAuth(); username != "" || password != "" {
|
if username, password := m.BasicAuth(); username != "" || password != "" {
|
||||||
if parsed, err := url.Parse(uri); err == nil {
|
if parsed, err := url.Parse(uri); err == nil {
|
||||||
if parsed.User == nil {
|
if parsed.User == nil {
|
||||||
|
|||||||
@@ -33,10 +33,26 @@ func TestServiceEndpoint(t *testing.T) {
|
|||||||
wantURI: "https://keep:me@vision.example.com",
|
wantURI: "https://keep:me@vision.example.com",
|
||||||
wantMethod: ServiceMethod,
|
wantMethod: ServiceMethod,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "ExpandsBaseUrlEnv",
|
||||||
|
svc: Service{Uri: "${OLLAMA_BASE_URL}/api/generate"},
|
||||||
|
wantURI: "http://custom:11434/api/generate",
|
||||||
|
wantMethod: ServiceMethod,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "FallbacksWhenEnvMissing",
|
||||||
|
svc: Service{Uri: "${OLLAMA_BASE_URL}/api/generate"},
|
||||||
|
wantURI: "http://ollama:11434/api/generate",
|
||||||
|
wantMethod: ServiceMethod,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if tt.name == "ExpandsBaseUrlEnv" {
|
||||||
|
t.Setenv("OLLAMA_BASE_URL", "http://custom:11434")
|
||||||
|
}
|
||||||
|
|
||||||
uri, method := tt.svc.Endpoint()
|
uri, method := tt.svc.Endpoint()
|
||||||
if uri != tt.wantURI {
|
if uri != tt.wantURI {
|
||||||
t.Fatalf("uri: got %q want %q", uri, tt.wantURI)
|
t.Fatalf("uri: got %q want %q", uri, tt.wantURI)
|
||||||
|
|||||||
2
internal/ai/vision/testdata/vision.yml
vendored
2
internal/ai/vision/testdata/vision.yml
vendored
@@ -70,7 +70,7 @@ Models:
|
|||||||
Run: manual
|
Run: manual
|
||||||
Resolution: 720
|
Resolution: 720
|
||||||
Service:
|
Service:
|
||||||
Uri: http://ollama:11434/api/generate
|
Uri: ${OLLAMA_BASE_URL}/api/generate
|
||||||
Key: ${OLLAMA_API_KEY}
|
Key: ${OLLAMA_API_KEY}
|
||||||
FileScheme: base64
|
FileScheme: base64
|
||||||
RequestFormat: ollama
|
RequestFormat: ollama
|
||||||
|
|||||||
@@ -25,49 +25,7 @@ Additional information can be found in our Developer Guide:
|
|||||||
package vision
|
package vision
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/ai/vision/ollama"
|
|
||||||
"github.com/photoprism/photoprism/internal/ai/vision/openai"
|
|
||||||
"github.com/photoprism/photoprism/internal/event"
|
"github.com/photoprism/photoprism/internal/event"
|
||||||
"github.com/photoprism/photoprism/pkg/clean"
|
|
||||||
"github.com/photoprism/photoprism/pkg/fs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = event.Log
|
var log = event.Log
|
||||||
|
|
||||||
var ensureEnvOnce sync.Once
|
|
||||||
|
|
||||||
// ensureEnv loads environment-backed credentials once so adapters can look up
|
|
||||||
// OPENAI_API_KEY / OLLAMA_API_KEY even when operators rely on *_FILE fallbacks.
|
|
||||||
// Future engine integrations can reuse this hook to normalise additional
|
|
||||||
// secrets.
|
|
||||||
func ensureEnv() {
|
|
||||||
ensureEnvOnce.Do(func() {
|
|
||||||
loadEnvKeyFromFile(openai.APIKeyEnv, openai.APIKeyFileEnv)
|
|
||||||
loadEnvKeyFromFile(ollama.APIKeyEnv, ollama.APIKeyFileEnv)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// loadEnvKeyFromFile populates envVar from fileVar when the environment value
|
|
||||||
// is empty and the referenced file exists and is non-empty.
|
|
||||||
func loadEnvKeyFromFile(envVar, fileVar string) {
|
|
||||||
if os.Getenv(envVar) != "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
filePath := strings.TrimSpace(os.Getenv(fileVar))
|
|
||||||
|
|
||||||
if !fs.FileExistsNotEmpty(filePath) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// #nosec G304 path provided via env
|
|
||||||
if data, err := os.ReadFile(filePath); err == nil {
|
|
||||||
if key := clean.Auth(string(data)); key != "" {
|
|
||||||
_ = os.Setenv(envVar, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
61
internal/ai/vision/vision_env.go
Normal file
61
internal/ai/vision/vision_env.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package vision
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/internal/ai/vision/ollama"
|
||||||
|
"github.com/photoprism/photoprism/internal/ai/vision/openai"
|
||||||
|
"github.com/photoprism/photoprism/pkg/clean"
|
||||||
|
"github.com/photoprism/photoprism/pkg/fs"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ensureEnvOnce sync.Once
|
||||||
|
|
||||||
|
// ensureEnv loads environment-backed credentials once so adapters can look up
|
||||||
|
// OPENAI_API_KEY / OLLAMA_API_KEY even when operators rely on *_FILE fallbacks.
|
||||||
|
// Future engine integrations can reuse this hook to normalize additional
|
||||||
|
// secrets.
|
||||||
|
func ensureEnv() {
|
||||||
|
ensureEnvOnce.Do(func() {
|
||||||
|
loadEnvKeyFromFile(openai.APIKeyEnv, openai.APIKeyFileEnv)
|
||||||
|
loadEnvKeyFromFile(ollama.APIKeyEnv, ollama.APIKeyFileEnv)
|
||||||
|
|
||||||
|
// Init the Ollama base URL by trimming trailing slashes or using the default.
|
||||||
|
initEnvUrl(ollama.BaseUrlEnv, ollama.DefaultBaseUrl)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// initEnvUrl ensures that the variable contains no trailing
|
||||||
|
// slashes and sets a default value if it is missing.
|
||||||
|
func initEnvUrl(envName, defaultUrl string) {
|
||||||
|
if base := strings.TrimSpace(os.Getenv(envName)); base != "" {
|
||||||
|
if normalized := strings.TrimRight(base, "/"); normalized != base {
|
||||||
|
_ = os.Setenv(envName, normalized)
|
||||||
|
}
|
||||||
|
} else if defaultUrl != "" {
|
||||||
|
_ = os.Setenv(envName, defaultUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadEnvKeyFromFile populates envVar from fileVar when the environment value
|
||||||
|
// is empty and the referenced file exists and is non-empty.
|
||||||
|
func loadEnvKeyFromFile(envVar, fileVar string) {
|
||||||
|
if os.Getenv(envVar) != "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
filePath := strings.TrimSpace(os.Getenv(fileVar))
|
||||||
|
|
||||||
|
if !fs.FileExistsNotEmpty(filePath) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// #nosec G304 path provided via env
|
||||||
|
if data, err := os.ReadFile(filePath); err == nil {
|
||||||
|
if key := clean.Auth(string(data)); key != "" {
|
||||||
|
_ = os.Setenv(envVar, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,31 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestInitEnvUrl(t *testing.T) {
|
||||||
|
const envName = "TEST_OLLAMA_BASE_URL"
|
||||||
|
|
||||||
|
// Case: trims trailing slash.
|
||||||
|
t.Setenv(envName, "http://example.com/")
|
||||||
|
initEnvUrl(envName, "")
|
||||||
|
if got := os.Getenv(envName); got != "http://example.com" {
|
||||||
|
t.Fatalf("trim: expected http://example.com, got %s", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case: sets default when unset.
|
||||||
|
t.Setenv(envName, "")
|
||||||
|
initEnvUrl(envName, "http://default.local")
|
||||||
|
if got := os.Getenv(envName); got != "http://default.local" {
|
||||||
|
t.Fatalf("default: expected http://default.local, got %s", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case: leaves already-normalized value untouched.
|
||||||
|
t.Setenv(envName, "http://kept.local")
|
||||||
|
initEnvUrl(envName, "http://ignored.local")
|
||||||
|
if got := os.Getenv(envName); got != "http://kept.local" {
|
||||||
|
t.Fatalf("preserve: expected http://kept.local, got %s", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestLoadEnvKeyFromFile verifies that loadEnvKeyFromFile reads API keys from
|
// TestLoadEnvKeyFromFile verifies that loadEnvKeyFromFile reads API keys from
|
||||||
// *_FILE variables when the primary env var is empty.
|
// *_FILE variables when the primary env var is empty.
|
||||||
func TestLoadEnvKeyFromFile(t *testing.T) {
|
func TestLoadEnvKeyFromFile(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user