Spaces:
Running
Running
Download classroom_static/py-worker.js from Telearn/Project_Demo: direct link, hf CLI and curl.
- Browser
- Download file 3.18 kB
-
https://huggingface.co/spaces/Telearn/Project_Demo/resolve/main/classroom_static/py-worker.js
- Command line
-
hf download hf://spaces/Telearn/Project_Demo/classroom_static/py-worker.js
-
curl -L -o py-worker.js https://huggingface.co/spaces/Telearn/Project_Demo/resolve/main/classroom_static/py-worker.js
3.18 kB
| let pyodide = null; | |
| let inputControl = null; | |
| let inputBytes = null; | |
| async function initialize() { | |
| try { | |
| importScripts("/classroom-assets/vendor/pyodide/pyodide.js"); | |
| pyodide = await loadPyodide({ indexURL: "/classroom-assets/vendor/pyodide/" }); | |
| pyodide.setStdout({ | |
| write(buffer) { | |
| postMessage({ type: "stream", channel: "stdout", bytes: buffer }); | |
| return buffer.length; | |
| }, | |
| isatty: true | |
| }); | |
| pyodide.setStderr({ | |
| write(buffer) { | |
| postMessage({ type: "stream", channel: "stderr", bytes: buffer }); | |
| return buffer.length; | |
| }, | |
| isatty: true | |
| }); | |
| postMessage({ type: "ready" }); | |
| } catch (error) { | |
| postMessage({ type: "load_error", text: String(error) }); | |
| } | |
| } | |
| function readInteractiveInput() { | |
| if (!inputControl || !inputBytes) return ""; | |
| Atomics.store(inputControl, 0, 0); | |
| postMessage({ type: "input_request" }); | |
| Atomics.wait(inputControl, 0, 0); | |
| const length = Math.max(0, Math.min(Atomics.load(inputControl, 1), inputBytes.length)); | |
| const value = new TextDecoder().decode(inputBytes.slice(0, length)); | |
| Atomics.store(inputControl, 0, 0); | |
| return value; | |
| } | |
| self.onmessage = async event => { | |
| if (event.data.type !== "run" || !pyodide) return; | |
| const sharedInput = event.data.inputBuffer; | |
| if (!(sharedInput instanceof SharedArrayBuffer)) { | |
| postMessage({ type: "python_error", text: "瀏覽器未提供互動式 Python 所需的安全執行環境。" }); | |
| return; | |
| } | |
| inputControl = new Int32Array(sharedInput, 0, 2); | |
| inputBytes = new Uint8Array(sharedInput, 8); | |
| pyodide.setStdin({ stdin: readInteractiveInput, isatty: true }); | |
| try { | |
| const files = event.data.files || { "main.py": event.data.code || "" }; | |
| const entry = event.data.entry || "main.py"; | |
| pyodide.runPython(` | |
| import os, shutil, sys | |
| root = "/home/pyodide/classroom_project" | |
| shutil.rmtree(root, ignore_errors=True) | |
| os.makedirs(root, exist_ok=True) | |
| for name, module in list(sys.modules.items()): | |
| if str(getattr(module, "__file__", "")).startswith(root): | |
| del sys.modules[name] | |
| `); | |
| for (const [path, content] of Object.entries(files)) { | |
| const fullPath = `/home/pyodide/classroom_project/${path}`; | |
| pyodide.FS.mkdirTree(fullPath.slice(0, fullPath.lastIndexOf("/"))); | |
| pyodide.FS.writeFile(fullPath, content, { encoding: "utf8" }); | |
| } | |
| pyodide.globals.set("classroom_entry", entry); | |
| const succeeded = await pyodide.runPythonAsync(` | |
| import os, sys, traceback | |
| root = "/home/pyodide/classroom_project" | |
| os.chdir(root) | |
| if root not in sys.path: | |
| sys.path.insert(0, root) | |
| entry = os.path.join(root, classroom_entry) | |
| namespace = {"__name__": "__main__", "__file__": entry} | |
| ok = True | |
| try: | |
| with open(entry, "r", encoding="utf-8") as source: | |
| exec(compile(source.read(), entry, "exec"), namespace) | |
| except BaseException: | |
| ok = False | |
| traceback.print_exc() | |
| finally: | |
| sys.stdout.flush() | |
| sys.stderr.flush() | |
| ok | |
| `); | |
| postMessage({ type: succeeded ? "done" : "python_error", text: succeeded ? "" : "程式執行失敗" }); | |
| } catch (error) { | |
| postMessage({ type: "python_error", text: String(error) }); | |
| } | |
| }; | |
| initialize(); | |