82 lines
3.1 KiB
TypeScript
82 lines
3.1 KiB
TypeScript
import { type LoaderFunctionArgs } from "@remix-run/server-runtime";
|
|
import { json } from "@remix-run/node";
|
|
import { z } from "zod";
|
|
import { requireUserId } from "~/services/session.server";
|
|
import { EnvironmentParamSchema } from "~/utils/pathBuilder";
|
|
import { parsePeriodToMs } from "~/utils/periods";
|
|
import { findProjectBySlug } from "~/models/project.server";
|
|
import { findEnvironmentBySlug } from "~/models/runtimeEnvironment.server";
|
|
import { clickhouseFactory } from "~/services/clickhouse/clickhouseFactoryInstance.server";
|
|
import {
|
|
PromptPresenter,
|
|
type GenerationRow,
|
|
type GenerationsPagination,
|
|
} from "~/presenters/v3/PromptPresenter.server";
|
|
|
|
export type { GenerationRow, GenerationsPagination };
|
|
|
|
export type GenerationsResponse = {
|
|
generations: GenerationRow[];
|
|
pagination: GenerationsPagination;
|
|
};
|
|
|
|
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
|
|
const userId = await requireUserId(request);
|
|
const { projectParam, organizationSlug, envParam, promptSlug } = EnvironmentParamSchema.extend({
|
|
promptSlug: z.string(),
|
|
}).parse(params);
|
|
|
|
const project = await findProjectBySlug(organizationSlug, projectParam, userId);
|
|
if (!project) throw new Response("Project not found", { status: 404 });
|
|
|
|
const environment = await findEnvironmentBySlug(project.id, envParam, userId);
|
|
if (!environment) throw new Response("Environment not found", { status: 404 });
|
|
|
|
const url = new URL(request.url);
|
|
|
|
const versions = url.searchParams
|
|
.getAll("versions")
|
|
.map(Number)
|
|
.filter((n) => Number.isInteger(n) && n > 0);
|
|
|
|
const period = url.searchParams.get("period") ?? "7d";
|
|
if (!/^\d+[mhdw]$/.test(period)) {
|
|
return json({ generations: [], pagination: {} } satisfies GenerationsResponse);
|
|
}
|
|
|
|
const fromTime = url.searchParams.get("from");
|
|
const toTime = url.searchParams.get("to");
|
|
const cursorParam = url.searchParams.get("cursor") ?? undefined;
|
|
|
|
const periodMs = parsePeriodToMs(period);
|
|
const startTime = fromTime ? new Date(fromTime) : new Date(Date.now() - periodMs);
|
|
const endTime = toTime ? new Date(toTime) : new Date();
|
|
|
|
if (isNaN(startTime.getTime()) || isNaN(endTime.getTime())) {
|
|
return json({ generations: [], pagination: {} } satisfies GenerationsResponse);
|
|
}
|
|
|
|
const models = url.searchParams.getAll("models").filter(Boolean);
|
|
const operations = url.searchParams.getAll("operations").filter(Boolean);
|
|
const providers = url.searchParams.getAll("providers").filter(Boolean);
|
|
|
|
const clickhouse = await clickhouseFactory.getClickhouseForOrganization(
|
|
project.organizationId,
|
|
"standard"
|
|
);
|
|
const presenter = new PromptPresenter(clickhouse);
|
|
const result = await presenter.listGenerations({
|
|
environmentId: environment.id,
|
|
promptSlug,
|
|
promptVersions: versions.length > 0 ? versions : undefined,
|
|
startTime,
|
|
endTime,
|
|
cursor: cursorParam,
|
|
responseModels: models.length > 0 ? models : undefined,
|
|
operations: operations.length > 0 ? operations : undefined,
|
|
providers: providers.length > 0 ? providers : undefined,
|
|
});
|
|
|
|
return json(result satisfies GenerationsResponse);
|
|
};
|