Музыка по запросу: авто-DJ радиостанция -> HTTP MP3-поток, Discord-голос, FreePBX телефон
  • Python 81.1%
  • TypeScript 11.9%
  • CSS 6.9%
  • HTML 0.1%
Find a file
2026-09-10 13:33:54 +00:00
deploy Скаут моделей (scout_models.py + full_probe.py + systemd timer), webui: новая сборка, апдейты API/station/track_agent 2026-09-10 13:33:54 +00:00
webui Скаут моделей (scout_models.py + full_probe.py + systemd timer), webui: новая сборка, апдейты API/station/track_agent 2026-09-10 13:33:54 +00:00
.gitignore React веб-морда (Vite+TS SPA, тёмная тема) + m3u-плейлисты (VLC/Kodi); station.py отдаёт dist на /, старая морда на /simple 2026-08-24 13:53:47 +00:00
extensions_custom.conf Радиостанция v2: временные телефонные номера (пул), выбор модели диджея, вайтлист IP без токена, фикс задержки между треками (предвыбор) и повторов, finish/end_station для конечных запросов, фикс обрезания токенов у reasoning-моделей 2026-08-24 11:54:10 +00:00
full_probe.py Скаут моделей (scout_models.py + full_probe.py + systemd timer), webui: новая сборка, апдейты API/station/track_agent 2026-09-10 13:33:54 +00:00
jukebox.agi Jukebox: авто-DJ радиостанция (поток + Discord-голос + FreePBX), LLM-агент выбора трека, пул воркеров, web UI 2026-08-24 10:18:04 +00:00
jukebox_api.py Скаут моделей (scout_models.py + full_probe.py + systemd timer), webui: новая сборка, апдейты API/station/track_agent 2026-09-10 13:33:54 +00:00
komarujukebox.py Скаут моделей (scout_models.py + full_probe.py + systemd timer), webui: новая сборка, апдейты API/station/track_agent 2026-09-10 13:33:54 +00:00
models.json Скаут моделей (scout_models.py + full_probe.py + systemd timer), webui: новая сборка, апдейты API/station/track_agent 2026-09-10 13:33:54 +00:00
README.md Страница /list — все активные станции с потоками и номерами (не потерять url) 2026-08-24 12:12:20 +00:00
scout_models.py Скаут моделей (scout_models.py + full_probe.py + systemd timer), webui: новая сборка, апдейты API/station/track_agent 2026-09-10 13:33:54 +00:00
station.agi Радиостанция v2: временные телефонные номера (пул), выбор модели диджея, вайтлист IP без токена, фикс задержки между треками (предвыбор) и повторов, finish/end_station для конечных запросов, фикс обрезания токенов у reasoning-моделей 2026-08-24 11:54:10 +00:00
station.py Скаут моделей (scout_models.py + full_probe.py + systemd timer), webui: новая сборка, апдейты API/station/track_agent 2026-09-10 13:33:54 +00:00
track_agent.py Скаут моделей (scout_models.py + full_probe.py + systemd timer), webui: новая сборка, апдейты API/station/track_agent 2026-09-10 13:33:54 +00:00
voicepool.py Скаут моделей (scout_models.py + full_probe.py + systemd timer), webui: новая сборка, апдейты API/station/track_agent 2026-09-10 13:33:54 +00:00

Jukebox — музыка по запросу: поток, телефон, Discord

Опиши, что хочешь послушать — система соберёт бесконечную радиостанцию под твой вайб и отдаст её сразу в трёх видах: живой HTTP MP3-поток (браузер, Minecraft- радио, любой плеер), голосовой канал Discord и телефонную трубку через FreePBX.

Как это работает

  1. Промт → трек. LLM-агент (track_agent.py) сам ищет на YouTube через тулзы (search_youtube, list_channel_uploads, get_video_details) и выбирает конкретное видео — понимает контекст «посвежее / из третьего акта / не тот кавер», а не гадает по устаревшей памяти. Модель для выбора настраивается (цепочка по аптайму либо конкретная). Скоринг по ключевым словам — fallback.
  2. Авто-DJ. Станция бесконечно подбирает треки под вайб, не повторяясь (модель видит и сыгранное, и то что уже в очереди), качает через yt-dlp, нормализует громкость (dynaudnorm), склеивает в непрерывный MP3 и вещает всем слушателям сразу. Следующий трек выбирается заранее, пока играет текущий — на стыке нет паузы.
  3. Конечные запросы. «Поставь одну песню X» — агент ставит её и завершает станцию (finish/end_station), а не крутит по кругу. Открытый вайб («что-нибудь бодрое») играет бесконечно.
  4. Пауза при пустоте. Нет слушателей → обычная станция замирает (0 CPU/ трафик), но живёт; пришёл слушатель — продолжает. Вечный эфир live крутит 24/7 и всегда готов принять звонок.

Компоненты

Файл Что делает
station.py Radio Station API + авто-DJ + MP3-поток + web UI + вечный эфир + пул телефонных номеров
track_agent.py LLM-агент выбора трека (tool-calling), цепочка/выбор модели, nudge-ретрай
komarujukebox.py Discord-бот: /listen, /radio_*, старые /phone, /queue
voicepool.py Пул ботов-воркеров для параллельного голосового стрима
jukebox_api.py Старый API очереди «заказал → сыграло в трубке подряд»
jukebox.agi AGI: проигрывание очереди заказов в трубке
station.agi AGI: слушать live/latest/номер-станции поток в трубке (MP3Player)
extensions_custom.conf Пример dialplan FreePBX

Станция и Discord-бот могут жить на разных машинах (бот ходит на станцию по HTTP), FreePBX — третья машина. Все три общаются по сети.

Вывод / точки входа

  • Веб: http://<station-host>/ — форма «вбей вайб, выбери модель → поток + плеер».
  • Список станций: http://<station-host>/list — все активные станции с их потоками и телефонными номерами (автообновление) — чтобы не потерять url, если закрыл вкладку.
  • Поток: http://<station-host>/stream/<id>.mp3, вечный …/stream/live.mp3.
  • Discord: /listen <vibe> [model] — поднимает станцию, врубает в твоём голосовом через воркер-бота, отдаёт ссылку и телефонный номер. /radio_skip|status|stop|volume|pool.
  • Телефон (FreePBX): вечный эфир 24/7, последняя созданная станция, а также пул временных персональных номеров — каждой станции при создании выдаётся свой номер из диапазона, звонок на него играет именно её (номера в extensions_custom.conf).

HTTP API станции

Метод Путь Назначение
POST /session создать станцию: {prompt, requester?, model?}{id, stream_url, phone}
GET /stream/<id>.mp3 живой MP3-поток станции
GET /session/<id> статус (что играет, очередь, слушатели)
POST /session/<id>/skip следующий трек
POST /session/<id>/enqueue заказать конкретный трек следующим
POST /session/<id>/stop остановить станцию
GET /latest последняя активная станция (для телефона)
GET /by_phone/<num> станция по временному номеру (для телефона)
GET /models список пресетов моделей
GET /sessions список станций (JSON)
GET /list список станций (HTML-страница)
GET /health health

Конфигурация (env)

Станция (station.py):

Переменная Смысл
JUKEBOX_TOKEN токен управляющих запросов (поток и заходы с доверенных сетей — без токена)
STATION_TRUSTED_NETS подсети без токена (через запятую, CIDR) — веб-морда, LAN, mesh
STATION_PORT порт (по умолчанию 80; для <1024 нужна CAP_NET_BIND_SERVICE)
STATION_PUBLIC_HOST хост в ссылках на поток
LOGFARE_API_KEY, LOGFARE_URL доступ к LLM
JUKEBOX_AGENT_MODELS цепочка моделей агента по аптайму
JUKEBOX_AGENT_MAX_TOKENS лимит токенов ответа (запас под reasoning-модели)
YT_DLP_PATH путь к yt-dlp
STATION_PHONE_START/END диапазон временных телефонных номеров
STATION_LIVE_PROMPT вайб вечного эфира

Discord-бот (komarujukebox.py): DISCORD_BOT_TOKEN, STATION_API, STATION_TOKEN, STATION_PHONE, опционально JUKEBOX_WORKER_TOKENS / JUKEBOX_WORKER_CLIENT_IDS для нескольких голосовых станций одновременно.

Разворачивание

# станция
python3 -m venv venv && ./venv/bin/pip install aiohttp yt-dlp
# задать env (см. выше), затем запустить station.py как сервис

# Discord-бот
pip install -U discord.py pynacl
# задать env, запустить komarujukebox.py как сервис

# FreePBX: положить station.agi в agi-bin, подключить extensions_custom.conf

Токены воркеров (для нескольких станций одновременно) задаются через JUKEBOX_WORKER_TOKENS или отдельные env-файлы. Без них пул стартует пустым — /listen тогда отдаёт только поток и телефон.

Секреты

Токены/ключи держатся в env (или env-файлах с chmod 600), читаются через переменные окружения и не коммитятся — см. .gitignore. В коде нет захардкоженных ключей.

Замечания по безопасности

  • /stream намеренно без токена (плееры не шлют заголовки) — защита неугадываемым id сессии; рассчитано на закрытую сеть без внешнего доступа.
  • Управляющие эндпоинты требуют X-Jukebox-Token, кроме запросов из доверенных подсетей (STATION_TRUSTED_NETS).
  • Публичного доступа к потоку нет by design; для выставления наружу добавь обратный прокси с TLS и аутентификацией.