KuraiMusik
An internet radio that never switches off. AI generates the music, and the system mixes and streams it on its own, around the clock, across several stations with nobody in the booth.
What you see
Step in, pick a station from Dubstep, Hacker Music and Jazz, and listen to a continuous stream, just like a real radio. There's no playlist to build: tracks are generated with AI, blend into each other with a crossfade, and the player shows you what's on.



Architecture
A radio can't pause while a model finishes generating. So I separated what takes time from what always has to be playing: music is generated in the background, and the broadcast only picks up what's already ready.
Web clientNext.js
Lives in its own repository. It picks the station, plays the stream and gets the current track and system status in real time.
OrchestratorFastAPI
Exposes the stations, the current track and system health, and announces changes over WebSocket and Socket.IO.
Background generationCelery and Redis
Watches each station's buffer and queues new tracks when they're needed, without touching the broadcast.
Mixing and broadcastLiquidsoap and Icecast
Liquidsoap blends tracks with a crossfade and normalizes the volume, and Icecast delivers the audio to whoever is listening.
- ACE-StepGenerates the music, as a separate microservice
- RedisWork queues
- LiquidsoapMixing and gain control
- IcecastStreaming to listeners
- PrometheusMetrics and system health
A playlist that evolves
Each station keeps a dynamic buffer. New tracks are generated continuously and the oldest ones leave to make room, so over time the programming changes completely instead of looping the same songs.
Failures never reach your ears
A circuit breaker protects the system when the generation API fails, and the radio keeps playing what's already in the buffer. Its state also reaches the client, which can say so with a friendly "we're tuning the signal".
Making it sound like a radio
Crossfades and automatic gain control prevent cuts and volume jumps between tracks that were generated separately. Each MP3 also carries its ID3 metadata.
Stations as configuration
Each station is declared in a YAML file, with its mount point, its name and its prompts. Adding one doesn't require touching the orchestrator's code.
A client that knows right away
Track changes, buffer updates and the circuit breaker's state are sent as events, so the interface doesn't have to keep asking.
The challenge
Keeping a radio station of AI-generated music going all day with no operator, so that a single failure never reaches the ears of whoever is listening. Generating a track takes time, and a live stream can't wait.
What's behind it
- The backend and streaming engine live in one repository, the Next.js client in another, and ACE-Step runs as an independent service.
- The whole backend starts with Docker Compose, including Icecast and Liquidsoap.
- The system exposes health probes, Prometheus metrics and structured logs.
- Rate limiting protects the API from abuse.
- Tests cover unit, integration, smoke, API contracts, resilience and load with Locust.
Decisions and trade-offs
- Generate before streaming. Generating ahead uses more resources, but listeners never depend on the model's inference time.
- Degrade instead of going down. If one piece fails, the system isolates it and the radio keeps playing.
- Keep the generator apart from the radio. There are more services to coordinate, but the model can fail, restart or change without stopping the broadcast.
- Use Icecast and Liquidsoap instead of custom streaming. I depend on how they're configured, and in return I lean on radio tools that are already proven.