feat(gpu-server): complete GPU server setup with AI services, monitoring, and public access

- Set up 5 AI services on Windows GPU server (RTX 3090):
  - mana-llm (Port 3025): OpenAI-compatible LLM gateway via Ollama
  - mana-stt (Port 3020): WhisperX with word timestamps + speaker diarization
  - mana-tts (Port 3022): Kokoro (EN) + Edge TTS (DE) + Piper (local DE)
  - mana-image-gen (Port 3023): FLUX.2 klein 4B image generation
  - Ollama (Port 11434): gemma3:4b/12b, qwen2.5-coder:14b, nomic-embed-text

- Add @manacore/shared-gpu TypeScript client package with SttClient, TtsClient, ImageClient
- Add CUDA-compatible whisper_service using faster-whisper for Windows
- Configure public access via Cloudflare Tunnel (gpu-llm/stt/tts/img.mana.how)
- Add Loki log aggregator (Docker on Mac Mini) + log shipper on GPU server
- Add GPU scrape targets to Prometheus/VictoriaMetrics config
- Add Grafana Loki datasource for GPU service logs
- Add health check with auto-restart, log rotation, and log shipping
- Document complete setup: Always-On config, troubleshooting, architecture

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-03-27 21:35:30 +01:00
parent 7754cf6e00
commit 16e0d99c5a
13 changed files with 1245 additions and 7 deletions

View file

@ -0,0 +1,56 @@
import type { GpuServiceConfig } from './types';
import { SttClient } from './stt-client';
import { TtsClient } from './tts-client';
import { ImageClient } from './image-client';
/**
* Unified client for all Mana GPU services.
*
* @example Public URLs (from anywhere):
* ```ts
* const gpu = new GpuClient({ baseUrl: 'https://gpu.mana.how' });
* ```
*
* @example LAN (direct):
* ```ts
* const gpu = new GpuClient({ baseUrl: 'http://192.168.178.11' });
* ```
*
* @example Custom URLs:
* ```ts
* const gpu = new GpuClient({
* baseUrl: '',
* urls: { stt: 'https://gpu-stt.mana.how', tts: 'https://gpu-tts.mana.how' },
* });
* ```
*/
export class GpuClient {
public readonly stt: SttClient;
public readonly tts: TtsClient;
public readonly image: ImageClient;
constructor(config: GpuServiceConfig) {
this.stt = new SttClient(config);
this.tts = new TtsClient(config);
this.image = new ImageClient(config);
}
/** Check health of all GPU services. */
async healthCheck(): Promise<{
stt: boolean;
tts: boolean;
image: boolean;
}> {
const [sttHealth, ttsHealth, imageHealth] = await Promise.allSettled([
this.stt.health(),
this.tts.health(),
this.image.health(),
]);
return {
stt: sttHealth.status === 'fulfilled' && sttHealth.value.status === 'healthy',
tts: ttsHealth.status === 'fulfilled' && ttsHealth.value.status === 'healthy',
image: imageHealth.status === 'fulfilled' && imageHealth.value.status === 'healthy',
};
}
}