Files
live-radio/tests/test_lyria.py
T
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

127 lines
3.7 KiB
Python

from __future__ import annotations
from types import SimpleNamespace
import pytest
from google.genai import errors as genai_errors
from ozan_radio.dj import TrackPlan
from ozan_radio.lyria import (
_block_reason,
_build_lyria_prompt,
_extract_audio,
_extract_lyrics,
_response_parts,
_sanitize_for_retry,
_wants_vocals,
friendly_lyria_error,
)
from ozan_radio.settings import LyriaSettings
def test_wants_vocals_explicit_no():
assert _wants_vocals("Instrumental. No vocals. Build slowly.") is False
def test_wants_vocals_whispered_texture():
assert _wants_vocals("whispered vocal textures drift in and out") is True
def test_wants_vocals_griot_request():
assert _wants_vocals("West African griot vocals over desert dub") is True
def test_build_lyria_prompt_instrumental(sample_plan, lyria_instrumental):
out = _build_lyria_prompt(sample_plan, lyria_instrumental)
assert "Instrumental only, no vocals" in out
assert sample_plan.lyria_prompt in out
def test_build_lyria_prompt_mix(sample_plan, lyria_mix):
out = _build_lyria_prompt(sample_plan, lyria_mix)
assert "Wordless vocal textures" in out
assert "Instrumental only" not in out
def test_build_lyria_prompt_vocals_override_mode(sample_plan, lyria_instrumental):
plan = TrackPlan(
id="v1",
title="Griot Night",
mood="",
dj_line="",
lyria_prompt="Sahel griot male vocal chants over dub.",
)
out = _build_lyria_prompt(plan, lyria_instrumental)
assert "Include lead vocals" in out
def test_build_lyria_prompt_hindi_language(sample_plan):
cfg = LyriaSettings(
model="lyria-3-pro-preview",
vocal_mode="vocals",
language="hi",
singer_profile="male_baritone",
output_format="mp3",
prefer_instrumental=False,
)
plan = TrackPlan(
id="h1",
title="Devotional",
mood="",
dj_line="",
lyria_prompt="Hindi devotional desert dub.",
)
out = _build_lyria_prompt(plan, cfg)
assert "Hindi" in out
assert "Male Baritone" in out
def test_sanitize_for_retry_softens_griot():
raw = "West African griot vocal sample over dub"
soft = _sanitize_for_retry(raw)
assert "griot" not in soft.lower() or "Sahel" in soft
assert soft != raw
def test_response_parts_from_candidates():
part = SimpleNamespace(text=None, inline_data=SimpleNamespace(data=b"audio"))
content = SimpleNamespace(parts=[part])
candidate = SimpleNamespace(content=content, finish_reason="STOP")
response = SimpleNamespace(parts=None, candidates=[candidate])
parts = _response_parts(response)
assert len(parts) == 1
assert _extract_audio(parts) == b"audio"
def test_response_parts_empty_candidates():
response = SimpleNamespace(parts=None, candidates=[])
assert _response_parts(response) == []
def test_extract_lyrics_joins_text():
parts = [
SimpleNamespace(text="[[A0]]", inline_data=None),
SimpleNamespace(text="line two", inline_data=None),
]
assert "line two" in _extract_lyrics(parts)
def test_block_reason_strips_enum_prefix():
feedback = SimpleNamespace(block_reason="BlockedReason.PROHIBITED_CONTENT")
response = SimpleNamespace(prompt_feedback=feedback)
assert _block_reason(response) == "PROHIBITED_CONTENT"
def test_friendly_lyria_error_quota():
exc = genai_errors.ClientError(
429,
{"error": {"message": "resource_exhausted", "status": "RESOURCE_EXHAUSTED"}},
None,
)
msg = friendly_lyria_error(exc)
assert "quota" in msg.lower() or "resource" in msg.lower()
def test_friendly_lyria_error_runtime_passthrough():
assert friendly_lyria_error(RuntimeError("custom")) == "custom"