Skip to content

Add AI Radio Plugin#3407

Open
swiftbird07 wants to merge 20 commits intomusic-assistant:devfrom
swiftbird07:ai-radio
Open

Add AI Radio Plugin#3407
swiftbird07 wants to merge 20 commits intomusic-assistant:devfrom
swiftbird07:ai-radio

Conversation

@swiftbird07
Copy link

As discussed in Discord here is the pull request for my AI Radio plugin.

The plugin allows a user to define a 'station' and specify a MA playlist and the tool will generate the text and respective TTS mp3 files and insert them into a new playlist (or to a current queue) making it more like a radio like experience with weather reports, song intro and outros, news etc.

Features

  • server adds new API commands for ai_radio if plugin is enabled
  • AI-Radio frontend only shows "AI Radio" menu item if plugin is enabled
  • There are two modes of operation: Playlist mode and Dynamic mode. In playlist mode the station is "pre-built" ahead of time, while in Dynamic mode each section is generated "on the fly" for the current queue.
  • Via the menu you can configure stations and sections and then start the radio
  • Sections are used in station configuration and are basically re-usable prompts with placeholders and a few added config options like if you want to enable (or force) web search for a prompt
  • Stations define how each selected section is used and with what guards; you can specify what happens at the start of the radio, between songs and at the end. For each of these you can configure specific flow rules that define what must happen or what can happen with a chance. E.g. you can define that between songs a song transition will be moderated and then with a 20% chance a weather broadcast is inserted as well
  • If more than one section was selected it will be automatically merged together so it sound more like a continuous moderation

Notes

  • I added a small helper script scripts/update_and_redeploy_container.sh to help me update my local deployment, but if you want I can remove that
  • I tried to follow the DEVELOPMENT.md as close as possible. Though this is the first time contributing to this project so there are certainly things I missed so have mercy 😅
  • I will create a PR for the frontend as well

Screenshots

Backend (API)

Screenshot 2026-03-16 at 21 19 24 Screenshot 2026-03-16 at 21 19 39 Screenshot 2026-03-16 at 21 19 47

Frontend

Screenshot 2026-03-14 at 16 45 04 Screenshot 2026-03-14 at 16 46 57 Screenshot 2026-03-14 at 16 46 48

…time behavior

- refactor AI Radio plugin structure and web UI flows (wizard, sections, run controls)
- improve config clarity/help text and standalone MA-styled web UI experience
- add detailed runtime phases/logging and human-readable session status rendering
- improve dynamic batching with earlier prefetch trigger (`dynamic_prefetch_remaining_tracks`)
- add advanced plugin setting for UI auto-refresh interval (`ui_auto_refresh_seconds`)
- fix typing issues and expand provider tests
…e prompts, and improve styles; add air.png to mp3 metadata.
…tyling for better layout and usability. Adjust grid alignment, input heights, and import label styles for improved user experience.
…o-generate IDs from names, and enhance UI layout for better usability.
…ndling, session cancellation, and normalization logic
Copilot AI review requested due to automatic review settings March 16, 2026 20:23
@github-actions
Copy link
Contributor

github-actions bot commented Mar 16, 2026

🔒 Dependency Security Report

✅ No dependency changes detected in this PR.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new AI Radio plugin provider to Music Assistant that can generate radio-style moderator sections (LLM + TTS) and insert them into a playlist (playlist mode) or generate them on-the-fly while queueing (dynamic mode).

Changes:

  • Introduces a new ai_radio plugin provider with storage/normalization and runtime execution logic (LLM generation, TTS synthesis, optional weather enrichment).
  • Registers new admin-only API commands for station/section CRUD and run control (start/stop/status).
  • Adds unit tests for storage normalization, runtime session state handling, and provider validation helpers.

Reviewed changes

Copilot reviewed 15 out of 17 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
music_assistant/providers/ai_radio/provider.py Plugin provider entrypoint, API route registration, run lifecycle management.
music_assistant/providers/ai_radio/runtime.py Core runtime for playlist/dynamic modes, planning/generation/TTS, weather token prep.
music_assistant/providers/ai_radio/storage.py Persistent storage + normalization for stations/sections and defaults.
music_assistant/providers/ai_radio/models.py Dataclasses/utilities for session state, slot planning, text limiting, etc.
music_assistant/providers/ai_radio/constants.py Plugin constants and defaults.
music_assistant/providers/ai_radio/config.py Provider config entries (API keys, UI refresh interval, UI link label).
music_assistant/providers/ai_radio/manifest.json Declares the plugin manifest.
music_assistant/providers/ai_radio/example_station.json Example station definition for reference/testing.
tests/providers/ai_radio/* Unit tests covering storage/runtime/provider helper behavior.
scripts/update_and_redeploy_container.sh Local dev helper script for building and redeploying a container.
DEVELOPMENT.md Adds instructions for building a local Python artifact for Docker builds.

Comment on lines +393 to +394
track_entry_local_indices = [
index for index, uri in enumerate(entries) if "://track/" in uri
Comment on lines +78 to +79
parsed = {item["id"]: item for item in defaults}
await self._write_sections()
raw_constraints = section.get("constraints")
max_chars = 0
if isinstance(raw_constraints, dict):
max_chars = int(raw_constraints.get("max_chars", 0) or 0)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 16, 2026 20:41
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new AI Radio plugin provider that can generate LLM-driven “radio host” sections (with optional weather/news) and synthesize them to TTS MP3s, supporting both prebuilt playlist mode and dynamic queue mode.

Changes:

  • Introduces the ai_radio plugin provider (storage, runtime execution, config entries, manifest, example station).
  • Adds unit tests covering storage normalization, runtime session state/logging, and provider helper validation.
  • Adds a local Docker redeploy helper script and a short DEVELOPMENT.md note about building Python artifacts.

Reviewed changes

Copilot reviewed 15 out of 17 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
music_assistant/providers/ai_radio/provider.py Plugin provider wiring: API commands, station/section CRUD, session lifecycle.
music_assistant/providers/ai_radio/runtime.py Core runtime: planning sections, LLM calls, weather tokens, TTS synthesis, queue/playlist publishing.
music_assistant/providers/ai_radio/storage.py Disk persistence + normalization/validation for stations/sections/general settings.
music_assistant/providers/ai_radio/models.py Dataclasses/utilities used across runtime/provider (slots, session state, helpers).
music_assistant/providers/ai_radio/config.py Provider config entries (API keys, UI refresh, UI URL label).
music_assistant/providers/ai_radio/constants.py Plugin constants/defaults (models, providers, limits, tokens).
music_assistant/providers/ai_radio/manifest.json Declares the plugin provider and its metadata.
music_assistant/providers/ai_radio/example_station.json Example station payload for reference/testing.
music_assistant/providers/ai_radio/init.py Exposes setup + config entries for provider loading.
tests/providers/ai_radio/test_storage.py Unit tests for storage normalization/materialization behavior.
tests/providers/ai_radio/test_runtime.py Unit tests for session execution state changes and weather-token prep warnings.
tests/providers/ai_radio/test_provider.py Unit tests for provider validation logic (dynamic-mode requirements, UI settings).
tests/providers/ai_radio/init.py Test package marker.
scripts/update_and_redeploy_container.sh Local helper to build artifacts and redeploy a Docker container.
DEVELOPMENT.md Adds short instructions for building dist/ artifacts for Docker builds.

Comment on lines +78 to +79
parsed = {item["id"]: item for item in defaults}
await self._write_sections()
raw_constraints = section.get("constraints")
max_chars = 0
if isinstance(raw_constraints, dict):
max_chars = int(raw_constraints.get("max_chars", 0) or 0)
Comment on lines +224 to +242
"instructions": str(source_general.get("instructions", defaults["instructions"])),
"openai_base_url": _text("openai_base_url"),
"section_store_path": _text("section_store_path"),
"weather_provider": _text("weather_provider"),
"weather_timeout_seconds": _number("weather_timeout_seconds", int),
"tts_provider": _text("tts_provider"),
"openai_tts_model": _text("openai_tts_model"),
"openai_tts_voice": _text("openai_tts_voice"),
"openai_tts_instructions": str(
source_general.get(
"openai_tts_instructions",
defaults["openai_tts_instructions"],
)
),
"elevenlabs_model": _text("elevenlabs_model"),
"elevenlabs_voice_id": str(
source_general.get("elevenlabs_voice_id", defaults["elevenlabs_voice_id"])
).strip(),
}
"authorization": f"Bearer {api_key}",
"content-type": "application/json",
"accept": accept,
},
Comment on lines +21 to +33
CONTAINER_NAME="${CONTAINER_NAME:-music-assistant-local}"
IMAGE_NAME="${IMAGE_NAME:-ma-server-local}"
MASS_VERSION="${MASS_VERSION:-0.0.0}"
NETWORK_MODE="${NETWORK_MODE:-host}"

DATA_DIR="${DATA_DIR:-/path/to/mass_data}"
MUSIC_DIR="${MUSIC_DIR:-/path/to/music}"
TIMEZONE_FILE="${TIMEZONE_FILE:-/path/to/timezone/file}"

TOTAL_STEPS=5
if [[ -n "$FRONTEND_PATH_ARG" ]]; then
TOTAL_STEPS=6
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants