File size: 7,666 Bytes
f308768 dde59de 8da3888 46f7f75 f308768 1a2d6eb a80108c 46f7f75 a80108c cab2a73 1a2d6eb c1397f0 1a2d6eb cab2a73 1a2d6eb a80108c 1a2d6eb a80108c 46f7f75 a80108c 1a2d6eb a80108c 46f7f75 f308768 1a2d6eb a80108c 1a2d6eb cab2a73 1a2d6eb c1397f0 46f7f75 1a2d6eb cab2a73 1a2d6eb 46f7f75 a80108c 1a2d6eb cab2a73 1a2d6eb f308768 1a2d6eb 71b3e56 1a2d6eb f308768 c1397f0 8da3888 1a2d6eb cab2a73 1a2d6eb 46f7f75 1a2d6eb cab2a73 1a2d6eb f308768 1a2d6eb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | import gradio as gr
import os
import subprocess
import shutil
import numpy as np
from PIL import Image
import pywasm
# 1. Configuration & Persistent Paths
SAVE_DIR = "/data"
EMCC_DIR = os.path.join(SAVE_DIR, "emsdk")
if not os.path.exists(SAVE_DIR):
os.makedirs(SAVE_DIR, exist_ok=True)
def get_wasm_files():
"""Helper to list current WASM files in the bucket"""
if not os.path.exists(SAVE_DIR):
return []
files = [f for f in os.listdir(SAVE_DIR) if f.endswith('.wasm')]
return files if files else []
# 2. Compiler Logic (The Forge)
def ensure_compiler():
"""Checks for Emscripten in the bucket, installs if missing"""
emcc_path = os.path.join(EMCC_DIR, "upstream/emscripten/emcc")
if os.path.exists(emcc_path):
return emcc_path
try:
subprocess.run(["git", "clone", "https://github.com/emscripten-core/emsdk.git", EMCC_DIR],
check=True, capture_output=True)
subprocess.run([os.path.join(EMCC_DIR, "emsdk"), "install", "latest"],
check=True, capture_output=True)
subprocess.run([os.path.join(EMCC_DIR, "emsdk"), "activate", "latest"],
check=True, capture_output=True)
return emcc_path
except Exception as e:
return f"Error: {str(e)}"
def compile_c(c_code, filename):
if not filename:
return "β Error: Please provide a filename."
emcc_path = ensure_compiler()
if "Error" in emcc_path:
return emcc_path
# Clean up filename - remove extension if user included it
base = filename.split('.')[0]
if not base:
return "β Error: Invalid filename."
c_f = f"/tmp/{base}.c"
out_wasm = f"/tmp/{base}.wasm"
dest_wasm = os.path.join(SAVE_DIR, f"{base}.wasm")
with open(c_f, "w") as f:
f.write(c_code)
try:
# SIDE_MODULE=1 creates a clean standalone WASM for pywasm
res = subprocess.run([
emcc_path, c_f,
"-O3",
"-s", "WASM=1",
"-s", "SIDE_MODULE=1",
"-o", out_wasm
], capture_output=True, text=True, timeout=120)
if res.returncode != 0:
stderr = res.stderr[-2000:] if len(res.stderr) > 2000 else res.stderr
return f"β Compiler Error:\n{stderr}"
if os.path.exists(out_wasm):
if os.path.exists(dest_wasm):
os.remove(dest_wasm)
shutil.move(out_wasm, dest_wasm)
return f"β
Successfully Forged: {base}.wasm"
return "β Error: WASM file generation failed."
except subprocess.TimeoutExpired:
return "β Error: Compilation timed out (>120s)."
except Exception as e:
return f"β System Error: {str(e)}"
# 3. Execution Logic (The Runner) - FIXED
def run_wasm_func(wasm_file, func_name, args_str):
if not wasm_file:
return "β Select a WASM file."
if not func_name:
return "β Provide a function name."
path = os.path.join(SAVE_DIR, wasm_file)
if not os.path.exists(path):
return f"β WASM file not found: {wasm_file}"
try:
# Parse arguments
arg_list = []
if args_str and args_str.strip():
for x in args_str.split(","):
x = x.strip()
if x:
arg_list.append(int(x))
# Create runtime and load
runtime = pywasm.Runtime()
module_instance = runtime.instance_from_file(path)
# Try calling the function
# pywasm may need underscore prefix for exported C functions
errors = []
for name in [func_name, f"_{func_name}"]:
try:
result = runtime.invocate(module_instance, name, arg_list)
return f"β
Execution Successful!\nFunction: {name}\nResult: {result}"
except AssertionError as e:
# Usually wrong number of arguments
errors.append(f"'{name}': Wrong argument count or assertion failed")
except Exception as e:
errors.append(f"'{name}': {str(e)}")
return f"β Runner Error:\n" + "\n".join(errors)
except Exception as e:
return f"β Runner Error: {str(e)}"
# 4. Visualizer Logic (Normalized & Tiled)
def render_wasm(wasm_file):
if not wasm_file:
return None, "β Select a file."
path = os.path.join(SAVE_DIR, wasm_file)
if not os.path.exists(path):
return None, f"β File not found: {wasm_file}"
try:
with open(path, "rb") as f:
data = f.read()
if len(data) == 0:
return None, "β Empty WASM file."
arr = np.frombuffer(data, dtype=np.uint8).copy()
# Normalize bytes to visible pixel range
min_val = arr.min()
max_val = arr.max()
if max_val > min_val:
arr = ((arr - min_val) * (255.0 / (max_val - min_val))).astype(np.uint8)
# Tile to fill 1080p canvas
canvas_size = 1920 * 1080
if len(arr) > 0:
repeats = (canvas_size // len(arr)) + 1
tiled = np.tile(arr, repeats)
canvas = tiled[:canvas_size]
else:
canvas = np.zeros(canvas_size, dtype=np.uint8)
img = Image.fromarray(canvas.reshape((1080, 1920)), mode='L')
return img, f"β
Visualizing {len(data)} bytes β 1920Γ1080 grayscale"
except Exception as e:
return None, f"β Visualizer Error: {str(e)}"
# 5. Gradio UI
with gr.Blocks() as demo:
gr.Markdown("# π οΈ LCPU: Advanced Arithmetic Engine")
with gr.Tab("1. The Forge"):
wasm_name = gr.Textbox(label="Output Filename", value="logic_core",
placeholder="e.g. math_engine (no extension)")
c_code_input = gr.TextArea(
label="C Code Source",
value='int add(int a, int b) {\n return a + b;\n}\n\nint mul(int a, int b) {\n return a * b;\n}',
lines=10
)
compile_btn = gr.Button("π Build Binary", variant="primary")
forge_status = gr.Textbox(label="Forge Output", interactive=False)
with gr.Tab("2. The Runner"):
with gr.Row():
run_select = gr.Dropdown(label="Select Binary", choices=get_wasm_files())
refresh_run = gr.Button("π Refresh", variant="secondary")
f_name = gr.Textbox(label="Function Name", value="add")
args_in = gr.Textbox(label="Arguments (comma separated)", placeholder="10, 20")
run_btn = gr.Button("β‘ Run Logic", variant="primary")
run_output = gr.Textbox(label="Output Result", interactive=False)
with gr.Tab("3. The Visualizer"):
with gr.Row():
vis_select = gr.Dropdown(label="Select Binary", choices=get_wasm_files())
refresh_vis = gr.Button("π Refresh", variant="secondary")
render_btn = gr.Button("π¨ Map to 1080p", variant="primary")
canvas_img = gr.Image(label="Logic Texture")
vis_status = gr.Textbox(label="Visualizer Status", interactive=False)
# Wiring - FIXED
compile_btn.click(compile_c, inputs=[c_code_input, wasm_name], outputs=forge_status)
# Refresh buttons - return new Dropdown with updated choices
refresh_run.click(lambda: gr.Dropdown(choices=get_wasm_files()), outputs=run_select)
refresh_vis.click(lambda: gr.Dropdown(choices=get_wasm_files()), outputs=vis_select)
run_btn.click(run_wasm_func, inputs=[run_select, f_name, args_in], outputs=run_output)
render_btn.click(render_wasm, inputs=vis_select, outputs=[canvas_img, vis_status])
if __name__ == "__main__":
demo.launch(theme=gr.themes.Monochrome()) |