johncrash64/radio-dj

GitHub: johncrash64/radio-dj

一个封装为单一 Go 二进制文件的全天候 AI DJ 网络电台,通过 LLM 驱动的语音播报和 Icecast 流媒体广播,实现自动化、可互动的个人电台运营。

Stars: 14 | Forks: 6

# radio-dj **一个封装在单一 Go 二进制文件中的 24/7 AI-DJ 网络电台。** 指定你的音乐文件夹,配上你自己的 LLM API key,它就会广播一条 连续的 Icecast MP3 流,让 DJ 在直播过程中——甚至在歌曲播放中途——进行解说。 [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Go](https://img.shields.io/badge/Go-1.26+-00ADD8?logo=go&logoColor=white)](https://go.dev) [![macOS](https://img.shields.io/badge/Platform-macOS%20%7C%20Linux-lightgrey)]() [![LinkedIn](https://img.shields.io/badge/Follow-johncrash64-0A66C2?logo=linkedin&logoColor=white)](https://www.linkedin.com/in/johncrash64/) English · [Español](README.es.md)
radio-dj cassette spinning `radio-dj` 是一个用于运行完整电台的单一 Go 二进制文件(约 9 MB)。它 会从你的音乐库中挑选曲目,AI DJ 会在歌曲之间进行语音播报——包括曲目介绍、 当前时间、**真实天气**、通过网络搜索获取的奇闻趣事,以及直播点播 专属问候——并广播标准的 Icecast MP3 流,任何播放器都可以 收听。 无需 Docker。绝不臃肿。仅仅是一个 **8.7 MB 的二进制文件**,占用 **约 20–30 MB 的 RAM**(包含 Icecast + ffmpeg 时约 50–60 MB)——在 macOS 上测得,轻量到甚至可以跑在树莓派上。
## ✨ 功能特性 - **24/7 电台** — 一条永不掉线的连续 Icecast MP3 流 (192 kbps)。 - **AI DJ** 在歌曲间进行语音播报 —— 介绍、时间、真实天气、奇闻趣事 (网络搜索),以及直播点播专属问候。语音支持任何语言。 - **歌曲进行中的实时闪避 (ducking)** —— DJ 可以在音乐播放*之上*说话 (`sidechaincompress`),硬件混音器风格。 - **实时点播** —— 听众可以通过 Web UI 或 API 点播歌曲, DJ 会在节目中读出点播者的名字。 - **新粗野主义 UI** —— 动画卡带、正在播放 + 下一首,以及三个 信息面板(历史记录、DJ 日志、点播列表)。 - **可编辑技能** —— 以文本文件形式重新编程 DJ 的播报环节。无需 重新编译。 - **BYOK LLM** —— 支持 GLM, OpenAI, OpenRouter, Ollama, Groq,或任何 兼容 OpenAI 的提供商。 - **常驻运行** —— 可作为 macOS launchd、Linux systemd 或 OpenRC 服务安装,重启后依然运行。 - **可安装的 PWA** —— 将电台 UI 添加到你的程序坞/主屏幕(通过 Chrome 安装按钮或 Safari → 添加到程序坞)。App shell 支持离线工作。 ## 📸 截图 | DJ 直播中 (桌面端) | 移动端 | 设置向导 | |:---:|:---:|:---:| | DJ 直播中 — 带有动画卡带的桌面 UI | 移动端视图 | 引导向导 — 首次运行设置 | ## 🚀 快速开始 ### 一行命令(推荐) ``` curl -fsSL https://github.com/johncrash64/radio-dj/raw/master/install.sh | bash ``` 自动检测你的操作系统(macOS 或 Linux),安装 `icecast` + `ffmpeg` + `edge-tts`, 并下载预编译的二进制文件(如果没有则从源码构建)。 ### 从源码构建 **macOS (Homebrew):** ``` brew install icecast ffmpeg pipx install edge-tts git clone https://github.com/johncrash64/radio-dj.git cd radio-dj && go build -o radio-dj . ``` **Linux (apt):** ``` sudo apt-get install icecast2 ffmpeg pipx install edge-tts # or: pip3 install --user edge-tts git clone https://github.com/johncrash64/radio-dj.git cd radio-dj && go build -o radio-dj . ``` ### 配置并启动 运行 `radio-dj serve` —— 首次运行时会打开一个**引导向导**,它会 将所有配置写入 `~/.radio-dj/config.json`。你也可以设置环境变量(见下文): ``` export ZAI_API_KEY=your_key # GLM-5.2 (any OpenAI-compatible works) export RDJ_LIBRARY=~/Music/library # your music folder export RDJ_LOCATION="La Paz" # for time + weather export RDJ_VOICE_CMD="edge-tts --voice es-CO-SalomeNeural --text {text} --write-media {out}" ``` ### 常驻服务(支持重启后自动恢复) ``` radio-dj install # macOS → launchd agent · Linux → systemd user unit or OpenRC (needs sudo/doas) radio-dj uninstall # stop and remove the service ``` 然后打开 **http://localhost:7710** (Web UI) 和 **http://localhost:7702/stream.mp3** (音频流)。 ### 作为应用安装 (PWA) 电台 UI 是一个 Progressive Web App —— 安装它以获得原生应用般的体验: - **Chrome / Edge** —— 打开 UI,点击地址栏中的**安装图标**。 - **macOS Safari** —— **文件 → 添加到程序坞**。 - **iOS Safari** —— 分享 → **添加到主屏幕**。 安装后,它会在独立窗口中打开,没有浏览器框架,并且 App shell 支持离线加载(但直播流本身仍需网络连接)。 ## 🎙️ DJ DJ 由 **LLM Director(导演)** 驱动,它会通过一次 结构化调用规划好每一 *tanda*(批次)—— 它负责挑选歌单并决定在歌曲之间说什么: - **曲目介绍** —— “接下来是,*专辑*里 *艺术家* 的*歌曲*……” - **电台 ID** —— 电台名称、位置、听众数量。 - **时间与天气** —— 基于你的位置获取真实情况。 - **奇闻趣事** —— 由 LLM 进行网络搜索,或使用免费的 Wikipedia API。 - **点播专属问候** —— “这首歌是送给 *María* 的 —— *她点播了……*” 每一句语音播报的流程:**LLM**(结合曲目上下文)撰写文本 → **你的 TTS** 进行语音合成 → 在曲目播放前或中途播出。歌曲进行中的播报使用 `sidechaincompress`,在 DJ 说话时压低背景音乐的音量。 ## 🧩 技能(可编辑) DJ 的播报环节以文本文件形式存放在 `~/.radio-dj/skills/` 下。你可以编辑 内置环节或添加你自己的内容 —— radio-dj 会在启动时加载它们。无需重新编译。 ## 📡 API 简单的 HTTP 接口 —— 兼容任何客户端(移动应用、Home Assistant、PanelHUD): | 方法 | 路径 | 描述 | |---|---|---| | `GET` | `/now-playing` | 当前 + 下一首曲目、点播列表、状态 | | `POST` | `/request` | `{"from":"María","text":"Bohemian Rhapsody"}` — 点播一首歌 | | `GET` | `/stream.mp3` | 音频流 | | `GET` | `/listen.pls` · `/listen.m3u` | 用于 Sonos/VLC/汽车的播放列表 | | `GET` | `/health` | 存活探测 | 音频流是一个 **标准的 Icecast / HTTP-MP3 URL** —— 将其粘贴到 VLC、mpv、 任何浏览器、TuneIn、Radio Garden、Sonos,或 iOS/Android 电台应用中即可。 完整参考:**[docs/API.md](docs/API.md)** · **[docs/openapi.yaml](docs/openapi.yaml)**。 ## ⚙️ 配置 radio-dj 从**三个层级读取配置,最低层级优先**: ``` env vars (RDJ_*) > ~/.radio-dj/config.json > defaults ``` **你只需选择其中一种。** 引导向导会为你写入 `config.json`。 高级用户 / CI 可以通过环境变量覆盖任何配置。 ### `config.json` 键(由向导写入,或手动编辑) ``` { "library": "/home/me/Music/library", "source": "folder", "glm_api_key": "your-key", "glm_model": "glm-5.2", "llm_provider": "glm", "voice_provider":"edge-tts", "voice": "es-CO-SalomeNeural", "location": "La Paz", "lat": -16.5, "lon": -68.15, "language": "es", "dj_talk": "regular", "chunk": 8, "bitrate": 192, "station_name": "radio-dj" } ``` ### 完整参考(环境变量 → config.json 键 → 默认值) | 环境变量 | `config.json` 键 | 默认值 | 说明 | |---|---|---|---| | `ZAI_API_KEY` / `RDJ_GLM_API_KEY` | `glm_api_key` | — | 你的 LLM key (BYOK) | | `RDJ_LIBRARY` | `library` | `~/Music/library` | 音乐文件夹 | | `RDJ_SOURCE` | `source` | `folder` | `folder` 或 `navidrome` | | `RDJ_NAVIDROME_URL` | `navidrome_url` | `http://localhost:4533` | Navidrome 服务器 | | `RDJ_NAVIDROME_USER` | `navidrome_user` | — | Navidrome 用户名 | | `RDJ_NAVIDROME_PASS` | `navidrome_pass` | — | Navidrome 密码 | | `RDJ_GLM_MODEL` | `glm_model` | `glm-5.2` | 模型名称 | | `RDJ_LLM_PROVIDER` | `llm_provider` | `glm` | 预设:`glm`/`openai`/`openrouter`/… | | `RDJ_VOICE_CMD` | `voice_cmd` | — | 原始 TTS 命令(`{text}` / `{out}` 占位符) | | `RDJ_VOICE_PROVIDER` | `voice_provider` | — | `edge-tts` / `piper` / `say` | | `RDJ_VOICE` | `voice` | — | 该提供商对应的语音 ID | | `RDJ_LOCATION` | `location` | `La Paz` | 城市名称(用于获取时间 + 天气) | | `RDJ_LAT` / `RDJ_LON` | `lat` / `lon` | La Paz 坐标 | 获取天气所需的精确坐标 | | `RDJ_LANGUAGE` | `language` | `es` | `es` 或 `en`(DJ 提示词 + UI 语言) | | `RDJ_DJ_TALK` | `dj_talk` | `regular` | `low`/`regular`/`high`/`verbose` — 话痨程度 | | `RDJ_DJ_EVERY` | `dj_every` | `3` | DJ 两次播报之间的歌曲间隔(旧版下限) | | `RDJ_CHUNK` | `chunk` | `8` | 每批次歌曲数(预取窗口) | | `RDJ_BITRATE` | `bitrate` | `192` | 流媒体比特率 (kbps) | | `RDJ_STATION_NAME` | `station_name` | `radio-dj` | 电台名称 | | `RDJ_BED` | `bed` | — | 用于闪避的器乐背景音(DJ 在音乐之上说话) | | `RDJ_ICECAST_HOST` | — | `localhost` | icecast 主机地址 (仅限环境变量) | | `RDJ_ICECAST_PORT` | — | `7702` | icecast 端口 (仅限环境变量) | | `RDJ_ICECAST_SOURCE_PW` | — | — | icecast 源密码 (仅限环境变量) | | `RDJ_STATUS_PORT` | — | `7710` | Web UI + API 端口 (仅限环境变量) | ## 🛠️ 架构 ``` radio-dj (Go, ~20–30 MB RAM) ├─ supervisor spawns + watches icecast (child, auto-restart) ├─ producer builds next batch (LLM Director + TTS) via prefetch ├─ master ffmpeg (persistent) PCM → MP3 → icecast, never reconnects └─ decoders ffmpeg (per segment) track/voice → PCM into the master ``` 一条永不中断的 icecast 连接 = 听众端零卡顿掉线。 ``` ┌──────────┐ PCM ┌──────────────┐ MP3 ┌──────────┐ │ producer │─────────▶│ master ffmpeg │──────▶│ icecast │──▶ listeners └──────────┘ └──────────────┘ └──────────┘ │ ▲ │ TTS voice │ PCM (fd4) ▼ │ ┌──────────┐ ┌───────────────┐ │ LLM + TTS │ │ sidechaincomp │ ← ducks music for voice └──────────┘ └───────────────┘ ``` ## 🪶 许可证 **MIT** —— 随你折腾。详见 [LICENSE](LICENSE)。
由 **[johncrash64](https://www.linkedin.com/in/johncrash64/)** 制作 · [报告 Bug](https://github.com/johncrash64/radio-dj/issues) · [功能请求](https://github.com/johncrash64/radio-dj/issues)
标签:AI电台, EVTX分析, FFmpeg, Go语言, Icecast, LLM集成, 日志审计, 流媒体, 程序破解, 音频处理