Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Bundle\Core\DependencyInjection\Configuration\Parser;

use Ibexa\Bundle\Core\DependencyInjection\Configuration\AbstractParser;
use Ibexa\Bundle\Core\DependencyInjection\Configuration\SiteAccessAware\ContextualizerInterface;
use Symfony\Component\Config\Definition\Builder\NodeBuilder;

/**
* Configuration parser for embedding models.
*
* Example configuration:
* ```yaml
* ibexa:
* system:
* default: # configuration per siteaccess or siteaccess group
* embedding_models:
* name: "text-embedding-3-small"
* dimensions: 1536
* field_suffix: "3small"
* embedding_provider: "ibexa_openai"
* default_embedding_model: text-embedding-ada-002
* ```
*/
final class Embeddings extends AbstractParser
{
public function addSemanticConfig(NodeBuilder $nodeBuilder): void
{
$nodeBuilder
->arrayNode('embedding_models')
->normalizeKeys(false)
->info('Defines available embedding models')
->arrayPrototype()
->children()
->scalarNode('name')->isRequired()->end()
->integerNode('dimensions')->isRequired()->end()
->scalarNode('field_suffix')->isRequired()->end()
->scalarNode('embedding_provider')->isRequired()->end()
->end()
->end()
->end()
->scalarNode('default_embedding_model')
->info('Default embedding model identifier')
->defaultValue('text-embedding-ada-002')
->end();
}

/**
* @param array<mixed> $config
*/
public function preMap(array $config, ContextualizerInterface $contextualizer): void
{
$contextualizer->mapConfigArray('embedding_models', $config);
$contextualizer->mapSetting('default_embedding_model', $config);
}

/**
* @param array<mixed> $scopeSettings
*/
public function mapConfig(array &$scopeSettings, $currentScope, ContextualizerInterface $contextualizer): void
{
// Nothing to do here.
}
}
1 change: 1 addition & 0 deletions src/bundle/Core/IbexaCoreBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ public function getContainerExtension()
new ConfigParser\UrlChecker(),
new ConfigParser\TwigVariablesParser(),
new ConfigParser\UserContentTypeIdentifier(),
new ConfigParser\Embeddings(),
],
[
new RepositoryConfigParser\Storage(),
Expand Down
3 changes: 3 additions & 0 deletions src/bundle/Core/Resources/config/default_settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,6 @@ parameters:
writeFlags: ~
linkHandling: ~
permissions: [ ]

ibexa.site_access.config.default.embedding_models: []
ibexa.site_access.config.default.default_embedding_model: 'text-embedding-ada-002'
24 changes: 24 additions & 0 deletions src/bundle/Core/Resources/config/embeddings.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
services:
_defaults:
autowire: true
autoconfigure: true
public: false

Ibexa\Contracts\Core\Search\Embedding\EmbeddingProviderRegistryInterface:
alias: Ibexa\Core\Search\Embedding\EmbeddingProviderRegistry

Ibexa\Core\Search\Embedding\EmbeddingProviderRegistry:
arguments:
$embeddingProviders: !tagged_iterator { tag: 'ibexa.embedding_provider', index_by: 'provider_name' }

Ibexa\Contracts\Core\Search\Embedding\EmbeddingProviderResolverInterface:
alias: Ibexa\Core\Search\Embedding\EmbeddingProviderResolver

Ibexa\Core\Search\Embedding\EmbeddingProviderResolver: ~

Ibexa\Contracts\Core\Search\Embedding\EmbeddingConfigurationInterface:
alias: Ibexa\Core\Search\Embedding\EmbeddingConfiguration

Ibexa\Core\Search\Embedding\EmbeddingConfiguration: ~

Ibexa\Contracts\Core\Search\FieldType\EmbeddingFieldFactory: ~
1 change: 1 addition & 0 deletions src/bundle/Core/Resources/config/services.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
imports:
- { resource: commands.yml }
- { resource: embeddings.yaml }

parameters:
ibexa.site_access.default.name: default
Expand Down
113 changes: 113 additions & 0 deletions src/contracts/Repository/Values/Content/EmbeddingQuery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Contracts\Core\Repository\Values\Content;

use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion;
use Ibexa\Contracts\Core\Repository\Values\Content\Query\Embedding;
use InvalidArgumentException;

final class EmbeddingQuery extends Query
{
private ?Embedding $embedding = null;

public function getEmbedding(): ?Embedding
{
return $this->embedding;
}

public function setEmbedding(?Embedding $embedding = null): void
{
$this->embedding = $embedding;
}

public function getFilter(): Criterion
{
return $this->filter;
}

public function setFilter(Criterion $filter): void
{
$this->filter = $filter;
}

/**
* @return \Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation[]
*/
public function getAggregations(): array
{
return $this->aggregations;
}

/**
* @param \Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation[] $aggregations
*/
public function setAggregations(array $aggregations): void
{
$this->aggregations = $aggregations;
}

public function getOffset(): int
{
return $this->offset;
}

public function setOffset(int $offset): void
{
$this->offset = $offset;
}

public function getLimit(): int
{
return $this->limit;
}

public function setLimit(int $limit): void
{
$this->limit = $limit;
}

public function setPerformCount(bool $performCount): void
{
$this->performCount = $performCount;
}

public function getPerformCount(): bool
{
return $this->performCount;
}

public function isValid(): bool
{
$invalid = [];

if ($this->query !== null) {
$invalid[] = 'query';
}
if (!empty($this->sortClauses)) {
$invalid[] = 'sortClauses';
}
if (!empty($this->facetBuilders)) {
$invalid[] = 'facetBuilders';
}
if ($this->spellcheck !== null) {
$invalid[] = 'spellcheck';
}

if (count($invalid) > 0) {

Check warning on line 102 in src/contracts/Repository/Values/Content/EmbeddingQuery.php

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use empty() to check whether the array is empty or not.

See more on https://sonarcloud.io/project/issues?id=ibexa_core&issues=AZnheVRx_e-CFroOAlzM&open=AZnheVRx_e-CFroOAlzM&pullRequest=536
throw new InvalidArgumentException(
sprintf(
'EmbeddingQuery did not set [%s].',
implode(', ', $invalid)
)
);
}

return true;
}
}
111 changes: 111 additions & 0 deletions src/contracts/Repository/Values/Content/EmbeddingQueryBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Contracts\Core\Repository\Values\Content;

use Ibexa\Contracts\Core\Repository\Values\Content\Query\Criterion;
use Ibexa\Contracts\Core\Repository\Values\Content\Query\Embedding;

final class EmbeddingQueryBuilder
{
private ?Embedding $embedding = null;

private ?int $limit = null;

private ?int $offset = null;

private ?Criterion $filter = null;

/** @var array<\Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation> */
private array $aggregations = [];

private bool $performCount = false;

private function __construct()
{
}

Check failure on line 31 in src/contracts/Repository/Values/Content/EmbeddingQueryBuilder.php

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add a nested comment explaining why this method is empty, throw an Exception or complete the implementation.

See more on https://sonarcloud.io/project/issues?id=ibexa_core&issues=AZnoBWGEQPvkbLfp0yfd&open=AZnoBWGEQPvkbLfp0yfd&pullRequest=536

public static function create(): self
{
return new self();
}

public function withEmbedding(Embedding $embed): self
{
$this->embedding = $embed;

return $this;
}

public function setLimit(int $limit): self
{
$this->limit = $limit;

return $this;
}

public function setOffset(int $offset): self
{
$this->offset = $offset;

return $this;
}

public function setFilter(Criterion $filter): self
{
$this->filter = $filter;

return $this;
}

/**
* @param array<\Ibexa\Contracts\Core\Repository\Values\Content\Query\Aggregation> $aggregations
*/
public function setAggregations(array $aggregations): self
{
$this->aggregations = $aggregations;

return $this;
}

public function setPerformCount(bool $performCount): self
{
$this->performCount = $performCount;

return $this;
}

public function build(): EmbeddingQuery
{
$query = new EmbeddingQuery();

if ($this->embedding !== null) {
$query->setEmbedding($this->embedding);
}

if ($this->limit !== null) {
$query->setLimit($this->limit);
}

if ($this->offset !== null) {
$query->setOffset($this->offset);
}

if ($this->filter !== null) {
$query->setFilter($this->filter);
}

if (!empty($this->aggregations)) {
$query->setAggregations($this->aggregations);
}

$query->setPerformCount($this->performCount);

return $query;
}
}
7 changes: 6 additions & 1 deletion src/contracts/Repository/Values/Content/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
/**
* This class is used to perform a Content query.
*/
class Query extends ValueObject
class Query extends ValueObject implements QueryValidatorInterface
{
public const SORT_ASC = 'ascending';
public const SORT_DESC = 'descending';
Expand Down Expand Up @@ -102,6 +102,11 @@ class Query extends ValueObject
* @var bool
*/
public $performCount = true;

public function isValid(): bool
{
return true;
}
}

class_alias(Query::class, 'eZ\Publish\API\Repository\Values\Content\Query');
33 changes: 33 additions & 0 deletions src/contracts/Repository/Values/Content/Query/Embedding.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Contracts\Core\Repository\Values\Content\Query;

use Ibexa\Contracts\Core\Repository\Values\ValueObject;

abstract class Embedding extends ValueObject
{
/** @var float[] */
protected array $value;

/**
* @param float[] $value
*/
public function __construct(array $value)
{
$this->value = $value;
}

/**
* @return float[]
*/
public function getValue(): array
{
return $this->value;
}
}
Loading
Loading