- Created `quick-replies.blade.php` for managing quick replies. - Added `settings.blade.php` for admin settings management. - Implemented `ticket-show.blade.php` to display ticket details. - Introduced `timeline-card.blade.php` component for displaying timeline information. Enhance quick reply management functionality - Developed `quick-reply-manager.blade.php` for creating and editing quick replies. - Integrated Livewire for dynamic interaction and validation. Implement settings page for AI configuration - Created `settings-page.blade.php` for managing AI settings, including prompts and provider instances. - Added functionality for managing models and embeddings. Add ticket show functionality with real-time updates - Implemented ticket details view with processing status and tool call logs. - Added support for displaying article suggestions and error messages. Create unit tests for AI classifier and domain info tool - Added `AIClassifierServiceTest.php` to validate AI classifier functionality. - Implemented `DomainInfoToolTest.php` for domain parameter validation. - Created `OxxaClientTest.php` to test API interactions and password hashing.
47 lines
1.7 KiB
PHP
47 lines
1.7 KiB
PHP
<?php
|
|
|
|
namespace App\Repositories;
|
|
|
|
use App\DTOs\ArticleCandidateDTO;
|
|
use App\Models\Article;
|
|
use App\Models\ArticleChunk;
|
|
use App\Repositories\Contracts\ArticleRepositoryInterface;
|
|
|
|
class ArticleRepository implements ArticleRepositoryInterface
|
|
{
|
|
public function findSimilarByEmbedding(array $embedding, int $limit = 5, array $embeddingContext = []): array
|
|
{
|
|
$vector = '['.implode(',', array_map(static fn ($value) => (float) $value, $embedding)).']';
|
|
|
|
$chunkDistances = ArticleChunk::query()
|
|
->selectRaw('article_id, MIN(embedding <=> ?::vector) as distance', [$vector])
|
|
->whereNotNull('embedding')
|
|
->when($embeddingContext !== [], function ($query) use ($embeddingContext) {
|
|
$query
|
|
->where('embedding_provider_instance_id', $embeddingContext['provider_instance_id'] ?? null)
|
|
->where('embedding_model', $embeddingContext['embedding_model'] ?? null);
|
|
})
|
|
->groupBy('article_id')
|
|
->orderByRaw('MIN(embedding <=> ?::vector)', [$vector])
|
|
->limit($limit)
|
|
->get();
|
|
|
|
if ($chunkDistances->isEmpty()) {
|
|
return [];
|
|
}
|
|
|
|
$distanceByArticleId = $chunkDistances->pluck('distance', 'article_id');
|
|
$articleIds = $chunkDistances->pluck('article_id')->all();
|
|
|
|
$articles = Article::query()
|
|
->whereIn('id', $articleIds)
|
|
->get()
|
|
->sortBy(fn (Article $a) => (float) ($distanceByArticleId[$a->id] ?? 1))
|
|
->values();
|
|
|
|
return $articles
|
|
->map(fn (Article $article) => ArticleCandidateDTO::fromArticle($article, (float) ($distanceByArticleId[$article->id] ?? 1)))
|
|
->all();
|
|
}
|
|
}
|