airabbitX commited on
Commit
843c692
·
verified ·
1 Parent(s): 39bfa61

Create index.html

Browse files
Files changed (1) hide show
  1. index.html +702 -18
index.html CHANGED
@@ -1,19 +1,703 @@
1
- <!doctype html>
2
  <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
  <html>
3
+ <head>
4
+ <title>Surf Spot Finder (Animated Workflow Simulation)</title>
5
+ <style>
6
+ :root {
7
+ --primary-color: #00d230; /* theme.primaryColor */
8
+ --background-color: #FFFFFF; /* theme.backgroundColor */
9
+ --secondary-background-color: #F0F2F6; /* theme.secondaryBackgroundColor */
10
+ --text-color: #161616; /* theme.textColor */
11
+ --font-family: "sans serif", Arial, sans-serif;
12
+ --sidebar-width: 360px;
13
+ --border-radius: 6px;
14
+ --input-border-color: #ccc;
15
+ --input-focus-border-color: var(--primary-color);
16
+ }
17
+ body {
18
+ display: flex;
19
+ flex-direction: column;
20
+ font-family: var(--font-family);
21
+ background-color: var(--background-color);
22
+ color: var(--text-color);
23
+ margin: 0;
24
+ height: 100vh;
25
+ overflow: hidden;
26
+ }
27
+ .app-header {
28
+ padding: 10px 20px;
29
+ background-color: var(--secondary-background-color);
30
+ border-bottom: 1px solid #ddd;
31
+ font-size: 1.2em;
32
+ color: var(--primary-color);
33
+ text-align: center;
34
+ }
35
+ .app-container {
36
+ display: flex;
37
+ flex-grow: 1;
38
+ overflow: hidden;
39
+ }
40
+
41
+ /* Animation Controls */
42
+ #animation-controls {
43
+ padding: 15px 20px;
44
+ background-color: #e0f7fa;
45
+ border-bottom: 1px solid #b2ebf2;
46
+ display: flex;
47
+ align-items: center;
48
+ gap: 15px;
49
+ }
50
+ #animation-controls button { background-color: #00796b; }
51
+ #animation-controls button:hover:not(:disabled) { background-color: #004d40; }
52
+ #animation-status { font-style: italic; color: #004d40; }
53
+
54
+ /* Sidebar */
55
+ .sidebar {
56
+ width: var(--sidebar-width);
57
+ min-width: var(--sidebar-width);
58
+ background-color: var(--secondary-background-color);
59
+ padding: 20px;
60
+ overflow-y: auto;
61
+ border-right: 1px solid #ddd;
62
+ }
63
+ .sidebar h3 { color: var(--primary-color); margin-top: 0; border-bottom: 1px solid #ddd; padding-bottom: 5px;}
64
+ .sidebar .st-input-container, .sidebar .st-selectbox-container, .sidebar .st-date-input-container, .sidebar .st-time-input-container, .sidebar .st-checkbox-container {
65
+ margin-bottom: 18px;
66
+ }
67
+ .sidebar label {
68
+ display: block;
69
+ margin-bottom: 5px;
70
+ font-size: 0.9em;
71
+ font-weight: bold;
72
+ }
73
+ .sidebar input[type="text"], .sidebar input[type="number"], .sidebar input[type="date"], .sidebar select {
74
+ width: 100%;
75
+ padding: 8px 10px;
76
+ border-radius: var(--border-radius);
77
+ border: 1px solid var(--input-border-color);
78
+ box-sizing: border-box;
79
+ font-family: var(--font-family);
80
+ }
81
+ .sidebar input:focus, .sidebar select:focus {
82
+ border-color: var(--input-focus-border-color);
83
+ box-shadow: 0 0 0 2px rgba(0, 210, 48, 0.2);
84
+ outline: none;
85
+ }
86
+ .sidebar .st-button {
87
+ width: 100%;
88
+ padding: 10px;
89
+ background-color: var(--primary-color);
90
+ color: white;
91
+ border: none;
92
+ border-radius: var(--border-radius);
93
+ cursor: pointer;
94
+ font-size: 1em;
95
+ transition: background-color 0.2s;
96
+ }
97
+ .sidebar .st-button:hover:not(:disabled) { background-color: #00a020; }
98
+ .sidebar .st-button:disabled { background-color: #ccc; cursor: not-allowed; }
99
+ .sidebar .st-expander {
100
+ border: 1px solid #ddd;
101
+ border-radius: var(--border-radius);
102
+ margin-bottom: 15px;
103
+ background-color: #fff;
104
+ }
105
+ .sidebar .st-expander-header {
106
+ padding: 10px;
107
+ cursor: pointer;
108
+ font-weight: bold;
109
+ border-bottom: 1px solid #eee;
110
+ display: flex; justify-content: space-between; align-items: center;
111
+ }
112
+ .sidebar .st-expander-header::after { content: '▼'; font-size: 0.8em; }
113
+ .sidebar .st-expander.expanded .st-expander-header::after { content: '▲'; }
114
+ .sidebar .st-expander-content {
115
+ padding: 10px;
116
+ display: none; /* Toggled by JS */
117
+ }
118
+ .sidebar .st-expander.expanded .st-expander-content { display: block; }
119
+ .sidebar .st-data-editor { border: 1px solid #ccc; padding: 5px; min-height: 80px; background-color: #f9f9f9; font-size:0.9em; }
120
+
121
+ /* Main Content Area */
122
+ .main-content {
123
+ flex-grow: 1;
124
+ padding: 25px;
125
+ overflow-y: auto;
126
+ }
127
+ .main-content h1, .main-content h2, .main-content h3 {
128
+ color: #1B365D; /* From previous simulation, good for headers */
129
+ }
130
+ .main-content .st-info, .main-content .st-success, .main-content .st-error, .main-content .st-code, .main-content .st-status {
131
+ padding: 12px 15px;
132
+ margin: 15px 0;
133
+ border-radius: var(--border-radius);
134
+ border-left-width: 5px;
135
+ border-left-style: solid;
136
+ }
137
+ .main-content .st-info { background-color: #e7f3fe; border-left-color: #2196F3; }
138
+ .main-content .st-success { background-color: #e8f5e9; border-left-color: #4CAF50; }
139
+ .main-content .st-error { background-color: #ffebee; border-left-color: #f44336; }
140
+ .main-content .st-code { background-color: #f5f5f5; border: 1px solid #e0e0e0; padding: 10px; white-space: pre-wrap; font-family: monospace;}
141
+ .main-content .st-status { background-color: #fff8e1; border-left-color: #ffc107; }
142
+ .main-content .st-expander {
143
+ border: 1px solid #ddd; border-radius: var(--border-radius); margin: 20px 0;
144
+ }
145
+ .main-content .st-expander-header {
146
+ padding: 12px 15px; cursor: pointer; font-weight: bold; background-color: #f9f9f9;
147
+ border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center;
148
+ }
149
+ .main-content .st-expander-header::after { content: '▼'; font-size: 0.8em; }
150
+ .main-content .st-expander.expanded .st-expander-header::after { content: '▲'; }
151
+ .main-content .st-expander-content { padding: 15px; display: none; }
152
+ .main-content .st-expander.expanded .st-expander-content { display: block; }
153
+
154
+ .results-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-bottom: 20px;}
155
+ .trace-span { border: 1px solid #eee; padding: 10px; margin-bottom: 10px; border-radius: var(--border-radius); }
156
+ .trace-span-header { display: flex; justify-content: space-between; font-weight: bold; margin-bottom: 5px; }
157
+ .trace-span-status-ok { color: green; }
158
+ .trace-span-status-error { color: red; }
159
+ .trace-span-details { font-size: 0.9em; color: #555; white-space: pre-wrap; word-break: break-all;}
160
+
161
+ .evaluation-results-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
162
+ .progress-bar-container { background-color: #e0e0e0; border-radius: var(--border-radius); overflow: hidden; height: 20px; margin: 5px 0;}
163
+ .progress-bar { background-color: var(--primary-color); height: 100%; width: 0%; transition: width 0.5s ease-out; }
164
+
165
+
166
+ /* Animation specific styles */
167
+ .sim-focus { border-color: var(--primary-color) !important; box-shadow: 0 0 0 3px rgba(0, 210, 48, 0.3) !important; }
168
+ .sim-active-button { background-color: #00a020 !important; transform: scale(0.98); }
169
+ .sim-selectbox-option { background-color: #e0ffe0 !important; }
170
+ .sim-expander-toggle { background-color: #f0f0f0; }
171
+ .gif-simulation-overlay {
172
+ position: fixed; top: 0; left: 0; width: 100%; height: 100%;
173
+ background-color: rgba(0,0,0,0.5); color: white;
174
+ display: flex; flex-direction: column; justify-content: center; align-items: center;
175
+ z-index: 1000; font-size: 1.5em;
176
+ }
177
+ .gif-simulation-overlay .progress-bar-container { width: 50%; margin-top: 20px; }
178
+ </style>
179
+ </head>
180
+ <body>
181
+ <div class="app-header">🏄 Surf Spot Finder - Animated Simulation</div>
182
+ <div id="animation-controls">
183
+ <button id="start-animation-btn">Run Full Workflow Animation</button>
184
+ <button id="download-gif-btn">Download GIF (Simulated)</button>
185
+ <span id="animation-status"></span>
186
+ </div>
187
+ <div class="app-container">
188
+ <div class="sidebar" id="sidebar">
189
+ <!-- Sidebar content will be rendered here by JS -->
190
+ </div>
191
+ <div class="main-content" id="main-content">
192
+ <!-- Main content will be rendered here by JS -->
193
+ </div>
194
+ </div>
195
+
196
+ <script>
197
+ // --- State Variables ---
198
+ let simState = {
199
+ location: "Los Angeles California, US",
200
+ maxDrivingHours: 2,
201
+ date: new Date(new Date().setDate(new Date().getDate() + 1)), // Tomorrow
202
+ time: "09:00",
203
+ framework: "OPENAI", // Default, assuming AgentFramework.OPENAI.name
204
+ modelId: "openai/gpt-4.1-mini",
205
+ evalModelId: "openai/gpt-4o",
206
+ evalCheckpoints: [
207
+ { criteria: "Agent considered at least three surf spots", points: 1, id: "cp1" },
208
+ { criteria: "Agent gathered wind forecasts", points: 1, id: "cp2" },
209
+ ],
210
+ runEvaluation: true,
211
+ // For agent run
212
+ currentQuery: "",
213
+ agentTraceSpans: [],
214
+ finalAgentOutput: "",
215
+ executionTime: 0,
216
+ estimatedCost: 0,
217
+ totalTokens: 0,
218
+ evaluationResults: null
219
+ };
220
+ let isAnimating = false;
221
+ let currentStatusMessages = [];
222
+
223
+ // --- DOM Elements ---
224
+ const animationStatusEl = document.getElementById('animation-status');
225
+ const sidebarEl = document.getElementById('sidebar');
226
+ const mainContentEl = document.getElementById('main-content');
227
+ const startAnimationBtn = document.getElementById('start-animation-btn');
228
+ const downloadGifBtn = document.getElementById('download-gif-btn');
229
+
230
+ // --- Helper & Simulation Functions ---
231
+ async function simulateDelay(ms) { /* ... as before ... */
232
+ if (!isAnimating) return;
233
+ return new Promise(resolve => setTimeout(resolve, ms));
234
+ }
235
+ async function simulateType(element, text, charDelay = 50) { /* ... as before ... */
236
+ if (!isAnimating) { element.value = text; return; }
237
+ element.classList.add('sim-focus');
238
+ element.value = '';
239
+ for (const char of text) {
240
+ element.value += char;
241
+ await simulateDelay(charDelay + Math.random() * 10);
242
+ }
243
+ element.classList.remove('sim-focus');
244
+ }
245
+ async function simulateClick(buttonElement, actionDelay = 200) { /* ... as before ... */
246
+ if (!isAnimating) return;
247
+ buttonElement.classList.add('sim-active-button');
248
+ await simulateDelay(actionDelay);
249
+ buttonElement.classList.remove('sim-active-button');
250
+ await simulateDelay(50);
251
+ }
252
+ async function simulateSelect(selectElement, value, displayDelay = 500) {
253
+ if (!isAnimating) { selectElement.value = value; return; }
254
+ selectElement.classList.add('sim-focus');
255
+ // Briefly show each option leading up to the target for visual effect
256
+ const options = Array.from(selectElement.options);
257
+ const targetIndex = options.findIndex(opt => opt.value === value);
258
+ if (targetIndex === -1) {
259
+ console.warn(`Value ${value} not found in select`);
260
+ selectElement.value = value; // try to set it anyway
261
+ selectElement.classList.remove('sim-focus');
262
+ return;
263
+ }
264
+ for (let i = 0; i <= targetIndex; i++) {
265
+ selectElement.value = options[i].value;
266
+ options[i].classList.add('sim-selectbox-option');
267
+ await simulateDelay(50 + Math.random()*20);
268
+ if (i < targetIndex) options[i].classList.remove('sim-selectbox-option');
269
+ }
270
+ await simulateDelay(displayDelay);
271
+ options[targetIndex].classList.remove('sim-selectbox-option');
272
+ selectElement.classList.remove('sim-focus');
273
+ }
274
+ async function simulateCheckbox(checkboxElement, checked, displayDelay = 300) {
275
+ if (!isAnimating) { checkboxElement.checked = checked; return; }
276
+ checkboxElement.classList.add('sim-focus');
277
+ await simulateDelay(displayDelay / 2);
278
+ checkboxElement.checked = checked;
279
+ await simulateDelay(displayDelay / 2);
280
+ checkboxElement.classList.remove('sim-focus');
281
+ }
282
+ async function simulateExpanderToggle(expanderHeaderElement, expand = true) {
283
+ if (!isAnimating) {
284
+ const content = expanderHeaderElement.nextElementSibling;
285
+ expanderHeaderElement.parentElement.classList.toggle('expanded', expand);
286
+ if (content) content.style.display = expand ? 'block' : 'none';
287
+ return;
288
+ }
289
+ expanderHeaderElement.classList.add('sim-expander-toggle');
290
+ await simulateDelay(200);
291
+ const content = expanderHeaderElement.nextElementSibling;
292
+ expanderHeaderElement.parentElement.classList.toggle('expanded', expand);
293
+ if (content) content.style.display = expand ? 'block' : 'none';
294
+ await simulateDelay(200);
295
+ expanderHeaderElement.classList.remove('sim-expander-toggle');
296
+ }
297
+ function downloadFile(filename, content, mimeType) { /* ... as before ... */
298
+ const blob = new Blob([content], { type: mimeType });
299
+ const url = URL.createObjectURL(blob);
300
+ const a = document.createElement('a');
301
+ a.href = url;
302
+ a.download = filename;
303
+ document.body.appendChild(a);
304
+ a.click();
305
+ URL.revokeObjectURL(url);
306
+ document.body.removeChild(a);
307
+ if(!isAnimating) alert(`Simulated download: ${filename}`);
308
+ }
309
+
310
+
311
+ // --- UI Rendering Functions ---
312
+ function renderSidebar() {
313
+ // Simplified: In a real Streamlit app, these are Python calls. Here, we build HTML.
314
+ sidebarEl.innerHTML = `
315
+ <h3>Configuration</h3>
316
+ <div class="st-input-container">
317
+ <label for="sim-location">Enter a location</label>
318
+ <input type="text" id="sim-location" value="${simState.location}">
319
+ <div id="sim-location-status" style="font-size:0.8em; text-align:right;"></div>
320
+ </div>
321
+ <div class="st-input-container">
322
+ <label for="sim-maxDrivingHours">Enter the maximum driving hours</label>
323
+ <input type="number" id="sim-maxDrivingHours" value="${simState.maxDrivingHours}" min="1">
324
+ </div>
325
+ <div style="display: flex; gap: 10px;">
326
+ <div class="st-date-input-container" style="flex:2;">
327
+ <label for="sim-date">Select a date</label>
328
+ <input type="date" id="sim-date" value="${simState.date.toISOString().split('T')[0]}">
329
+ </div>
330
+ <div class="st-time-input-container" style="flex:1;">
331
+ <label for="sim-time">Select a time</label>
332
+ <select id="sim-time">
333
+ ${Array.from({length: 24}, (_, i) => i).map(h =>
334
+ `<option value="${String(h).padStart(2, '0')}:00" ${simState.time === `${String(h).padStart(2, '0')}:00` ? 'selected' : ''}>${String(h).padStart(2, '0')}:00</option>`
335
+ ).join('')}
336
+ </select>
337
+ </div>
338
+ </div>
339
+ <div class="st-selectbox-container">
340
+ <label for="sim-framework">Select the agent framework to use</label>
341
+ <select id="sim-framework">
342
+ <option value="ANYAGENT" ${simState.framework === 'ANYAGENT' ? 'selected':''}>ANYAGENT</option>
343
+ <option value="OPENAI" ${simState.framework === 'OPENAI' ? 'selected':''}>OPENAI</option>
344
+ <option value="LANGCHAIN" ${simState.framework === 'LANGCHAIN' ? 'selected':''}>LANGCHAIN</option>
345
+ </select>
346
+ </div>
347
+ <div class="st-selectbox-container">
348
+ <label for="sim-modelId">Select the model to use</label>
349
+ <select id="sim-modelId">
350
+ <option value="openai/gpt-4.1-nano" ${simState.modelId === 'openai/gpt-4.1-nano' ? 'selected':''}>openai/gpt-4.1-nano</option>
351
+ <option value="openai/gpt-4.1-mini" ${simState.modelId === 'openai/gpt-4.1-mini' ? 'selected':''}>openai/gpt-4.1-mini</option>
352
+ <option value="openai/gpt-4o" ${simState.modelId === 'openai/gpt-4o' ? 'selected':''}>openai/gpt-4o</option>
353
+ </select>
354
+ </div>
355
+ <div class="st-expander" id="sim-eval-expander">
356
+ <div class="st-expander-header" onclick="toggleExpander('sim-eval-expander')">Custom Evaluation</div>
357
+ <div class="st-expander-content">
358
+ <div class="st-selectbox-container">
359
+ <label for="sim-evalModelId">Evaluation Model</label>
360
+ <select id="sim-evalModelId">
361
+ <option value="openai/gpt-4.1-mini" ${simState.evalModelId === 'openai/gpt-4.1-mini' ? 'selected':''}>openai/gpt-4.1-mini</option>
362
+ <option value="openai/gpt-4o" ${simState.evalModelId === 'openai/gpt-4o' ? 'selected':''}>openai/gpt-4o</option>
363
+ </select>
364
+ </div>
365
+ <label>Checkpoints (Simplified Edit):</label>
366
+ <div class="st-data-editor" id="sim-evalCheckpoints">
367
+ ${simState.evalCheckpoints.map(cp => `<div>- ${cp.criteria} (${cp.points} pts) <input type="text" value="${cp.criteria}" data-id="${cp.id}" class="sim-checkpoint-crit"><input type="number" value="${cp.points}" data-id="${cp.id}" class="sim-checkpoint-pts" style="width:50px;"></div>`).join('')}
368
+ </div>
369
+ <div class="st-checkbox-container">
370
+ <input type="checkbox" id="sim-runEvaluation" ${simState.runEvaluation ? 'checked' : ''}>
371
+ <label for="sim-runEvaluation">Run Evaluation</label>
372
+ </div>
373
+ </div>
374
+ </div>
375
+ <button class="st-button" id="sim-run-agent-btn">Run Agent 🤖</button>
376
+ `;
377
+ // Add event listeners for manual interaction (if not animating)
378
+ document.getElementById('sim-run-agent-btn').onclick = () => { if (!isAnimating) manualRunAgent(); };
379
+ // More listeners for inputs can be added if full manual mode is desired
380
+ }
381
+
382
+ function toggleExpander(expanderId) { // For manual clicks
383
+ if (isAnimating) return;
384
+ const expander = document.getElementById(expanderId);
385
+ expander.classList.toggle('expanded');
386
+ const content = expander.querySelector('.st-expander-content');
387
+ if (content) content.style.display = expander.classList.contains('expanded') ? 'block' : 'none';
388
+ }
389
+
390
+ function renderInitialMainContent() {
391
+ mainContentEl.innerHTML = `
392
+ <h1>🏄 Surf Spot Finder</h1>
393
+ <p>Find the best surfing spots based on your location and preferences! This is a simulation of the <a href="#" target="_blank" rel="noopener noreferrer">[Original Github Repo]</a>.</p>
394
+ <div class="st-info">👈 Configure your search parameters in the sidebar and click Run Agent to start (or run the full animation)!</div>
395
+ <h3>🛠️ Available Tools (Simulated)</h3>
396
+ <div class="st-expander">
397
+ <div class="st-expander-header" onclick="toggleExpander(this.parentElement)">🌤️ Weather Tools</div>
398
+ <div class="st-expander-content">
399
+ <p><strong>get_wind_forecast:</strong> Gets wind conditions for a spot.</p>
400
+ <p><strong>get_wave_forecast:</strong> Gets wave conditions for a spot.</p>
401
+ </div>
402
+ </div>
403
+ <div class="st-expander">
404
+ <div class="st-expander-header" onclick="toggleExpander(this.parentElement)">📍 Location Tools</div>
405
+ <div class="st-expander-content">
406
+ <p><strong>get_area_lat_lon:</strong> Converts area name to lat/lon.</p>
407
+ <p><strong>get_surfing_spots:</strong> Finds surf spots near lat/lon.</p>
408
+ <p><strong>driving_hours_to_meters:</strong> Converts driving hours to meters.</p>
409
+ </div>
410
+ </div>
411
+ <h3>📊 Custom Evaluation</h3>
412
+ <p>The Surf Spot Finder includes a powerful evaluation system. Configure it in the sidebar!</p>
413
+ `;
414
+ }
415
+
416
+ function renderAgentRunView() {
417
+ let html = `<h2>🔍 Running Surf Spot Finder...</h2>`;
418
+ html += `<div class="st-code" id="sim-query-display">Query: ${simState.currentQuery}</div>`;
419
+ html += `<div class="st-status" id="sim-status-display">Agent is running...</div>`;
420
+
421
+ // After run is complete
422
+ if (simState.finalAgentOutput) {
423
+ html = `<h2>🏄 Results</h2>`; // Overwrite "Running..."
424
+ html += `<div class="results-grid">
425
+ <div class="st-info">⏱️ Execution Time: ${simState.executionTime.toFixed(2)}s</div>
426
+ <div class="st-info">💰 Estimated Cost: $${simState.estimatedCost.toFixed(6)}</div>
427
+ <div class="st-info">📦 Total Tokens: ${simState.totalTokens}</div>
428
+ </div>`;
429
+ html += `<h3>Final Output</h3><div class="st-success">${simState.finalAgentOutput}</div>`;
430
+
431
+ html += `<div class="st-expander expanded" id="sim-agent-trace-expander">
432
+ <div class="st-expander-header" onclick="toggleExpander('sim-agent-trace-expander')">🧩 Agent Trace</div>
433
+ <div class="st-expander-content" id="sim-agent-trace-content">
434
+ ${simState.agentTraceSpans.map(span => `
435
+ <div class="trace-span">
436
+ <div class="trace-span-header">
437
+ <span>${span.name}</span>
438
+ <span class="${span.status === 'OK' ? 'trace-span-status-ok' : 'trace-span-status-error'}">● ${span.status}</span>
439
+ </div>
440
+ <div class="trace-span-details">
441
+ ${span.input ? `<strong>Input:</strong> ${JSON.stringify(span.input).substring(0,150)}...<br>` : ''}
442
+ ${span.output ? `<strong>Output:</strong> ${JSON.stringify(span.output).substring(0,150)}...` : ''}
443
+ </div>
444
+ </div>
445
+ `).join('')}
446
+ </div>
447
+ </div>`;
448
+
449
+ if (simState.runEvaluation && simState.evaluationResults) {
450
+ const { criteriaResults, overallScore, totalPossiblePoints } = simState.evaluationResults;
451
+ html += `<h2>📊 Evaluation Results</h2>
452
+ <div class="evaluation-results-grid">
453
+ <div><h4>Criteria Results</h4>
454
+ ${criteriaResults.map(cr => `
455
+ <div class="${cr.passed ? 'st-success' : 'st-error'}" style="margin-bottom:5px; padding:8px;">
456
+ ${cr.passed ? '✅' : '❌'} ${cr.criteria} (${cr.points} pts)
457
+ </div>`).join('')}
458
+ </div>
459
+ <div><h4>Overall Score</h4>
460
+ <h3>${overallScore} / ${totalPossiblePoints}</h3>
461
+ <div class="progress-bar-container"><div class="progress-bar" style="width:${(overallScore/totalPossiblePoints)*100}%"></div></div>
462
+ <strong>${((overallScore/totalPossiblePoints)*100).toFixed(1)}%</strong>
463
+ </div>
464
+ </div>`;
465
+ }
466
+ }
467
+ mainContentEl.innerHTML = html;
468
+ }
469
+
470
+ function updateStatusDisplay(message, isRunning = true) {
471
+ const statusEl = document.getElementById('sim-status-display');
472
+ if (statusEl) {
473
+ currentStatusMessages.push(message);
474
+ if (currentStatusMessages.length > 3) currentStatusMessages.shift(); // Keep last 3
475
+ statusEl.innerHTML = currentStatusMessages.join('<br>') + (isRunning ? '<br><em>Agent is active...</em>' : '<br><strong>Agent run finished!</strong>');
476
+ if (!isRunning) statusEl.classList.replace('st-status', 'st-success');
477
+ }
478
+ }
479
+
480
+ // --- Core Simulation Logic ---
481
+ async function manualRunAgent() { // For manual button click
482
+ if (isAnimating) return;
483
+ // Gather inputs from DOM
484
+ simState.location = document.getElementById('sim-location').value;
485
+ simState.maxDrivingHours = parseInt(document.getElementById('sim-maxDrivingHours').value);
486
+ simState.date = new Date(document.getElementById('sim-date').value + 'T' + document.getElementById('sim-time').value);
487
+ simState.framework = document.getElementById('sim-framework').value;
488
+ simState.modelId = document.getElementById('sim-modelId').value;
489
+ simState.evalModelId = document.getElementById('sim-evalModelId').value;
490
+ // Simplified checkpoint reading for manual
491
+ simState.evalCheckpoints = Array.from(document.querySelectorAll('#sim-evalCheckpoints .sim-checkpoint-crit')).map((inp,idx) => ({
492
+ id: `cp${idx+1}`,
493
+ criteria: inp.value,
494
+ points: parseInt(document.querySelectorAll('#sim-evalCheckpoints .sim-checkpoint-pts')[idx].value) || 1
495
+ }));
496
+ simState.runEvaluation = document.getElementById('sim-runEvaluation').checked;
497
+
498
+ await _runAgentLogic();
499
+ }
500
+
501
+ async function _runAgentLogic() {
502
+ simState.currentQuery = `Find surf spots near ${simState.location} within ${simState.maxDrivingHours} hours drive for ${simState.date.toDateString()} at ${simState.time}.`;
503
+ simState.agentTraceSpans = [];
504
+ simState.finalAgentOutput = "";
505
+ simState.executionTime = 0;
506
+ simState.estimatedCost = 0;
507
+ simState.totalTokens = 0;
508
+ simState.evaluationResults = null;
509
+ currentStatusMessages = [];
510
+
511
+ renderAgentRunView(); // Initial view with query and "Running..."
512
+
513
+ const startTime = Date.now();
514
+
515
+ // Simulate agent steps
516
+ await simulateAgentStep("Tool: get_area_lat_lon", {location: simState.location}, {lat: 36.97, lon: -122.03}, "OK"); // Santa Cruz approx
517
+ await simulateAgentStep("Tool: driving_hours_to_meters", {hours: simState.maxDrivingHours}, {meters: simState.maxDrivingHours * 50000}, "OK"); // Rough conversion
518
+ await simulateAgentStep("Tool: get_surfing_spots", {lat: 36.97, lon: -122.03, radius: simState.maxDrivingHours * 50000}, {spots: ["Steamer Lane", "Cowell's Beach", "Pleasure Point"]}, "OK");
519
+ await simulateAgentStep("Tool: get_wave_forecast", {spot: "Steamer Lane", date: simState.date.toISOString()}, {waveHeight: "4-6ft", period: "12s"}, "OK");
520
+ await simulateAgentStep("Tool: get_wind_forecast", {spot: "Steamer Lane", date: simState.date.toISOString()}, {speed: "10mph", direction: "NW"}, "OK");
521
+
522
+ simState.finalAgentOutput = `Recommended Spot: Steamer Lane. Forecast for ${simState.date.toDateString()} ${simState.time}: Waves 4-6ft (12s period), Wind 10mph NW. Other options: Cowell's Beach, Pleasure Point.`;
523
+ simState.executionTime = (Date.now() - startTime) / 1000 + (Math.random() * 2); // Add some randomness
524
+ simState.estimatedCost = 0.0015 + Math.random() * 0.001;
525
+ simState.totalTokens = 1200 + Math.floor(Math.random() * 500);
526
+
527
+ updateStatusDisplay("Agent finished processing.", false);
528
+
529
+ if (simState.runEvaluation) {
530
+ await _runEvaluationLogic();
531
+ }
532
+ renderAgentRunView(); // Final render with all results
533
+ }
534
+
535
+ async function simulateAgentStep(name, input, output, status) {
536
+ if (!isAnimating && !document.hidden) await simulateDelay(500 + Math.random() * 500); // Only delay if visible and not animating full flow
537
+ else if (isAnimating) await simulateDelay(300 + Math.random() * 200);
538
+
539
+ const span = { name, input, output, status };
540
+ simState.agentTraceSpans.push(span);
541
+ updateStatusDisplay(`Step: ${name} (${status}) - Input: ${JSON.stringify(input).substring(0,30)}... Output: ${JSON.stringify(output).substring(0,30)}...`);
542
+ if (isAnimating) renderAgentRunView(); // Re-render trace during animation
543
+ }
544
+
545
+ async function _runEvaluationLogic() {
546
+ if (isAnimating) await simulateDelay(1000); // Simulate evaluation time
547
+ let overallScore = 0;
548
+ let totalPossiblePoints = 0;
549
+ const criteriaResults = simState.evalCheckpoints.map(cp => {
550
+ const passed = Math.random() > 0.3; // 70% chance of passing for simulation
551
+ if (passed) overallScore += cp.points;
552
+ totalPossiblePoints += cp.points;
553
+ return { criteria: cp.criteria, points: cp.points, passed };
554
+ });
555
+ simState.evaluationResults = { criteriaResults, overallScore, totalPossiblePoints };
556
+ }
557
+
558
+ // --- Animation Workflow ---
559
+ startAnimationBtn.addEventListener('click', async () => {
560
+ if (isAnimating) {
561
+ isAnimating = false;
562
+ animationStatusEl.textContent = "Animation stopped by user.";
563
+ startAnimationBtn.textContent = "Run Full Workflow Animation";
564
+ document.querySelectorAll('.sidebar button, .sidebar input, .sidebar select').forEach(el => el.disabled = false);
565
+ return;
566
+ }
567
+ isAnimating = true;
568
+ startAnimationBtn.textContent = "Stop Animation";
569
+ animationStatusEl.textContent = "Animation running...";
570
+ document.querySelectorAll('.sidebar button, .sidebar input, .sidebar select').forEach(el => el.disabled = true);
571
+ startAnimationBtn.disabled = false; // Keep stop button enabled
572
+
573
+ _resetSimStateForAnimation();
574
+ renderSidebar(); // Initial render for animation
575
+ renderInitialMainContent();
576
+
577
+ try {
578
+ await animateFullWorkflow();
579
+ if (isAnimating) animationStatusEl.textContent = "Animation completed!";
580
+ } catch (error) {
581
+ if (isAnimating) {
582
+ console.error("Animation error:", error);
583
+ animationStatusEl.textContent = "Animation encountered an error: " + error.message;
584
+ }
585
+ } finally {
586
+ isAnimating = false;
587
+ startAnimationBtn.textContent = "Run Full Workflow Animation";
588
+ document.querySelectorAll('.sidebar button, .sidebar input, .sidebar select').forEach(el => el.disabled = false);
589
+ startAnimationBtn.disabled = false;
590
+ }
591
+ });
592
+
593
+ function _resetSimStateForAnimation() {
594
+ simState = { // Reset to defaults
595
+ location: "", maxDrivingHours: 1, date: new Date(new Date().setDate(new Date().getDate() + 2)), time: "10:00",
596
+ framework: "ANYAGENT", modelId: "openai/gpt-4o", evalModelId: "openai/gpt-4o",
597
+ evalCheckpoints: [ { criteria: "Agent used location tool", points: 1, id: "acp1" }, { criteria: "Agent found spots", points: 2, id: "acp2" } ],
598
+ runEvaluation: true, currentQuery: "", agentTraceSpans: [], finalAgentOutput: "",
599
+ executionTime: 0, estimatedCost: 0, totalTokens: 0, evaluationResults: null
600
+ };
601
+ currentStatusMessages = [];
602
+ }
603
+
604
+ async function animateFullWorkflow() {
605
+ animationStatusEl.textContent = "Animating: Sidebar Inputs...";
606
+
607
+ // Location
608
+ const locationInput = document.getElementById('sim-location');
609
+ await simulateType(locationInput, "Santa Cruz, California");
610
+ simState.location = locationInput.value;
611
+ document.getElementById('sim-location-status').textContent = '✅ Validated'; // Simulate validation
612
+ await simulateDelay(300);
613
+
614
+ // Max Driving Hours
615
+ const hoursInput = document.getElementById('sim-maxDrivingHours');
616
+ await simulateType(hoursInput, "1"); // Type "1"
617
+ simState.maxDrivingHours = parseInt(hoursInput.value);
618
+ await simulateDelay(300);
619
+
620
+ // Date & Time (simplified selection for animation)
621
+ const dateInput = document.getElementById('sim-date');
622
+ const futureDate = new Date(Date.now() + 3 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]; // 3 days in future
623
+ dateInput.value = futureDate; // Just set it
624
+ simState.date = new Date(futureDate);
625
+ dateInput.classList.add('sim-focus'); await simulateDelay(200); dateInput.classList.remove('sim-focus');
626
+
627
+ const timeSelect = document.getElementById('sim-time');
628
+ await simulateSelect(timeSelect, "10:00");
629
+ simState.time = timeSelect.value;
630
+ simState.date.setHours(10,0,0,0); // Update date object with time
631
+
632
+ // Framework & Model
633
+ await simulateSelect(document.getElementById('sim-framework'), "OPENAI");
634
+ simState.framework = document.getElementById('sim-framework').value;
635
+ await simulateSelect(document.getElementById('sim-modelId'), "openai/gpt-4o");
636
+ simState.modelId = document.getElementById('sim-modelId').value;
637
+
638
+ // Custom Evaluation
639
+ const evalExpanderHeader = document.getElementById('sim-eval-expander').firstElementChild;
640
+ await simulateExpanderToggle(evalExpanderHeader, true); // Expand
641
+ await simulateDelay(200);
642
+ await simulateSelect(document.getElementById('sim-evalModelId'), "openai/gpt-4o");
643
+ simState.evalModelId = document.getElementById('sim-evalModelId').value;
644
+
645
+ // Simulate editing a checkpoint
646
+ const firstCritInput = document.querySelector('#sim-evalCheckpoints .sim-checkpoint-crit');
647
+ if (firstCritInput) {
648
+ await simulateType(firstCritInput, "Agent correctly identified tide times");
649
+ simState.evalCheckpoints[0].criteria = firstCritInput.value;
650
+ }
651
+ await simulateCheckbox(document.getElementById('sim-runEvaluation'), true);
652
+ simState.runEvaluation = true;
653
+ await simulateDelay(500);
654
+ await simulateExpanderToggle(evalExpanderHeader, false); // Collapse
655
+
656
+ animationStatusEl.textContent = "Animating: Running Agent...";
657
+ await simulateClick(document.getElementById('sim-run-agent-btn'));
658
+ await _runAgentLogic(); // This will handle rendering the main content
659
+
660
+ if (isAnimating) animationStatusEl.textContent = "Animation: Workflow Complete!";
661
+ }
662
+
663
+ // --- GIF Download Simulation ---
664
+ downloadGifBtn.addEventListener('click', async () => {
665
+ if (isAnimating) {
666
+ alert("Please stop the main animation before simulating GIF download.");
667
+ return;
668
+ }
669
+ animationStatusEl.textContent = "Simulating GIF Download...";
670
+ downloadGifBtn.disabled = true;
671
+
672
+ const overlay = document.createElement('div');
673
+ overlay.className = 'gif-simulation-overlay';
674
+ overlay.innerHTML = `
675
+ <div>🎥 Simulating GIF Recording...</div>
676
+ <div class="progress-bar-container" style="width:300px; height: 20px; background: #555;">
677
+ <div class="progress-bar" id="gif-sim-progress" style="background: lightgreen; width:0%;"></div>
678
+ </div>
679
+ <p style="font-size:0.7em;">(This is a placeholder. Actual GIF generation is complex.)</p>
680
+ `;
681
+ document.body.appendChild(overlay);
682
+ const progressBar = document.getElementById('gif-sim-progress');
683
+
684
+ for (let i = 0; i <= 100; i+=10) {
685
+ progressBar.style.width = i + '%';
686
+ await new Promise(r => setTimeout(r, 150));
687
+ }
688
+
689
+ downloadFile("simulated_animation.txt", "This is a placeholder for an animated GIF of the workflow.\nActual client-side GIF generation of complex animations is computationally intensive.", "text/plain");
690
+
691
+ document.body.removeChild(overlay);
692
+ animationStatusEl.textContent = "GIF Download Simulation Complete.";
693
+ downloadGifBtn.disabled = false;
694
+ });
695
+
696
+
697
+ // --- Initial Page Load ---
698
+ renderSidebar();
699
+ renderInitialMainContent();
700
+
701
+ </script>
702
+ </body>
703
+ </html>