init project
This commit is contained in:
119
app/Services/EmbeddingVector.php
Normal file
119
app/Services/EmbeddingVector.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class EmbeddingVector
|
||||
{
|
||||
/**
|
||||
* Parse one phrase per line and return unique normalized display values.
|
||||
*
|
||||
* @return list<string>
|
||||
*/
|
||||
public static function phrasesFromText(string $text, int $limit = 50): array
|
||||
{
|
||||
$lines = preg_split('/\R/u', $text) ?: [];
|
||||
$phrases = [];
|
||||
$seen = [];
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$phrase = self::cleanPhrase($line);
|
||||
|
||||
if ($phrase === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hash = self::hashPhrase($phrase);
|
||||
|
||||
if (isset($seen[$hash])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$seen[$hash] = true;
|
||||
$phrases[] = $phrase;
|
||||
|
||||
if (count($phrases) >= $limit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $phrases;
|
||||
}
|
||||
|
||||
public static function cleanPhrase(string $phrase): string
|
||||
{
|
||||
return Str::of($phrase)->squish()->value();
|
||||
}
|
||||
|
||||
public static function hashPhrase(string $phrase): string
|
||||
{
|
||||
return hash('sha256', Str::of($phrase)->squish()->lower()->value());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, int|float> $vector
|
||||
* @return array<int, float>
|
||||
*/
|
||||
public static function normalize(array $vector): array
|
||||
{
|
||||
$magnitude = sqrt(array_sum(array_map(
|
||||
fn (int|float $value): float => (float) $value * (float) $value,
|
||||
$vector
|
||||
)));
|
||||
|
||||
if ($magnitude == 0.0) {
|
||||
return array_map(fn (): float => 0.0, $vector);
|
||||
}
|
||||
|
||||
return array_map(fn (int|float $value): float => (float) $value / $magnitude, $vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, int|float> $first
|
||||
* @param array<int, int|float> $second
|
||||
*/
|
||||
public static function cosineSimilarity(array $first, array $second): float
|
||||
{
|
||||
if (count($first) !== count($second)) {
|
||||
throw new InvalidArgumentException('Vectors must have the same number of dimensions.');
|
||||
}
|
||||
|
||||
$dotProduct = 0.0;
|
||||
$firstMagnitude = 0.0;
|
||||
$secondMagnitude = 0.0;
|
||||
|
||||
foreach ($first as $index => $firstValue) {
|
||||
$secondValue = $second[$index];
|
||||
|
||||
$dotProduct += (float) $firstValue * (float) $secondValue;
|
||||
$firstMagnitude += (float) $firstValue * (float) $firstValue;
|
||||
$secondMagnitude += (float) $secondValue * (float) $secondValue;
|
||||
}
|
||||
|
||||
if ($firstMagnitude == 0.0 || $secondMagnitude == 0.0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return max(-1.0, min(1.0, $dotProduct / (sqrt($firstMagnitude) * sqrt($secondMagnitude))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, int|float> $vector
|
||||
* @return array<int, float>
|
||||
*/
|
||||
public static function rounded(array $vector, int $precision = 6): array
|
||||
{
|
||||
return array_map(fn (int|float $value): float => round((float) $value, $precision), $vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, int|float> $vector
|
||||
* @return array<int, float>
|
||||
*/
|
||||
public static function preview(array $vector, int $limit = 12): array
|
||||
{
|
||||
return array_slice(self::rounded($vector), 0, $limit);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user