89 lines
2.4 KiB
PHP
89 lines
2.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Memory;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Pgvector\Laravel\Distance;
|
|
use Pgvector\Laravel\Vector;
|
|
|
|
class MemoryService
|
|
{
|
|
public function __construct(
|
|
protected ?string $ollamaUrl = null,
|
|
protected ?string $embedModel = null,
|
|
) {
|
|
$this->ollamaUrl ??= config('services.ollama.url');
|
|
$this->embedModel ??= config('services.ollama.embedding_model');
|
|
}
|
|
|
|
/**
|
|
* Erstellt ein Embedding via Ollama und persistiert die Memory.
|
|
*/
|
|
public function remember(string $content, array $metadata = []): Memory
|
|
{
|
|
$embedding = $this->embed($content);
|
|
|
|
return Memory::create([
|
|
'content' => $content,
|
|
'metadata' => $metadata,
|
|
'embedding' => $embedding ? new Vector($embedding) : null,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @return array<int, Memory>
|
|
*/
|
|
public function recall(string $query, int $limit = 5): array
|
|
{
|
|
$embedding = $this->embed($query);
|
|
if ($embedding === null) {
|
|
return Memory::latest()->limit($limit)->get()->all();
|
|
}
|
|
|
|
return Memory::query()
|
|
->nearestNeighbors('embedding', new Vector($embedding), Distance::Cosine)
|
|
->limit($limit)
|
|
->get()
|
|
->all();
|
|
}
|
|
|
|
/**
|
|
* Erzeugt ein Embedding über die Ollama /api/embeddings Schnittstelle.
|
|
*
|
|
* @return array<int, float>|null
|
|
*/
|
|
public function embed(string $text): ?array
|
|
{
|
|
try {
|
|
$response = Http::timeout(30)
|
|
->post(rtrim($this->ollamaUrl, '/').'/api/embeddings', [
|
|
'model' => $this->embedModel,
|
|
'prompt' => $text,
|
|
]);
|
|
|
|
if (! $response->successful()) {
|
|
Log::warning('Embedding-Request fehlgeschlagen', ['status' => $response->status()]);
|
|
|
|
return null;
|
|
}
|
|
|
|
return $response->json('embedding');
|
|
} catch (\Throwable $e) {
|
|
Log::error('Embedding-Fehler', ['exception' => $e->getMessage()]);
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public function summarizeRecent(int $limit = 10): string
|
|
{
|
|
$memories = Memory::latest()->limit($limit)->get();
|
|
|
|
return $memories
|
|
->map(fn (Memory $m) => '- '.str($m->content)->limit(160))
|
|
->implode("\n");
|
|
}
|
|
}
|