148 lines
4.8 KiB
PHP
148 lines
4.8 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Services\SystemStatsService;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Http;
|
|
|
|
/**
|
|
* Voller System-Statusbericht für die HUD-Diagnose-Animation.
|
|
* Erweitert SystemStatsService um Service-Pings (Reverb, Google) + Uptime.
|
|
*/
|
|
class FoxStatusController
|
|
{
|
|
public function __invoke(SystemStatsService $stats): JsonResponse
|
|
{
|
|
$base = $stats->collect();
|
|
|
|
return response()->json([
|
|
'system' => [
|
|
'cpu' => $base['cpu'],
|
|
'memory' => $base['memory'],
|
|
'disk' => $base['disk'],
|
|
'load' => $base['load'],
|
|
'uptime' => $this->uptime(),
|
|
],
|
|
'services' => [
|
|
'ollama' => $base['ollama'],
|
|
'openai' => $base['openai'],
|
|
'reverb' => $this->reverbStatus(),
|
|
'google_directions' => $this->googleApiStatus('directions'),
|
|
'google_places' => $this->googleApiStatus('places'),
|
|
'google_geocoding' => $this->googleApiStatus('geocoding'),
|
|
'searxng' => $this->searxStatus(),
|
|
'queue' => ['len' => $base['queue']],
|
|
],
|
|
'fox' => [
|
|
'version' => '0.9.0',
|
|
'mode' => config('services.tts.engine', 'piper'),
|
|
'voice' => config('services.openai.tts_voice', 'onyx'),
|
|
'last_action' => $this->lastActionMeta(),
|
|
],
|
|
'timestamp' => now()->toIso8601String(),
|
|
]);
|
|
}
|
|
|
|
protected function uptime(): array
|
|
{
|
|
$raw = (string) @file_get_contents('/proc/uptime');
|
|
$secs = (float) explode(' ', trim($raw))[0];
|
|
|
|
return [
|
|
'seconds' => (int) $secs,
|
|
'human' => $this->humanDuration((int) $secs),
|
|
];
|
|
}
|
|
|
|
protected function humanDuration(int $secs): string
|
|
{
|
|
$d = intdiv($secs, 86400);
|
|
$h = intdiv($secs % 86400, 3600);
|
|
$m = intdiv($secs % 3600, 60);
|
|
|
|
return ($d ? $d.'d ' : '').($h ? $h.'h ' : '').$m.'m';
|
|
}
|
|
|
|
protected function reverbStatus(): array
|
|
{
|
|
try {
|
|
$r = Http::timeout(2)->get('http://reverb:8080/');
|
|
|
|
return ['online' => $r->status() < 500];
|
|
} catch (\Throwable) {
|
|
return ['online' => false];
|
|
}
|
|
}
|
|
|
|
protected function googleApiStatus(string $api): array
|
|
{
|
|
$key = config('services.google.maps_key');
|
|
if (empty($key)) {
|
|
return ['online' => false, 'reason' => 'no_key'];
|
|
}
|
|
|
|
// Cache 60s damit jeder Status-Call nicht alle APIs pingt.
|
|
return Cache::remember('fox.google.'.$api, 60, function () use ($api, $key) {
|
|
try {
|
|
if ($api === 'directions') {
|
|
$r = Http::timeout(3)->get('https://maps.googleapis.com/maps/api/directions/json', [
|
|
'origin' => '48.2082,16.3738', 'destination' => '48.21,16.37', 'key' => $key,
|
|
]);
|
|
$status = $r->json('status');
|
|
|
|
return ['online' => $r->successful() && in_array($status, ['OK', 'ZERO_RESULTS'], true)];
|
|
}
|
|
if ($api === 'geocoding') {
|
|
$r = Http::timeout(3)->get('https://maps.googleapis.com/maps/api/geocode/json', [
|
|
'latlng' => '48.2082,16.3738', 'key' => $key,
|
|
]);
|
|
|
|
return ['online' => $r->successful() && $r->json('status') === 'OK'];
|
|
}
|
|
if ($api === 'places') {
|
|
$r = Http::timeout(3)
|
|
->withHeaders(['X-Goog-Api-Key' => $key, 'X-Goog-FieldMask' => 'places.id'])
|
|
->post('https://places.googleapis.com/v1/places:searchText', [
|
|
'textQuery' => 'wien', 'maxResultCount' => 1,
|
|
]);
|
|
|
|
return ['online' => $r->successful()];
|
|
}
|
|
|
|
return ['online' => false];
|
|
} catch (\Throwable) {
|
|
return ['online' => false];
|
|
}
|
|
});
|
|
}
|
|
|
|
protected function searxStatus(): array
|
|
{
|
|
try {
|
|
$r = Http::timeout(2)->get(rtrim((string) config('services.searxng.url'), '/').'/search', [
|
|
'q' => 'test', 'format' => 'json',
|
|
]);
|
|
|
|
return ['online' => $r->status() < 500];
|
|
} catch (\Throwable) {
|
|
return ['online' => false];
|
|
}
|
|
}
|
|
|
|
protected function lastActionMeta(): ?array
|
|
{
|
|
$cached = Cache::get('fox.last_pois');
|
|
if (! is_array($cached)) {
|
|
return null;
|
|
}
|
|
|
|
return [
|
|
'type' => 'poi_search',
|
|
'label' => $cached['label'] ?? null,
|
|
'count' => count($cached['pois'] ?? []),
|
|
];
|
|
}
|
|
}
|