File size: 6,001 Bytes
9243cff
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
"use client"

import { useState, useEffect } from "react"
import AnalyticsDashboard from "@/components/analytics-dashboard"
import { Navigation } from "@/components/navigation"
import { PageHeader } from "@/components/page-header"

interface Evaluation {
  id: string
  name: string
  organization: string
  overallScore: number
  modality: string[]
  submittedDate: string
  categoryEvaluations?: {
    [categoryId: string]: {
      benchmarkAnswers?: { [questionId: string]: string }
      processAnswers?: { [questionId: string]: string }
    }
  }
}

const loadEvaluationData = async (): Promise<Evaluation[]> => {
  const evaluationFiles = [
    "/evaluations/gpt-4-turbo.json",
    "/evaluations/claude-3-sonnet.json", 
    "/evaluations/gemini-pro.json",
    "/evaluations/fraud-detector.json",
  ]

  const additionalFiles = []
  for (let i = 1; i <= 10; i++) {
    additionalFiles.push(`/evaluations/eval-${Date.now() - i * 86400000}.json`)
  }

  const allFiles = [...evaluationFiles, ...additionalFiles]
  const evaluations: Evaluation[] = []

  for (const file of allFiles) {
    try {
      const response = await fetch(file)
      if (!response.ok) continue

      const data = await response.json()

      // Calculate overall score based on completion percentage
      let overallScore = 0
      if (data.categoryEvaluations) {
        const allCategories = Object.keys(data.categoryEvaluations)
        const categoryScores = allCategories.map(categoryId => {
          const categoryData = data.categoryEvaluations[categoryId]
          if (!categoryData) return 0

          // Count total questions and answered questions
          const benchmarkAnswers = categoryData.benchmarkAnswers || {}
          const processAnswers = categoryData.processAnswers || {}
          
          const allAnswers = { ...benchmarkAnswers, ...processAnswers }
          const totalQuestions = Object.keys(allAnswers).length
          if (totalQuestions === 0) return 0

          // Count answered questions (not N/A, null, undefined, or empty)
          const answeredQuestions = Object.values(allAnswers).filter(
            (answer: any) => answer && answer !== "N/A" && String(answer).trim() !== ""
          ).length

          return (answeredQuestions / totalQuestions) * 100
        })

        overallScore = categoryScores.length > 0 
          ? categoryScores.reduce((sum, score) => sum + score, 0) / categoryScores.length 
          : 0
      }

      const evaluation: Evaluation = {
        id: data.id || `eval-${Date.now()}`,
        name: data.systemName || "Unknown System",
        organization: data.provider || "Unknown Provider",
        overallScore,
        modality: [...(data.inputModalities || ["Text"]), ...(data.outputModalities || ["Text"])],
        submittedDate: data.evaluationDate || new Date().toISOString().split("T")[0],
        categoryEvaluations: data.categoryEvaluations
      }

      evaluations.push(evaluation)
    } catch (error) {
      console.error(`Failed to load evaluation from ${file}:`, error)
    }
  }

  return evaluations
}

export default function AnalyticsPage() {
  const { theme, setTheme } = useTheme()
  const [evaluations, setEvaluations] = useState<Evaluation[]>([])
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    const loadData = async () => {
      try {
        const data = await loadEvaluationData()
        setEvaluations(data)
      } catch (error) {
        console.error("Failed to load evaluation data:", error)
      } finally {
        setLoading(false)
      }
    }
    loadData()
  }, [])

  if (loading) {
    return (
      <div className="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-950 dark:to-slate-900 flex items-center justify-center">
        <div className="text-center">
          <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4"></div>
          <p className="text-muted-foreground">Loading analytics...</p>
        </div>
      </div>
    )
  }

  return (
    <div className="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-950 dark:to-slate-900">
      <header className="border-b bg-card/80 backdrop-blur-sm">
        <div className="container mx-auto px-4 sm:px-6 py-4">
          <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3">
            <div>
              <h1 className="text-xl sm:text-2xl font-bold font-heading text-foreground">Analytics & Leaderboards</h1>
              <p className="text-sm text-muted-foreground">Explore evaluation completeness across models and categories</p>
            </div>
            <div className="flex items-center gap-2 sm:gap-3">
              <Link href="/">
                <Button variant="ghost" size="sm" className="gap-2">
                  <Home className="h-4 w-4" />
                  <span className="hidden sm:inline">Dashboard</span>
                </Button>
              </Link>
              <Link href="/about">
                <Button variant="ghost" size="sm" className="gap-2">
                  <Info className="h-4 w-4" />
                  <span className="hidden sm:inline">About</span>
                </Button>
              </Link>
              <Button
                variant="ghost"
                size="sm"
                onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
                className="h-9 w-9 p-0"
              >
                <Sun className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
                <Moon className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
                <span className="sr-only">Toggle theme</span>
              </Button>
            </div>
          </div>
        </div>
      </header>

      <div className="container mx-auto px-4 py-8">
        <AnalyticsDashboard evaluations={evaluations} />
      </div>
    </div>
  )
}