Spaces:
Paused
Download README.md from HelloSun/testzerogpu: direct link, hf CLI and curl.
- Browser
- Download file 8.49 kB
-
https://huggingface.co/spaces/HelloSun/testzerogpu/resolve/main/README.md
- Command line
-
hf download hf://spaces/HelloSun/testzerogpu/README.md
-
curl -L -o README.md https://huggingface.co/spaces/HelloSun/testzerogpu/resolve/main/README.md
A newer version of the Gradio SDK is available: 6.31.0
title: testzerogpu
emoji: 🖥️
colorFrom: gray
colorTo: blue
sdk: gradio
sdk_version: 6.25.0
python_version: '3.12'
app_file: app.py
pinned: false
license: apache-2.0
short_description: ZeroGPU web terminal with OpenCode
ZeroGPU web terminal. UI 與 HelloSun/CPU_TERMINAL_00 一致(多頁終端機、檔案瀏覽器、
下載/上傳、複製/貼上、狀態列)。
OpenCode 在啟動時安裝,並重設使用者層級設定為預設值。
檔案
app.py— FastAPI + xterm.js 終端機、檔案瀏覽器、/wssession 管理與固定 LXDE 桌面packages.txt— 系統套件(tmux、xvfb、x11vnc、lxde-core、xterm、novnc、x11-utils,以及 Playwright Chromium 所需的系統函式庫與字型)requirements.txt— Python 相依套件(含playwright)
終端機分頁(全部共用、全部長存)
- 每個分頁 = 一個 tmux session:真正共用的 shell 在 tmux 裡,每個瀏覽器分頁只是
一條 tmux client attach。因此不同裝置可以有不同終端機大小,tmux 會針對每個 client
重畫畫面:
- window 大小由 tmux 依所有目前附掛的 client 自動計算(
window-size smallest), 取最小的那台,並自動扣掉狀態列。window 一定放得進每台裝置的可視區域,因此不會有 錯位、殘影或亂碼。較大的裝置會看到 tmux 以·填滿、外框標出 window 範圍。 - 輸入、重連都不會改動 window 大小(舊版每次按鍵都會切換尺寸,多裝置會互相拉扯)。 手機/小視窗離線後,window 會自動放大回剩下那台的尺寸。
- 每條連線在 URL 帶上自己的
cols/rows,第一次重畫就是正確大小。 - 前端只有可見的分頁會保持連線;切走的分頁立即 detach,不以錯誤尺寸拖累其他裝置。
- 每次(重新)附掛,前端都會
term.reset()清空本機畫面後再接收 tmux 的完整重畫, 重連或重新整理不會把新舊畫面疊在一起。 - 多位元組字元(中文)用增量 UTF-8 解碼,不會在切斷處產生亂碼。
- 斷線只會 detach 該 client,
opencode與所有程序都留在 tmux session 裡。
- window 大小由 tmux 依所有目前附掛的 client 自動計算(
- 分頁清單由伺服器統一管理:
GET /api/tabs回傳目前所有共用分頁,所有裝置看到的 分頁完全相同。按+開的新分頁(POST /api/tabs)會出現在每一台裝置上。 - 只有明確關閉分頁(
DELETE /api/tabs/{id},前端會先確認)才會 kill 該 tmux session,而且所有裝置會一起關閉該分頁;至少會保留一頁。 - 分頁清單會落地到
~/.webterm_tabs.json;只要容器還活著,tmux session 也能跨 app 行程重啟接回。Space 重建(整個容器重來)時仍會失去程序,這是平台限制。 - 分頁數量上限可用 Space 變數
WEBTERM_MAX_TABS覆寫(預設 12)。 - 除錯用端點:
GET /api/tabs、GET /api/sessions(含 tmux 是否可用、每個 attach 的 尺寸與訂閱數)。
installpi.sh 已從 Space 流程中移除(不再自動執行),檔案本身保留在 repo 作為紀錄,
需要時手動執行。
固定桌面分頁(Xvfb + LXDE + x11vnc + noVNC)
終端機分頁之外,最左側有一個 固定 的「桌面 1(LXDE,共用)」分頁:
- 伺服器永遠維持 恰好一個
Xvfb(:99)+ 一個 LXDE session + 一個x11vnc(只監聽127.0.0.1:5900)。看門狗每 3 秒檢查,任何一個程序死掉會自動補回, 重複的程序會被清掉。 - 桌面裡永遠有一個標題為「共用終端機」的 xterm;把它關掉後看門狗會自動再開一個, 所以固定分頁裡永遠有 1 個可用的圖形終端機視窗(使用者自己另開的终端機不受影響)。
- 容器內沒有 systemd-logind session,因此會自動停用
lxpolkit與light-lockerautostart,避免桌面啟動時跳出「No session for pid …」的 Error 對話框。 - 剪貼簿同步(固定開啟):桌面裡的 CLIPBOARD/PRIMARY 永遠與瀏覽器所在系統的
剪貼簿雙向同步;右上角「剪貼簿同步」按鈕可隨時手動再同步一次(沒有關閉選項)。
在桌面內按 Ctrl+V
(或 Cmd+V)會先把本機剪貼簿送進 X11 再貼上。底層由
autocutsel將 x11vnc 使用的 CUT_BUFFER0 與 X11 selection 對齊,xterm 也設定為選取即同步 CLIPBOARD。 瀏覽器基於安全限制,頁面需要保持在前景;若系統阻擋寫入,點一下桌面會重試。 - 瀏覽器是透過
/vncWebSocket 橋接到同一個桌面,所有裝置看到完全相同、可同時操作的 LXDE 畫面;關掉瀏覽器分頁不會終止桌面,重新整理或重新連線都會接回原畫面。 - 這個分頁是固定的:按它的
×不會刪除分頁,而是重新啟動一份新的桌面 (POST /api/desktop/restart),永遠維持一個。 - 終端機分頁也支援系統剪貼簿:選取後按 Ctrl+Shift+C(或 Ctrl+Insert)複製, Ctrl+V、Ctrl+Shift+V(或 Shift+Insert)直接貼上。貼上走 xterm.js 的 bracketed paste,與一般終端機一致。
- 檔案瀏覽器可瀏覽/下載伺服器上的任何路徑(含
/tmp、/),不再有白名單限制; 選取資料夾後下載會即時串流打包成.tar.gz,不會一次載入記憶體。 - 桌面分頁的「上傳」會把檔案存到
~/Desktop(同名檔案自動加序號),上傳後可直接在 LXDE 桌面看到。 - 除錯端點:
GET /api/desktop/status、POST /api/desktop/restart(程序 pid、VNC port、 健康狀態);桌面 log 在/tmp/webterm-desktop.log。 - 可用 Space 變數覆寫:
DESKTOP_DISPLAY(預設:99)、DESKTOP_GEOMETRY(預設1440x900x24)、DESKTOP_VNC_PORT(預設5900)、DESKTOP_NOVNC_ROOT(預設/usr/share/novnc)。noVNC 靜態檔由/novnc/*提供,缺少時前端自動改用 CDN。
Playwright + Chromium(桌面內使用)
Space 啟動後會在背景自動安裝 Playwright 的 Chromium(下載到
~/.cache/ms-playwright,系統依賴已由 packages.txt 預裝),完成後:
共用 LXDE 桌面會出現 Playwright Chromium 圖示,點兩下即可在桌面內開瀏覽器 (以 root 執行,已自動加上
--no-sandbox --disable-dev-shm-usage)。也可直接執行啟動器:
~/.local/bin/playwright-chromium。在終端機用 Python 操作時,記得 Chromium 需要無沙箱參數:
from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(args=["--no-sandbox", "--disable-dev-shm-usage"]) page = browser.new_page() page.goto("https://example.com") print(page.title()) browser.close()若要開在共用桌面(看的到視窗),把
headless設為False並使用DISPLAY=:99; Playwright 會自動沿用PLAYWRIGHT_BROWSERS_PATH。除錯端點:
GET /api/playwright/status(是否就緒、Chromium 路徑、最後錯誤)、POST /api/playwright/install(手動觸發重裝)。安裝 log 在/tmp/webterm-playwright.log。手動更新 Chromium:
python3 -m playwright install chromium。
記憶體守衛(memguard)
每次 Space 啟動時,app.py 的 install_memguard() 會自動:
- 把 repo 的
memguard.py複製到~/memkill.py並啟動它opencode本體 + 它啟動的所有子行程合計 RSS > 80 GiB(單一行程 > 64 GiB)→ 對記憶體最肥的那個子行程樹送SIGKILL- 只砍子行程,opencode 本體永不砍
- 被砍的指令與峰值寫入
/tmp/memkill.last.json、歷史/tmp/memkill.jsonl、log/var/log/memkill.log
- 把 repo 的
AGENTS.md複製到~/.config/opencode/AGENTS.md- opencode 每輪開工都會讀:被砍後不准用同一種做法重跑,必須改用串流/分頁/分段落盤/降批次等低記憶體做法,改不過來就停下來問使用者
- 在
~/.bashrc加冪等自動啟動,新開的終端機也一定有守衛
上限可用 Space 變數覆寫:MEMGUARD_TOTAL_GIB、MEMGUARD_PER_PROC_GIB。
使用者在終端機檢查:
pgrep -af 'memkill[.]py' # 守衛是否活著
tail -f /var/log/memkill.log # 每 2 秒的用量
cat /tmp/memkill.last.json # 上次被砍的是哪條指令、峰值幾 GiB