Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
File size: 6,340 Bytes
374bcb6 | 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 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | /**
* Zod schemas + types for the web app's HTTP API (browser β Next.js route
* handlers). One source of truth so the client and server can't drift.
*/
import { z } from "zod";
export const MAX_TEXT_LENGTH = 1000;
export const SESSION_TTL_SECONDS = 30 * 60;
/* ββ Auth βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
export const userSchema = z.object({
id: z.number().int(),
username: z.string(),
hfId: z.string(),
avatarUrl: z.string().nullable(),
showInLeaderboard: z.boolean(),
isAdmin: z.boolean(),
});
export type ApiUser = z.infer<typeof userSchema>;
export const meResponseSchema = z.object({
user: userSchema.nullable(),
});
export type MeResponse = z.infer<typeof meResponseSchema>;
/* ββ TTS generate βββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
export const ttsGenerateRequestSchema = z.object({
text: z.string().trim().min(1).max(MAX_TEXT_LENGTH),
/** True when the text came from the prompt pool (the Random button), not
* free-typed. Determines the vote's recorded sentenceOrigin. */
fromPool: z.boolean().optional(),
/** Signed proof that this exact prompt was served by the random endpoint. */
promptToken: z.string().optional(),
});
export type TTSGenerateRequest = z.infer<typeof ttsGenerateRequestSchema>;
export const conversationalLineSchema = z.object({
text: z.string().trim().min(1).max(MAX_TEXT_LENGTH),
speaker: z.union([z.literal(0), z.literal(1)]),
});
export type ConversationalLine = z.infer<typeof conversationalLineSchema>;
export const conversationalGenerateRequestSchema = z.object({
script: z.array(conversationalLineSchema).min(2),
});
export type ConversationalGenerateRequest = z.infer<
typeof conversationalGenerateRequestSchema
>;
export const generateResponseSchema = z.object({
sessionId: z.string().uuid(),
audioA: z.string(),
audioB: z.string(),
expiresIn: z.number().int(),
});
export type GenerateResponse = z.infer<typeof generateResponseSchema>;
/* ββ Vote βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
export const voteRequestSchema = z.object({
sessionId: z.string().uuid(),
chosen: z.union([z.literal("a"), z.literal("b")]),
});
export type VoteRequest = z.infer<typeof voteRequestSchema>;
export const revealedModelSchema = z.object({
id: z.string(),
name: z.string(),
open: z.boolean(),
url: z.string(),
});
export const voteResponseSchema = z.object({
chosen: revealedModelSchema,
rejected: revealedModelSchema,
/** Whether this vote affected the public Elo board. */
counted: z.boolean(),
});
export type VoteResponse = z.infer<typeof voteResponseSchema>;
/**
* When a captcha is required before the vote can be recorded, the vote endpoint
* returns this instead (HTTP 200) β the client solves the Cap challenge and
* retries with the token. Kept separate so the normal path stays unchanged.
*/
export const captchaRequiredSchema = z.object({
needsCaptcha: z.literal(true),
});
export type CaptchaRequired = z.infer<typeof captchaRequiredSchema>;
/* ββ Leaderboard ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
export const leaderboardRowSchema = z.object({
rank: z.number().int(),
id: z.string(),
name: z.string(),
url: z.string(),
/** Optional provider logo URL. */
icon: z.string().nullable(),
/** Displayed rating: Glicko-2 while preliminary, BradleyβTerry once established. */
elo: z.number().int(),
/** Β± uncertainty on the rating (β2Β·RD for Glicko, half the BT CI width). */
uncertainty: z.number().int(),
winRate: z.number(), // 0β100
totalVotes: z.number().int(),
tier: z.enum(["S", "A", "B"]).nullable(),
open: z.boolean(),
/** True while the model has < ESTABLISHED_THRESHOLD counted votes. */
preliminary: z.boolean(),
/**
* False for retired models kept on the board for their historical rating
* (no longer battled). The UI badges these "no longer active".
*/
active: z.boolean(),
/**
* True when the model was pulled for misconduct (e.g. vote manipulation). It's
* delisted from the ranking (rank 0) and shown with a "Suspended" badge; its
* row and votes are preserved as evidence.
*/
suspended: z.boolean(),
/** Unix seconds when suspended (for the badge tooltip). */
suspendedAt: z.number().int().nullable(),
/** Human-readable suspension reason (badge tooltip). */
suspendedReason: z.string().nullable(),
});
export type LeaderboardRow = z.infer<typeof leaderboardRowSchema>;
export const leaderboardResponseSchema = z.object({
rows: z.array(leaderboardRowSchema),
});
export type LeaderboardResponse = z.infer<typeof leaderboardResponseSchema>;
export const topVoterSchema = z.object({
rank: z.number().int(),
username: z.string(),
voteCount: z.number().int(),
});
export type TopVoter = z.infer<typeof topVoterSchema>;
/* ββ Sentences ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
export const randomSentenceResponseSchema = z.object({
sentence: z.string(),
promptToken: z.string(),
});
export type RandomSentenceResponse = z.infer<
typeof randomSentenceResponseSchema
>;
export const sentenceStatsSchema = z.object({
total: z.number().int(),
consumed: z.number().int(),
remaining: z.number().int(),
consumptionPct: z.number(),
});
export type SentenceStats = z.infer<typeof sentenceStatsSchema>;
/* ββ Errors βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
export const errorResponseSchema = z.object({
error: z.string(),
detail: z.string().optional(),
});
export type ErrorResponse = z.infer<typeof errorResponseSchema>;
|