Skip to content

Commit

Permalink
fix display
Browse files Browse the repository at this point in the history
  • Loading branch information
MadcowD committed Aug 9, 2024
1 parent 0dc8728 commit a10878b
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 20 deletions.
103 changes: 103 additions & 0 deletions ell-studio/src/components/LMPHistoryChart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React, { useMemo, useState } from 'react';
import { AreaChart, Area, XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid, Brush, Legend } from 'recharts';
import { format, differenceInDays, differenceInHours, startOfDay, startOfHour, startOfMinute, eachDayOfInterval, eachHourOfInterval, eachMinuteOfInterval, addMinutes, getMinutes } from 'date-fns';

const LMPHistoryChart = ({ data, title }) => {
const [dateRange, setDateRange] = useState(null);

const aggregatedData = useMemo(() => {
if (!data?.length) return [];

const sortedData = [...data].sort((a, b) => new Date(a.date) - new Date(b.date));
const zoomStart = dateRange?.start || new Date(sortedData[0].date);
const zoomEnd = dateRange?.end || new Date(sortedData[sortedData.length - 1].date);

const daysDiff = differenceInDays(zoomEnd, zoomStart);
const hoursDiff = differenceInHours(zoomEnd, zoomStart);

let aggregationInterval;
let aggregationFunction;

if (daysDiff > 30) {
aggregationInterval = eachDayOfInterval;
aggregationFunction = startOfDay;
} else if (hoursDiff > 24) {
aggregationInterval = eachHourOfInterval;
aggregationFunction = startOfHour;
} else {
aggregationInterval = eachMinuteOfInterval;
aggregationFunction = startOfMinute;
}

const aggregatedMap = new Map();
sortedData.forEach((item) => {
const date = new Date(item.date);
if (date >= zoomStart && date <= zoomEnd) {
const key = format(aggregationFunction(date), "yyyy-MM-dd'T'HH:mm");
const existing = aggregatedMap.get(key) || 0;
aggregatedMap.set(key, existing + item.count);
}
});

return aggregationInterval({ start: zoomStart, end: zoomEnd }).map((date) => {
const key = format(date, "yyyy-MM-dd'T'HH:mm");
return {
date: key,
versions: aggregatedMap.get(key) || 0,
};
});
}, [data, dateRange]);

const formatXAxis = (tickItem) => {
const date = new Date(tickItem);
const daysDiff = differenceInDays(dateRange?.end || new Date(), dateRange?.start || new Date(data[0].date));
if (daysDiff > 30) return format(date, "MMM d");
if (daysDiff > 1) return format(date, "MMM d HH:mm");
return format(date, "HH:mm");
};

const formatTooltip = (value, name, props) => {
return [`${value} versions`, "LMPs Created"];
};

const handleZoom = (domain) => {
setDateRange({
start: new Date(domain.startDate),
end: new Date(domain.endDate),
});
};

return (
<div className="bg-[#161b22] p-4 rounded-lg shadow-lg w-full h-full">
<h3 className="text-lg font-semibold mb-2 text-white">{title}</h3>
<ResponsiveContainer width="100%" height="90%">
<AreaChart data={aggregatedData} margin={{ top: 5, right: 20, left: 0, bottom: 0 }}>
<defs>
<linearGradient id="colorVersions" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="#8884d8" stopOpacity={0.8} />
<stop offset="95%" stopColor="#8884d8" stopOpacity={0} />
</linearGradient>
</defs>
<XAxis dataKey="date" stroke="#4a5568" tick={{ fill: "#4a5568", fontSize: 10 }} tickFormatter={formatXAxis} />
<YAxis stroke="#4a5568" tick={{ fill: "#4a5568", fontSize: 10 }} />
<CartesianGrid strokeDasharray="3 3" stroke="#2d3748" />
<Tooltip
contentStyle={{
backgroundColor: "#1f2937",
border: "none",
color: "#fff",
fontSize: 12,
}}
labelFormatter={(label) => format(new Date(label), "PPpp")}
formatter={formatTooltip}
/>
<Legend wrapperStyle={{ fontSize: 12 }} />
<Area type="monotone" dataKey="versions" stroke="#8884d8" fillOpacity={1} fill="url(#colorVersions)" name="LMPs Created" />
<Brush dataKey="date" height={20} stroke="#8884d8" fill="#161b22" onChange={handleZoom} />
</AreaChart>
</ResponsiveContainer>
</div>
);
};

export default LMPHistoryChart;
12 changes: 11 additions & 1 deletion ell-studio/src/hooks/useBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,14 @@ export const useTraces = (lmps) => {
},
enabled: !!lmps && lmps.length > 0,
});
};
};

export const useLMPHistory = (days = 365) => {
return useQuery({
queryKey: ['lmpHistory', days],
queryFn: async () => {
const response = await axios.get(`${API_BASE_URL}/api/lmp-history?days=${days}`);
return response.data;
},
});
};
50 changes: 31 additions & 19 deletions ell-studio/src/pages/Invocations.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { FiCopy, FiZap, FiEdit2, FiFilter, FiClock, FiColumns, FiPause, FiPlay }
import InvocationsTable from '../components/invocations/InvocationsTable';
import InvocationsLayout from '../components/invocations/InvocationsLayout';
import MetricChart from '../components/MetricChart';
import LMPHistoryChart from '../components/LMPHistoryChart'; // New import
import { useNavigate, useLocation } from 'react-router-dom';
import { useInvocationsFromLMP } from '../hooks/useBackend';
import { useInvocationsFromLMP, useLMPHistory } from '../hooks/useBackend'; // Added useLMPHistory

const Traces = () => {
const [selectedTrace, setSelectedTrace] = useState(null);
Expand All @@ -16,6 +17,7 @@ const Traces = () => {
const pageSize = 50;

const { data: invocations , isLoading } = useInvocationsFromLMP(null, null, currentPage, pageSize);
const { data: lmpHistory, isLoading: isLMPHistoryLoading } = useLMPHistory(365); // Fetch 1 year of data

useEffect(() => {
const searchParams = new URLSearchParams(location.search);
Expand Down Expand Up @@ -56,7 +58,7 @@ const Traces = () => {
return sum / invocations.length;
}, [invocations]);

if (isLoading) {
if (isLoading || isLMPHistoryLoading) {
return <div>Loading...</div>;
}

Expand All @@ -65,7 +67,7 @@ const Traces = () => {
selectedTrace={selectedTrace}
setSelectedTrace={setSelectedTrace}
showSidebar={true}
containerClass={'p-6'}
containerClass={'p-6 flex flex-col h-full'}
>
<div className="flex justify-between items-center mb-6">
<h1 className="text-2xl font-semibold text-white flex items-center">
Expand All @@ -85,22 +87,32 @@ const Traces = () => {
</button>
</div>
</div>
<div className="flex space-x-6 mb-6">
<MetricChart
rawData={chartData}
dataKey="count"
color="#8884d8"
title="Invocations"
yAxisLabel="Count"
/>
<MetricChart
rawData={chartData}
dataKey="latency"
color="#82ca9d"
title="Latency"
aggregation="avg"
yAxisLabel="ms"
/>
<div className="flex space-x-6 mb-6 flex-grow">
<div className="flex-1">
<MetricChart
rawData={chartData}
dataKey="count"
color="#8884d8"
title="Invocations"
yAxisLabel="Count"
/>
</div>
<div className="flex-1">
<MetricChart
rawData={chartData}
dataKey="latency"
color="#82ca9d"
title="Latency"
aggregation="avg"
yAxisLabel="ms"
/>
</div>
{/* <div className="flex-1">
<LMPHistoryChart
data={lmpHistory}
title="LMP History"
/>
</div> */}
</div>
<div className="flex items-center space-x-2 mb-6">
<button className="flex items-center px-2 py-1 bg-[#1c2128] text-xs rounded hover:bg-gray-700">
Expand Down
24 changes: 24 additions & 0 deletions src/ell/studio/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
from ell.studio.datamodels import SerializedLMPPublic, SerializedLMPWithUses

from ell.types import SerializedLMP
from datetime import datetime, timedelta
from sqlmodel import select

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -152,6 +154,28 @@ def get_all_traces_leading_to(
traces = serializer.get_all_traces_leading_to(session, invocation_id)
return traces

@app.get("/api/lmp-history")
def get_lmp_history(
days: int = Query(365, ge=1, le=3650), # Default to 1 year, max 10 years
session: Session = Depends(get_session)
):
# Calculate the start date
start_date = datetime.utcnow() - timedelta(days=days)

# Query to get all LMP creation times within the date range
query = (
select(SerializedLMP.created_at)
.where(SerializedLMP.created_at >= start_date)
.order_by(SerializedLMP.created_at)
)

results = session.exec(query).all()

# Convert results to a list of dictionaries
history = [{"date": str(row), "count": 1} for row in results]

return history

async def notify_clients(entity: str, id: Optional[str] = None):
message = json.dumps({"entity": entity, "id": id})
await manager.broadcast(message)
Expand Down

0 comments on commit a10878b

Please sign in to comment.