Define techno-ethnic taste lane and notify when generation is ready.
Bonobo, Jamaica dub, Sahara, Mongolia overtone, and Urdu colour in settings and DJ prompts. Generate runs in background with polling, ready toast, optional browser notification, and autoplay of the new track. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
import json
|
||||
import random
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import BackgroundTasks, FastAPI, HTTPException
|
||||
@@ -35,7 +36,15 @@ app.add_middleware(
|
||||
_config: Config | None = None
|
||||
_queue: RadioQueue | None = None
|
||||
_generating = False
|
||||
_generation_state: dict = {"busy": False, "phase": None, "error": None, "track_title": None}
|
||||
_generation_state: dict = {
|
||||
"busy": False,
|
||||
"phase": None,
|
||||
"error": None,
|
||||
"track_title": None,
|
||||
"last_completed_at": None,
|
||||
"last_completed_title": None,
|
||||
"last_completed_id": None,
|
||||
}
|
||||
_chat = ChatStore()
|
||||
|
||||
|
||||
@@ -101,14 +110,29 @@ def _play_library_entry(q: RadioQueue, cfg: Config, entry: dict) -> dict:
|
||||
return {"status": "ok", "source": "library", "track": np.__dict__ if np else None}
|
||||
|
||||
|
||||
def _set_generation(*, busy: bool, phase: str | None = None, error: str | None = None, title: str | None = None) -> None:
|
||||
def _set_generation(
|
||||
*,
|
||||
busy: bool,
|
||||
phase: str | None = None,
|
||||
error: str | None = None,
|
||||
title: str | None = None,
|
||||
completed_id: str | None = None,
|
||||
) -> None:
|
||||
global _generation_state
|
||||
_generation_state = {
|
||||
state = {
|
||||
"busy": busy,
|
||||
"phase": phase,
|
||||
"error": error,
|
||||
"track_title": title,
|
||||
"last_completed_at": _generation_state.get("last_completed_at"),
|
||||
"last_completed_title": _generation_state.get("last_completed_title"),
|
||||
"last_completed_id": _generation_state.get("last_completed_id"),
|
||||
}
|
||||
if completed_id and title:
|
||||
state["last_completed_at"] = datetime.now(timezone.utc).isoformat()
|
||||
state["last_completed_title"] = title
|
||||
state["last_completed_id"] = completed_id
|
||||
_generation_state = state
|
||||
|
||||
|
||||
async def _compose_track(request: str | None = None, *, check_limit: bool = True) -> dict:
|
||||
@@ -138,12 +162,17 @@ async def _compose_track(request: str | None = None, *, check_limit: bool = True
|
||||
_set_generation(busy=True, phase="composing", title=plan.title)
|
||||
track = LyriaEngine(cfg).generate(plan)
|
||||
q.add(track)
|
||||
q.play_id(track.plan.id)
|
||||
rs = load_radio_settings(lyria_model=cfg.lyria_model)
|
||||
cost = cost_per_track(cfg.lyria_model, rs.costs.__dict__)
|
||||
record_generation(cfg.output_dir, cost, track.plan.id, track.plan.title)
|
||||
np = q.now_playing()
|
||||
_, budget = _can_generate_today(cfg)
|
||||
_set_generation(busy=False)
|
||||
_set_generation(
|
||||
busy=False,
|
||||
title=track.plan.title,
|
||||
completed_id=track.plan.id,
|
||||
)
|
||||
return {
|
||||
"status": "ok",
|
||||
"source": "generated",
|
||||
@@ -262,8 +291,30 @@ async def patch_settings(body: SettingsPatch) -> dict:
|
||||
|
||||
|
||||
@app.post("/api/generate")
|
||||
async def generate_track() -> dict:
|
||||
return await _compose_track()
|
||||
async def generate_track(background: BackgroundTasks) -> dict:
|
||||
"""Start generation in background — poll /api/stats for progress and ready state."""
|
||||
cfg = _get_config()
|
||||
if _generating:
|
||||
return {
|
||||
"status": "busy",
|
||||
"message": "Already generating a track",
|
||||
"generation": _generation_state,
|
||||
}
|
||||
ok, budget = _can_generate_today(cfg)
|
||||
if not ok:
|
||||
return {
|
||||
"status": "limit",
|
||||
"message": f"Daily limit reached ({budget['max_per_day']} new songs)",
|
||||
"budget": budget,
|
||||
}
|
||||
background.add_task(_background_compose, None)
|
||||
return {
|
||||
"status": "accepted",
|
||||
"generating": True,
|
||||
"message": "Generating — planning then Lyria compose (~30–90s)",
|
||||
"budget": budget,
|
||||
"generation": _generation_state,
|
||||
}
|
||||
|
||||
|
||||
@app.post("/api/shuffle/next")
|
||||
|
||||
Reference in New Issue
Block a user