Skip to content

Repository files navigation

🌙 爱搞鸡鸭

陪你一起创造的桌面常驻精灵 白天把活儿丢给它,夜里它替你办完。

Python FastAPI Hardware Harness AdventureX

AdventureX 2026 · Desktop Daemon 赛道 · 清闲 UberNovo


💡 一句话产品

白天你把想做但没空做的活儿丢给桌上这只精灵,它按四象限排好队,趁你睡觉把能自动做的都做完。早上醒来——事情变少了、进度变多了,拿不准的攒成一张确认清单等你拍板

它坐在一把清闲人体工学椅上,靠桌面环境判断你在不在、要不要开工,全程无需手动操作:白天——脚踏上的传感器检测到你落座就开工;夜晚——灯灭(你入睡)它就开始烧 token 替你办事,灯亮(你醒来)就停工并播报晨报。

为什么必须是「这台机器」

我们每天和 AI 说话,但它住在别人的服务器里,关掉标签页就消失——它不属于你。如果有一台机器 24 小时待在你桌上、只属于你一个人,它不睡觉、能跑程序、能存你的数据、能在你睡着时把事情办了,那么 Agent 最好的家就不是云,而是一台离你最近、一直醒着的小主机

本地常驻主机 云端 Agent
✅ 整夜独占算力 ❌ 按调用计费、排队
✅ 能碰真实环境(文件/外设) ❌ 够不着你的桌面
✅ 隐私护城河,数据不出这台机器 ❌ 数据上云

🎬 演示故事 ·「快进一夜」

  1. 晚上交班 —— 你把三件事丢给精灵(挑图修图分类 / 把技术文档整理成讲稿大纲 / 盯 GitHub issue),它说「晚安,交给我」。
  2. 关灯入睡 —— 你关掉房间的灯,这既是「人退场」的仪式,也是精灵的开工信号。灯转值班蓝,开始夜间执行、烧 token。
  3. 快进一夜 —— token 计数在走,灯从蓝渐变。
  4. 早上开灯播报 —— 你开灯(醒来)→ 精灵停工、灯转暖光,主动播报晨报:图挑好了在这个文件夹、讲稿大纲已生成、issue 回复草稿等你确认。
  5. 看得见成果 —— 关键是让评委看到本地文件夹里真的多了东西、确认清单里真有条目。

✨ 当前已实现(Phase 1 骨架 + Phase 2 Agent 核心)

能力 状态 说明
🗂️ 四象限任务看板 增删改查、拖拽改象限、多客户端实时刷新
🌓 环境感知状态机 脚踏 + 灯光 → 待命 / 白天工作 / 夜间执行 自动推导
💡 LED 灯语联动 屏幕精灵灯与实体灯同一套语言,随模式变色
🔌 硬件连接架构 GPIO 直读传感器 + UART 驱动 T5 面板;MQTT 为可选外部边界(已按重构提案 v1 落地)
🤖 四象限自动分类 ClassifierAgent:LLM 优先(DeepSeek),无 key 时启发式兜底;显式指定的象限不覆盖
🌙 夜间执行器 灯灭自动开工:ExecutorAgent 路由 skill,产物真实落盘 data/output/;灯亮收工不留半个产物
🤝 信任机制(确认清单) 没现成 skill 的活不擅自做,攒进确认清单(呼吸红),早上拍板联动任务状态
🌅 晨报 灯亮自动播报:完成/失败/待拍板/token 消耗,前端弹卡 + 落盘 markdown
🧘 久坐提醒 连续落座 30 分钟(可调)→ 轻提示 + 面板音频,起身自动复位
🚶 离席开工 人离开超阈值(可调)→ 自动进入「离席执行」干活(走时 toast 告诉你);坐回弹「离席汇报」
🧩 Skill 插件系统 BaseSkill 契约 + 首个落地 skill(文档→讲稿大纲),新 skill 注册即用
🖥️ 交互式启动 CLI 菜单式/命令式双模式,自动开浏览器,端口占用友好处理
🧪 Harness 测试编排 Phase 1 回归 + Phase 2 契约 + 行为场景 18 项全绿,自带环境编排与报告

产品的三个核心设计语言

① 环境感知 → 四种状态(无感,是整个 Demo 的记忆点)

传感器 组合 系统模式 精灵状态
灯灭 light=0 🌙 夜间执行 值班蓝,开始烧 token
灯亮 + 踩脚踏 light=1, sit=1 💼 白天工作 冷白,陪你干活
灯亮 + 未踩脚踏 light=1, sit=0 😴 待命 暖光,安静守着
拿不准的事 🚨 需拍板 呼吸红,等你决定

② 四象限任务分类(X 轴 = 截止紧迫度,Y 轴 = 自主度)

可自动(有现成 skill) 需拍板(要你决定)
紧急 ① 夜间执行 ② 确认清单
不紧急 ③ 排队中 ④ 待定

③ LED 灯语(屏幕 UI 与硬件灯效是同一套叙事)

暖光=休息 · 冷白=工作 · 值班蓝=夜间值班 · 呼吸红=需拍板

🤝 信任机制:它不是擅自做主的老板,是打工仔。拿不准的(这封邮件语气对不对?这条要不要删?)不擅自做,攒进明早确认清单,用呼吸红灯提醒。这解决了「放手让 AI 整夜乱搞」的信任焦虑。


🏗️ 技术架构

 压力/光敏传感器 ──GPIO──> ┌───────────────── Orange Pi 3B ─────────────────┐
                           │  hardware/gpio_adapter.py  (消抖+稳定判定)      │
                           │            │ EnvironmentState                   │
                           │            ▼                                    │
                           │  domain/  状态机 StateMachine (唯一权威状态)     │
                           │            │ DomainEvent (revision++)            │
                           │            ▼                                    │
                           │  services/orchestrator.py (组合根/事件总线)      │
                           │     ┌──────┼───────────┬─────────────┐          │
                           │     ▼      ▼           ▼             ▼          │
                           │   UART  WebSocket    MQTT(可选)   Executor(P2)  │
                           └─────┼──────┼───────────┼─────────────────────────┘
                                 │      │           │
                    T5 面板 ◄────┘      │           ▼
                    (MODE_SET等)        │      外部应用/调试/Home Assistant
                                         ▼
                              前端看板 (HTML/CSS/JS 静态托管)
                              四象限看板 + 精灵灯 + 确认清单
                                         ▲
                                    SQLite (aiosqlite, WAL) 本地存储

架构要点(《MQTT 重构提案 v1》):MQTT 是可选的外部集成边界,不是内部硬件链路。内部数据路径固定为 传感器 ──GPIO──> Orange Pi ──UART──> T5。领域层 domain/ 不碰任何网络库,MQTT 可整体关闭,核心照常运行。

技术栈

技术 选型理由
后端 FastAPI + Uvicorn 异步、自带 WS、类型安全,单进程跑通全链路
存储 SQLite (aiosqlite, WAL) 零部署、本地隐私、读写并发友好
硬件-有线 pyserial-asyncio 一根 USB 线解决供电+通信,现场最可靠
硬件-无线 WebSocket / MQTT (aiomqtt) WiFi 灵活 / IoT 标准(QoS1+LWT+保留消息)
前端 原生 HTML/CSS/JS 无构建、FastAPI 直接托管,设计师改 CSS 即可换肤
LLM (Phase 2) 国产模型(DeepSeek 等) 国内访问无障碍、成本低
测试 pytest + 自研 Harness 单元/链路 + 场景编排双保险

🚀 快速开始

只需 Python 3.11+,无需 Node。前端由后端直接托管。

方式 A · 双击即用(非技术队友)

脚本 作用
安装依赖.bat 首次运行一次,自动装依赖(会检测并提示装 Python)
启动看板.bat 起后端 + 自动打开浏览器(日常用)
一键演示.bat MQTT Broker + 后端全链路(现场演示)
演示剧本.bat 视频四拍 + 夜场,回车逐拍推进(需看板已在运行;自动热调阈值并恢复)

方式 B · 命令行(开发者)

# 1. 安装依赖
pip install -r requirements.txt

# 2. 启动(进入交互式菜单,按编号选择)
python cli.py

# 或直接启动看板(后端+前端,自动开浏览器)
python cli.py serve --open

# 3. 浏览器打开(启动后会自动打开)
http://127.0.0.1:8000

💡 前端不用单独启动——它由 FastAPI 静态托管,起了后端访问 http://127.0.0.1:8000/ 就是看板。设计师改 frontend/css/style.css 后刷新浏览器即可,无需 npm。 (前端开发者若装了 Node,可 cd frontend && npm run dev 获得热重载,Vite 在 :5173 代理到后端。)


🖥️ 统一启动器 CLI

运行 python cli.py 进入交互式菜单(也可直接用子命令):

请选择启动模式:
  1 ◈  启动看板       后端 + 前端, 自动开浏览器      ★ 推荐
  2 ✦  一键演示       Broker + 后端[MQTT] 全链路
  3 ☁  MQTT Broker   只启动本地消息中转
  4 ⚙  硬件模拟器     已废弃, 改用 env 注入
  5 ✓  运行测试       全部 / Phase1 / MQTT / Agent
  6 ⚑  环境自检       依赖 / 端口 / 配置
  7 ⚡ Harness 测试   Phase1 回归 + Phase2 Agent 契约
  8 🎬 演示剧本       视频四拍 + 夜场, 回车推进
  0 ✕  退出

子命令速查

命令 作用 常用示例
serve 启动后端(+前端) python cli.py serve --open --reload
demo 一键全链路编排 python cli.py demo --open
broker 本地 MQTT Broker python cli.py broker --port 1883
sim 硬件模拟器(已废弃,改用 env)
test 跑 pytest python cli.py test --agent
check 环境自检 python cli.py check
harness 测试编排框架 python cli.py harness --only phase1
env 注入模拟环境状态 python cli.py env night / env work / env --light off
presence 查看/热调久坐·离席阈值 python cli.py presence --sedentary 30 --away 10--reset 恢复)
play 演示剧本(回车逐拍推进) python cli.py play
reset-db 清空开发数据库(需先停后端) python cli.py reset-db --with-output

🛟 端口被占用? CLI 会友好提示 [o]打开浏览器 / [p]换端口 / [b]返回,不会报错崩溃。


🔌 硬件接入(给 YUANZL)

《MQTT 重构提案 v1》(权威规范,见 docs/Nightshift_MQTT_重构提案_v1.md):

内部硬件链路压力/光敏传感器 ──GPIO──> Orange Pi 3B ──UART──> T5 面板

边界 协议 实现
GPIO 输入 直读数字输入,消抖+稳定判定 → EnvironmentState{sit,light,ready} backend/hardware/gpio_adapter.py
UART 面板 T5-Link 板间协议:MODE_SET / ATTENTION_SET / WORK_STATE_SET / DASHBOARD_SET / TASK_LIST / UI_ACTION / AUDIO_PLAY backend/hardware/uart_adapter.py
MQTT(可选外部边界) 仅供外部调试/控制/Home Assistant,默认关闭 backend/integrations/mqtt/

MQTT 不是内部总线:GPIO 不经 MQTT 回环,T5 不接 MQTT,MQTT 故障不影响 GPIO/UART/执行器。

MQTT Topic 速查nightshift/v1/opi/{node_id}/,默认 node_id=opi5b01,详见 docs/MQTT_硬件接入文档.md):

  • 后端 → 外部:availability(retain) / state(retain) / event / telemetry
  • 外部 → 后端:command(信封含 request_id + reply_to + ttl_ms,幂等)→ 后端回 reply/{client_id}

没硬件也能联调(注入模拟环境状态):

curl -X POST http://127.0.0.1:8000/api/dev/environment \
  -H "Content-Type: application/json" -d '{"light": false}'   # 关灯 -> 夜间执行
curl http://127.0.0.1:8000/api/dev/panel                       # 看 T5 面板收到的指令
# 演示热调(不用真等 30 分钟): 久坐提醒/离席开工阈值秒级化
curl -X POST http://127.0.0.1:8000/api/dev/presence \
  -H "Content-Type: application/json" -d '{"sedentary_seconds": 30, "away_seconds": 10}'

🧪 测试与质量

单元/链路测试(pytest)

python -m pytest tests/test_phase1.py -v   # Phase 1 全链路(自包含,自动起后端)
python -m pytest tests/test_mqtt.py -v     # MQTT 链路(自带嵌入式 broker)
python -m pytest tests/test_agent.py -v    # Agent 层单元测试(纯单元,无需服务器)
python -m pytest tests/ -v                 # 全部测试一次跑通

Harness 测试编排框架(Phase 2 驱动器)

一个场景驱动的编排框架:自动拉起完整环境 → 执行场景 → 生成报告

python -m harness                          # spawn 完整环境,跑全部场景
python -m harness --only phase1            # 只跑 Phase 1 回归
python -m harness --only agent             # 只跑 Phase 2 契约
python -m harness --attach http://127.0.0.1:8000   # 连接已运行的后端
python cli.py harness --only phase1        # 经由统一 CLI
  • Phase 1 回归scenarios/phase1_core.py,7 项):健康/状态/CRUD/导入/前端WS/硬件链路/LED下行 —— 必须全绿
  • Phase 2 契约scenarios/agent_contracts.py,8 项):Agent 层接口契约(BaseAgent / Classifier / Executor / Scheduler / Reporter / BaseSkill / 多Agent协作)—— 已全部转绿;新 Agent 模块按契约对齐即可。
  • Phase 2 行为scenarios/agent_behavior.py,3 项):夜循环端到端(灯灭→执行→产物落盘→灯亮→晨报)/ 自动分类 / 确认清单拍板 —— 当前 18 项全绿
  • 报告:控制台彩色汇总 + harness/reports/*.json + 自包含 *.html
  • 环境用独立临时数据库NIGHTSHIFT_DB_PATH),不污染开发数据,退出自动回收。

写一个新场景(放 harness/scenarios/ 任意文件即自动注册):

from harness.scenario import Scenario, scenario

@scenario
class MyScenario(Scenario):
    name = "phase2.my_feature"
    title = "我的功能"
    requires = ("backend.agent.my_module",)   # 缺失则 SKIP
    async def run(self, ctx):
        r = ctx.http.get("/api/xxx")
        ctx.check(r.status_code == 200, "应返回 200")

👥 团队与角色分工

成员 角色 你的快速入口
全栈(后端+分类器+执行器+前端) python cli.py serve --reload,看 backend/harness/
YUANZL 硬件 / 嵌入式(技术核心) docs/Nightshift_MQTT_重构提案_v1.md,按 gpio_adapter.py / uart_adapter.py 实现真实适配器
许新豪 设计 / 视觉 / 叙事 素材放 frontend/assets/,改 frontend/css/style.css 顶部 :root 变量即可全局换肤
Lucy PM 双击 启动看板.bat 看看板;演示数据在 backend/routes/tasks.pyMOCK_TASKS

📁 项目结构

d:\zhende-zdv\
├── cli.py                  # 统一启动器(交互菜单 + 子命令)
├── 安装依赖.bat / 启动看板.bat / 一键演示.bat   # Windows 双击脚本
├── requirements.txt
├── pytest.ini
│
├── backend/                # FastAPI 后端
│   ├── main.py             # 入口(路由 + WebSocket + 静态托管)
│   ├── config.py           # 配置(pydantic-settings, NIGHTSHIFT_ 前缀)
│   ├── database.py         # SQLite 异步连接(aiosqlite, WAL)
│   ├── models.py           # 数据模型 + 建表 SQL + 四象限/模式/LED 枚举
│   ├── ws.py               # WebSocket 双通道连接管理器
│   ├── routes/
│   │   ├── tasks.py        # 任务 CRUD + mock 导入(Lucy 调数据处)
│   │   └── confirmations.py# 确认清单:列表 + 拍板(Phase 2 信任机制)
│   ├── domain/             # 领域层(唯一权威状态 + 状态机 + 领域事件,不碰网络库)
│   │   ├── models.py       # EnvironmentState / SystemState / WorkState
│   │   ├── events.py       # DomainEvent 类型
│   │   └── state_machine.py# 模式推导 + revision 维护
│   ├── agent/              # Agent 层(Phase 2,不碰 MQTT/UART/WS,结果交调度层落地)
│   │   ├── base_agent.py   # BaseAgent / AgentResult / AgentContext(契约地基)
│   │   ├── llm.py          # LLM 接入(DeepSeek 兼容端点 + NullLLM 降级)
│   │   ├── classifier.py   # 四象限自动分类(LLM 优先,启发式兜底)
│   │   ├── executor.py     # 夜间执行器:任务 -> skill 路由 / 无 skill 转确认
│   │   ├── scheduler.py    # NightScheduler 夜循环调度(灯灭开工,灯亮收工)
│   │   ├── reporter.py     # 晨报生成(模板 + 可选 LLM 导语)
│   │   └── skills/         # BaseSkill 契约 + doc_outline(首个落地 skill)
│   ├── hardware/           # 硬件物理边界
│   │   ├── gpio_adapter.py # GPIO 直读传感器(消抖+稳定判定,含模拟实现)
│   │   └── uart_adapter.py # UART 驱动 T5 面板(含模拟实现)
│   ├── integrations/
│   │   └── mqtt/           # MQTT 可选外部集成边界
│   │       ├── topics.py   # Topic 命名 (nightshift/v1/opi/{node_id}/...)
│   │       ├── schemas.py  # 消息 Schema 构造/校验
│   │       ├── client.py   # aiomqtt 客户端(线程隔离/LWT/重连)
│   │       ├── publisher.py# availability/state/event 发布
│   │       ├── command_handler.py  # command -> 领域 -> reply
│   │       └── dev_broker.py       # 本地嵌入式 Broker(免装 mosquitto)
│   └── services/
│       └── orchestrator.py # NightshiftCore 组合根(连接以上所有)
│
├── frontend/               # 前端(FastAPI 静态托管,无需构建)
│   ├── index.html          # 单页骨架
│   ├── css/style.css       # 设计令牌(设计师改这里)
│   └── js/                 # app/api/ws/kanban/status/confirm/report 模块
│
├── harness/                # Harness 测试编排框架(Phase 2 驱动器)
│   ├── config.py  environment.py  clients.py  scenario.py
│   ├── scenarios/          # phase1_core(回归) + agent_contracts(契约) + agent_behavior(行为)
│   ├── report.py  runner.py  main.py
│   └── reports/            # 生成的 JSON/HTML 报告
│
├── tests/                  # pytest(test_phase1 / test_mqtt / test_agent)
├── docs/
│   ├── Nightshift_MQTT_重构提案_v1.md  # 连接架构权威规范(队友提交)
│   └── MQTT_硬件接入文档.md            # MQTT 集成实用参考
└── data/                   # 运行时生成的 SQLite 数据库 + Agent 产物 (output/)

⚙️ 配置参考

全部通过环境变量覆盖,前缀 NIGHTSHIFT_(见 backend/config.py):

变量 默认 说明
NIGHTSHIFT_HOST / NIGHTSHIFT_PORT 127.0.0.1 / 8000 服务地址
NIGHTSHIFT_DB_PATH data/nightshift.db SQLite 路径
NIGHTSHIFT_SERIAL_ENABLED true 串口通道开关
NIGHTSHIFT_SERIAL_BAUDRATE 115200 串口波特率
NIGHTSHIFT_MQTT_ENABLED false MQTT 总开关(false 时核心照常运行)
NIGHTSHIFT_MQTT_HOST / NIGHTSHIFT_MQTT_PORT 127.0.0.1 / 1883 Broker 地址
NIGHTSHIFT_MQTT_NODE_ID / NIGHTSHIFT_MQTT_BASE_TOPIC opi5b01 / nightshift/v1 节点标识 / 主题命名空间
NIGHTSHIFT_LLM_API_KEY DeepSeek key;不配则 Agent 走启发式/模板兜底,演示不受影响
NIGHTSHIFT_LLM_BASE_URL / NIGHTSHIFT_LLM_MODEL https://api.deepseek.com/v1 / deepseek-chat OpenAI 兼容端点 / 模型
NIGHTSHIFT_AGENT_OUTPUT_DIR data/output/ Agent 产物落盘目录(大纲/晨报)
NIGHTSHIFT_SEDENTARY_REMIND_SECONDS 1800 连续落座多久提醒活动(久坐提醒)
NIGHTSHIFT_AWAY_EXEC_SECONDS 300 离席多久自动开工(演示可热调,见下)

🗺️ 路线图

✅ Phase 1 · 骨架(已完成) 任务看板 / 领域状态机(domain 层)/ LED 灯语 / GPIO+UART 硬件架构 / MQTT 可选外部边界 / 交互式 CLI / Harness 回归

✅ Phase 2 · Agent 核心(已完成)

  • LLM 接入层(DeepSeek OpenAI 兼容端点,无 key 自动降级,演示/CI 不依赖网络)
  • 四象限自动分类 Agent(LLM 优先 + 启发式兜底,显式象限不覆盖)
  • 夜间执行器 + Skill 插件系统(首个落地 skill:文档→讲稿大纲,产物真实落盘 data/output/
  • 多 Agent 协作调度(NightScheduler:灯灭开工、灯亮收工,收工不留半个产物)
  • 确认清单信任机制(拿不准→呼吸红→拍板联动)+ 晨报(WS 弹卡 + 落盘)

🚧 下一步

  • 真实 GPIO / UART 适配器(待 YUANZL 确认硬件库与引脚方案,新增 GPIOAdapter/UARTAdapter 子类即可)
  • 更多 skill(按 BaseSkill 契约注册即用)与晨报语音播报(面板 AUDIO_PLAY)

🔮 非目标(本次不碰,讲「可扩展」) 多数据源全接入(只做 1 个真的,其余 mock)· 多 skill 库(只做 1 个能落地的)· 账号体系 / 云同步 / 复杂权限


❓ 常见问题

问题 排查
启动报「端口 10048 被占用」 端口已被占用。CLI 会提示 [o]打开浏览器 / [p]换端口 / [b]返回;或 python cli.py serve --port 8001 --open
前端打不开 / 空白 前端由后端托管,确认后端已启动,访问 http://127.0.0.1:8000/(不是 5173)
需要装 Node 吗? 不需要。只有前端开发者想要热重载才可选装
MQTT 连不上 python cli.py broker 起本地 Broker;Windows 上 MQTT 客户端需 SelectorEventLoop(代码已内置处理)
测试报错连不上后端 test_phase1.py 现为自包含(conftest.py 自动起后端);test_mqtt.py 自带 broker;两者均可直接 pytest
硬件一直没反应 先用 POST /api/dev/environment 验证软件链路,再接真机;检查 GPIO/UART 连接与主题是否匹配

Nightshift —— 它不替你创造,而是替你守住创造所需要的环境: 少一点打断,少一点重复劳动,多一点连续的专注和自由。🌙

AdventureX 2026 · 清闲 UberNovo 团队出品

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages