Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
| /** | |
| * Admin panel API types. Response shapes for /api/admin/*; consumed by the | |
| * admin UI. Kept in @ttsa/shared so client and server agree on the contract. | |
| */ | |
| import { z } from "zod"; | |
| /* ββ Shared time series βββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| export const timePointSchema = z.object({ | |
| date: z.string(), | |
| count: z.number().int(), | |
| flagged: z.number().int().optional(), | |
| }); | |
| export type TimePoint = z.infer<typeof timePointSchema>; | |
| /* ββ Overview βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| export const adminOverviewSchema = z.object({ | |
| totals: z.object({ | |
| users: z.number().int(), | |
| votes: z.number().int(), | |
| models: z.number().int(), | |
| activeModels: z.number().int(), | |
| }), | |
| /** Vote count per day for the last 30 days, oldest first. */ | |
| votesByDay: z.array(z.object({ date: z.string(), count: z.number().int() })), | |
| recentVotes: z.array( | |
| z.object({ | |
| id: z.number().int(), | |
| createdAt: z.number().int(), | |
| username: z.string(), | |
| chosenModel: z.string(), | |
| rejectedModel: z.string(), | |
| text: z.string(), | |
| }), | |
| ), | |
| recentUsers: z.array( | |
| z.object({ | |
| id: z.number().int(), | |
| username: z.string(), | |
| avatarUrl: z.string().nullable(), | |
| joinDate: z.number().int(), | |
| }), | |
| ), | |
| }); | |
| export type AdminOverview = z.infer<typeof adminOverviewSchema>; | |
| /* ββ Models βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| export const adminModelSchema = z.object({ | |
| id: z.string(), | |
| name: z.string(), | |
| modelType: z.string(), | |
| provider: z.string().nullable(), | |
| isOpen: z.boolean(), | |
| isActive: z.boolean(), | |
| /** Epoch seconds until which the model is timed out, or null. */ | |
| timedOutUntil: z.number().int().nullable(), | |
| url: z.string().nullable(), | |
| icon: z.string().nullable(), | |
| rating: z.number(), | |
| ratingDeviation: z.number(), | |
| volatility: z.number(), | |
| winCount: z.number().int(), | |
| matchCount: z.number().int(), | |
| voteCount: z.number().int(), | |
| updatedAt: z.number().int(), | |
| }); | |
| export type AdminModel = z.infer<typeof adminModelSchema>; | |
| export const adminModelsResponseSchema = z.object({ | |
| models: z.array(adminModelSchema), | |
| }); | |
| export type AdminModelsResponse = z.infer<typeof adminModelsResponseSchema>; | |
| /** PATCH body for editing a model's display/active metadata. */ | |
| export const adminModelUpdateSchema = z.object({ | |
| name: z.string().min(1).optional(), | |
| url: z.string().optional(), | |
| icon: z.string().optional(), | |
| isActive: z.boolean().optional(), | |
| }); | |
| export type AdminModelUpdate = z.infer<typeof adminModelUpdateSchema>; | |
| /* ββ Users ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| export const adminUserRowSchema = z.object({ | |
| id: z.number().int(), | |
| username: z.string(), | |
| avatarUrl: z.string().nullable(), | |
| email: z.string().nullable(), | |
| joinDate: z.number().int(), | |
| hfAccountCreated: z.number().int().nullable(), | |
| voteCount: z.number().int(), | |
| }); | |
| export type AdminUserRow = z.infer<typeof adminUserRowSchema>; | |
| export const adminUsersResponseSchema = z.object({ | |
| rows: z.array(adminUserRowSchema), | |
| total: z.number().int(), | |
| }); | |
| export type AdminUsersResponse = z.infer<typeof adminUsersResponseSchema>; | |
| export const adminUserDetailSchema = z.object({ | |
| user: adminUserRowSchema.extend({ | |
| hfId: z.string(), | |
| trustScore: z.number(), | |
| quarantined: z.boolean(), | |
| }), | |
| /** Flagged-vote count for this user (fraud lens). */ | |
| flaggedVotes: z.number().int(), | |
| /** Votes per day (clean vs flagged), last 30d. */ | |
| votesByDay: z.array(timePointSchema), | |
| /** Distribution of which model the user picks (bias lens). */ | |
| choiceDistribution: z.array( | |
| z.object({ model: z.string(), count: z.number().int() }), | |
| ), | |
| logins: z.array( | |
| z.object({ | |
| id: z.number().int(), | |
| ip: z.string().nullable(), | |
| userAgent: z.string().nullable(), | |
| fingerprint: z.string().nullable(), | |
| createdAt: z.number().int(), | |
| }), | |
| ), | |
| votes: z.array( | |
| z.object({ | |
| id: z.number().int(), | |
| createdAt: z.number().int(), | |
| chosenModel: z.string(), | |
| rejectedModel: z.string(), | |
| flagged: z.boolean(), | |
| riskScore: z.number(), | |
| text: z.string(), | |
| }), | |
| ), | |
| }); | |
| export type AdminUserDetail = z.infer<typeof adminUserDetailSchema>; | |
| /* ββ Votes ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| export const adminVoteRowSchema = z.object({ | |
| id: z.number().int(), | |
| createdAt: z.number().int(), | |
| username: z.string(), | |
| modelType: z.string(), | |
| chosenModel: z.string(), | |
| rejectedModel: z.string(), | |
| chosenVoice: z.string().nullable(), | |
| rejectedVoice: z.string().nullable(), | |
| sentenceOrigin: z.string(), | |
| countsForPublic: z.boolean(), | |
| flagged: z.boolean(), | |
| riskScore: z.number(), | |
| text: z.string(), | |
| }); | |
| export type AdminVoteRow = z.infer<typeof adminVoteRowSchema>; | |
| export const adminVotesResponseSchema = z.object({ | |
| rows: z.array(adminVoteRowSchema), | |
| total: z.number().int(), | |
| }); | |
| export type AdminVotesResponse = z.infer<typeof adminVotesResponseSchema>; | |
| /* ββ Analytics ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| export const adminAnalyticsSchema = z.object({ | |
| sentencePool: z.object({ | |
| total: z.number().int(), | |
| consumed: z.number().int(), | |
| remaining: z.number().int(), | |
| consumptionPct: z.number(), | |
| }), | |
| votesByOrigin: z.array( | |
| z.object({ origin: z.string(), count: z.number().int() }), | |
| ), | |
| topModelsByVotes: z.array( | |
| z.object({ id: z.string(), name: z.string(), votes: z.number().int() }), | |
| ), | |
| topVoices: z.array( | |
| z.object({ | |
| modelId: z.string(), | |
| voice: z.string(), | |
| winCount: z.number().int(), | |
| matchCount: z.number().int(), | |
| }), | |
| ), | |
| }); | |
| export type AdminAnalytics = z.infer<typeof adminAnalyticsSchema>; | |
| /* ββ Model detail (drill-down) ββββββββββββββββββββββββββββββββββββββββββ */ | |
| export const adminModelDetailSchema = z.object({ | |
| model: adminModelSchema, | |
| rank: z.number().int(), | |
| flaggedVotes: z.number().int(), | |
| /** Rating + RD over time, one point per recorded match. */ | |
| ratingHistory: z.array( | |
| z.object({ | |
| t: z.number().int(), | |
| rating: z.number(), | |
| rd: z.number(), | |
| }), | |
| ), | |
| /** Votes per day where this model appeared (clean vs flagged). */ | |
| votesByDay: z.array(timePointSchema), | |
| /** Win/loss vs each opponent (top by total). */ | |
| vsOpponents: z.array( | |
| z.object({ | |
| opponent: z.string(), | |
| wins: z.number().int(), | |
| losses: z.number().int(), | |
| winRate: z.number(), | |
| }), | |
| ), | |
| /** Top voters for this model + their flagged share (fraud lens). */ | |
| topVoters: z.array( | |
| z.object({ | |
| userId: z.number().int(), | |
| username: z.string(), | |
| /** Times this user picked the model (wins for the model). */ | |
| votes: z.number().int(), | |
| flagged: z.number().int(), | |
| /** Total battles this user had with the model (wins + losses). */ | |
| battles: z.number().int(), | |
| /** Share (0β100) of those battles where they picked the model. */ | |
| preferPct: z.number(), | |
| /** Anomaly of their preference vs the model's global pick rate, in | |
| * standard deviations. High = this user favors the model far more than | |
| * the crowd (a manipulation signal). */ | |
| anomalyZ: z.number(), | |
| quarantined: z.boolean(), | |
| }), | |
| ), | |
| recentVotes: z.array(adminVoteRowSchema), | |
| }); | |
| export type AdminModelDetail = z.infer<typeof adminModelDetailSchema>; | |
| /* ββ Security βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| export const adminSecurityEventSchema = z.object({ | |
| id: z.number().int(), | |
| createdAt: z.number().int(), | |
| kind: z.string(), | |
| severity: z.string(), | |
| userId: z.number().int().nullable(), | |
| username: z.string().nullable(), | |
| ip: z.string().nullable(), | |
| fingerprint: z.string().nullable(), | |
| voteId: z.number().int().nullable(), | |
| detail: z.string().nullable(), | |
| }); | |
| export type AdminSecurityEvent = z.infer<typeof adminSecurityEventSchema>; | |
| export const adminSecurityOverviewSchema = z.object({ | |
| flaggedVotes: z.number().int(), | |
| totalVotes: z.number().int(), | |
| quarantinedUsers: z.number().int(), | |
| eventsBySeverity: z.array( | |
| z.object({ severity: z.string(), count: z.number().int() }), | |
| ), | |
| topRiskyIps: z.array( | |
| z.object({ | |
| ip: z.string(), | |
| accounts: z.number().int(), | |
| events: z.number().int(), | |
| }), | |
| ), | |
| recentEvents: z.array(adminSecurityEventSchema), | |
| quarantined: z.array( | |
| z.object({ | |
| id: z.number().int(), | |
| username: z.string(), | |
| trustScore: z.number(), | |
| }), | |
| ), | |
| /** Model-centric manipulation alert: models with a *cluster* of accounts | |
| * whose preference is anomalously high vs the crowd. One anomalous account | |
| * is usually a superfan; several converging on one model β especially | |
| * sharing IPs β is a vote ring. */ | |
| suspiciousModels: z.array( | |
| z.object({ | |
| modelId: z.string(), | |
| modelName: z.string(), | |
| /** Number of distinct accounts with anomalous preference for this model. */ | |
| anomalousAccounts: z.number().int(), | |
| /** How many of those accounts share an IP with another flagged account | |
| * (the coordination signal that separates a ring from lone superfans). */ | |
| sharedIpAccounts: z.number().int(), | |
| /** Highest per-account anomaly (standard deviations). */ | |
| maxAnomalyZ: z.number(), | |
| /** Total picks from these accounts β votes potentially inflating the rating. */ | |
| inflatedVotes: z.number().int(), | |
| accounts: z.array( | |
| z.object({ | |
| userId: z.number().int(), | |
| username: z.string(), | |
| picks: z.number().int(), | |
| battles: z.number().int(), | |
| preferPct: z.number(), | |
| anomalyZ: z.number(), | |
| quarantined: z.boolean(), | |
| }), | |
| ), | |
| }), | |
| ), | |
| }); | |
| export type AdminSecurityOverview = z.infer<typeof adminSecurityOverviewSchema>; | |
| /* ββ IP lookup ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */ | |
| export const adminIpLookupSchema = z.object({ | |
| ip: z.string(), | |
| accounts: z.array( | |
| z.object({ | |
| userId: z.number().int(), | |
| username: z.string(), | |
| joinDate: z.number().int().nullable(), | |
| trustScore: z.number(), | |
| quarantined: z.boolean(), | |
| logins: z.number().int(), | |
| totalVotes: z.number().int(), | |
| lastSeen: z.number().int().nullable(), | |
| /** Other IPs this account has logged in from (pivot for wider rings). */ | |
| otherIps: z.array(z.string()), | |
| }), | |
| ), | |
| }); | |
| export type AdminIpLookup = z.infer<typeof adminIpLookupSchema>; | |
| export const adminSecurityEventsResponseSchema = z.object({ | |
| rows: z.array(adminSecurityEventSchema), | |
| total: z.number().int(), | |
| }); | |
| export type AdminSecurityEventsResponse = z.infer< | |
| typeof adminSecurityEventsResponseSchema | |
| >; | |
| /* ββ Errors (observability) βββββββββββββββββββββββββββββββββββββββββββββ */ | |
| export const adminErrorRowSchema = z.object({ | |
| id: z.number().int(), | |
| createdAt: z.number().int(), | |
| source: z.string(), | |
| severity: z.string(), | |
| message: z.string(), | |
| stack: z.string().nullable(), | |
| route: z.string().nullable(), | |
| method: z.string().nullable(), | |
| provider: z.string().nullable(), | |
| model: z.string().nullable(), | |
| status: z.number().int().nullable(), | |
| userId: z.number().int().nullable(), | |
| detail: z.string().nullable(), | |
| }); | |
| export type AdminErrorRow = z.infer<typeof adminErrorRowSchema>; | |
| export const adminErrorsResponseSchema = z.object({ | |
| rows: z.array(adminErrorRowSchema), | |
| total: z.number().int(), | |
| }); | |
| export type AdminErrorsResponse = z.infer<typeof adminErrorsResponseSchema>; | |
| /** One day of error counts, split by source (for the stacked trend chart). */ | |
| export const adminErrorDaySchema = z.object({ | |
| date: z.string(), | |
| /** Total across all sources for the day. */ | |
| count: z.number().int(), | |
| /** Per-source counts; keys are source names present that day. */ | |
| bySource: z.record(z.string(), z.number().int()), | |
| }); | |
| export type AdminErrorDay = z.infer<typeof adminErrorDaySchema>; | |
| export const adminErrorOverviewSchema = z.object({ | |
| last24h: z.number().int(), | |
| last7d: z.number().int(), | |
| total: z.number().int(), | |
| distinctSources: z.number().int(), | |
| /** Highest-volume failing model in the last 7d (null if none). */ | |
| topFailingModel: z | |
| .object({ model: z.string(), count: z.number().int() }) | |
| .nullable(), | |
| /** Source names that appear in errorsByDay (chart series + legend). */ | |
| sources: z.array(z.string()), | |
| /** Errors per day for the last 30d, oldest first, stacked by source. */ | |
| errorsByDay: z.array(adminErrorDaySchema), | |
| /** Failures grouped by source, last 7d. */ | |
| bySource: z.array(z.object({ source: z.string(), count: z.number().int() })), | |
| /** Failures grouped by model, last 7d (top by count). */ | |
| byModel: z.array(z.object({ model: z.string(), count: z.number().int() })), | |
| /** Failures grouped by provider, last 7d. */ | |
| byProvider: z.array( | |
| z.object({ provider: z.string(), count: z.number().int() }), | |
| ), | |
| recent: z.array(adminErrorRowSchema), | |
| }); | |
| export type AdminErrorOverview = z.infer<typeof adminErrorOverviewSchema>; | |
| /* ββ Generations (latency / throughput observability) βββββββββββββββββββ */ | |
| /** Per-model latency + reliability summary over a window. */ | |
| export const adminGenModelStatSchema = z.object({ | |
| model: z.string(), | |
| provider: z.string(), | |
| total: z.number().int(), | |
| failures: z.number().int(), | |
| successRate: z.number(), // 0..100 | |
| p50: z.number().int(), // ms | |
| p95: z.number().int(), // ms | |
| avg: z.number().int(), // ms | |
| }); | |
| export type AdminGenModelStat = z.infer<typeof adminGenModelStatSchema>; | |
| /** One day of generation throughput + latency. */ | |
| export const adminGenDaySchema = z.object({ | |
| date: z.string(), | |
| total: z.number().int(), | |
| failures: z.number().int(), | |
| /** Median latency that day (ms). */ | |
| p50: z.number().int(), | |
| /** 95th-percentile latency that day (ms). */ | |
| p95: z.number().int(), | |
| }); | |
| export type AdminGenDay = z.infer<typeof adminGenDaySchema>; | |
| export const adminGenerationRowSchema = z.object({ | |
| id: z.number().int(), | |
| createdAt: z.number().int(), | |
| provider: z.string(), | |
| model: z.string(), | |
| routerModel: z.string().nullable(), | |
| durationMs: z.number().int(), | |
| success: z.boolean(), | |
| audioBytes: z.number().int(), | |
| textLength: z.number().int().nullable(), | |
| status: z.number().int().nullable(), | |
| error: z.string().nullable(), | |
| userId: z.number().int().nullable(), | |
| }); | |
| export type AdminGenerationRow = z.infer<typeof adminGenerationRowSchema>; | |
| export const adminGenerationsResponseSchema = z.object({ | |
| rows: z.array(adminGenerationRowSchema), | |
| total: z.number().int(), | |
| }); | |
| export type AdminGenerationsResponse = z.infer< | |
| typeof adminGenerationsResponseSchema | |
| >; | |
| export const adminGenerationOverviewSchema = z.object({ | |
| last24h: z.number().int(), | |
| last7d: z.number().int(), | |
| /** Overall success rate over the last 7d (0..100). */ | |
| successRate7d: z.number(), | |
| /** Overall P50 / P95 latency over the last 7d (ms). */ | |
| p50: z.number().int(), | |
| p95: z.number().int(), | |
| /** Throughput + latency per day for the last 30d, oldest first. */ | |
| byDay: z.array(adminGenDaySchema), | |
| /** Per-model latency + reliability over the last 7d (sorted slowest first). */ | |
| byModel: z.array(adminGenModelStatSchema), | |
| /** Recent failed generations. */ | |
| recentFailures: z.array(adminGenerationRowSchema), | |
| }); | |
| export type AdminGenerationOverview = z.infer< | |
| typeof adminGenerationOverviewSchema | |
| >; | |
| /* ββ Test runs ("Test All") βββββββββββββββββββββββββββββββββββββββββββββ */ | |
| export const adminTestRunSchema = z.object({ | |
| id: z.number().int(), | |
| status: z.string(), // running | done | interrupted | |
| sentence: z.string(), | |
| total: z.number().int(), | |
| completed: z.number().int(), | |
| passed: z.number().int(), | |
| failed: z.number().int(), | |
| startedBy: z.string().nullable(), | |
| createdAt: z.number().int(), | |
| finishedAt: z.number().int().nullable(), | |
| }); | |
| export type AdminTestRun = z.infer<typeof adminTestRunSchema>; | |
| export const adminTestRunsResponseSchema = z.object({ | |
| rows: z.array(adminTestRunSchema), | |
| total: z.number().int(), | |
| }); | |
| export type AdminTestRunsResponse = z.infer<typeof adminTestRunsResponseSchema>; | |
| export const adminTestResultSchema = z.object({ | |
| id: z.number().int(), | |
| model: z.string(), | |
| modelName: z.string(), | |
| provider: z.string().nullable(), | |
| status: z.string(), // pending | running | pass | fail | |
| durationMs: z.number().int().nullable(), | |
| /** Audio URL when a sample was produced (served by the test audio route). */ | |
| audioUrl: z.string().nullable(), | |
| error: z.string().nullable(), | |
| }); | |
| export type AdminTestResult = z.infer<typeof adminTestResultSchema>; | |
| export const adminTestRunDetailSchema = z.object({ | |
| run: adminTestRunSchema, | |
| results: z.array(adminTestResultSchema), | |
| }); | |
| export type AdminTestRunDetail = z.infer<typeof adminTestRunDetailSchema>; | |