Fathima-Firose commited on
Commit
2be2a6d
·
verified ·
1 Parent(s): bf77d5e

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +47 -0
  2. index.html +454 -0
  3. requirements.txt +5 -0
app.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify, send_from_directory
2
+ from transformers import pipeline
3
+ import torch
4
+ import scipy.io.wavfile
5
+ import numpy as np
6
+ import os
7
+
8
+ app = Flask(__name__, static_folder='static')
9
+
10
+ device = "cuda:0" if torch.cuda.is_available() else "cpu"
11
+ pipe = pipeline("text-to-audio", "meta-llama/musicgen-small", device=device)
12
+
13
+ if not os.path.exists('static/music'):
14
+ os.makedirs('static/music')
15
+
16
+ @app.route('/')
17
+ def index():
18
+ return send_from_directory('.', 'index.html')
19
+
20
+ @app.route('/generate-music', methods=['POST'])
21
+ def generate_music():
22
+ try:
23
+ data = request.json
24
+ prompt = data.get('prompt')
25
+ duration = data.get('duration', 15)
26
+
27
+ if not prompt:
28
+ return jsonify({'error': 'Prompt is required'}), 400
29
+
30
+ max_new_tokens = int(duration * 50)
31
+ music = pipe(prompt, forward_params={"max_new_tokens": max_new_tokens})
32
+
33
+ sampling_rate = music["sampling_rate"]
34
+ audio_numpy = music["audio"][0].T
35
+ output_filename = f"music_{hash(prompt)}.wav"
36
+ output_path = os.path.join('static/music', output_filename)
37
+ audio_int16 = np.int16(audio_numpy * 32767)
38
+ scipy.io.wavfile.write(output_path, rate=sampling_rate, data=audio_int16)
39
+
40
+ file_url = f"/static/music/{output_filename}"
41
+ return jsonify({'url': file_url})
42
+ except Exception as e:
43
+ print(f"An error occurred: {e}")
44
+ return jsonify({'error': 'Failed to generate music'}), 500
45
+
46
+ if __name__ == '__main__':
47
+ app.run(debug=True)
index.html ADDED
@@ -0,0 +1,454 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Neon MusicGen AI</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com">
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&family=Orbitron:wght@500;700&display=swap" rel="stylesheet">
10
+ <style>
11
+ :root {
12
+ --primary-purple: #9b5cff;
13
+ --secondary-purple: #7a2aff;
14
+ --dark-bg-1: #0f0b14;
15
+ --dark-bg-2: #120919;
16
+ --text-light: #f0f0f0;
17
+ --text-medium: #c0c0c0;
18
+ --glow-color: rgba(155, 92, 255, 0.8);
19
+ --border-color: rgba(155, 92, 255, 0.3);
20
+ }
21
+
22
+ *, *::before, *::after {
23
+ box-sizing: border-box;
24
+ margin: 0;
25
+ padding: 0;
26
+ }
27
+
28
+ body {
29
+ font-family: 'Inter', sans-serif;
30
+ color: var(--text-light);
31
+ background: linear-gradient(135deg, var(--dark-bg-1), var(--dark-bg-2));
32
+ min-height: 100vh;
33
+ display: flex;
34
+ flex-direction: column;
35
+ align-items: center;
36
+ padding: 2rem 1rem;
37
+ overflow-x: hidden;
38
+ position: relative;
39
+ }
40
+
41
+ /* Animated Particle Background */
42
+ .particles {
43
+ position: fixed;
44
+ top: 0;
45
+ left: 0;
46
+ width: 100%;
47
+ height: 100%;
48
+ background-image:
49
+ radial-gradient(circle at 20% 20%, rgba(122, 42, 255, 0.1) 0%, transparent 30%),
50
+ radial-gradient(circle at 80% 70%, rgba(155, 92, 255, 0.15) 0%, transparent 40%),
51
+ radial-gradient(circle at 50% 90%, rgba(122, 42, 255, 0.05) 0%, transparent 20%);
52
+ animation: moveParticles 20s linear infinite;
53
+ z-index: -1;
54
+ }
55
+
56
+ @keyframes moveParticles {
57
+ 0% { transform: translate(0, 0); }
58
+ 50% { transform: translate(10px, 15px); }
59
+ 100% { transform: translate(0, 0); }
60
+ }
61
+
62
+ .container {
63
+ width: 100%;
64
+ max-width: 600px;
65
+ text-align: center;
66
+ z-index: 1;
67
+ }
68
+
69
+ /* Header */
70
+ header {
71
+ display: flex;
72
+ align-items: center;
73
+ justify-content: center;
74
+ gap: 1rem;
75
+ margin-bottom: 2rem;
76
+ animation: fadeIn 1s ease-out;
77
+ }
78
+
79
+ .logo {
80
+ font-size: 2.5rem;
81
+ color: var(--primary-purple);
82
+ text-shadow: 0 0 10px var(--glow-color), 0 0 20px var(--glow-color);
83
+ }
84
+
85
+ header h1 {
86
+ font-family: 'Orbitron', sans-serif;
87
+ font-size: 2rem;
88
+ font-weight: 700;
89
+ letter-spacing: 1px;
90
+ }
91
+
92
+ /* Hero Section */
93
+ .hero {
94
+ margin-bottom: 2.5rem;
95
+ animation: fadeIn 1.2s ease-out;
96
+ }
97
+
98
+ .hero h2 {
99
+ font-size: 1.5rem;
100
+ font-weight: 500;
101
+ color: var(--text-medium);
102
+ text-shadow: 0 0 5px rgba(0,0,0,0.5);
103
+ }
104
+
105
+ /* Main Generator Card */
106
+ .generator-card {
107
+ background: rgba(20, 15, 30, 0.5);
108
+ border: 1px solid var(--border-color);
109
+ border-radius: 16px;
110
+ padding: 2rem;
111
+ backdrop-filter: blur(10px);
112
+ -webkit-backdrop-filter: blur(10px);
113
+ box-shadow: 0 0 40px rgba(122, 42, 255, 0.2);
114
+ display: flex;
115
+ flex-direction: column;
116
+ gap: 1.5rem;
117
+ animation: slideUpFadeIn 1s ease-out forwards;
118
+ opacity: 0;
119
+ transform: translateY(30px);
120
+ }
121
+
122
+ @keyframes slideUpFadeIn {
123
+ to {
124
+ opacity: 1;
125
+ transform: translateY(0);
126
+ }
127
+ }
128
+
129
+ .input-group {
130
+ text-align: left;
131
+ }
132
+
133
+ .input-group label {
134
+ display: block;
135
+ margin-bottom: 0.5rem;
136
+ font-weight: 500;
137
+ color: var(--text-medium);
138
+ }
139
+
140
+ textarea, select {
141
+ width: 100%;
142
+ background: rgba(0, 0, 0, 0.3);
143
+ border: 1px solid var(--border-color);
144
+ border-radius: 8px;
145
+ padding: 0.75rem;
146
+ font-family: 'Inter', sans-serif;
147
+ font-size: 1rem;
148
+ color: var(--text-light);
149
+ transition: border-color 0.3s ease, box-shadow 0.3s ease;
150
+ }
151
+
152
+ textarea:focus, select:focus {
153
+ outline: none;
154
+ border-color: var(--primary-purple);
155
+ box-shadow: 0 0 15px var(--glow-color);
156
+ }
157
+
158
+ textarea {
159
+ resize: vertical;
160
+ min-height: 100px;
161
+ }
162
+
163
+ .settings-row {
164
+ display: flex;
165
+ gap: 1.5rem;
166
+ justify-content: space-between;
167
+ }
168
+
169
+ .settings-row .input-group {
170
+ flex: 1;
171
+ }
172
+
173
+ /* Generate Button */
174
+ .generate-btn {
175
+ background: linear-gradient(90deg, var(--primary-purple), var(--secondary-purple));
176
+ color: white;
177
+ font-family: 'Orbitron', sans-serif;
178
+ font-size: 1.1rem;
179
+ font-weight: 700;
180
+ border: none;
181
+ border-radius: 8px;
182
+ padding: 0.8rem 1.5rem;
183
+ cursor: pointer;
184
+ transition: transform 0.2s ease, box-shadow 0.3s ease;
185
+ position: relative;
186
+ overflow: hidden;
187
+ box-shadow: 0 0 20px var(--glow-color);
188
+ animation: pulseGlow 2.5s infinite ease-in-out;
189
+ }
190
+
191
+ @keyframes pulseGlow {
192
+ 0%, 100% { box-shadow: 0 0 20px var(--glow-color); }
193
+ 50% { box-shadow: 0 0 35px var(--glow-color); }
194
+ }
195
+
196
+ .generate-btn:hover {
197
+ transform: translateY(-3px);
198
+ box-shadow: 0 0 40px var(--glow-color);
199
+ }
200
+
201
+ /* Output Section */
202
+ .output-section {
203
+ margin-top: 2.5rem;
204
+ width: 100%;
205
+ display: flex;
206
+ flex-direction: column;
207
+ align-items: center;
208
+ gap: 1.5rem;
209
+ min-height: 120px; /* Reserve space */
210
+ animation: fadeIn 1.5s ease-out;
211
+ }
212
+
213
+ .loading-animation {
214
+ display: flex;
215
+ gap: 6px;
216
+ height: 40px;
217
+ align-items: flex-end;
218
+ }
219
+
220
+ .loading-animation .bar {
221
+ width: 8px;
222
+ background-color: var(--primary-purple);
223
+ border-radius: 4px;
224
+ animation: equalizer 1.2s infinite ease-in-out;
225
+ box-shadow: 0 0 10px var(--glow-color);
226
+ }
227
+
228
+ .loading-animation .bar:nth-child(2) { animation-delay: 0.2s; }
229
+ .loading-animation .bar:nth-child(3) { animation-delay: 0.4s; }
230
+ .loading-animation .bar:nth-child(4) { animation-delay: 0.6s; }
231
+ .loading-animation .bar:nth-child(5) { animation-delay: 0.8s; }
232
+
233
+ @keyframes equalizer {
234
+ 0%, 100% { height: 5px; }
235
+ 50% { height: 40px; }
236
+ }
237
+
238
+ .audio-player {
239
+ display: none; /* Hidden by default */
240
+ width: 100%;
241
+ }
242
+
243
+ audio {
244
+ width: 100%;
245
+ border-radius: 8px;
246
+ }
247
+
248
+ /* Customizing audio player controls */
249
+ audio::-webkit-media-controls-panel {
250
+ background-color: rgba(20, 15, 30, 0.7);
251
+ border: 1px solid var(--border-color);
252
+ border-radius: 8px;
253
+ }
254
+ audio::-webkit-media-controls-play-button,
255
+ audio::-webkit-media-controls-mute-button {
256
+ background-color: var(--primary-purple);
257
+ border-radius: 50%;
258
+ }
259
+ audio::-webkit-media-controls-current-time-display,
260
+ audio::-webkit-media-controls-time-remaining-display {
261
+ color: var(--text-light);
262
+ }
263
+
264
+ /* Download Button */
265
+ .download-btn {
266
+ background: transparent;
267
+ color: var(--primary-purple);
268
+ border: 2px solid var(--primary-purple);
269
+ border-radius: 8px;
270
+ padding: 0.7rem 1.5rem;
271
+ font-family: 'Orbitron', sans-serif;
272
+ font-weight: 500;
273
+ cursor: pointer;
274
+ position: relative;
275
+ overflow: hidden;
276
+ transition: color 0.3s ease, background-color 0.3s ease, box-shadow 0.3s ease;
277
+ display: none; /* Hidden by default */
278
+ }
279
+
280
+ .download-btn:hover {
281
+ color: white;
282
+ background-color: var(--primary-purple);
283
+ box-shadow: 0 0 20px var(--glow-color);
284
+ }
285
+
286
+ .download-btn::before {
287
+ content: '';
288
+ position: absolute;
289
+ top: 0;
290
+ left: -100%;
291
+ width: 100%;
292
+ height: 100%;
293
+ background: linear-gradient(120deg, transparent, rgba(255, 255, 255, 0.3), transparent);
294
+ transition: left 0.5s ease;
295
+ }
296
+
297
+ .download-btn:hover::before {
298
+ left: 100%;
299
+ }
300
+
301
+ /* Footer */
302
+ footer {
303
+ margin-top: 3rem;
304
+ color: var(--text-medium);
305
+ font-size: 0.9rem;
306
+ opacity: 0.7;
307
+ animation: fadeIn 1.8s ease-out;
308
+ }
309
+
310
+ /* Responsive Design */
311
+ @media (max-width: 640px) {
312
+ body { padding: 1rem; }
313
+ header h1 { font-size: 1.5rem; }
314
+ .logo { font-size: 2rem; }
315
+ .hero h2 { font-size: 1.2rem; }
316
+ .generator-card { padding: 1.5rem; }
317
+ .settings-row { flex-direction: column; gap: 1.5rem; }
318
+ }
319
+
320
+ </style>
321
+ </head>
322
+ <body>
323
+
324
+ <div class="particles"></div>
325
+
326
+ <div class="container">
327
+
328
+ <header>
329
+ <div class="logo">♪</div>
330
+ <h1>MusicGen AI</h1>
331
+ </header>
332
+
333
+ <section class="hero">
334
+ <h2>Transform Your Ideas into Music with AI</h2>
335
+ </section>
336
+
337
+ <main>
338
+ <div class="generator-card">
339
+
340
+ <div class="input-group">
341
+ <label for="prompt">Describe your music idea...</label>
342
+ <textarea id="prompt" name="prompt" rows="4" placeholder="e.g., A futuristic synthwave track with a driving beat, perfect for a midnight drive through a neon city."></textarea>
343
+ </div>
344
+
345
+ <div class="settings-row">
346
+ <div class="input-group">
347
+ <label for="model">Model Size</label>
348
+ <select id="model" name="model">
349
+ <option value="small">Small (Fastest)</option>
350
+ <option value="medium" selected>Medium (Balanced)</option>
351
+ <option value="large">Large (Highest Quality)</option>
352
+ </select>
353
+ </div>
354
+
355
+ <div class="input-group">
356
+ <label for="duration">Duration (seconds)</label>
357
+ <input type="number" id="duration" name="duration" min="2" max="60" value="15" style="width: 100%; padding: 0.75rem; background: rgba(0, 0, 0, 0.3); border: 1px solid var(--border-color); border-radius: 8px; color: var(--text-light); font-size: 1rem;">
358
+ </div>
359
+ </div>
360
+
361
+ <button class="generate-btn" id="generateBtn">Generate</button>
362
+
363
+ </div>
364
+
365
+ <section class="output-section" id="outputSection">
366
+ <div class="loading-animation" id="loading" style="display: none;">
367
+ <div class="bar"></div>
368
+ <div class="bar"></div>
369
+ <div class="bar"></div>
370
+ <div class="bar"></div>
371
+ <div class="bar"></div>
372
+ </div>
373
+
374
+ <div class="audio-player" id="audioPlayerWrapper">
375
+ <audio controls id="audioPlayer" src=""></audio>
376
+ </div>
377
+
378
+ <button class="download-btn" id="downloadBtn">Download Music</button>
379
+ </section>
380
+ </main>
381
+
382
+ <footer>
383
+ <p>Powered by Hugging Face MusicGen & Cloud AI</p>
384
+ </footer>
385
+
386
+ </div>
387
+
388
+ <script>
389
+ const generateBtn = document.getElementById('generateBtn');
390
+ const loading = document.getElementById('loading');
391
+ const audioPlayerWrapper = document.getElementById('audioPlayerWrapper');
392
+ const audioPlayer = document.getElementById('audioPlayer');
393
+ const downloadBtn = document.getElementById('downloadBtn');
394
+ const promptInput = document.getElementById('prompt');
395
+ const durationInput = document.getElementById('duration');
396
+
397
+ generateBtn.addEventListener('click', async () => {
398
+ const promptText = promptInput.value;
399
+ const duration = parseInt(durationInput.value, 10);
400
+
401
+ if (!promptText.trim()) {
402
+ alert('Please enter a music description!');
403
+ return;
404
+ }
405
+
406
+ // 1. Update UI to show loading state
407
+ generateBtn.disabled = true;
408
+ generateBtn.textContent = 'Generating...';
409
+ audioPlayerWrapper.style.display = 'none';
410
+ downloadBtn.style.display = 'none';
411
+ loading.style.display = 'flex';
412
+
413
+ try {
414
+ // 2. Send the request to the back-end
415
+ const response = await fetch('/generate-music', {
416
+ method: 'POST',
417
+ headers: {
418
+ 'Content-Type': 'application/json',
419
+ },
420
+ body: JSON.stringify({
421
+ prompt: promptText,
422
+ duration: duration
423
+ }),
424
+ });
425
+
426
+ if (!response.ok) {
427
+ throw new Error('Failed to generate music. Server returned ' + response.status);
428
+ }
429
+
430
+ const data = await response.json();
431
+
432
+ // 3. Update the audio player with the new file
433
+ audioPlayer.src = data.url;
434
+ downloadBtn.href = data.url; // Set download link
435
+ downloadBtn.setAttribute('download', 'neon-music-gen.wav'); // Set filename
436
+
437
+ // 4. Show the results
438
+ audioPlayerWrapper.style.display = 'block';
439
+ downloadBtn.style.display = 'block';
440
+
441
+ } catch (error) {
442
+ console.error('Error:', error);
443
+ alert('An error occurred. Please check the console for details.');
444
+ } finally {
445
+ // 5. Reset the UI
446
+ loading.style.display = 'none';
447
+ generateBtn.disabled = false;
448
+ generateBtn.textContent = 'Generate';
449
+ }
450
+ });
451
+ </script>
452
+
453
+ </body>
454
+ </html>
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ flask
2
+ transformers>=4.33.0
3
+ torch>=2.0.0
4
+ scipy
5
+ accelerate