Files
ozan 98890b9581 Add pytest suite, unlimited daily cap, and vocal batch generator.
Tests cover curation, Lyria, queue, and API routes. Setting max_new_songs_per_day to 0 disables the limit; generate-batch runs 20 curated multilingual vocal directions.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-07 15:33:58 +01:00

98 lines
2.7 KiB
Python

from __future__ import annotations
import json
from pathlib import Path
import pytest
from ozan_radio.dj import TrackPlan
from ozan_radio.settings import LyriaSettings
@pytest.fixture
def sample_plan() -> TrackPlan:
return TrackPlan(
id="abc12345",
title="Test Transmission",
mood="hypnotic test mood",
dj_line="Testing on air.",
lyria_prompt="Instrumental. 85 BPM desert dub with saz and ney. No vocals.",
)
@pytest.fixture
def lyria_mix() -> LyriaSettings:
return LyriaSettings(
model="lyria-3-pro-preview",
vocal_mode="mix",
language="auto",
singer_profile="",
output_format="mp3",
prefer_instrumental=False,
)
@pytest.fixture
def lyria_instrumental() -> LyriaSettings:
return LyriaSettings(
model="lyria-3-pro-preview",
vocal_mode="instrumental",
language="auto",
singer_profile="",
output_format="mp3",
prefer_instrumental=True,
)
@pytest.fixture
def songs_dir(tmp_path: Path) -> Path:
"""Minimal song library with one keeper and one skip-rated track."""
d = tmp_path / "songs"
d.mkdir()
keeper = {
"id": "11111111",
"title": "Sahara Test",
"mood": "warm",
"dj_line": "Test line.",
"lyria_prompt": "saz and ney",
"lyrics": "",
"file": "11111111_Sahara_Test.mp3",
"saved_at": "2026-06-07T12:00:00+00:00",
"curation": {
"rating": "love",
"shuffle_weight": 1.5,
"public_playlist": True,
"listener": "test",
"notes": "Gold template.",
"loved": ["saz", "ney"],
"disliked": ["fuzz guitar"],
"avoid_in_successors": ["electric guitar"],
"clone_prompt_hints": "saz first",
},
}
skipped = {
"id": "22222222",
"title": "Bad Intro",
"mood": "",
"dj_line": "",
"lyria_prompt": "",
"lyrics": "",
"file": "22222222_Bad_Intro.mp3",
"saved_at": "2026-06-06T12:00:00+00:00",
"curation": {
"rating": "skip",
"public_playlist": False,
"listener": "test",
"notes": "Removed.",
"loved": [],
"disliked": ["thin intro"],
"avoid_in_successors": [],
"clone_prompt_hints": "",
},
}
(d / "11111111_Sahara_Test.mp3").write_bytes(b"ID3fake")
(d / "22222222_Bad_Intro.mp3").write_bytes(b"ID3fake")
(d / "11111111.meta.json").write_text(json.dumps(keeper), encoding="utf-8")
(d / "22222222.meta.json").write_text(json.dumps(skipped), encoding="utf-8")
return d