From 1abcb459d842418bcc9a761110e84a0d8562e93d Mon Sep 17 00:00:00 2001 From: Matt Pocock Date: Tue, 10 Dec 2024 11:08:43 +0000 Subject: [PATCH] Began adding historical data back in --- .../app/components/ui/line-chart.tsx | 22 +- .../app/components/ui/live-date.tsx | 15 ++ apps/evalite-ui/app/routes/eval.$name.tsx | 189 ++++++++++-------- packages/evalite-core/src/db.ts | 19 ++ packages/evalite-core/src/server.ts | 11 +- 5 files changed, 166 insertions(+), 90 deletions(-) create mode 100644 apps/evalite-ui/app/components/ui/live-date.tsx diff --git a/apps/evalite-ui/app/components/ui/line-chart.tsx b/apps/evalite-ui/app/components/ui/line-chart.tsx index a27e8da..7cf63ba 100644 --- a/apps/evalite-ui/app/components/ui/line-chart.tsx +++ b/apps/evalite-ui/app/components/ui/line-chart.tsx @@ -1,5 +1,6 @@ "use client"; +import { formatDistance } from "date-fns"; import { Area, AreaChart, XAxis } from "recharts"; import { @@ -8,6 +9,7 @@ import { ChartTooltip, ChartTooltipContent, } from "~/components/ui/chart"; +import { LiveDate } from "./live-date"; const chartConfig = { score: { @@ -16,13 +18,21 @@ const chartConfig = { }, } satisfies ChartConfig; -export function MyLineChart(props: { data: { score: number }[] }) { +export function MyLineChart(props: { + data: { date: string; score: number }[]; +}) { return ( - + ({ + ...s, + score: Math.round(s.score * 100), + }))} + > } + content={ + } + /> + } /> { + const [, setNow] = useState(new Date()); + useEffect(() => { + const interval = setInterval(() => { + setNow(new Date()); + }, 1000); + return () => clearInterval(interval); + }, []); + return ( + {formatDistance(props.date, new Date(), { addSuffix: true })} + ); +}; diff --git a/apps/evalite-ui/app/routes/eval.$name.tsx b/apps/evalite-ui/app/routes/eval.$name.tsx index 9a6f05a..238516b 100644 --- a/apps/evalite-ui/app/routes/eval.$name.tsx +++ b/apps/evalite-ui/app/routes/eval.$name.tsx @@ -11,6 +11,8 @@ import React, { useContext } from "react"; import { DisplayInput } from "~/components/display-input"; import { InnerPageLayout } from "~/components/page-layout"; import { getScoreState, Score } from "~/components/score"; +import { MyLineChart } from "~/components/ui/line-chart"; +import { Separator } from "~/components/ui/separator"; import { Table, TableBody, @@ -58,7 +60,6 @@ export default function Page() { vscodeUrl={`vscode://file${evaluation.filepath}`} filepath={evaluation.filepath.split(/(\/|\\)/).slice(-1)[0]!} > - {/* {history.length > 1 && } */} {evaluation.status === "fail" && (
@@ -74,97 +75,115 @@ export default function Page() {
)} {evaluation.status === "success" && ( - - - - Input - Output - {showExpectedColumn && Expected} - {firstResult?.scores.map((scorer, index) => ( - - {scorer.name} - - ))} - - - - {evaluation.results.map((result, index) => { - const Wrapper = (props: { children: React.ReactNode }) => ( - { - return cn("block h-full p-4", isActive && "active"); - }} - > - {props.children} - - ); - return ( - - - - {showExpectedColumn && ( +
+ {history.length > 1 && ( + <> +

+ History +

+ {history.length > 1 && } + +

+ Results +

+ + )} +
- - - -
+ + + Input + Output + {showExpectedColumn && Expected} + {firstResult?.scores.map((scorer, index) => ( + + {scorer.name} + + ))} + + + + {evaluation.results.map((result, index) => { + const Wrapper = (props: { children: React.ReactNode }) => ( + { + return cn("block h-full p-4", isActive && "active"); + }} + > + {props.children} + + ); + return ( + - )} - {result.scores.map((scorer, index) => { - const scoreInPreviousEvaluation = prevEvaluation?.results - .find((r) => r.input === result.input) - ?.scores.find((s) => s.name === scorer.name); - return ( - + {showExpectedColumn && ( + - ); - })} - - ); - })} - -
- - - + + + +
+ )} + {result.scores.map((scorer, index) => { + const scoreInPreviousEvaluation = + prevEvaluation?.results + .find((r) => r.input === result.input) + ?.scores.find((s) => s.name === scorer.name); + return ( + + + + + + ); + })} + + ); + })} + + +
)}
{ + return db + .prepare<{ name: string }, Db.Eval & { average_score: number }>( + ` + SELECT evals.*, AVG(scores.score) as average_score + FROM evals + LEFT JOIN results ON evals.id = results.eval_id + LEFT JOIN scores ON results.id = scores.result_id + WHERE evals.name = @name + GROUP BY evals.id + ORDER BY evals.created_at ASC + ` + ) + .all({ name }); +}; diff --git a/packages/evalite-core/src/server.ts b/packages/evalite-core/src/server.ts index a5cc829..367329f 100644 --- a/packages/evalite-core/src/server.ts +++ b/packages/evalite-core/src/server.ts @@ -6,6 +6,7 @@ import { getAverageScoresFromResults, getEvals, getEvalsAverageScores, + getHistoricalEvalsWithScoresByName, getMostRecentEvalByName, getMostRecentRun, getPreviousEvalRun, @@ -176,6 +177,7 @@ export const createServer = (opts: { db: SQLiteDatabase }) => { server.route<{ Querystring: { name: string; + timestamp?: string; }; Reply: GetEvalByNameResult; }>({ @@ -186,7 +188,9 @@ export const createServer = (opts: { db: SQLiteDatabase }) => { type: "object", properties: { name: { type: "string" }, + timestamp: { type: "string" }, }, + required: ["name"], }, }, handler: async (req, res) => { @@ -214,8 +218,13 @@ export const createServer = (opts: { db: SQLiteDatabase }) => { results.map((r) => r.id) ); + const history = getHistoricalEvalsWithScoresByName(opts.db, name); + return res.code(200).send({ - history: [], // TODO when we enable chart + history: history.map((h) => ({ + score: h.average_score, + date: h.created_at, + })), evaluation: { ...evaluation, results: results