auralynq-rag / web /components /landing /SystemStatus.tsx
MHamdan's picture
Deploy Auralynq RAG (Llama-3.3-70B via HF Inference Providers)
8c1b9fe verified
Raw
History Blame Contribute Delete
6.91 kB
"use client";
import { useEffect, useState } from "react";
import type { ReactNode } from "react";
import { statusSummary } from "@/lib/api";
type Health = "healthy" | "degraded" | "offline" | "checking";
interface Group {
key: string;
label: string;
value: string;
health: Health;
icon: ReactNode;
}
const ICON: Record<string, ReactNode> = {
api: <path d="M4 7h16M4 12h16M4 17h10" />,
corpus: <path d="M4 5a2 2 0 0 1 2-2h9l5 5v11a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2Z M14 3v5h5" />,
vector: <path d="M12 3v18M5 7l7-4 7 4M5 17l7 4 7-4M5 7v10M19 7v10" />,
embeddings: <path d="M6 6h.01M12 6h.01M18 6h.01M6 12h.01M12 12h.01M18 12h.01M6 18h.01M12 18h.01M18 18h.01" />,
llm: <path d="M12 2a7 7 0 0 0-4 12.74V18a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2v-3.26A7 7 0 0 0 12 2ZM9 22h6" />,
voice: <path d="M9 3h6v8a3 3 0 0 1-6 0Z M5 11a7 7 0 0 0 14 0M12 18v3" />,
tracing: <path d="M3 12h4l3 8 4-16 3 8h4" />,
};
function Glyph({ name }: { name: string }) {
return (
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.6"
strokeLinecap="round"
strokeLinejoin="round"
className="h-5 w-5"
aria-hidden
>
{ICON[name]}
</svg>
);
}
const HEALTH_PILL: Record<Health, string> = {
healthy: "pill-ok",
degraded: "pill-warn",
offline: "pill-bad",
checking: "pill-neutral",
};
const HEALTH_LABEL: Record<Health, string> = {
healthy: "Healthy",
degraded: "Degraded",
offline: "Offline",
checking: "Checking…",
};
export function SystemStatus() {
const [groups, setGroups] = useState<Group[] | null>(null);
const [up, setUp] = useState<boolean | null>(null);
useEffect(() => {
statusSummary()
.then((s) => {
setUp(true);
setGroups(buildGroups(s));
})
.catch(() => {
setUp(false);
setGroups(buildGroups(null));
});
}, []);
const live: Group[] = groups ?? checkingGroups();
return (
<div className="mx-auto mt-12 max-w-5xl">
<div className="mb-4 flex items-center justify-between px-1">
<div>
<p className="overline">Live system status</p>
<p className="mt-1 text-sm text-fg3">Every subsystem, reported from your running stack.</p>
</div>
<span className={`pill ${up === null ? "pill-neutral" : up ? "pill-ok" : "pill-bad"}`}>
<span
className={`inline-block h-2 w-2 rounded-full ${
up === null ? "bg-fg3" : up ? "bg-ok animate-pulse-soft" : "bg-bad"
}`}
/>
{up === null ? "Connecting…" : up ? "API online" : "API offline"}
</span>
</div>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-4">
{live.map((g) => (
<div key={g.key} className="card card-hover">
<div className="flex items-start justify-between gap-2">
<span className="inline-flex rounded-lg border border-edge bg-panel2 p-2 text-brand">
<Glyph name={g.icon as string} />
</span>
<span className={`pill ${HEALTH_PILL[g.health]}`}>
<span
className={`inline-block h-1.5 w-1.5 rounded-full ${
g.health === "healthy"
? "bg-ok"
: g.health === "degraded"
? "bg-warn"
: g.health === "offline"
? "bg-bad"
: "bg-fg3"
}`}
/>
{HEALTH_LABEL[g.health]}
</span>
</div>
<h3 className="mt-3 text-sm font-semibold text-fg">{g.label}</h3>
<p className="mt-0.5 truncate text-sm text-fg3" title={g.value}>
{g.value}
</p>
</div>
))}
</div>
</div>
);
}
// ---- mapping the /status payload into the seven product subsystems --------
interface StatusPayload {
providers?: { subsystem: string; provider: string }[];
index?: { vectors?: number };
corpus?: { indexed?: boolean; indexed_document_count?: number; vector_count?: number };
tracing?: { provider?: string; enabled?: boolean; phoenix_endpoint?: string | null };
}
function provider(p: StatusPayload, key: string): string | null {
const row = (p.providers || []).find((r) => r.subsystem === key);
const v = row?.provider;
return v && v !== "null" ? v : null;
}
function buildGroups(p: StatusPayload | null): Group[] {
if (!p) {
return checkingGroups().map((g) => ({ ...g, health: "offline" as Health, value: "unreachable" }));
}
const vectors = p.index?.vectors ?? p.corpus?.vector_count ?? 0;
const docs = p.corpus?.indexed_document_count ?? 0;
const indexed = !!p.corpus?.indexed || vectors > 0;
const llm = provider(p, "llm");
const vs = provider(p, "vector_store");
const emb = provider(p, "embeddings");
const asr = provider(p, "asr");
const tts = provider(p, "tts");
const tracingOn = !!p.tracing?.enabled;
const tracingProv = p.tracing?.provider || (tracingOn ? "enabled" : "in-process");
const presence = (v: string | null): Health => (v ? "healthy" : "degraded");
return [
{ key: "api", label: "API", value: "FastAPI · online", health: "healthy", icon: "api" },
{
key: "corpus",
label: "Corpus",
value: indexed ? `${docs || "—"} document${docs === 1 ? "" : "s"} indexed` : "empty — ingest to begin",
health: indexed ? "healthy" : "degraded",
icon: "corpus",
},
{
key: "vector",
label: "Vector DB",
value: vs ? `${vs} · ${vectors.toLocaleString()} vectors` : `${vectors.toLocaleString()} vectors`,
health: vectors > 0 ? "healthy" : "degraded",
icon: "vector",
},
{ key: "embeddings", label: "Embeddings", value: emb || "not configured", health: presence(emb), icon: "embeddings" },
{ key: "llm", label: "LLM", value: llm || "not configured", health: presence(llm), icon: "llm" },
{
key: "voice",
label: "ASR / TTS",
value: asr || tts ? `${asr || "—"} · ${tts || "—"}` : "offline fallback",
health: asr || tts ? "healthy" : "degraded",
icon: "voice",
},
{
key: "tracing",
label: "Tracing",
value: tracingProv,
health: tracingOn ? "healthy" : "degraded",
icon: "tracing",
},
];
}
function checkingGroups(): Group[] {
return [
{ key: "api", label: "API", icon: "api" },
{ key: "corpus", label: "Corpus", icon: "corpus" },
{ key: "vector", label: "Vector DB", icon: "vector" },
{ key: "embeddings", label: "Embeddings", icon: "embeddings" },
{ key: "llm", label: "LLM", icon: "llm" },
{ key: "voice", label: "ASR / TTS", icon: "voice" },
{ key: "tracing", label: "Tracing", icon: "tracing" },
].map((g) => ({ ...g, value: "checking…", health: "checking" as Health }));
}