Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.yml
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.yml }

parameters:
ibexa.site_access.default.name: default
Expand Down
116 changes: 116 additions & 0 deletions src/contracts/Repository/Values/Content/EmbeddingQuery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?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;

/**
* This class is used to perform an embedding query.
*/
class EmbeddingQuery extends Query
{
private ?Embedding $embedding = null;

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

public function setEmbedding(?Embedding $embedding): 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) {
throw new InvalidArgumentException(
sprintf(
'EmbeddingQuery may not set [%s].',
implode(', ', $invalid)
)
);
}

return true;
}
}
77 changes: 77 additions & 0 deletions src/contracts/Repository/Values/Content/EmbeddingQueryBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?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 EmbeddingQuery $query;

private function __construct()
{
$this->query = new EmbeddingQuery();
}

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

public function withEmbedding(Embedding $embed): self
{
$this->query->setEmbedding($embed);

return $this;
}

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

return $this;
}

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

return $this;
}

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

return $this;
}

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

return $this;
}

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

return $this;
}

public function build(): EmbeddingQuery
{
return $this->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');
31 changes: 31 additions & 0 deletions src/contracts/Repository/Values/Content/Query/Embedding.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
namespace Ibexa\Contracts\Core\Repository\Values\Content;

interface QueryValidatorInterface
{
public function isValid(): bool;
}
Loading
Loading