64 lines
1.8 KiB
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);
|
|
}
|
|
}
|