Skip to content

Commit

Permalink
ok
Browse files Browse the repository at this point in the history
  • Loading branch information
hughcrt committed Jan 11, 2025
1 parent 32974c7 commit 37787e0
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 72 deletions.
42 changes: 21 additions & 21 deletions packages/backend/src/api/v1/analytics/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { checkAccess } from "@/src/utils/authorization";
import sql from "@/src/utils/db";
import Context from "@/src/utils/koa";
import Router from "koa-router";
Expand All @@ -14,6 +13,7 @@ analytics.get("/tokens", async (ctx: Context) => {
const { projectId } = ctx.state;
const { datesQuery, filteredRunsQuery, granularity } = parseQuery(
projectId,
ctx.querystring,
ctx.query,
);

Expand Down Expand Up @@ -79,6 +79,7 @@ analytics.get("/costs", async (ctx: Context) => {
const { projectId } = ctx.state;
const { datesQuery, filteredRunsQuery, granularity } = parseQuery(
projectId,
ctx.querystring,
ctx.query,
);

Expand Down Expand Up @@ -144,6 +145,7 @@ analytics.get("/errors", async (ctx: Context) => {
const { projectId } = ctx.state;
const { datesQuery, filteredRunsQuery, granularity } = parseQuery(
projectId,
ctx.querystring,
ctx.query,
);

Expand Down Expand Up @@ -216,7 +218,7 @@ analytics.get("/users/new", async (ctx: Context) => {
startDate,
endDate,
filteredRunsQuery,
} = parseQuery(projectId, ctx.query);
} = parseQuery(projectId, ctx.querystring, ctx.query);

const distinctMap = {
hourly: sql`distinct on (r.external_user_id, date_trunc('hour', r.created_at at time zone ${timeZone})::timestamp)`,
Expand Down Expand Up @@ -539,7 +541,7 @@ analytics.get("/users/active", async (ctx: Context) => {
startDate,
endDate,
filteredRunsQuery,
} = parseQuery(projectId, ctx.query);
} = parseQuery(projectId, ctx.querystring, ctx.query);

const distinctMap = {
hourly: sql`distinct on (r.external_user_id, date_trunc('hour', r.created_at at time zone ${timeZone})::timestamp)`,
Expand Down Expand Up @@ -776,7 +778,7 @@ analytics.get("/users/average-cost", async (ctx: Context) => {
localCreatedAt,
startDate,
endDate,
} = parseQuery(projectId, ctx.query);
} = parseQuery(projectId, ctx.querystring, ctx.query);

const [{ stat }] = await sql`
with total_costs as (
Expand Down Expand Up @@ -888,6 +890,7 @@ analytics.get("/run-types", async (ctx: Context) => {
const { projectId } = ctx.state;
const { datesQuery, filteredRunsQuery, granularity } = parseQuery(
projectId,
ctx.querystring,
ctx.query,
);

Expand Down Expand Up @@ -959,7 +962,7 @@ analytics.get("/latency", async (ctx: Context) => {
startDate,
endDate,
timeZone,
} = parseQuery(projectId, ctx.query);
} = parseQuery(projectId, ctx.querystring, ctx.query);

const [{ stat }] = await sql`
select
Expand Down Expand Up @@ -1032,6 +1035,7 @@ analytics.get("/feedback-ratio", async (ctx: Context) => {
const { projectId } = ctx.state;
const { datesQuery, filteredRunsQuery, granularity } = parseQuery(
projectId,
ctx.querystring,
ctx.query,
);

Expand Down Expand Up @@ -1130,9 +1134,12 @@ analytics.get("/models/top", async (ctx: Context) => {
checks: z.string().optional(),
});
const { projectId } = ctx.state;
const { startDate, endDate, timeZone, userId, name, checks } =
querySchema.parse(ctx.request.query);
const filtersQuery = buildFiltersQuery(checks || "");
const { startDate, endDate, timeZone, userId, name } = querySchema.parse(
ctx.request.query,
);

const deserializedChecks = deserializeLogic(ctx.querystring);
const filtersQuery = buildFiltersQuery(deserializedChecks);

let dateFilter = sql``;
if (startDate && endDate && timeZone) {
Expand Down Expand Up @@ -1191,7 +1198,8 @@ analytics.get("/templates/top", async (ctx: Context) => {
const { startDate, endDate, timeZone, checks } = querySchema.parse(
ctx.request.query,
);
const filtersQuery = buildFiltersQuery(checks || "");
const deserializedChecks = deserializeLogic(ctx.querystring);
const filtersQuery = buildFiltersQuery(deserializedChecks);

const topTemplates = await sql`
select
Expand Down Expand Up @@ -1223,22 +1231,13 @@ analytics.get("/templates/top", async (ctx: Context) => {

analytics.get("/languages/top", async (ctx: Context) => {
const { projectId } = ctx.state;
ctx.query.granularity = "daily";
const { datesQuery, startDate, endDate, timeZone, filteredRunsQuery } =
parseQuery(projectId, ctx.query);
parseQuery(projectId, ctx.querystring, ctx.query);

const data = await sql`
with dates as (
select
*
from (
select generate_series(
${startDate} at time zone ${timeZone},
${endDate} at time zone ${timeZone},
'1 day'::interval
)::timestamp as date) t
where
date <=current_timestamp at time zone ${timeZone}
${datesQuery}
),
filtered_runs as (
${filteredRunsQuery}
Expand Down Expand Up @@ -1274,6 +1273,7 @@ analytics.get("/custom-events", async (ctx: Context) => {
const { projectId } = ctx.state;
const { startDate, endDate, timeZone, filteredRunsQuery } = parseQuery(
projectId,
ctx.querystring,
ctx.query,
);

Expand Down
12 changes: 6 additions & 6 deletions packages/backend/src/api/v1/analytics/utils.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { convertChecksToSQL } from "@/src/utils/checks";
import sql from "@/src/utils/db";
import Context from "@/src/utils/koa";
import { deserializeLogic } from "shared";
import { deserializeLogic, LogicNode } from "shared";
import { z } from "zod";

export function buildFiltersQuery(checks: string) {
const deserializedChecks = deserializeLogic(checks);
export function buildFiltersQuery(deserializedChecks: LogicNode) {
return deserializedChecks?.length && deserializedChecks.length > 1
? convertChecksToSQL(deserializedChecks)
: sql`1 = 1`;
}

export function parseQuery(projectId: string, query: unknown) {
export function parseQuery(projectId: string, queryString: string, query: any) {
const deserializedChecks = deserializeLogic(queryString);
const filtersQuery = buildFiltersQuery(deserializedChecks);

return z
.object({
startDate: z.string().datetime(),
Expand All @@ -26,7 +27,6 @@ export function parseQuery(projectId: string, query: unknown) {
checks: z.string().optional(),
})
.transform(({ startDate, endDate, timeZone, granularity, checks }) => {
const filtersQuery = buildFiltersQuery(checks || "");
const granularityToIntervalMap = {
hourly: "1 hour",
daily: "1 day",
Expand Down
10 changes: 6 additions & 4 deletions packages/backend/src/api/v1/external-users.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { checkAccess } from "@/src/utils/authorization";
import sql from "@/src/utils/db";
import Router from "koa-router";
import { Context } from "koa";
import { checkAccess } from "@/src/utils/authorization";
import Router from "koa-router";
import { deserializeLogic } from "shared";
import { z } from "zod";
import { buildFiltersQuery } from "./analytics/utils";

Expand Down Expand Up @@ -112,6 +113,9 @@ users.get(
checks,
} = querySchema.parse(ctx.request.query);

const deserializedChecks = deserializeLogic(ctx.querystring);
const filtersQuery = buildFiltersQuery(deserializedChecks);

let searchQuery = sql``;
if (search) {
searchQuery = sql`and (
Expand All @@ -129,8 +133,6 @@ users.get(
`;
}

const filtersQuery = buildFiltersQuery(checks || "");

const sortMapping = {
createdAt: "eu.created_at",
lastSeen: "eu.last_seen",
Expand Down
81 changes: 46 additions & 35 deletions packages/frontend/pages/users/[[...id]].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ import LineChart from "@/components/analytics/OldLineChart";
import Link from "next/link";
import { parseAsString, useQueryState } from "nuqs";
import { deserializeLogic, getDefaultDateRange } from "shared";
import ChartComponent from "@/components/analytics/Charts/ChartComponent";
import AnalyticsCard from "@/components/analytics/AnalyticsCard";

const columns = [
{
Expand Down Expand Up @@ -132,13 +134,7 @@ function SelectedUser({ id, onClose }) {
});
}

const [dateRange, setDateRange] = useLocalStorage({
key: "dateRange-analytics",
getInitialValueInEffect: false,
deserialize: deserializeDateRange,
defaultValue: getDefaultDateRange(),
});
const [startDate, endDate] = dateRange;
const [startDate, endDate] = getDefaultDateRange(90);

const [granularity] = useState("daily");

Expand All @@ -151,15 +147,6 @@ function SelectedUser({ id, onClose }) {
deserializeLogic(`users=${id}`),
);

const { data: runCountData, isLoading: runCountLoading } =
useAnalyticsChartData(
id && "run-types",
startDate,
endDate,
granularity,
deserializeLogic(`users=${id}`),
);

const commonChartData: {
startDate: Date;
endDate: Date;
Expand Down Expand Up @@ -250,33 +237,57 @@ function SelectedUser({ id, onClose }) {
</Stack>

<Box w={"100%"}>
<LineChart
data={runCountData?.data?.filter((d) => d.type === "chat")}
loading={runCountLoading}
props={["runs"]}
splitBy="type"
agg="sum"
<AnalyticsCard
title="Chat Messages"
description="Number of chat messages sent by the user"
{...commonChartData}
/>
>
<ChartComponent
dataKey="run-types"
startDate={startDate}
endDate={endDate}
granularity={"daily"}
checks={[
"AND",
{ id: "users", params: { users: id } },
{ id: "type", params: { type: "chat" } },
]}
aggregationMethod="sum"
isCustom={false}
/>
</AnalyticsCard>
</Box>
<Box w={"100%"}>
<LineChart
data={tokensData?.data}
loading={tokensDataLoading}
splitBy="name"
props={["tokens"]}
agg="sum"
<AnalyticsCard
title="Tokens"
description="Number of tokens generated by the user's LLM calls"
{...commonChartData}
/>
>
<ChartComponent
dataKey="tokens"
startDate={startDate}
endDate={endDate}
granularity={"daily"}
checks={["AND", { id: "users", params: { users: id } }]}
aggregationMethod="sum"
isCustom={false}
/>
</AnalyticsCard>
</Box>

{topModels && (
<TopModels data={topModels} isLoading={topModelsLoading} />
)}
<Box w={"100%"}>
<AnalyticsCard
title="Top Models"
description="The top models used by the user"
>
<ChartComponent
dataKey="models/top"
startDate={startDate}
endDate={endDate}
granularity={"daily"}
checks={["AND", { id: "users", params: { users: id } }]}
isCustom={false}
/>
</AnalyticsCard>
</Box>
<Button
leftSection={<IconTrash size={14} />}
size="xs"
Expand Down
5 changes: 3 additions & 2 deletions packages/frontend/utils/dataHooks/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ export function useAnalyticsChartData<T>(
secondDimensionKey: string | null = null,
) {
const timeZone = new window.Intl.DateTimeFormat().resolvedOptions().timeZone;
const checksParam = checks ? `&checks=${serializeLogic(checks)}` : "";

const checksParam = checks ? `${serializeLogic(checks)}` : "";
const firstDimensionParam = firstDimensionKey
? `&firstDimension=${firstDimensionKey}`
: "";
Expand All @@ -30,7 +31,7 @@ export function useAnalyticsChartData<T>(

const { data, isLoading, error } = useProjectSWR<T[]>(
key
? `${getPrefix(key)}?startDate=${startDate.toISOString()}&endDate=${endDate.toISOString()}&timeZone=${timeZone}&granularity=${granularity}${checksParam}${firstDimensionParam}${secondDimensionParam}`
? `${getPrefix(key)}?${checksParam}&startDate=${startDate.toISOString()}&endDate=${endDate.toISOString()}&timeZone=${timeZone}&granularity=${granularity}${firstDimensionParam}${secondDimensionParam}`
: undefined,
);

Expand Down
8 changes: 4 additions & 4 deletions packages/shared/dashboards/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { LogicNode } from "../checks";

export function getDefaultDateRange() {
export function getDefaultDateRange(
nbDaysFromToday: number = 30,
): [Date, Date] {
const endOfToday = new Date();
endOfToday.setHours(23, 59, 59, 999);

const oneWeekAgoDate = new Date(endOfToday);
oneWeekAgoDate.setDate(oneWeekAgoDate.getDate() - 30);
oneWeekAgoDate.setDate(oneWeekAgoDate.getDate() - nbDaysFromToday);
oneWeekAgoDate.setHours(0, 0, 0, 0);
const defaultRange: [Date, Date] = [oneWeekAgoDate, endOfToday];
return defaultRange;
Expand Down

0 comments on commit 37787e0

Please sign in to comment.