Skip to content
Draft

squash #4280

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e7f7fd1
squash
ildyria Apr 6, 2026
e8d5a72
fix
ildyria Apr 6, 2026
859bf81
fix ty
ildyria Apr 6, 2026
c454fd7
progress but still not ready
ildyria Apr 6, 2026
073de50
WIP still broken
ildyria Apr 8, 2026
20dc32f
more work
ildyria Apr 9, 2026
21872eb
Merge branch 'master' into assisted-vision
ildyria Apr 10, 2026
fe5983c
Merge branch 'master' into assisted-vision
ildyria Apr 10, 2026
f8d0353
disable AI vision for now
ildyria Apr 10, 2026
8f440eb
fixes
ildyria Apr 11, 2026
7229e5c
Merge branch 'pr/ildyria/4280' into assisted-vision
ildyria Apr 11, 2026
9b11422
WIP
ildyria Apr 11, 2026
f2595e6
more work
ildyria Apr 11, 2026
a80de73
more things
ildyria Apr 11, 2026
f077258
Merge branch 'master' into assisted-vision
ildyria Apr 11, 2026
e5f9037
feat(feature-30): implement policy gates, request authorizers, and ri…
Copilot Apr 11, 2026
231f575
docs: tick T-030-93 through T-030-103 as completed in tasks.md
Copilot Apr 11, 2026
86b29ab
Merge branch 'master' into assisted-vision
ildyria Apr 11, 2026
0e34152
Merge branch 'master' into assisted-vision
ildyria Apr 12, 2026
cdffae9
fixes
ildyria Apr 12, 2026
5f9e727
Fix language
ildyria Apr 12, 2026
092f616
Fix ty
ildyria Apr 12, 2026
4ccc43b
more fixes
ildyria Apr 12, 2026
74ff1de
more fixes
ildyria Apr 12, 2026
00cc766
Merge branch 'master' into assisted-vision
ildyria Apr 24, 2026
d0d056e
fix open questions
ildyria Apr 24, 2026
2bf7023
feat: migrate face recognition from InsightFace to DeepFace (MIT lice…
Copilot Apr 25, 2026
34b3daa
fixes
ildyria Apr 25, 2026
800fc6e
fixes
ildyria Apr 25, 2026
90acda6
force python 3.13
ildyria Apr 25, 2026
5538bd2
fix
ildyria Apr 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 6 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ vite/*
secrets/*
# Local testing @ildyria
public/uploads-bck/*
public/uploads/*
*.sql

# Node
node_modules/
Expand All @@ -56,8 +58,12 @@ npm-debug.log
# Mapping for database and config used by docker compose
lychee/*

# Python
ai-vision-service/*

# Laravel
/storage/logs/*
/storage/tmp/*
/storage/framework/cache/*
/storage/framework/sessions/*
/storage/framework/views/*
Expand Down
3 changes: 0 additions & 3 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ updates:
dependency-type: "production"
development-dependencies:
dependency-type: "development"
ignore:
- dependency-name: "typescript"
versions: [ ">=6.0.0" ]

- package-ecosystem: composer
directory: /
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/CICD.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ on:
- '**/*.md'
- 'public/dist/*.js'
- 'public/dist/**/*.js'
- 'ai-vision-service/**'
pull_request:
paths-ignore:
- '**/*.md'
- 'public/dist/*.js'
- 'public/dist/**/*.js'
- 'ai-vision-service/**'
# Allow manually triggering the workflow.
workflow_dispatch:

Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,8 @@ jobs:
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: 'Dependency Review'
uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0
with:
# No fix available yet
# Note that the model is directly baked into the inage
# So the risk is limited.
allow-ghsas: GHSA-hqmj-h5c6-369m
153 changes: 153 additions & 0 deletions .github/workflows/python_ai_vision_face_recognition.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
name: Python AI Vision Service for face recognition

on:
push:
branches:
- master
- assisted-vision
paths:
- 'ai-vision-service/face-recognition/**'
pull_request:
paths:
- 'ai-vision-service/face-recognition/**'
workflow_dispatch:

# Declare default permissions as read only.
permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ !contains(github.ref, 'master') && !startsWith(github.ref, 'refs/tags/') }}

defaults:
run:
working-directory: ai-vision-service/face-recognition

jobs:
# ---------------------------------------------------------------------------
# Lint – formatting and style
# ---------------------------------------------------------------------------
lint:
name: Lint (ruff)
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
with:
egress-policy: audit

- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Set up uv
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
with:
enable-cache: true

- name: Install dev dependencies
run: uv sync --frozen

- name: Check formatting
run: uv run ruff format --check app/ tests/

- name: Lint
run: uv run ruff check app/ tests/

# ---------------------------------------------------------------------------
# Type check
# ---------------------------------------------------------------------------
typecheck:
name: Type check (ty)
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
with:
egress-policy: audit

- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Set up uv
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
with:
enable-cache: true

- name: Install dev dependencies
run: uv sync --frozen

- name: Type check
run: uv run ty check app/

# ---------------------------------------------------------------------------
# Test matrix – Python 3.13 and 3.14
# ---------------------------------------------------------------------------
test:
name: Tests (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version:
- "3.13"

steps:
- name: Harden Runner
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
with:
egress-policy: audit

- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Set up uv
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
with:
enable-cache: true
python-version: ${{ matrix.python-version }}

- name: Install dev dependencies
run: uv sync --frozen

- name: Run tests
run: uv run pytest --cov=app --cov-report=xml -v

- name: Upload coverage
if: matrix.python-version == '3.13'
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
files: ai-vision-service/face-recognition/coverage.xml
flags: ai-vision-service/face-recognition
continue-on-error: true

# ---------------------------------------------------------------------------
# Docker build verification
# ---------------------------------------------------------------------------
docker-build:
name: Docker build
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0
with:
egress-policy: audit

- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd #v4.0.0

- name: Build Docker image (no model bake in CI to save time)
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
with:
context: ai-vision-service/face-recognition
push: false
load: true
tags: lychee-ai-vision:ci
# Override the model-bake step by targeting the builder stage
# to avoid downloading 300MB of model weights in CI.
target: builder
cache-from: type=gha
cache-to: type=gha,mode=max
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ clover.xml
.NO_AUTO_COMPOSER_MIGRATE
storage/bootstrap/cache/*
storage/image-jobs/*
**/__pycache__/**
.coverage

# used by Vite
public/hot
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ class-leak:
docker-build:
docker build -t lychee-frankenphp .

docker-build-legacy:
docker build -t lychee-frankenphp -f Dockerfile-legacy .

docker-build-no-cache:
docker build -t lychee-frankenphp . --no-cache

Expand Down
2 changes: 2 additions & 0 deletions ai-vision-service/face-recognition/.insightface/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!.gitignore
59 changes: 59 additions & 0 deletions ai-vision-service/face-recognition/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Multi-stage build: keep the runtime image lean.

# ---------------------------------------------------------------------------
# Stage 1 – builder: install dependencies and bake the model weights.
# ---------------------------------------------------------------------------
FROM python:3.13-slim@sha256:739e7213785e88c0f702dcdc12c0973afcbd606dbf021a589cab77d6b00b579d AS builder

# Install uv from the official image.
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv

# Runtime libraries required by opencv-python.
RUN apt-get update && apt-get install -y --no-install-recommends \
libgl1 \
libglib2.0-0 \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Install dependencies only (no source code) so layer cache is reused when
# only application code changes.
COPY pyproject.toml uv.lock README.md ./
RUN uv sync --frozen --no-dev

# Bake ArcFace + RetinaFace model weights into the image at build time.
# The resulting image starts instantly and works in airgapped environments.
# Model updates require an image rebuild.
RUN DEEPFACE_HOME=/root/.deepface uv run python -c \
"from deepface import DeepFace; \
import numpy as np; \
DeepFace.represent( \
img_path=np.zeros((1, 1, 3), dtype='uint8'), \
model_name='ArcFace', \
detector_backend='retinaface', \
enforce_detection=False, \
); \
print('ArcFace + RetinaFace models downloaded.')"

# ---------------------------------------------------------------------------
# Stage 2 – runtime: copy only what's needed to run.
# ---------------------------------------------------------------------------
FROM python:3.13-slim@sha256:739e7213785e88c0f702dcdc12c0973afcbd606dbf021a589cab77d6b00b579d AS runtime

WORKDIR /app

# Copy the pre-built virtualenv and baked model weights from the builder stage.
COPY --from=builder /app/.venv /app/.venv
COPY --from=builder /root/.deepface /root/.deepface

# Copy application source.
COPY app/ ./app/

ENV PATH="/app/.venv/bin:$PATH"
ENV DEEPFACE_HOME=/root/.deepface

EXPOSE 8000

# Use a shell-form CMD so that the ${VISION_FACE_WORKERS:-1} variable is
# expanded at container startup, not at image build time.
CMD ["sh", "-c", "uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers ${VISION_FACE_WORKERS:-1}"]
Loading
Loading