baouws commited on
Commit
ad1e277
·
verified ·
1 Parent(s): d5f2e8a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +213 -616
app.py CHANGED
@@ -1,653 +1,250 @@
1
  import gradio as gr
2
  import requests
3
  import json
4
- import tempfile
5
- import os
6
- from typing import Optional
7
- import random
8
 
9
- # Free Hugging Face LLM model for text generation
10
- MODEL_NAME = "microsoft/DialoGPT-medium"
11
- HF_API_URL = f"https://api-inference.huggingface.co/models/{MODEL_NAME}"
 
 
 
 
 
 
12
 
13
- def generate_strudel_code(music_style: str, api_token: Optional[str] = None) -> str:
14
- """Generate Strudel code using expanded pattern library and optional LLM"""
15
-
16
- # Expanded Strudel examples with more variety
17
- strudel_examples = {
18
- "jazz": [
19
- 'note("c3 eb3 g3 bb3").slow(2).gain(0.8)',
20
- 'note("f3 a3 c4 e4").slow(3).lpf(800)',
21
- 'note("bb2 d3 f3 a3").slow(2.5).room(0.3)'
22
- ],
23
- "techno": [
24
- 's("bd hh").fast(2).gain(0.9)',
25
- 's("bd*2 ~ bd ~").stack(s("~ hh*4")).lpf(2000)',
26
- 's("bd ~ ~ bd").stack(s("hh*8")).distort(0.1)'
27
- ],
28
- "ambient": [
29
- 'note("c4 d4 e4 f4").slow(4).lpf(400).room(0.8)',
30
- 'note("g3 bb3 d4 f4").slow(6).gain(0.6).delay(0.3)',
31
- 'sine(200).slow(8).lpf(300).room(0.9)'
32
- ],
33
- "drum and bass": [
34
- 's("bd*2 [~ sn] bd sn").fast(4)',
35
- 's("bd ~ bd sn").fast(3).stack(s("hh*16").gain(0.3))',
36
- 's("bd*2 ~ sn ~").fast(4).lpf(1200)'
37
- ],
38
- "house": [
39
- 's("bd ~ ~ ~ bd ~ ~ ~").stack(s("~ hh ~ hh"))',
40
- 's("bd*2 ~ ~ bd ~ ~ ~").stack(s("hh*4")).lpf(800)',
41
- 's("bd ~ bd ~").stack(s("~ hh*2")).gain(0.8)'
42
- ],
43
- "classical": [
44
- 'note("c4 d4 e4 f4 g4 a4 b4 c5").slow(8)',
45
- 'note("g3 b3 d4 g4").slow(4).stack(note("d2 g2").slow(2))',
46
- 'note("c4 e4 g4 c5").slow(6).gain(0.7)'
47
- ],
48
- "hip hop": [
49
- 's("bd sn bd sn").stack(s("hh*8"))',
50
- 's("bd*2 ~ sn ~").stack(s("hh ~ hh ~")).slow(0.8)',
51
- 's("bd ~ sn bd").stack(s("hh*4")).lpf(1000)'
52
- ],
53
- "rock": [
54
- 's("bd ~ sn ~").stack(note("e2 ~ g2 ~"))',
55
- 's("bd bd sn ~").stack(note("a2 c3 e3").slow(2))',
56
- 's("bd ~ sn bd").stack(note("e2 g2").slow(1.5))'
57
- ],
58
- "blues": [
59
- 'note("c3 eb3 f3 g3 bb3").slow(3)',
60
- 'note("e2 a2 b2 e3").slow(4).gain(0.8)',
61
- 'note("g2 bb2 d3 f3").slow(3.5).room(0.2)'
62
- ],
63
- "reggae": [
64
- 's("~ bd ~ sn").slow(2)',
65
- 's("~ bd*2 ~ sn").stack(s("hh ~ hh ~")).slow(1.5)',
66
- 's("~ bd ~ sn ~").slow(2.5).gain(0.7)'
67
- ],
68
- "electronic": [
69
- 'square(220).slow(4).lpf(800)',
70
- 's("bd*4").stack(sawtooth(110).slow(2))',
71
- 'sine(440).fast(2).lpf(1000).delay(0.2)'
72
- ],
73
- "minimal": [
74
- 's("bd ~ ~ ~").slow(2)',
75
- 'note("c4").slow(8).gain(0.5)',
76
- 's("~ ~ bd ~").stack(sine(200).slow(16))'
77
- ],
78
- "funk": [
79
- 's("bd ~ sn bd").stack(note("e2 ~ a2 ~"))',
80
- 's("bd*2 sn ~ bd").fast(1.2).stack(s("hh*8"))',
81
- 'note("a2 c3 e3").slow(2).stack(s("bd sn"))'
82
- ]
83
- }
84
-
85
- # Find matching style
86
- best_match = None
87
- for style, patterns in strudel_examples.items():
88
- if style.lower() in music_style.lower():
89
- best_match = random.choice(patterns)
90
- break
91
-
92
- # If no direct match, try partial matches
93
- if not best_match:
94
- for style, patterns in strudel_examples.items():
95
- if any(word in music_style.lower() for word in style.split()):
96
- best_match = random.choice(patterns)
97
- break
98
-
99
- # Try API generation if token provided and no pattern match
100
- if not best_match and api_token:
101
- try:
102
- headers = {
103
- "Authorization": f"Bearer {api_token}",
104
- "Content-Type": "application/json"
105
- }
106
-
107
- prompt = f"Create Strudel live coding music pattern for {music_style}. Use functions: note(), s(), sound(), sine(), square(), sawtooth(), slow(), fast(), stack(), lpf(), gain(), room(), delay(). Example: s('bd hh').fast(2)"
108
-
109
- payload = {
110
- "inputs": prompt,
111
- "parameters": {
112
- "max_length": 80,
113
- "temperature": 0.8,
114
- "return_full_text": False,
115
- "num_return_sequences": 1
116
- }
117
- }
118
-
119
- response = requests.post(HF_API_URL, headers=headers, json=payload, timeout=15)
120
- if response.status_code == 200:
121
- result = response.json()
122
- if isinstance(result, list) and len(result) > 0:
123
- generated_text = result[0].get('generated_text', '').strip()
124
- # Validate that it contains Strudel functions
125
- if generated_text and any(func in generated_text for func in
126
- ['note(', 's(', 'sound(', 'sine(', 'square(', 'sawtooth(']):
127
- return generated_text
128
- except Exception as e:
129
- print(f"API Error: {e}")
130
-
131
- # Return best match or default
132
- return best_match or 'note("c4 d4 e4 f4").slow(2).gain(0.7)'
133
 
134
- def create_strudel_html(strudel_code: str) -> str:
135
- """Create simplified HTML with Strudel player that works better in HF Spaces"""
136
- return f"""
137
- <!DOCTYPE html>
138
- <html lang="en">
139
- <head>
140
- <meta charset="UTF-8">
141
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
142
- <title>Strudel Music Player</title>
143
- <script src="https://unpkg.com/tone@latest/build/Tone.js"></script>
144
- <style>
145
- * {{
146
- box-sizing: border-box;
147
- margin: 0;
148
- padding: 0;
149
- }}
150
-
151
- body {{
152
- font-family: 'Courier New', Arial, sans-serif;
153
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
154
- color: white;
155
- min-height: 100vh;
156
- display: flex;
157
- flex-direction: column;
158
- align-items: center;
159
- justify-content: center;
160
- padding: 20px;
161
- }}
162
-
163
- .container {{
164
- background: rgba(0, 0, 0, 0.3);
165
- backdrop-filter: blur(10px);
166
- border-radius: 15px;
167
- padding: 30px;
168
- max-width: 600px;
169
- width: 100%;
170
- text-align: center;
171
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
172
- }}
173
-
174
- h1 {{
175
- margin-bottom: 20px;
176
- font-size: 2.5em;
177
- text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
178
- }}
179
-
180
- .code-display {{
181
- background: rgba(0, 0, 0, 0.6);
182
- padding: 20px;
183
- border-radius: 10px;
184
- margin: 20px 0;
185
- font-family: 'Courier New', monospace;
186
- font-size: 16px;
187
- border-left: 4px solid #4CAF50;
188
- word-break: break-all;
189
- text-align: left;
190
- }}
191
-
192
- .controls {{
193
- margin: 30px 0;
194
- display: flex;
195
- gap: 15px;
196
- justify-content: center;
197
- flex-wrap: wrap;
198
- }}
199
-
200
- button {{
201
- padding: 12px 24px;
202
- font-size: 16px;
203
- font-weight: bold;
204
- background: linear-gradient(45deg, #4CAF50, #45a049);
205
- color: white;
206
- border: none;
207
- border-radius: 25px;
208
- cursor: pointer;
209
- transition: all 0.3s ease;
210
- box-shadow: 0 4px 15px rgba(76, 175, 80, 0.3);
211
- min-width: 100px;
212
- }}
213
-
214
- button:hover:not(:disabled) {{
215
- transform: translateY(-2px);
216
- box-shadow: 0 6px 20px rgba(76, 175, 80, 0.4);
217
- }}
218
-
219
- button:disabled {{
220
- background: #666;
221
- cursor: not-allowed;
222
- transform: none;
223
- box-shadow: none;
224
- }}
225
-
226
- .status {{
227
- font-size: 18px;
228
- font-weight: bold;
229
- margin: 20px 0;
230
- padding: 10px;
231
- border-radius: 5px;
232
- transition: all 0.3s ease;
233
- }}
234
-
235
- .playing {{
236
- background: rgba(76, 175, 80, 0.2);
237
- color: #4CAF50;
238
- }}
239
-
240
- .stopped {{
241
- background: rgba(244, 67, 54, 0.2);
242
- color: #f44336;
243
- }}
244
-
245
- .info {{
246
- margin-top: 20px;
247
- font-size: 14px;
248
- opacity: 0.8;
249
- line-height: 1.5;
250
- }}
251
-
252
- .error {{
253
- background: rgba(244, 67, 54, 0.2);
254
- color: #f44336;
255
- padding: 10px;
256
- border-radius: 5px;
257
- margin: 10px 0;
258
- }}
259
- </style>
260
- </head>
261
- <body>
262
- <div class="container">
263
- <h1>🎵 Strudel Player</h1>
264
-
265
- <div class="code-display">
266
- <strong>Generated Pattern:</strong><br>
267
- <code id="codeDisplay">{strudel_code}</code>
268
- </div>
269
-
270
- <div class="controls">
271
- <button id="playBtn" onclick="playMusic()">▶️ Play</button>
272
- <button id="pauseBtn" onclick="pauseMusic()" disabled>⏸️ Pause</button>
273
- <button id="stopBtn" onclick="stopMusic()" disabled>⏹️ Stop</button>
274
- </div>
275
-
276
- <div id="status" class="status stopped">Click Play to start audio</div>
277
-
278
- <div class="info">
279
- <p>🎧 Use headphones for best experience</p>
280
- <p>⚡ Powered by Web Audio API & Tone.js</p>
281
- </div>
282
- </div>
283
 
284
- <script>
285
- // Simple audio player using Tone.js as fallback
286
- let isPlaying = false;
287
- let audioContext = null;
288
- let currentPattern = null;
289
-
290
- // Initialize audio context on first user interaction
291
- async function initAudio() {{
292
- try {{
293
- if (!audioContext) {{
294
- await Tone.start();
295
- audioContext = Tone.getContext();
296
- updateStatus('Audio initialized - Ready to play', 'stopped');
297
- }}
298
- return true;
299
- }} catch (error) {{
300
- console.error('Audio initialization failed:', error);
301
- updateStatus('Audio initialization failed: ' + error.message, 'error');
302
- return false;
303
- }}
304
- }}
305
-
306
- // Simple pattern interpreter (basic Strudel-inspired)
307
- function interpretPattern(code) {{
308
- try {{
309
- // Very basic pattern parsing - in a real implementation you'd want full Strudel
310
- const synth = new Tone.Synth().toDestination();
311
- const player = new Tone.Player().toDestination();
312
-
313
- // Simple note pattern recognition
314
- const noteMatch = code.match(/note\\(["']([^"']+)["']\\)/);
315
- if (noteMatch) {{
316
- const notes = noteMatch[1].split(' ');
317
- let time = 0;
318
- const interval = 0.5; // Default timing
319
-
320
- // Schedule notes
321
- notes.forEach((note, index) => {{
322
- if (note.trim()) {{
323
- Tone.Transport.schedule((time) => {{
324
- synth.triggerAttackRelease(note + '4', '8n', time);
325
- }}, time);
326
- time += interval;
327
- }}
328
- }});
329
-
330
- return {{ duration: time, type: 'notes' }};
331
- }}
332
-
333
- // Simple drum pattern recognition
334
- const drumMatch = code.match(/s\\(["']([^"']+)["']\\)/);
335
- if (drumMatch) {{
336
- // Simulate basic drum sounds with synth
337
- const kicks = drumMatch[1].split(' ');
338
- let time = 0;
339
- const interval = 0.25;
340
-
341
- kicks.forEach((drum, index) => {{
342
- if (drum.includes('bd')) {{
343
- Tone.Transport.schedule((time) => {{
344
- synth.triggerAttackRelease('C2', '8n', time);
345
- }}, time);
346
- }} else if (drum.includes('sn')) {{
347
- Tone.Transport.schedule((time) => {{
348
- synth.triggerAttackRelease('E4', '16n', time);
349
- }}, time);
350
- }} else if (drum.includes('hh')) {{
351
- Tone.Transport.schedule((time) => {{
352
- synth.triggerAttackRelease('A5', '32n', time);
353
- }}, time);
354
- }}
355
- time += interval;
356
- }});
357
-
358
- return {{ duration: time, type: 'drums' }};
359
- }}
360
-
361
- // Fallback - play a simple melody
362
- const melody = ['C4', 'D4', 'E4', 'F4'];
363
- melody.forEach((note, index) => {{
364
- Tone.Transport.schedule((time) => {{
365
- synth.triggerAttackRelease(note, '4n', time);
366
- }}, index * 0.5);
367
- }});
368
-
369
- return {{ duration: 2, type: 'fallback' }};
370
-
371
- }} catch (error) {{
372
- console.error('Pattern interpretation error:', error);
373
- updateStatus('Pattern error: ' + error.message, 'error');
374
- return null;
375
- }}
376
- }}
377
-
378
- async function playMusic() {{
379
- try {{
380
- const audioReady = await initAudio();
381
- if (!audioReady) return;
382
-
383
- if (isPlaying) return;
384
-
385
- updateStatus('🎵 Playing pattern...', 'playing');
386
-
387
- const code = document.getElementById('codeDisplay').textContent;
388
- currentPattern = interpretPattern(code);
389
-
390
- if (currentPattern) {{
391
- Tone.Transport.start();
392
- isPlaying = true;
393
- updateControls();
394
-
395
- // Auto-stop after pattern duration
396
- setTimeout(() => {{
397
- if (isPlaying) {{
398
- stopMusic();
399
- }}
400
- }}, (currentPattern.duration + 1) * 1000);
401
- }} else {{
402
- updateStatus('Failed to parse pattern', 'error');
403
- }}
404
-
405
- }} catch (error) {{
406
- console.error('Playback error:', error);
407
- updateStatus('Playback error: ' + error.message, 'error');
408
- }}
409
- }}
410
-
411
- function pauseMusic() {{
412
- if (isPlaying) {{
413
- Tone.Transport.pause();
414
- isPlaying = false;
415
- updateStatus('⏸️ Paused', 'stopped');
416
- updateControls();
417
- }}
418
- }}
419
-
420
- function stopMusic() {{
421
- Tone.Transport.stop();
422
- Tone.Transport.cancel();
423
- isPlaying = false;
424
- currentPattern = null;
425
- updateStatus('⏹️ Stopped', 'stopped');
426
- updateControls();
427
- }}
428
-
429
- function updateControls() {{
430
- document.getElementById('playBtn').disabled = isPlaying;
431
- document.getElementById('pauseBtn').disabled = !isPlaying;
432
- document.getElementById('stopBtn').disabled = !isPlaying;
433
- }}
434
-
435
- function updateStatus(message, type) {{
436
- const status = document.getElementById('status');
437
- status.textContent = message;
438
- status.className = `status ${{type}}`;
439
- }}
440
-
441
- // Cleanup on page unload
442
- window.addEventListener('beforeunload', () => {{
443
- if (isPlaying) {{
444
- stopMusic();
445
- }}
446
- }});
447
-
448
- // Handle visibility changes
449
- document.addEventListener('visibilitychange', () => {{
450
- if (document.hidden && isPlaying) {{
451
- pauseMusic();
452
- }}
453
- }});
454
-
455
- console.log('Strudel player initialized');
456
- </script>
457
- </body>
458
- </html>"""
459
 
460
- def generate_and_play(music_style: str, api_token: Optional[str] = None):
461
- """Generate Strudel code and return playable HTML"""
462
- if not music_style.strip():
463
- return "❌ Please enter a music style description.", "<p>Enter a music style to generate audio</p>"
464
 
465
  try:
466
- # Generate the Strudel code
467
- strudel_code = generate_strudel_code(music_style, api_token)
 
 
 
 
 
 
 
 
 
 
 
 
 
468
 
469
- # Create HTML file
470
- html_content = create_strudel_html(strudel_code)
471
 
472
- # Save to temporary file for Gradio
473
- with tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False) as f:
474
- f.write(html_content)
475
- html_file_path = f.name
476
 
477
- success_msg = f"✅ Generated Strudel pattern: `{strudel_code}`\n\n🎵 Click Play in the player below to hear your music!"
 
478
 
479
- return success_msg, html_content
480
 
481
  except Exception as e:
482
- error_msg = f"Error generating music: {str(e)}"
483
- return error_msg, "<p>Error generating audio player</p>"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
484
 
485
- def create_interface():
486
- """Create the Gradio interface"""
487
 
488
- # Custom CSS for better appearance
489
- custom_css = """
490
- .gradio-container {
491
- max-width: 900px !important;
492
- margin: auto !important;
493
- }
 
 
 
494
 
495
- .main-header {
496
- text-align: center;
497
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
498
- -webkit-background-clip: text;
499
- -webkit-text-fill-color: transparent;
500
- font-size: 2.5em;
501
- font-weight: bold;
502
- margin-bottom: 20px;
503
- }
504
 
505
- .examples-section {
506
- background: #f8f9fa;
507
- border-radius: 10px;
508
- padding: 15px;
509
- margin: 10px 0;
510
- }
511
- """
512
 
513
- with gr.Blocks(
514
- title="🎵 Strudel Music Generator",
515
- theme=gr.themes.Soft(primary_hue="blue", secondary_hue="purple"),
516
- css=custom_css
517
- ) as demo:
518
-
519
- gr.HTML("""
520
- <div class="main-header">
521
- 🎵 Strudel Music Generator
522
- </div>
523
- """)
524
-
525
- gr.Markdown("""
526
- Generate algorithmic music patterns using [Strudel.cc](https://strudel.cc/) syntax!
527
-
528
- **How to use:**
529
- 1. 🎼 Describe your desired music style
530
- 2. 🔑 (Optional) Add your Hugging Face API token for AI-generated patterns
531
- 3. 🎵 Click "Generate Music" to create your pattern
532
- 4. ▶️ Use the audio player controls to play your music
533
- """)
534
-
535
- with gr.Row():
536
- with gr.Column(scale=2):
537
- music_input = gr.Textbox(
538
- label="🎼 Music Style Description",
539
- placeholder="Try: 'jazz piano', 'techno beats', 'ambient soundscape', 'funky bass'...",
540
- lines=2,
541
- max_lines=3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
542
  )
543
 
544
- api_token_input = gr.Textbox(
545
- label="🔑 Hugging Face API Token (Optional)",
546
- placeholder="hf_... (for AI-generated patterns)",
547
- type="password",
548
- info="Get your free token at https://huggingface.co/settings/tokens"
 
 
 
 
 
 
 
 
 
 
 
 
 
549
  )
550
 
551
- generate_btn = gr.Button(
552
- "🎵 Generate Music",
553
- variant="primary",
554
- size="lg"
 
 
555
  )
556
 
557
- with gr.Column(scale=1):
558
- gr.Markdown("""
559
- <div class="examples-section">
560
-
561
- ### 🎨 Style Examples:
562
- - **Jazz**: swing, bebop, smooth
563
- - **Electronic**: techno, house, ambient
564
- - **Classical**: piano, strings, orchestral
565
- - **Urban**: hip hop, reggae, funk
566
- - **Rock**: blues, metal, indie
567
- - **Experimental**: minimal, drone, glitch
568
-
569
- </div>
570
- """)
571
 
572
- with gr.Row():
573
- code_output = gr.Textbox(
574
- label="📝 Generated Code & Status",
575
- interactive=False,
576
- lines=4,
577
- show_copy_button=True
578
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
579
 
580
- with gr.Row():
581
- audio_player = gr.HTML(
582
- label="🎵 Interactive Audio Player",
583
- value="<div style='text-align: center; padding: 40px; background: #f0f0f0; border-radius: 10px;'><h3>🎼 Generate music to see the player</h3><p>Your interactive audio player will appear here</p></div>",
584
- elem_id="audio-player"
585
  )
586
-
587
- # Event handlers
588
- generate_btn.click(
589
- fn=generate_and_play,
590
- inputs=[music_input, api_token_input],
591
- outputs=[code_output, audio_player],
592
- show_progress=True
593
- )
594
-
595
- # Enter key support
596
- music_input.submit(
597
- fn=generate_and_play,
598
- inputs=[music_input, api_token_input],
599
- outputs=[code_output, audio_player]
600
- )
601
-
602
- # Example interactions
603
- gr.Examples(
604
- examples=[
605
- ["jazz piano with swing rhythm"],
606
- ["minimal techno beat"],
607
- ["ambient electronic soundscape"],
608
- ["funky bass line groove"],
609
- ["classical piano arpeggios"],
610
- ["drum and bass breakbeat"],
611
- ["reggae dub rhythm"],
612
- ["experimental glitch sounds"]
613
- ],
614
- inputs=[music_input],
615
- label="🎯 Quick Start Examples"
616
- )
617
-
618
- gr.Markdown("""
619
- ---
620
-
621
- ### 🎓 About Strudel
622
-
623
- **Strudel** is a live coding language for algorithmic music composition. This app generates Strudel patterns and plays them using Web Audio API.
624
-
625
- **Key Functions:**
626
- - `note("c d e f")` - Play musical notes
627
- - `s("bd hh sn")` - Play drum samples (bd=bass drum, hh=hi-hat, sn=snare)
628
- - `sound("piano")` - Use instrument sounds
629
- - `.slow(2)` / `.fast(2)` - Change tempo
630
- - `.stack()` - Layer multiple patterns
631
- - `.lpf(800)` - Low-pass filter
632
- - `.gain(0.5)` - Volume control
633
-
634
- **🔧 Technical Notes:**
635
- - Audio runs entirely in your browser
636
- - No audio files needed - everything is synthesized
637
- - Works best with modern browsers and headphones
638
- - Patterns are simplified for web compatibility
639
-
640
- **🚀 Want full Strudel?** Visit [strudel.cc](https://strudel.cc/) for the complete live coding environment!
641
- """)
642
 
643
- return demo
 
 
 
 
 
 
 
 
 
 
 
 
644
 
645
- # Launch configuration
646
  if __name__ == "__main__":
647
- demo = create_interface()
648
- demo.launch(
649
  server_name="0.0.0.0",
650
  server_port=7860,
651
- share=False,
652
- show_error=True
653
  )
 
1
  import gradio as gr
2
  import requests
3
  import json
4
+ from transformers import AutoTokenizer, AutoModelForCausalLM
5
+ import torch
 
 
6
 
7
+ # Initialize StarCoder model and tokenizer
8
+ MODEL_NAME = "bigcode/starcoder"
9
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
10
+ model = AutoModelForCausalLM.from_pretrained(
11
+ MODEL_NAME,
12
+ torch_dtype=torch.float16,
13
+ device_map="auto",
14
+ trust_remote_code=True
15
+ )
16
 
17
+ # Strudel code examples for few-shot prompting
18
+ STRUDEL_EXAMPLES = """
19
+ // Basic drum pattern
20
+ s("bd hh sn hh").gain(0.8)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
+ // Melodic pattern
23
+ n("0 2 4 7").s("sine").octave(4).lpf(2000)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
+ // Techno beat
26
+ stack(
27
+ s("bd*4").gain(0.8),
28
+ s("~ hh ~ hh").gain(0.6),
29
+ n("0 ~ 3 ~").s("sawtooth").octave(2).lpf(800)
30
+ )
31
+
32
+ // Ambient pattern
33
+ n("[0 2 4]/3").s("sine").octave(3).slow(4).room(0.9).gain(0.5)
34
+ """
35
+
36
+ def generate_strudel_code(prompt, genre="general", complexity="simple", max_length=200, temperature=0.7):
37
+ """Generate Strudel code using StarCoder"""
38
+
39
+ # Build context-aware prompt
40
+ system_prompt = f"""// Strudel is a live coding language for music
41
+ // Generate {complexity} {genre} music code using Strudel syntax
42
+ // Examples:
43
+ {STRUDEL_EXAMPLES}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
+ // User request: {prompt}
46
+ // Generated Strudel code:
47
+ """
 
48
 
49
  try:
50
+ # Tokenize input
51
+ inputs = tokenizer.encode(system_prompt, return_tensors="pt")
52
+
53
+ # Generate code
54
+ with torch.no_grad():
55
+ outputs = model.generate(
56
+ inputs,
57
+ max_length=len(inputs[0]) + max_length,
58
+ temperature=temperature,
59
+ do_sample=True,
60
+ top_p=0.95,
61
+ pad_token_id=tokenizer.eos_token_id,
62
+ stop_strings=["//", "\n\n"],
63
+ num_return_sequences=1
64
+ )
65
 
66
+ # Decode output
67
+ generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
68
 
69
+ # Extract only the generated part
70
+ strudel_code = generated_text[len(system_prompt):].strip()
 
 
71
 
72
+ # Clean up the code
73
+ strudel_code = clean_strudel_code(strudel_code)
74
 
75
+ return strudel_code
76
 
77
  except Exception as e:
78
+ return f"Error generating code: {str(e)}"
79
+
80
+ def clean_strudel_code(code):
81
+ """Clean and format generated Strudel code"""
82
+ lines = code.split('\n')
83
+ cleaned_lines = []
84
+
85
+ for line in lines:
86
+ line = line.strip()
87
+ # Stop at common completion indicators
88
+ if line.startswith('//') and any(word in line.lower() for word in ['user', 'request', 'example']):
89
+ break
90
+ if line and not line.startswith('//'):
91
+ cleaned_lines.append(line)
92
+
93
+ return '\n'.join(cleaned_lines[:10]) # Limit to 10 lines
94
 
95
+ def create_full_strudel_template(generated_code, include_visuals=True):
96
+ """Wrap generated code in a complete Strudel template"""
97
 
98
+ visual_code = """
99
+ // Hydra visuals
100
+ await initHydra({feedStrudel:5})
101
+
102
+ osc(10, 0.1, 0.8)
103
+ .kaleid(4)
104
+ .color(1.5, 0.8, 1.2)
105
+ .out()
106
+ """ if include_visuals else ""
107
 
108
+ template = f"""{visual_code}
109
+ // Generated Strudel Music Code
110
+ {generated_code}
111
+
112
+ // Global effects
113
+ all(x => x.fft(5).scope())
114
+ """
 
 
115
 
116
+ return template
117
+
118
+ # Gradio interface
119
+ def generate_interface(prompt, genre, complexity, include_visuals, max_length, temperature):
120
+ """Main interface function"""
 
 
121
 
122
+ if not prompt.strip():
123
+ return "Please enter a description of the music you want to create."
124
+
125
+ # Generate the core Strudel code
126
+ generated_code = generate_strudel_code(
127
+ prompt=prompt,
128
+ genre=genre,
129
+ complexity=complexity,
130
+ max_length=max_length,
131
+ temperature=temperature
132
+ )
133
+
134
+ # Create full template
135
+ full_code = create_full_strudel_template(generated_code, include_visuals)
136
+
137
+ return full_code
138
+
139
+ # Create Gradio app
140
+ with gr.Blocks(title="Strudel Code Generator", theme=gr.themes.Monochrome()) as app:
141
+ gr.Markdown("""
142
+ # 🎵 Strudel Code Generator
143
+
144
+ Generate live coding music patterns using AI! Powered by StarCoder.
145
+
146
+ **How to use:**
147
+ 1. Describe the music you want (e.g., "techno beat with bass", "ambient soundscape", "jazz drums")
148
+ 2. Choose genre and complexity
149
+ 3. Click Generate
150
+ 4. Copy the code to [strudel.cc](https://strudel.cc) to hear it!
151
+ """)
152
+
153
+ with gr.Row():
154
+ with gr.Column():
155
+ prompt_input = gr.Textbox(
156
+ label="Describe your music",
157
+ placeholder="e.g., 'Create a techno beat with kick drum and hi-hats'",
158
+ lines=3
159
+ )
160
+
161
+ with gr.Row():
162
+ genre_dropdown = gr.Dropdown(
163
+ choices=["general", "techno", "house", "ambient", "jazz", "rock", "experimental"],
164
+ value="general",
165
+ label="Genre"
166
  )
167
 
168
+ complexity_dropdown = gr.Dropdown(
169
+ choices=["simple", "moderate", "complex"],
170
+ value="simple",
171
+ label="Complexity"
172
+ )
173
+
174
+ include_visuals = gr.Checkbox(
175
+ label="Include Hydra visuals",
176
+ value=True
177
+ )
178
+
179
+ with gr.Accordion("Advanced Settings", open=False):
180
+ max_length_slider = gr.Slider(
181
+ minimum=50,
182
+ maximum=500,
183
+ value=200,
184
+ step=50,
185
+ label="Max code length"
186
  )
187
 
188
+ temperature_slider = gr.Slider(
189
+ minimum=0.1,
190
+ maximum=1.0,
191
+ value=0.7,
192
+ step=0.1,
193
+ label="Creativity (temperature)"
194
  )
195
 
196
+ generate_btn = gr.Button("🎵 Generate Strudel Code", variant="primary")
 
 
 
 
 
 
 
 
 
 
 
 
 
197
 
198
+ with gr.Column():
199
+ output_code = gr.Code(
200
+ label="Generated Strudel Code",
201
+ language="javascript",
202
+ lines=20
 
203
  )
204
+
205
+ gr.Markdown("""
206
+ **Next steps:**
207
+ 1. Copy the generated code
208
+ 2. Go to [strudel.cc](https://strudel.cc)
209
+ 3. Paste and run the code
210
+ 4. Enjoy your AI-generated music! 🎶
211
+ """)
212
+
213
+ # Example buttons
214
+ gr.Markdown("### Quick Examples")
215
+ with gr.Row():
216
+ examples = [
217
+ ["Create a minimal techno beat with kick and hi-hats", "techno", "simple"],
218
+ ["Ambient soundscape with reverb and slow patterns", "ambient", "moderate"],
219
+ ["Jazz-inspired drum pattern with syncopation", "jazz", "moderate"],
220
+ ["Experimental glitchy electronic music", "experimental", "complex"],
221
+ ]
222
 
223
+ for example_text, example_genre, example_complexity in examples:
224
+ btn = gr.Button(f"💡 {example_text[:30]}...")
225
+ btn.click(
226
+ lambda t=example_text, g=example_genre, c=example_complexity: (t, g, c),
227
+ outputs=[prompt_input, genre_dropdown, complexity_dropdown]
228
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
 
230
+ # Connect the generate button
231
+ generate_btn.click(
232
+ generate_interface,
233
+ inputs=[
234
+ prompt_input,
235
+ genre_dropdown,
236
+ complexity_dropdown,
237
+ include_visuals,
238
+ max_length_slider,
239
+ temperature_slider
240
+ ],
241
+ outputs=output_code
242
+ )
243
 
244
+ # Launch the app
245
  if __name__ == "__main__":
246
+ app.launch(
 
247
  server_name="0.0.0.0",
248
  server_port=7860,
249
+ share=True
 
250
  )