import { getApiKeys } from "@/lib/localDb"; import { UPDATER_CONFIG } from "@/shared/constants/config"; import { getConsistentMachineId } from "@/shared/utils/machineId"; const CLI_TOKEN_SALT = "9r-cli-auth"; function createSilentWavFile() { const sampleRate = 16000; const channels = 1; const bitsPerSample = 16; const durationMs = 250; const sampleCount = Math.max(1, Math.floor((sampleRate * durationMs) / 1000)); const dataSize = sampleCount * channels * (bitsPerSample / 8); const buffer = new ArrayBuffer(44 + dataSize); const view = new DataView(buffer); const writeAscii = (offset, value) => { for (let i = 0; i < value.length; i += 1) { view.setUint8(offset + i, value.charCodeAt(i)); } }; writeAscii(0, "RIFF"); view.setUint32(4, 36 + dataSize, true); writeAscii(8, "WAVE"); writeAscii(12, "fmt "); view.setUint32(16, 16, true); view.setUint16(20, 1, true); view.setUint16(22, channels, true); view.setUint32(24, sampleRate, true); view.setUint32(28, sampleRate * channels * (bitsPerSample / 8), true); view.setUint16(32, channels * (bitsPerSample / 8), true); view.setUint16(34, bitsPerSample, true); writeAscii(36, "data"); view.setUint32(40, dataSize, true); return new Blob([buffer], { type: "audio/wav" }); } async function getInternalHeaders() { let apiKey = null; try { const keys = await getApiKeys(); apiKey = keys.find((k) => k.isActive !== false)?.key || null; } catch {} const headers = { "Content-Type": "application/json" }; if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`; headers["x-9r-cli-token"] = await getConsistentMachineId(CLI_TOKEN_SALT); return headers; } export async function pingModelByKind(model, kind, baseUrl = `http://127.0.0.1:${process.env.PORT || UPDATER_CONFIG.appPort}`) { const headers = await getInternalHeaders(); const start = Date.now(); if (kind === "embedding") { const res = await fetch(`${baseUrl}/api/v1/embeddings`, { method: "POST", headers, body: JSON.stringify({ model, input: "test" }), signal: AbortSignal.timeout(15000), }); const latencyMs = Date.now() - start; const rawText = await res.text().catch(() => ""); let parsed = null; try { parsed = rawText ? JSON.parse(rawText) : null; } catch {} if (!res.ok) { const detail = parsed?.error?.message || parsed?.error || rawText; return { ok: false, latencyMs, error: `HTTP ${res.status}${detail ? `: ${String(detail).slice(0, 240)}` : ""}`, status: res.status }; } const hasEmbedding = Array.isArray(parsed?.data) && parsed.data.length > 0 && Array.isArray(parsed.data[0]?.embedding); if (!hasEmbedding) { return { ok: false, latencyMs, status: res.status, error: "Provider returned no embedding data" }; } return { ok: true, latencyMs, error: null, status: res.status }; } if (kind === "image") { const res = await fetch(`${baseUrl}/api/v1/images/generations`, { method: "POST", headers, body: JSON.stringify({ model, prompt: "test" }), signal: AbortSignal.timeout(15000), }); const latencyMs = Date.now() - start; const rawText = await res.text().catch(() => ""); let parsed = null; try { parsed = rawText ? JSON.parse(rawText) : null; } catch {} if (!res.ok) { const detail = parsed?.error?.message || parsed?.msg || parsed?.message || parsed?.error || rawText; return { ok: false, latencyMs, error: `HTTP ${res.status}${detail ? `: ${String(detail).slice(0, 240)}` : ""}`, status: res.status }; } const hasImages = Array.isArray(parsed?.data) && parsed.data.length > 0; if (!hasImages) { return { ok: false, latencyMs, status: res.status, error: "Provider returned no image data for this model" }; } return { ok: true, latencyMs, error: null, status: res.status }; } if (kind === "stt") { const form = new FormData(); const sampleAudio = createSilentWavFile(); form.append("file", sampleAudio, "test.wav"); form.append("model", model); const res = await fetch(`${baseUrl}/api/v1/audio/transcriptions`, { method: "POST", headers: Object.fromEntries(Object.entries(headers).filter(([key]) => key.toLowerCase() !== "content-type")), body: form, signal: AbortSignal.timeout(15000), }); const latencyMs = Date.now() - start; const rawText = await res.text().catch(() => ""); let parsed = null; try { parsed = rawText ? JSON.parse(rawText) : null; } catch {} if (!res.ok) { const detail = parsed?.error?.message || parsed?.msg || parsed?.message || parsed?.error || rawText; return { ok: false, latencyMs, error: `HTTP ${res.status}${detail ? `: ${String(detail).slice(0, 240)}` : ""}`, status: res.status }; } const text = typeof parsed?.text === "string" ? parsed.text : ""; if (!text.trim()) { return { ok: false, latencyMs, status: res.status, error: "Provider returned no transcription text for this model" }; } return { ok: true, latencyMs, error: null, status: res.status }; } const res = await fetch(`${baseUrl}/api/v1/chat/completions`, { method: "POST", headers, body: JSON.stringify({ model, max_tokens: 1, stream: false, messages: [{ role: "user", content: "hi" }], }), signal: AbortSignal.timeout(15000), }); const latencyMs = Date.now() - start; const rawText = await res.text().catch(() => ""); let parsed = null; try { parsed = rawText ? JSON.parse(rawText) : null; } catch {} if (!res.ok) { const detail = parsed?.error?.message || parsed?.msg || parsed?.message || parsed?.error || rawText; return { ok: false, latencyMs, error: `HTTP ${res.status}${detail ? `: ${String(detail).slice(0, 240)}` : ""}`, status: res.status }; } const providerStatus = parsed?.status; const providerMsg = parsed?.msg || parsed?.message; const hasProviderErrorStatus = providerStatus !== undefined && providerStatus !== null && String(providerStatus) !== "200" && String(providerStatus) !== "0"; if (hasProviderErrorStatus && providerMsg) { return { ok: false, latencyMs, status: res.status, error: `Provider status ${providerStatus}: ${String(providerMsg).slice(0, 240)}`, }; } if (parsed?.error) { const providerError = parsed?.error?.message || parsed?.error || "Provider returned an error"; return { ok: false, latencyMs, status: res.status, error: String(providerError).slice(0, 240), }; } const hasChoices = Array.isArray(parsed?.choices) && parsed.choices.length > 0; if (!hasChoices) { return { ok: false, latencyMs, status: res.status, error: "Provider returned no completion choices for this model", }; } return { ok: true, latencyMs, error: null, status: res.status }; }