用途:构建基于 Streamlit 的操作员界面,通过 PUDA CLI 控制机器。CLI 是控制平面,UI 仅调用 puda。布局、控件与样式需同时遵循 developing-with-streamlit 技能。
主要能力与必需控件:每个手动控制 UI 必须包含 Start、Complete、Reset 三个按钮。Start 在所有相关机器上开启手动运行;Complete 关闭;Reset 通过 CLI 重置单台机器。UI 有 Idle 与 started 两态:Idle 时启用 Start 和 Reset,禁用机器操作与 Complete。Start 须在 PUDA 项目根目录执行 puda machine start <machine_ids> --run-id manual,成功后才将 st.session_state.started 置为 True。Complete 对同一机器集与 run ID 执行 puda machine complete <machine_ids> --run-id manual,成功才回到 Idle。Reset 始终可见并执行 puda machine reset <machine_id>。未成功 Start 前不得发送机器操作命令。
CLI 后端:始终在项目根目录调用 puda,捕获 stdout/stderr 并在 UI 显示失败。若缺少 puda machine start/complete,提示更新 CLI 至 >= 0.0.36(puda version,puda update)。<machine_ids> 可逗号分隔,Start 与 Complete 须针对同一集合。
单动作派发:使用 puda machine run <machine_id> <command_name> --params '<json-object>' --run-id manual,通过 subprocess.run 实现(cwd 为项目根、capture_output、text、timeout)。该命令只排队一条命令,不发送 START/COMPLETE,仅在 Start 成功后调用。参数用 --params JSON 对象,需关键字参数时用 --kwargs。记录命令、退出码、stdout、stderr 到操作员命令日志。禁止生成临时协议文件、puda protocol run 或自建 NATS 发布助手。
实现规则:后端只用 subprocess/puda,UI 不得另开 NATS 客户端;run_id 固定为 manual;除 Start/Reset 外的控件以 started 状态门控;CLI 失败不得翻转状态。建议封装小助手模块(如 puda_cli.py)。
命令日志:保存在 st.session_state,每次操作后显示命令、退出码、stdout、stderr。若动作控件位于 @st.fragment,日志须渲染在同一 fragment 内,并在记录后自动展开。
布局:优先单屏,顶部放 Start/Complete/Reset,左侧机器控件、右侧摄像头。启用 Tailnet MagicDNS 时用 MagicDNS 名称而非变动 IP,可用 tailscale status --json 获取并去掉末尾点。播放器 URL 形如 http://<machine-hostname>:<player-port>/<path> 或含 tailnet 的完整形式,嵌入 st.iframe 前须验证返回 HTTP 200;仅无 MagicDNS 时回退 IP。仪表盘 URL 形如 http://<machine-hostname>:<streamlit-port>/,上报前验证 /_stcore/health 返回 HTTP 200。
参考实现:references/first-manual-app.py 为已验证的 First/Qubot 单屏手动点动仪表盘,展示生命周期状态机、直接 puda machine run 派发、语义化 Complete/Reset、fragment 内命令日志和直播布局,应复制改造而非作为运行时依赖导入。
验证:上报完成前运行虚拟环境的 python -m py_compile app.py,确认源码含直接 machine run 路径且无临时协议、puda protocol run 或自建 NATS 派发,确认 Streamlit 运行且 health 返回 200,Tailnet URL 仅在 health 也成功后提供。
限制:仅适用于 PUDA 环境;需项目根目录含 puda.config/project.md;CLI 版本不足需更新;具体机器 ID、端口与凭据由实际项目提供。