Molbap HF Staff commited on
Commit
3a8fe4b
·
verified ·
1 Parent(s): 695b000

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +421 -55
index.html CHANGED
@@ -1,57 +1,423 @@
1
  <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>Gradio-Lite: Serverless Gradio Running Entirely in Your Browser</title>
7
- <meta name="description" content="Gradio-Lite: Serverless Gradio Running Entirely in Your Browser">
8
-
9
- <script type="module" crossorigin src="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.js"></script>
10
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.css" />
11
-
12
- <style>
13
- html, body {
14
- margin: 0;
15
- padding: 0;
16
- height: 100%;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  }
18
- </style>
19
- </head>
20
- <body>
21
- <gradio-lite>
22
- <gradio-file name="app.py" entrypoint>
23
- import gradio as gr
24
-
25
- from filters import as_gray
26
-
27
- def process(input_image):
28
- output_image = as_gray(input_image)
29
- return output_image
30
-
31
- demo = gr.Interface(
32
- process,
33
- "image",
34
- "image",
35
- examples=["lion.jpg", "logo.png"],
36
- )
37
-
38
- demo.launch()
39
- </gradio-file>
40
-
41
- <gradio-file name="filters.py">
42
- from skimage.color import rgb2gray
43
-
44
- def as_gray(image):
45
- return rgb2gray(image)
46
- </gradio-file>
47
-
48
- <gradio-file name="lion.jpg" url="https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/test_data/lion.jpg" />
49
- <gradio-file name="logo.png" url="https://raw.githubusercontent.com/gradio-app/gradio/main/guides/assets/logo.png" />
50
-
51
- <gradio-requirements>
52
- # Same syntax as requirements.txt
53
- scikit-image
54
- </gradio-requirements>
55
- </gradio-lite>
56
- </body>
57
- </html>
 
1
  <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Python Code Structure Visualizer</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://d3js.org/d3.v7.min.js"></script>
9
+ <link rel="preconnect" href="https://fonts.googleapis.com">
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Fira+Code:wght@400;500&display=swap" rel="stylesheet">
12
+ <style>
13
+ body {
14
+ font-family: 'Inter', sans-serif;
15
+ }
16
+ .fira-code {
17
+ font-family: 'Fira Code', monospace;
18
+ }
19
+ /* Custom styles for D3 graph */
20
+ .graph-container {
21
+ width: 100%;
22
+ height: 100%;
23
+ min-height: 500px;
24
+ cursor: grab;
25
+ }
26
+ .graph-container:active {
27
+ cursor: grabbing;
28
+ }
29
+ .node circle {
30
+ stroke: #fff;
31
+ stroke-width: 1.5px;
32
+ }
33
+ .node text {
34
+ font-size: 10px;
35
+ font-family: 'Fira Code', monospace;
36
+ paint-order: stroke;
37
+ stroke: #111827; /* Match dark background */
38
+ stroke-width: 3px;
39
+ stroke-linecap: butt;
40
+ stroke-linejoin: miter;
41
+ pointer-events: none;
42
+ }
43
+ .link {
44
+ stroke-opacity: 0.6;
45
+ }
46
+ .link.inheritance {
47
+ stroke-dasharray: 5, 5;
48
+ stroke: #60a5fa; /* blue-400 */
49
+ }
50
+ .link.method {
51
+ stroke: #4b5563; /* gray-600 */
52
+ }
53
+ .node.selected > circle {
54
+ stroke: #facc15; /* yellow-400 */
55
+ stroke-width: 3px;
56
+ }
57
+ /* Tab styling */
58
+ .tab.active {
59
+ background-color: #3b82f6; /* blue-500 */
60
+ color: white;
61
+ }
62
+ </style>
63
+ </head>
64
+ <body class="bg-gray-900 text-gray-200 flex flex-col h-screen">
65
+ <header class="bg-gray-800/50 backdrop-blur-sm border-b border-gray-700 p-4 shadow-lg">
66
+ <h1 class="text-2xl font-bold text-center text-white">Bloatedness Visualizer</h1>
67
+ <p class="text-center text-gray-400 mt-1">Paste your model in the 'Main' tab and add dependencies in other tabs.</p>
68
+ </header>
69
+
70
+ <main class="flex-grow flex flex-col md:flex-row gap-4 p-4 overflow-hidden">
71
+ <!-- Left Panel: Code Input & Controls -->
72
+ <div class="md:w-1/3 flex flex-col h-full">
73
+ <div class="flex-grow flex flex-col bg-gray-800 rounded-lg shadow-2xl border border-gray-700">
74
+ <div class="p-4 border-b border-gray-700 flex justify-between items-center">
75
+ <h2 class="text-lg font-semibold">Code Input</h2>
76
+ <button id="visualize-btn" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-md transition-colors duration-300">
77
+ Visualize
78
+ </button>
79
+ </div>
80
+ <div class="border-b border-gray-700 bg-gray-900/50 px-2 pt-2 flex items-center gap-2">
81
+ <div id="tab-bar" class="flex gap-1">
82
+ <!-- Tabs will be dynamically inserted here -->
83
+ </div>
84
+ <button id="add-tab-btn" class="ml-auto bg-gray-600 hover:bg-gray-500 text-white font-bold h-8 w-8 rounded-full transition-colors duration-200">+</button>
85
+ </div>
86
+ <div id="code-inputs-container" class="flex-grow relative">
87
+ <!-- Textareas will be dynamically inserted here -->
88
+ </div>
89
+ </div>
90
+ </div>
91
+
92
+ <!-- Right Panel: Visualization & Details -->
93
+ <div class="md:w-2/3 flex flex-col gap-4 h-full">
94
+ <div class="flex-grow bg-gray-800 rounded-lg shadow-2xl border border-gray-700 relative overflow-hidden">
95
+ <div id="graph-container" class="w-full h-full"></div>
96
+ <div id="loading-spinner" class="absolute inset-0 bg-gray-800/50 flex items-center justify-center hidden z-10">
97
+ <svg class="animate-spin h-10 w-10 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
98
+ <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
99
+ <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
100
+ </svg>
101
+ </div>
102
+ </div>
103
+ <div id="details-panel" class="h-40 bg-gray-800 rounded-lg shadow-2xl border border-gray-700 p-4 flex flex-col">
104
+ <h3 class="text-lg font-semibold border-b border-gray-700 pb-2 mb-2">Details</h3>
105
+ <div id="details-content" class="text-gray-400 fira-code overflow-y-auto">
106
+ <p>Click on a node in the graph to see its details. Scroll to zoom, drag to pan.</p>
107
+ </div>
108
+ </div>
109
+ </div>
110
+ </main>
111
+
112
+ <script>
113
+ // --- DOM Element References ---
114
+ const visualizeBtn = document.getElementById('visualize-btn');
115
+ const graphContainer = document.getElementById('graph-container');
116
+ const detailsContent = document.getElementById('details-content');
117
+ const loadingSpinner = document.getElementById('loading-spinner');
118
+ const tabBar = document.getElementById('tab-bar');
119
+ const codeInputsContainer = document.getElementById('code-inputs-container');
120
+ const addTabBtn = document.getElementById('add-tab-btn');
121
+
122
+ // --- Example Code ---
123
+ const exampleCodeMain = `
124
+ # A specific model implementation that uses an external class
125
+ class MyAwesomeModel(BaseModel, AttentionMixin):
126
+ def __init__(self, config):
127
+ super().__init__(config)
128
+ self._init_attention(config)
129
+
130
+ def forward(self, input_ids) -> BaseModelOutputWithPast:
131
+ """The main forward pass for the model."""
132
+ x = self._split_heads(input_ids)
133
+ # The return type is a class not defined in this file
134
+ return BaseModelOutputWithPast(last_hidden_state=x)
135
+ `;
136
+
137
+ const exampleCodeDeps = `
138
+ # This class is an external dependency, not defined here
139
+ # from modeling_outputs import BaseModelOutputWithPast
140
+
141
+ # A common mixin for attention mechanisms
142
+ class AttentionMixin:
143
+ def _init_attention(self, config):
144
+ self.num_heads = config.num_heads
145
+ self.head_dim = config.hidden_size // config.num_heads
146
+
147
+ def _split_heads(self, tensor):
148
+ # Logic to split tensor for multi-head attention
149
+ return tensor
150
+
151
+ # A base class for all models, similar to PreTrainedModel
152
+ class BaseModel:
153
+ def __init__(self, config):
154
+ self.config = config
155
+
156
+ def from_pretrained(cls, model_name):
157
+ # Load weights
158
+ pass
159
+ `;
160
+
161
+ // --- Tab Management ---
162
+ let tabCounter = 0;
163
+
164
+ function addTab(name, content = '', isActive = false) {
165
+ tabCounter++;
166
+ const tabId = `tab-${tabCounter}`;
167
+ const textareaId = `textarea-${tabCounter}`;
168
+
169
+ // Create Tab Button
170
+ const tabButton = document.createElement('button');
171
+ tabButton.id = tabId;
172
+ tabButton.className = 'tab px-4 py-2 text-sm font-medium rounded-t-md transition-colors duration-200';
173
+ tabButton.textContent = name;
174
+ tabButton.dataset.textareaId = textareaId;
175
+ tabBar.appendChild(tabButton);
176
+
177
+ // Create Textarea
178
+ const textarea = document.createElement('textarea');
179
+ textarea.id = textareaId;
180
+ textarea.className = 'fira-code w-full h-full p-4 bg-gray-900 text-gray-300 resize-none focus:outline-none absolute top-0 left-0';
181
+ textarea.placeholder = `Paste dependency code here...`;
182
+ textarea.value = content;
183
+ codeInputsContainer.appendChild(textarea);
184
+
185
+ tabButton.addEventListener('click', () => switchTab(tabId));
186
+
187
+ if (isActive) {
188
+ switchTab(tabId);
189
+ } else {
190
+ textarea.classList.add('hidden');
191
+ }
192
+ }
193
+
194
+ function switchTab(tabId) {
195
+ // Update tab buttons
196
+ document.querySelectorAll('.tab').forEach(tab => {
197
+ tab.classList.toggle('active', tab.id === tabId);
198
+ });
199
+ // Update textareas
200
+ document.querySelectorAll('#code-inputs-container textarea').forEach(area => {
201
+ area.classList.toggle('hidden', area.id !== document.getElementById(tabId).dataset.textareaId);
202
+ });
203
+ }
204
+
205
+ addTabBtn.addEventListener('click', () => addTab(`Dep ${tabCounter}`));
206
+
207
+ // --- Core Logic: Parser ---
208
+ function parsePythonCode(code) {
209
+ const nodes = [];
210
+ const links = [];
211
+ const nodeRegistry = new Set();
212
+ let currentClassInfo = null;
213
+ const lines = code.split('\n');
214
+
215
+ lines.forEach(line => {
216
+ const indentation = line.match(/^\s*/)[0].length;
217
+ if (line.trim().length > 0 && indentation === 0) {
218
+ currentClassInfo = null;
219
+ }
220
+
221
+ const classMatch = /^\s*class\s+([\w\d_]+)\s*(?:\(([\w\d_,\s]+)\))?:/.exec(line);
222
+ if (classMatch) {
223
+ const className = classMatch[1];
224
+ const parents = classMatch[2] ? classMatch[2].split(',').map(p => p.trim()) : [];
225
+ if (!nodeRegistry.has(className)) {
226
+ nodes.push({ id: className, type: 'class', parents: parents });
227
+ nodeRegistry.add(className);
228
+ } else {
229
+ // If class was already created as an external placeholder, update it
230
+ const existingNode = nodes.find(n => n.id === className);
231
+ if (existingNode && existingNode.isExternal) {
232
+ existingNode.isExternal = false;
233
+ existingNode.parents = parents;
234
+ }
235
+ }
236
+
237
+ currentClassInfo = { name: className, indentation: indentation };
238
+
239
+ parents.forEach(parent => {
240
+ if (!nodeRegistry.has(parent)) {
241
+ nodes.push({ id: parent, type: 'class', isExternal: true, parents: [] });
242
+ nodeRegistry.add(parent);
243
+ }
244
+ links.push({ source: className, target: parent, type: 'inheritance' });
245
+ });
246
+ }
247
+
248
+ const methodMatch = /^\s+def\s+([\w\d_]+)\s*\(([^)]*)\)/.exec(line);
249
+ if (currentClassInfo && methodMatch && indentation > currentClassInfo.indentation) {
250
+ const methodName = methodMatch[1];
251
+ const signature = methodMatch[2];
252
+ const methodId = `${currentClassInfo.name}.${methodName}`;
253
+ if (!nodeRegistry.has(methodId)) {
254
+ nodes.push({ id: methodId, name: methodName, type: 'method', parentClass: currentClassInfo.name, signature: `(${signature})` });
255
+ nodeRegistry.add(methodId);
256
+ links.push({ source: currentClassInfo.name, target: methodId, type: 'method' });
257
+ }
258
+ }
259
+ });
260
+
261
+ return { nodes, links };
262
+ }
263
+
264
+ // --- Core Logic: D3 Visualization ---
265
+ let simulation;
266
+ function renderGraph(data) {
267
+ graphContainer.innerHTML = '';
268
+ const width = graphContainer.clientWidth;
269
+ const height = graphContainer.clientHeight;
270
+
271
+ const svg = d3.select(graphContainer).append("svg")
272
+ .attr("viewBox", [-width / 2, -height / 2, width, height]);
273
+
274
+ const container = svg.append("g");
275
+
276
+ // Add zoom capabilities
277
+ const zoom = d3.zoom()
278
+ .scaleExtent([0.1, 4])
279
+ .on("zoom", (event) => {
280
+ container.attr("transform", event.transform);
281
+ });
282
+ svg.call(zoom);
283
+
284
+
285
+ if (simulation) {
286
+ simulation.stop();
287
+ }
288
+
289
+ simulation = d3.forceSimulation(data.nodes)
290
+ .force("link", d3.forceLink(data.links).id(d => d.id).distance(d => d.type === 'inheritance' ? 150 : 60).strength(0.5))
291
+ .force("charge", d3.forceManyBody().strength(-400))
292
+ .force("center", d3.forceCenter(0, 0))
293
+ .force("x", d3.forceX())
294
+ .force("y", d3.forceY());
295
+
296
+ const link = container.append("g")
297
+ .selectAll("line")
298
+ .data(data.links)
299
+ .join("line")
300
+ .attr("class", d => `link ${d.type}`);
301
+
302
+ const node = container.append("g")
303
+ .selectAll("g")
304
+ .data(data.nodes)
305
+ .join("g")
306
+ .attr("class", "node")
307
+ .call(drag(simulation));
308
+
309
+ node.append("circle")
310
+ .attr("r", d => d.type === 'class' ? 15 : 8)
311
+ .attr("fill", d => {
312
+ if (d.type !== 'class') return '#9ca3af';
313
+ return d.isExternal ? '#be185d' : '#2563eb';
314
+ });
315
+
316
+ node.append("text")
317
+ .text(d => d.type === 'class' ? d.id : d.name)
318
+ .attr("x", d => d.type === 'class' ? 18 : 12)
319
+ .attr("y", 3)
320
+ .attr("fill", "#e5e7eb");
321
+
322
+ node.on("click", (event, d) => {
323
+ event.stopPropagation(); // Prevent zoom from firing on node click
324
+ updateDetailsPanel(d);
325
+ node.classed("selected", n => n.id === d.id);
326
+ });
327
+
328
+ simulation.on("tick", () => {
329
+ link.attr("x1", d => d.source.x).attr("y1", d => d.source.y)
330
+ .attr("x2", d => d.target.x).attr("y2", d => d.target.y);
331
+ node.attr("transform", d => `translate(${d.x},${d.y})`);
332
+ });
333
+ }
334
+
335
+ // --- Interactivity ---
336
+ function drag(simulation) {
337
+ function dragstarted(event, d) {
338
+ if (!event.active) simulation.alphaTarget(0.3).restart();
339
+ d.fx = d.x;
340
+ d.fy = d.y;
341
+ }
342
+ function dragged(event, d) {
343
+ d.fx = event.x;
344
+ d.fy = event.y;
345
+ }
346
+ function dragended(event, d) {
347
+ if (!event.active) simulation.alphaTarget(0);
348
+ d.fx = null;
349
+ d.fy = null;
350
+ }
351
+ return d3.drag()
352
+ .on("start", dragstarted)
353
+ .on("drag", dragged)
354
+ .on("end", dragended);
355
+ }
356
+
357
+ // --- UI Updates ---
358
+ function updateDetailsPanel(d) {
359
+ let content = '';
360
+ if (d.type === 'class') {
361
+ content = `
362
+ <p><span class="text-gray-100 font-semibold">Name:</span> ${d.id}</p>
363
+ <p><span class="text-gray-100 font-semibold">Type:</span> ${d.isExternal ? 'External Class' : 'Class'}</p>
364
+ <p><span class="text-gray-100 font-semibold">Inherits from:</span> ${d.parents && d.parents.length > 0 ? d.parents.join(', ') : 'None'}</p>
365
+ ${d.isExternal ? '<p class="text-pink-400 mt-1">Note: This class was not defined in the provided code.</p>' : ''}
366
+ `;
367
+ } else if (d.type === 'method') {
368
+ content = `
369
+ <p><span class="text-gray-100 font-semibold">Name:</span> ${d.name}</p>
370
+ <p><span class="text-gray-100 font-semibold">Type:</span> Method</p>
371
+ <p><span class="text-gray-100 font-semibold">Belongs to:</span> ${d.parentClass}</p>
372
+ <p><span class="text-gray-100 font-semibold">Signature:</span> ${d.name}${d.signature}</p>
373
+ `;
374
+ }
375
+ detailsContent.innerHTML = content;
376
+ }
377
+
378
+ function handleVisualize() {
379
+ loadingSpinner.classList.remove('hidden');
380
+ setTimeout(() => {
381
+ try {
382
+ let allCode = '';
383
+ document.querySelectorAll('#code-inputs-container textarea').forEach(area => {
384
+ allCode += area.value + '\n';
385
+ });
386
+
387
+ if (!allCode.trim()) {
388
+ graphContainer.innerHTML = '<p class="p-4 text-center text-gray-400">Please paste some code to visualize.</p>';
389
+ return;
390
+ }
391
+ const graphData = parsePythonCode(allCode);
392
+ renderGraph(graphData);
393
+ } catch (error) {
394
+ console.error("Failed to visualize code:", error);
395
+ graphContainer.innerHTML = `<p class="p-4 text-center text-red-400">An error occurred during parsing. Check the console for details.</p>`;
396
+ } finally {
397
+ loadingSpinner.classList.add('hidden');
398
+ }
399
+ }, 50);
400
+ }
401
+
402
+ // --- Event Listeners ---
403
+ visualizeBtn.addEventListener('click', handleVisualize);
404
+
405
+ // --- Initial Load ---
406
+ window.addEventListener('load', () => {
407
+ addTab('Main', exampleCodeMain, true);
408
+ addTab('Deps', exampleCodeDeps);
409
+ handleVisualize();
410
+ });
411
+ window.addEventListener('resize', () => {
412
+ let allCode = '';
413
+ document.querySelectorAll('#code-inputs-container textarea').forEach(area => {
414
+ allCode += area.value + '\n';
415
+ });
416
+ if (allCode.trim()) {
417
+ handleVisualize();
418
  }
419
+ });
420
+
421
+ </script>
422
+ </body>
423
+ </html>