Skip to content

Commit

Permalink
Merge pull request #730 from biigle/largo-sim-sort
Browse files Browse the repository at this point in the history
Largo sort
  • Loading branch information
mzur authored Jan 25, 2024
2 parents f87213a + 3c310cc commit ea69fc3
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 123 deletions.
10 changes: 6 additions & 4 deletions .docker/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# This file is just used to get security alerts from GitHub. Make sure the versions match
# in worker.dockerfile.
numpy==1.22.*
numpy==1.24.*
opencv-contrib-python-headless==4.6.0
scipy==1.10.0
scikit-learn
matplotlib==3.5.2
scipy==1.10.*
scikit-learn==1.2.*
matplotlib==3.6.*
PyExcelerate==0.6.7
Pillow==10.2.0
Shapely==1.8.1
torch==2.1.*
torchvision==0.16.*
148 changes: 66 additions & 82 deletions .docker/worker.dockerfile
Original file line number Diff line number Diff line change
@@ -1,32 +1,36 @@
# PHP 8.1.13
#FROM php:8.1-alpine
FROM php@sha256:f9e31f22bdd89c1334a03db5c8800a5f3b1e1fe042d470adccf58a29672c6202
# PHP 8.1.27
# FROM php:8.1
FROM php@sha256:9b5dfb7deef3e48d67b2599e4d3967bb3ece19fd5ba09cb8e7ee10f5facf36e0
MAINTAINER Martin Zurowietz <martin@cebitec.uni-bielefeld.de>
LABEL org.opencontainers.image.source https://github.com/biigle/core

ARG OPENCV_VERSION=4.6.0-r3
RUN apk add --no-cache \
eigen \
RUN LC_ALL=C.UTF-8 apt-get update \
&& apt-get install -y --no-install-recommends \
ffmpeg \
lapack \
openblas \
py3-numpy \
python3 \
py3-opencv="$OPENCV_VERSION"
python3-numpy \
python3-opencv \
python3-scipy \
python3-sklearn \
python3-matplotlib \
python3-shapely \
&& apt-get -y autoremove \
&& apt-get clean \
&& rm -r /var/lib/apt/lists/*

RUN ln -s "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
ADD ".docker/all-php.ini" "$PHP_INI_DIR/conf.d/all.ini"

RUN apk add --no-cache \
libxml2 \
libzip \
openssl \
postgresql \
&& apk add --no-cache --virtual .build-deps \
RUN LC_ALL=C.UTF-8 apt-get update \
&& apt-get install -y --no-install-recommends \
libxml2-dev \
libzip-dev \
postgresql-dev \
&& docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \
libpq-dev \
&& apt-get install -y --no-install-recommends \
libxml2 \
libzip4 \
postgresql-client \
&& docker-php-ext-configure pgsql -with-pgsql=/usr/bin/pgsql \
&& docker-php-ext-install -j$(nproc) \
exif \
pcntl \
Expand All @@ -35,15 +39,29 @@ RUN apk add --no-cache \
pgsql \
soap \
zip \
&& apk del --purge .build-deps
&& apt-get purge -y \
libxml2-dev \
libzip-dev \
libpq-dev \
&& apt-get -y autoremove \
&& apt-get clean \
&& rm -r /var/lib/apt/lists/*

# Configure proxy if there is any. See: https://stackoverflow.com/a/2266500/1796523
RUN [ -z "$HTTP_PROXY" ] || pear config-set http_proxy $HTTP_PROXY
RUN apk add --no-cache yaml \
&& apk add --no-cache --virtual .build-deps g++ make autoconf yaml-dev \

RUN LC_ALL=C.UTF-8 apt-get update \
&& apt-get install -y --no-install-recommends \
libyaml-dev \
&& apt-get install -y --no-install-recommends \
libyaml-0-2 \
&& pecl install yaml \
&& docker-php-ext-enable yaml \
&& apk del --purge .build-deps
&& printf "\n" | docker-php-ext-enable yaml \
&& apt-get purge -y \
libyaml-dev \
&& apt-get -y autoremove \
&& apt-get clean \
&& rm -r /var/lib/apt/lists/*

ARG PHPREDIS_VERSION=5.3.7
RUN curl -L -o /tmp/redis.tar.gz https://github.com/phpredis/phpredis/archive/${PHPREDIS_VERSION}.tar.gz \
Expand All @@ -53,72 +71,38 @@ RUN curl -L -o /tmp/redis.tar.gz https://github.com/phpredis/phpredis/archive/${
&& mv phpredis-${PHPREDIS_VERSION} /usr/src/php/ext/redis \
&& docker-php-ext-install -j$(nproc) redis

ENV PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:${PKG_CONFIG_PATH}"
# Install vips from source because the apk package does not have dzsave support! Install
# libvips and the vips PHP extension in one go so the *-dev dependencies are reused.
ARG LIBVIPS_VERSION=8.12.2
ARG PHP_VIPS_EXT_VERSION=1.0.13
RUN apk add --no-cache --virtual .build-deps \
autoconf \
automake \
build-base \
expat-dev \
glib-dev \
libgsf-dev \
libjpeg-turbo-dev \
libpng-dev \
tiff-dev \
librsvg-dev \
&& apk add --no-cache \
expat \
glib \
libgsf \
libjpeg-turbo \
libpng \
tiff \
librsvg \
&& cd /tmp \
&& curl -L https://github.com/libvips/libvips/releases/download/v${LIBVIPS_VERSION}/vips-${LIBVIPS_VERSION}.tar.gz -o vips-${LIBVIPS_VERSION}.tar.gz \
&& tar -xzf vips-${LIBVIPS_VERSION}.tar.gz \
&& cd vips-${LIBVIPS_VERSION} \
&& ./configure \
--without-python \
--enable-debug=no \
--disable-dependency-tracking \
--disable-static \
&& make -j $(nproc) \
&& make -s install-strip \
&& cd /tmp \
&& curl -L https://github.com/libvips/php-vips-ext/raw/master/vips-${PHP_VIPS_EXT_VERSION}.tgz -o vips-${PHP_VIPS_EXT_VERSION}.tgz \
&& echo '' | pecl install vips-${PHP_VIPS_EXT_VERSION}.tgz \
# ENV PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:${PKG_CONFIG_PATH}"

RUN LC_ALL=C.UTF-8 apt-get update \
&& apt-get install -y --no-install-recommends \
libvips-dev \
&& apt-get install -y --no-install-recommends \
libvips42 \
&& pecl install vips \
&& docker-php-ext-enable vips \
&& rm -r /tmp/* \
&& apk del --purge .build-deps \
&& rm -rf /var/cache/apk/*
&& apt-get purge -y \
libvips-dev \
&& apt-get -y autoremove \
&& apt-get clean \
&& rm -r /var/lib/apt/lists/*

# Unset proxy configuration again.
RUN [ -z "$HTTP_PROXY" ] || pear config-set http_proxy ""

# Other Python dependencies are added with the OpenCV build above.
RUN apk add --no-cache py3-scipy py3-scikit-learn py3-matplotlib py3-shapely

# Set this library path so the Python modules are linked correctly.
# See: https://github.com/python-pillow/Pillow/issues/1763#issuecomment-204252397
ENV LIBRARY_PATH=/lib:/usr/lib
# Install Python dependencies. Note that these also depend on some image processing libs
# that were installed along with vips.
RUN apk add --no-cache --virtual .build-deps \
python3-dev \
py3-pip \
py3-wheel \
build-base \
libjpeg-turbo-dev \
libpng-dev \
&& pip3 install --no-cache-dir \
RUN LC_ALL=C.UTF-8 apt-get update \
&& apt-get install -y --no-install-recommends \
python3-pip \
&& pip3 install --no-cache-dir --break-system-packages \
PyExcelerate==0.6.7 \
Pillow==10.2.0 \
&& apk del --purge .build-deps \
&& rm -rf /var/cache/apk/*
&& pip3 install --no-cache-dir --break-system-packages --index-url https://download.pytorch.org/whl/cpu \
torch==2.1.* \
torchvision==0.16.* \
&& apt-get purge -y \
python3-pip \
&& apt-get -y autoremove \
&& apt-get clean \
&& rm -r /var/lib/apt/lists/*

WORKDIR /var/www

Expand Down
17 changes: 17 additions & 0 deletions app/Events/AnnotationLabelAttached.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace Biigle\Events;

use Biigle\AnnotationLabel;
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
use Illuminate\Foundation\Events\Dispatchable;

class AnnotationLabelAttached implements ShouldDispatchAfterCommit
{
use Dispatchable;

public function __construct(public AnnotationLabel $annotationLabel)
{
//
}
}
3 changes: 3 additions & 0 deletions app/Http/Controllers/Api/ImageAnnotationLabelController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Biigle\Http\Controllers\Api;

use Biigle\Events\AnnotationLabelAttached;
use Biigle\Http\Requests\StoreImageAnnotationLabel;
use Biigle\ImageAnnotation;
use Biigle\ImageAnnotationLabel;
Expand Down Expand Up @@ -184,6 +185,8 @@ public function store(StoreImageAnnotationLabel $request)
// should not be returned
unset($annotationLabel->annotation);

AnnotationLabelAttached::dispatch($annotationLabel);

return response($annotationLabel, 201);
} catch (QueryException $e) {
// Although we check for existence above, this error happened some time.
Expand Down
3 changes: 3 additions & 0 deletions app/Http/Controllers/Api/VideoAnnotationLabelController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Biigle\Http\Controllers\Api;

use Biigle\Events\AnnotationLabelAttached;
use Biigle\Http\Requests\DestroyVideoAnnotationLabel;
use Biigle\Http\Requests\StoreVideoAnnotationLabel;
use Biigle\VideoAnnotationLabel;
Expand Down Expand Up @@ -65,6 +66,8 @@ public function store(StoreVideoAnnotationLabel $request)
// should not be returned
unset($annotationLabel->annotation);

AnnotationLabelAttached::dispatch($annotationLabel);

return response($annotationLabel, 201);
} catch (QueryException $e) {
// Although we check for existence above, this error happened some time.
Expand Down
34 changes: 18 additions & 16 deletions app/Jobs/CloneImagesOrVideos.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
use Biigle\ImageAnnotation;
use Biigle\ImageAnnotationLabel;
use Biigle\ImageLabel;
use Biigle\Modules\Largo\Jobs\GenerateImageAnnotationPatch;
use Biigle\Modules\Largo\Jobs\GenerateVideoAnnotationPatch;
use Biigle\Modules\Largo\Jobs\ProcessAnnotatedImage;
use Biigle\Modules\Largo\Jobs\ProcessAnnotatedVideo;
use Biigle\Project;
use Biigle\Traits\ChecksMetadataStrings;
use Biigle\Video;
Expand Down Expand Up @@ -162,24 +162,26 @@ public function postProcessCloning($volume)
{
ProcessNewVolumeFiles::dispatch($volume);

if (class_exists(GenerateImageAnnotationPatch::class)) {
ImageAnnotation::join('images', 'images.id', '=', 'image_annotations.image_id')
->where('images.volume_id', "=", $volume->id)
->select('image_annotations.id')
->eachById(function ($annotation) {
GenerateImageAnnotationPatch::dispatch($annotation)
// Give the ProcessNewVolumeFiles job a head start so the file thumbnails are
// generated (mostly) before the annotation thumbnails.
$delay = now()->addSeconds(30);

if (class_exists(ProcessAnnotatedImage::class)) {
$volume->images()->whereHas('annotations')
->eachById(function ($image) use ($delay) {
ProcessAnnotatedImage::dispatch($image)
->delay($delay)
->onQueue(config('largo.generate_annotation_patch_queue'));
}, 1000, 'image_annotations.id', 'id');
});
}

if (class_exists(GenerateVideoAnnotationPatch::class)) {
VideoAnnotation::join('videos', 'videos.id', '=', 'video_annotations.video_id')
->where('videos.volume_id', "=", $volume->id)
->select('video_annotations.id')
->eachById(function ($annotation) {
GenerateVideoAnnotationPatch::dispatch($annotation)
if (class_exists(ProcessAnnotatedVideo::class)) {
$volume->videos()
->whereHas('annotations')->eachById(function ($video) use ($delay) {
ProcessAnnotatedVideo::dispatch($video)
->delay($delay)
->onQueue(config('largo.generate_annotation_patch_queue'));
}, 1000, 'video_annotations.id', 'id');
});
}
}

Expand Down
10 changes: 0 additions & 10 deletions requirements.txt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
namespace Biigle\Tests\Http\Controllers\Api;

use ApiTestCase;
use Biigle\Events\AnnotationLabelAttached;
use Biigle\Tests\AnnotationSessionTest;
use Biigle\Tests\ImageAnnotationLabelTest;
use Biigle\Tests\ImageAnnotationTest;
use Cache;
use Carbon\Carbon;
use Illuminate\Support\Facades\Event;
use Session;

class ImageAnnotationLabelControllerTest extends ApiTestCase
Expand Down Expand Up @@ -115,6 +117,7 @@ public function testStoreLegacy()

public function store($url)
{
Event::fake();
$id = $this->annotation->id;
$this->doTestApiRoute('POST', "{$url}/{$id}/labels");

Expand Down Expand Up @@ -150,12 +153,16 @@ public function store($url)
$response->assertStatus(201);
$this->assertEquals(1, $this->annotation->labels()->count());

Event::assertDispatched(AnnotationLabelAttached::class);

$this->beAdmin();
$response = $this->json('POST', "{$url}/{$id}/labels", [
'label_id' => $this->labelRoot()->id,
'confidence' => 0.1,
]);
$response->assertStatus(201);

Event::assertDispatched(AnnotationLabelAttached::class);
$this->assertEquals(2, $this->annotation->labels()->count());
$response->assertJsonFragment([
'id' => $this->labelRoot()->id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
namespace Biigle\Tests\Http\Controllers\Api;

use ApiTestCase;
use Biigle\Events\AnnotationLabelAttached;
use Biigle\MediaType;
use Biigle\Tests\LabelTest;
use Biigle\Tests\VideoAnnotationLabelTest;
use Biigle\Tests\VideoAnnotationTest;
use Biigle\Tests\VideoTest;
use Illuminate\Support\Facades\Event;

class VideoAnnotationLabelControllerTest extends ApiTestCase
{
Expand All @@ -20,6 +22,7 @@ public function setUp(): void

public function testStore()
{
Event::fake();
$annotation = VideoAnnotationTest::create(['video_id' => $this->video->id]);
$id = $annotation->id;

Expand Down Expand Up @@ -51,6 +54,7 @@ public function testStore()
$this->assertNotNull($label);
$this->assertEquals($this->labelRoot()->id, $label->label_id);
$this->assertEquals($this->editor()->id, $label->user_id);
Event::assertDispatched(AnnotationLabelAttached::class);

$this
->postJson("api/v1/video-annotations/{$id}/labels", [
Expand Down
Loading

0 comments on commit ea69fc3

Please sign in to comment.