Skip to content

Commit 38a4444

Browse files
authored
Aggregated metrics part 3 (#50)
* parameterize logger * fix logging too much * fix sqlite stuff to use rollout_id * fix * fix sqlite logger tests * fix defualt_agent_rollout_processor.py * for generating some test data * comment out saving logs code * Refactor pivot test to handle JSONL logs and improve data parsing - Updated the test to read from a new JSONL log file instead of JSON, enhancing data handling. - Adjusted the parsing logic to accommodate line-by-line JSON parsing for better flexibility. - Modified row and column field definitions to include additional identifiers for improved data aggregation. * everything is rollout id basd * route based on path to table or pivot * Add TabButton component for improved tab navigation in Dashboard * Implement pagination in EvaluationTable component - Enhanced TableBody to support pagination by slicing the dataset based on current page and page size. - Added pagination controls in EvaluationTable for navigating between pages and adjusting page size. - Reset current page to 1 when the dataset changes to ensure consistent user experience. * Refactor page size selection in EvaluationTable component - Replaced the native select element with a custom Select component for improved styling and consistency. - Updated the page size selection logic to maintain functionality while enhancing the user interface. * Refactor table components for consistency and improved styling - Introduced a new TableContainer component to standardize table layout and styling across the application. - Replaced traditional HTML table elements in EvaluationRow, EvaluationTable, and PivotTable with the new TableContainer, TableHeader, TableCell, TableRow, and TableRowInteractive components for better maintainability and visual consistency. - Enhanced the table structure to support additional styling options and improve responsiveness. * Update EvaluationRow component to use RowModel for model display * TODO: actually implement configurable pivot * vite build
1 parent 33c52a8 commit 38a4444

15 files changed

+704
-275
lines changed

vite-app/dist/assets/index-D9iVTBbF.css

Lines changed: 0 additions & 1 deletion
This file was deleted.

vite-app/dist/assets/index-DWfIf2rx.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vite-app/dist/assets/index-D_nkLTVA.js

Lines changed: 88 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vite-app/dist/assets/index-D_nkLTVA.js.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vite-app/dist/assets/index-DiF_B1x_.js

Lines changed: 0 additions & 88 deletions
This file was deleted.

vite-app/dist/assets/index-DiF_B1x_.js.map

Lines changed: 0 additions & 1 deletion
This file was deleted.

vite-app/dist/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
66
<title>EP | Log Viewer</title>
77
<link rel="icon" href="/assets/favicon-BkAAWQga.png" />
8-
<script type="module" crossorigin src="/assets/index-DiF_B1x_.js"></script>
9-
<link rel="stylesheet" crossorigin href="/assets/index-D9iVTBbF.css">
8+
<script type="module" crossorigin src="/assets/index-D_nkLTVA.js"></script>
9+
<link rel="stylesheet" crossorigin href="/assets/index-DWfIf2rx.css">
1010
</head>
1111
<body>
1212
<div id="root"></div>

vite-app/src/App.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useEffect, useRef } from "react";
2+
import { Routes, Route, Navigate } from "react-router-dom";
23
import { observer } from "mobx-react";
34
import Dashboard from "./components/Dashboard";
45
import Button from "./components/Button";
@@ -15,7 +16,9 @@ const MAX_RECONNECT_ATTEMPTS = 5;
1516

1617
const App = observer(() => {
1718
const wsRef = useRef<WebSocket | null>(null);
18-
const reconnectTimeoutRef = useRef<number | null>(null);
19+
const reconnectTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(
20+
null
21+
);
1922
const reconnectAttemptsRef = useRef(0);
2023

2124
const connectWebSocket = () => {
@@ -145,7 +148,17 @@ const App = observer(() => {
145148
</nav>
146149

147150
<main className="max-w-7xl mx-auto px-3 py-4">
148-
<Dashboard onRefresh={handleManualRefresh} />
151+
<Routes>
152+
<Route path="/" element={<Navigate to="/table" replace />} />
153+
<Route
154+
path="/table"
155+
element={<Dashboard onRefresh={handleManualRefresh} />}
156+
/>
157+
<Route
158+
path="/pivot"
159+
element={<Dashboard onRefresh={handleManualRefresh} />}
160+
/>
161+
</Routes>
149162
</main>
150163
</div>
151164
);

vite-app/src/components/Dashboard.tsx

Lines changed: 90 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { observer } from "mobx-react";
2-
import { useMemo, useState } from "react";
2+
import { useMemo, useState, useEffect } from "react";
3+
import { useLocation, useNavigate } from "react-router-dom";
34
import { state } from "../App";
45
import Button from "./Button";
56
import { EvaluationTable } from "./EvaluationTable";
67
import PivotTable from "./PivotTable";
8+
import TabButton from "./TabButton";
79
import flattenJson from "../util/flatten-json";
810

911
interface DashboardProps {
@@ -52,7 +54,19 @@ const Dashboard = observer(({ onRefresh }: DashboardProps) => {
5254
const expandAll = () => state.setAllRowsExpanded(true);
5355
const collapseAll = () => state.setAllRowsExpanded(false);
5456

55-
const [activeTab, setActiveTab] = useState<"table" | "pivot">("table");
57+
const location = useLocation();
58+
const navigate = useNavigate();
59+
60+
const deriveTabFromPath = (path: string): "table" | "pivot" =>
61+
path.endsWith("/pivot") ? "pivot" : "table";
62+
63+
const [activeTab, setActiveTab] = useState<"table" | "pivot">(
64+
deriveTabFromPath(location.pathname)
65+
);
66+
67+
useEffect(() => {
68+
setActiveTab(deriveTabFromPath(location.pathname));
69+
}, [location.pathname]);
5670

5771
const flattened = useMemo(() => {
5872
const flattenedDataset = state.sortedDataset.map((row) => flattenJson(row));
@@ -61,80 +75,88 @@ const Dashboard = observer(({ onRefresh }: DashboardProps) => {
6175

6276
return (
6377
<div className="text-sm">
64-
{/* Summary Stats */}
78+
{/* Summary */}
6579
<div className="mb-4 bg-white border border-gray-200 p-3">
66-
<div className="flex justify-between items-center mb-2">
67-
<h2 className="text-sm font-semibold text-gray-900">
68-
Dataset Summary
69-
</h2>
70-
{state.totalCount > 0 && (
71-
<div className="flex gap-2">
72-
<Button
73-
onClick={() => setActiveTab("table")}
74-
size="sm"
75-
variant="secondary"
76-
>
77-
Table
78-
</Button>
79-
<Button
80-
onClick={() => setActiveTab("pivot")}
81-
size="sm"
82-
variant="secondary"
83-
>
84-
Pivot
85-
</Button>
86-
</div>
87-
)}
88-
</div>
89-
<div className="text-xs space-y-1">
90-
<div>
91-
<span className="font-semibold text-gray-700">Total Rows:</span>{" "}
92-
{state.totalCount}
93-
</div>
94-
{activeTab === "table" && state.totalCount > 0 && (
95-
<div className="flex gap-2">
96-
<Button onClick={expandAll} size="sm" variant="secondary">
97-
Expand All
98-
</Button>
99-
<Button onClick={collapseAll} size="sm" variant="secondary">
100-
Collapse All
101-
</Button>
102-
</div>
103-
)}
80+
<h2 className="text-sm font-semibold text-gray-900 mb-2">
81+
Dataset Summary
82+
</h2>
83+
<div className="text-xs">
84+
<span className="font-semibold text-gray-700">Total Rows:</span>{" "}
85+
{state.totalCount}
10486
</div>
10587
</div>
10688

107-
{/* Show empty state or main table */}
89+
{/* Content Area */}
10890
{state.totalCount === 0 ? (
10991
<EmptyState onRefresh={onRefresh} />
110-
) : activeTab === "table" ? (
111-
<EvaluationTable />
11292
) : (
113-
<div className="bg-white border border-gray-200 p-3">
114-
<div className="text-xs text-gray-600 mb-2">
115-
Showing pivot of flattened rows (JSONPath keys). Defaults: rows by
116-
eval name and status; columns by model; values average score.
93+
<div className="bg-white border border-gray-200">
94+
{/* Tabs + contextual actions */}
95+
<div className="px-3 pt-2 border-b border-gray-200">
96+
<div className="flex justify-between h-8">
97+
<div id="tabs" className="flex gap-1">
98+
<TabButton
99+
label="Table"
100+
isActive={activeTab === "table"}
101+
onClick={() => {
102+
setActiveTab("table");
103+
navigate("/table");
104+
}}
105+
title="View table"
106+
/>
107+
<TabButton
108+
label="Pivot"
109+
isActive={activeTab === "pivot"}
110+
onClick={() => {
111+
setActiveTab("pivot");
112+
navigate("/pivot");
113+
}}
114+
title="View pivot"
115+
/>
116+
</div>
117+
{activeTab === "table" && (
118+
<div className="flex gap-2 pb-2">
119+
<Button onClick={expandAll} size="sm" variant="secondary">
120+
Expand All
121+
</Button>
122+
<Button onClick={collapseAll} size="sm" variant="secondary">
123+
Collapse All
124+
</Button>
125+
</div>
126+
)}
127+
</div>
128+
</div>
129+
130+
{/* Tab content */}
131+
<div className="p-3">
132+
{activeTab === "table" ? (
133+
<EvaluationTable />
134+
) : (
135+
<div>
136+
<div className="text-xs text-gray-600 mb-2">
137+
Showing pivot of flattened rows (JSONPath keys). Defaults:
138+
rows by eval name and status; columns by model; values average
139+
score.
140+
</div>
141+
<PivotTable
142+
data={flattened}
143+
rowFields={[
144+
"$.eval_metadata.name" as keyof (typeof flattened)[number],
145+
"$.eval_metadata.status" as keyof (typeof flattened)[number],
146+
]}
147+
columnFields={[
148+
"$.input_metadata.completion_params.model" as keyof (typeof flattened)[number],
149+
]}
150+
valueField={
151+
"$.evaluation_result.score" as keyof (typeof flattened)[number]
152+
}
153+
aggregator="avg"
154+
showRowTotals
155+
showColumnTotals
156+
/>
157+
</div>
158+
)}
117159
</div>
118-
<PivotTable
119-
// Flattened object list
120-
data={flattened}
121-
// Row keys
122-
rowFields={[
123-
"$.eval_metadata.name" as keyof (typeof flattened)[number],
124-
"$.eval_metadata.status" as keyof (typeof flattened)[number],
125-
]}
126-
// Column keys
127-
columnFields={[
128-
"$.input_metadata.completion_params.model" as keyof (typeof flattened)[number],
129-
]}
130-
// Value and aggregation
131-
valueField={
132-
"$.evaluation_result.score" as keyof (typeof flattened)[number]
133-
}
134-
aggregator="avg"
135-
showRowTotals
136-
showColumnTotals
137-
/>
138160
</div>
139161
)}
140162
</div>

vite-app/src/components/EvaluationRow.tsx

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { ChatInterface } from "./ChatInterface";
44
import { MetadataSection } from "./MetadataSection";
55
import StatusIndicator from "./StatusIndicator";
66
import { state } from "../App";
7+
import { TableCell, TableRowInteractive } from "./TableContainer";
78

89
// Small, focused components following "dereference values late" principle
910
const ExpandIcon = observer(({ rolloutId }: { rolloutId?: string }) => {
@@ -172,7 +173,7 @@ const ExpandedContent = observer(
172173
input_metadata: EvaluationRowType["input_metadata"];
173174
tools: EvaluationRowType["tools"];
174175
}) => (
175-
<div className="p-4 bg-gray-50 border-t border-gray-200">
176+
<div className="p-4 bg-gray-50">
176177
<div className="flex gap-3 w-fit">
177178
{/* Left Column - Chat Interface */}
178179
<div className="min-w-0">
@@ -204,48 +205,45 @@ export const EvaluationRow = observer(
204205
return (
205206
<>
206207
{/* Main Table Row */}
207-
<tr
208-
className="hover:bg-gray-50 cursor-pointer text-sm border-b border-gray-200"
209-
onClick={toggleExpanded}
210-
>
208+
<TableRowInteractive onClick={toggleExpanded}>
211209
{/* Expand/Collapse Icon */}
212-
<td className="px-3 py-3 w-8">
210+
<TableCell className="w-8 py-3">
213211
<ExpandIcon rolloutId={rolloutId} />
214-
</td>
212+
</TableCell>
215213

216214
{/* Name */}
217-
<td className="px-3 py-3 text-xs">
215+
<TableCell className="py-3 text-xs">
218216
<RowName name={row.eval_metadata?.name} />
219-
</td>
217+
</TableCell>
220218

221219
{/* Status */}
222-
<td className="px-3 py-3 text-xs">
220+
<TableCell className="py-3 text-xs">
223221
<RowStatus
224222
status={row.eval_metadata?.status}
225223
showSpinner={row.eval_metadata?.status === "running"}
226224
/>
227-
</td>
225+
</TableCell>
228226

229227
{/* Rollout ID */}
230-
<td className="px-3 py-3 text-xs">
228+
<TableCell className="py-3 text-xs">
231229
<RolloutId rolloutId={row.rollout_id} />
232-
</td>
230+
</TableCell>
233231

234232
{/* Model */}
235-
<td className="px-3 py-3 text-xs">
233+
<TableCell className="py-3 text-xs">
236234
<RowModel model={row.input_metadata.completion_params?.model} />
237-
</td>
235+
</TableCell>
238236

239237
{/* Score */}
240-
<td className="px-3 py-3 text-xs">
238+
<TableCell className="py-3 text-xs">
241239
<RowScore score={row.evaluation_result?.score} />
242-
</td>
240+
</TableCell>
243241

244242
{/* Created */}
245-
<td className="px-3 py-3 text-xs">
243+
<TableCell className="py-3 text-xs">
246244
<RowCreated created_at={row.created_at} />
247-
</td>
248-
</tr>
245+
</TableCell>
246+
</TableRowInteractive>
249247

250248
{/* Expanded Content Row */}
251249
{isExpanded && (

0 commit comments

Comments
 (0)