Avijit Ghosh commited on
Commit
9243cff
·
1 Parent(s): a0f8d42

add logo and fix navigation

Browse files
app/about/page-new.tsx ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client"
2
+
3
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
4
+ import { Badge } from "@/components/ui/badge"
5
+ import { Separator } from "@/components/ui/separator"
6
+ import { Button } from "@/components/ui/button"
7
+ import Link from "next/link"
8
+ import { ExternalLink } from "lucide-react"
9
+ import { Navigation } from "@/components/navigation"
10
+ import { PageHeader } from "@/components/page-header"
11
+
12
+ export default function AboutPage() {
13
+ return (
14
+ <div className="min-h-screen bg-background">
15
+ <Navigation />
16
+
17
+ <PageHeader
18
+ title="About AI Evaluation Dashboard"
19
+ description="A comprehensive platform for documenting and sharing AI system evaluations with transparency and rigor."
20
+ />
21
+
22
+ <div className="container mx-auto px-4 sm:px-6 py-6 max-w-4xl">
23
+ <div className="grid gap-6">
24
+ <Card>
25
+ <CardHeader>
26
+ <CardTitle>Project Goals</CardTitle>
27
+ <CardDescription>
28
+ Our mission is to advance responsible AI development through transparent evaluation
29
+ </CardDescription>
30
+ </CardHeader>
31
+ <CardContent className="space-y-4">
32
+ <div className="grid gap-3">
33
+ <div className="flex items-start gap-3">
34
+ <div className="w-2 h-2 bg-primary rounded-full mt-2 flex-shrink-0" />
35
+ <div>
36
+ <h4 className="font-medium">Comprehensive Evaluation Framework</h4>
37
+ <p className="text-sm text-muted-foreground">
38
+ Support structured evaluation across 20+ categories covering capabilities and risks
39
+ </p>
40
+ </div>
41
+ </div>
42
+ <div className="flex items-start gap-3">
43
+ <div className="w-2 h-2 bg-primary rounded-full mt-2 flex-shrink-0" />
44
+ <div>
45
+ <h4 className="font-medium">Transparency & Accountability</h4>
46
+ <p className="text-sm text-muted-foreground">
47
+ Promote open documentation of AI system capabilities, limitations, and risks
48
+ </p>
49
+ </div>
50
+ </div>
51
+ <div className="flex items-start gap-3">
52
+ <div className="w-2 h-2 bg-primary rounded-full mt-2 flex-shrink-0" />
53
+ <div>
54
+ <h4 className="font-medium">Industry Standards</h4>
55
+ <p className="text-sm text-muted-foreground">
56
+ Facilitate adoption of consistent evaluation practices across organizations
57
+ </p>
58
+ </div>
59
+ </div>
60
+ </div>
61
+ </CardContent>
62
+ </Card>
63
+
64
+ <Card>
65
+ <CardHeader>
66
+ <CardTitle>Key Features</CardTitle>
67
+ <CardDescription>
68
+ Tools and capabilities that support comprehensive AI evaluation
69
+ </CardDescription>
70
+ </CardHeader>
71
+ <CardContent>
72
+ <div className="grid gap-4 sm:grid-cols-2">
73
+ <div className="space-y-2">
74
+ <Badge variant="secondary" className="mb-2">Evaluation</Badge>
75
+ <ul className="space-y-1 text-sm">
76
+ <li>• Structured evaluation forms</li>
77
+ <li>• Multi-modal system support</li>
78
+ <li>• Evidence-based assessments</li>
79
+ <li>• Category-specific questions</li>
80
+ </ul>
81
+ </div>
82
+ <div className="space-y-2">
83
+ <Badge variant="secondary" className="mb-2">Analytics</Badge>
84
+ <ul className="space-y-1 text-sm">
85
+ <li>• Completeness tracking</li>
86
+ <li>• Performance benchmarking</li>
87
+ <li>• Risk area identification</li>
88
+ <li>• Comparative analysis</li>
89
+ </ul>
90
+ </div>
91
+ <div className="space-y-2">
92
+ <Badge variant="secondary" className="mb-2">Documentation</Badge>
93
+ <ul className="space-y-1 text-sm">
94
+ <li>• Standardized reporting</li>
95
+ <li>• Evidence management</li>
96
+ <li>• Version tracking</li>
97
+ <li>• Export capabilities</li>
98
+ </ul>
99
+ </div>
100
+ <div className="space-y-2">
101
+ <Badge variant="secondary" className="mb-2">Collaboration</Badge>
102
+ <ul className="space-y-1 text-sm">
103
+ <li>• Team evaluation workflows</li>
104
+ <li>• Review processes</li>
105
+ <li>• Stakeholder engagement</li>
106
+ <li>• Public transparency</li>
107
+ </ul>
108
+ </div>
109
+ </div>
110
+ </CardContent>
111
+ </Card>
112
+
113
+ <Card>
114
+ <CardHeader>
115
+ <CardTitle>Evaluation Categories</CardTitle>
116
+ <CardDescription>
117
+ Comprehensive coverage across capabilities and risk areas
118
+ </CardDescription>
119
+ </CardHeader>
120
+ <CardContent>
121
+ <div className="grid gap-6 sm:grid-cols-2">
122
+ <div>
123
+ <h4 className="font-medium mb-3 text-primary">Capability Areas</h4>
124
+ <div className="flex flex-wrap gap-2">
125
+ <Badge variant="outline">Language Communication</Badge>
126
+ <Badge variant="outline">Problem Solving</Badge>
127
+ <Badge variant="outline">Creativity Innovation</Badge>
128
+ <Badge variant="outline">Learning Memory</Badge>
129
+ <Badge variant="outline">Social Intelligence</Badge>
130
+ <Badge variant="outline">Perception Vision</Badge>
131
+ <Badge variant="outline">Physical Manipulation</Badge>
132
+ <Badge variant="outline">Metacognition</Badge>
133
+ <Badge variant="outline">Robotic Intelligence</Badge>
134
+ </div>
135
+ </div>
136
+ <div>
137
+ <h4 className="font-medium mb-3 text-destructive">Risk Areas</h4>
138
+ <div className="flex flex-wrap gap-2">
139
+ <Badge variant="outline">Harmful Content</Badge>
140
+ <Badge variant="outline">Information Integrity</Badge>
141
+ <Badge variant="outline">Privacy Data</Badge>
142
+ <Badge variant="outline">Bias Fairness</Badge>
143
+ <Badge variant="outline">Security Robustness</Badge>
144
+ <Badge variant="outline">Dangerous Capabilities</Badge>
145
+ <Badge variant="outline">Human AI Interaction</Badge>
146
+ <Badge variant="outline">Environmental Impact</Badge>
147
+ <Badge variant="outline">Economic Displacement</Badge>
148
+ <Badge variant="outline">Governance Accountability</Badge>
149
+ <Badge variant="outline">Value Chain</Badge>
150
+ </div>
151
+ </div>
152
+ </div>
153
+ </CardContent>
154
+ </Card>
155
+
156
+ <Card>
157
+ <CardHeader>
158
+ <CardTitle>Getting Started</CardTitle>
159
+ <CardDescription>
160
+ Begin evaluating AI systems with our structured approach
161
+ </CardDescription>
162
+ </CardHeader>
163
+ <CardContent className="space-y-4">
164
+ <div className="grid gap-4 sm:grid-cols-3">
165
+ <div className="text-center p-4 border rounded-lg">
166
+ <div className="w-8 h-8 bg-primary text-primary-foreground rounded-full flex items-center justify-center mx-auto mb-2 text-sm font-bold">
167
+ 1
168
+ </div>
169
+ <h4 className="font-medium mb-1">Create Evaluation</h4>
170
+ <p className="text-xs text-muted-foreground">Start a new evaluation for your AI system</p>
171
+ </div>
172
+ <div className="text-center p-4 border rounded-lg">
173
+ <div className="w-8 h-8 bg-primary text-primary-foreground rounded-full flex items-center justify-center mx-auto mb-2 text-sm font-bold">
174
+ 2
175
+ </div>
176
+ <h4 className="font-medium mb-1">Complete Assessment</h4>
177
+ <p className="text-xs text-muted-foreground">Answer questions across relevant categories</p>
178
+ </div>
179
+ <div className="text-center p-4 border rounded-lg">
180
+ <div className="w-8 h-8 bg-primary text-primary-foreground rounded-full flex items-center justify-center mx-auto mb-2 text-sm font-bold">
181
+ 3
182
+ </div>
183
+ <h4 className="font-medium mb-1">Review & Share</h4>
184
+ <p className="text-xs text-muted-foreground">Analyze results and share with stakeholders</p>
185
+ </div>
186
+ </div>
187
+ </CardContent>
188
+ </Card>
189
+
190
+ <Separator />
191
+
192
+ <div className="text-center space-y-4">
193
+ <h3 className="text-lg font-semibold">Ready to get started?</h3>
194
+ <p className="text-muted-foreground">
195
+ Create your first evaluation card and begin documenting your AI system's capabilities and risks.
196
+ </p>
197
+ <Link href="/">
198
+ <Button size="lg" className="gap-2">
199
+ Start Evaluating
200
+ <ExternalLink className="h-4 w-4" />
201
+ </Button>
202
+ </Link>
203
+ </div>
204
+ </div>
205
+ </div>
206
+ </div>
207
+ )
208
+ }
app/about/page-old.tsx ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client"
2
+
3
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
4
+ import { Badge } from "@/components/ui/badge"
5
+ import { Separator } from "@/components/ui/separator"
6
+ import { Button } from "@/components/ui/button"
7
+ import Link from "next/link"
8
+ import { ExternalLink } from "lucide-react"
9
+ import { Navigation } from "@/components/navigation"
10
+ import { PageHeader } from "@/components/page-header"
11
+
12
+ export default function AboutPage() {
13
+ return (
14
+ <div className="min-h-screen bg-background">
15
+ <Navigation />
16
+
17
+ <PageHeader
18
+ title="About AI Evaluation Dashboard"
19
+ description="A comprehensive platform for documenting and sharing AI system evaluations with transparency and rigor."
20
+ />
21
+
22
+ <div className="container mx-auto px-4 sm:px-6 py-6 max-w-4xl">
23
+ <div className="grid gap-6">
24
+ <Card>
25
+ <CardHeader>
26
+ <CardTitle>Project Goals</CardTitle>
27
+ <CardDescription>
28
+ Our mission is to advance responsible AI development through transparent evaluation
29
+ </CardDescription>
30
+ </CardHeader>
31
+ <CardContent className="space-y-4">
32
+ <div className="grid gap-3">
33
+ <div className="flex items-start gap-3">
34
+ <div className="w-2 h-2 bg-blue-500 rounded-full mt-2 flex-shrink-0"></div>
35
+ <div>
36
+ <h4 className="font-semibold">Standardize AI Evaluation Reporting</h4>
37
+ <p className="text-sm text-muted-foreground">
38
+ Provide a consistent framework for documenting AI system capabilities and limitations across different models and platforms.
39
+ </p>
40
+ </div>
41
+ </div>
42
+ <div className="flex items-start gap-3">
43
+ <div className="w-2 h-2 bg-green-500 rounded-full mt-2 flex-shrink-0"></div>
44
+ <div>
45
+ <h4 className="font-semibold">Facilitate Transparency</h4>
46
+ <p className="text-sm text-muted-foreground">
47
+ Enable AI developers and researchers to share detailed evaluation results in an accessible, standardized format.
48
+ </p>
49
+ </div>
50
+ </div>
51
+ <div className="flex items-start gap-3">
52
+ <div className="w-2 h-2 bg-purple-500 rounded-full mt-2 flex-shrink-0"></div>
53
+ <div>
54
+ <h4 className="font-semibold">Enable Comparative Analysis</h4>
55
+ <p className="text-sm text-muted-foreground">
56
+ Support side-by-side comparison of AI systems across multiple dimensions including capabilities and risks.
57
+ </p>
58
+ </div>
59
+ </div>
60
+ <div className="flex items-start gap-3">
61
+ <div className="w-2 h-2 bg-orange-500 rounded-full mt-2 flex-shrink-0"></div>
62
+ <div>
63
+ <h4 className="font-semibold">Support Research and Policy</h4>
64
+ <p className="text-sm text-muted-foreground">
65
+ Consolidate evaluation data to inform AI research directions and policy development.
66
+ </p>
67
+ </div>
68
+ </div>
69
+ <div className="flex items-start gap-3">
70
+ <div className="w-2 h-2 bg-red-500 rounded-full mt-2 flex-shrink-0"></div>
71
+ <div>
72
+ <h4 className="font-semibold">Promote Responsible AI Development</h4>
73
+ <p className="text-sm text-muted-foreground">
74
+ Encourage comprehensive risk assessment and responsible deployment practices through structured evaluation.
75
+ </p>
76
+ </div>
77
+ </div>
78
+ </div>
79
+ </CardContent>
80
+ </Card>
81
+
82
+ {/* EvalEval link removed from page body per request; footer includes external link instead */}
83
+
84
+ <Card>
85
+ <CardHeader>
86
+ <CardTitle>Standards and Frameworks</CardTitle>
87
+ <CardDescription>
88
+ Built on established international standards for AI evaluation
89
+ </CardDescription>
90
+ </CardHeader>
91
+ <CardContent className="space-y-4">
92
+ <div className="grid gap-4 md:grid-cols-2">
93
+ <div className="p-4 border rounded-lg">
94
+ <div className="flex items-center gap-2 mb-2">
95
+ <Badge variant="destructive">Risk Assessment</Badge>
96
+ </div>
97
+ <h4 className="font-semibold mb-2">NIST AI 600-1</h4>
98
+ <p className="text-sm text-muted-foreground mb-3">
99
+ Risk categories are derived from the NIST AI Risk Management Framework (AI RMF 1.0), providing a comprehensive approach to identifying and managing AI-related risks.
100
+ </p>
101
+ <Link href="https://nvlpubs.nist.gov/nistpubs/ai/NIST.AI.600-1.pdf" target="_blank">
102
+ <Button variant="outline" size="sm">
103
+ <ExternalLink className="mr-2 h-3 w-3" />
104
+ Learn More
105
+ </Button>
106
+ </Link>
107
+ </div>
108
+ <div className="p-4 border rounded-lg">
109
+ <div className="flex items-center gap-2 mb-2">
110
+ <Badge variant="default">Capabilities</Badge>
111
+ </div>
112
+ <h4 className="font-semibold mb-2">OECD AI Classification</h4>
113
+ <p className="text-sm text-muted-foreground mb-3">
114
+ Capability categories are based on the OECD AI Classification Framework, ensuring alignment with international standards for AI system categorization.
115
+ </p>
116
+ <Link href="https://www.oecd.org/en/publications/introducing-the-oecd-ai-capability-indicators_be745f04-en/full-report/component-4.html#chapter-d1e230-f85c23a209" target="_blank">
117
+ <Button variant="outline" size="sm">
118
+ <ExternalLink className="mr-2 h-3 w-3" />
119
+ Learn More
120
+ </Button>
121
+ </Link>
122
+ </div>
123
+ </div>
124
+ </CardContent>
125
+ </Card>
126
+
127
+ <Card>
128
+ <CardHeader>
129
+ <CardTitle>For Contributors</CardTitle>
130
+ <CardDescription>
131
+ How to contribute to the evaluation framework
132
+ </CardDescription>
133
+ </CardHeader>
134
+ <CardContent className="space-y-4">
135
+ <div className="p-4 bg-muted rounded-lg">
136
+ <h4 className="font-semibold mb-2">Schema-Driven Architecture</h4>
137
+ <p className="text-sm text-muted-foreground mb-3">
138
+ All evaluation categories, form fields, and data structures are centrally managed in the <code className="bg-background px-1 py-0.5 rounded">schema/</code> folder. This is the primary location for making structural changes to the evaluation framework.
139
+ </p>
140
+ <div className="space-y-2 text-sm">
141
+ <div><code className="bg-background px-2 py-1 rounded">schema/evaluation-schema.json</code> - Evaluation categories and types</div>
142
+ <div><code className="bg-background px-2 py-1 rounded">schema/output-schema.json</code> - Complete data structure</div>
143
+ <div><code className="bg-background px-2 py-1 rounded">schema/system-info-schema.json</code> - Form field options</div>
144
+ <div><code className="bg-background px-2 py-1 rounded">schema/category-details.json</code> - Detailed descriptions</div>
145
+ </div>
146
+ </div>
147
+ <div className="p-4 bg-muted rounded-lg">
148
+ <h4 className="font-semibold mb-2">Adding Evaluations</h4>
149
+ <p className="text-sm text-muted-foreground">
150
+ Evaluation data files are stored in <code className="bg-background px-1 py-0.5 rounded">public/evaluations/</code> as JSON files. Each file represents a complete evaluation of an AI system and must conform to the schema.
151
+ </p>
152
+ </div>
153
+ <Link href="https://huggingface.co/spaces/evaleval/general-eval-card/tree/main/schema" target="_blank">
154
+ <Button className="w-full flex items-center justify-center gap-2">
155
+ <img src="https://huggingface.co/front/assets/huggingface_logo.svg" alt="Hugging Face" className="h-4 w-4" />
156
+ View on Hugging Face
157
+ </Button>
158
+ </Link>
159
+ </CardContent>
160
+ </Card>
161
+ </div>
162
+
163
+ <Separator className="my-8" />
164
+
165
+ <div className="text-center text-sm text-muted-foreground">
166
+ <p className="mt-2">AI Evaluation Dashboard is an open-source project dedicated to advancing responsible AI development — built with ❤️ by the EvalEval Coalition.</p>
167
+ <p className="mt-2 flex items-center justify-center gap-3">
168
+ <img src="https://evalevalai.com/assets/img/logo-square.png" alt="EvalEval" className="h-8 w-8 rounded" />
169
+ <span>Learn more about EvalEval: <Link href="https://evalevalai.com/" target="_blank">evalevalai.com</Link></span>
170
+ </p>
171
+ </div>
172
+ </div>
173
+ </div>
174
+ </div>
175
+ )
176
+ }
app/about/page.tsx CHANGED
@@ -5,187 +5,203 @@ import { Badge } from "@/components/ui/badge"
5
  import { Separator } from "@/components/ui/separator"
6
  import { Button } from "@/components/ui/button"
7
  import Link from "next/link"
8
- import { ArrowLeft, ExternalLink, Sun, Moon } from "lucide-react"
9
- import { useTheme } from "next-themes"
 
10
 
11
  export default function AboutPage() {
12
- const { theme, setTheme } = useTheme()
13
-
14
  return (
15
- <div className="container mx-auto px-4 sm:px-6 py-4 sm:py-8 max-w-4xl">
16
- <div className="mb-6">
17
- <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 mb-4">
18
- <Link href="/">
19
- <Button variant="ghost">
20
- <ArrowLeft className="mr-2 h-4 w-4" />
21
- Back to Dashboard
22
- </Button>
23
- </Link>
24
- <Button
25
- variant="ghost"
26
- size="sm"
27
- onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
28
- className="h-9 w-9 p-0"
29
- >
30
- <Sun className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
31
- <Moon className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
32
- <span className="sr-only">Toggle theme</span>
33
- </Button>
34
- </div>
35
- <h1 className="text-2xl sm:text-3xl lg:text-4xl font-bold mb-2">About AI Evaluation Dashboard</h1>
36
- <p className="text-lg sm:text-xl text-muted-foreground">
37
- A comprehensive platform for documenting and sharing AI system evaluations
38
- </p>
39
- </div>
40
 
41
- <div className="grid gap-6">
42
- <Card>
43
- <CardHeader>
44
- <CardTitle>Project Goals</CardTitle>
45
- <CardDescription>
46
- Our mission is to advance responsible AI development through transparent evaluation
47
- </CardDescription>
48
- </CardHeader>
49
- <CardContent className="space-y-4">
50
- <div className="grid gap-3">
51
- <div className="flex items-start gap-3">
52
- <div className="w-2 h-2 bg-blue-500 rounded-full mt-2 flex-shrink-0"></div>
53
- <div>
54
- <h4 className="font-semibold">Standardize AI Evaluation Reporting</h4>
55
- <p className="text-sm text-muted-foreground">
56
- Provide a consistent framework for documenting AI system capabilities and limitations across different models and platforms.
57
- </p>
 
 
58
  </div>
59
- </div>
60
- <div className="flex items-start gap-3">
61
- <div className="w-2 h-2 bg-green-500 rounded-full mt-2 flex-shrink-0"></div>
62
- <div>
63
- <h4 className="font-semibold">Facilitate Transparency</h4>
64
- <p className="text-sm text-muted-foreground">
65
- Enable AI developers and researchers to share detailed evaluation results in an accessible, standardized format.
66
- </p>
 
 
 
 
 
 
 
 
 
67
  </div>
68
  </div>
69
- <div className="flex items-start gap-3">
70
- <div className="w-2 h-2 bg-purple-500 rounded-full mt-2 flex-shrink-0"></div>
71
- <div>
72
- <h4 className="font-semibold">Enable Comparative Analysis</h4>
73
- <p className="text-sm text-muted-foreground">
74
- Support side-by-side comparison of AI systems across multiple dimensions including capabilities and risks.
75
- </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  </div>
77
  </div>
78
- <div className="flex items-start gap-3">
79
- <div className="w-2 h-2 bg-orange-500 rounded-full mt-2 flex-shrink-0"></div>
 
 
 
 
 
 
 
 
 
 
80
  <div>
81
- <h4 className="font-semibold">Support Research and Policy</h4>
82
- <p className="text-sm text-muted-foreground">
83
- Consolidate evaluation data to inform AI research directions and policy development.
84
- </p>
 
 
 
 
 
 
 
 
85
  </div>
86
- </div>
87
- <div className="flex items-start gap-3">
88
- <div className="w-2 h-2 bg-red-500 rounded-full mt-2 flex-shrink-0"></div>
89
  <div>
90
- <h4 className="font-semibold">Promote Responsible AI Development</h4>
91
- <p className="text-sm text-muted-foreground">
92
- Encourage comprehensive risk assessment and responsible deployment practices through structured evaluation.
93
- </p>
 
 
 
 
 
 
 
 
 
 
94
  </div>
95
  </div>
96
- </div>
97
- </CardContent>
98
- </Card>
99
-
100
- {/* EvalEval link removed from page body per request; footer includes external link instead */}
101
 
102
- <Card>
103
- <CardHeader>
104
- <CardTitle>Standards and Frameworks</CardTitle>
105
- <CardDescription>
106
- Built on established international standards for AI evaluation
107
- </CardDescription>
108
- </CardHeader>
109
- <CardContent className="space-y-4">
110
- <div className="grid gap-4 md:grid-cols-2">
111
- <div className="p-4 border rounded-lg">
112
- <div className="flex items-center gap-2 mb-2">
113
- <Badge variant="destructive">Risk Assessment</Badge>
 
 
 
114
  </div>
115
- <h4 className="font-semibold mb-2">NIST AI 600-1</h4>
116
- <p className="text-sm text-muted-foreground mb-3">
117
- Risk categories are derived from the NIST AI Risk Management Framework (AI RMF 1.0), providing a comprehensive approach to identifying and managing AI-related risks.
118
- </p>
119
- <Link href="https://nvlpubs.nist.gov/nistpubs/ai/NIST.AI.600-1.pdf" target="_blank">
120
- <Button variant="outline" size="sm">
121
- <ExternalLink className="mr-2 h-3 w-3" />
122
- Learn More
123
- </Button>
124
- </Link>
125
- </div>
126
- <div className="p-4 border rounded-lg">
127
- <div className="flex items-center gap-2 mb-2">
128
- <Badge variant="default">Capabilities</Badge>
129
  </div>
130
- <h4 className="font-semibold mb-2">OECD AI Classification</h4>
131
- <p className="text-sm text-muted-foreground mb-3">
132
- Capability categories are based on the OECD AI Classification Framework, ensuring alignment with international standards for AI system categorization.
133
- </p>
134
- <Link href="https://www.oecd.org/en/publications/introducing-the-oecd-ai-capability-indicators_be745f04-en/full-report/component-4.html#chapter-d1e230-f85c23a209" target="_blank">
135
- <Button variant="outline" size="sm">
136
- <ExternalLink className="mr-2 h-3 w-3" />
137
- Learn More
138
- </Button>
139
- </Link>
140
  </div>
141
- </div>
142
- </CardContent>
143
- </Card>
144
 
145
- <Card>
146
- <CardHeader>
147
- <CardTitle>For Contributors</CardTitle>
148
- <CardDescription>
149
- How to contribute to the evaluation framework
150
- </CardDescription>
151
- </CardHeader>
152
- <CardContent className="space-y-4">
153
- <div className="p-4 bg-muted rounded-lg">
154
- <h4 className="font-semibold mb-2">Schema-Driven Architecture</h4>
155
- <p className="text-sm text-muted-foreground mb-3">
156
- All evaluation categories, form fields, and data structures are centrally managed in the <code className="bg-background px-1 py-0.5 rounded">schema/</code> folder. This is the primary location for making structural changes to the evaluation framework.
157
- </p>
158
- <div className="space-y-2 text-sm">
159
- <div><code className="bg-background px-2 py-1 rounded">schema/evaluation-schema.json</code> - Evaluation categories and types</div>
160
- <div><code className="bg-background px-2 py-1 rounded">schema/output-schema.json</code> - Complete data structure</div>
161
- <div><code className="bg-background px-2 py-1 rounded">schema/system-info-schema.json</code> - Form field options</div>
162
- <div><code className="bg-background px-2 py-1 rounded">schema/category-details.json</code> - Detailed descriptions</div>
163
- </div>
164
- </div>
165
- <div className="p-4 bg-muted rounded-lg">
166
- <h4 className="font-semibold mb-2">Adding Evaluations</h4>
167
- <p className="text-sm text-muted-foreground">
168
- Evaluation data files are stored in <code className="bg-background px-1 py-0.5 rounded">public/evaluations/</code> as JSON files. Each file represents a complete evaluation of an AI system and must conform to the schema.
169
- </p>
170
- </div>
171
- <Link href="https://huggingface.co/spaces/evaleval/general-eval-card/tree/main/schema" target="_blank">
172
- <Button className="w-full flex items-center justify-center gap-2">
173
- <img src="https://huggingface.co/front/assets/huggingface_logo.svg" alt="Hugging Face" className="h-4 w-4" />
174
- View on Hugging Face
175
  </Button>
176
  </Link>
177
- </CardContent>
178
- </Card>
179
- </div>
180
-
181
- <Separator className="my-8" />
182
-
183
- <div className="text-center text-sm text-muted-foreground">
184
- <p className="mt-2">AI Evaluation Dashboard is an open-source project dedicated to advancing responsible AI development — built with ❤️ by the EvalEval Coalition.</p>
185
- <p className="mt-2 flex items-center justify-center gap-3">
186
- <img src="https://evalevalai.com/assets/img/logo-square.png" alt="EvalEval" className="h-8 w-8 rounded" />
187
- <span>Learn more about EvalEval: <Link href="https://evalevalai.com/" target="_blank">evalevalai.com</Link></span>
188
- </p>
189
  </div>
190
  </div>
191
  )
 
5
  import { Separator } from "@/components/ui/separator"
6
  import { Button } from "@/components/ui/button"
7
  import Link from "next/link"
8
+ import { ExternalLink } from "lucide-react"
9
+ import { Navigation } from "@/components/navigation"
10
+ import { PageHeader } from "@/components/page-header"
11
 
12
  export default function AboutPage() {
 
 
13
  return (
14
+ <div className="min-h-screen bg-background">
15
+ <Navigation />
16
+
17
+ <PageHeader
18
+ title="About AI Evaluation Dashboard"
19
+ description="A comprehensive platform for documenting and sharing AI system evaluations with transparency and rigor."
20
+ />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
+ <div className="container mx-auto px-4 sm:px-6 py-6 max-w-4xl">
23
+ <div className="grid gap-6">
24
+ <Card>
25
+ <CardHeader>
26
+ <CardTitle>Project Goals</CardTitle>
27
+ <CardDescription>
28
+ Our mission is to advance responsible AI development through transparent evaluation
29
+ </CardDescription>
30
+ </CardHeader>
31
+ <CardContent className="space-y-4">
32
+ <div className="grid gap-3">
33
+ <div className="flex items-start gap-3">
34
+ <div className="w-2 h-2 bg-primary rounded-full mt-2 flex-shrink-0" />
35
+ <div>
36
+ <h4 className="font-medium">Comprehensive Evaluation Framework</h4>
37
+ <p className="text-sm text-muted-foreground">
38
+ Support structured evaluation across 20+ categories covering capabilities and risks
39
+ </p>
40
+ </div>
41
  </div>
42
+ <div className="flex items-start gap-3">
43
+ <div className="w-2 h-2 bg-primary rounded-full mt-2 flex-shrink-0" />
44
+ <div>
45
+ <h4 className="font-medium">Transparency & Accountability</h4>
46
+ <p className="text-sm text-muted-foreground">
47
+ Promote open documentation of AI system capabilities, limitations, and risks
48
+ </p>
49
+ </div>
50
+ </div>
51
+ <div className="flex items-start gap-3">
52
+ <div className="w-2 h-2 bg-primary rounded-full mt-2 flex-shrink-0" />
53
+ <div>
54
+ <h4 className="font-medium">Industry Standards</h4>
55
+ <p className="text-sm text-muted-foreground">
56
+ Facilitate adoption of consistent evaluation practices across organizations
57
+ </p>
58
+ </div>
59
  </div>
60
  </div>
61
+ </CardContent>
62
+ </Card>
63
+
64
+ <Card>
65
+ <CardHeader>
66
+ <CardTitle>Key Features</CardTitle>
67
+ <CardDescription>
68
+ Tools and capabilities that support comprehensive AI evaluation
69
+ </CardDescription>
70
+ </CardHeader>
71
+ <CardContent>
72
+ <div className="grid gap-4 sm:grid-cols-2">
73
+ <div className="space-y-2">
74
+ <Badge variant="secondary" className="mb-2">Evaluation</Badge>
75
+ <ul className="space-y-1 text-sm">
76
+ <li>• Structured evaluation forms</li>
77
+ <li>• Multi-modal system support</li>
78
+ <li>• Evidence-based assessments</li>
79
+ <li>• Category-specific questions</li>
80
+ </ul>
81
+ </div>
82
+ <div className="space-y-2">
83
+ <Badge variant="secondary" className="mb-2">Analytics</Badge>
84
+ <ul className="space-y-1 text-sm">
85
+ <li>• Completeness tracking</li>
86
+ <li>• Performance benchmarking</li>
87
+ <li>• Risk area identification</li>
88
+ <li>• Comparative analysis</li>
89
+ </ul>
90
+ </div>
91
+ <div className="space-y-2">
92
+ <Badge variant="secondary" className="mb-2">Documentation</Badge>
93
+ <ul className="space-y-1 text-sm">
94
+ <li>• Standardized reporting</li>
95
+ <li>• Evidence management</li>
96
+ <li>• Version tracking</li>
97
+ <li>• Export capabilities</li>
98
+ </ul>
99
+ </div>
100
+ <div className="space-y-2">
101
+ <Badge variant="secondary" className="mb-2">Collaboration</Badge>
102
+ <ul className="space-y-1 text-sm">
103
+ <li>• Team evaluation workflows</li>
104
+ <li>• Review processes</li>
105
+ <li>• Stakeholder engagement</li>
106
+ <li>• Public transparency</li>
107
+ </ul>
108
  </div>
109
  </div>
110
+ </CardContent>
111
+ </Card>
112
+
113
+ <Card>
114
+ <CardHeader>
115
+ <CardTitle>Evaluation Categories</CardTitle>
116
+ <CardDescription>
117
+ Comprehensive coverage across capabilities and risk areas
118
+ </CardDescription>
119
+ </CardHeader>
120
+ <CardContent>
121
+ <div className="grid gap-6 sm:grid-cols-2">
122
  <div>
123
+ <h4 className="font-medium mb-3 text-primary">Capability Areas</h4>
124
+ <div className="flex flex-wrap gap-2">
125
+ <Badge variant="outline">Language Communication</Badge>
126
+ <Badge variant="outline">Problem Solving</Badge>
127
+ <Badge variant="outline">Creativity Innovation</Badge>
128
+ <Badge variant="outline">Learning Memory</Badge>
129
+ <Badge variant="outline">Social Intelligence</Badge>
130
+ <Badge variant="outline">Perception Vision</Badge>
131
+ <Badge variant="outline">Physical Manipulation</Badge>
132
+ <Badge variant="outline">Metacognition</Badge>
133
+ <Badge variant="outline">Robotic Intelligence</Badge>
134
+ </div>
135
  </div>
 
 
 
136
  <div>
137
+ <h4 className="font-medium mb-3 text-destructive">Risk Areas</h4>
138
+ <div className="flex flex-wrap gap-2">
139
+ <Badge variant="outline">Harmful Content</Badge>
140
+ <Badge variant="outline">Information Integrity</Badge>
141
+ <Badge variant="outline">Privacy Data</Badge>
142
+ <Badge variant="outline">Bias Fairness</Badge>
143
+ <Badge variant="outline">Security Robustness</Badge>
144
+ <Badge variant="outline">Dangerous Capabilities</Badge>
145
+ <Badge variant="outline">Human AI Interaction</Badge>
146
+ <Badge variant="outline">Environmental Impact</Badge>
147
+ <Badge variant="outline">Economic Displacement</Badge>
148
+ <Badge variant="outline">Governance Accountability</Badge>
149
+ <Badge variant="outline">Value Chain</Badge>
150
+ </div>
151
  </div>
152
  </div>
153
+ </CardContent>
154
+ </Card>
 
 
 
155
 
156
+ <Card>
157
+ <CardHeader>
158
+ <CardTitle>Getting Started</CardTitle>
159
+ <CardDescription>
160
+ Begin evaluating AI systems with our structured approach
161
+ </CardDescription>
162
+ </CardHeader>
163
+ <CardContent className="space-y-4">
164
+ <div className="grid gap-4 sm:grid-cols-3">
165
+ <div className="text-center p-4 border rounded-lg">
166
+ <div className="w-8 h-8 bg-primary text-primary-foreground rounded-full flex items-center justify-center mx-auto mb-2 text-sm font-bold">
167
+ 1
168
+ </div>
169
+ <h4 className="font-medium mb-1">Create Evaluation</h4>
170
+ <p className="text-xs text-muted-foreground">Start a new evaluation for your AI system</p>
171
  </div>
172
+ <div className="text-center p-4 border rounded-lg">
173
+ <div className="w-8 h-8 bg-primary text-primary-foreground rounded-full flex items-center justify-center mx-auto mb-2 text-sm font-bold">
174
+ 2
175
+ </div>
176
+ <h4 className="font-medium mb-1">Complete Assessment</h4>
177
+ <p className="text-xs text-muted-foreground">Answer questions across relevant categories</p>
178
+ </div>
179
+ <div className="text-center p-4 border rounded-lg">
180
+ <div className="w-8 h-8 bg-primary text-primary-foreground rounded-full flex items-center justify-center mx-auto mb-2 text-sm font-bold">
181
+ 3
182
+ </div>
183
+ <h4 className="font-medium mb-1">Review & Share</h4>
184
+ <p className="text-xs text-muted-foreground">Analyze results and share with stakeholders</p>
 
185
  </div>
 
 
 
 
 
 
 
 
 
 
186
  </div>
187
+ </CardContent>
188
+ </Card>
 
189
 
190
+ <Separator />
191
+
192
+ <div className="text-center space-y-4">
193
+ <h3 className="text-lg font-semibold">Ready to get started?</h3>
194
+ <p className="text-muted-foreground">
195
+ Create your first evaluation card and begin documenting your AI system's capabilities and risks.
196
+ </p>
197
+ <Link href="/">
198
+ <Button size="lg" className="gap-2">
199
+ Start Evaluating
200
+ <ExternalLink className="h-4 w-4" />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  </Button>
202
  </Link>
203
+ </div>
204
+ </div>
 
 
 
 
 
 
 
 
 
 
205
  </div>
206
  </div>
207
  )
app/analytics/page-new.tsx ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client"
2
+
3
+ import { useState, useEffect } from "react"
4
+ import AnalyticsDashboard from "@/components/analytics-dashboard"
5
+ import { Navigation } from "@/components/navigation"
6
+ import { PageHeader } from "@/components/page-header"
7
+
8
+ interface Evaluation {
9
+ id: string
10
+ name: string
11
+ organization: string
12
+ overallScore: number
13
+ modality: string[]
14
+ submittedDate: string
15
+ categoryEvaluations?: {
16
+ [categoryId: string]: {
17
+ benchmarkAnswers?: { [questionId: string]: string }
18
+ processAnswers?: { [questionId: string]: string }
19
+ }
20
+ }
21
+ }
22
+
23
+ const loadEvaluationData = async (): Promise<Evaluation[]> => {
24
+ const evaluationFiles = [
25
+ "/evaluations/gpt-4-turbo.json",
26
+ "/evaluations/claude-3-sonnet.json",
27
+ "/evaluations/gemini-pro.json",
28
+ "/evaluations/fraud-detector.json"
29
+ ]
30
+
31
+ const evaluations: Evaluation[] = []
32
+
33
+ for (const file of evaluationFiles) {
34
+ try {
35
+ const response = await fetch(file)
36
+ if (!response.ok) continue
37
+
38
+ const data = await response.json()
39
+
40
+ // Calculate overall score based on evaluation completeness
41
+ const totalQuestions = Object.values(data.categoryEvaluations || {}).reduce((acc: number, catEval: any) => {
42
+ const benchmarkCount = Object.keys(catEval.benchmarkAnswers || {}).length
43
+ const processCount = Object.keys(catEval.processAnswers || {}).length
44
+ return acc + benchmarkCount + processCount
45
+ }, 0)
46
+
47
+ const answeredQuestions = Object.values(data.categoryEvaluations || {}).reduce((acc: number, catEval: any) => {
48
+ const benchmarkAnswered = Object.values(catEval.benchmarkAnswers || {}).filter((answer: any) =>
49
+ answer !== null && answer !== undefined && answer !== ""
50
+ ).length
51
+ const processAnswered = Object.values(catEval.processAnswers || {}).filter((answer: any) =>
52
+ answer !== null && answer !== undefined && answer !== ""
53
+ ).length
54
+ return acc + benchmarkAnswered + processAnswered
55
+ }, 0)
56
+
57
+ const overallScore = totalQuestions > 0 ? Math.round((answeredQuestions / totalQuestions) * 100) : 0
58
+
59
+ const evaluation: Evaluation = {
60
+ id: data.id || file.split('/').pop()?.replace('.json', '') || 'unknown',
61
+ name: data.systemName || 'Unknown System',
62
+ organization: data.provider || 'Unknown Provider',
63
+ overallScore,
64
+ modality: [
65
+ ...(data.inputModalities || []),
66
+ ...(data.outputModalities || [])
67
+ ].filter((v, i, a) => a.indexOf(v) === i), // Remove duplicates
68
+ submittedDate: data.evaluationDate || new Date().toISOString().split('T')[0],
69
+ categoryEvaluations: data.categoryEvaluations
70
+ }
71
+
72
+ evaluations.push(evaluation)
73
+ } catch (error) {
74
+ console.error(`Failed to load ${file}:`, error)
75
+ continue
76
+ }
77
+ }
78
+
79
+ return evaluations
80
+ }
81
+
82
+ export default function AnalyticsPage() {
83
+ const [evaluations, setEvaluations] = useState<Evaluation[]>([])
84
+ const [loading, setLoading] = useState(true)
85
+
86
+ useEffect(() => {
87
+ const loadData = async () => {
88
+ try {
89
+ const data = await loadEvaluationData()
90
+ setEvaluations(data)
91
+ } catch (error) {
92
+ console.error("Failed to load evaluation data:", error)
93
+ } finally {
94
+ setLoading(false)
95
+ }
96
+ }
97
+ loadData()
98
+ }, [])
99
+
100
+ if (loading) {
101
+ return (
102
+ <div className="min-h-screen bg-background">
103
+ <Navigation />
104
+ <div className="flex items-center justify-center min-h-[60vh]">
105
+ <div className="text-center">
106
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4"></div>
107
+ <p className="text-muted-foreground">Loading analytics...</p>
108
+ </div>
109
+ </div>
110
+ </div>
111
+ )
112
+ }
113
+
114
+ return (
115
+ <div className="min-h-screen bg-background">
116
+ <Navigation />
117
+
118
+ <PageHeader
119
+ title="Analytics & Leaderboards"
120
+ description="Explore evaluation completeness across models and categories with comprehensive analytics and insights."
121
+ />
122
+
123
+ <div className="container mx-auto px-4 sm:px-6 py-6">
124
+ <AnalyticsDashboard evaluations={evaluations} />
125
+ </div>
126
+ </div>
127
+ )
128
+ }
app/analytics/page-old.tsx ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client"
2
+
3
+ import { useState, useEffect } from "react"
4
+ import AnalyticsDashboard from "@/components/analytics-dashboard"
5
+ import { Navigation } from "@/components/navigation"
6
+ import { PageHeader } from "@/components/page-header"
7
+
8
+ interface Evaluation {
9
+ id: string
10
+ name: string
11
+ organization: string
12
+ overallScore: number
13
+ modality: string[]
14
+ submittedDate: string
15
+ categoryEvaluations?: {
16
+ [categoryId: string]: {
17
+ benchmarkAnswers?: { [questionId: string]: string }
18
+ processAnswers?: { [questionId: string]: string }
19
+ }
20
+ }
21
+ }
22
+
23
+ const loadEvaluationData = async (): Promise<Evaluation[]> => {
24
+ const evaluationFiles = [
25
+ "/evaluations/gpt-4-turbo.json",
26
+ "/evaluations/claude-3-sonnet.json",
27
+ "/evaluations/gemini-pro.json",
28
+ "/evaluations/fraud-detector.json",
29
+ ]
30
+
31
+ const additionalFiles = []
32
+ for (let i = 1; i <= 10; i++) {
33
+ additionalFiles.push(`/evaluations/eval-${Date.now() - i * 86400000}.json`)
34
+ }
35
+
36
+ const allFiles = [...evaluationFiles, ...additionalFiles]
37
+ const evaluations: Evaluation[] = []
38
+
39
+ for (const file of allFiles) {
40
+ try {
41
+ const response = await fetch(file)
42
+ if (!response.ok) continue
43
+
44
+ const data = await response.json()
45
+
46
+ // Calculate overall score based on completion percentage
47
+ let overallScore = 0
48
+ if (data.categoryEvaluations) {
49
+ const allCategories = Object.keys(data.categoryEvaluations)
50
+ const categoryScores = allCategories.map(categoryId => {
51
+ const categoryData = data.categoryEvaluations[categoryId]
52
+ if (!categoryData) return 0
53
+
54
+ // Count total questions and answered questions
55
+ const benchmarkAnswers = categoryData.benchmarkAnswers || {}
56
+ const processAnswers = categoryData.processAnswers || {}
57
+
58
+ const allAnswers = { ...benchmarkAnswers, ...processAnswers }
59
+ const totalQuestions = Object.keys(allAnswers).length
60
+ if (totalQuestions === 0) return 0
61
+
62
+ // Count answered questions (not N/A, null, undefined, or empty)
63
+ const answeredQuestions = Object.values(allAnswers).filter(
64
+ (answer: any) => answer && answer !== "N/A" && String(answer).trim() !== ""
65
+ ).length
66
+
67
+ return (answeredQuestions / totalQuestions) * 100
68
+ })
69
+
70
+ overallScore = categoryScores.length > 0
71
+ ? categoryScores.reduce((sum, score) => sum + score, 0) / categoryScores.length
72
+ : 0
73
+ }
74
+
75
+ const evaluation: Evaluation = {
76
+ id: data.id || `eval-${Date.now()}`,
77
+ name: data.systemName || "Unknown System",
78
+ organization: data.provider || "Unknown Provider",
79
+ overallScore,
80
+ modality: [...(data.inputModalities || ["Text"]), ...(data.outputModalities || ["Text"])],
81
+ submittedDate: data.evaluationDate || new Date().toISOString().split("T")[0],
82
+ categoryEvaluations: data.categoryEvaluations
83
+ }
84
+
85
+ evaluations.push(evaluation)
86
+ } catch (error) {
87
+ console.error(`Failed to load evaluation from ${file}:`, error)
88
+ }
89
+ }
90
+
91
+ return evaluations
92
+ }
93
+
94
+ export default function AnalyticsPage() {
95
+ const { theme, setTheme } = useTheme()
96
+ const [evaluations, setEvaluations] = useState<Evaluation[]>([])
97
+ const [loading, setLoading] = useState(true)
98
+
99
+ useEffect(() => {
100
+ const loadData = async () => {
101
+ try {
102
+ const data = await loadEvaluationData()
103
+ setEvaluations(data)
104
+ } catch (error) {
105
+ console.error("Failed to load evaluation data:", error)
106
+ } finally {
107
+ setLoading(false)
108
+ }
109
+ }
110
+ loadData()
111
+ }, [])
112
+
113
+ if (loading) {
114
+ return (
115
+ <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">
116
+ <div className="text-center">
117
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4"></div>
118
+ <p className="text-muted-foreground">Loading analytics...</p>
119
+ </div>
120
+ </div>
121
+ )
122
+ }
123
+
124
+ return (
125
+ <div className="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-950 dark:to-slate-900">
126
+ <header className="border-b bg-card/80 backdrop-blur-sm">
127
+ <div className="container mx-auto px-4 sm:px-6 py-4">
128
+ <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3">
129
+ <div>
130
+ <h1 className="text-xl sm:text-2xl font-bold font-heading text-foreground">Analytics & Leaderboards</h1>
131
+ <p className="text-sm text-muted-foreground">Explore evaluation completeness across models and categories</p>
132
+ </div>
133
+ <div className="flex items-center gap-2 sm:gap-3">
134
+ <Link href="/">
135
+ <Button variant="ghost" size="sm" className="gap-2">
136
+ <Home className="h-4 w-4" />
137
+ <span className="hidden sm:inline">Dashboard</span>
138
+ </Button>
139
+ </Link>
140
+ <Link href="/about">
141
+ <Button variant="ghost" size="sm" className="gap-2">
142
+ <Info className="h-4 w-4" />
143
+ <span className="hidden sm:inline">About</span>
144
+ </Button>
145
+ </Link>
146
+ <Button
147
+ variant="ghost"
148
+ size="sm"
149
+ onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
150
+ className="h-9 w-9 p-0"
151
+ >
152
+ <Sun className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
153
+ <Moon className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
154
+ <span className="sr-only">Toggle theme</span>
155
+ </Button>
156
+ </div>
157
+ </div>
158
+ </div>
159
+ </header>
160
+
161
+ <div className="container mx-auto px-4 py-8">
162
+ <AnalyticsDashboard evaluations={evaluations} />
163
+ </div>
164
+ </div>
165
+ )
166
+ }
app/analytics/page.tsx CHANGED
@@ -2,10 +2,8 @@
2
 
3
  import { useState, useEffect } from "react"
4
  import AnalyticsDashboard from "@/components/analytics-dashboard"
5
- import { Button } from "@/components/ui/button"
6
- import { Home, Info, Moon, Sun } from "lucide-react"
7
- import Link from "next/link"
8
- import { useTheme } from "next-themes"
9
 
10
  interface Evaluation {
11
  id: string
@@ -27,66 +25,54 @@ const loadEvaluationData = async (): Promise<Evaluation[]> => {
27
  "/evaluations/gpt-4-turbo.json",
28
  "/evaluations/claude-3-sonnet.json",
29
  "/evaluations/gemini-pro.json",
30
- "/evaluations/fraud-detector.json",
31
  ]
32
 
33
- const additionalFiles = []
34
- for (let i = 1; i <= 10; i++) {
35
- additionalFiles.push(`/evaluations/eval-${Date.now() - i * 86400000}.json`)
36
- }
37
-
38
- const allFiles = [...evaluationFiles, ...additionalFiles]
39
  const evaluations: Evaluation[] = []
40
 
41
- for (const file of allFiles) {
42
  try {
43
  const response = await fetch(file)
44
  if (!response.ok) continue
45
 
46
  const data = await response.json()
47
-
48
- // Calculate overall score based on completion percentage
49
- let overallScore = 0
50
- if (data.categoryEvaluations) {
51
- const allCategories = Object.keys(data.categoryEvaluations)
52
- const categoryScores = allCategories.map(categoryId => {
53
- const categoryData = data.categoryEvaluations[categoryId]
54
- if (!categoryData) return 0
55
-
56
- // Count total questions and answered questions
57
- const benchmarkAnswers = categoryData.benchmarkAnswers || {}
58
- const processAnswers = categoryData.processAnswers || {}
59
-
60
- const allAnswers = { ...benchmarkAnswers, ...processAnswers }
61
- const totalQuestions = Object.keys(allAnswers).length
62
- if (totalQuestions === 0) return 0
63
-
64
- // Count answered questions (not N/A, null, undefined, or empty)
65
- const answeredQuestions = Object.values(allAnswers).filter(
66
- (answer: any) => answer && answer !== "N/A" && String(answer).trim() !== ""
67
- ).length
68
-
69
- return (answeredQuestions / totalQuestions) * 100
70
- })
71
-
72
- overallScore = categoryScores.length > 0
73
- ? categoryScores.reduce((sum, score) => sum + score, 0) / categoryScores.length
74
- : 0
75
- }
76
 
77
  const evaluation: Evaluation = {
78
- id: data.id || `eval-${Date.now()}`,
79
- name: data.systemName || "Unknown System",
80
- organization: data.provider || "Unknown Provider",
81
  overallScore,
82
- modality: [...(data.inputModalities || ["Text"]), ...(data.outputModalities || ["Text"])],
83
- submittedDate: data.evaluationDate || new Date().toISOString().split("T")[0],
 
 
 
84
  categoryEvaluations: data.categoryEvaluations
85
  }
86
 
87
  evaluations.push(evaluation)
88
  } catch (error) {
89
- console.error(`Failed to load evaluation from ${file}:`, error)
 
90
  }
91
  }
92
 
@@ -94,7 +80,6 @@ const loadEvaluationData = async (): Promise<Evaluation[]> => {
94
  }
95
 
96
  export default function AnalyticsPage() {
97
- const { theme, setTheme } = useTheme()
98
  const [evaluations, setEvaluations] = useState<Evaluation[]>([])
99
  const [loading, setLoading] = useState(true)
100
 
@@ -114,53 +99,28 @@ export default function AnalyticsPage() {
114
 
115
  if (loading) {
116
  return (
117
- <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">
118
- <div className="text-center">
119
- <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4"></div>
120
- <p className="text-muted-foreground">Loading analytics...</p>
 
 
 
121
  </div>
122
  </div>
123
  )
124
  }
125
 
126
  return (
127
- <div className="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-950 dark:to-slate-900">
128
- <header className="border-b bg-card/80 backdrop-blur-sm">
129
- <div className="container mx-auto px-4 sm:px-6 py-4">
130
- <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3">
131
- <div>
132
- <h1 className="text-xl sm:text-2xl font-bold font-heading text-foreground">Analytics & Leaderboards</h1>
133
- <p className="text-sm text-muted-foreground">Explore evaluation completeness across models and categories</p>
134
- </div>
135
- <div className="flex items-center gap-2 sm:gap-3">
136
- <Link href="/">
137
- <Button variant="ghost" size="sm" className="gap-2">
138
- <Home className="h-4 w-4" />
139
- <span className="hidden sm:inline">Dashboard</span>
140
- </Button>
141
- </Link>
142
- <Link href="/about">
143
- <Button variant="ghost" size="sm" className="gap-2">
144
- <Info className="h-4 w-4" />
145
- <span className="hidden sm:inline">About</span>
146
- </Button>
147
- </Link>
148
- <Button
149
- variant="ghost"
150
- size="sm"
151
- onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
152
- className="h-9 w-9 p-0"
153
- >
154
- <Sun className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
155
- <Moon className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
156
- <span className="sr-only">Toggle theme</span>
157
- </Button>
158
- </div>
159
- </div>
160
- </div>
161
- </header>
162
-
163
- <div className="container mx-auto px-4 py-8">
164
  <AnalyticsDashboard evaluations={evaluations} />
165
  </div>
166
  </div>
 
2
 
3
  import { useState, useEffect } from "react"
4
  import AnalyticsDashboard from "@/components/analytics-dashboard"
5
+ import { Navigation } from "@/components/navigation"
6
+ import { PageHeader } from "@/components/page-header"
 
 
7
 
8
  interface Evaluation {
9
  id: string
 
25
  "/evaluations/gpt-4-turbo.json",
26
  "/evaluations/claude-3-sonnet.json",
27
  "/evaluations/gemini-pro.json",
28
+ "/evaluations/fraud-detector.json"
29
  ]
30
 
 
 
 
 
 
 
31
  const evaluations: Evaluation[] = []
32
 
33
+ for (const file of evaluationFiles) {
34
  try {
35
  const response = await fetch(file)
36
  if (!response.ok) continue
37
 
38
  const data = await response.json()
39
+
40
+ // Calculate overall score based on evaluation completeness
41
+ const totalQuestions = Object.values(data.categoryEvaluations || {}).reduce((acc: number, catEval: any) => {
42
+ const benchmarkCount = Object.keys(catEval.benchmarkAnswers || {}).length
43
+ const processCount = Object.keys(catEval.processAnswers || {}).length
44
+ return acc + benchmarkCount + processCount
45
+ }, 0)
46
+
47
+ const answeredQuestions = Object.values(data.categoryEvaluations || {}).reduce((acc: number, catEval: any) => {
48
+ const benchmarkAnswered = Object.values(catEval.benchmarkAnswers || {}).filter((answer: any) =>
49
+ answer !== null && answer !== undefined && answer !== ""
50
+ ).length
51
+ const processAnswered = Object.values(catEval.processAnswers || {}).filter((answer: any) =>
52
+ answer !== null && answer !== undefined && answer !== ""
53
+ ).length
54
+ return acc + benchmarkAnswered + processAnswered
55
+ }, 0)
56
+
57
+ const overallScore = totalQuestions > 0 ? Math.round((answeredQuestions / totalQuestions) * 100) : 0
 
 
 
 
 
 
 
 
 
 
58
 
59
  const evaluation: Evaluation = {
60
+ id: data.id || file.split('/').pop()?.replace('.json', '') || 'unknown',
61
+ name: data.systemName || 'Unknown System',
62
+ organization: data.provider || 'Unknown Provider',
63
  overallScore,
64
+ modality: [
65
+ ...(data.inputModalities || []),
66
+ ...(data.outputModalities || [])
67
+ ].filter((v, i, a) => a.indexOf(v) === i), // Remove duplicates
68
+ submittedDate: data.evaluationDate || new Date().toISOString().split('T')[0],
69
  categoryEvaluations: data.categoryEvaluations
70
  }
71
 
72
  evaluations.push(evaluation)
73
  } catch (error) {
74
+ console.error(`Failed to load ${file}:`, error)
75
+ continue
76
  }
77
  }
78
 
 
80
  }
81
 
82
  export default function AnalyticsPage() {
 
83
  const [evaluations, setEvaluations] = useState<Evaluation[]>([])
84
  const [loading, setLoading] = useState(true)
85
 
 
99
 
100
  if (loading) {
101
  return (
102
+ <div className="min-h-screen bg-background">
103
+ <Navigation />
104
+ <div className="flex items-center justify-center min-h-[60vh]">
105
+ <div className="text-center">
106
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4"></div>
107
+ <p className="text-muted-foreground">Loading analytics...</p>
108
+ </div>
109
  </div>
110
  </div>
111
  )
112
  }
113
 
114
  return (
115
+ <div className="min-h-screen bg-background">
116
+ <Navigation />
117
+
118
+ <PageHeader
119
+ title="Analytics & Leaderboards"
120
+ description="Explore evaluation completeness across models and categories with comprehensive analytics and insights."
121
+ />
122
+
123
+ <div className="container mx-auto px-4 sm:px-6 py-6">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  <AnalyticsDashboard evaluations={evaluations} />
125
  </div>
126
  </div>
app/page-new.tsx ADDED
@@ -0,0 +1,573 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client"
2
+
3
+ import { useState, useMemo, useEffect } from "react"
4
+ import { Button } from "@/components/ui/button"
5
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
6
+ import { Filter, ArrowUpDown } from "lucide-react"
7
+ import { EvaluationCard, type EvaluationCardData } from "@/components/evaluation-card"
8
+ import { getBenchmarkQuestions, getProcessQuestions } from "@/lib/schema"
9
+ import { AIEvaluationDashboard } from "@/components/ai-evaluation-dashboard"
10
+ import { Navigation } from "@/components/navigation"
11
+ import { PageHeader } from "@/components/page-header"
12
+
13
+ const loadEvaluationData = async (): Promise<EvaluationCardData[]> => {
14
+ const evaluationFiles = [
15
+ "/evaluations/gpt-4-turbo.json",
16
+ "/evaluations/claude-3-sonnet.json",
17
+ "/evaluations/gemini-pro.json",
18
+ "/evaluations/fraud-detector.json",
19
+ ]
20
+
21
+ const additionalFiles = []
22
+ for (let i = 1; i <= 10; i++) {
23
+ additionalFiles.push(`/evaluations/eval-${Date.now() - i * 86400000}.json`) // Check for files from last 10 days
24
+ }
25
+
26
+ const allFiles = [...evaluationFiles, ...additionalFiles]
27
+ const evaluations: EvaluationCardData[] = []
28
+
29
+ for (const file of allFiles) {
30
+ try {
31
+ const response = await fetch(file)
32
+ if (!response.ok) continue // Skip files that don't exist
33
+
34
+ const data = await response.json()
35
+
36
+ const cardData: EvaluationCardData = {
37
+ id: data.id || `eval-${Date.now()}`,
38
+ systemName: data.systemName || "Unknown System",
39
+ provider: data.provider || "Unknown Provider",
40
+ inputModalities: data.inputModalities || ["Text"],
41
+ outputModalities: data.outputModalities || ["Text"],
42
+ completedDate: data.evaluationDate || new Date().toISOString().split("T")[0],
43
+ applicableCategories: data.overallStats?.totalApplicable || 0,
44
+ completedCategories: data.overallStats?.totalApplicable || 0,
45
+ status:
46
+ data.overallStats?.strongCategories?.length >= (data.overallStats?.adequateCategories?.length || 0)
47
+ ? "strong"
48
+ : data.overallStats?.adequateCategories?.length >= (data.overallStats?.weakCategories?.length || 0)
49
+ ? "adequate"
50
+ : "weak",
51
+ capabilityEval: {
52
+ strong: (data.overallStats?.strongCategories || []).filter((cat: string) =>
53
+ [
54
+ "language-communication",
55
+ "social-intelligence",
56
+ "problem-solving",
57
+ "creativity-innovation",
58
+ "learning-memory",
59
+ "perception-vision",
60
+ "physical-manipulation",
61
+ "metacognition",
62
+ "robotic-intelligence",
63
+ ].includes(cat),
64
+ ).length,
65
+ adequate: (data.overallStats?.adequateCategories || []).filter((cat: string) =>
66
+ [
67
+ "language-communication",
68
+ "social-intelligence",
69
+ "problem-solving",
70
+ "creativity-innovation",
71
+ "learning-memory",
72
+ "perception-vision",
73
+ "physical-manipulation",
74
+ "metacognition",
75
+ "robotic-intelligence",
76
+ ].includes(cat),
77
+ ).length,
78
+ weak: (data.overallStats?.weakCategories || []).filter((cat: string) =>
79
+ [
80
+ "language-communication",
81
+ "social-intelligence",
82
+ "problem-solving",
83
+ "creativity-innovation",
84
+ "learning-memory",
85
+ "perception-vision",
86
+ "physical-manipulation",
87
+ "metacognition",
88
+ "robotic-intelligence",
89
+ ].includes(cat),
90
+ ).length,
91
+ insufficient: (data.overallStats?.insufficientCategories || []).filter((cat: string) =>
92
+ [
93
+ "language-communication",
94
+ "social-intelligence",
95
+ "problem-solving",
96
+ "creativity-innovation",
97
+ "learning-memory",
98
+ "perception-vision",
99
+ "physical-manipulation",
100
+ "metacognition",
101
+ "robotic-intelligence",
102
+ ].includes(cat),
103
+ ).length,
104
+ strongCategories: (data.overallStats?.strongCategories || []).filter((cat: string) =>
105
+ [
106
+ "language-communication",
107
+ "social-intelligence",
108
+ "problem-solving",
109
+ "creativity-innovation",
110
+ "learning-memory",
111
+ "perception-vision",
112
+ "physical-manipulation",
113
+ "metacognition",
114
+ "robotic-intelligence",
115
+ ].includes(cat),
116
+ ),
117
+ adequateCategories: (data.overallStats?.adequateCategories || []).filter((cat: string) =>
118
+ [
119
+ "language-communication",
120
+ "social-intelligence",
121
+ "problem-solving",
122
+ "creativity-innovation",
123
+ "learning-memory",
124
+ "perception-vision",
125
+ "physical-manipulation",
126
+ "metacognition",
127
+ "robotic-intelligence",
128
+ ].includes(cat),
129
+ ),
130
+ weakCategories: (data.overallStats?.weakCategories || []).filter((cat: string) =>
131
+ [
132
+ "language-communication",
133
+ "social-intelligence",
134
+ "problem-solving",
135
+ "creativity-innovation",
136
+ "learning-memory",
137
+ "perception-vision",
138
+ "physical-manipulation",
139
+ "metacognition",
140
+ "robotic-intelligence",
141
+ ].includes(cat),
142
+ ),
143
+ insufficientCategories: (data.overallStats?.insufficientCategories || []).filter((cat: string) =>
144
+ [
145
+ "language-communication",
146
+ "social-intelligence",
147
+ "problem-solving",
148
+ "creativity-innovation",
149
+ "learning-memory",
150
+ "perception-vision",
151
+ "physical-manipulation",
152
+ "metacognition",
153
+ "robotic-intelligence",
154
+ ].includes(cat),
155
+ ),
156
+ totalApplicable: data.overallStats?.capabilityApplicable || 0,
157
+ },
158
+ riskEval: {
159
+ strong: (data.overallStats?.strongCategories || []).filter((cat: string) =>
160
+ [
161
+ "harmful-content",
162
+ "information-integrity",
163
+ "privacy-data",
164
+ "bias-fairness",
165
+ "security-robustness",
166
+ "dangerous-capabilities",
167
+ "human-ai-interaction",
168
+ "environmental-impact",
169
+ "economic-displacement",
170
+ "governance-accountability",
171
+ "value-chain",
172
+ ].includes(cat),
173
+ ).length,
174
+ adequate: (data.overallStats?.adequateCategories || []).filter((cat: string) =>
175
+ [
176
+ "harmful-content",
177
+ "information-integrity",
178
+ "privacy-data",
179
+ "bias-fairness",
180
+ "security-robustness",
181
+ "dangerous-capabilities",
182
+ "human-ai-interaction",
183
+ "environmental-impact",
184
+ "economic-displacement",
185
+ "governance-accountability",
186
+ "value-chain",
187
+ ].includes(cat),
188
+ ).length,
189
+ weak: (data.overallStats?.weakCategories || []).filter((cat: string) =>
190
+ [
191
+ "harmful-content",
192
+ "information-integrity",
193
+ "privacy-data",
194
+ "bias-fairness",
195
+ "security-robustness",
196
+ "dangerous-capabilities",
197
+ "human-ai-interaction",
198
+ "environmental-impact",
199
+ "economic-displacement",
200
+ "governance-accountability",
201
+ "value-chain",
202
+ ].includes(cat),
203
+ ).length,
204
+ insufficient: (data.overallStats?.insufficientCategories || []).filter((cat: string) =>
205
+ [
206
+ "harmful-content",
207
+ "information-integrity",
208
+ "privacy-data",
209
+ "bias-fairness",
210
+ "security-robustness",
211
+ "dangerous-capabilities",
212
+ "human-ai-interaction",
213
+ "environmental-impact",
214
+ "economic-displacement",
215
+ "governance-accountability",
216
+ "value-chain",
217
+ ].includes(cat),
218
+ ).length,
219
+ strongCategories: (data.overallStats?.strongCategories || []).filter((cat: string) =>
220
+ [
221
+ "harmful-content",
222
+ "information-integrity",
223
+ "privacy-data",
224
+ "bias-fairness",
225
+ "security-robustness",
226
+ "dangerous-capabilities",
227
+ "human-ai-interaction",
228
+ "environmental-impact",
229
+ "economic-displacement",
230
+ "governance-accountability",
231
+ "value-chain",
232
+ ].includes(cat),
233
+ ),
234
+ adequateCategories: (data.overallStats?.adequateCategories || []).filter((cat: string) =>
235
+ [
236
+ "harmful-content",
237
+ "information-integrity",
238
+ "privacy-data",
239
+ "bias-fairness",
240
+ "security-robustness",
241
+ "dangerous-capabilities",
242
+ "human-ai-interaction",
243
+ "environmental-impact",
244
+ "economic-displacement",
245
+ "governance-accountability",
246
+ "value-chain",
247
+ ].includes(cat),
248
+ ),
249
+ weakCategories: (data.overallStats?.weakCategories || []).filter((cat: string) =>
250
+ [
251
+ "harmful-content",
252
+ "information-integrity",
253
+ "privacy-data",
254
+ "bias-fairness",
255
+ "security-robustness",
256
+ "dangerous-capabilities",
257
+ "human-ai-interaction",
258
+ "environmental-impact",
259
+ "economic-displacement",
260
+ "governance-accountability",
261
+ "value-chain",
262
+ ].includes(cat),
263
+ ),
264
+ insufficientCategories: (data.overallStats?.insufficientCategories || []).filter((cat: string) =>
265
+ [
266
+ "harmful-content",
267
+ "information-integrity",
268
+ "privacy-data",
269
+ "bias-fairness",
270
+ "security-robustness",
271
+ "dangerous-capabilities",
272
+ "human-ai-interaction",
273
+ "environmental-impact",
274
+ "economic-displacement",
275
+ "governance-accountability",
276
+ "value-chain",
277
+ ].includes(cat),
278
+ ),
279
+ totalApplicable: data.overallStats?.riskApplicable || 0,
280
+ },
281
+ priorityAreas: data.overallStats?.priorityAreas || [],
282
+ priorityDetails: (() => {
283
+ // Build a richer structure: for each area, include yes questions and negative questions (no/na) with optional reason
284
+ const pd: Record<
285
+ string,
286
+ {
287
+ yes: string[]
288
+ negative: { text: string; status: "no" | "na"; reason?: string }[]
289
+ }
290
+ > = {}
291
+ const areas = data.overallStats?.priorityAreas || []
292
+ for (const area of areas) {
293
+ const catEval = data.categoryEvaluations?.[area]
294
+ if (!catEval) continue
295
+
296
+ const yesList: string[] = []
297
+ const negList: { text: string; status: "no" | "na"; reason?: string }[] = []
298
+
299
+ // Helper to detect NA reason from category metadata
300
+ const naReasonFromMeta = (): string | undefined => {
301
+ if (typeof catEval.additionalAspects === "string" && /not applicable/i.test(catEval.additionalAspects)) {
302
+ return catEval.additionalAspects
303
+ }
304
+ // look into processSources scopes for any note
305
+ if (catEval.processSources) {
306
+ for (const entries of Object.values(catEval.processSources)) {
307
+ if (Array.isArray(entries)) {
308
+ for (const ent of entries as any[]) {
309
+ if (ent && typeof ent.scope === "string" && /not applicable/i.test(ent.scope)) {
310
+ return ent.scope
311
+ }
312
+ }
313
+ }
314
+ }
315
+ }
316
+ return undefined
317
+ }
318
+
319
+ const naMeta = naReasonFromMeta()
320
+
321
+ // check benchmarkAnswers (A1..A6)
322
+ if (catEval.benchmarkAnswers) {
323
+ for (const [qid, ans] of Object.entries(catEval.benchmarkAnswers)) {
324
+ const answer = ans
325
+ const isArray = Array.isArray(answer)
326
+ const negative = answer === "no" || (isArray && (answer as any[]).includes("no"))
327
+ const positive = answer === "yes" || (isArray && (answer as any[]).includes("yes"))
328
+ const qText = getBenchmarkQuestions().find((x) => x.id === qid)?.text || qid
329
+ if (positive) yesList.push(qText)
330
+ if (negative) {
331
+ const status = naMeta ? "na" : "no"
332
+ negList.push({ text: qText, status, reason: naMeta })
333
+ }
334
+ }
335
+ }
336
+
337
+ // check processAnswers (B1..B6)
338
+ if (catEval.processAnswers) {
339
+ for (const [qid, ans] of Object.entries(catEval.processAnswers)) {
340
+ const answer = ans
341
+ const isArray = Array.isArray(answer)
342
+ const negative = answer === "no" || (isArray && (answer as any[]).includes("no"))
343
+ const positive = answer === "yes" || (isArray && (answer as any[]).includes("yes"))
344
+ const qText = getProcessQuestions().find((x) => x.id === qid)?.text || qid
345
+ if (positive) yesList.push(qText)
346
+ if (negative) {
347
+ const status = naMeta ? "na" : "no"
348
+ negList.push({ text: qText, status, reason: naMeta })
349
+ }
350
+ }
351
+ }
352
+
353
+ if (yesList.length || negList.length) pd[area] = { yes: yesList, negative: negList }
354
+ }
355
+ return pd
356
+ })(),
357
+ }
358
+
359
+ evaluations.push(cardData)
360
+ } catch (error) {
361
+ continue
362
+ }
363
+ }
364
+
365
+ return evaluations
366
+ }
367
+
368
+ export default function HomePage() {
369
+ const [showNewEvaluation, setShowNewEvaluation] = useState(false)
370
+ const [evaluationsData, setEvaluationsData] = useState<EvaluationCardData[]>([])
371
+ const [loading, setLoading] = useState(true)
372
+
373
+ useEffect(() => {
374
+ const loadData = async () => {
375
+ const data = await loadEvaluationData()
376
+ setEvaluationsData(data)
377
+ setLoading(false)
378
+ }
379
+ loadData()
380
+ }, [])
381
+
382
+ const [sortBy, setSortBy] = useState<"date-newest" | "date-oldest" | "completeness-highest" | "completeness-lowest">("date-newest")
383
+ const [filterByProvider, setFilterByProvider] = useState<string>("all")
384
+ const [filterByModality, setFilterByModality] = useState<string>("all")
385
+
386
+ const uniqueProviders = useMemo(() => {
387
+ const providers = [...new Set(evaluationsData.map((item) => item.provider))].sort()
388
+ return providers
389
+ }, [evaluationsData])
390
+
391
+ const uniqueModalities = useMemo(() => {
392
+ // Define all possible modalities to ensure complete filter options
393
+ const allModalities = ["Text", "Image", "Audio", "Video", "Tabular", "Robotics/Action", "Other"]
394
+
395
+ // Get modalities that actually exist in the data
396
+ const existingModalities = new Set<string>()
397
+ evaluationsData.forEach((item) => {
398
+ item.inputModalities.forEach((mod) => existingModalities.add(mod))
399
+ item.outputModalities.forEach((mod) => existingModalities.add(mod))
400
+ })
401
+
402
+ // Return only modalities that exist in the data, in the order defined by allModalities
403
+ return allModalities.filter((mod) => existingModalities.has(mod))
404
+ }, [evaluationsData])
405
+
406
+ const filteredAndSortedEvaluations = useMemo(() => {
407
+ let filtered = evaluationsData
408
+
409
+ if (filterByProvider !== "all") {
410
+ filtered = filtered.filter((item) => item.provider === filterByProvider)
411
+ }
412
+
413
+ if (filterByModality !== "all") {
414
+ filtered = filtered.filter((item) =>
415
+ item.inputModalities.includes(filterByModality) ||
416
+ item.outputModalities.includes(filterByModality)
417
+ )
418
+ }
419
+
420
+ filtered = filtered.sort((a, b) => {
421
+ if (sortBy.includes("completeness")) {
422
+ const aCompleteness = (a.completedCategories / a.applicableCategories) * 100
423
+ const bCompleteness = (b.completedCategories / b.applicableCategories) * 100
424
+
425
+ if (sortBy === "completeness-highest") {
426
+ return bCompleteness - aCompleteness
427
+ } else {
428
+ return aCompleteness - bCompleteness
429
+ }
430
+ } else {
431
+ const dateA = new Date(a.completedDate)
432
+ const dateB = new Date(b.completedDate)
433
+
434
+ if (sortBy === "date-newest") {
435
+ return dateB.getTime() - dateA.getTime()
436
+ } else {
437
+ return dateA.getTime() - dateB.getTime()
438
+ }
439
+ }
440
+ })
441
+
442
+ return filtered
443
+ }, [evaluationsData, sortBy, filterByProvider, filterByModality])
444
+
445
+ const handleViewEvaluation = (id: string) => {}
446
+
447
+ const handleDeleteEvaluation = (id: string) => {
448
+ setEvaluationsData((prev) => prev.filter((evaluation) => evaluation.id !== id))
449
+ }
450
+
451
+ const handleSaveEvaluation = (newEvaluation: EvaluationCardData) => {
452
+ setEvaluationsData((prev) => [newEvaluation, ...prev])
453
+ }
454
+
455
+ if (showNewEvaluation) {
456
+ return <AIEvaluationDashboard onBack={() => setShowNewEvaluation(false)} onSaveEvaluation={handleSaveEvaluation} />
457
+ }
458
+
459
+ if (loading) {
460
+ return (
461
+ <div className="min-h-screen bg-background">
462
+ <Navigation />
463
+ <div className="flex items-center justify-center min-h-[60vh]">
464
+ <div className="text-center">
465
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4"></div>
466
+ <p className="text-muted-foreground">Loading evaluations...</p>
467
+ </div>
468
+ </div>
469
+ </div>
470
+ )
471
+ }
472
+
473
+ return (
474
+ <div className="min-h-screen bg-background">
475
+ <Navigation onNewEvaluation={() => setShowNewEvaluation(true)} />
476
+
477
+ <PageHeader
478
+ title="Evaluation Cards"
479
+ description={`Track and manage AI system evaluations across capabilities and risks. ${filteredAndSortedEvaluations.length} eval cards available.`}
480
+ />
481
+
482
+ <div className="container mx-auto px-4 sm:px-6 py-6">
483
+ <div className="space-y-6">
484
+ {/* Filters */}
485
+ <div className="flex flex-col sm:flex-row sm:flex-wrap items-start sm:items-center gap-3 sm:gap-4 p-4 bg-card rounded-lg border">
486
+ <div className="flex items-center gap-2 w-full sm:w-auto">
487
+ <ArrowUpDown className="h-4 w-4 text-muted-foreground" />
488
+ <span className="text-sm font-medium">Sort by:</span>
489
+ <Select value={sortBy} onValueChange={(value: "date-newest" | "date-oldest" | "completeness-highest" | "completeness-lowest") => setSortBy(value)}>
490
+ <SelectTrigger className="w-full sm:w-48">
491
+ <SelectValue />
492
+ </SelectTrigger>
493
+ <SelectContent>
494
+ <SelectItem value="date-newest">Date (Newest)</SelectItem>
495
+ <SelectItem value="date-oldest">Date (Oldest)</SelectItem>
496
+ <SelectItem value="completeness-highest">Completeness (Highest)</SelectItem>
497
+ <SelectItem value="completeness-lowest">Completeness (Lowest)</SelectItem>
498
+ </SelectContent>
499
+ </Select>
500
+ </div>
501
+
502
+ <div className="flex items-center gap-2 w-full sm:w-auto">
503
+ <Filter className="h-4 w-4 text-muted-foreground" />
504
+ <span className="text-sm font-medium">Provider:</span>
505
+ <Select value={filterByProvider} onValueChange={setFilterByProvider}>
506
+ <SelectTrigger className="w-full sm:w-40">
507
+ <SelectValue />
508
+ </SelectTrigger>
509
+ <SelectContent>
510
+ <SelectItem value="all">All Providers</SelectItem>
511
+ {uniqueProviders.map((provider) => (
512
+ <SelectItem key={provider} value={provider}>
513
+ {provider}
514
+ </SelectItem>
515
+ ))}
516
+ </SelectContent>
517
+ </Select>
518
+ </div>
519
+
520
+ <div className="flex items-center gap-2 w-full sm:w-auto">
521
+ <Filter className="h-4 w-4 text-muted-foreground" />
522
+ <span className="text-sm font-medium">Modality:</span>
523
+ <Select value={filterByModality} onValueChange={setFilterByModality}>
524
+ <SelectTrigger className="w-full sm:w-40">
525
+ <SelectValue />
526
+ </SelectTrigger>
527
+ <SelectContent>
528
+ <SelectItem value="all">All Modalities</SelectItem>
529
+ {uniqueModalities.map((modality) => (
530
+ <SelectItem key={modality} value={modality}>
531
+ {modality}
532
+ </SelectItem>
533
+ ))}
534
+ </SelectContent>
535
+ </Select>
536
+ </div>
537
+ </div>
538
+
539
+ {/* Results */}
540
+ {filteredAndSortedEvaluations.length > 0 ? (
541
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
542
+ {filteredAndSortedEvaluations.map((evaluation) => (
543
+ <EvaluationCard
544
+ key={evaluation.id}
545
+ evaluation={evaluation}
546
+ onView={handleViewEvaluation}
547
+ onDelete={handleDeleteEvaluation}
548
+ />
549
+ ))}
550
+ </div>
551
+ ) : (
552
+ <div className="text-center py-12">
553
+ <div className="mx-auto w-24 h-24 bg-muted rounded-full flex items-center justify-center mb-4">
554
+ <Filter className="h-8 w-8 text-muted-foreground" />
555
+ </div>
556
+ <h3 className="text-lg font-semibold mb-2">No evaluations match your filters</h3>
557
+ <p className="text-muted-foreground mb-4">Try adjusting your filter criteria to see more results</p>
558
+ <Button
559
+ variant="outline"
560
+ onClick={() => {
561
+ setFilterByProvider("all")
562
+ setFilterByModality("all")
563
+ }}
564
+ >
565
+ Clear Filters
566
+ </Button>
567
+ </div>
568
+ )}
569
+ </div>
570
+ </div>
571
+ </div>
572
+ )
573
+ }
app/page-old.tsx ADDED
@@ -0,0 +1,636 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client"
2
+
3
+ import { useState, useMemo, useEffect } from "react"
4
+ import { Button } from "@/components/ui/button"
5
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
6
+ import { Filter, ArrowUpDown } from "lucide-react"
7
+ import { EvaluationCard, type EvaluationCardData } from "@/components/evaluation-card"
8
+ import { geexport default function HomePage() {
9
+ const [showNewEvaluation, setShowNewEvaluation] = useState(false)
10
+ const [evaluationsData, setEvaluationsData] = useState<EvaluationCardData[]>([])
11
+ const [loading, setLoading] = useState(true)
12
+
13
+ useEffect(() => {
14
+ const loadData = async () => {
15
+ const data = await loadEvaluationData()
16
+ setEvaluationsData(data)
17
+ setLoading(false)
18
+ }
19
+ loadData()
20
+ }, [])tions, getProcessQuestions } from "@/lib/schema"
21
+ import { AIEvaluationDashboard } from "@/components/ai-evaluation-dashboard"
22
+ import { Navigation } from "@/components/navigation"
23
+ import { PageHeader } from "@/components/page-header"
24
+
25
+ const loadEvaluationData = async (): Promise<EvaluationCardData[]> => {
26
+ const evaluationFiles = [
27
+ "/evaluations/gpt-4-turbo.json",
28
+ "/evaluations/claude-3-sonnet.json",
29
+ "/evaluations/gemini-pro.json",
30
+ "/evaluations/fraud-detector.json",
31
+ ]
32
+
33
+ const additionalFiles = []
34
+ for (let i = 1; i <= 10; i++) {
35
+ additionalFiles.push(`/evaluations/eval-${Date.now() - i * 86400000}.json`) // Check for files from last 10 days
36
+ }
37
+
38
+ const allFiles = [...evaluationFiles, ...additionalFiles]
39
+ const evaluations: EvaluationCardData[] = []
40
+
41
+ for (const file of allFiles) {
42
+ try {
43
+ const response = await fetch(file)
44
+ if (!response.ok) continue // Skip files that don't exist
45
+
46
+ const data = await response.json()
47
+
48
+ const cardData: EvaluationCardData = {
49
+ id: data.id || `eval-${Date.now()}`,
50
+ systemName: data.systemName || "Unknown System",
51
+ provider: data.provider || "Unknown Provider",
52
+ inputModalities: data.inputModalities || ["Text"],
53
+ outputModalities: data.outputModalities || ["Text"],
54
+ completedDate: data.evaluationDate || new Date().toISOString().split("T")[0],
55
+ applicableCategories: data.overallStats?.totalApplicable || 0,
56
+ completedCategories: data.overallStats?.totalApplicable || 0,
57
+ status:
58
+ data.overallStats?.strongCategories?.length >= (data.overallStats?.adequateCategories?.length || 0)
59
+ ? "strong"
60
+ : data.overallStats?.adequateCategories?.length >= (data.overallStats?.weakCategories?.length || 0)
61
+ ? "adequate"
62
+ : "weak",
63
+ capabilityEval: {
64
+ strong: (data.overallStats?.strongCategories || []).filter((cat: string) =>
65
+ [
66
+ "language-communication",
67
+ "social-intelligence",
68
+ "problem-solving",
69
+ "creativity-innovation",
70
+ "learning-memory",
71
+ "perception-vision",
72
+ "physical-manipulation",
73
+ "metacognition",
74
+ "robotic-intelligence",
75
+ ].includes(cat),
76
+ ).length,
77
+ adequate: (data.overallStats?.adequateCategories || []).filter((cat: string) =>
78
+ [
79
+ "language-communication",
80
+ "social-intelligence",
81
+ "problem-solving",
82
+ "creativity-innovation",
83
+ "learning-memory",
84
+ "perception-vision",
85
+ "physical-manipulation",
86
+ "metacognition",
87
+ "robotic-intelligence",
88
+ ].includes(cat),
89
+ ).length,
90
+ weak: (data.overallStats?.weakCategories || []).filter((cat: string) =>
91
+ [
92
+ "language-communication",
93
+ "social-intelligence",
94
+ "problem-solving",
95
+ "creativity-innovation",
96
+ "learning-memory",
97
+ "perception-vision",
98
+ "physical-manipulation",
99
+ "metacognition",
100
+ "robotic-intelligence",
101
+ ].includes(cat),
102
+ ).length,
103
+ insufficient: (data.overallStats?.insufficientCategories || []).filter((cat: string) =>
104
+ [
105
+ "language-communication",
106
+ "social-intelligence",
107
+ "problem-solving",
108
+ "creativity-innovation",
109
+ "learning-memory",
110
+ "perception-vision",
111
+ "physical-manipulation",
112
+ "metacognition",
113
+ "robotic-intelligence",
114
+ ].includes(cat),
115
+ ).length,
116
+ strongCategories: (data.overallStats?.strongCategories || []).filter((cat: string) =>
117
+ [
118
+ "language-communication",
119
+ "social-intelligence",
120
+ "problem-solving",
121
+ "creativity-innovation",
122
+ "learning-memory",
123
+ "perception-vision",
124
+ "physical-manipulation",
125
+ "metacognition",
126
+ "robotic-intelligence",
127
+ ].includes(cat),
128
+ ),
129
+ adequateCategories: (data.overallStats?.adequateCategories || []).filter((cat: string) =>
130
+ [
131
+ "language-communication",
132
+ "social-intelligence",
133
+ "problem-solving",
134
+ "creativity-innovation",
135
+ "learning-memory",
136
+ "perception-vision",
137
+ "physical-manipulation",
138
+ "metacognition",
139
+ "robotic-intelligence",
140
+ ].includes(cat),
141
+ ),
142
+ weakCategories: (data.overallStats?.weakCategories || []).filter((cat: string) =>
143
+ [
144
+ "language-communication",
145
+ "social-intelligence",
146
+ "problem-solving",
147
+ "creativity-innovation",
148
+ "learning-memory",
149
+ "perception-vision",
150
+ "physical-manipulation",
151
+ "metacognition",
152
+ "robotic-intelligence",
153
+ ].includes(cat),
154
+ ),
155
+ insufficientCategories: (data.overallStats?.insufficientCategories || []).filter((cat: string) =>
156
+ [
157
+ "language-communication",
158
+ "social-intelligence",
159
+ "problem-solving",
160
+ "creativity-innovation",
161
+ "learning-memory",
162
+ "perception-vision",
163
+ "physical-manipulation",
164
+ "metacognition",
165
+ "robotic-intelligence",
166
+ ].includes(cat),
167
+ ),
168
+ totalApplicable: data.overallStats?.capabilityApplicable || 0,
169
+ },
170
+ riskEval: {
171
+ strong: (data.overallStats?.strongCategories || []).filter((cat: string) =>
172
+ [
173
+ "harmful-content",
174
+ "information-integrity",
175
+ "privacy-data",
176
+ "bias-fairness",
177
+ "security-robustness",
178
+ "dangerous-capabilities",
179
+ "human-ai-interaction",
180
+ "environmental-impact",
181
+ "economic-displacement",
182
+ "governance-accountability",
183
+ "value-chain",
184
+ ].includes(cat),
185
+ ).length,
186
+ adequate: (data.overallStats?.adequateCategories || []).filter((cat: string) =>
187
+ [
188
+ "harmful-content",
189
+ "information-integrity",
190
+ "privacy-data",
191
+ "bias-fairness",
192
+ "security-robustness",
193
+ "dangerous-capabilities",
194
+ "human-ai-interaction",
195
+ "environmental-impact",
196
+ "economic-displacement",
197
+ "governance-accountability",
198
+ "value-chain",
199
+ ].includes(cat),
200
+ ).length,
201
+ weak: (data.overallStats?.weakCategories || []).filter((cat: string) =>
202
+ [
203
+ "harmful-content",
204
+ "information-integrity",
205
+ "privacy-data",
206
+ "bias-fairness",
207
+ "security-robustness",
208
+ "dangerous-capabilities",
209
+ "human-ai-interaction",
210
+ "environmental-impact",
211
+ "economic-displacement",
212
+ "governance-accountability",
213
+ "value-chain",
214
+ ].includes(cat),
215
+ ).length,
216
+ insufficient: (data.overallStats?.insufficientCategories || []).filter((cat: string) =>
217
+ [
218
+ "harmful-content",
219
+ "information-integrity",
220
+ "privacy-data",
221
+ "bias-fairness",
222
+ "security-robustness",
223
+ "dangerous-capabilities",
224
+ "human-ai-interaction",
225
+ "environmental-impact",
226
+ "economic-displacement",
227
+ "governance-accountability",
228
+ "value-chain",
229
+ ].includes(cat),
230
+ ).length,
231
+ strongCategories: (data.overallStats?.strongCategories || []).filter((cat: string) =>
232
+ [
233
+ "harmful-content",
234
+ "information-integrity",
235
+ "privacy-data",
236
+ "bias-fairness",
237
+ "security-robustness",
238
+ "dangerous-capabilities",
239
+ "human-ai-interaction",
240
+ "environmental-impact",
241
+ "economic-displacement",
242
+ "governance-accountability",
243
+ "value-chain",
244
+ ].includes(cat),
245
+ ),
246
+ adequateCategories: (data.overallStats?.adequateCategories || []).filter((cat: string) =>
247
+ [
248
+ "harmful-content",
249
+ "information-integrity",
250
+ "privacy-data",
251
+ "bias-fairness",
252
+ "security-robustness",
253
+ "dangerous-capabilities",
254
+ "human-ai-interaction",
255
+ "environmental-impact",
256
+ "economic-displacement",
257
+ "governance-accountability",
258
+ "value-chain",
259
+ ].includes(cat),
260
+ ),
261
+ weakCategories: (data.overallStats?.weakCategories || []).filter((cat: string) =>
262
+ [
263
+ "harmful-content",
264
+ "information-integrity",
265
+ "privacy-data",
266
+ "bias-fairness",
267
+ "security-robustness",
268
+ "dangerous-capabilities",
269
+ "human-ai-interaction",
270
+ "environmental-impact",
271
+ "economic-displacement",
272
+ "governance-accountability",
273
+ "value-chain",
274
+ ].includes(cat),
275
+ ),
276
+ insufficientCategories: (data.overallStats?.insufficientCategories || []).filter((cat: string) =>
277
+ [
278
+ "harmful-content",
279
+ "information-integrity",
280
+ "privacy-data",
281
+ "bias-fairness",
282
+ "security-robustness",
283
+ "dangerous-capabilities",
284
+ "human-ai-interaction",
285
+ "environmental-impact",
286
+ "economic-displacement",
287
+ "governance-accountability",
288
+ "value-chain",
289
+ ].includes(cat),
290
+ ),
291
+ totalApplicable: data.overallStats?.riskApplicable || 0,
292
+ },
293
+ priorityAreas: data.overallStats?.priorityAreas || [],
294
+ priorityDetails: (() => {
295
+ // Build a richer structure: for each area, include yes questions and negative questions (no/na) with optional reason
296
+ const pd: Record<
297
+ string,
298
+ {
299
+ yes: string[]
300
+ negative: { text: string; status: "no" | "na"; reason?: string }[]
301
+ }
302
+ > = {}
303
+ const areas = data.overallStats?.priorityAreas || []
304
+ for (const area of areas) {
305
+ const catEval = data.categoryEvaluations?.[area]
306
+ if (!catEval) continue
307
+
308
+ const yesList: string[] = []
309
+ const negList: { text: string; status: "no" | "na"; reason?: string }[] = []
310
+
311
+ // Helper to detect NA reason from category metadata
312
+ const naReasonFromMeta = (): string | undefined => {
313
+ if (typeof catEval.additionalAspects === "string" && /not applicable/i.test(catEval.additionalAspects)) {
314
+ return catEval.additionalAspects
315
+ }
316
+ // look into processSources scopes for any note
317
+ if (catEval.processSources) {
318
+ for (const entries of Object.values(catEval.processSources)) {
319
+ if (Array.isArray(entries)) {
320
+ for (const ent of entries as any[]) {
321
+ if (ent && typeof ent.scope === "string" && /not applicable/i.test(ent.scope)) {
322
+ return ent.scope
323
+ }
324
+ }
325
+ }
326
+ }
327
+ }
328
+ return undefined
329
+ }
330
+
331
+ const naMeta = naReasonFromMeta()
332
+
333
+ // check benchmarkAnswers (A1..A6)
334
+ if (catEval.benchmarkAnswers) {
335
+ for (const [qid, ans] of Object.entries(catEval.benchmarkAnswers)) {
336
+ const answer = ans
337
+ const isArray = Array.isArray(answer)
338
+ const negative = answer === "no" || (isArray && (answer as any[]).includes("no"))
339
+ const positive = answer === "yes" || (isArray && (answer as any[]).includes("yes"))
340
+ const qText = getBenchmarkQuestions().find((x) => x.id === qid)?.text || qid
341
+ if (positive) yesList.push(qText)
342
+ if (negative) {
343
+ const status = naMeta ? "na" : "no"
344
+ negList.push({ text: qText, status, reason: naMeta })
345
+ }
346
+ }
347
+ }
348
+
349
+ // check processAnswers (B1..B6)
350
+ if (catEval.processAnswers) {
351
+ for (const [qid, ans] of Object.entries(catEval.processAnswers)) {
352
+ const answer = ans
353
+ const isArray = Array.isArray(answer)
354
+ const negative = answer === "no" || (isArray && (answer as any[]).includes("no"))
355
+ const positive = answer === "yes" || (isArray && (answer as any[]).includes("yes"))
356
+ const qText = getProcessQuestions().find((x) => x.id === qid)?.text || qid
357
+ if (positive) yesList.push(qText)
358
+ if (negative) {
359
+ const status = naMeta ? "na" : "no"
360
+ negList.push({ text: qText, status, reason: naMeta })
361
+ }
362
+ }
363
+ }
364
+
365
+ if (yesList.length || negList.length) pd[area] = { yes: yesList, negative: negList }
366
+ }
367
+ return pd
368
+ })(),
369
+ }
370
+
371
+ evaluations.push(cardData)
372
+ } catch (error) {
373
+ continue
374
+ }
375
+ }
376
+
377
+ return evaluations
378
+ }
379
+
380
+ export default function HomePage() {
381
+ const { theme, setTheme } = useTheme()
382
+ const [showNewEvaluation, setShowNewEvaluation] = useState(false)
383
+ const [evaluationsData, setEvaluationsData] = useState<EvaluationCardData[]>([])
384
+ const [loading, setLoading] = useState(true)
385
+
386
+ useEffect(() => {
387
+ const loadData = async () => {
388
+ const data = await loadEvaluationData()
389
+ setEvaluationsData(data)
390
+ setLoading(false)
391
+ }
392
+ loadData()
393
+ }, [])
394
+
395
+ const [sortBy, setSortBy] = useState<"date-newest" | "date-oldest" | "completeness-highest" | "completeness-lowest">("date-newest")
396
+ const [filterByProvider, setFilterByProvider] = useState<string>("all")
397
+ const [filterByModality, setFilterByModality] = useState<string>("all")
398
+
399
+ const uniqueProviders = useMemo(() => {
400
+ const providers = [...new Set(evaluationsData.map((item) => item.provider))].sort()
401
+ return providers
402
+ }, [evaluationsData])
403
+
404
+ const uniqueModalities = useMemo(() => {
405
+ // Define all possible modalities to ensure complete filter options
406
+ const allModalities = ["Text", "Image", "Audio", "Video", "Tabular", "Robotics/Action", "Other"]
407
+
408
+ // Get modalities that actually exist in the data
409
+ const existingModalities = new Set<string>()
410
+ evaluationsData.forEach((item) => {
411
+ item.inputModalities.forEach((mod) => existingModalities.add(mod))
412
+ item.outputModalities.forEach((mod) => existingModalities.add(mod))
413
+ })
414
+
415
+ // Return all predefined modalities, with existing ones first, then missing ones
416
+ const existing = allModalities.filter(mod => existingModalities.has(mod)).sort()
417
+ const missing = allModalities.filter(mod => !existingModalities.has(mod)).sort()
418
+
419
+ return [...existing, ...missing]
420
+ }, [evaluationsData])
421
+
422
+ const filteredAndSortedEvaluations = useMemo(() => {
423
+ let filtered = evaluationsData
424
+
425
+ if (filterByProvider !== "all") {
426
+ filtered = filtered.filter((item) => item.provider === filterByProvider)
427
+ }
428
+
429
+ if (filterByModality !== "all") {
430
+ filtered = filtered.filter((item) =>
431
+ item.inputModalities.includes(filterByModality) ||
432
+ item.outputModalities.includes(filterByModality)
433
+ )
434
+ }
435
+
436
+ filtered = [...filtered].sort((a, b) => {
437
+ if (sortBy === "completeness-highest" || sortBy === "completeness-lowest") {
438
+ // Calculate completeness scores for both items
439
+ const calculateCompletenessScore = (evaluation: EvaluationCardData) => {
440
+ const capTotal = evaluation.capabilityEval.strong + evaluation.capabilityEval.adequate + evaluation.capabilityEval.weak + evaluation.capabilityEval.insufficient
441
+ const riskTotal = evaluation.riskEval.strong + evaluation.riskEval.adequate + evaluation.riskEval.weak + evaluation.riskEval.insufficient
442
+ const totalItems = capTotal + riskTotal
443
+
444
+ if (totalItems === 0) return 0
445
+
446
+ const capScore = evaluation.capabilityEval.strong * 4 + evaluation.capabilityEval.adequate * 3 + evaluation.capabilityEval.weak * 2 + evaluation.capabilityEval.insufficient * 1
447
+ const riskScore = evaluation.riskEval.strong * 4 + evaluation.riskEval.adequate * 3 + evaluation.riskEval.weak * 2 + evaluation.riskEval.insufficient * 1
448
+
449
+ return Math.round(((capScore + riskScore) / (totalItems * 4)) * 100)
450
+ }
451
+
452
+ const scoreA = calculateCompletenessScore(a)
453
+ const scoreB = calculateCompletenessScore(b)
454
+
455
+ if (sortBy === "completeness-highest") {
456
+ return scoreB - scoreA
457
+ } else {
458
+ return scoreA - scoreB
459
+ }
460
+ } else {
461
+ const dateA = new Date(a.completedDate)
462
+ const dateB = new Date(b.completedDate)
463
+
464
+ if (sortBy === "date-newest") {
465
+ return dateB.getTime() - dateA.getTime()
466
+ } else {
467
+ return dateA.getTime() - dateB.getTime()
468
+ }
469
+ }
470
+ })
471
+
472
+ return filtered
473
+ }, [evaluationsData, sortBy, filterByProvider, filterByModality])
474
+
475
+ const handleViewEvaluation = (id: string) => {}
476
+
477
+ const handleDeleteEvaluation = (id: string) => {
478
+ setEvaluationsData((prev) => prev.filter((evaluation) => evaluation.id !== id))
479
+ }
480
+
481
+ const handleSaveEvaluation = (newEvaluation: EvaluationCardData) => {
482
+ setEvaluationsData((prev) => [newEvaluation, ...prev])
483
+ }
484
+
485
+ if (showNewEvaluation) {
486
+ return <AIEvaluationDashboard onBack={() => setShowNewEvaluation(false)} onSaveEvaluation={handleSaveEvaluation} />
487
+ }
488
+
489
+ if (loading) {
490
+ return (
491
+ <div className="min-h-screen bg-background flex items-center justify-center">
492
+ <div className="text-center">
493
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4"></div>
494
+ <p className="text-muted-foreground">Loading evaluations...</p>
495
+ </div>
496
+ </div>
497
+ )
498
+ }
499
+
500
+ return (
501
+ <div className="min-h-screen bg-background">
502
+ <header className="border-b bg-card">
503
+ <div className="container mx-auto px-4 sm:px-6 py-4">
504
+ <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3">
505
+ <div>
506
+ <h1 className="text-xl sm:text-2xl font-bold font-heading text-foreground">AI Evaluation Dashboard</h1>
507
+ <p className="text-sm text-muted-foreground">Manage and track your AI system evaluations</p>
508
+ </div>
509
+ <div className="flex items-center gap-2 sm:gap-3">
510
+ <Link href="/analytics">
511
+ <Button variant="ghost" size="sm" className="gap-2">
512
+ <ArrowUpDown className="h-4 w-4" />
513
+ <span className="hidden sm:inline">Analytics</span>
514
+ </Button>
515
+ </Link>
516
+ <Link href="/about">
517
+ <Button variant="ghost" size="sm" className="gap-2">
518
+ <Info className="h-4 w-4" />
519
+ <span className="hidden sm:inline">About</span>
520
+ </Button>
521
+ </Link>
522
+ <Button
523
+ variant="ghost"
524
+ size="sm"
525
+ onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
526
+ className="h-9 w-9 p-0"
527
+ >
528
+ <Sun className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
529
+ <Moon className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
530
+ <span className="sr-only">Toggle theme</span>
531
+ </Button>
532
+ <Button onClick={() => setShowNewEvaluation(true)} className="gap-2">
533
+ <Plus className="h-4 w-4" />
534
+ <span className="hidden sm:inline">New Eval Card</span>
535
+ <span className="sm:hidden">New</span>
536
+ </Button>
537
+ </div>
538
+ </div>
539
+ </div>
540
+ </header>
541
+
542
+ <div className="container mx-auto px-4 sm:px-6 py-4 sm:py-6">
543
+ <div className="space-y-6">
544
+ <div className="flex items-center justify-between">
545
+ <h2 className="text-xl font-semibold font-heading">Evaluation Cards</h2>
546
+ <p className="text-sm text-muted-foreground">{filteredAndSortedEvaluations.length} eval cards</p>
547
+ </div>
548
+
549
+ <div className="flex flex-col sm:flex-row sm:flex-wrap items-start sm:items-center gap-3 sm:gap-4 p-4 bg-card rounded-lg border">
550
+ <div className="flex items-center gap-2 w-full sm:w-auto">
551
+ <ArrowUpDown className="h-4 w-4 text-muted-foreground" />
552
+ <span className="text-sm font-medium">Sort by:</span>
553
+ <Select value={sortBy} onValueChange={(value: "date-newest" | "date-oldest" | "completeness-highest" | "completeness-lowest") => setSortBy(value)}>
554
+ <SelectTrigger className="w-full sm:w-48">
555
+ <SelectValue />
556
+ </SelectTrigger>
557
+ <SelectContent>
558
+ <SelectItem value="date-newest">Date (Newest)</SelectItem>
559
+ <SelectItem value="date-oldest">Date (Oldest)</SelectItem>
560
+ <SelectItem value="completeness-highest">Completeness (Highest)</SelectItem>
561
+ <SelectItem value="completeness-lowest">Completeness (Lowest)</SelectItem>
562
+ </SelectContent>
563
+ </Select>
564
+ </div>
565
+
566
+ <div className="flex items-center gap-2 w-full sm:w-auto">
567
+ <Filter className="h-4 w-4 text-muted-foreground" />
568
+ <span className="text-sm font-medium">Provider:</span>
569
+ <Select value={filterByProvider} onValueChange={setFilterByProvider}>
570
+ <SelectTrigger className="w-full sm:w-40">
571
+ <SelectValue />
572
+ </SelectTrigger>
573
+ <SelectContent>
574
+ <SelectItem value="all">All Providers</SelectItem>
575
+ {uniqueProviders.map((provider) => (
576
+ <SelectItem key={provider} value={provider}>
577
+ {provider}
578
+ </SelectItem>
579
+ ))}
580
+ </SelectContent>
581
+ </Select>
582
+ </div>
583
+
584
+ <div className="flex items-center gap-2 w-full sm:w-auto">
585
+ <Filter className="h-4 w-4 text-muted-foreground" />
586
+ <span className="text-sm font-medium">Modality:</span>
587
+ <Select value={filterByModality} onValueChange={setFilterByModality}>
588
+ <SelectTrigger className="w-full sm:w-40">
589
+ <SelectValue />
590
+ </SelectTrigger>
591
+ <SelectContent>
592
+ <SelectItem value="all">All Modalities</SelectItem>
593
+ {uniqueModalities.map((modality) => (
594
+ <SelectItem key={modality} value={modality}>
595
+ {modality}
596
+ </SelectItem>
597
+ ))}
598
+ </SelectContent>
599
+ </Select>
600
+ </div>
601
+ </div>
602
+
603
+ {filteredAndSortedEvaluations.length > 0 ? (
604
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
605
+ {filteredAndSortedEvaluations.map((evaluation) => (
606
+ <EvaluationCard
607
+ key={evaluation.id}
608
+ evaluation={evaluation}
609
+ onView={handleViewEvaluation}
610
+ onDelete={handleDeleteEvaluation}
611
+ />
612
+ ))}
613
+ </div>
614
+ ) : (
615
+ <div className="text-center py-12">
616
+ <div className="mx-auto w-24 h-24 bg-muted rounded-full flex items-center justify-center mb-4">
617
+ <Filter className="h-8 w-8 text-muted-foreground" />
618
+ </div>
619
+ <h3 className="text-lg font-semibold mb-2">No evaluations match your filters</h3>
620
+ <p className="text-muted-foreground mb-4">Try adjusting your filter criteria to see more results</p>
621
+ <Button
622
+ variant="outline"
623
+ onClick={() => {
624
+ setFilterByProvider("all")
625
+ setFilterByModality("all")
626
+ }}
627
+ >
628
+ Clear Filters
629
+ </Button>
630
+ </div>
631
+ )}
632
+ </div>
633
+ </div>
634
+ </div>
635
+ )
636
+ }
app/page.tsx CHANGED
@@ -3,12 +3,12 @@
3
  import { useState, useMemo, useEffect } from "react"
4
  import { Button } from "@/components/ui/button"
5
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
6
- import { Plus, Moon, Sun, Filter, ArrowUpDown, Info } from "lucide-react"
7
- import { useTheme } from "next-themes"
8
  import { EvaluationCard, type EvaluationCardData } from "@/components/evaluation-card"
9
  import { getBenchmarkQuestions, getProcessQuestions } from "@/lib/schema"
10
  import { AIEvaluationDashboard } from "@/components/ai-evaluation-dashboard"
11
- import Link from "next/link"
 
12
 
13
  const loadEvaluationData = async (): Promise<EvaluationCardData[]> => {
14
  const evaluationFiles = [
@@ -366,7 +366,6 @@ const loadEvaluationData = async (): Promise<EvaluationCardData[]> => {
366
  }
367
 
368
  export default function HomePage() {
369
- const { theme, setTheme } = useTheme()
370
  const [showNewEvaluation, setShowNewEvaluation] = useState(false)
371
  const [evaluationsData, setEvaluationsData] = useState<EvaluationCardData[]>([])
372
  const [loading, setLoading] = useState(true)
@@ -399,12 +398,9 @@ export default function HomePage() {
399
  item.inputModalities.forEach((mod) => existingModalities.add(mod))
400
  item.outputModalities.forEach((mod) => existingModalities.add(mod))
401
  })
402
-
403
- // Return all predefined modalities, with existing ones first, then missing ones
404
- const existing = allModalities.filter(mod => existingModalities.has(mod)).sort()
405
- const missing = allModalities.filter(mod => !existingModalities.has(mod)).sort()
406
-
407
- return [...existing, ...missing]
408
  }, [evaluationsData])
409
 
410
  const filteredAndSortedEvaluations = useMemo(() => {
@@ -421,29 +417,15 @@ export default function HomePage() {
421
  )
422
  }
423
 
424
- filtered = [...filtered].sort((a, b) => {
425
- if (sortBy === "completeness-highest" || sortBy === "completeness-lowest") {
426
- // Calculate completeness scores for both items
427
- const calculateCompletenessScore = (evaluation: EvaluationCardData) => {
428
- const capTotal = evaluation.capabilityEval.strong + evaluation.capabilityEval.adequate + evaluation.capabilityEval.weak + evaluation.capabilityEval.insufficient
429
- const riskTotal = evaluation.riskEval.strong + evaluation.riskEval.adequate + evaluation.riskEval.weak + evaluation.riskEval.insufficient
430
- const totalItems = capTotal + riskTotal
431
-
432
- if (totalItems === 0) return 0
433
-
434
- const capScore = evaluation.capabilityEval.strong * 4 + evaluation.capabilityEval.adequate * 3 + evaluation.capabilityEval.weak * 2 + evaluation.capabilityEval.insufficient * 1
435
- const riskScore = evaluation.riskEval.strong * 4 + evaluation.riskEval.adequate * 3 + evaluation.riskEval.weak * 2 + evaluation.riskEval.insufficient * 1
436
-
437
- return Math.round(((capScore + riskScore) / (totalItems * 4)) * 100)
438
- }
439
-
440
- const scoreA = calculateCompletenessScore(a)
441
- const scoreB = calculateCompletenessScore(b)
442
-
443
  if (sortBy === "completeness-highest") {
444
- return scoreB - scoreA
445
  } else {
446
- return scoreA - scoreB
447
  }
448
  } else {
449
  const dateA = new Date(a.completedDate)
@@ -476,10 +458,13 @@ export default function HomePage() {
476
 
477
  if (loading) {
478
  return (
479
- <div className="min-h-screen bg-background flex items-center justify-center">
480
- <div className="text-center">
481
- <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4"></div>
482
- <p className="text-muted-foreground">Loading evaluations...</p>
 
 
 
483
  </div>
484
  </div>
485
  )
@@ -487,53 +472,22 @@ export default function HomePage() {
487
 
488
  return (
489
  <div className="min-h-screen bg-background">
490
- <header className="border-b bg-card">
491
- <div className="container mx-auto px-4 sm:px-6 py-4">
492
- <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3">
493
- <div>
494
- <h1 className="text-xl sm:text-2xl font-bold font-heading text-foreground">AI Evaluation Dashboard</h1>
495
- <p className="text-sm text-muted-foreground">Manage and track your AI system evaluations</p>
496
- </div>
497
- <div className="flex items-center gap-2 sm:gap-3">
498
- <Link href="/analytics">
499
- <Button variant="ghost" size="sm" className="gap-2">
500
- <ArrowUpDown className="h-4 w-4" />
501
- <span className="hidden sm:inline">Analytics</span>
502
- </Button>
503
- </Link>
504
- <Link href="/about">
505
- <Button variant="ghost" size="sm" className="gap-2">
506
- <Info className="h-4 w-4" />
507
- <span className="hidden sm:inline">About</span>
508
- </Button>
509
- </Link>
510
- <Button
511
- variant="ghost"
512
- size="sm"
513
- onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
514
- className="h-9 w-9 p-0"
515
- >
516
- <Sun className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
517
- <Moon className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
518
- <span className="sr-only">Toggle theme</span>
519
- </Button>
520
- <Button onClick={() => setShowNewEvaluation(true)} className="gap-2">
521
- <Plus className="h-4 w-4" />
522
- <span className="hidden sm:inline">New Eval Card</span>
523
- <span className="sm:hidden">New</span>
524
- </Button>
525
- </div>
526
- </div>
527
- </div>
528
- </header>
529
-
530
- <div className="container mx-auto px-4 sm:px-6 py-4 sm:py-6">
531
  <div className="space-y-6">
532
- <div className="flex items-center justify-between">
533
- <h2 className="text-xl font-semibold font-heading">Evaluation Cards</h2>
534
- <p className="text-sm text-muted-foreground">{filteredAndSortedEvaluations.length} eval cards</p>
535
- </div>
536
-
537
  <div className="flex flex-col sm:flex-row sm:flex-wrap items-start sm:items-center gap-3 sm:gap-4 p-4 bg-card rounded-lg border">
538
  <div className="flex items-center gap-2 w-full sm:w-auto">
539
  <ArrowUpDown className="h-4 w-4 text-muted-foreground" />
@@ -588,6 +542,7 @@ export default function HomePage() {
588
  </div>
589
  </div>
590
 
 
591
  {filteredAndSortedEvaluations.length > 0 ? (
592
  <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
593
  {filteredAndSortedEvaluations.map((evaluation) => (
 
3
  import { useState, useMemo, useEffect } from "react"
4
  import { Button } from "@/components/ui/button"
5
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
6
+ import { Filter, ArrowUpDown, Plus } from "lucide-react"
 
7
  import { EvaluationCard, type EvaluationCardData } from "@/components/evaluation-card"
8
  import { getBenchmarkQuestions, getProcessQuestions } from "@/lib/schema"
9
  import { AIEvaluationDashboard } from "@/components/ai-evaluation-dashboard"
10
+ import { Navigation } from "@/components/navigation"
11
+ import { PageHeader } from "@/components/page-header"
12
 
13
  const loadEvaluationData = async (): Promise<EvaluationCardData[]> => {
14
  const evaluationFiles = [
 
366
  }
367
 
368
  export default function HomePage() {
 
369
  const [showNewEvaluation, setShowNewEvaluation] = useState(false)
370
  const [evaluationsData, setEvaluationsData] = useState<EvaluationCardData[]>([])
371
  const [loading, setLoading] = useState(true)
 
398
  item.inputModalities.forEach((mod) => existingModalities.add(mod))
399
  item.outputModalities.forEach((mod) => existingModalities.add(mod))
400
  })
401
+
402
+ // Return only modalities that exist in the data, in the order defined by allModalities
403
+ return allModalities.filter((mod) => existingModalities.has(mod))
 
 
 
404
  }, [evaluationsData])
405
 
406
  const filteredAndSortedEvaluations = useMemo(() => {
 
417
  )
418
  }
419
 
420
+ filtered = filtered.sort((a, b) => {
421
+ if (sortBy.includes("completeness")) {
422
+ const aCompleteness = (a.completedCategories / a.applicableCategories) * 100
423
+ const bCompleteness = (b.completedCategories / b.applicableCategories) * 100
424
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
425
  if (sortBy === "completeness-highest") {
426
+ return bCompleteness - aCompleteness
427
  } else {
428
+ return aCompleteness - bCompleteness
429
  }
430
  } else {
431
  const dateA = new Date(a.completedDate)
 
458
 
459
  if (loading) {
460
  return (
461
+ <div className="min-h-screen bg-background">
462
+ <Navigation />
463
+ <div className="flex items-center justify-center min-h-[60vh]">
464
+ <div className="text-center">
465
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4"></div>
466
+ <p className="text-muted-foreground">Loading evaluations...</p>
467
+ </div>
468
  </div>
469
  </div>
470
  )
 
472
 
473
  return (
474
  <div className="min-h-screen bg-background">
475
+ <Navigation />
476
+
477
+ <PageHeader
478
+ title="Evaluation Cards"
479
+ description={`Track and manage AI system evaluations across capabilities and risks. ${filteredAndSortedEvaluations.length} eval cards available.`}
480
+ >
481
+ <Button onClick={() => setShowNewEvaluation(true)} className="gap-2">
482
+ <Plus className="h-4 w-4" />
483
+ <span className="hidden sm:inline">New Eval Card</span>
484
+ <span className="sm:hidden">New</span>
485
+ </Button>
486
+ </PageHeader>
487
+
488
+ <div className="container mx-auto px-4 sm:px-6 py-6">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
489
  <div className="space-y-6">
490
+ {/* Filters */}
 
 
 
 
491
  <div className="flex flex-col sm:flex-row sm:flex-wrap items-start sm:items-center gap-3 sm:gap-4 p-4 bg-card rounded-lg border">
492
  <div className="flex items-center gap-2 w-full sm:w-auto">
493
  <ArrowUpDown className="h-4 w-4 text-muted-foreground" />
 
542
  </div>
543
  </div>
544
 
545
+ {/* Results */}
546
  {filteredAndSortedEvaluations.length > 0 ? (
547
  <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
548
  {filteredAndSortedEvaluations.map((evaluation) => (
components/navigation.tsx ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client"
2
+
3
+ import { Button } from "@/components/ui/button"
4
+ import { Moon, Sun, Home, ArrowUpDown, Info } from "lucide-react"
5
+ import { useTheme } from "next-themes"
6
+ import Link from "next/link"
7
+ import { usePathname } from "next/navigation"
8
+ import { cn } from "@/lib/utils"
9
+
10
+ export function Navigation() {
11
+ const { theme, setTheme } = useTheme()
12
+ const pathname = usePathname()
13
+
14
+ const navItems = [
15
+ {
16
+ href: "/",
17
+ label: "Home",
18
+ icon: Home,
19
+ isActive: pathname === "/"
20
+ },
21
+ {
22
+ href: "/analytics",
23
+ label: "Analytics",
24
+ icon: ArrowUpDown,
25
+ isActive: pathname === "/analytics"
26
+ },
27
+ {
28
+ href: "/about",
29
+ label: "About",
30
+ icon: Info,
31
+ isActive: pathname === "/about"
32
+ }
33
+ ]
34
+
35
+ return (
36
+ <header className="border-b bg-card">
37
+ <div className="container mx-auto px-4 sm:px-6 py-4">
38
+ <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3">
39
+ {/* Logo and branding */}
40
+ <div className="flex items-center gap-4">
41
+ {/* Logo */}
42
+ <Link href="/" className="flex-shrink-0">
43
+ <div className="w-10 h-10 bg-gradient-to-br from-blue-500 to-purple-600 rounded-lg flex items-center justify-center text-white font-bold text-lg hover:scale-105 transition-transform">
44
+ AI
45
+ </div>
46
+ </Link>
47
+
48
+ {/* App title and description */}
49
+ <div>
50
+ <Link href="/" className="block group">
51
+ <h1 className="text-xl sm:text-2xl font-bold font-heading text-foreground group-hover:text-primary transition-colors">
52
+ AI Eval Dashboard
53
+ </h1>
54
+ </Link>
55
+ <p className="text-sm text-muted-foreground">
56
+ AI evaluation documentation platform
57
+ </p>
58
+ </div>
59
+ </div>
60
+
61
+ {/* Navigation and actions */}
62
+ <div className="flex items-center gap-2 sm:gap-3">
63
+ {/* Navigation links */}
64
+ <nav className="flex items-center gap-1">
65
+ {navItems.map((item) => (
66
+ <Link key={item.href} href={item.href}>
67
+ <Button
68
+ variant={item.isActive ? "default" : "ghost"}
69
+ size="sm"
70
+ className={cn(
71
+ "gap-2",
72
+ item.isActive && "bg-primary text-primary-foreground"
73
+ )}
74
+ >
75
+ <item.icon className="h-4 w-4" />
76
+ <span className="hidden sm:inline">{item.label}</span>
77
+ </Button>
78
+ </Link>
79
+ ))}
80
+ </nav>
81
+
82
+ {/* Separator */}
83
+ <div className="w-px h-6 bg-border" />
84
+
85
+ {/* Theme toggle */}
86
+ <Button
87
+ variant="ghost"
88
+ size="sm"
89
+ onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
90
+ className="h-9 w-9 p-0"
91
+ >
92
+ <Sun className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
93
+ <Moon className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
94
+ <span className="sr-only">Toggle theme</span>
95
+ </Button>
96
+ </div>
97
+ </div>
98
+ </div>
99
+ </header>
100
+ )
101
+ }
components/page-header.tsx ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ interface PageHeaderProps {
2
+ title: string
3
+ description?: string
4
+ children?: React.ReactNode
5
+ }
6
+
7
+ export function PageHeader({ title, description, children }: PageHeaderProps) {
8
+ return (
9
+ <div className="container mx-auto px-4 sm:px-6 py-6 border-b bg-muted/30">
10
+ <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
11
+ <div>
12
+ <h2 className="text-2xl sm:text-3xl font-bold font-heading text-foreground">
13
+ {title}
14
+ </h2>
15
+ {description && (
16
+ <p className="text-base text-muted-foreground mt-1">
17
+ {description}
18
+ </p>
19
+ )}
20
+ </div>
21
+ {children && (
22
+ <div className="flex items-center gap-2">
23
+ {children}
24
+ </div>
25
+ )}
26
+ </div>
27
+ </div>
28
+ )
29
+ }