Add DJ curation metadata, public auto-play radio, and Lyria web controls.

Extensive per-track meta feeds DeepSeek planning. Caravan of the Night kept with electric guitar marked disliked. Sahara Saz remains gold standard. Gateway index.html auto-plays on tinqs.com.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-07 15:20:10 +01:00
parent 4b2003866d
commit b2aad43a44
25 changed files with 1869 additions and 75 deletions
+21 -3
View File
@@ -7,12 +7,17 @@ from dataclasses import dataclass
import httpx
from ozan_radio.config import Config
from ozan_radio.settings import ListenerSettings, load_settings
from ozan_radio.curation import curation_summary_for_dj
from ozan_radio.settings import ListenerSettings, load_lyria_settings, load_settings
from ozan_radio.taste import TasteSeeds
CHAT_SYSTEM = """You are the on-air DJ for Live Ozan Radio. Chat with the listener in a warm,
concise radio-host voice. You never play catalog music — only AI-generated tracks via Lyria 3.
Lyria cannot remix or edit an existing MP3. If the listener asks to "add vocals to this song"
or change a saved track, explain you're composing a NEW successor track in that spirit — not
overlaying on the file they're hearing.
When the listener asks for a vibe, mood, genre, or "play something X", set action to "generate"
and include a vibe_hint Lyria can use. Otherwise action is "none".
@@ -34,6 +39,13 @@ Your job:
4. Keep variety — don't repeat the same vibe twice in a row.
5. Follow settings.json taste profile when provided — it overrides generic defaults.
6. Stay in the listener's lane unless they ask for something else in chat.
7. If the request references a saved track ("more like Sahara's Saz", "add vocals to X"),
compose a fresh successor — same palette, new title. Never imply remixing an MP3.
8. For vocals Lyria accepts well: "wordless vocal textures", "Sahel blues male chants",
"melodic call-and-response". Avoid "vocal sample" / "griot sample" phrasing.
9. Read listener curation metadata — clone what they loved, hard-avoid what they disliked
(e.g. fuzz electric guitar on vocal tracks, long guitar-only intros before saz).
10. Gold standard track: Sahara's Saz — saz+ney+sub bass by 0:20, whispered textures OK.
Respond with JSON only:
{
@@ -68,10 +80,16 @@ class DeepSeekDJ:
self._config = config
def _taste_block(self) -> str:
parts: list[str] = []
settings = load_settings()
if settings:
return settings.dj_context()
return "No settings.json — freestyle eclectic world groove."
parts.append(settings.dj_context())
else:
parts.append("No settings.json — freestyle eclectic world groove.")
parts.append(load_lyria_settings().dj_context())
cfg = Config.from_env()
parts.append(curation_summary_for_dj(cfg.output_dir))
return "\n".join(parts)
async def _completion(self, messages: list[dict], *, json_mode: bool = False) -> str:
self._config.require_deepseek()