34 lines
1.1 KiB
PHP
34 lines
1.1 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Ai;
|
|
|
|
final class HybridFusion
|
|
{
|
|
/**
|
|
* Fuse already authorised lexical/vector rankings. Scores are ranking signals, not probabilities.
|
|
*
|
|
* @param list<string> $lexical
|
|
* @param list<string> $vector
|
|
* @param list<string> $authorised
|
|
* @return list<array{id:string,score:float}>
|
|
*/
|
|
public function rank(array $lexical, array $vector, array $authorised, int $limit = 10): array
|
|
{
|
|
$scores = [];
|
|
foreach ([$lexical, $vector] as $ranking) {
|
|
foreach (array_values(array_unique($ranking)) as $position => $id) {
|
|
if (in_array($id, $authorised, true)) {
|
|
$scores[$id] = ($scores[$id] ?? 0.0) + 1.0 / (60 + $position + 1);
|
|
}
|
|
}
|
|
}
|
|
$items = [];
|
|
foreach ($scores as $id => $score) {
|
|
$items[] = ['id' => $id, 'score' => $score];
|
|
}
|
|
usort($items, fn ($a, $b) => ($b['score'] <=> $a['score']) ?: strcmp($a['id'], $b['id']));
|
|
|
|
return array_slice($items, 0, max(0, min(100, $limit)));
|
|
}
|
|
}
|