用GPT-Live-1和Codex让我的LED显示屏活起来
用树莓派和 128 × 64 HUB75 面板打造语音助手 Jack,通过 GPT-Live-1 全双工语音模型让 LED 屏显示天气、日历和列车信息。
中文
复制

我室友过生日,我送了他一块小 LED 显示屏,能显示从我们窗外经过的航班。这礼物挺酷的,但看着飞机一架架在屏幕上冒出来,我就开始琢磨:这种显示屏除了追踪飞机,还能不能干点别的?能不能显示天气或者我的日历?出门的时候,我能不能直接问一句“下一班火车几点?”,然后答案就出现在屏幕上?
你的浏览器不支持 video 标签。
这事很快就变成了一个副业项目,用到了 Raspberry Pi、一块 128 × 64 的 HUB75 LED 面板、Codex,还有一个我后来管它叫 Jack 的助手。对话跑在 GPT-Live-1 上,这是我们最近在 API 里上线的全双工语音模型。另一个模型负责做研究,渲染器负责处理像素——不过我们一开始的设想绝对没这么周全。这篇文章记录的就是这个过程。
Codex 如何帮我让 HUB75 RGB LED 面板跑起来
一开始,Codex 和我得先搞清楚怎么往屏幕上放点有用的东西。我手上是一块 128 × 64 的 HUB75 RGB 面板,但我对控制器、接线,以及除了它原本显示的内容之外还能怎么给它送数据,几乎一无所知。
我开始给 Codex 发照片,让它解释我看到的都是什么。它帮我认出了关键接口,看懂了那块基于 ESP32 的控制器,也弄明白了 HUB75 面板到底是怎么接收显示数据的。它甚至在照片上做了标注,告诉我哪些部分重要——这很有用,因为靠我自己,看到的差不多就是一块电路板,外加一大堆猜错的机会。
硬件的基本情况搞清楚之后,Codex 帮我让控制器跑起了 WLED-MM,并确认面板配置的分辨率就是正确的 128 × 64。到这一步,我们就能给它发送自定义画面,开始试在这么小的屏幕上到底什么效果好看。Codex 负责查资料和排查问题,我负责接线,遇到和预期不符的情况再反馈给它。
在我的 Mac 上搭建语音控制的 LED 显示屏原型
第一个能跑的版本比最终成品简单得多。控制器跑起 WLED-MM 之后,Codex 帮我写了一个渲染器和一个自定义 skill,我则用 ChatGPT 桌面应用里的 Voice 告诉它屏幕上该显示什么。
这已经足够让这块屏变得不一样了。它能显示天气、日历、地铁到站时间、金融图表、消息、倒计时、照片、画作,或者一段自定义动画场景;只要某个想法在这么小的屏幕上效果不对,我们就去改渲染器。
语音交互仍然发生在 Codex 里,自定义 skill 让它有办法更新这面墙该显示的内容。再往后,Mac 上的渲染器把布局转成 128 × 64 的 RGB 帧,通过 DDP 走本地网络发出去,而运行 WLED-MM 的 ESP32 控制器负责把这些帧送到面板上。
Codex 帮的不只是把这些环节接起来。128 × 64 的屏幕没多少空间,所以我们反复琢磨怎么把文字、图片、天气、日历事件和地铁到站信息塞进去,又不至于糊成一团没法看。我告诉 Codex 哪里看着不对,它去调渲染器或布局,然后我们再试一次,直到待机画面开始变成我真正愿意一直挂着的东西。
问题在于,整套东西仍然依赖我的 Mac。渲染器跑在那儿,语音交互也从那儿发起,笔记本一休眠,或者我把它带出门,这面墙就不再是我想要的那个有用的样子了。理想情况下,我希望下班回到公寓,直接让墙给我看点东西。
把语音助手和渲染器搬到 Raspberry Pi
我跟 Codex 说想把笔记本从这条链路里拿掉,于是我们把必须常驻的部分迁到了 Raspberry Pi 上,把代码放进一个私有仓库,并确保有备份,万一搞坏了还能回滚。Pi 插好之后,Codex 负责把代码跑起来、看日志、处理各种出错的地方,我则继续描述我想让它做什么。
现在它上面运行着两个小型服务:
- 语音服务负责麦克风、PipeWire 音频、WebRTC 回声消除、唤醒与休眠行为、打断、GPT-Live-1 连接,以及客户端委派。
- 渲染服务负责让动画待机画面持续运行、刷新天气和 MTA 地铁到站信息、使用脱敏后的日历数据、校验场景描述,并把帧流式传输到墙上。
把麦克风和扬声器接到 Pi 上之后,我可以走进房间,说一句“Hey Jack”,不用打开电脑就能让它做点事。我们花了不少时间改进唤醒行为和它的回应方式,但真正让它不再像笔记本上的演示、而更像一个可以一直开着的东西,是把它从我的 Mac 上搬下来。
GPT-Live-1 与 Raspberry Pi 如何配合
我们最终的分工是:GPT-Live-1 是跟我对话的那部分,不是往墙上画东西的那部分。GPT-Live-1 让对话保持开启,在说话时仍然在听,允许我打断它,并判断某个请求是否需要对话本身之外的东西。
需要时,Raspberry Pi 会收到委派,并以低推理强度用 GPT-5.6 Luna 发起一个客户端 Responses API 请求。Luna 可以搜索公开网络、查看我日历的只读连接、从 Wikimedia Commons 找可复用的图片,并判断这个请求需要什么样的场景。
有一次,我让 Jack 往墙上放一张照片,它说做不到。渲染器早就支持图片了,只是我没给语音助手一个查找并发送图片的工具。Codex 帮我把它接到 Wikimedia Commons,让它能找一张匹配的图片,并检查其许可和署名。我们还调整了图片适配面板的方式:Pi 会把图片缩放到 128 × 64 像素以内,同时保持比例,这样图片就不会被拉伸铺满屏幕。
随着我们不断添加功能,Codex 帮我们避免各部分纠缠在一起:Pi 上的代码决定 Luna 能用哪些工具,Luna 判断需要什么信息或场景,渲染器则先校验场景 JSON,再把它变成正好 128 × 64 的 RGB 像素。随后它把这些帧通过 DDP 发送给 WLED-MM 控制器,由后者驱动 HUB75 面板。

最早的 bug 出现在一次再普通不过的对话里。我问 Jack 纽约的天气,然后说“把这个显示到墙上”,它却不知道“这个”指的是什么。Codex 发现,我们的应用只把最新一条请求发给了负责更新显示屏的模型。我们改了交接逻辑,把最近的对话和之前的结果一并传过去。
从“Hey Jack”到 LED 显示屏上的像素
如果我让 Jack 查点东西并显示到屏幕上,大致会经历这些步骤:
- Raspberry Pi 以 24 kHz PCM 音频采集我的声音,并在本地做音频处理。
- GPT-Live-1 接收音频流,理解我的请求,并保持对话开启,这样我可以打断它或补充内容。
- 如果请求涉及研究、日历信息、图片或更新墙面,GPT-Live-1 会在客户端发起委派,Pi 通过 Responses API 把任务发给 GPT-5.6 Luna。
- Luna 调用我为该请求开放的工具,比如托管的网页搜索、只读日历连接、可复用图片查询,或者更新墙面的工具。
- 如果已有合适的天气、日程、留言或倒计时场景,它会直接选用;如果我提的是之前没设想过的东西,它会新建一个场景。
- 本地渲染器校验该场景,把它转成 128 × 64 的 RGB 帧,通过 DDP 发送到墙上,同时 GPT-Live-1 告诉我它查到了什么。
我喜欢的一点是,我不必等一轮死板的语音助手交互结束才能说下一句。我可以打断 Jack,把意思说清楚,研究和渲染照样在后台进行。
总的来说,这只是个挺简单的副业项目。我之前没有 HUB75 面板、ESP32 控制器、Raspberry Pi 或语音模型的经验,换作以前,我大概一打开显示器就会放弃。但这次 Codex 帮我边做边摸索,遇到不熟悉的东西,直接问就行。
如果你有类似的项目却不知从何入手,不妨问问 Codex。你可能会惊讶于自己能走多远。