Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions examples/dj_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""
OpenMythos DJ engine — end-to-end example.

Runs with no external dependencies and no audio files: it uses a small
synthetic library of track metadata so you can see the whole pipeline work,
then swap in your own library (a CSV, a folder of audio, or a list of dicts).

python examples/dj_example.py
"""

from open_mythos.dj import (
BUILTIN_PROFILES,
analyze_library,
get_profile,
plan_mix,
plan_to_mixlang,
)

# A synthetic library: title/artist/bpm/key(Camelot or name)/energy/genre.
LIBRARY = [
{"title": "Opening Fog", "artist": "Aster", "bpm": 122, "key": "8A", "energy": 0.32, "genre": "melodic techno"},
{"title": "First Light", "artist": "Vela", "bpm": 123, "key": "8A", "energy": 0.41, "genre": "melodic techno"},
{"title": "Undertow", "artist": "Koa", "bpm": 124, "key": "9A", "energy": 0.52, "genre": "melodic house"},
{"title": "Pulse Theory", "artist": "N-Six", "bpm": 124, "key": "9B", "energy": 0.6, "genre": "progressive"},
{"title": "Glass Arc", "artist": "Mira", "bpm": 125, "key": "10A", "energy": 0.68, "genre": "melodic techno"},
{"title": "Night Runner", "artist": "Kilo", "bpm": 126, "key": "10A", "energy": 0.75, "genre": "melodic techno"},
{"title": "Ascend", "artist": "Orbit", "bpm": 126, "key": "11A", "energy": 0.82, "genre": "progressive"},
{"title": "Peak Signal", "artist": "Volt", "bpm": 128, "key": "11A", "energy": 0.9, "genre": "melodic techno"},
{"title": "Comedown", "artist": "Haze", "bpm": 122, "key": "7A", "energy": 0.45, "genre": "deep house"},
{"title": "Afterglow", "artist": "Sol", "bpm": 120, "key": "7A", "energy": 0.3, "genre": "organic house"},
{"title": "Detour", "artist": "Rue", "bpm": 127, "key": "3A", "energy": 0.7, "genre": "techno"},
{"title": "Static Bloom", "artist": "Ohm", "bpm": 125, "key": "9A", "energy": 0.64, "genre": "melodic house"},
]


def main() -> None:
library = analyze_library(LIBRARY)
print(f"Analyzed {len(library)} tracks.\n")

print("Available style profiles:", ", ".join(sorted(BUILTIN_PROFILES)), "\n")

profile = get_profile("melodic_journey")
plan = plan_mix(library, profile, length=10)

print("=" * 68)
print(plan.to_text())
print("=" * 68)

print("\nTransitions used:", ", ".join(plan.transitions()))

print("\n--- Same library, 'peak_time_techno' personality ---\n")
plan2 = plan_mix(library, get_profile("peak_time_techno"), length=8)
print(plan2.to_text())

print("\n--- OpenMythos bridge: mix serialized as training tokens ---\n")
mixlang = plan_to_mixlang(plan, dj_name="melodic_journey")
print(mixlang[:400] + (" ..." if len(mixlang) > 400 else ""))
print(
"\nFeed a corpus of real setlists in this format to the RDT "
"to learn a DJ's personality (Layer 2)."
)


if __name__ == "__main__":
main()
84 changes: 84 additions & 0 deletions examples/dj_learn_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"""
OpenMythos DJ engine — learn a DJ's personality from their setlists, then mix
a *new* library in that learned style.

Runs with no external dependencies. It parses two example setlists (inline
text), learns a DJStyleProfile from them, prints what it inferred, then uses
that learned profile to plan a mix over a separate library.

python examples/dj_learn_example.py
"""

from open_mythos.dj import (
analyze_library,
learn_profile_from_setlists,
plan_mix,
setlist_from_text,
setlists_to_corpus,
)

# Two real-ish setlists in the forgiving text format:
# Artist - Title | bpm key energy and >> transition
SET_ONE = """
# Night 1 — a slow harmonic build
Aster - Opening Fog | 121 8A 0.30
>> long_blend
Vela - First Light | 122 8A 0.42
>> long_blend
Ohm - Static Bloom | 124 9A 0.58
>> filter_sweep
Mira - Glass Arc | 125 10A 0.70
>> long_blend
Volt - Peak Signal | 127 11A 0.88
"""

SET_TWO = """
# Night 2 — same DJ, same shape
Sol - Afterglow | 120 7A 0.33
>> long_blend
Koa - Undertow | 123 8A 0.50
>> long_blend
Static - Rise | 125 9A 0.66
>> filter_sweep
Orbit - Ascend | 126 10A 0.84
"""

NEW_LIBRARY = [
{"title": "Cold Start", "artist": "Nyx", "bpm": 121, "key": "8A", "energy": 0.31, "genre": "melodic techno"},
{"title": "Drift", "artist": "Lume", "bpm": 122, "key": "8A", "energy": 0.44, "genre": "melodic techno"},
{"title": "Signal Path", "artist": "Ferro", "bpm": 124, "key": "9A", "energy": 0.6, "genre": "melodic house"},
{"title": "Overpass", "artist": "Cane", "bpm": 125, "key": "10A", "energy": 0.72, "genre": "progressive"},
{"title": "Skyline", "artist": "Ivo", "bpm": 126, "key": "11A", "energy": 0.85, "genre": "melodic techno"},
{"title": "Zenith", "artist": "Rho", "bpm": 128, "key": "11A", "energy": 0.92, "genre": "melodic techno"},
{"title": "Ebb", "artist": "Tal", "bpm": 121, "key": "7A", "energy": 0.4, "genre": "deep house"},
]


def main() -> None:
setlists = [
setlist_from_text(SET_ONE, name="night_1"),
setlist_from_text(SET_TWO, name="night_2"),
]
print(f"Parsed {len(setlists)} setlists "
f"({sum(len(s.tracks) for s in setlists)} tracks total).\n")

profile = learn_profile_from_setlists(setlists, name="learned_dj")
print("--- Learned personality ---")
print(profile.to_json())

print("\n--- Applying the learned style to a NEW library ---\n")
plan = plan_mix(analyze_library(NEW_LIBRARY), profile)
print(plan.to_text())

print("\n--- RDT training corpus (mix language) ---")
rows = setlists_to_corpus(setlists)
for r in rows:
print(r[:110] + " ...")
print(
f"\n{len(rows)} rows ready. Write many of these to a .txt corpus and "
"train the OpenMythos RDT to generate mixes in this DJ's style."
)


if __name__ == "__main__":
main()
113 changes: 84 additions & 29 deletions open_mythos/__init__.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,30 +1,87 @@
from open_mythos.main import (
ACTHalting,
Expert,
GQAttention,
LoRAAdapter,
LTIInjection,
MLAttention,
MoEFFN,
MythosConfig,
OpenMythos,
RecurrentBlock,
RMSNorm,
TransformerBlock,
apply_rope,
loop_index_embedding,
precompute_rope_freqs,
)
from open_mythos.tokenizer import MythosTokenizer
from open_mythos.variants import (
mythos_1b,
mythos_1t,
mythos_3b,
mythos_10b,
mythos_50b,
mythos_100b,
mythos_500b,
)
"""OpenMythos package root.

Heavy, torch-dependent symbols (the model, variants) are imported *lazily* via
PEP 562 ``__getattr__`` so that torch-free subpackages — notably
``open_mythos.dj`` — can be imported and used without pulling in the full model
stack. ``from open_mythos import OpenMythos`` still works exactly as before; the
import just happens on first attribute access.
"""

from importlib import import_module
from typing import TYPE_CHECKING

# name -> submodule it lives in. Resolved lazily on first access.
_LAZY_EXPORTS = {
# open_mythos.main
"ACTHalting": "open_mythos.main",
"Expert": "open_mythos.main",
"GQAttention": "open_mythos.main",
"LoRAAdapter": "open_mythos.main",
"LTIInjection": "open_mythos.main",
"MLAttention": "open_mythos.main",
"MoEFFN": "open_mythos.main",
"MythosConfig": "open_mythos.main",
"OpenMythos": "open_mythos.main",
"RecurrentBlock": "open_mythos.main",
"RMSNorm": "open_mythos.main",
"TransformerBlock": "open_mythos.main",
"apply_rope": "open_mythos.main",
"loop_index_embedding": "open_mythos.main",
"precompute_rope_freqs": "open_mythos.main",
# open_mythos.tokenizer
"MythosTokenizer": "open_mythos.tokenizer",
# open_mythos.variants
"mythos_1b": "open_mythos.variants",
"mythos_3b": "open_mythos.variants",
"mythos_10b": "open_mythos.variants",
"mythos_50b": "open_mythos.variants",
"mythos_100b": "open_mythos.variants",
"mythos_500b": "open_mythos.variants",
"mythos_1t": "open_mythos.variants",
}

if TYPE_CHECKING: # keep static analysis / IDEs happy
from open_mythos.main import ( # noqa: F401
ACTHalting,
Expert,
GQAttention,
LoRAAdapter,
LTIInjection,
MLAttention,
MoEFFN,
MythosConfig,
OpenMythos,
RecurrentBlock,
RMSNorm,
TransformerBlock,
apply_rope,
loop_index_embedding,
precompute_rope_freqs,
)
from open_mythos.tokenizer import MythosTokenizer # noqa: F401
from open_mythos.variants import ( # noqa: F401
mythos_1b,
mythos_1t,
mythos_3b,
mythos_10b,
mythos_50b,
mythos_100b,
mythos_500b,
)


def __getattr__(name: str):
module = _LAZY_EXPORTS.get(name)
if module is None:
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
value = getattr(import_module(module), name)
globals()[name] = value # cache so subsequent access is direct
return value


def __dir__():
return sorted(list(globals().keys()) + list(_LAZY_EXPORTS.keys()))


__all__ = [
"MythosConfig",
Expand All @@ -49,7 +106,5 @@
"mythos_100b",
"mythos_500b",
"mythos_1t",
"load_tokenizer",
"get_vocab_size",
"MythosTokenizer",
]
Loading