Skip to content

StefanoBalocco/aiCast

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

aiCast — Generative Web Radio Daemon

A Node.js daemon that runs a shared MP3 broadcast with songs generated by a remote ACE-Step server and lyrics, titles, and band names from an OpenAI-compatible chat-completions endpoint. All listeners receive one continuous stream (Icecast/SHOUTcast-style, with optional ICY metadata).

Requirements

  • Node.js ≥ 20

Quick Start

  1. Install: pnpm install
  2. Build: pnpm run build (compiles TypeScript daemon and tests)
  3. Run: pnpm start (runs dist/index.js)

On first run, config.json is created in the working directory with sensible defaults. Edit it to point to your ACE-Step and text-generation endpoints, then restart.

Configuration

Edit config.json (created with defaults on first run). The example below is illustrative — the generated default file has empty bands/themes and no streamListen; optional fields (per-theme audioDuration, streamListen) are shown here for reference:

{
  "stationName": "aiCast",
  "listen": { "host": "127.0.0.1", "port": 8008 },
  "dataDir": "./data",
  "bands": [
    {
      "prompt": "dark pop",
      "language": "en",
      "bandName": "",
      "comment": ""
    }
  ],
  "themes": [
    { "band": "<bandKey>", "prompt": "a song about rain", "enabled": true, "audioDuration": 120 },
    { "band": "<bandKey>", "prompt": "", "enabled": true }
  ],
  "audio": {
    "url": "http://localhost:8001",
    "apiKey": "",
    "api": "acestep"
  },
  "text": {
    "url": "http://localhost:8080/api/v1",
    "apiKey": "",
    "model": ""
  },
  "generation": {
    "audioDuration": 180,
    "inferenceSteps": 8,
    "quality": 2,
    "lookahead": 1
  },
  "streamListen": { "host": "0.0.0.0", "port": 9000 }
}

Key Fields

  • stationName: Broadcast name (displayed in listeners and ICY metadata)
  • listen.host, listen.port: Interface and port for the HTTP server
  • dataDir: Directory for library MP3s and state file
  • bands: Style definitions. Each entry has:
    • prompt: music description (e.g. "dark pop", "ambient")
    • language: exactly two ISO 639-1 letters (e.g. "en", "it")
    • bandName: auto-filled by the server via LLM (ignored on PUT)
    • comment: optional note
  • themes: The ordered play queue. Each entry has:
    • band: the owning band's key (server-derived, from the bandKey field in GET /api/config)
    • prompt: lyric subject; empty or omitted means instrumental
    • enabled: toggle the row in/out of rotation
    • audioDuration (optional): override the global duration for this row (10–600 seconds); absent uses global
  • audio.{url,apiKey,api}: ACE-Step endpoint (acestep = native REST, acestep.cpp = GGML variant)
  • text.{url,apiKey,model}: OpenAI-compatible endpoint for band names and lyrics
  • generation.audioDuration: default song length in seconds (per-theme override available)
  • generation.inferenceSteps: inference steps for audio generation
  • generation.quality (optional): MP3 quality (0=best … 8=worst; empty/absent = backend default; only applied on acestep.cpp backend)
  • generation.lookahead: prefetch queue size
  • streamListen (optional): { host, port } — dedicated listener for /stream. When set, /stream is served only on this listener and omitted from the admin listener. Must differ from listen. Requires restart to change.

Commands

Command Action
pnpm run build Compile daemon and tests to dist/
pnpm run tests Run AVA test suite
pnpm start Run the daemon

Control Panel

Open http://localhost:8008 in a browser. The panel lets you:

  • Edit station name, listen address, and player settings
  • Manage bands and the ordered theme queue (add/remove bands, edit themes, reorder queue rows)
  • Configure ACE-Step and text-generation endpoints
  • Set audio duration, inference steps, quality, and optional dedicated stream listener
  • Watch live status: listener count, current song, generation queue
  • Copy stream URL

Built with myopie.js (reactive components) and jTDAL (template engine), both loaded from CDN.

HTTP Endpoints

Method Path Description
GET /stream MP3 broadcast (audio/mpeg, Icecast/SHOUTcast-style)
GET / Control panel HTML
GET /public/* Static assets (CSS, JS)
GET /api/config Full config with derived keys (JSON)
PUT /api/bands Save bands array; server owns band names
PUT /api/themes Save themes array (ordered play queue)
PUT /api/settings Save scalar/settings sections (no bands/themes)
GET /api/status Live status: listener count, current song, generation queue, play counts
POST /api/reset Reset play counters ({}, { band }, or { band, theme })

Project Layout

  • src/ — TypeScript sources (strict, ESM, .js extensions in imports)
  • dist/ — compiled daemon and build artifacts (committed)
  • public/panel.js, aicast.css
  • tests/ — AVA test suite
  • data/ — library MP3s and state.json
  • build.mjs — build orchestrator

State & Library

Generated MP3s live in data/library/ with filenames <styleKey>_<lyricsKey>_NNNNN.mp3. data/state.json persists per-series play counters and the playback cursor (playCursor); band names are stored in config.json. Each generated track also carries its ACE-Step seed in the ID3v2 comment as seed: <value> — the daemon picks a random seed per track and sends it to the backend, so a track can be reproduced.

Audio Backends

Two ACE-Step backends available behind one AudioClient interface:

  • acestep: native REST API
  • acestep.cpp: GGML-based variant

Set audio.api in config to choose.

Audio Format

Audio is always requested and stored as MP3 directly from the backend; lame/WAV transcoding has been removed.

Architecture

See AGENTS.md and the source code for the authoritative design details.

About

An icecast-like service to stream music from an acestep server

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors