From 62ecb3eb24e9526df9cde4fb926592addd84abd4 Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Thu, 5 Mar 2026 18:30:02 +0100 Subject: [PATCH] refactor: GPU Infrastruktur aus Core Admin entfernt (liegt im Lehrer) Co-Authored-By: Claude Opus 4.6 --- .../app/(admin)/infrastructure/gpu/page.tsx | 390 ------------------ admin-core/lib/navigation.ts | 9 - 2 files changed, 399 deletions(-) delete mode 100644 admin-core/app/(admin)/infrastructure/gpu/page.tsx diff --git a/admin-core/app/(admin)/infrastructure/gpu/page.tsx b/admin-core/app/(admin)/infrastructure/gpu/page.tsx deleted file mode 100644 index e88c903..0000000 --- a/admin-core/app/(admin)/infrastructure/gpu/page.tsx +++ /dev/null @@ -1,390 +0,0 @@ -'use client' - -/** - * GPU Infrastructure Admin Page - * - * vast.ai GPU Management for LLM Processing - */ - -import { useEffect, useState, useCallback } from 'react' -import { PagePurpose } from '@/components/common/PagePurpose' - -interface VastStatus { - instance_id: number | null - status: string - gpu_name: string | null - dph_total: number | null - endpoint_base_url: string | null - last_activity: string | null - auto_shutdown_in_minutes: number | null - total_runtime_hours: number | null - total_cost_usd: number | null - account_credit: number | null - account_total_spend: number | null - session_runtime_minutes: number | null - session_cost_usd: number | null - message: string | null - error?: string -} - -export default function GPUInfrastructurePage() { - const [status, setStatus] = useState(null) - const [loading, setLoading] = useState(true) - const [actionLoading, setActionLoading] = useState(null) - const [error, setError] = useState(null) - const [message, setMessage] = useState(null) - - const API_PROXY = '/api/admin/gpu' - - const fetchStatus = useCallback(async () => { - setLoading(true) - setError(null) - - try { - const response = await fetch(API_PROXY) - const data = await response.json() - - if (!response.ok) { - throw new Error(data.error || `HTTP ${response.status}`) - } - - setStatus(data) - } catch (err) { - setError(err instanceof Error ? err.message : 'Verbindungsfehler') - setStatus({ - instance_id: null, - status: 'error', - gpu_name: null, - dph_total: null, - endpoint_base_url: null, - last_activity: null, - auto_shutdown_in_minutes: null, - total_runtime_hours: null, - total_cost_usd: null, - account_credit: null, - account_total_spend: null, - session_runtime_minutes: null, - session_cost_usd: null, - message: 'Verbindung fehlgeschlagen' - }) - } finally { - setLoading(false) - } - }, []) - - useEffect(() => { - fetchStatus() - }, [fetchStatus]) - - useEffect(() => { - const interval = setInterval(fetchStatus, 30000) - return () => clearInterval(interval) - }, [fetchStatus]) - - const powerOn = async () => { - setActionLoading('on') - setError(null) - setMessage(null) - - try { - const response = await fetch(API_PROXY, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ action: 'on' }), - }) - - const data = await response.json() - - if (!response.ok) { - throw new Error(data.error || data.detail || 'Aktion fehlgeschlagen') - } - - setMessage('Start angefordert') - setTimeout(fetchStatus, 3000) - setTimeout(fetchStatus, 10000) - } catch (err) { - setError(err instanceof Error ? err.message : 'Fehler beim Starten') - fetchStatus() - } finally { - setActionLoading(null) - } - } - - const powerOff = async () => { - setActionLoading('off') - setError(null) - setMessage(null) - - try { - const response = await fetch(API_PROXY, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ action: 'off' }), - }) - - const data = await response.json() - - if (!response.ok) { - throw new Error(data.error || data.detail || 'Aktion fehlgeschlagen') - } - - setMessage('Stop angefordert') - setTimeout(fetchStatus, 3000) - setTimeout(fetchStatus, 10000) - } catch (err) { - setError(err instanceof Error ? err.message : 'Fehler beim Stoppen') - fetchStatus() - } finally { - setActionLoading(null) - } - } - - const getStatusBadge = (s: string) => { - const baseClasses = 'px-3 py-1 rounded-full text-sm font-semibold uppercase' - switch (s) { - case 'running': - return `${baseClasses} bg-green-100 text-green-800` - case 'stopped': - case 'exited': - return `${baseClasses} bg-red-100 text-red-800` - case 'loading': - case 'scheduling': - case 'creating': - case 'starting...': - case 'stopping...': - return `${baseClasses} bg-yellow-100 text-yellow-800` - default: - return `${baseClasses} bg-slate-100 text-slate-600` - } - } - - const getCreditColor = (credit: number | null) => { - if (credit === null) return 'text-slate-500' - if (credit < 5) return 'text-red-600' - if (credit < 15) return 'text-yellow-600' - return 'text-green-600' - } - - return ( -
- {/* Page Purpose */} - - - {/* Status Cards */} -
-
-
-
Status
- {loading ? ( - - Laden... - - ) : ( - - {actionLoading === 'on' ? 'starting...' : - actionLoading === 'off' ? 'stopping...' : - status?.status || 'unbekannt'} - - )} -
- -
-
GPU
-
- {status?.gpu_name || '-'} -
-
- -
-
Kosten/h
-
- {status?.dph_total ? `$${status.dph_total.toFixed(3)}` : '-'} -
-
- -
-
Auto-Stop
-
- {status && status.auto_shutdown_in_minutes !== null - ? `${status.auto_shutdown_in_minutes} min` - : '-'} -
-
- -
-
Budget
-
- {status && status.account_credit !== null - ? `$${status.account_credit.toFixed(2)}` - : '-'} -
-
- -
-
Session
-
- {status && status.session_runtime_minutes !== null && status.session_cost_usd !== null - ? `${Math.round(status.session_runtime_minutes)} min / $${status.session_cost_usd.toFixed(3)}` - : '-'} -
-
-
- - {/* Buttons */} -
- - - - - {message && ( - {message} - )} - {error && ( - {error} - )} -
-
- - {/* Extended Stats */} -
-
-

Kosten-Uebersicht

-
-
- Session Laufzeit - - {status && status.session_runtime_minutes !== null - ? `${Math.round(status.session_runtime_minutes)} Minuten` - : '-'} - -
-
- Session Kosten - - {status && status.session_cost_usd !== null - ? `$${status.session_cost_usd.toFixed(4)}` - : '-'} - -
-
- Gesamtlaufzeit - - {status && status.total_runtime_hours !== null - ? `${status.total_runtime_hours.toFixed(1)} Stunden` - : '-'} - -
-
- Gesamtkosten - - {status && status.total_cost_usd !== null - ? `$${status.total_cost_usd.toFixed(2)}` - : '-'} - -
-
- vast.ai Ausgaben - - {status && status.account_total_spend !== null - ? `$${status.account_total_spend.toFixed(2)}` - : '-'} - -
-
-
- -
-

Instanz-Details

-
-
- Instanz ID - - {status?.instance_id || '-'} - -
-
- GPU - - {status?.gpu_name || '-'} - -
-
- Stundensatz - - {status?.dph_total ? `$${status.dph_total.toFixed(4)}/h` : '-'} - -
-
- Letzte Aktivitaet - - {status?.last_activity - ? new Date(status.last_activity).toLocaleString('de-DE') - : '-'} - -
- {status?.endpoint_base_url && status.status === 'running' && ( -
-
Endpoint
- - {status.endpoint_base_url} - -
- )} -
-
-
- - {/* Info */} -
-
- - - -
-

Auto-Shutdown

-

- Die GPU-Instanz wird automatisch gestoppt, wenn sie laengere Zeit inaktiv ist. - Der Status wird alle 30 Sekunden automatisch aktualisiert. -

-
-
-
-
- ) -} diff --git a/admin-core/lib/navigation.ts b/admin-core/lib/navigation.ts index 1e0dfa8..f69d706 100644 --- a/admin-core/lib/navigation.ts +++ b/admin-core/lib/navigation.ts @@ -38,15 +38,6 @@ export const navigation: NavCategory[] = [ colorClass: 'infrastructure', description: 'GPU, Security, CI/CD & Monitoring', modules: [ - { - id: 'gpu', - name: 'GPU Infrastruktur', - href: '/infrastructure/gpu', - description: 'vast.ai GPU Management', - purpose: 'GPU-Instanzen auf vast.ai fuer ML-Training und Inferenz verwalten.', - audience: ['DevOps', 'Entwickler'], - subgroup: 'Compute', - }, { id: 'middleware', name: 'Middleware',