Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Python Code Parser</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<script src="https://unpkg.com/[email protected]"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script> | |
<style> | |
.table-container { overflow-x: auto; } | |
pre { white-space: pre-wrap; word-wrap: break-word; } | |
#point-cloud { display: none; width: 100%; height: 400px; } | |
#point-details { width: 100%; min-height: 100px; background: #1f2937; padding: 1rem; border-radius: 0.5rem; } | |
</style> | |
</head> | |
<body class="bg-gray-900 text-gray-200 min-h-screen p-8 font-sans"> | |
<div class="max-w-7xl mx-auto bg-gray-800 p-6 rounded-xl shadow-2xl"> | |
<h1 class="text-3xl font-bold text-blue-400 mb-6">Python Code Parser</h1> | |
<!-- Form --> | |
<form hx-post="/" hx-target="#results" hx-swap="innerHTML" class="space-y-6"> | |
<div> | |
<label class="block text-sm font-medium text-gray-300 mb-2">Upload a Python File</label> | |
<input type="file" name="file" accept=".py" class="w-full p-2 border rounded-lg bg-gray-700 text-gray-200"> | |
</div> | |
<div> | |
<label class="block text-sm font-medium text-gray-300 mb-2">Or Paste Your Code</label> | |
<textarea name="code" rows="6" class="w-full p-2 border rounded-lg bg-gray-700 text-gray-200" placeholder="Paste Python code here...">{{ code_input or '' }}</textarea> | |
<input type="text" name="filename" class="mt-2 w-full p-2 border rounded-lg bg-gray-700 text-gray-200" placeholder="Enter filename (e.g., script.py)" value="{{ filename or '' }}"> | |
</div> | |
<button type="submit" class="w-full bg-blue-500 text-white p-2 rounded-lg hover:bg-blue-600 transition">Parse</button> | |
</form> | |
<!-- Results Section --> | |
<div id="results" class="mt-8"> | |
{% if parts %} | |
{% include 'results_partial.html' %} | |
{% endif %} | |
</div> | |
</div> | |
<!-- Three.js Point Cloud Script --> | |
<script> | |
let scene, camera, renderer, points, raycaster, mouse, hoveredPoint = null; | |
let isDragging = false, previousMousePosition = { x: 0, y: 0 }; | |
const pointDetails = document.getElementById('point-details'); | |
function initPointCloud(parts) { | |
const canvas = document.getElementById('point-cloud'); | |
scene = new THREE.Scene(); | |
camera = new THREE.PerspectiveCamera(75, canvas.offsetWidth / 400, 0.1, 1000); | |
renderer = new THREE.WebGLRenderer({ canvas: canvas, alpha: true }); | |
renderer.setSize(canvas.offsetWidth, 400); | |
const positions = []; | |
const colors = []; | |
parts.forEach((part, index) => { | |
const vector = part.vector; | |
const x = vector[0] * 10; // category_id | |
const y = vector[1] * 10; // level | |
const z = vector[2] * 100; // center_pos | |
positions.push(x, y, z); | |
// Color by category (e.g., variables in blue, others in orange) | |
let color; | |
if (['input_variable', 'assigned_variable', 'returned_variable'].includes(part.category)) { | |
color = [0, 0, 1]; // Blue for variables | |
} else { | |
color = [1, 0.5, 0]; // Orange for non-variables | |
} | |
colors.push(...color); | |
part.pointIndex = index * 3; // Store index for lookup | |
}); | |
const geometry = new THREE.BufferGeometry(); | |
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); | |
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3)); | |
const material = new THREE.PointsMaterial({ size: 5, vertexColors: true }); | |
points = new THREE.Points(geometry, material); | |
scene.add(points); | |
camera.position.z = 100; | |
raycaster = new THREE.Raycaster(); | |
raycaster.params.Points.threshold = 5; // Increase sensitivity | |
mouse = new THREE.Vector2(); | |
canvas.addEventListener('mousedown', onMouseDown); | |
canvas.addEventListener('mousemove', onMouseMove); | |
canvas.addEventListener('mouseup', onMouseUp); | |
} | |
function animate() { | |
requestAnimationFrame(animate); | |
renderer.render(scene, camera); | |
} | |
function onMouseDown(event) { | |
isDragging = true; | |
previousMousePosition = { x: event.clientX, y: event.clientY }; | |
} | |
function onMouseMove(event) { | |
const rect = renderer.domElement.getBoundingClientRect(); | |
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1; | |
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1; | |
if (isDragging) { | |
const deltaX = event.clientX - previousMousePosition.x; | |
const deltaY = event.clientY - previousMousePosition.y; | |
points.rotation.y += deltaX * 0.005; | |
points.rotation.x += deltaY * 0.005; | |
previousMousePosition = { x: event.clientX, y: event.clientY }; | |
} else { | |
raycaster.setFromCamera(mouse, camera); | |
const intersects = raycaster.intersectObject(points); | |
if (intersects.length > 0) { | |
const index = intersects[0].index; | |
const part = window.parts.find(p => p.pointIndex === index * 3); | |
if (part && hoveredPoint !== part) { | |
hoveredPoint = part; | |
const variableRole = part.category in ['input_variable', 'assigned_variable', 'returned_variable'] ? | |
part.category.replace('_variable', '').capitalize() : '-'; | |
pointDetails.innerHTML = ` | |
<div class="text-gray-200"> | |
<strong>Category:</strong> ${part.category}<br> | |
<strong>Node ID:</strong> ${part.node_id}<br> | |
<strong>Parent Path:</strong> ${part.parent_path}<br> | |
<strong>Level:</strong> ${part.level}<br> | |
<strong>Location:</strong> Lines ${part.location[0]} to ${part.location[1]}<br> | |
<strong>Variable Role:</strong> ${variableRole}<br> | |
<strong>Vector:</strong> [${part.vector.join(', ')}]<br> | |
<strong>Code:</strong><pre class="text-xs text-gray-300">${part.source}</pre> | |
</div> | |
`; | |
} | |
} else { | |
hoveredPoint = null; | |
pointDetails.innerHTML = '<p class="text-gray-400">Hover over a point to see details</p>'; | |
} | |
} | |
} | |
function onMouseUp() { | |
isDragging = false; | |
} | |
function togglePointCloud() { | |
const canvas = document.getElementById('point-cloud'); | |
const table = document.getElementById('results-table'); | |
if (canvas.style.display === 'none') { | |
canvas.style.display = 'block'; | |
table.style.display = 'none'; | |
if (!scene && window.parts) { | |
initPointCloud(window.parts); | |
} | |
} else { | |
canvas.style.display = 'none'; | |
table.style.display = 'block'; | |
} | |
} | |
</script> | |
</body> | |
</html> |