fox/app/Tools/WebSearchTool.php

64 lines
1.8 KiB
PHP

<?php
namespace App\Tools;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Prism\Prism\Tool;
/**
* Websuche via lokaler SearXNG-Instanz - kein externer API-Key nötig.
*/
class WebSearchTool
{
public function asPrismTool(): Tool
{
return (new Tool)
->as('web_search')
->for('Sucht im Web via SearXNG (Meta-Suchmaschine, lokal) und gibt die besten Treffer zurück.')
->withStringParameter('query', 'Die Suchanfrage')
->using(fn (string $query) => $this->execute($query));
}
public function execute(string $query): string
{
try {
$response = Http::timeout(15)
->acceptJson()
->get(rtrim(config('services.searxng.url'), '/').'/search', [
'q' => $query,
'format' => 'json',
'language' => 'de',
'pageno' => 1,
]);
} catch (\Throwable $e) {
Log::warning('SearXNG nicht erreichbar', ['error' => $e->getMessage()]);
return 'Suche fehlgeschlagen: '.$e->getMessage();
}
if (! $response->successful()) {
return 'Suche fehlgeschlagen (HTTP '.$response->status().').';
}
$results = $response->json('results', []);
if (empty($results)) {
return 'Keine Treffer für: '.$query;
}
$lines = [];
foreach (array_slice($results, 0, 5) as $i => $hit) {
$lines[] = sprintf(
"%d. %s\n %s\n %s",
$i + 1,
$hit['title'] ?? '(ohne Titel)',
$hit['url'] ?? '',
trim((string) ($hit['content'] ?? '')),
);
}
return implode("\n\n", $lines);
}
}