thecollabagepatch commited on
Commit
21a61ae
·
1 Parent(s): b285a5d

dice button for magenta prompts

Browse files
Files changed (4) hide show
  1. Dockerfile +2 -0
  2. app.py +7 -1
  3. magentaRT_rt_tester.html +39 -28
  4. magenta_prompts.js +115 -0
Dockerfile CHANGED
@@ -152,6 +152,8 @@ COPY --chown=appuser:appuser lil_demo_540p.mp4 /home/appuser/app/lil_demo_540p.m
152
 
153
  COPY --chown=appuser:appuser magentaRT_rt_tester.html /home/appuser/app/magentaRT_rt_tester.html
154
 
 
 
155
  # Create docs directory and copy documentation files
156
  COPY --chown=appuser:appuser docs/ /home/appuser/app/docs/
157
 
 
152
 
153
  COPY --chown=appuser:appuser magentaRT_rt_tester.html /home/appuser/app/magentaRT_rt_tester.html
154
 
155
+ COPY --chown=appuser:appuser magenta_prompts.js /home/appuser/app/magenta_prompts.js
156
+
157
  # Create docs directory and copy documentation files
158
  COPY --chown=appuser:appuser docs/ /home/appuser/app/docs/
159
 
app.py CHANGED
@@ -1640,4 +1640,10 @@ def tester():
1640
  return HTMLResponse(
1641
  html_path.read_text(encoding="utf-8"),
1642
  headers={"Cache-Control": "no-store"} # avoid sticky caches while iterating
1643
- )
 
 
 
 
 
 
 
1640
  return HTMLResponse(
1641
  html_path.read_text(encoding="utf-8"),
1642
  headers={"Cache-Control": "no-store"} # avoid sticky caches while iterating
1643
+ )
1644
+
1645
+ @app.get("/magenta_prompts.js")
1646
+ def magenta_prompts_js():
1647
+ js_path = Path(__file__).parent / "magenta_prompts.js"
1648
+ return FileResponse(js_path, media_type="text/javascript",
1649
+ headers={"Cache-Control": "no-store"})
magentaRT_rt_tester.html CHANGED
@@ -221,6 +221,11 @@
221
  </div>
222
  </div>
223
 
 
 
 
 
 
224
  <script>
225
  (() => {
226
  const $ = (id) => document.getElementById(id);
@@ -462,35 +467,39 @@ async function scheduleWavBytes(arrayBuffer) {
462
  const btnAddStyle = document.getElementById("btnAddStyle");
463
 
464
  function addStyleRow(name = "", weight = 1.0) {
465
- const row = document.createElement("div");
466
- row.className = "style-row";
467
- row.innerHTML = `
468
- <input class="style-name" type="text" placeholder="e.g. acid house" value="${name}">
469
- <input class="style-range" type="range" min="0.0" max="2.0" step="0.01" value="${weight}">
470
- <input class="style-number" type="number" min="0.0" max="2.0" step="0.01" value="${weight}">
 
 
471
  <button class="btn remove" type="button" title="Remove">×</button>
472
- `;
473
-
474
- const nameEl = row.querySelector(".style-name");
475
- const rangeEl = row.querySelector(".style-range");
476
- const numEl = row.querySelector(".style-number");
477
- const remove = row.querySelector(".remove");
478
-
479
- // keep slider/number in sync + auto-update
480
- const sync = (fromRange) => {
481
- if (fromRange) numEl.value = rangeEl.value;
482
- else rangeEl.value = numEl.value;
483
- };
484
- rangeEl.addEventListener("input", () => { sync(true); debouncedUpdate(); });
485
- numEl.addEventListener("input", () => { sync(false); debouncedUpdate(); });
486
- nameEl.addEventListener("input", () => { debouncedUpdate(); });
487
-
488
- remove.addEventListener("click", () => { row.remove(); debouncedUpdate(); });
489
-
490
- styleRows.appendChild(row);
491
- // initial sync
492
- sync(true);
493
- }
 
 
494
 
495
  function stylesCSV() {
496
  // only include rows with non-empty names
@@ -806,6 +815,8 @@ async function scheduleWavBytes(arrayBuffer) {
806
  }
807
  }
808
 
 
 
809
  })();
810
  </script>
811
  </body>
 
221
  </div>
222
  </div>
223
 
224
+ <script type="module">
225
+ import { MagentaPrompts } from "./magenta_prompts.js";
226
+ window.MagentaPrompts = MagentaPrompts; // expose for inline handlers if needed
227
+ </script>
228
+
229
  <script>
230
  (() => {
231
  const $ = (id) => document.getElementById(id);
 
467
  const btnAddStyle = document.getElementById("btnAddStyle");
468
 
469
  function addStyleRow(name = "", weight = 1.0) {
470
+ const row = document.createElement("div");
471
+ row.className = "style-row";
472
+ row.innerHTML = `
473
+ <input class="style-name" type="text" placeholder="e.g. acid house" value="${name}">
474
+ <input class="style-range" type="range" min="0.0" max="2.0" step="0.01" value="${weight}">
475
+ <input class="style-number" type="number" min="0.0" max="2.0" step="0.01" value="${weight}">
476
+ <div class="controls" style="display:flex; gap:6px; justify-content:flex-end;">
477
+ <button class="btn dice" type="button" title="Dice">🎲</button>
478
  <button class="btn remove" type="button" title="Remove">×</button>
479
+ </div>
480
+ `;
481
+
482
+ const nameEl = row.querySelector(".style-name");
483
+ const rangeEl = row.querySelector(".style-range");
484
+ const numEl = row.querySelector(".style-number");
485
+ const remove = row.querySelector(".remove");
486
+ const dice = row.querySelector(".dice");
487
+
488
+ // keep slider/number in sync + auto-update
489
+ const sync = (fromRange) => { if (fromRange) numEl.value = rangeEl.value; else rangeEl.value = numEl.value; };
490
+ rangeEl.addEventListener("input", () => { sync(true); debouncedUpdate(); });
491
+ numEl.addEventListener("input", () => { sync(false); debouncedUpdate(); });
492
+ nameEl.addEventListener("input", () => { debouncedUpdate(); });
493
+
494
+ remove.addEventListener("click", () => { row.remove(); debouncedUpdate(); });
495
+ dice.addEventListener("click", () => {
496
+ nameEl.value = window.MagentaPrompts.getNextCyclingStyle();
497
+ debouncedUpdate();
498
+ });
499
+
500
+ styleRows.appendChild(row);
501
+ sync(true);
502
+ }
503
 
504
  function stylesCSV() {
505
  // only include rows with non-empty names
 
815
  }
816
  }
817
 
818
+
819
+
820
  })();
821
  </script>
822
  </body>
magenta_prompts.js ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // magenta_prompts.js
2
+ // Minimal browser port of MagentaPrompts (Swift) with single-word vibes,
3
+ // descriptive instruments, and micro-genre leaning. Outputs 1–3 words.
4
+
5
+ export const MagentaPrompts = (() => {
6
+ // ---- Base pools ----
7
+ const instruments = [
8
+ "electric guitar","acoustic guitar","flamenco guitar","bass guitar",
9
+ "electric piano","grand piano","synth lead","synth arpeggio",
10
+ "violin","cello","trumpet","saxophone","clarinet",
11
+ "drums","808 drums","live drums",
12
+ "strings","brass section","hammond organ","wurlitzer","moog bass","analog synth"
13
+ ];
14
+
15
+ // single-word vibes only (kept surprising like 'warmup')
16
+ const vibes = [
17
+ "warmup","afterglow","sunrise","midnight","dusk","twilight","daybreak","nocturne","aurora","ember",
18
+ "neon","chrome","velvet","glass","granite","desert","oceanic","skyline","underground","warehouse",
19
+ "dreamy","nostalgic","moody","uplifting","mysterious","energetic","chill","dark","bright","atmospheric",
20
+ "spacey","groovy","ethereal","glitchy","dusty","tape","vintage","hazy","crystalline","shimmer",
21
+ "magnetic","luminous","starlit","shadow","smolder","static","drift","bloom","horizon"
22
+ ];
23
+
24
+ const genres = [
25
+ "synthwave","death metal","lofi hiphop","acid house","techno","ambient",
26
+ "jazz","blues","rock","pop","electronic","hip hop","reggae","folk",
27
+ "classical","funk","soul","disco","dubstep","drum and bass","trance","garage"
28
+ ];
29
+
30
+ const microGenres = [
31
+ "breakbeat","boom bap","uk garage","two step","dub techno","deep house",
32
+ "lofi house","minimal techno","progressive house","psytrance","goa",
33
+ "liquid dnb","neurofunk","glitch hop","idm","electro","footwork",
34
+ "phonk","dark trap","hyperpop","darksynth","chillwave","vaporwave","future garage"
35
+ ];
36
+
37
+ const genreQualifiers = ["deep","dub","dark","melodic","minimal","uplifting","lofi","industrial","retro","neo"];
38
+
39
+ const genericTechniques = ["arpeggio","ostinato","staccato","legato","tremolo","harmonics","plucks","pad","chops"];
40
+
41
+ const instrumentDescriptors = {
42
+ "electric guitar": ["palm-muted","tremolo","shoegaze","chorused","lead","octave"],
43
+ "acoustic guitar": ["fingerstyle","nylon","arpeggio","strummed"],
44
+ "flamenco guitar": ["rasgueado","picado"],
45
+ "bass guitar": ["slap","picked","sub","syncopated"],
46
+ "moog bass": ["sub","resonant","rubbery"],
47
+ "analog synth": ["pad","plucks","supersaw","arpeggio"],
48
+ "synth lead": ["portamento","supersaw","mono"],
49
+ "electric piano": ["rhodes","chorused","tine"],
50
+ "wurlitzer": ["dirty","tremolo"],
51
+ "grand piano": ["felt","upright","arpeggio"],
52
+ "hammond organ": ["leslie","drawbar"],
53
+ "strings": ["pizzicato","ostinato","legato"],
54
+ "violin": ["pizzicato","legato","tremolo"],
55
+ "cello": ["sul tasto","legato","pizzicato"],
56
+ "trumpet": ["muted","harmon"],
57
+ "saxophone": ["breathy","subtone"],
58
+ "clarinet": ["staccato","legato"],
59
+ "drums": ["brushed","breakbeat","rimshot"],
60
+ "808 drums": ["808","trap"],
61
+ "live drums": ["brushed","tight","roomy"],
62
+ "brass section": ["stabs","swell"]
63
+ };
64
+
65
+ // ---- cycling state ----
66
+ const categories = ["instrument","vibe","genre"];
67
+ let currentCategoryIndex = 0;
68
+
69
+ // ---- public API ----
70
+ function getNextCyclingStyle() {
71
+ const cat = categories[currentCategoryIndex];
72
+ currentCategoryIndex = (currentCategoryIndex + 1) % categories.length;
73
+ if (cat === "instrument") return getRandomInstrument();
74
+ if (cat === "vibe") return getRandomVibe();
75
+ return getRandomGenre();
76
+ }
77
+ function getRandomInstrument() {
78
+ const inst = oneOf(instruments) ?? "electric guitar";
79
+ if (chance(0.45)) {
80
+ const specific = oneOf(instrumentDescriptors[inst] || []);
81
+ const tech = specific || oneOf(genericTechniques) || "arpeggio";
82
+ return clip1to3([tech, inst]);
83
+ }
84
+ return inst;
85
+ }
86
+ function getRandomVibe() {
87
+ return oneOf(vibes) ?? "warmup"; // single word only
88
+ }
89
+ function getRandomGenre() {
90
+ if (chance(0.65)) {
91
+ return oneOf(microGenres) ?? "breakbeat";
92
+ } else {
93
+ const pool = genres.filter(g => g.toLowerCase() !== "jazz"); // avoid pure "jazz" on dice
94
+ const base = oneOf(pool) ?? "electronic";
95
+ if (chance(0.30)) {
96
+ const q = oneOf(genreQualifiers) ?? "deep";
97
+ return clip1to3([q, base]);
98
+ }
99
+ return base;
100
+ }
101
+ }
102
+ function getRandomStyle() {
103
+ const r = Math.floor(Math.random()*3);
104
+ return r===0 ? getRandomInstrument() : r===1 ? getRandomVibe() : getRandomGenre();
105
+ }
106
+ function resetCycle(){ currentCategoryIndex = 0; }
107
+
108
+ // ---- helpers ----
109
+ const chance = p => Math.random() < Math.max(0, Math.min(1, p));
110
+ const oneOf = arr => (arr && arr.length) ? arr[Math.floor(Math.random()*arr.length)] : undefined;
111
+ const clip1to3 = (words, max=3) =>
112
+ words.flatMap(w => String(w).split(" ")).slice(0, max).join(" ");
113
+
114
+ return { getNextCyclingStyle, getRandomStyle, resetCycle };
115
+ })();