Add basic dashboard to homepage

This commit is contained in:
David Corbitt
2023-08-08 11:18:35 -07:00
parent 6f8db40f74
commit a1249f17c9
7 changed files with 789 additions and 19 deletions

View File

@@ -10,6 +10,7 @@ import { datasetsRouter } from "./routers/datasets.router";
import { datasetEntries } from "./routers/datasetEntries.router";
import { externalApiRouter } from "./routers/externalApi.router";
import { organizationsRouter } from "./routers/organizations.router";
import { dashboardRouter } from "./routers/dashboard.router";
/**
* This is the primary router for your server.
@@ -27,6 +28,7 @@ export const appRouter = createTRPCRouter({
datasets: datasetsRouter,
datasetEntries: datasetEntries,
organizations: organizationsRouter,
dashboard: dashboardRouter,
externalApi: externalApiRouter,
});

View File

@@ -0,0 +1,95 @@
import { sql } from "kysely";
import { z } from "zod";
import { createTRPCRouter, publicProcedure } from "~/server/api/trpc";
import { kysely, prisma } from "~/server/db";
export const dashboardRouter = createTRPCRouter({
stats: publicProcedure
.input(
z.object({
startDate: z.string().optional(),
organizationId: z.string(),
}),
)
.query(async ({ input }) => {
console.log("made it 1");
// Return the stats group by hour
const periods = await kysely
.selectFrom("LoggedCall")
.leftJoin(
"LoggedCallModelResponse",
"LoggedCall.id",
"LoggedCallModelResponse.originalLoggedCallId",
)
.where("organizationId", "=", input.organizationId)
.select(({ fn }) => [
sql<Date>`date_trunc('day', "LoggedCallModelResponse"."startTime")`.as("period"),
sql<number>`count("LoggedCall"."id")::int`.as("numQueries"),
fn.sum(fn.coalesce('LoggedCallModelResponse.totalCost', sql<number>`0`)).as("totalCost"),
])
.groupBy("period")
.orderBy("period")
.execute();
console.log("made it 2");
const totals = await kysely
.selectFrom("LoggedCall")
.where("organizationId", "=", input.organizationId)
.leftJoin(
"LoggedCallModelResponse",
"LoggedCall.id",
"LoggedCallModelResponse.originalLoggedCallId",
)
.select(({ fn }) => [
fn.sum(fn.coalesce('LoggedCallModelResponse.totalCost', sql<number>`0`)).as("totalCost"),
fn.count("id").as("numQueries"),
])
.executeTakeFirst();
console.log("made it 3");
const errors = await kysely
.selectFrom("LoggedCall")
.where("organizationId", "=", input.organizationId)
.leftJoin(
"LoggedCallModelResponse",
"LoggedCall.id",
"LoggedCallModelResponse.originalLoggedCallId",
)
.select(({ fn }) => [fn.count("id").as("count"), "respStatus as code"])
.where("respStatus", ">", 200)
.groupBy("code")
.orderBy("count", "desc")
.execute();
console.log("made it 4");
const namedErrors = errors.map((e) => {
if (e.code === 429) {
return { ...e, name: "Rate limited" };
} else if (e.code === 500) {
return { ...e, name: "Internal server error" };
} else {
return { ...e, name: "Other" };
}
});
console.log("data is", { periods, totals, errors: namedErrors });
return { periods, totals, errors: namedErrors };
// const resp = await kysely.selectFrom("LoggedCall").selectAll().execute();
}),
// TODO useInfiniteQuery
// https://discord.com/channels/966627436387266600/1122258443886153758/1122258443886153758
loggedCalls: publicProcedure.input(z.object({})).query(async ({ input }) => {
const loggedCalls = await prisma.loggedCall.findMany({
orderBy: { startTime: "desc" },
include: { tags: true, modelResponse: true },
take: 20,
});
return loggedCalls;
}),
});

View File

@@ -1,6 +1,56 @@
import { PrismaClient } from "@prisma/client";
import {
type Experiment,
type PromptVariant,
type TestScenario,
type TemplateVariable,
type ScenarioVariantCell,
type ModelResponse,
type Evaluation,
type OutputEvaluation,
type Dataset,
type DatasetEntry,
type Organization,
type OrganizationUser,
type WorldChampEntrant,
type LoggedCall,
type LoggedCallModelResponse,
type LoggedCallTag,
type ApiKey,
type Account,
type Session,
type User,
type VerificationToken,
PrismaClient,
} from "@prisma/client";
import { Kysely, PostgresDialect } from "kysely";
import { Pool } from "pg";
import { env } from "~/env.mjs";
interface DB {
Experiment: Experiment;
PromptVariant: PromptVariant;
TestScenario: TestScenario;
TemplateVariable: TemplateVariable;
ScenarioVariantCell: ScenarioVariantCell;
ModelResponse: ModelResponse;
Evaluation: Evaluation;
OutputEvaluation: OutputEvaluation;
Dataset: Dataset;
DatasetEntry: DatasetEntry;
Organization: Organization;
OrganizationUser: OrganizationUser;
WorldChampEntrant: WorldChampEntrant;
LoggedCall: LoggedCall;
LoggedCallModelResponse: LoggedCallModelResponse;
LoggedCallTag: LoggedCallTag;
ApiKey: ApiKey;
Account: Account;
Session: Session;
User: User;
VerificationToken: VerificationToken;
}
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined;
};
@@ -14,4 +64,12 @@ export const prisma =
: ["error"],
});
export const kysely = new Kysely<DB>({
dialect: new PostgresDialect({
pool: new Pool({
connectionString: env.DATABASE_URL,
}),
}),
});
if (env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;