turntable-time-machine / tests /test_app_logic.py
Codex
Replace DJ intro TTS with MMS models
7b926ae
Raw
History Blame Contribute Delete
10.2 kB
from __future__ import annotations
import glob
import os
import unittest
from pathlib import Path
import soundfile as sf
import app
from src.lyrics_generator import generate_micro_lyrics
from src.music_generator import generate_music
from src.safety import sanitize_generated_lyrics
from src.tts import generate_dj_voice
class TurntableTimeMachineLogicTests(unittest.TestCase):
def tearDown(self):
os.environ.pop("TTM_TEST_MODEL_CALLS", None)
os.environ.pop("TTM_DISABLE_TTS_MODEL", None)
patterns = [
"outputs/test_*.wav",
"outputs/final_mix_*.wav",
"outputs/music_raw_*.wav",
"outputs/music_processed_*.wav",
"outputs/dj_intro_*.wav",
]
for path in [item for pattern in patterns for item in glob.glob(pattern)]:
try:
Path(path).unlink()
except OSError:
pass
def test_taxonomy_files_loaded(self):
self.assertGreaterEqual(len(app.ERAS), 4)
self.assertGreaterEqual(len(app.PERSONAS), 3)
self.assertGreaterEqual(len(app.TEXTURES), 4)
self.assertGreaterEqual(len(app.LANGUAGES), 4)
self.assertGreaterEqual(len(app.THEMES), 4)
def test_genre_dropdowns_update_from_selected_era(self):
source_update = app.update_source_genres("1980s")
remix_update = app.update_remix_genres("2020s")
self.assertIn("Synth-pop", source_update["choices"])
self.assertIn("Amapiano-inspired groove", remix_update["choices"])
self.assertEqual(source_update["value"], source_update["choices"][0])
self.assertEqual(remix_update["value"], remix_update["choices"][0])
def test_lyric_theme_visibility_tracks_vocal_mode(self):
self.assertTrue(app.update_lyric_theme_visibility("Original micro-lyrics")["visible"])
self.assertFalse(app.update_lyric_theme_visibility("Instrumental only")["visible"])
self.assertFalse(app.update_lyric_theme_visibility("Wordless vocal texture")["visible"])
def test_micro_lyrics_sanitizer_removes_instruction_text(self):
clean, warnings = sanitize_generated_lyrics(
"No explanation, no punctuation\n"
"Vapor dreams drift on neon haze\n"
"We chase tomorrow through glass streets"
)
self.assertEqual(clean, "Vapor dreams drift on neon haze\nWe chase tomorrow through glass streets")
self.assertTrue(any("instruction" in warning for warning in warnings))
def test_compact_control_css_does_not_restyle_radio_inputs(self):
self.assertIn('input:not([type="radio"]):not([type="checkbox"])', app.CSS)
self.assertIn('input[type="radio"]', app.CSS)
def test_surprise_me_returns_complete_valid_state(self):
result = app.surprise_me()
self.assertEqual(len(result), 15)
self.assertIn(result[0], app.ERA_LABEL_TO_ID)
self.assertIn(result[2], app.ERA_LABEL_TO_ID)
self.assertIn(result[4], app.PERSONA_LABEL_TO_ID)
self.assertIn(result[5], app.TEXTURE_LABEL_TO_ID)
self.assertIn(result[7], app.LANGUAGE_LABEL_TO_ID)
self.assertIn(result[8], app.PROMPT_MODES)
self.assertIn(result[9], app.VOCAL_MODES)
self.assertIn(result[11], app.DURATIONS)
self.assertIn("era-card", result[14])
def test_prompt_mode_labels_are_plain_language(self):
self.assertEqual(
app.PROMPT_MODES,
["Best stability (English)", "Broadcast language", "English + broadcast language"],
)
def test_music_wrapper_attempts_model_by_default_then_falls_back(self):
result = generate_music(
"Create an original music clip. No vocals. No lyrics.",
duration=1,
bpm=110,
seed=101,
output_path="outputs/test_default_model_attempt.wav",
)
self.assertTrue(result["model_attempted"])
self.assertEqual(result["model_id"], "ACE-Step/Ace-Step1.5")
self.assertTrue(result["fallback_used"])
audio, sr = sf.read(result["path"])
self.assertEqual(sr, 44100)
self.assertGreater(audio.shape[0], 0)
def test_fallback_music_varies_by_prompt_route(self):
first = generate_music(
"Create an original music clip. Start from 1960s Motown-inspired soul. Transform it into 2000s filtered disco house.",
duration=1,
bpm=118,
seed=123,
output_path="outputs/test_route_one.wav",
)
second = generate_music(
"Create an original music clip. Start from 2020s lo-fi chill. Transform it into 1970s funk.",
duration=1,
bpm=118,
seed=123,
output_path="outputs/test_route_two.wav",
)
audio_one, _ = sf.read(first["path"])
audio_two, _ = sf.read(second["path"])
self.assertGreater(float(abs(audio_one - audio_two).mean()), 0.001)
def test_audio_model_calls_can_be_exercised_with_test_switch(self):
os.environ["TTM_TEST_MODEL_CALLS"] = "1"
music = generate_music(
"Create an original music clip. Optional wordless, non-lexical vocal texture only.",
duration=1,
bpm=122,
vocal_mode="Wordless vocal texture",
seed=202,
output_path="outputs/test_model_music.wav",
)
tts = generate_dj_voice(
"Signal detected. This is a fictional DJ intro.",
"en",
"neon_signal_host",
"outputs/test_model_tts.wav",
)
lyrics = generate_micro_lyrics(
app.ERAS[2],
app.ERAS[2]["genres"][0],
app.ERAS[4],
app.ERAS[4]["genres"][0],
"nostalgic and warm",
app.THEMES[0],
"en",
seed=303,
)
self.assertFalse(music["fallback_used"])
self.assertEqual(music["vocal_rendering_status"], "wordless")
self.assertTrue(tts["tts_succeeded"])
self.assertFalse(lyrics["fallback_used"])
self.assertIn("simulated for tests", music["status"])
self.assertIn("simulated for tests", tts["status"])
self.assertEqual(tts["model_id"], "facebook/mms-tts-eng")
self.assertIn("simulated for tests", lyrics["status"])
def test_tts_model_routes_by_language(self):
os.environ["TTM_TEST_MODEL_CALLS"] = "1"
tts = generate_dj_voice(
"Bonsoir, voyageurs du temps.",
"fr",
"warehouse_announcer",
"outputs/test_model_tts_fr.wav",
)
self.assertTrue(tts["tts_succeeded"])
self.assertEqual(tts["model_id"], "facebook/mms-tts-fra")
def test_generate_pipeline_all_vocal_modes_create_final_audio(self):
os.environ["TTM_DISABLE_TTS_MODEL"] = "1"
for index, vocal_mode in enumerate(app.VOCAL_MODES):
with self.subTest(vocal_mode=vocal_mode):
result = app.generate_time_machine_mix(
"1980s",
"Synth-pop",
"2000s",
"Filtered disco house",
"The Neon Signal Host",
"Clean digital master",
"nostalgic and warm",
"English",
"Best stability (English)",
vocal_mode,
"Night drive",
1,
400 + index,
False,
)
(
final_path,
music_path,
intro_path,
intro_status,
_intro_text,
lyrics_text,
prompt,
_card,
status,
) = result[:9]
self.assertTrue(Path(final_path).exists())
self.assertTrue(Path(music_path).exists())
self.assertIsNone(intro_path)
self.assertIn("Spoken DJ intro is unavailable", intro_status)
self.assertIn("ACE-Step", status)
self.assertIn("Spoken DJ intro unavailable", status)
audio, sr = sf.read(final_path)
self.assertEqual(sr, 44100)
self.assertGreater(audio.shape[0], 0)
if vocal_mode == "Original micro-lyrics":
self.assertGreaterEqual(len(lyrics_text.splitlines()), 2)
self.assertIn("Lyrics:", prompt)
elif vocal_mode == "Wordless vocal texture":
self.assertIn("non-lexical vocal texture", prompt)
else:
self.assertIn("No vocals. No lyrics.", prompt)
def test_generate_pipeline_uses_mocked_model_outputs_when_available(self):
os.environ["TTM_TEST_MODEL_CALLS"] = "1"
result = app.generate_time_machine_mix(
"1980s",
"Synth-pop",
"2000s",
"Filtered disco house",
"The Neon Signal Host",
"Clean digital master",
"nostalgic and warm",
"English",
"Best stability (English)",
"Original micro-lyrics",
"Night drive",
1,
777,
False,
)
(
final_path,
music_path,
intro_path,
intro_status,
_intro_text,
lyrics_text,
prompt,
_card,
status,
) = result[:9]
self.assertTrue(Path(final_path).exists())
self.assertTrue(Path(music_path).exists())
self.assertTrue(Path(intro_path).exists())
self.assertEqual(intro_status, "Spoken DJ intro generated.")
self.assertIn("ACE-Step model call simulated", status)
self.assertIn("MMS TTS spoken-DJ model call simulated", status)
self.assertIn("tiny-aya-global text model call simulated", status)
self.assertIn("Lyrics:", prompt)
self.assertGreaterEqual(len(lyrics_text.splitlines()), 2)
if __name__ == "__main__":
unittest.main()