Untitled
unknown
plain_text
a month ago
12 kB
2
Indexable
"use client" import * as React from "react" import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts" import { Card, CardContent, CardHeader, CardTitle, CardDescription, } from "@/components/ui/card" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartTooltipContent, } from "@/components/ui/chart" const chartConfig = { bin1: { label: "Bio", color: "hsl(var(--chart-1))", }, bin2: { label: "Recycling", color: "hsl(var(--chart-2))", }, bin3: { label: "Paper", color: "hsl(var(--chart-3))", }, bin4: { label: "Residual", color: "hsl(var(--chart-4))", }, } satisfies ChartConfig export function FillRates({ currentFillLevels }) { const [timeRange, setTimeRange] = React.useState("90d") // For now, let's create demo data based on current fill levels const generateHistoricalData = () => { const data = [] const endDate = new Date() const startDate = new Date() startDate.setDate(endDate.getDate() - 90) // 90 days ago for (let date = new Date(startDate); date <= endDate; date.setDate(date.getDate() + 1)) { // Create random variations of current fill levels data.push({ date: date.toISOString().split('T')[0], bin1: Math.max(0, Math.min(100, currentFillLevels.bin1 + (Math.random() - 0.5) * 20)), bin2: Math.max(0, Math.min(100, currentFillLevels.bin2 + (Math.random() - 0.5) * 20)), bin3: Math.max(0, Math.min(100, currentFillLevels.bin3 + (Math.random() - 0.5) * 20)), bin4: Math.max(0, Math.min(100, currentFillLevels.bin4 + (Math.random() - 0.5) * 20)), }) } return data } const chartData = generateHistoricalData() // Filter data based on selected time range const filteredData = chartData.filter((item) => { const date = new Date(item.date) const referenceDate = new Date() let daysToSubtract = 90 if (timeRange === "30d") daysToSubtract = 30 if (timeRange === "7d") daysToSubtract = 7 const startDate = new Date(referenceDate) startDate.setDate(startDate.getDate() - daysToSubtract) return date >= startDate }) return ( <Card> <CardHeader className="flex items-center gap-2 space-y-0 border-b py-4 sm:flex-row"> <div className="grid flex-1 gap-1 text-center sm:text-left"> <CardTitle>Fill Levels Over Time</CardTitle> <CardDescription>Historical fill levels for all bins</CardDescription> </div> <Select value={timeRange} onValueChange={setTimeRange}> <SelectTrigger className="w-[160px] rounded-lg"> <SelectValue placeholder="Last 3 months" /> </SelectTrigger> <SelectContent> <SelectItem value="90d">Last 3 months</SelectItem> <SelectItem value="30d">Last 30 days</SelectItem> <SelectItem value="7d">Last 7 days</SelectItem> </SelectContent> </Select> </CardHeader> <CardContent className="pt-4"> <ChartContainer config={chartConfig} className="h-[300px]"> <AreaChart data={filteredData}> <defs> {Object.keys(chartConfig).map((bin) => ( <linearGradient key={bin} id={`fill${bin}`} x1="0" y1="0" x2="0" y2="1" > <stop offset="5%" stopColor={`var(--color-${bin})`} stopOpacity={0.8} /> <stop offset="95%" stopColor={`var(--color-${bin})`} stopOpacity={0.1} /> </linearGradient> ))} </defs> <CartesianGrid strokeDasharray="3 3" /> <XAxis dataKey="date" tickLine={false} axisLine={false} tickMargin={8} minTickGap={32} tickFormatter={(value) => { const date = new Date(value) return date.toLocaleDateString("en-US", { month: "short", day: "numeric", }) }} /> <YAxis tickLine={false} axisLine={false} tickMargin={8} domain={[0, 100]} tickFormatter={(value) => `${value}%`} /> <ChartTooltip content={ <ChartTooltipContent labelFormatter={(value) => { return new Date(value).toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric", }) }} /> } /> {Object.keys(chartConfig).map((bin) => ( <Area key={bin} dataKey={bin} type="monotone" fill={`url(#fill${bin})`} stroke={`var(--color-${bin})`} strokeWidth={2} /> ))} <ChartLegend content={<ChartLegendContent />} /> </AreaChart> </ChartContainer> </CardContent> </Card> ) } "use client" import { useEffect, useState } from "react" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Overview } from "@/components/statistics/overview" import { DailySorting } from "@/components/statistics/daily-sorting" import { HourlyActivity } from "@/components/statistics/hourly-activity" import { FillRates } from "@/components/statistics/fill-rates" import { ModelUsage } from "@/components/statistics/model-usage" import { ClassificationTimes } from "@/components/statistics/classification-times" import { Activity, Brain, ChartBar, LineChart, Recycle, Timer } from "lucide-react" export default function StatisticsPage() { const [isLoading, setIsLoading] = useState(true) const [data, setData] = useState(null) const [fillLevels, setFillLevels] = useState(null) useEffect(() => { // Fetch both stats and fill levels Promise.all([ fetch('/api/stats').then(res => res.json()), fetch('/api/fill-levels').then(res => res.json()) ]) .then(([statsData, fillLevelsData]) => { setData(statsData) setFillLevels(fillLevelsData) setIsLoading(false) }) .catch(error => { console.error('Error fetching data:', error) setIsLoading(false) }) }, []) if (isLoading) { return <div className="flex items-center justify-center h-screen">Loading...</div> } return ( <div className="flex-1 space-y-4 p-8 pt-6"> <div className="flex items-center justify-between space-y-2"> <h2 className="text-3xl font-bold tracking-tight">Statistics</h2> </div> {/* Quick Stats Cards */} <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4"> <Card> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardTitle className="text-sm font-medium">Total Items</CardTitle> <Recycle className="h-4 w-4 text-muted-foreground" /> </CardHeader> <CardContent> <div className="text-2xl font-bold">{data?.summary?.total_sorts || 0}</div> <p className="text-xs text-muted-foreground"> +{data?.summary?.today_sorts || 0} today </p> </CardContent> </Card> <Card> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardTitle className="text-sm font-medium">API Usage</CardTitle> <Activity className="h-4 w-4 text-muted-foreground" /> </CardHeader> <CardContent> <div className="text-2xl font-bold"> {Math.round((data?.summary?.model_usage_total?.api / (data?.summary?.model_usage_total?.api + data?.summary?.model_usage_total?.local || 1)) * 100)}% </div> <p className="text-xs text-muted-foreground">Of total classifications</p> </CardContent> </Card> <Card> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardTitle className="text-sm font-medium">Response Time</CardTitle> <Timer className="h-4 w-4 text-muted-foreground" /> </CardHeader> <CardContent> <div className="text-2xl font-bold"> {data?.summary?.avg_classification_time_ms || 0}ms </div> <p className="text-xs text-muted-foreground">Average classification speed</p> </CardContent> </Card> <Card> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardTitle className="text-sm font-medium">Daily Average</CardTitle> <ChartBar className="h-4 w-4 text-muted-foreground" /> </CardHeader> <CardContent> <div className="text-2xl font-bold"> {Math.round(data?.summary?.total_sorts / (Object.keys(data?.daily_stats || {}).length || 1))} </div> <p className="text-xs text-muted-foreground">Items per day</p> </CardContent> </Card> </div> {/* Main Content Tabs */} <Tabs defaultValue="overview" className="space-y-4"> <TabsList> <TabsTrigger value="overview" className="gap-2"> <LineChart className="h-4 w-4" /> Overview </TabsTrigger> <TabsTrigger value="sorting" className="gap-2"> <ChartBar className="h-4 w-4" /> Sorting </TabsTrigger> <TabsTrigger value="bins" className="gap-2"> <Recycle className="h-4 w-4" /> Bins </TabsTrigger> <TabsTrigger value="performance" className="gap-2"> <Activity className="h-4 w-4" /> Performance </TabsTrigger> </TabsList> <TabsContent value="overview" className="space-y-4"> <Overview data={data} /> </TabsContent> <TabsContent value="sorting" className="space-y-4"> <div className="grid gap-4 md:grid-cols-2"> <DailySorting data={data} /> <HourlyActivity data={data} /> </div> </TabsContent> <TabsContent value="bins" className="space-y-4"> <FillRates currentFillLevels={fillLevels} /> </TabsContent> <TabsContent value="performance" className="space-y-4"> <div className="grid gap-4 md:grid-cols-2"> <ModelUsage data={data} /> <ClassificationTimes data={data} /> </div> </TabsContent> </Tabs> </div> ) }
Editor is loading...
Leave a Comment