Files
portal/app/tests/Unit/Autopodbor/Similarity/EmbeddingRelevanceTest.php
T

75 lines
3.2 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
use App\Services\Autopodbor\Agent\Similarity\Embedder;
use App\Services\Autopodbor\Agent\Similarity\EmbeddingRelevance;
/** Детерминированный эмбеддер для офлайн-теста: текст → заранее заданный вектор (по подстроке). */
function fakeEmbedder(array $byNeedle): Embedder
{
return new class($byNeedle) implements Embedder
{
/** @param array<string,array<int,float>> $map */
public function __construct(private array $map) {}
public function embed(array $texts): array
{
return array_map(function (string $t): array {
foreach ($this->map as $needle => $vec) {
if (str_contains($t, $needle)) {
return $vec;
}
}
return [0.0, 0.0, 0.0]; // нет совпадения — нулевая похожесть
}, $texts);
}
};
}
it('ранжирует кандидатов по близости к профилю клиента (косинус)', function () {
// профиль клиента — «автоломбард / займ под залог авто»
$embedder = fakeEmbedder([
'залог авто' => [1.0, 0.0, 0.0], // клиентский профиль и близкие к нему
'автозайм' => [0.9, 0.1, 0.0],
'пластиковые окна' => [0.0, 1.0, 0.0], // совсем другое
]);
$rel = new EmbeddingRelevance($embedder);
$ranked = $rel->rank(
clientExamples: ['Автоломбард Клиента залог авто'],
candidates: [
['name' => 'Окна Комфорт', 'description' => 'пластиковые окна и балконы'],
['name' => 'АвтоДеньги', 'description' => 'автозайм под ПТС'],
['name' => 'ЗалогЦентр', 'description' => 'займ под залог авто'],
],
);
// ближайший — «займ под залог авто» (точное совпадение профиля), затем «автозайм», окна — последними
expect(array_column($ranked, 'name'))->toBe(['ЗалогЦентр', 'АвтоДеньги', 'Окна Комфорт']);
expect($ranked[0]['relevance_pct'])->toBe(100);
expect($ranked[2]['relevance_pct'])->toBe(0);
foreach ($ranked as $c) {
expect($c['relevance_pct'])->toBeGreaterThanOrEqual(0)->toBeLessThanOrEqual(100);
}
});
it('без профиля клиента похожесть 0, порядок сохраняется', function () {
$rel = new EmbeddingRelevance(fakeEmbedder([]));
$ranked = $rel->rank(clientExamples: [], candidates: [
['name' => 'А', 'description' => 'x'],
['name' => 'Б', 'description' => 'y'],
]);
expect($ranked)->toHaveCount(2);
expect($ranked[0]['relevance_pct'])->toBe(0);
expect($ranked[1]['relevance_pct'])->toBe(0);
});
it('пустой список кандидатов → пустой результат', function () {
$rel = new EmbeddingRelevance(fakeEmbedder([]));
expect($rel->rank(['что-то'], []))->toBe([]);
});