An AI-powered radio station that runs itself. It creates original music, writes DJ scripts, speaks them in a realistic voice, and streams everything live — all from one command.
No music library needed. No recording equipment. No experience required.
- What Is This?
- How It Works
- What You'll Need
- Getting Started
- The Setup Wizard
- Using Your Station
- Development Setup
- Project Structure
- API Reference
- Tech Stack
- Security
- Further Reading
- License
Airwave is a complete, self-running radio station powered by artificial intelligence. Once you set it up, it:
- Creates original music from text descriptions you provide (e.g., "relaxing lo-fi hip hop with piano")
- Writes DJ scripts — natural, conversational breaks between songs
- Speaks the scripts in a realistic AI-generated voice
- Streams everything live as a continuous broadcast anyone can listen to
- Manages itself — generates new music when the queue gets low, rotates styles, handles errors
You control the station through a web dashboard where you can change the music style, update your DJ's personality, add announcements, and monitor everything in real time.
You configure styles AI generates music Listeners tune in
and DJ personality --> and DJ breaks --> to the live stream
(Web UI) (runs automatically) (any device)
Behind the scenes:
+------------------------------------------------------+
| Web Dashboard |
| (your control panel) |
+------------------------------------------------------+
| FastAPI Backend |
| |
| Scheduler --> Music Buffer --> Playout Queue |
| | | | |
| DJ Brain --> Script + Voice | |
| | v |
| +----------------------------> Liquidsoap |
| | |
| Icecast |
| | |
| Live Stream |
+------------------------------------------------------+
The AI services:
| Service | What It Does | Default Provider |
|---|---|---|
| Music Generation | Creates original songs from your style descriptions | SunoAPI.org (unofficial Suno bridge) |
| Script Writing | Writes the DJ scripts between songs | Google Gemini |
| DJ Voice | Speaks the DJ scripts in a realistic voice | Fish Audio |
- Docker and Docker Compose — This packages everything so you don't have to install a dozen things separately. Get Docker here.
- A SunoAPI.org account — For music generation. Sign up at sunoapi.org
- A Google AI Studio account — For DJ script writing. Sign up at aistudio.google.com
- A Fish Audio account — For the DJ's voice. Sign up at fish.audio
You'll need an API key from each one — the setup wizard will show you exactly where to find them. Google AI Studio and Fish Audio both have free tiers you can start on; SunoAPI.org is credit-based, so music generation costs money from the first track.
About music generation: Suno does not currently offer a public API. This project talks to SunoAPI.org, an unofficial third-party service that resells access to Suno's models — it is not operated by or affiliated with Suno. That means your music key comes from sunoapi.org, not from suno.com, and the usual third-party caveats apply: pricing, model availability, and uptime are outside this project's control, and they can change without notice. If Suno ships an official API, or you would rather use a different music service, the music provider is swappable — see Adding Providers.
Don't have API keys yet? That's fine. You can start the station without them and add keys later through the settings page. The station just won't generate content until at least the music key is added.
git clone https://github.com/SmashingGoodTime/airwave.git
cd airwavecp .env.example .envThis step is required — Docker Compose mounts .env into the app container so API keys entered through the setup wizard are saved back to it. You can edit .env to add API keys now, or enter them through the setup wizard instead.
While you're here, change the ICECAST_SOURCE_PASSWORD, ICECAST_ADMIN_PASSWORD, and HARBOR_SOURCE_PASSWORD values from their hackme defaults (see Security).
The station stores its database in a data/ folder on your machine, so your settings survive container upgrades:
mkdir -p dataEmergency audio is already handled — audio/fallback/ ships with one track that plays if music generation is ever slow or unavailable, so the station will not go silent on a fresh install. To use your own material instead, drop any MP3 or WAV files into that folder; see audio/fallback/README.md.
docker-compose upThis starts three services:
| Service | What It Does | URL |
|---|---|---|
| App | Web dashboard + API | http://localhost:8000 |
| Liquidsoap | Audio mixing and playout | (internal) |
| Icecast | Live stream server | http://localhost:8080/stream |
Wait for the log message: Airwave backend ready
Go to http://localhost:8000 in your browser. The setup wizard will walk you through everything.
The first time you open your station, a step-by-step wizard guides you through configuration. Here's what each step does:
Give your station a name (e.g., "Sunset Radio", "The Chill Zone") and pick your timezone. The timezone is used for scheduling — so you can play different music at different times of day.
Connect the three AI services that power your station. For each one, you'll paste an API key — a long string of characters that acts like a password. The wizard has links to each service's website where you can create an account and find your key.
All three services are optional. You can skip any of them and add keys later.
Name your DJ and describe their personality. Are they laid-back and chill? Energetic and funny? The personality description shapes how your DJ talks between songs. There's an example you can use as a starting point.
You'll also pick a content policy:
- Instrumental Only — Music without singing
- Clean Vocals — Songs with singing, but nothing explicit
- No Restrictions — Anything goes
Tell the AI what kind of music to create. Each "style" is a text description like "relaxing lo-fi hip hop with mellow piano and soft drums." The wizard has preset styles you can add with one click, or write your own.
Your station will randomly pick from these styles when generating new music.
Review everything and hit Start Broadcasting. Your station begins generating music immediately.
Once your station is running, the dashboard shows you everything at a glance:
- Now Playing — The current track with a progress bar
- Music Queue — How many songs are ready to play (green = healthy, red = running low)
- AI Services — Whether each service is connected and working
- Listen Live — An embedded player so you can hear your station
- Recent Plays — A scrolling log of everything that's played
The dashboard updates in real time — you don't need to refresh.
Go to the Styles page to add, edit, or remove music styles. You can:
- Add new styles anytime — they take effect immediately
- Set weights so some styles play more often than others
- Set schedules so certain styles only play at specific times (e.g., jazz at night)
- Toggle styles on/off without deleting them
The DJ Config page lets you change:
- Your station name and DJ name
- The DJ's personality (how they talk)
- Their voice
- How often they talk between songs
- Content policy for generated music
The Announcements page lets you add messages your DJ will mention during breaks — like upcoming events, shout-outs, or promotions. You can set:
- Priority — How urgently the announcement should be mentioned
- Max plays — Stop mentioning it after a certain number of times
- Expiration — Automatically stop after a date
The Shows page lets you create scheduled program blocks. Each block sets how long it runs, which music styles it draws from, and which DJ persona hosts it. Blocks play in queue order and loop.
When no show is scheduled, the station runs with the station-default styles and DJ.
The Play Log page shows a complete history of everything your station has played. You can filter by date and export the log as a CSV file.
docker-compose downEverything that matters lives on your machine, outside the containers:
data/— the station database (settings, styles, play history).env— API keys, including any entered through the setup wizardaudio/— generated music, DJ breaks, and recordings
Next time you run docker-compose up, everything picks up where it left off — even after upgrading or rebuilding the containers.
If you want to modify the code or run without Docker:
python -m venv venv
source venv/bin/activate # or venv\Scripts\activate on Windows
pip install -r requirements.txt
python -m server.mainThe API starts at http://localhost:8000.
To also run the test suite, install requirements-dev.txt instead — it adds the test tooling on top of the runtime dependencies. See CONTRIBUTING.md.
cd frontend
npm install
npm run devThe dev server starts at http://localhost:3000 with hot reload. API calls are proxied to port 8000.
cd frontend
npm run buildThe built files go to frontend/dist/ and are served by FastAPI automatically.
airwave/
├── server/ # Python backend
│ ├── main.py # App entry point
│ ├── config.py # Settings from .env
│ ├── database.py # SQLite database
│ ├── models/ # Data models (Track, Style, Show, etc.)
│ ├── routers/ # API endpoints
│ │ ├── shows.py # Show schedule management
│ │ └── ... # Styles, DJ, dashboard, etc.
│ ├── providers/ # AI service integrations
│ │ ├── music/suno.py # Music generation
│ │ ├── scriptwriter/google.py # DJ break scripts
│ │ └── voice/fish.py # Text-to-speech
│ ├── engine/ # Core station logic
│ │ ├── scheduler.py # Show-aware master orchestrator
│ │ ├── music_buffer.py # Track queue manager
│ │ ├── dj_brain.py # DJ break timing & context
│ │ └── playout.py # Liquidsoap interface
│ ├── events/ # Real-time event system
│ └── utils/ # Audio processing, rate limiting
├── frontend/src/ # React web dashboard
│ ├── pages/
│ │ ├── Shows.jsx # Show schedule management
│ │ └── ... # Dashboard, Styles, DJ, etc.
├── liquidsoap/station.liq # Audio playout config
├── icecast/icecast.xml # Stream server config
├── data/ # Station database (created on first run)
├── audio/ # All audio files
│ ├── tracks/ # Generated music
│ ├── breaks/ # DJ break audio
│ ├── fallback/ # Emergency audio
│ └── archive/ # Played tracks
└── docs/ # Documentation
All endpoints are under /api/. The web dashboard uses these same endpoints.
| Method | Endpoint | Description |
|---|---|---|
| Setup | ||
| GET | /api/setup/status |
Check if first-run setup is complete |
| POST | /api/setup/complete |
Save initial station configuration |
| Music Styles | ||
| GET | /api/styles |
List all music styles |
| POST | /api/styles |
Create a new style |
| PUT | /api/styles/{id} |
Update a style |
| DELETE | /api/styles/{id} |
Delete a style |
| POST | /api/styles/{id}/toggle |
Enable or disable a style |
| Announcements | ||
| GET | /api/announcements |
List all announcements |
| POST | /api/announcements |
Create an announcement |
| PUT | /api/announcements/{id} |
Update an announcement |
| DELETE | /api/announcements/{id} |
Delete an announcement |
| DJ Configuration | ||
| GET | /api/dj/config |
Get current DJ settings |
| PUT | /api/dj/config |
Update DJ settings |
| POST | /api/dj/preview |
Generate a test DJ break |
| GET | /api/dj/voices |
List available AI voices |
| Shows | ||
| GET | /api/shows |
List all scheduled shows |
| POST | /api/shows |
Create a show |
| PUT | /api/shows/{id} |
Update a show |
| DELETE | /api/shows/{id} |
Delete a show |
| POST | /api/shows/{id}/toggle |
Enable or disable a show |
| GET | /api/shows/active |
Get the currently active show |
| Dashboard | ||
| GET | /api/dashboard/status |
Current station status (includes active show) |
| GET | /api/dashboard/health |
AI service health check |
| GET | /api/dashboard/recent |
Recently played items |
| WS | /api/dashboard/ws |
Real-time status updates |
| Play Log | ||
| GET | /api/playlog |
Play history (paginated) |
| GET | /api/playlog/export |
Download history as CSV |
| Stream | ||
| GET | /api/stream/url |
Get the live stream URL |
| What | Technology |
|---|---|
| Backend | Python 3.11+, FastAPI, SQLAlchemy, SQLite |
| Frontend | React 18, Vite |
| Music AI | SunoAPI.org (unofficial Suno bridge) |
| Script AI | Google Gemini API |
| Voice AI | Fish Audio API |
| Audio Processing | FFmpeg |
| Audio Playout | Liquidsoap 2.2 |
| Live Streaming | Icecast 2.4 |
| Packaging | Docker, Docker Compose |
A few things to know before running the station anywhere other than your own machine:
- The control API is unauthenticated. Anyone who can reach port 8000 can reconfigure your station, read your play history, and trigger paid AI generations. On a shared or public network, bind the port to localhost (change the compose mapping to
"127.0.0.1:8000:8000") or put a firewall / reverse proxy with authentication in front of it. - Change the default passwords. Set real values for
ICECAST_SOURCE_PASSWORD,ICECAST_ADMIN_PASSWORD, andHARBOR_SOURCE_PASSWORDin.env— thehackmedefaults are placeholders. Anyone with the source password can hijack your stream. - Only the stream needs to be public. Port 8080 (Icecast) is the only thing listeners need. Liquidsoap's telnet and harbor ports are intentionally not published outside the Docker network.
.envholds your API keys. It is ignored by git — keep it that way, and don't paste it into bug reports.
- Getting Started Guide — Detailed walkthrough from zero to a running station
- Configuration Reference — Every setting explained
- Architecture Direction — How the station is moving toward timeline-based broadcast automation
- Adding Providers — How to add new AI services (for developers)
- Contributing — How to contribute to the project
MIT — Use it however you like.