SignalMod / frontend /src /api /client.ts
Ruperth's picture
feat: add comment composer recent activity feed and random usernames
7e7e06a
raw
history blame
3.02 kB
import type {
ModelStatusEntry,
PredictResponse,
PredictionsListResponse,
SuggestedVideo,
VideoResponse,
} from "../types/api";
const BASE = import.meta.env.VITE_API_BASE_URL ?? "";
function parseApiError(body: unknown, fallback: string): string {
if (!body || typeof body !== "object") return fallback;
const detail = (body as { detail?: unknown }).detail;
if (typeof detail === "string") return detail;
if (Array.isArray(detail)) {
return detail
.map((item) => {
if (item && typeof item === "object" && "msg" in item) {
return String((item as { msg: unknown }).msg);
}
return String(item);
})
.join("; ");
}
return fallback;
}
async function request<T>(path: string, init?: RequestInit): Promise<T> {
const res = await fetch(`${BASE}${path}`, {
...init,
headers: { "Content-Type": "application/json", ...init?.headers },
});
if (!res.ok) {
const err = await res.json().catch(() => ({}));
throw new Error(parseApiError(err, res.statusText));
}
return res.json() as Promise<T>;
}
export function predict(text: string, threshold: number) {
return request<PredictResponse>("/predict", {
method: "POST",
body: JSON.stringify({ text, threshold }),
});
}
export function predictVideo(url: string, maxComments: number, threshold: number) {
return request<VideoResponse>("/predict-video", {
method: "POST",
body: JSON.stringify({ url, max_comments: maxComments, threshold }),
});
}
export function getModels() {
return request<{ available: string[]; active: string }>("/models");
}
export async function getModelsStatus() {
try {
return await request<{ models: ModelStatusEntry[]; active: string }>("/models/status");
} catch (e) {
if (e instanceof Error && e.message.toLowerCase().includes("not found")) {
const legacy = await getModels();
return {
active: legacy.active,
models: legacy.available.map((name) => ({
name,
available: true,
reason: null,
type: "unknown",
})),
};
}
throw e;
}
}
export function setModel(name: string) {
return request<{ message: string; model: string }>("/models/select", {
method: "POST",
body: JSON.stringify({ model_name: name }),
});
}
export function getSuggestedVideos() {
return request<{ videos: SuggestedVideo[]; max_comments: number }>("/videos/suggested");
}
export function listPredictions(videoId?: string, limit = 20) {
const params = new URLSearchParams();
if (videoId) params.set("video_id", videoId);
params.set("limit", String(limit));
return request<PredictionsListResponse>(`/predictions?${params.toString()}`);
}
export function getModelInfo() {
return request<{
name: string;
description: string;
predictions_served: number;
display_banner?: string | null;
train_test_gap_pp?: number | null;
recommended_threshold?: number | null;
accuracy?: string;
}>("/model-info");
}