amd-gaia 0.15.0__py3-none-any.whl → 0.15.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.1.dist-info}/METADATA +223 -223
- amd_gaia-0.15.1.dist-info/RECORD +178 -0
- {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.1.dist-info}/entry_points.txt +1 -0
- {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.1.dist-info}/licenses/LICENSE.md +20 -20
- gaia/__init__.py +29 -29
- gaia/agents/__init__.py +19 -19
- gaia/agents/base/__init__.py +9 -9
- gaia/agents/base/agent.py +2177 -2177
- gaia/agents/base/api_agent.py +120 -120
- gaia/agents/base/console.py +1841 -1841
- gaia/agents/base/errors.py +237 -237
- gaia/agents/base/mcp_agent.py +86 -86
- gaia/agents/base/tools.py +83 -83
- gaia/agents/blender/agent.py +556 -556
- gaia/agents/blender/agent_simple.py +133 -135
- gaia/agents/blender/app.py +211 -211
- gaia/agents/blender/app_simple.py +41 -41
- gaia/agents/blender/core/__init__.py +16 -16
- gaia/agents/blender/core/materials.py +506 -506
- gaia/agents/blender/core/objects.py +316 -316
- gaia/agents/blender/core/rendering.py +225 -225
- gaia/agents/blender/core/scene.py +220 -220
- gaia/agents/blender/core/view.py +146 -146
- gaia/agents/chat/__init__.py +9 -9
- gaia/agents/chat/agent.py +835 -835
- gaia/agents/chat/app.py +1058 -1058
- gaia/agents/chat/session.py +508 -508
- gaia/agents/chat/tools/__init__.py +15 -15
- gaia/agents/chat/tools/file_tools.py +96 -96
- gaia/agents/chat/tools/rag_tools.py +1729 -1729
- gaia/agents/chat/tools/shell_tools.py +436 -436
- gaia/agents/code/__init__.py +7 -7
- gaia/agents/code/agent.py +549 -549
- gaia/agents/code/cli.py +377 -0
- gaia/agents/code/models.py +135 -135
- gaia/agents/code/orchestration/__init__.py +24 -24
- gaia/agents/code/orchestration/checklist_executor.py +1763 -1763
- gaia/agents/code/orchestration/checklist_generator.py +713 -713
- gaia/agents/code/orchestration/factories/__init__.py +9 -9
- gaia/agents/code/orchestration/factories/base.py +63 -63
- gaia/agents/code/orchestration/factories/nextjs_factory.py +118 -118
- gaia/agents/code/orchestration/factories/python_factory.py +106 -106
- gaia/agents/code/orchestration/orchestrator.py +841 -841
- gaia/agents/code/orchestration/project_analyzer.py +391 -391
- gaia/agents/code/orchestration/steps/__init__.py +67 -67
- gaia/agents/code/orchestration/steps/base.py +188 -188
- gaia/agents/code/orchestration/steps/error_handler.py +314 -314
- gaia/agents/code/orchestration/steps/nextjs.py +828 -828
- gaia/agents/code/orchestration/steps/python.py +307 -307
- gaia/agents/code/orchestration/template_catalog.py +469 -469
- gaia/agents/code/orchestration/workflows/__init__.py +14 -14
- gaia/agents/code/orchestration/workflows/base.py +80 -80
- gaia/agents/code/orchestration/workflows/nextjs.py +186 -186
- gaia/agents/code/orchestration/workflows/python.py +94 -94
- gaia/agents/code/prompts/__init__.py +11 -11
- gaia/agents/code/prompts/base_prompt.py +77 -77
- gaia/agents/code/prompts/code_patterns.py +2036 -2036
- gaia/agents/code/prompts/nextjs_prompt.py +40 -40
- gaia/agents/code/prompts/python_prompt.py +109 -109
- gaia/agents/code/schema_inference.py +365 -365
- gaia/agents/code/system_prompt.py +41 -41
- gaia/agents/code/tools/__init__.py +42 -42
- gaia/agents/code/tools/cli_tools.py +1138 -1138
- gaia/agents/code/tools/code_formatting.py +319 -319
- gaia/agents/code/tools/code_tools.py +769 -769
- gaia/agents/code/tools/error_fixing.py +1347 -1347
- gaia/agents/code/tools/external_tools.py +180 -180
- gaia/agents/code/tools/file_io.py +845 -845
- gaia/agents/code/tools/prisma_tools.py +190 -190
- gaia/agents/code/tools/project_management.py +1016 -1016
- gaia/agents/code/tools/testing.py +321 -321
- gaia/agents/code/tools/typescript_tools.py +122 -122
- gaia/agents/code/tools/validation_parsing.py +461 -461
- gaia/agents/code/tools/validation_tools.py +806 -806
- gaia/agents/code/tools/web_dev_tools.py +1758 -1758
- gaia/agents/code/validators/__init__.py +16 -16
- gaia/agents/code/validators/antipattern_checker.py +241 -241
- gaia/agents/code/validators/ast_analyzer.py +197 -197
- gaia/agents/code/validators/requirements_validator.py +145 -145
- gaia/agents/code/validators/syntax_validator.py +171 -171
- gaia/agents/docker/__init__.py +7 -7
- gaia/agents/docker/agent.py +642 -642
- gaia/agents/emr/__init__.py +8 -8
- gaia/agents/emr/agent.py +1506 -1506
- gaia/agents/emr/cli.py +1322 -1322
- gaia/agents/emr/constants.py +475 -475
- gaia/agents/emr/dashboard/__init__.py +4 -4
- gaia/agents/emr/dashboard/server.py +1974 -1974
- gaia/agents/jira/__init__.py +11 -11
- gaia/agents/jira/agent.py +894 -894
- gaia/agents/jira/jql_templates.py +299 -299
- gaia/agents/routing/__init__.py +7 -7
- gaia/agents/routing/agent.py +567 -570
- gaia/agents/routing/system_prompt.py +75 -75
- gaia/agents/summarize/__init__.py +11 -0
- gaia/agents/summarize/agent.py +885 -0
- gaia/agents/summarize/prompts.py +129 -0
- gaia/api/__init__.py +23 -23
- gaia/api/agent_registry.py +238 -238
- gaia/api/app.py +305 -305
- gaia/api/openai_server.py +575 -575
- gaia/api/schemas.py +186 -186
- gaia/api/sse_handler.py +373 -373
- gaia/apps/__init__.py +4 -4
- gaia/apps/llm/__init__.py +6 -6
- gaia/apps/llm/app.py +173 -169
- gaia/apps/summarize/app.py +116 -633
- gaia/apps/summarize/html_viewer.py +133 -133
- gaia/apps/summarize/pdf_formatter.py +284 -284
- gaia/audio/__init__.py +2 -2
- gaia/audio/audio_client.py +439 -439
- gaia/audio/audio_recorder.py +269 -269
- gaia/audio/kokoro_tts.py +599 -599
- gaia/audio/whisper_asr.py +432 -432
- gaia/chat/__init__.py +16 -16
- gaia/chat/app.py +430 -430
- gaia/chat/prompts.py +522 -522
- gaia/chat/sdk.py +1228 -1225
- gaia/cli.py +5481 -5632
- gaia/database/__init__.py +10 -10
- gaia/database/agent.py +176 -176
- gaia/database/mixin.py +290 -290
- gaia/database/testing.py +64 -64
- gaia/eval/batch_experiment.py +2332 -2332
- gaia/eval/claude.py +542 -542
- gaia/eval/config.py +37 -37
- gaia/eval/email_generator.py +512 -512
- gaia/eval/eval.py +3179 -3179
- gaia/eval/groundtruth.py +1130 -1130
- gaia/eval/transcript_generator.py +582 -582
- gaia/eval/webapp/README.md +167 -167
- gaia/eval/webapp/package-lock.json +875 -875
- gaia/eval/webapp/package.json +20 -20
- gaia/eval/webapp/public/app.js +3402 -3402
- gaia/eval/webapp/public/index.html +87 -87
- gaia/eval/webapp/public/styles.css +3661 -3661
- gaia/eval/webapp/server.js +415 -415
- gaia/eval/webapp/test-setup.js +72 -72
- gaia/llm/__init__.py +9 -2
- gaia/llm/base_client.py +60 -0
- gaia/llm/exceptions.py +12 -0
- gaia/llm/factory.py +70 -0
- gaia/llm/lemonade_client.py +3236 -3221
- gaia/llm/lemonade_manager.py +294 -294
- gaia/llm/providers/__init__.py +9 -0
- gaia/llm/providers/claude.py +108 -0
- gaia/llm/providers/lemonade.py +120 -0
- gaia/llm/providers/openai_provider.py +79 -0
- gaia/llm/vlm_client.py +382 -382
- gaia/logger.py +189 -189
- gaia/mcp/agent_mcp_server.py +245 -245
- gaia/mcp/blender_mcp_client.py +138 -138
- gaia/mcp/blender_mcp_server.py +648 -648
- gaia/mcp/context7_cache.py +332 -332
- gaia/mcp/external_services.py +518 -518
- gaia/mcp/mcp_bridge.py +811 -550
- gaia/mcp/servers/__init__.py +6 -6
- gaia/mcp/servers/docker_mcp.py +83 -83
- gaia/perf_analysis.py +361 -0
- gaia/rag/__init__.py +10 -10
- gaia/rag/app.py +293 -293
- gaia/rag/demo.py +304 -304
- gaia/rag/pdf_utils.py +235 -235
- gaia/rag/sdk.py +2194 -2194
- gaia/security.py +163 -163
- gaia/talk/app.py +289 -289
- gaia/talk/sdk.py +538 -538
- gaia/testing/__init__.py +87 -87
- gaia/testing/assertions.py +330 -330
- gaia/testing/fixtures.py +333 -333
- gaia/testing/mocks.py +493 -493
- gaia/util.py +46 -46
- gaia/utils/__init__.py +33 -33
- gaia/utils/file_watcher.py +675 -675
- gaia/utils/parsing.py +223 -223
- gaia/version.py +100 -100
- amd_gaia-0.15.0.dist-info/RECORD +0 -168
- gaia/agents/code/app.py +0 -266
- gaia/llm/llm_client.py +0 -723
- {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.1.dist-info}/WHEEL +0 -0
- {amd_gaia-0.15.0.dist-info → amd_gaia-0.15.1.dist-info}/top_level.txt +0 -0
gaia/eval/webapp/server.js
CHANGED
|
@@ -1,416 +1,416 @@
|
|
|
1
|
-
// Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
-
// SPDX-License-Identifier: MIT
|
|
3
|
-
|
|
4
|
-
const express = require('express');
|
|
5
|
-
const fs = require('fs');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
|
|
8
|
-
const app = express();
|
|
9
|
-
const PORT = process.env.PORT || 3000;
|
|
10
|
-
|
|
11
|
-
// Serve static files
|
|
12
|
-
app.use(express.static(path.join(__dirname, 'public')));
|
|
13
|
-
|
|
14
|
-
// Parse JSON bodies
|
|
15
|
-
app.use(express.json());
|
|
16
|
-
|
|
17
|
-
// Base paths for data files - use environment variables or defaults
|
|
18
|
-
const EXPERIMENTS_PATH = process.env.EXPERIMENTS_PATH || path.join(__dirname, '../../../..', 'experiments');
|
|
19
|
-
const EVALUATIONS_PATH = process.env.EVALUATIONS_PATH || path.join(__dirname, '../../../..', 'evaluation');
|
|
20
|
-
const TEST_DATA_PATH = process.env.TEST_DATA_PATH || path.join(__dirname, '../../../..', 'test_data');
|
|
21
|
-
const GROUNDTRUTH_PATH = process.env.GROUNDTRUTH_PATH || path.join(__dirname, '../../../..', 'groundtruth');
|
|
22
|
-
const AGENT_OUTPUTS_PATH = process.env.AGENT_OUTPUTS_PATH || path.join(__dirname, '../../../..');
|
|
23
|
-
const SINGLE_AGENT_FILE = process.env.SINGLE_AGENT_FILE;
|
|
24
|
-
|
|
25
|
-
// API endpoint to list available files
|
|
26
|
-
app.get('/api/files', (req, res) => {
|
|
27
|
-
try {
|
|
28
|
-
const experiments = fs.existsSync(EXPERIMENTS_PATH)
|
|
29
|
-
? fs.readdirSync(EXPERIMENTS_PATH).filter(file => file.endsWith('.experiment.json'))
|
|
30
|
-
: [];
|
|
31
|
-
|
|
32
|
-
let evaluations = [];
|
|
33
|
-
if (fs.existsSync(EVALUATIONS_PATH)) {
|
|
34
|
-
// Get files from root
|
|
35
|
-
const rootFiles = fs.readdirSync(EVALUATIONS_PATH).filter(file =>
|
|
36
|
-
file.endsWith('.experiment.eval.json') ||
|
|
37
|
-
file === 'consolidated_evaluations_report.json' ||
|
|
38
|
-
file.endsWith('_evaluations_report.json'));
|
|
39
|
-
evaluations.push(...rootFiles.map(file => ({
|
|
40
|
-
name: file,
|
|
41
|
-
path: path.join(EVALUATIONS_PATH, file),
|
|
42
|
-
type: 'evaluation',
|
|
43
|
-
directory: 'root'
|
|
44
|
-
})));
|
|
45
|
-
|
|
46
|
-
// Check for subdirectories
|
|
47
|
-
const items = fs.readdirSync(EVALUATIONS_PATH, { withFileTypes: true });
|
|
48
|
-
for (const item of items) {
|
|
49
|
-
if (item.isDirectory()) {
|
|
50
|
-
const subDirPath = path.join(EVALUATIONS_PATH, item.name);
|
|
51
|
-
const subDirFiles = fs.readdirSync(subDirPath).filter(file =>
|
|
52
|
-
file.endsWith('.experiment.eval.json') ||
|
|
53
|
-
file === 'consolidated_evaluations_report.json' ||
|
|
54
|
-
file.endsWith('_evaluations_report.json'));
|
|
55
|
-
evaluations.push(...subDirFiles.map(file => ({
|
|
56
|
-
name: `${item.name}/${file}`,
|
|
57
|
-
path: path.join(subDirPath, file),
|
|
58
|
-
type: 'evaluation',
|
|
59
|
-
directory: item.name
|
|
60
|
-
})));
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Collect agent outputs
|
|
66
|
-
let agentOutputs = [];
|
|
67
|
-
if (SINGLE_AGENT_FILE && fs.existsSync(SINGLE_AGENT_FILE)) {
|
|
68
|
-
// Single file mode
|
|
69
|
-
agentOutputs.push({
|
|
70
|
-
name: path.basename(SINGLE_AGENT_FILE),
|
|
71
|
-
path: SINGLE_AGENT_FILE,
|
|
72
|
-
type: 'agent_output',
|
|
73
|
-
directory: 'single'
|
|
74
|
-
});
|
|
75
|
-
} else if (fs.existsSync(AGENT_OUTPUTS_PATH)) {
|
|
76
|
-
// Directory mode - look for agent_output_*.json files
|
|
77
|
-
const agentFiles = fs.readdirSync(AGENT_OUTPUTS_PATH).filter(file =>
|
|
78
|
-
file.startsWith('agent_output_') && file.endsWith('.json'));
|
|
79
|
-
agentOutputs = agentFiles.map(file => ({
|
|
80
|
-
name: file,
|
|
81
|
-
path: path.join(AGENT_OUTPUTS_PATH, file),
|
|
82
|
-
type: 'agent_output',
|
|
83
|
-
directory: 'root'
|
|
84
|
-
}));
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
res.json({
|
|
88
|
-
experiments: experiments.map(file => ({
|
|
89
|
-
name: file,
|
|
90
|
-
path: path.join(EXPERIMENTS_PATH, file),
|
|
91
|
-
type: 'experiment'
|
|
92
|
-
})),
|
|
93
|
-
evaluations: evaluations,
|
|
94
|
-
agentOutputs: agentOutputs,
|
|
95
|
-
paths: {
|
|
96
|
-
experiments: EXPERIMENTS_PATH,
|
|
97
|
-
evaluations: EVALUATIONS_PATH,
|
|
98
|
-
testData: TEST_DATA_PATH,
|
|
99
|
-
groundtruth: GROUNDTRUTH_PATH
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
} catch (error) {
|
|
103
|
-
res.status(500).json({ error: 'Failed to list files', details: error.message });
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// API endpoint to load experiment data
|
|
108
|
-
app.get('/api/experiment/:filename', (req, res) => {
|
|
109
|
-
try {
|
|
110
|
-
const filename = req.params.filename;
|
|
111
|
-
const filePath = path.join(EXPERIMENTS_PATH, filename);
|
|
112
|
-
|
|
113
|
-
if (!fs.existsSync(filePath)) {
|
|
114
|
-
return res.status(404).json({ error: 'File not found' });
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
118
|
-
res.json(data);
|
|
119
|
-
} catch (error) {
|
|
120
|
-
res.status(500).json({ error: 'Failed to load experiment', details: error.message });
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
// API endpoint to load evaluation data (supports subdirectories)
|
|
125
|
-
app.get('/api/evaluation/*', (req, res) => {
|
|
126
|
-
try {
|
|
127
|
-
const filename = req.params[0];
|
|
128
|
-
const filePath = path.join(EVALUATIONS_PATH, filename);
|
|
129
|
-
|
|
130
|
-
if (!fs.existsSync(filePath)) {
|
|
131
|
-
return res.status(404).json({ error: 'File not found' });
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
135
|
-
res.json(data);
|
|
136
|
-
} catch (error) {
|
|
137
|
-
res.status(500).json({ error: 'Failed to load evaluation', details: error.message });
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
// API endpoint to load agent output data
|
|
142
|
-
app.get('/api/agent-output/:filename(*)', (req, res) => {
|
|
143
|
-
try {
|
|
144
|
-
const filename = req.params.filename;
|
|
145
|
-
let filePath;
|
|
146
|
-
|
|
147
|
-
// Check if it's a single file mode or directory mode
|
|
148
|
-
if (SINGLE_AGENT_FILE && fs.existsSync(SINGLE_AGENT_FILE) &&
|
|
149
|
-
path.basename(SINGLE_AGENT_FILE) === filename) {
|
|
150
|
-
filePath = SINGLE_AGENT_FILE;
|
|
151
|
-
} else {
|
|
152
|
-
filePath = path.join(AGENT_OUTPUTS_PATH, filename);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (!fs.existsSync(filePath)) {
|
|
156
|
-
return res.status(404).json({ error: 'Agent output file not found' });
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
160
|
-
|
|
161
|
-
// Process the agent output data to extract useful information
|
|
162
|
-
const processedData = {
|
|
163
|
-
...data,
|
|
164
|
-
metadata: {
|
|
165
|
-
filename: filename,
|
|
166
|
-
filepath: filePath,
|
|
167
|
-
fileSize: fs.statSync(filePath).size,
|
|
168
|
-
lastModified: fs.statSync(filePath).mtime,
|
|
169
|
-
conversationLength: data.conversation ? data.conversation.length : 0,
|
|
170
|
-
hasPerformanceStats: data.conversation ?
|
|
171
|
-
data.conversation.some(msg => msg.role === 'system' && msg.content?.type === 'stats') : false
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
res.json(processedData);
|
|
176
|
-
} catch (error) {
|
|
177
|
-
res.status(500).json({ error: 'Failed to load agent output', details: error.message });
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
// API endpoint to get combined report (experiment + evaluation)
|
|
182
|
-
app.get('/api/report/:experimentFile/:evaluationFile?', (req, res) => {
|
|
183
|
-
try {
|
|
184
|
-
const experimentFile = req.params.experimentFile;
|
|
185
|
-
const evaluationFile = req.params.evaluationFile;
|
|
186
|
-
|
|
187
|
-
// Load experiment data
|
|
188
|
-
const experimentPath = path.join(EXPERIMENTS_PATH, experimentFile);
|
|
189
|
-
if (!fs.existsSync(experimentPath)) {
|
|
190
|
-
return res.status(404).json({ error: 'Experiment file not found' });
|
|
191
|
-
}
|
|
192
|
-
const experimentData = JSON.parse(fs.readFileSync(experimentPath, 'utf8'));
|
|
193
|
-
|
|
194
|
-
let evaluationData = null;
|
|
195
|
-
if (evaluationFile) {
|
|
196
|
-
const evaluationPath = path.join(EVALUATIONS_PATH, evaluationFile);
|
|
197
|
-
if (fs.existsSync(evaluationPath)) {
|
|
198
|
-
evaluationData = JSON.parse(fs.readFileSync(evaluationPath, 'utf8'));
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
res.json({
|
|
203
|
-
experiment: experimentData,
|
|
204
|
-
evaluation: evaluationData,
|
|
205
|
-
combined: true
|
|
206
|
-
});
|
|
207
|
-
} catch (error) {
|
|
208
|
-
res.status(500).json({ error: 'Failed to load report', details: error.message });
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
// API endpoint to list test data directories and files
|
|
213
|
-
app.get('/api/test-data', (req, res) => {
|
|
214
|
-
try {
|
|
215
|
-
const testData = { directories: [], files: [] };
|
|
216
|
-
|
|
217
|
-
if (!fs.existsSync(TEST_DATA_PATH)) {
|
|
218
|
-
return res.json(testData);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const entries = fs.readdirSync(TEST_DATA_PATH, { withFileTypes: true });
|
|
222
|
-
|
|
223
|
-
// Check if TEST_DATA_PATH itself contains data files (user pointed to specific subdirectory)
|
|
224
|
-
const rootDataFiles = entries
|
|
225
|
-
.filter(entry => entry.isFile() && (entry.name.endsWith('.txt') || entry.name.endsWith('.pdf')))
|
|
226
|
-
.map(entry => entry.name);
|
|
227
|
-
|
|
228
|
-
if (rootDataFiles.length > 0) {
|
|
229
|
-
// User pointed directly at a data directory (e.g., test_data/meetings)
|
|
230
|
-
const hasMetadata = entries.some(entry =>
|
|
231
|
-
entry.isFile() && entry.name.endsWith('_metadata.json')
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
// Use the directory name from the path
|
|
235
|
-
const dirName = path.basename(TEST_DATA_PATH);
|
|
236
|
-
|
|
237
|
-
testData.directories.push({
|
|
238
|
-
name: dirName,
|
|
239
|
-
path: TEST_DATA_PATH,
|
|
240
|
-
files: rootDataFiles,
|
|
241
|
-
hasMetadata: hasMetadata
|
|
242
|
-
});
|
|
243
|
-
} else {
|
|
244
|
-
// User pointed at parent directory - scan for subdirectories
|
|
245
|
-
for (const entry of entries) {
|
|
246
|
-
if (entry.isDirectory()) {
|
|
247
|
-
const dirPath = path.join(TEST_DATA_PATH, entry.name);
|
|
248
|
-
const dirFiles = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
249
|
-
|
|
250
|
-
const dataFiles = dirFiles
|
|
251
|
-
.filter(file => file.isFile() && (file.name.endsWith('.txt') || file.name.endsWith('.pdf')))
|
|
252
|
-
.map(file => file.name);
|
|
253
|
-
|
|
254
|
-
const hasMetadata = dirFiles.some(file =>
|
|
255
|
-
file.isFile() && file.name.endsWith('_metadata.json')
|
|
256
|
-
);
|
|
257
|
-
|
|
258
|
-
testData.directories.push({
|
|
259
|
-
name: entry.name,
|
|
260
|
-
path: dirPath,
|
|
261
|
-
files: dataFiles,
|
|
262
|
-
hasMetadata: hasMetadata
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
res.json(testData);
|
|
269
|
-
} catch (error) {
|
|
270
|
-
res.status(500).json({ error: 'Failed to list test data', details: error.message });
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
// API endpoint to load test data file content
|
|
275
|
-
app.get('/api/test-data/:type/:filename', (req, res) => {
|
|
276
|
-
try {
|
|
277
|
-
const type = req.params.type;
|
|
278
|
-
const filename = req.params.filename;
|
|
279
|
-
// Try subdirectory first, then root level
|
|
280
|
-
let filePath = path.join(TEST_DATA_PATH, type, filename);
|
|
281
|
-
|
|
282
|
-
// If not found in subdirectory, try root level
|
|
283
|
-
if (!fs.existsSync(filePath)) {
|
|
284
|
-
const rootPath = path.join(TEST_DATA_PATH, filename);
|
|
285
|
-
if (fs.existsSync(rootPath)) {
|
|
286
|
-
filePath = rootPath;
|
|
287
|
-
} else {
|
|
288
|
-
return res.status(404).json({ error: 'Test data file not found' });
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// Check if file is PDF
|
|
293
|
-
if (filename.endsWith('.pdf')) {
|
|
294
|
-
// For PDFs, send file info and indicate it's a binary file
|
|
295
|
-
const stats = fs.statSync(filePath);
|
|
296
|
-
res.json({
|
|
297
|
-
filename: filename,
|
|
298
|
-
type: type,
|
|
299
|
-
isPdf: true,
|
|
300
|
-
size: stats.size,
|
|
301
|
-
message: 'PDF file - preview not available. Please open the file directly to view contents.'
|
|
302
|
-
});
|
|
303
|
-
} else {
|
|
304
|
-
// For text files, send the content
|
|
305
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
306
|
-
res.json({
|
|
307
|
-
filename: filename,
|
|
308
|
-
type: type,
|
|
309
|
-
content: content
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
} catch (error) {
|
|
313
|
-
res.status(500).json({ error: 'Failed to load test data file', details: error.message });
|
|
314
|
-
}
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
// API endpoint to load test data metadata
|
|
318
|
-
app.get('/api/test-data/:type/metadata', (req, res) => {
|
|
319
|
-
try {
|
|
320
|
-
const type = req.params.type;
|
|
321
|
-
const metadataFiles = [
|
|
322
|
-
`${type}_metadata.json`,
|
|
323
|
-
'metadata.json'
|
|
324
|
-
];
|
|
325
|
-
|
|
326
|
-
let metadataPath = null;
|
|
327
|
-
for (const filename of metadataFiles) {
|
|
328
|
-
const potentialPath = path.join(TEST_DATA_PATH, type, filename);
|
|
329
|
-
if (fs.existsSync(potentialPath)) {
|
|
330
|
-
metadataPath = potentialPath;
|
|
331
|
-
break;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
if (!metadataPath) {
|
|
336
|
-
return res.status(404).json({ error: 'Metadata file not found' });
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
|
|
340
|
-
res.json(metadata);
|
|
341
|
-
} catch (error) {
|
|
342
|
-
res.status(500).json({ error: 'Failed to load metadata', details: error.message });
|
|
343
|
-
}
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
// API endpoint to list groundtruth files
|
|
347
|
-
app.get('/api/groundtruth', (req, res) => {
|
|
348
|
-
try {
|
|
349
|
-
const groundtruthData = { directories: [], files: [] };
|
|
350
|
-
|
|
351
|
-
if (!fs.existsSync(GROUNDTRUTH_PATH)) {
|
|
352
|
-
return res.json(groundtruthData);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// Function to recursively find groundtruth files
|
|
356
|
-
function findGroundtruthFiles(dir, relativePath = '') {
|
|
357
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
358
|
-
|
|
359
|
-
for (const entry of entries) {
|
|
360
|
-
const fullPath = path.join(dir, entry.name);
|
|
361
|
-
const relativeFilePath = relativePath ? path.join(relativePath, entry.name) : entry.name;
|
|
362
|
-
|
|
363
|
-
if (entry.isDirectory()) {
|
|
364
|
-
findGroundtruthFiles(fullPath, relativeFilePath);
|
|
365
|
-
} else if (entry.isFile() && entry.name.endsWith('.groundtruth.json')) {
|
|
366
|
-
groundtruthData.files.push({
|
|
367
|
-
name: entry.name,
|
|
368
|
-
path: relativeFilePath,
|
|
369
|
-
directory: relativePath || 'root',
|
|
370
|
-
type: entry.name.includes('consolidated') ? 'consolidated' : 'individual'
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
findGroundtruthFiles(GROUNDTRUTH_PATH);
|
|
377
|
-
|
|
378
|
-
res.json(groundtruthData);
|
|
379
|
-
} catch (error) {
|
|
380
|
-
res.status(500).json({ error: 'Failed to list groundtruth files', details: error.message });
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
// API endpoint to load groundtruth file content
|
|
385
|
-
app.get('/api/groundtruth/:filename(*)', (req, res) => {
|
|
386
|
-
try {
|
|
387
|
-
const filename = req.params.filename;
|
|
388
|
-
const filePath = path.join(GROUNDTRUTH_PATH, filename);
|
|
389
|
-
|
|
390
|
-
if (!fs.existsSync(filePath)) {
|
|
391
|
-
return res.status(404).json({ error: 'Groundtruth file not found' });
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
395
|
-
res.json(data);
|
|
396
|
-
} catch (error) {
|
|
397
|
-
res.status(500).json({ error: 'Failed to load groundtruth file', details: error.message });
|
|
398
|
-
}
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
// Serve the main application
|
|
402
|
-
app.get('/', (req, res) => {
|
|
403
|
-
res.sendFile(path.join(__dirname, 'public', 'index.html'));
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
app.listen(PORT, () => {
|
|
407
|
-
console.log(`Gaia Evaluation Visualizer running on http://localhost:${PORT}`);
|
|
408
|
-
console.log(`Experiments path: ${EXPERIMENTS_PATH}`);
|
|
409
|
-
console.log(`Evaluations path: ${EVALUATIONS_PATH}`);
|
|
410
|
-
console.log(`Test data path: ${TEST_DATA_PATH}`);
|
|
411
|
-
console.log(`Groundtruth path: ${GROUNDTRUTH_PATH}`);
|
|
412
|
-
console.log(`Agent outputs path: ${AGENT_OUTPUTS_PATH}`);
|
|
413
|
-
if (SINGLE_AGENT_FILE) {
|
|
414
|
-
console.log(`Single agent file: ${SINGLE_AGENT_FILE}`);
|
|
415
|
-
}
|
|
1
|
+
// Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
const express = require('express');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
const app = express();
|
|
9
|
+
const PORT = process.env.PORT || 3000;
|
|
10
|
+
|
|
11
|
+
// Serve static files
|
|
12
|
+
app.use(express.static(path.join(__dirname, 'public')));
|
|
13
|
+
|
|
14
|
+
// Parse JSON bodies
|
|
15
|
+
app.use(express.json());
|
|
16
|
+
|
|
17
|
+
// Base paths for data files - use environment variables or defaults
|
|
18
|
+
const EXPERIMENTS_PATH = process.env.EXPERIMENTS_PATH || path.join(__dirname, '../../../..', 'experiments');
|
|
19
|
+
const EVALUATIONS_PATH = process.env.EVALUATIONS_PATH || path.join(__dirname, '../../../..', 'evaluation');
|
|
20
|
+
const TEST_DATA_PATH = process.env.TEST_DATA_PATH || path.join(__dirname, '../../../..', 'test_data');
|
|
21
|
+
const GROUNDTRUTH_PATH = process.env.GROUNDTRUTH_PATH || path.join(__dirname, '../../../..', 'groundtruth');
|
|
22
|
+
const AGENT_OUTPUTS_PATH = process.env.AGENT_OUTPUTS_PATH || path.join(__dirname, '../../../..');
|
|
23
|
+
const SINGLE_AGENT_FILE = process.env.SINGLE_AGENT_FILE;
|
|
24
|
+
|
|
25
|
+
// API endpoint to list available files
|
|
26
|
+
app.get('/api/files', (req, res) => {
|
|
27
|
+
try {
|
|
28
|
+
const experiments = fs.existsSync(EXPERIMENTS_PATH)
|
|
29
|
+
? fs.readdirSync(EXPERIMENTS_PATH).filter(file => file.endsWith('.experiment.json'))
|
|
30
|
+
: [];
|
|
31
|
+
|
|
32
|
+
let evaluations = [];
|
|
33
|
+
if (fs.existsSync(EVALUATIONS_PATH)) {
|
|
34
|
+
// Get files from root
|
|
35
|
+
const rootFiles = fs.readdirSync(EVALUATIONS_PATH).filter(file =>
|
|
36
|
+
file.endsWith('.experiment.eval.json') ||
|
|
37
|
+
file === 'consolidated_evaluations_report.json' ||
|
|
38
|
+
file.endsWith('_evaluations_report.json'));
|
|
39
|
+
evaluations.push(...rootFiles.map(file => ({
|
|
40
|
+
name: file,
|
|
41
|
+
path: path.join(EVALUATIONS_PATH, file),
|
|
42
|
+
type: 'evaluation',
|
|
43
|
+
directory: 'root'
|
|
44
|
+
})));
|
|
45
|
+
|
|
46
|
+
// Check for subdirectories
|
|
47
|
+
const items = fs.readdirSync(EVALUATIONS_PATH, { withFileTypes: true });
|
|
48
|
+
for (const item of items) {
|
|
49
|
+
if (item.isDirectory()) {
|
|
50
|
+
const subDirPath = path.join(EVALUATIONS_PATH, item.name);
|
|
51
|
+
const subDirFiles = fs.readdirSync(subDirPath).filter(file =>
|
|
52
|
+
file.endsWith('.experiment.eval.json') ||
|
|
53
|
+
file === 'consolidated_evaluations_report.json' ||
|
|
54
|
+
file.endsWith('_evaluations_report.json'));
|
|
55
|
+
evaluations.push(...subDirFiles.map(file => ({
|
|
56
|
+
name: `${item.name}/${file}`,
|
|
57
|
+
path: path.join(subDirPath, file),
|
|
58
|
+
type: 'evaluation',
|
|
59
|
+
directory: item.name
|
|
60
|
+
})));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Collect agent outputs
|
|
66
|
+
let agentOutputs = [];
|
|
67
|
+
if (SINGLE_AGENT_FILE && fs.existsSync(SINGLE_AGENT_FILE)) {
|
|
68
|
+
// Single file mode
|
|
69
|
+
agentOutputs.push({
|
|
70
|
+
name: path.basename(SINGLE_AGENT_FILE),
|
|
71
|
+
path: SINGLE_AGENT_FILE,
|
|
72
|
+
type: 'agent_output',
|
|
73
|
+
directory: 'single'
|
|
74
|
+
});
|
|
75
|
+
} else if (fs.existsSync(AGENT_OUTPUTS_PATH)) {
|
|
76
|
+
// Directory mode - look for agent_output_*.json files
|
|
77
|
+
const agentFiles = fs.readdirSync(AGENT_OUTPUTS_PATH).filter(file =>
|
|
78
|
+
file.startsWith('agent_output_') && file.endsWith('.json'));
|
|
79
|
+
agentOutputs = agentFiles.map(file => ({
|
|
80
|
+
name: file,
|
|
81
|
+
path: path.join(AGENT_OUTPUTS_PATH, file),
|
|
82
|
+
type: 'agent_output',
|
|
83
|
+
directory: 'root'
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
res.json({
|
|
88
|
+
experiments: experiments.map(file => ({
|
|
89
|
+
name: file,
|
|
90
|
+
path: path.join(EXPERIMENTS_PATH, file),
|
|
91
|
+
type: 'experiment'
|
|
92
|
+
})),
|
|
93
|
+
evaluations: evaluations,
|
|
94
|
+
agentOutputs: agentOutputs,
|
|
95
|
+
paths: {
|
|
96
|
+
experiments: EXPERIMENTS_PATH,
|
|
97
|
+
evaluations: EVALUATIONS_PATH,
|
|
98
|
+
testData: TEST_DATA_PATH,
|
|
99
|
+
groundtruth: GROUNDTRUTH_PATH
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
} catch (error) {
|
|
103
|
+
res.status(500).json({ error: 'Failed to list files', details: error.message });
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// API endpoint to load experiment data
|
|
108
|
+
app.get('/api/experiment/:filename', (req, res) => {
|
|
109
|
+
try {
|
|
110
|
+
const filename = req.params.filename;
|
|
111
|
+
const filePath = path.join(EXPERIMENTS_PATH, filename);
|
|
112
|
+
|
|
113
|
+
if (!fs.existsSync(filePath)) {
|
|
114
|
+
return res.status(404).json({ error: 'File not found' });
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
118
|
+
res.json(data);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
res.status(500).json({ error: 'Failed to load experiment', details: error.message });
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// API endpoint to load evaluation data (supports subdirectories)
|
|
125
|
+
app.get('/api/evaluation/*', (req, res) => {
|
|
126
|
+
try {
|
|
127
|
+
const filename = req.params[0];
|
|
128
|
+
const filePath = path.join(EVALUATIONS_PATH, filename);
|
|
129
|
+
|
|
130
|
+
if (!fs.existsSync(filePath)) {
|
|
131
|
+
return res.status(404).json({ error: 'File not found' });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
135
|
+
res.json(data);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
res.status(500).json({ error: 'Failed to load evaluation', details: error.message });
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// API endpoint to load agent output data
|
|
142
|
+
app.get('/api/agent-output/:filename(*)', (req, res) => {
|
|
143
|
+
try {
|
|
144
|
+
const filename = req.params.filename;
|
|
145
|
+
let filePath;
|
|
146
|
+
|
|
147
|
+
// Check if it's a single file mode or directory mode
|
|
148
|
+
if (SINGLE_AGENT_FILE && fs.existsSync(SINGLE_AGENT_FILE) &&
|
|
149
|
+
path.basename(SINGLE_AGENT_FILE) === filename) {
|
|
150
|
+
filePath = SINGLE_AGENT_FILE;
|
|
151
|
+
} else {
|
|
152
|
+
filePath = path.join(AGENT_OUTPUTS_PATH, filename);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (!fs.existsSync(filePath)) {
|
|
156
|
+
return res.status(404).json({ error: 'Agent output file not found' });
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
160
|
+
|
|
161
|
+
// Process the agent output data to extract useful information
|
|
162
|
+
const processedData = {
|
|
163
|
+
...data,
|
|
164
|
+
metadata: {
|
|
165
|
+
filename: filename,
|
|
166
|
+
filepath: filePath,
|
|
167
|
+
fileSize: fs.statSync(filePath).size,
|
|
168
|
+
lastModified: fs.statSync(filePath).mtime,
|
|
169
|
+
conversationLength: data.conversation ? data.conversation.length : 0,
|
|
170
|
+
hasPerformanceStats: data.conversation ?
|
|
171
|
+
data.conversation.some(msg => msg.role === 'system' && msg.content?.type === 'stats') : false
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
res.json(processedData);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
res.status(500).json({ error: 'Failed to load agent output', details: error.message });
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// API endpoint to get combined report (experiment + evaluation)
|
|
182
|
+
app.get('/api/report/:experimentFile/:evaluationFile?', (req, res) => {
|
|
183
|
+
try {
|
|
184
|
+
const experimentFile = req.params.experimentFile;
|
|
185
|
+
const evaluationFile = req.params.evaluationFile;
|
|
186
|
+
|
|
187
|
+
// Load experiment data
|
|
188
|
+
const experimentPath = path.join(EXPERIMENTS_PATH, experimentFile);
|
|
189
|
+
if (!fs.existsSync(experimentPath)) {
|
|
190
|
+
return res.status(404).json({ error: 'Experiment file not found' });
|
|
191
|
+
}
|
|
192
|
+
const experimentData = JSON.parse(fs.readFileSync(experimentPath, 'utf8'));
|
|
193
|
+
|
|
194
|
+
let evaluationData = null;
|
|
195
|
+
if (evaluationFile) {
|
|
196
|
+
const evaluationPath = path.join(EVALUATIONS_PATH, evaluationFile);
|
|
197
|
+
if (fs.existsSync(evaluationPath)) {
|
|
198
|
+
evaluationData = JSON.parse(fs.readFileSync(evaluationPath, 'utf8'));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
res.json({
|
|
203
|
+
experiment: experimentData,
|
|
204
|
+
evaluation: evaluationData,
|
|
205
|
+
combined: true
|
|
206
|
+
});
|
|
207
|
+
} catch (error) {
|
|
208
|
+
res.status(500).json({ error: 'Failed to load report', details: error.message });
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// API endpoint to list test data directories and files
|
|
213
|
+
app.get('/api/test-data', (req, res) => {
|
|
214
|
+
try {
|
|
215
|
+
const testData = { directories: [], files: [] };
|
|
216
|
+
|
|
217
|
+
if (!fs.existsSync(TEST_DATA_PATH)) {
|
|
218
|
+
return res.json(testData);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const entries = fs.readdirSync(TEST_DATA_PATH, { withFileTypes: true });
|
|
222
|
+
|
|
223
|
+
// Check if TEST_DATA_PATH itself contains data files (user pointed to specific subdirectory)
|
|
224
|
+
const rootDataFiles = entries
|
|
225
|
+
.filter(entry => entry.isFile() && (entry.name.endsWith('.txt') || entry.name.endsWith('.pdf')))
|
|
226
|
+
.map(entry => entry.name);
|
|
227
|
+
|
|
228
|
+
if (rootDataFiles.length > 0) {
|
|
229
|
+
// User pointed directly at a data directory (e.g., test_data/meetings)
|
|
230
|
+
const hasMetadata = entries.some(entry =>
|
|
231
|
+
entry.isFile() && entry.name.endsWith('_metadata.json')
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
// Use the directory name from the path
|
|
235
|
+
const dirName = path.basename(TEST_DATA_PATH);
|
|
236
|
+
|
|
237
|
+
testData.directories.push({
|
|
238
|
+
name: dirName,
|
|
239
|
+
path: TEST_DATA_PATH,
|
|
240
|
+
files: rootDataFiles,
|
|
241
|
+
hasMetadata: hasMetadata
|
|
242
|
+
});
|
|
243
|
+
} else {
|
|
244
|
+
// User pointed at parent directory - scan for subdirectories
|
|
245
|
+
for (const entry of entries) {
|
|
246
|
+
if (entry.isDirectory()) {
|
|
247
|
+
const dirPath = path.join(TEST_DATA_PATH, entry.name);
|
|
248
|
+
const dirFiles = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
249
|
+
|
|
250
|
+
const dataFiles = dirFiles
|
|
251
|
+
.filter(file => file.isFile() && (file.name.endsWith('.txt') || file.name.endsWith('.pdf')))
|
|
252
|
+
.map(file => file.name);
|
|
253
|
+
|
|
254
|
+
const hasMetadata = dirFiles.some(file =>
|
|
255
|
+
file.isFile() && file.name.endsWith('_metadata.json')
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
testData.directories.push({
|
|
259
|
+
name: entry.name,
|
|
260
|
+
path: dirPath,
|
|
261
|
+
files: dataFiles,
|
|
262
|
+
hasMetadata: hasMetadata
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
res.json(testData);
|
|
269
|
+
} catch (error) {
|
|
270
|
+
res.status(500).json({ error: 'Failed to list test data', details: error.message });
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// API endpoint to load test data file content
|
|
275
|
+
app.get('/api/test-data/:type/:filename', (req, res) => {
|
|
276
|
+
try {
|
|
277
|
+
const type = req.params.type;
|
|
278
|
+
const filename = req.params.filename;
|
|
279
|
+
// Try subdirectory first, then root level
|
|
280
|
+
let filePath = path.join(TEST_DATA_PATH, type, filename);
|
|
281
|
+
|
|
282
|
+
// If not found in subdirectory, try root level
|
|
283
|
+
if (!fs.existsSync(filePath)) {
|
|
284
|
+
const rootPath = path.join(TEST_DATA_PATH, filename);
|
|
285
|
+
if (fs.existsSync(rootPath)) {
|
|
286
|
+
filePath = rootPath;
|
|
287
|
+
} else {
|
|
288
|
+
return res.status(404).json({ error: 'Test data file not found' });
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Check if file is PDF
|
|
293
|
+
if (filename.endsWith('.pdf')) {
|
|
294
|
+
// For PDFs, send file info and indicate it's a binary file
|
|
295
|
+
const stats = fs.statSync(filePath);
|
|
296
|
+
res.json({
|
|
297
|
+
filename: filename,
|
|
298
|
+
type: type,
|
|
299
|
+
isPdf: true,
|
|
300
|
+
size: stats.size,
|
|
301
|
+
message: 'PDF file - preview not available. Please open the file directly to view contents.'
|
|
302
|
+
});
|
|
303
|
+
} else {
|
|
304
|
+
// For text files, send the content
|
|
305
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
306
|
+
res.json({
|
|
307
|
+
filename: filename,
|
|
308
|
+
type: type,
|
|
309
|
+
content: content
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
} catch (error) {
|
|
313
|
+
res.status(500).json({ error: 'Failed to load test data file', details: error.message });
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// API endpoint to load test data metadata
|
|
318
|
+
app.get('/api/test-data/:type/metadata', (req, res) => {
|
|
319
|
+
try {
|
|
320
|
+
const type = req.params.type;
|
|
321
|
+
const metadataFiles = [
|
|
322
|
+
`${type}_metadata.json`,
|
|
323
|
+
'metadata.json'
|
|
324
|
+
];
|
|
325
|
+
|
|
326
|
+
let metadataPath = null;
|
|
327
|
+
for (const filename of metadataFiles) {
|
|
328
|
+
const potentialPath = path.join(TEST_DATA_PATH, type, filename);
|
|
329
|
+
if (fs.existsSync(potentialPath)) {
|
|
330
|
+
metadataPath = potentialPath;
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (!metadataPath) {
|
|
336
|
+
return res.status(404).json({ error: 'Metadata file not found' });
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
|
|
340
|
+
res.json(metadata);
|
|
341
|
+
} catch (error) {
|
|
342
|
+
res.status(500).json({ error: 'Failed to load metadata', details: error.message });
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// API endpoint to list groundtruth files
|
|
347
|
+
app.get('/api/groundtruth', (req, res) => {
|
|
348
|
+
try {
|
|
349
|
+
const groundtruthData = { directories: [], files: [] };
|
|
350
|
+
|
|
351
|
+
if (!fs.existsSync(GROUNDTRUTH_PATH)) {
|
|
352
|
+
return res.json(groundtruthData);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Function to recursively find groundtruth files
|
|
356
|
+
function findGroundtruthFiles(dir, relativePath = '') {
|
|
357
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
358
|
+
|
|
359
|
+
for (const entry of entries) {
|
|
360
|
+
const fullPath = path.join(dir, entry.name);
|
|
361
|
+
const relativeFilePath = relativePath ? path.join(relativePath, entry.name) : entry.name;
|
|
362
|
+
|
|
363
|
+
if (entry.isDirectory()) {
|
|
364
|
+
findGroundtruthFiles(fullPath, relativeFilePath);
|
|
365
|
+
} else if (entry.isFile() && entry.name.endsWith('.groundtruth.json')) {
|
|
366
|
+
groundtruthData.files.push({
|
|
367
|
+
name: entry.name,
|
|
368
|
+
path: relativeFilePath,
|
|
369
|
+
directory: relativePath || 'root',
|
|
370
|
+
type: entry.name.includes('consolidated') ? 'consolidated' : 'individual'
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
findGroundtruthFiles(GROUNDTRUTH_PATH);
|
|
377
|
+
|
|
378
|
+
res.json(groundtruthData);
|
|
379
|
+
} catch (error) {
|
|
380
|
+
res.status(500).json({ error: 'Failed to list groundtruth files', details: error.message });
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// API endpoint to load groundtruth file content
|
|
385
|
+
app.get('/api/groundtruth/:filename(*)', (req, res) => {
|
|
386
|
+
try {
|
|
387
|
+
const filename = req.params.filename;
|
|
388
|
+
const filePath = path.join(GROUNDTRUTH_PATH, filename);
|
|
389
|
+
|
|
390
|
+
if (!fs.existsSync(filePath)) {
|
|
391
|
+
return res.status(404).json({ error: 'Groundtruth file not found' });
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
395
|
+
res.json(data);
|
|
396
|
+
} catch (error) {
|
|
397
|
+
res.status(500).json({ error: 'Failed to load groundtruth file', details: error.message });
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// Serve the main application
|
|
402
|
+
app.get('/', (req, res) => {
|
|
403
|
+
res.sendFile(path.join(__dirname, 'public', 'index.html'));
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
app.listen(PORT, () => {
|
|
407
|
+
console.log(`Gaia Evaluation Visualizer running on http://localhost:${PORT}`);
|
|
408
|
+
console.log(`Experiments path: ${EXPERIMENTS_PATH}`);
|
|
409
|
+
console.log(`Evaluations path: ${EVALUATIONS_PATH}`);
|
|
410
|
+
console.log(`Test data path: ${TEST_DATA_PATH}`);
|
|
411
|
+
console.log(`Groundtruth path: ${GROUNDTRUTH_PATH}`);
|
|
412
|
+
console.log(`Agent outputs path: ${AGENT_OUTPUTS_PATH}`);
|
|
413
|
+
if (SINGLE_AGENT_FILE) {
|
|
414
|
+
console.log(`Single agent file: ${SINGLE_AGENT_FILE}`);
|
|
415
|
+
}
|
|
416
416
|
});
|