open-prompt / src /components /analytics /enhanced-analytics.tsx
GitHub Action
Automated sync to Hugging Face
bcce530
"use client"
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Progress } from "@/components/ui/progress"
import {
BarChart3,
TrendingUp,
TrendingDown,
Users,
Play,
Star,
GitFork,
Eye,
Clock,
Zap
} from "lucide-react"
interface AnalyticsStat {
label: string
value: string | number
change?: number
changeLabel?: string
icon: React.ReactNode
}
interface EnhancedAnalyticsProps {
stats: {
totalRuns: number
totalStars: number
totalRemixes: number
totalViews: number
averageResponseTime: number
tokenUsage: number
topPrompts: { title: string; runs: number; stars: number }[]
runsByDay: { date: string; runs: number }[]
modelUsage: { model: string; percentage: number }[]
}
}
export function EnhancedAnalytics({ stats }: EnhancedAnalyticsProps) {
const mainStats: AnalyticsStat[] = [
{
label: "Total Runs",
value: stats.totalRuns.toLocaleString(),
change: 12.5,
changeLabel: "vs last week",
icon: <Play className="h-5 w-5 text-green-500" />
},
{
label: "Total Stars",
value: stats.totalStars.toLocaleString(),
change: 8.3,
changeLabel: "vs last week",
icon: <Star className="h-5 w-5 text-yellow-500" />
},
{
label: "Remixes",
value: stats.totalRemixes.toLocaleString(),
change: 25.0,
changeLabel: "vs last week",
icon: <GitFork className="h-5 w-5 text-purple-500" />
},
{
label: "Total Views",
value: stats.totalViews.toLocaleString(),
change: -2.1,
changeLabel: "vs last week",
icon: <Eye className="h-5 w-5 text-blue-500" />
}
]
return (
<div className="space-y-6">
{/* Main Stats Grid */}
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
{mainStats.map((stat, index) => (
<Card key={index}>
<CardContent className="p-4">
<div className="flex items-center justify-between mb-2">
{stat.icon}
{stat.change !== undefined && (
<Badge
variant="outline"
className={stat.change >= 0 ? "text-green-500" : "text-red-500"}
>
{stat.change >= 0 ? (
<TrendingUp className="h-3 w-3 mr-1" />
) : (
<TrendingDown className="h-3 w-3 mr-1" />
)}
{Math.abs(stat.change)}%
</Badge>
)}
</div>
<p className="text-2xl font-bold">{stat.value}</p>
<p className="text-sm text-muted-foreground">{stat.label}</p>
</CardContent>
</Card>
))}
</div>
{/* Performance Metrics */}
<div className="grid md:grid-cols-2 gap-6">
<Card>
<CardHeader>
<CardTitle className="text-lg flex items-center gap-2">
<Clock className="h-5 w-5" />
Performance Metrics
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div>
<div className="flex items-center justify-between mb-2">
<span className="text-sm">Avg Response Time</span>
<span className="font-medium">{stats.averageResponseTime}ms</span>
</div>
<Progress
value={Math.min((stats.averageResponseTime / 5000) * 100, 100)}
className="h-2"
/>
<p className="text-xs text-muted-foreground mt-1">
{stats.averageResponseTime < 2000 ? "Excellent" :
stats.averageResponseTime < 4000 ? "Good" : "Needs improvement"}
</p>
</div>
<div>
<div className="flex items-center justify-between mb-2">
<span className="text-sm">Token Efficiency</span>
<span className="font-medium">{(stats.tokenUsage / 1000).toFixed(1)}k tokens</span>
</div>
<Progress value={75} className="h-2" />
<p className="text-xs text-muted-foreground mt-1">Above average efficiency</p>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="text-lg flex items-center gap-2">
<Zap className="h-5 w-5" />
Model Usage
</CardTitle>
</CardHeader>
<CardContent className="space-y-3">
{stats.modelUsage.map((model, index) => (
<div key={index}>
<div className="flex items-center justify-between mb-1">
<span className="text-sm">{model.model}</span>
<span className="text-sm font-medium">{model.percentage}%</span>
</div>
<Progress value={model.percentage} className="h-2" />
</div>
))}
</CardContent>
</Card>
</div>
{/* Top Prompts */}
<Card>
<CardHeader>
<CardTitle className="text-lg flex items-center gap-2">
<BarChart3 className="h-5 w-5" />
Top Performing Prompts
</CardTitle>
<CardDescription>Your most popular prompts by runs</CardDescription>
</CardHeader>
<CardContent>
<div className="space-y-4">
{stats.topPrompts.map((prompt, index) => (
<div key={index} className="flex items-center gap-4">
<div className="h-8 w-8 rounded-full bg-primary/10 flex items-center justify-center text-primary font-medium">
{index + 1}
</div>
<div className="flex-1 min-w-0">
<p className="font-medium truncate">{prompt.title}</p>
<div className="flex items-center gap-3 text-sm text-muted-foreground">
<span className="flex items-center gap-1">
<Play className="h-3 w-3" />
{prompt.runs} runs
</span>
<span className="flex items-center gap-1">
<Star className="h-3 w-3" />
{prompt.stars} stars
</span>
</div>
</div>
<Progress
value={(prompt.runs / stats.topPrompts[0].runs) * 100}
className="w-24 h-2"
/>
</div>
))}
</div>
</CardContent>
</Card>
{/* Activity Chart (Simple Bar Representation) */}
<Card>
<CardHeader>
<CardTitle className="text-lg">Weekly Activity</CardTitle>
<CardDescription>Runs per day over the last 7 days</CardDescription>
</CardHeader>
<CardContent>
<div className="flex items-end gap-2 h-32">
{stats.runsByDay.map((day, index) => {
const maxRuns = Math.max(...stats.runsByDay.map(d => d.runs))
const height = (day.runs / maxRuns) * 100
return (
<div key={index} className="flex-1 flex flex-col items-center">
<div
className="w-full bg-primary rounded-t transition-all hover:bg-primary/80"
style={{ height: `${height}%`, minHeight: '4px' }}
/>
<span className="text-xs text-muted-foreground mt-2">
{day.date}
</span>
</div>
)
})}
</div>
</CardContent>
</Card>
</div>
)
}