Update app.py
Browse files
app.py
CHANGED
|
@@ -4,90 +4,102 @@ import subprocess
|
|
| 4 |
import shutil
|
| 5 |
import numpy as np
|
| 6 |
from PIL import Image
|
|
|
|
| 7 |
|
| 8 |
# 1. Setup Persistent Paths
|
| 9 |
SAVE_DIR = "/data"
|
| 10 |
EMCC_DIR = os.path.join(SAVE_DIR, "emsdk")
|
| 11 |
if not os.path.exists(SAVE_DIR): os.makedirs(SAVE_DIR, exist_ok=True)
|
| 12 |
|
| 13 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
def ensure_compiler():
|
| 15 |
-
# If already installed in bucket, just return the path
|
| 16 |
emcc_path = os.path.join(EMCC_DIR, "upstream/emscripten/emcc")
|
| 17 |
-
if os.path.exists(emcc_path):
|
| 18 |
-
return emcc_path
|
| 19 |
-
|
| 20 |
-
print("Installing Portable Emscripten to Bucket (One-time setup)...")
|
| 21 |
try:
|
| 22 |
-
# Clone EMSDK into the persistent bucket
|
| 23 |
subprocess.run(["git", "clone", "https://github.com/emscripten-core/emsdk.git", EMCC_DIR], check=True)
|
| 24 |
subprocess.run([os.path.join(EMCC_DIR, "emsdk"), "install", "latest"], check=True)
|
| 25 |
subprocess.run([os.path.join(EMCC_DIR, "emsdk"), "activate", "latest"], check=True)
|
| 26 |
return emcc_path
|
| 27 |
-
except Exception as e:
|
| 28 |
-
return f"Error installing compiler: {e}"
|
| 29 |
|
| 30 |
-
def
|
| 31 |
-
if not filename
|
| 32 |
-
|
| 33 |
-
# Ensure compiler is ready
|
| 34 |
emcc_path = ensure_compiler()
|
| 35 |
if "Error" in emcc_path: return emcc_path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
final_wasm = os.path.join(SAVE_DIR, f"{base_name}.wasm")
|
| 42 |
-
|
| 43 |
-
with open(c_file, "w") as f: f.write(c_code)
|
| 44 |
-
|
| 45 |
try:
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
if result.returncode != 0: return f"β Compiler Error:\n{result.stderr}"
|
| 53 |
-
|
| 54 |
-
if os.path.exists(out_wasm):
|
| 55 |
-
shutil.move(out_wasm, final_wasm)
|
| 56 |
-
return f"β
Success! Compiled to: {final_wasm}"
|
| 57 |
-
return "β WASM not generated."
|
| 58 |
except Exception as e:
|
| 59 |
-
return f"
|
| 60 |
|
| 61 |
-
# ---
|
| 62 |
-
def render_wasm(
|
| 63 |
-
if not
|
| 64 |
-
|
| 65 |
-
with open(path, "rb") as f: data = f.read()
|
| 66 |
-
|
| 67 |
arr = np.frombuffer(data, dtype=np.uint8)
|
| 68 |
canvas = np.zeros(1920 * 1080, dtype=np.uint8)
|
| 69 |
-
|
| 70 |
-
canvas
|
| 71 |
-
|
| 72 |
-
img = Image.fromarray(canvas.reshape((1080, 1920)), mode='L')
|
| 73 |
-
return img, f"β
Rendered {len(arr)} bytes to 1080p"
|
| 74 |
|
| 75 |
-
# ---
|
| 76 |
with gr.Blocks(theme=gr.themes.Monochrome()) as demo:
|
| 77 |
-
gr.Markdown("# π οΈ LCPU
|
| 78 |
|
| 79 |
-
with gr.Tab("1.
|
| 80 |
-
name = gr.Textbox(label="
|
| 81 |
-
code = gr.TextArea(label="C Code", value=
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
btn.click(compile_c_logic, [code, name], stat)
|
| 85 |
|
| 86 |
-
with gr.Tab("2.
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
|
| 92 |
if __name__ == "__main__":
|
| 93 |
demo.launch()
|
|
|
|
| 4 |
import shutil
|
| 5 |
import numpy as np
|
| 6 |
from PIL import Image
|
| 7 |
+
import pywasm # Add this to your requirements.txt
|
| 8 |
|
| 9 |
# 1. Setup Persistent Paths
|
| 10 |
SAVE_DIR = "/data"
|
| 11 |
EMCC_DIR = os.path.join(SAVE_DIR, "emsdk")
|
| 12 |
if not os.path.exists(SAVE_DIR): os.makedirs(SAVE_DIR, exist_ok=True)
|
| 13 |
|
| 14 |
+
# Helper to get fresh file lists
|
| 15 |
+
def get_wasm_files():
|
| 16 |
+
return [f for f in os.listdir(SAVE_DIR) if f.endswith('.wasm')]
|
| 17 |
+
|
| 18 |
+
# --- COMPILER LOGIC ---
|
| 19 |
def ensure_compiler():
|
|
|
|
| 20 |
emcc_path = os.path.join(EMCC_DIR, "upstream/emscripten/emcc")
|
| 21 |
+
if os.path.exists(emcc_path): return emcc_path
|
|
|
|
|
|
|
|
|
|
| 22 |
try:
|
|
|
|
| 23 |
subprocess.run(["git", "clone", "https://github.com/emscripten-core/emsdk.git", EMCC_DIR], check=True)
|
| 24 |
subprocess.run([os.path.join(EMCC_DIR, "emsdk"), "install", "latest"], check=True)
|
| 25 |
subprocess.run([os.path.join(EMCC_DIR, "emsdk"), "activate", "latest"], check=True)
|
| 26 |
return emcc_path
|
| 27 |
+
except Exception as e: return f"Error: {e}"
|
|
|
|
| 28 |
|
| 29 |
+
def compile_c(c_code, filename):
|
| 30 |
+
if not filename: return "β Need name."
|
|
|
|
|
|
|
| 31 |
emcc_path = ensure_compiler()
|
| 32 |
if "Error" in emcc_path: return emcc_path
|
| 33 |
+
|
| 34 |
+
base = filename.split('.')[0]
|
| 35 |
+
c_f, out_js, out_wasm = f"/tmp/{base}.c", f"/tmp/{base}.js", f"/tmp/{base}.wasm"
|
| 36 |
+
with open(c_f, "w") as f: f.write(c_code)
|
| 37 |
+
|
| 38 |
+
try:
|
| 39 |
+
# Exporting functions so they are callable by the runner
|
| 40 |
+
res = subprocess.run([emcc_path, c_f, "-s", "WASM=1", "-s", "EXPORTED_FUNCTIONS=['_main']", "-o", out_js], capture_output=True, text=True)
|
| 41 |
+
if res.returncode != 0: return f"β {res.stderr}"
|
| 42 |
+
shutil.move(out_wasm, os.path.join(SAVE_DIR, f"{base}.wasm"))
|
| 43 |
+
return f"β
Compiled {base}.wasm"
|
| 44 |
+
except Exception as e: return f"β {e}"
|
| 45 |
|
| 46 |
+
# --- WASM RUNNER (The New "Execution" Tab) ---
|
| 47 |
+
def run_wasm_func(wasm_file, func_name, args):
|
| 48 |
+
if not wasm_file: return "Select a file."
|
| 49 |
+
path = os.path.join(SAVE_DIR, wasm_file)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
try:
|
| 51 |
+
runtime = pywasm.load(path)
|
| 52 |
+
# Parse comma-separated args: "5, 10" -> [5, 10]
|
| 53 |
+
arg_list = [int(x.strip()) for x in args.split(",")] if args else []
|
| 54 |
+
result = runtime.exec(func_name, arg_list)
|
| 55 |
+
return f"Result: {result}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
except Exception as e:
|
| 57 |
+
return f"Error running {func_name}: {e}"
|
| 58 |
|
| 59 |
+
# --- VISUALIZER ---
|
| 60 |
+
def render_wasm(wasm_file):
|
| 61 |
+
if not wasm_file: return None, "Select a file."
|
| 62 |
+
with open(os.path.join(SAVE_DIR, wasm_file), "rb") as f: data = f.read()
|
|
|
|
|
|
|
| 63 |
arr = np.frombuffer(data, dtype=np.uint8)
|
| 64 |
canvas = np.zeros(1920 * 1080, dtype=np.uint8)
|
| 65 |
+
canvas[:min(len(arr), 1920*1080)] = arr[:min(len(arr), 1920*1080)]
|
| 66 |
+
return Image.fromarray(canvas.reshape((1080, 1920)), mode='L'), "Rendered."
|
|
|
|
|
|
|
|
|
|
| 67 |
|
| 68 |
+
# --- UI ---
|
| 69 |
with gr.Blocks(theme=gr.themes.Monochrome()) as demo:
|
| 70 |
+
gr.Markdown("# π οΈ LCPU: Forge, Run & Visualize")
|
| 71 |
|
| 72 |
+
with gr.Tab("1. Forge"):
|
| 73 |
+
name = gr.Textbox(label="WASM Name", value="math_logic")
|
| 74 |
+
code = gr.TextArea(label="C Code", value='int add(int a, int b) { return a + b; }', lines=6)
|
| 75 |
+
comp_btn = gr.Button("π Build")
|
| 76 |
+
status = gr.Textbox(label="Log")
|
|
|
|
| 77 |
|
| 78 |
+
with gr.Tab("2. Runner"):
|
| 79 |
+
with gr.Row():
|
| 80 |
+
run_select = gr.Dropdown(label="Select WASM", choices=get_wasm_files())
|
| 81 |
+
refresh_run = gr.Button("π", variant="secondary")
|
| 82 |
+
func_input = gr.Textbox(label="Function Name", value="add")
|
| 83 |
+
args_input = gr.Textbox(label="Arguments (comma separated)", placeholder="5, 10")
|
| 84 |
+
run_btn = gr.Button("β‘ Execute WASM")
|
| 85 |
+
run_out = gr.Textbox(label="Output")
|
| 86 |
+
|
| 87 |
+
with gr.Tab("3. Visualizer"):
|
| 88 |
+
with gr.Row():
|
| 89 |
+
vis_select = gr.Dropdown(label="Select WASM", choices=get_wasm_files())
|
| 90 |
+
refresh_vis = gr.Button("π", variant="secondary")
|
| 91 |
+
render_btn = gr.Button("π¨ Render 1080p")
|
| 92 |
+
img_out = gr.Image()
|
| 93 |
+
|
| 94 |
+
# Event Logic
|
| 95 |
+
comp_btn.click(compile_c, [code, name], status)
|
| 96 |
+
|
| 97 |
+
# Live Refresh Logic
|
| 98 |
+
refresh_run.click(lambda: gr.Dropdown(choices=get_wasm_files()), outputs=run_select)
|
| 99 |
+
refresh_vis.click(lambda: gr.Dropdown(choices=get_wasm_files()), outputs=vis_select)
|
| 100 |
+
|
| 101 |
+
run_btn.click(run_wasm_func, [run_select, func_input, args_input], run_out)
|
| 102 |
+
render_btn.click(render_wasm, vis_select, [img_out, status])
|
| 103 |
|
| 104 |
if __name__ == "__main__":
|
| 105 |
demo.launch()
|