Skip to content

PS-1229 Similarity - #868

Open
4rthem wants to merge 16 commits into
masterfrom
similarity
Open

4rthem wants to merge 16 commits into
masterfrom
similarity

Conversation

@4rthem

@4rthem 4rthem commented Aug 3, 2026

Copy link
Copy Markdown
Member

No description provided.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a “Similarity” feature across the stack: a self-hosted CLIP embedder service generates vectors for assets, the Databox API stores/indexes them and serves a “similar assets” endpoint, and the Databox UI surfaces similar results in the asset view and via an action dialog.

Changes:

  • Add a Python/FastAPI similarity-embedder service (Dockerized) to compute CLIP embeddings.
  • Add backend support for storing embeddings, indexing them into Elasticsearch as a dense_vector, and serving GET /assets/{id}/similar using kNN + ACL pre-filtering.
  • Add frontend UI (panel + dialog + action) to fetch and display similar assets and their scores.

Reviewed changes

Copilot reviewed 36 out of 37 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
similarity/embedder/requirements.txt Pins Python dependencies for the embedder service.
similarity/embedder/main.py Implements /embed, /embed-text, and /healthz endpoints for embedding generation.
similarity/embedder/Dockerfile Builds the embedder image and pre-downloads model weights at build time.
docker-compose.yml Adds the similarity-embedder service/profile and related env; adjusts Elasticsearch volume/heap; removes ElasticHQ.
docker-compose.dev.yml Exposes the embedder port in dev compose override.
doc/tech/Databox/integration/01_integrations.md Documents the new similarity integration and adds it to the integration list.
databox/client/src/components/Media/Asset/View/AssetView.tsx Adds the Similar Assets panel into the asset view layout.
databox/client/src/components/Media/Asset/SimilarAssets.tsx New accordion panel that loads and displays similar assets.
databox/client/src/components/Media/Asset/Actions/SimilarAssetsDialog.tsx New modal dialog to browse more similar assets.
databox/client/src/components/Media/Asset/Actions/SaveFileAsNewAssetDialog.tsx Refactors destination handling using tree node data + IRI helper.
databox/client/src/components/Media/Asset/Actions/AssetViewActions.tsx Adds “Find similar” action opening the similar-assets dialog.
databox/client/src/api/asset.ts Adds getSimilarAssets() API helper and result typing.
databox/api/tests/ElasticSearch/KnnQueryTest.php Adds unit tests for the new ES kNN query serialization/filter embedding.
databox/api/src/Service/Vector/EmbedderClient.php Adds an HTTP client wrapper to call the similarity embedder service.
databox/api/src/Service/Vector/AssetEmbeddingManager.php Adds embedding generation + persistence logic for assets.
databox/api/src/Integration/Core/Similarity/SimilarityIntegration.php Adds a workflow integration to compute embeddings on ingest and depend on rendition generation.
databox/api/src/Integration/Core/Similarity/SimilarityEmbedAction.php Workflow action that triggers embedding generation.
databox/api/src/Entity/Core/AssetEmbedding.php New entity/table for persisted embeddings and metadata.
databox/api/src/Entity/Core/Asset.php Exposes /assets/{id}/similar collection operation via API Platform.
databox/api/src/Elasticsearch/SimilarAssetSearch.php Implements similar-asset search with ES kNN + ACL pre-filtering.
databox/api/src/Elasticsearch/Query/Knn.php Adds Elastica query wrapper for ES kNN query (ES >= 8.12).
databox/api/src/Elasticsearch/Listener/AssetPostTransformListener.php Injects embedding vectors into indexed asset documents.
databox/api/src/Elasticsearch/AppIndexableDependencyResolver.php Ensures Asset reindexing happens when an embedding changes.
databox/api/src/Controller/Admin/DashboardController.php Adds admin menu entry for the Asset Embedding CRUD.
databox/api/src/Controller/Admin/AssetEmbeddingCrudController.php Adds read-only admin UI for viewing embeddings.
databox/api/src/Consumer/Handler/Similarity/SimilarityEmbedHandler.php Adds async handler to compute embeddings via messenger.
databox/api/src/Consumer/Handler/Similarity/SimilarityEmbed.php Adds messenger message for embedding computation jobs.
databox/api/src/Command/SimilarityIndexCommand.php Adds CLI command to backfill embeddings (sync or queued).
databox/api/src/Api/Provider/SimilarAssetCollectionProvider.php API provider for the “similar assets” collection, including scores meta.
databox/api/migrations/Version20260802120000.php Migration creating asset_embedding table and constraints.
databox/api/fixtures/Newspaper.yaml Enables the similarity integration in fixtures for the Newspaper workspace.
databox/api/config/packages/framework.yaml Configures the named HTTP client for the embedder base URI.
databox/api/config/packages/fos_elastica.yaml Adds embedding as an indexed dense_vector (cosine similarity).
databox/api/.env Adds default SIMILARITY_EMBEDDER_URL.
dashboard/client/src/global.d.ts Removes ELASTICHQ_URL from typed globals.
dashboard/client/src/App.tsx Removes ElasticHQ link from the dashboard UI.
.env Enables the similarity compose profile and updates Elasticsearch image/version + embedder dev port.
Suppressed comments (1)

doc/tech/Databox/integration/01_integrations.md:161

  • The integration list entry uses similarity, but the actual integration key added by this PR is core.similarity. The table should reflect the real key so it can be copy/pasted for configuration.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +28 to +41
$rendition = $this->renditionManager->getAssetRenditionByName($asset->getId(), $renditionName);
$file = $rendition?->getFile();
if (null === $file || !FileUtil::isImageType($file->getType())) {
return false;
}

$path = $this->fileFetcher->getFile($file);
$result = $this->embedderClient->embedImageFile($path);

$existingEmbedding = $this->em->getRepository(AssetEmbedding::class)
->findOneBy(['asset' => $asset->getId()]);
if (null !== $existingEmbedding && !$force) {
return false;
}
Comment on lines +45 to +52
@app.post("/embed")
async def embed(file: UploadFile) -> dict:
data = await file.read()
try:
image = Image.open(io.BytesIO(data)).convert("RGB")
except Exception:
raise HTTPException(status_code=422, detail="Unsupported or corrupted image")

Comment thread similarity/embedder/Dockerfile Outdated
Comment thread doc/tech/Databox/integration/01_integrations.md Outdated
Comment thread databox/client/src/components/Media/Asset/SimilarAssets.tsx
@4rthem 4rthem changed the title Similarity PS-1229 Similarity Aug 3, 2026
4rthem and others added 15 commits September 3, 2026 18:02
The service now lives in alchemy-fr/phrasea-similarity-embedder with its
own CI publishing to the private AWS ECR registry. Phrasea pulls the
published image (SIMILARITY_EMBEDDER_IMAGE, defaults to
122649456891.dkr.ecr.eu-west-3.amazonaws.com/ps-similarity-embedder:latest)
instead of building it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The report API now lives in alchemy-fr/phrasea-report with its own CI
publishing to ECR Public. Phrasea pulls the published image
(REPORT_API_IMAGE, defaults to
public.ecr.aws/b2s9z7l1/ps-report-api:latest) instead of building it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The custom Keycloak image (SPI mappers + phrasea theme) now lives in
alchemy-fr/phrasea-keycloak with its own CI publishing to ECR Public.
Phrasea pulls the published image (KEYCLOAK_IMAGE, defaults to
public.ecr.aws/b2s9z7l1/ps-keycloak:latest) instead of building it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants