Spaces:
Running
Running
File size: 5,272 Bytes
94004a2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | import { apiJson, apiFetch, apiPost } from './client';
import type { SystemInfo, ModelStatus, LogsResponse, ClearTauriResponse } from './types';
// ββ Tauri IPC helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Try native Tauri invoke() first β it's faster (no HTTP round-trip) and
// works when the Python backend is still booting. Falls back to HTTP when
// running in browser dev mode (no Tauri shell).
let _invoke: ((cmd: string, args?: Record<string, unknown>) => Promise<unknown>) | null = null;
async function getInvoke() {
if (_invoke !== null) return _invoke;
try {
const mod = await import('@tauri-apps/api/core');
_invoke = mod.invoke;
return _invoke;
} catch {
// Not running inside Tauri (browser dev mode)
_invoke = null as any;
return null;
}
}
/** Try Tauri invoke, fall back to HTTP. */
async function invokeOrFetch<T>(
command: string,
args: Record<string, unknown> | undefined,
httpFallback: () => Promise<T>,
): Promise<T> {
try {
const invoke = await getInvoke();
if (invoke) {
return (await invoke(command, args)) as T;
}
} catch {
// invoke failed β fall through to HTTP
}
return httpFallback();
}
// ββ System info (polled every 5s) ββββββββββββββββββββββββββββββββββββββββ
export interface SysinfoData {
cpu: number;
ram: number;
total_ram: number;
vram: number;
gpu_active: boolean;
}
// Cache VRAM from Python β it changes much slower than CPU/RAM, so we
// only refresh it every 15s instead of every 5s poll cycle.
let _vramCache: { vram: number; gpu_active: boolean; ts: number } | null = null;
const VRAM_CACHE_TTL = 15_000;
export async function sysinfo(): Promise<SysinfoData> {
// Rust provides CPU + RAM; VRAM stays at 0. We merge with the Python
// endpoint to get GPU data when available.
const rustData = await invokeOrFetch<SysinfoData>(
'get_sysinfo',
undefined,
() => apiJson<SysinfoData>('/sysinfo'),
);
// If we got data from Rust (vram=0), enrich with Python's VRAM data
// but only re-fetch every 15s to avoid hammering the backend.
if (rustData.vram === 0) {
const now = Date.now();
if (!_vramCache || now - _vramCache.ts > VRAM_CACHE_TTL) {
try {
const pyData = await apiJson<SysinfoData>('/sysinfo');
_vramCache = { vram: pyData.vram, gpu_active: pyData.gpu_active, ts: now };
} catch {
// Python backend not ready yet β return Rust-only data
return rustData;
}
}
return {
...rustData,
vram: _vramCache.vram,
gpu_active: _vramCache.gpu_active,
};
}
return rustData;
}
// ββ Model status βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export async function modelStatus(): Promise<ModelStatus> {
return apiJson<ModelStatus>('/model/status');
}
// ββ Audio cleaning βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export async function cleanAudio(formData: FormData): Promise<Response> {
// Returns Response because caller needs blob body + X-Clean-Filename header.
return apiFetch('/clean-audio', { method: 'POST', body: formData });
}
// ββ System info (one-shot, for Settings) βββββββββββββββββββββββββββββββββ
export async function systemInfo(): Promise<SystemInfo> {
return apiJson<SystemInfo>('/system/info');
}
// ββ Logs (polled every 5s) βββββββββββββββββββββββββββββββββββββββββββββββ
export async function systemLogs(tail: number = 300): Promise<LogsResponse> {
return invokeOrFetch<LogsResponse>(
'read_log_tail',
{ source: 'backend', tail },
() => apiJson<LogsResponse>(`/system/logs?tail=${tail}`),
);
}
export async function systemLogsTauri(tail: number = 300): Promise<LogsResponse> {
return invokeOrFetch<LogsResponse>(
'read_log_tail',
{ source: 'tauri', tail },
() => apiJson<LogsResponse>(`/system/logs/tauri?tail=${tail}`),
);
}
// ββ Log clearing βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export async function clearSystemLogs(): Promise<unknown> {
return apiPost('/system/logs/clear');
}
export async function clearTauriLogs(): Promise<ClearTauriResponse> {
return apiPost<ClearTauriResponse>('/system/logs/tauri/clear');
}
// ββ Memory flush βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
export async function flushMemory(unloadModel: boolean = false): Promise<unknown> {
return apiPost(`/system/flush-memory?unload_model=${unloadModel}`);
}
|