from __future__ import annotations import html import random from .safety import copyright_safety_note LANG_TEMPLATES = { "de": "Erzeuge einen originalen Musikclip. Ausgangspunkt: {source_era} {source_genre}: {source_style}. Verwandle ihn in {remix_era} {remix_genre}: {remix_style}. Stimmung: {mood}. Textur: {texture_terms}. BPM: {bpm}. Dauer: {duration} Sekunden.", "fr": "Cree un clip musical original. Point de depart: {source_era} {source_genre}: {source_style}. Transforme-le en {remix_era} {remix_genre}: {remix_style}. Ambiance: {mood}. Texture: {texture_terms}. BPM: {bpm}. Duree: {duration} secondes.", "es": "Crea un clip musical original. Punto de partida: {source_era} {source_genre}: {source_style}. Transformalo en {remix_era} {remix_genre}: {remix_style}. Ambiente: {mood}. Textura: {texture_terms}. BPM: {bpm}. Duracion: {duration} segundos.", } INTRO_MOOD_LINES = { "en": "The mood is {mood}, and the route is entirely original.", "de": "Die Stimmung ist {mood}, und diese Route ist vollstaendig original.", "fr": "L'ambiance est {mood}, et cette route est entierement originale.", "es": "El ambiente es {mood}, y esta ruta es completamente original.", } INTRO_TEMPLATES = { "de": "Guten Abend, Zeitreisende. Wir schicken {source_era} {source_genre} durch {remix_era} {remix_genre}.", "fr": "Bonsoir, voyageurs du temps. Nous envoyons {source_era} {source_genre} vers {remix_era} {remix_genre}.", "es": "Buenas noches, viajeros del tiempo. Enviamos {source_era} {source_genre} hacia {remix_era} {remix_genre}.", } def choose_bpm(remix_genre, source_genre=None, mood=None, seed=None) -> int: rng = random.Random(seed) lo, hi = (remix_genre or {}).get("bpm_range") or (source_genre or {}).get("bpm_range") or [90, 125] if mood == "relaxed and intimate": hi = max(lo, int((lo + hi) / 2)) elif mood == "energetic and club-ready": lo = min(hi, int((lo + hi) / 2)) return rng.randint(int(lo), int(hi)) def _english_prompt(source_era, source_genre, remix_era, remix_genre, texture, mood, duration, bpm) -> str: texture_terms = ", ".join(texture.get("prompt_terms", [])) or texture.get("label", "clean digital master") return ( f"Create an original music clip. Start from a {source_era.get('label')} {source_genre.get('label')} " f"musical vocabulary: {source_genre.get('safe_prompt_style')}. Transform it into a {remix_era.get('label')} " f"{remix_genre.get('label')} production: {remix_genre.get('safe_prompt_style')}. Mood: {mood}. " f"Texture: {texture_terms}. BPM: {bpm}. Duration: {duration} seconds." ) def _localized_prompt(language_id, source_era, source_genre, remix_era, remix_genre, texture, mood, duration, bpm) -> tuple[str, str]: if language_id == "en": return _english_prompt(source_era, source_genre, remix_era, remix_genre, texture, mood, duration, bpm), "English prompt." template = LANG_TEMPLATES.get(language_id) if not template: return _english_prompt(source_era, source_genre, remix_era, remix_genre, texture, mood, duration, bpm), "Selected language template missing; English prompt used." return template.format( source_era=source_era.get("label"), source_genre=source_genre.get("label"), source_style=source_genre.get("safe_prompt_style"), remix_era=remix_era.get("label"), remix_genre=remix_genre.get("label"), remix_style=remix_genre.get("safe_prompt_style"), texture_terms=", ".join(texture.get("prompt_terms", [])), mood=mood, bpm=bpm, duration=duration, ), "Selected-language prompt built from deterministic template." def build_music_prompt( source_era, source_genre, remix_era, remix_genre, texture, mood, duration, bpm, language_id="en", prompt_language_mode="Best stability (English)", vocal_mode="Instrumental only", lyrics=None, ) -> str: english = _english_prompt(source_era, source_genre, remix_era, remix_genre, texture, mood, duration, bpm) localized, _ = _localized_prompt(language_id, source_era, source_genre, remix_era, remix_genre, texture, mood, duration, bpm) if prompt_language_mode in ("Broadcast language", "Selected language prompt"): prompt = localized elif prompt_language_mode in ("English + broadcast language", "Bilingual prompt") and language_id != "en": prompt = f"{english}\n{localized}" else: prompt = english if vocal_mode == "Instrumental only": prompt += " No vocals. No lyrics." elif vocal_mode == "Wordless vocal texture": prompt += " Optional wordless, non-lexical vocal texture only. No recognizable words. No lyrics." elif vocal_mode == "Original micro-lyrics": prompt += f" Use only the following original micro-lyrics. Do not add extra lyrics.\nLyrics:\n{lyrics or ''}" prompt += " Original composition only. No copyrighted melody. Do not imitate any specific song, artist, singer, producer, DJ, hook, riff, sample, lyric, melody, or arrangement." return prompt def build_dj_intro(persona, source_era, source_genre, remix_era, remix_genre, mood, language_id="en") -> dict: values = { "source_era": source_era.get("label"), "source_genre": source_genre.get("label"), "remix_era": remix_era.get("label"), "remix_genre": remix_genre.get("label"), } if language_id == "en": text = (persona.get("intro_template") or "").format(**values) status = "English persona intro template." else: text = INTRO_TEMPLATES.get(language_id, persona.get("intro_template", "")).format(**values) status = "Handcrafted multilingual intro template." if language_id in INTRO_TEMPLATES else "Intro template fallback to English." text = f"{text} {INTRO_MOOD_LINES.get(language_id, INTRO_MOOD_LINES['en']).format(mood=mood)}" return {"text": text[:420], "status": status} def build_mixtape_card( source_era, source_genre, remix_era, remix_genre, persona, texture, mood, bpm, language, prompt_language_mode, vocal_mode, lyric_theme, lyrics, statuses, seed, ) -> str: route = f"{source_era.get('label')} {source_genre.get('label')} -> {remix_era.get('label')} {remix_genre.get('label')}" rows = [ ("Route", route), ("Fictional DJ", persona.get("name")), ("Language", language.get("label")), ("Prompt mode", prompt_language_mode), ("Vocal mode", vocal_mode), ("Lyric theme", lyric_theme.get("label") if lyric_theme else "None"), ("Texture", texture.get("label")), ("Mood", mood), ("BPM / Seed", f"{bpm} / {seed}"), ("Model stack", "ACE-Step 1.5 music, MMS TTS spoken DJ, Tiny Aya text; graceful local fallbacks"), ("Status", " | ".join(statuses)), ("Safety", copyright_safety_note()), ] lyric_html = "" if lyrics: lyric_html = f"
{html.escape(lyrics).replace(chr(10), '
')}
" kv = "".join(f"
{html.escape(k)}{html.escape(str(v))}
" for k, v in rows) return f"""
Mixtape Card

{html.escape(route)}

{lyric_html} {kv}
"""