Spaces:
Paused
Paused
File size: 5,316 Bytes
a2bbd94 | 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 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | /**
* Typed fetch wrappers for the aggregate-first mega-scale evaluation API
* ("megaeval"). Mirrors the style of services/labeleval.ts.
*
* Async run semantics: POST /runs returns immediately with status "queued";
* results endpoints return HTTP 409 until the run is "published".
*/
import type {
CacheStats,
CompareRequest,
CompareResponse,
ContainerObjectsResponse,
ContainerSortPreset,
ContainersResponse,
CreateRunRequest,
DimName,
DistributionsResponse,
ErrorSearchRequest,
ErrorSearchResponse,
EvaluationQueryRequest,
EvaluationQueryResponse,
EvaluationRunInfo,
GeneratePopulationRequest,
MegaevalStatus,
PopulationMeta,
QualityFunnelResponse,
ReviewState,
ShiftResponse,
SimilarityRequest,
SimilarityResponse,
WhyRequest,
WhyResponse,
} from '../types/megaeval';
async function handle<T>(res: Response): Promise<T> {
if (!res.ok) {
const body = await res.text().catch(() => '');
throw new Error(`API ${res.status}: ${body || res.statusText}`);
}
return res.json() as Promise<T>;
}
const JSON_HEADERS = { 'Content-Type': 'application/json' };
function get<T>(url: string): Promise<T> {
return fetch(url).then((res) => handle<T>(res));
}
function post<T>(url: string, body?: unknown): Promise<T> {
return fetch(url, {
method: 'POST',
headers: JSON_HEADERS,
body: body === undefined ? undefined : JSON.stringify(body),
}).then((res) => handle<T>(res));
}
// ---------------------------------------------------------------- populations
export const generatePopulation = (body: GeneratePopulationRequest) =>
post<PopulationMeta>('/api/megaeval/population/generate', body);
export const getPopulations = () =>
get<{ populations: PopulationMeta[] }>('/api/megaeval/populations');
export const getDimensions = () =>
get<{ dimensions: Record<DimName, string[]> }>('/api/megaeval/dimensions');
// ---------------------------------------------------------------- runs
export const createRun = (body: CreateRunRequest) =>
post<EvaluationRunInfo>('/api/megaeval/runs', body);
export const getRuns = () => get<{ runs: EvaluationRunInfo[] }>('/api/megaeval/runs');
export const getRun = (runId: string) =>
get<EvaluationRunInfo>(`/api/megaeval/runs/${encodeURIComponent(runId)}`);
export const getMegaevalStatus = () => get<MegaevalStatus>('/api/megaeval/status');
// ---------------------------------------------------------------- query / cache
export const queryEvaluations = (body: EvaluationQueryRequest) =>
post<EvaluationQueryResponse>('/api/evaluations/query', body);
export const getCacheStats = () => get<CacheStats>('/api/megaeval/cache');
// ---------------------------------------------------------------- run results
export const getRunFunnel = (runId: string) =>
get<QualityFunnelResponse>(`/api/megaeval/runs/${encodeURIComponent(runId)}/funnel`);
export const getRunContainers = (
runId: string,
sort: ContainerSortPreset = 'highest_risk',
limit = 50,
offset = 0
) =>
get<ContainersResponse>(
`/api/megaeval/runs/${encodeURIComponent(runId)}/containers?sort=${encodeURIComponent(
sort
)}&limit=${limit}&offset=${offset}`
);
export const getContainerObjects = (runId: string, containerId: number) =>
get<ContainerObjectsResponse>(
`/api/megaeval/runs/${encodeURIComponent(runId)}/containers/${containerId}/objects`
);
export const searchErrors = (body: ErrorSearchRequest) =>
post<ErrorSearchResponse>('/api/megaeval/errors/search', body);
export const compareRuns = (body: CompareRequest) =>
post<CompareResponse>('/api/megaeval/compare', body);
export const getRunShift = (runId: string) =>
get<ShiftResponse>(`/api/megaeval/runs/${encodeURIComponent(runId)}/shift`);
export const whyAnalysis = (body: WhyRequest) => post<WhyResponse>('/api/megaeval/why', body);
export const findSimilarContainers = (body: SimilarityRequest) =>
post<SimilarityResponse>('/api/megaeval/similarity', body);
// ---------------------------------------------------------------- review sampling
export const getRunReview = (runId: string) =>
get<ReviewState>(`/api/megaeval/runs/${encodeURIComponent(runId)}/review`);
export const planReview = (runId: string, targetN?: number) =>
post<ReviewState>(
`/api/megaeval/runs/${encodeURIComponent(runId)}/review/plan`,
targetN !== undefined ? { target_n: targetN } : {}
);
export const executeReview = (runId: string) =>
post<ReviewState>(`/api/megaeval/runs/${encodeURIComponent(runId)}/review/execute`);
// ---------------------------------------------------------------- distributions
export const getRunDistributions = (runId: string) =>
get<DistributionsResponse>(`/api/megaeval/runs/${encodeURIComponent(runId)}/distributions`);
// ---------------------------------------------------------------- formatting
/** Compact count formatting for large aggregates: 950 -> "950", 214_700 -> "214.7K", 1_300_000 -> "1.3M". */
export function fmtCompact(n: number | null | undefined): string {
if (n === null || n === undefined || Number.isNaN(n)) return '—';
const abs = Math.abs(n);
if (abs >= 1e9) return `${(n / 1e9).toFixed(1)}B`;
if (abs >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
if (abs >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
return Math.round(n).toLocaleString();
}
|