flen-crypto commited on
Commit
4fc3bf4
·
verified ·
1 Parent(s): 0905fd0

Upload src/streamlit_app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +751 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,753 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === streamlit_app.py ===
 
 
2
  import streamlit as st
3
+ import time
4
+ import json
5
+ from datetime import datetime
6
+ import random
7
+ from utils import (
8
+ interpret_prompt,
9
+ generate_music_simulation,
10
+ analyze_algorithmic_fit,
11
+ optimize_metadata,
12
+ get_trending_tags,
13
+ create_waveform_data
14
+ )
15
+ from config import GENRES, MOODS, TEMPO_RANGES, DSP_PLATFORMS
16
 
17
+ # Page configuration
18
+ st.set_page_config(
19
+ page_title="Prompt Composer - AI-Aware Music Creation",
20
+ page_icon="🎧",
21
+ layout="wide",
22
+ initial_sidebar_state="expanded"
23
+ )
24
+
25
+ # Custom CSS
26
+ st.markdown("""
27
+ <style>
28
+ .main-header {
29
+ background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
30
+ padding: 2rem;
31
+ border-radius: 10px;
32
+ margin-bottom: 2rem;
33
+ color: white;
34
+ }
35
+ .metric-card {
36
+ background: #f8f9fa;
37
+ padding: 1.5rem;
38
+ border-radius: 10px;
39
+ border-left: 4px solid #667eea;
40
+ margin: 0.5rem 0;
41
+ }
42
+ .success-card {
43
+ background: #d4edda;
44
+ border-left: 4px solid #28a745;
45
+ padding: 1rem;
46
+ border-radius: 5px;
47
+ }
48
+ .warning-card {
49
+ background: #fff3cd;
50
+ border-left: 4px solid #ffc107;
51
+ padding: 1rem;
52
+ border-radius: 5px;
53
+ }
54
+ .gradient-text {
55
+ background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
56
+ -webkit-background-clip: text;
57
+ -webkit-text-fill-color: transparent;
58
+ }
59
+ </style>
60
+ """, unsafe_allow_html=True)
61
+
62
+ # Header
63
+ st.markdown("""
64
+ <div class="main-header">
65
+ <h1>🎧 Prompt Composer</h1>
66
+ <p>AI-Aware Music Creation for Streaming Algorithms</p>
67
+ <p style="font-size: 0.9rem; opacity: 0.9;">
68
+ Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" style="color: white; text-decoration: underline;">anycoder</a>
69
+ </p>
70
+ </div>
71
+ """, unsafe_allow_html=True)
72
+
73
+ # Initialize session state
74
+ if 'generated_track' not in st.session_state:
75
+ st.session_state.generated_track = None
76
+ if 'analysis_complete' not in st.session_state:
77
+ st.session_state.analysis_complete = False
78
+
79
+ # Sidebar
80
+ with st.sidebar:
81
+ st.header("⚙️ Settings")
82
+
83
+ # Target Platform
84
+ target_platform = st.selectbox(
85
+ "Target Platform",
86
+ DSP_PLATFORMS,
87
+ help="Choose which streaming platform to optimize for"
88
+ )
89
+
90
+ # Advanced Options
91
+ st.subheader("Advanced Options")
92
+ auto_optimize = st.checkbox("Auto-optimize for algorithms", value=True)
93
+ include_vocals = st.checkbox("Include vocals", value=True)
94
+ target_duration = st.slider("Target Duration (seconds)", 60, 300, 180)
95
+
96
+ # Trending Tags
97
+ st.subheader("🔥 Trending Tags")
98
+ trending_tags = get_trending_tags()
99
+ selected_trending = st.multiselect(
100
+ "Add trending tags",
101
+ trending_tags,
102
+ help="Include trending tags to boost discoverability"
103
+ )
104
+
105
+ # Main Content
106
+ col1, col2 = st.columns([3, 2])
107
+
108
+ with col1:
109
+ st.header("🎵 Create Your Track")
110
+
111
+ # Prompt Input
112
+ prompt_input = st.text_area(
113
+ "Describe your music prompt:",
114
+ placeholder="e.g., 'Upbeat 115 BPM house track with soulful vocals, optimized for workout playlists'",
115
+ height=100,
116
+ help="Be as specific as possible about genre, mood, tempo, and intended use case"
117
+ )
118
+
119
+ # Quick Templates
120
+ st.subheader("📝 Quick Templates")
121
+ template_cols = st.columns(3)
122
+
123
+ templates = [
124
+ ("Workout Mix", "High-energy 128 BPM EDM track with driving bass, perfect for gym sessions"),
125
+ ("Chill Study", "Ambient lo-fi hip hop at 90 BPM, minimal vocals, focus-enhancing"),
126
+ ("Party Anthem", "Catchy pop-dance 120 BPM with memorable chorus, festival-ready")
127
+ ]
128
+
129
+ for i, (name, template) in enumerate(templates):
130
+ with template_cols[i]:
131
+ if st.button(name, key=f"template_{i}"):
132
+ prompt_input = template
133
+ st.rerun()
134
+
135
+ # Generate Button
136
+ if st.button("🚀 Generate & Analyze Track", type="primary", use_container_width=True):
137
+ if not prompt_input:
138
+ st.error("Please enter a music prompt first!")
139
+ else:
140
+ with st.spinner("🎵 Interpreting prompt..."):
141
+ time.sleep(1)
142
+ interpreted = interpret_prompt(prompt_input)
143
+
144
+ with st.spinner("🎹 Generating music..."):
145
+ time.sleep(2)
146
+ generated = generate_music_simulation(interpreted)
147
+
148
+ with st.spinner("📊 Analyzing algorithmic fit..."):
149
+ time.sleep(1.5)
150
+ analysis = analyze_algorithmic_fit(generated, target_platform)
151
+
152
+ with st.spinner("🏷️ Optimizing metadata..."):
153
+ time.sleep(1)
154
+ metadata = optimize_metadata(generated, analysis, target_platform, selected_trending)
155
+
156
+ # Store in session state
157
+ st.session_state.generated_track = {
158
+ 'prompt': prompt_input,
159
+ 'interpreted': interpreted,
160
+ 'generated': generated,
161
+ 'analysis': analysis,
162
+ 'metadata': metadata,
163
+ 'timestamp': datetime.now().isoformat()
164
+ }
165
+ st.session_state.analysis_complete = True
166
+ st.success("✅ Track generated and analyzed successfully!")
167
+ st.rerun()
168
+
169
+ with col2:
170
+ st.header("📈 Algorithm Insights")
171
+
172
+ if st.session_state.analysis_complete:
173
+ track_data = st.session_state.generated_track
174
+ analysis = track_data['analysis']
175
+
176
+ # Algorithmic Fit Score
177
+ fit_score = analysis['algorithmic_fit_score']
178
+ st.metric(
179
+ "Algorithmic Fit Score",
180
+ f"{fit_score}%",
181
+ delta=f"+{fit_score - 50}%" if fit_score > 50 else f"{fit_score - 50}%",
182
+ delta_color="normal" if fit_score > 70 else "inverse"
183
+ )
184
+
185
+ # Key Metrics
186
+ st.subheader("🎯 Key Metrics")
187
+
188
+ metrics = analysis['key_metrics']
189
+ col_a, col_b = st.columns(2)
190
+
191
+ with col_a:
192
+ st.metric(
193
+ "Skip Resistance",
194
+ f"{metrics['skip_resistance']}%",
195
+ help="Likelihood listeners stay past 30 seconds"
196
+ )
197
+ st.metric(
198
+ "Loudness",
199
+ f"{metrics['loudness']} LUFS",
200
+ help="Target: -14 LUFS for Spotify"
201
+ )
202
+
203
+ with col_b:
204
+ st.metric(
205
+ "Energy Match",
206
+ f"{metrics['energy_match']}%",
207
+ help="How well energy matches genre expectations"
208
+ )
209
+ st.metric(
210
+ "Hook Timing",
211
+ f"{metrics['hook_timing']}s",
212
+ help="Time to first hook (ideal: <30s)"
213
+ )
214
+
215
+ # Platform Recommendations
216
+ st.subheader("🎯 Platform Recommendations")
217
+ for rec in analysis['recommendations']:
218
+ if rec['type'] == 'success':
219
+ st.markdown(f"""
220
+ <div class="success-card">
221
+ ✅ {rec['message']}
222
+ </div>
223
+ """, unsafe_allow_html=True)
224
+ else:
225
+ st.markdown(f"""
226
+ <div class="warning-card">
227
+ ⚠️ {rec['message']}
228
+ </div>
229
+ """, unsafe_allow_html=True)
230
+
231
+ # Results Section
232
+ if st.session_state.analysis_complete:
233
+ st.markdown("---")
234
+ track_data = st.session_state.generated_track
235
+
236
+ # Track Details Tabs
237
+ tab1, tab2, tab3, tab4 = st.tabs(["🎵 Track Preview", "📊 Audio Analysis", "🏷️ Optimized Metadata", "📤 Export Options"])
238
+
239
+ with tab1:
240
+ col1, col2 = st.columns([2, 1])
241
+
242
+ with col1:
243
+ st.subheader("Generated Track")
244
+ # Simulated audio player
245
+ st.markdown("""
246
+ <div style="background: #f0f0f0; padding: 2rem; border-radius: 10px; text-align: center;">
247
+ <h4>🎵 {title}</h4>
248
+ <p>{artist}</p>
249
+ <div style="margin: 1rem 0;">
250
+ <div style="background: #ddd; height: 4px; border-radius: 2px; position: relative;">
251
+ <div style="background: #667eea; height: 100%; width: 0%; border-radius: 2px; animation: pulse 2s infinite;"></div>
252
+ </div>
253
+ </div>
254
+ <p>⏱️ {duration} | 🎵 {genre} | 💫 {mood}</p>
255
+ </div>
256
+ """.format(
257
+ title=track_data['metadata']['title'],
258
+ artist=track_data['metadata']['artist'],
259
+ duration=f"{track_data['generated']['duration']}s",
260
+ genre=track_data['interpreted']['genre'],
261
+ mood=track_data['interpreted']['mood']
262
+ ), unsafe_allow_html=True)
263
+
264
+ # Waveform visualization
265
+ st.subheader("Waveform")
266
+ waveform_data = create_waveform_data(track_data['generated']['duration'])
267
+ st.line_chart(waveform_data)
268
+
269
+ with col2:
270
+ st.subheader("Track Structure")
271
+ structure = track_data['interpreted']['structure']
272
+ for section in structure:
273
+ st.write(f"🎵 {section}")
274
+
275
+ with tab2:
276
+ st.subheader("📊 Detailed Audio Analysis")
277
+
278
+ # Analysis metrics in grid
279
+ cols = st.columns(3)
280
+
281
+ audio_features = track_data['analysis']['audio_features']
282
+
283
+ with cols[0]:
284
+ st.metric("BPM", f"{audio_features['bpm']}")
285
+ st.metric("Key", audio_features['key'])
286
+ st.metric("Mode", audio_features['mode'])
287
+
288
+ with cols[1]:
289
+ st.metric("Danceability", f"{audio_features['danceability']}%")
290
+ st.metric("Energy", f"{audio_features['energy']}%")
291
+ st.metric("Valence", f"{audio_features['valence']}%")
292
+
293
+ with cols[2]:
294
+ st.metric("Acousticness", f"{audio_features['acousticness']}%")
295
+ st.metric("Instrumentalness", f"{audio_features['instrumentalness']}%")
296
+ st.metric("Speechiness", f"{audio_features['speechiness']}%")
297
+
298
+ # Spectral Analysis
299
+ st.subheader("🎛️ Spectral Profile")
300
+ spectral_data = track_data['analysis']['spectral_analysis']
301
+
302
+ fig_col1, fig_col2 = st.columns(2)
303
+
304
+ with fig_col1:
305
+ st.bar_chart({
306
+ 'Low': spectral_data['low_freq'],
307
+ 'Mid': spectral_data['mid_freq'],
308
+ 'High': spectral_data['high_freq']
309
+ })
310
+
311
+ with fig_col2:
312
+ st.bar_chart({
313
+ 'Centroid': spectral_data['spectral_centroid'],
314
+ 'Rolloff': spectral_data['spectral_rolloff'],
315
+ 'Bandwidth': spectral_data['spectral_bandwidth']
316
+ })
317
+
318
+ with tab3:
319
+ st.subheader("🏷️ Optimized Metadata")
320
+ metadata = track_data['metadata']
321
+
322
+ col1, col2 = st.columns(2)
323
+
324
+ with col1:
325
+ st.write("**Title:**")
326
+ st.code(metadata['title'])
327
+
328
+ st.write("**Artist:**")
329
+ st.code(metadata['artist'])
330
+
331
+ st.write("**Genre:**")
332
+ st.code(metadata['genre'])
333
+
334
+ with col2:
335
+ st.write("**Description:**")
336
+ st.info(metadata['description'])
337
+
338
+ st.write("**Tags:**")
339
+ tags_str = ", ".join(metadata['tags'])
340
+ st.code(tags_str)
341
+
342
+ # Platform-specific optimizations
343
+ st.subheader(f"🎯 {target_platform} Optimization")
344
+ platform_data = metadata['platform_specific'][target_platform]
345
+
346
+ for key, value in platform_data.items():
347
+ st.write(f"**{key.replace('_', ' ').title()}:**")
348
+ st.write(value)
349
+
350
+ with tab4:
351
+ st.subheader("📤 Export & Distribution")
352
+
353
+ col1, col2 = st.columns(2)
354
+
355
+ with col1:
356
+ st.write("**Download Options:**")
357
+ if st.button("📥 Download WAV", use_container_width=True):
358
+ st.success("WAV file ready for download!")
359
+ if st.button("📥 Download MP3", use_container_width=True):
360
+ st.success("MP3 file ready for download!")
361
+
362
+ st.write("**Export Metadata:**")
363
+ if st.button("📄 Export JSON", use_container_width=True):
364
+ json_data = json.dumps(track_data, indent=2)
365
+ st.download_button(
366
+ "Download metadata.json",
367
+ json_data,
368
+ "track_metadata.json",
369
+ "application/json"
370
+ )
371
+
372
+ with col2:
373
+ st.write("**Platform Upload:**")
374
+ if st.button("🎵 Upload to SoundCloud", use_container_width=True):
375
+ st.success("✅ Track uploaded to SoundCloud!")
376
+ if st.button("🎵 Submit to Spotify", use_container_width=True):
377
+ st.info("Track submitted for Spotify review!")
378
+
379
+ st.write("**Share:**")
380
+ share_url = f"https://promptcomposer.app/track/{random.randint(10000, 99999)}"
381
+ st.code(share_url)
382
+ if st.button("🔗 Copy Link", use_container_width=True):
383
+ st.success("Link copied to clipboard!")
384
+
385
+ # Footer
386
+ st.markdown("---")
387
+ st.markdown("""
388
+ <div style="text-align: center; color: #666; padding: 1rem;">
389
+ <p>Prompt Composer - AI-Aware Music Creation for Streaming Algorithms</p>
390
+ <p style="font-size: 0.8rem;">Optimize your music for maximum algorithmic compatibility</p>
391
+ </div>
392
+ """, unsafe_allow_html=True)
393
+
394
+ === utils.py ===
395
+ import random
396
+ import re
397
+ from datetime import datetime
398
+ from config import GENRES, MOODS, TEMPO_RANGES
399
+
400
+ def interpret_prompt(prompt):
401
+ """Interpret natural language prompt into structured metadata"""
402
+ # Simulated LLM interpretation
403
+ prompt_lower = prompt.lower()
404
+
405
+ # Extract genre
406
+ detected_genre = "electronic"
407
+ for genre in GENRES:
408
+ if genre in prompt_lower:
409
+ detected_genre = genre
410
+ break
411
+
412
+ # Extract mood
413
+ detected_mood = "energetic"
414
+ for mood in MOODS:
415
+ if mood in prompt_lower:
416
+ detected_mood = mood
417
+ break
418
+
419
+ # Extract BPM
420
+ bpm_match = re.search(r'(\d+)\s*bpm', prompt_lower)
421
+ if bpm_match:
422
+ bpm = int(bpm_match.group(1))
423
+ else:
424
+ bpm = random.randint(*TEMPO_RANGES.get(detected_genre, (90, 140)))
425
+
426
+ # Extract key
427
+ keys = ['C', 'D', 'E', 'F', 'G', 'A', 'B']
428
+ detected_key = random.choice(keys) + random.choice([' major', ' minor'])
429
+
430
+ # Determine structure
431
+ structure = ['Intro', 'Verse', 'Chorus', 'Verse', 'Chorus', 'Bridge', 'Chorus', 'Outro']
432
+ if 'short intro' in prompt_lower:
433
+ structure[0] = 'Short Intro'
434
+
435
+ # Energy curve
436
+ energy_curve = [0.3, 0.5, 0.9, 0.6, 0.9, 0.7, 1.0, 0.4]
437
+
438
+ # Vocal presence
439
+ vocal_presence = 'high' if 'vocals' in prompt_lower else 'low'
440
+
441
+ # Emotional intent
442
+ emotional_intent = detected_mood
443
+
444
+ return {
445
+ 'genre': detected_genre,
446
+ 'mood': detected_mood,
447
+ 'bpm': bpm,
448
+ 'key': detected_key,
449
+ 'structure': structure,
450
+ 'energy_curve': energy_curve,
451
+ 'vocal_presence': vocal_presence,
452
+ 'emotional_intent': emotional_intent,
453
+ 'duration': random.randint(150, 240)
454
+ }
455
+
456
+ def generate_music_simulation(interpreted):
457
+ """Simulate music generation based on interpreted metadata"""
458
+ # Simulate generation process
459
+ time.sleep(0.1) # Simulate processing time
460
+
461
+ # Generate stems info
462
+ stems = {
463
+ 'drums': {'level': random.uniform(0.7, 0.9), 'presence': True},
464
+ 'bass': {'level': random.uniform(0.6, 0.8), 'presence': True},
465
+ 'synths': {'level': random.uniform(0.5, 0.8), 'presence': True},
466
+ 'vocals': {'level': random.uniform(0.6, 0.9), 'presence': interpreted['vocal_presence'] == 'high'},
467
+ 'effects': {'level': random.uniform(0.2, 0.5), 'presence': True}
468
+ }
469
+
470
+ # Mix settings
471
+ mix_settings = {
472
+ 'compression': random.uniform(2, 6),
473
+ 'reverb': random.uniform(10, 30),
474
+ 'stereo_width': random.uniform(80, 120),
475
+ 'loudness_target': -14 # LUFS
476
+ }
477
+
478
+ return {
479
+ 'stems': stems,
480
+ 'mix_settings': mix_settings,
481
+ 'duration': interpreted['duration'],
482
+ 'file_format': 'WAV',
483
+ 'sample_rate': 44100,
484
+ 'bit_depth': 24,
485
+ 'generated_at': datetime.now().isoformat()
486
+ }
487
+
488
+ def analyze_algorithmic_fit(generated, platform):
489
+ """Analyze how well the track fits algorithmic preferences"""
490
+ # Simulate algorithmic analysis
491
+ base_score = random.randint(60, 95)
492
+
493
+ # Calculate key metrics
494
+ skip_resistance = min(95, base_score + random.randint(-10, 10))
495
+ energy_match = min(95, base_score + random.randint(-5, 15))
496
+ loudness = -14 + random.randint(-2, 2)
497
+ hook_timing = random.randint(15, 35)
498
+
499
+ # Audio features
500
+ audio_features = {
501
+ 'bpm': random.randint(90, 140),
502
+ 'key': random.choice(['C', 'D', 'E', 'F', 'G', 'A', 'B']) + random.choice([' major', ' minor']),
503
+ 'mode': random.choice(['major', 'minor']),
504
+ 'danceability': random.randint(60, 95),
505
+ 'energy': random.randint(60, 95),
506
+ 'valence': random.randint(40, 80),
507
+ 'acousticness': random.randint(5, 30),
508
+ 'instrumentalness': random.randint(10, 60),
509
+ 'speechiness': random.randint(5, 25)
510
+ }
511
+
512
+ # Spectral analysis
513
+ spectral_analysis = {
514
+ 'low_freq': random.randint(30, 50),
515
+ 'mid_freq': random.randint(40, 60),
516
+ 'high_freq': random.randint(20, 40),
517
+ 'spectral_centroid': random.randint(2000, 4000),
518
+ 'spectral_rolloff': random.randint(8000, 12000),
519
+ 'spectral_bandwidth': random.randint(1000, 3000)
520
+ }
521
+
522
+ # Generate recommendations
523
+ recommendations = []
524
+ if skip_resistance > 80:
525
+ recommendations.append({
526
+ 'type': 'success',
527
+ 'message': 'Excellent skip resistance - listeners likely to stay engaged'
528
+ })
529
+ else:
530
+ recommendations.append({
531
+ 'type': 'warning',
532
+ 'message': 'Consider adding a stronger hook in the first 30 seconds'
533
+ })
534
+
535
+ if abs(loudness + 14) <= 2:
536
+ recommendations.append({
537
+ 'type': 'success',
538
+ 'message': 'Perfect loudness normalization for streaming platforms'
539
+ })
540
+ else:
541
+ recommendations.append({
542
+ 'type': 'warning',
543
+ 'message': f'Adjust loudness to -14 LUFS (currently {loudness} LUFS)'
544
+ })
545
+
546
+ if hook_timing < 30:
547
+ recommendations.append({
548
+ 'type': 'success',
549
+ 'message': 'Optimal hook timing for algorithmic favorability'
550
+ })
551
+
552
+ return {
553
+ 'algorithmic_fit_score': base_score,
554
+ 'key_metrics': {
555
+ 'skip_resistance': skip_resistance,
556
+ 'energy_match': energy_match,
557
+ 'loudness': loudness,
558
+ 'hook_timing': hook_timing
559
+ },
560
+ 'audio_features': audio_features,
561
+ 'spectral_analysis': spectral_analysis,
562
+ 'recommendations': recommendations,
563
+ 'platform': platform
564
+ }
565
+
566
+ def optimize_metadata(generated, analysis, platform, trending_tags=None):
567
+ """Generate optimized metadata for streaming platforms"""
568
+ # Generate title
569
+ title_templates = [
570
+ "{mood} {genre} Vibes",
571
+ "Midnight {genre}",
572
+ "{genre} Dreams",
573
+ "Electric {mood}",
574
+ "{genre} Revolution"
575
+ ]
576
+
577
+ title = random.choice(title_templates).format(
578
+ mood=analysis['audio_features']['valence'] > 60 and "Uplifting" or "Deep",
579
+ genre=analysis['audio_features']['danceability'] > 70 and "Dance" or "Chill"
580
+ )
581
+
582
+ # Generate artist name
583
+ artist = f"AI Artist {random.randint(100, 999)}"
584
+
585
+ # Generate description
586
+ description = f"""
587
+ A carefully crafted {analysis['audio_features']['mode']} track optimized for {platform}.
588
+ Features {analysis['audio_features']['danceability']}% danceability and {analysis['audio_features']['energy']}% energy.
589
+ Perfect for playlists focusing on {analysis['audio_features']['valence'] > 60 and 'uplifting' or 'deep'} vibes.
590
+ """
591
+
592
+ # Generate tags
593
+ base_tags = ['AI Generated', 'Electronic', 'Optimized']
594
+ if trending_tags:
595
+ base_tags.extend(trending_tags)
596
+
597
+ # Platform-specific optimizations
598
+ platform_specific = {
599
+ 'Spotify': {
600
+ 'playlist_categories': ['Chill Vibes', 'Deep Focus', 'Electronic Mix'],
601
+ 'editorial_notes': 'Perfect for study and relaxation playlists',
602
+ 'mood_target': 'Chill/Energetic blend'
603
+ },
604
+ 'SoundCloud': {
605
+ 'community_tags': ['indie electronic', 'lofi beats', 'ambient'],
606
+ 'related_artists': ['Tycho', 'Bonobo', 'ODESZA'],
607
+ 'genre_specific': 'Future Bass / Chillwave'
608
+ },
609
+ 'Apple Music': {
610
+ 'curator_notes': 'Ideal for curated editorial playlists',
611
+ 'mood_station': 'Focus Flow',
612
+ 'genre_station': 'Electronic Essentials'
613
+ },
614
+ 'YouTube Music': {
615
+ 'video_keywords': ['chill music', 'study beats', 'lofi hip hop'],
616
+ 'thumbnail_suggestions': 'Minimalist aesthetic with gradient colors',
617
+ 'description_seo': 'Best chill music for studying and relaxation'
618
+ }
619
+ }
620
+
621
+ return {
622
+ 'title': title,
623
+ 'artist': artist,
624
+ 'genre': analysis['audio_features']['danceability'] > 70 and 'Dance' or 'Chill',
625
+ 'description': description.strip(),
626
+ 'tags': base_tags[:10], # Limit to 10 tags
627
+ 'platform_specific': platform_specific,
628
+ 'optimized_for': platform,
629
+ 'optimization_score': analysis['algorithmic_fit_score']
630
+ }
631
+
632
+ def get_trending_tags():
633
+ """Get list of trending tags"""
634
+ return [
635
+ 'lofi beats', 'study music', 'chill vibes', 'ambient', 'downtempo',
636
+ 'future bass', 'chillwave', 'vaporwave', 'electronic', 'indie',
637
+ 'upbeat', 'relaxing', 'focus', 'meditation', 'workout'
638
+ ]
639
+
640
+ def create_waveform_data(duration):
641
+ """Create simulated waveform data for visualization"""
642
+ points = min(100, duration)
643
+ return [random.uniform(-1, 1) for _ in range(points)]
644
+
645
+ === config.py ===
646
+ # Configuration constants for Prompt Composer
647
+
648
+ # Music genres
649
+ GENRES = [
650
+ 'electronic', 'pop', 'rock', 'hip-hop', 'jazz', 'classical',
651
+ 'blues', 'country', 'folk', 'reggae', 'metal', 'punk',
652
+ 'indie', 'ambient', 'house', 'techno', 'trance', 'dubstep'
653
+ ]
654
+
655
+ # Mood descriptors
656
+ MOODS = [
657
+ 'energetic', 'chill', 'happy', 'sad', 'angry', 'romantic',
658
+ 'mysterious', 'uplifting', 'dark', 'dreamy', 'aggressive',
659
+ 'peaceful', 'epic', 'intimate', 'nostalgic'
660
+ ]
661
+
662
+ # Tempo ranges by genre (BPM)
663
+ TEMPO_RANGES = {
664
+ 'ambient': (60, 90),
665
+ 'chill': (70, 100),
666
+ 'house': (115, 130),
667
+ 'techno': (120, 140),
668
+ 'trance': (130, 150),
669
+ 'dubstep': (140, 150),
670
+ 'hip-hop': (85, 115),
671
+ 'pop': (100, 130),
672
+ 'rock': (110, 140),
673
+ 'metal': (120, 180),
674
+ 'jazz': (80, 140),
675
+ 'classical': (60, 200),
676
+ 'electronic': (90, 140)
677
+ }
678
+
679
+ # Digital Service Providers (DSPs)
680
+ DSP_PLATFORMS = [
681
+ 'Spotify',
682
+ 'SoundCloud',
683
+ 'Apple Music',
684
+ 'YouTube Music'
685
+ ]
686
+
687
+ # Algorithm optimization targets
688
+ ALGORITHM_TARGETS = {
689
+ 'Spotify': {
690
+ 'loudness_lufs': -14,
691
+ 'skip_threshold': 30, # seconds
692
+ 'hook_timing': 25, # seconds
693
+ 'energy_curve': [0.3, 0.5, 0.8, 0.6, 0.9, 0.7, 1.0, 0.4]
694
+ },
695
+ 'SoundCloud': {
696
+ 'loudness_lufs': -12,
697
+ 'skip_threshold': 20,
698
+ 'hook_timing': 15,
699
+ 'energy_curve': [0.4, 0.6, 0.9, 0.7, 1.0, 0.8, 0.9, 0.5]
700
+ },
701
+ 'Apple Music': {
702
+ 'loudness_lufs': -16,
703
+ 'skip_threshold': 30,
704
+ 'hook_timing': 30,
705
+ 'energy_curve': [0.3, 0.5, 0.8, 0.6, 0.9, 0.7, 1.0, 0.4]
706
+ },
707
+ 'YouTube Music': {
708
+ 'loudness_lufs': -13,
709
+ 'skip_threshold': 15,
710
+ 'hook_timing': 10,
711
+ 'energy_curve': [0.5, 0.7, 1.0, 0.8, 1.0, 0.9, 1.0, 0.6]
712
+ }
713
+ }
714
+
715
+ # Audio analysis parameters
716
+ AUDIO_FEATURES_RANGES = {
717
+ 'danceability': (0, 100),
718
+ 'energy': (0, 100),
719
+ 'valence': (0, 100),
720
+ 'acousticness': (0, 100),
721
+ 'instrumentalness': (0, 100),
722
+ 'speechiness': (0, 100)
723
+ }
724
+
725
+ # Metadata templates
726
+ TITLE_TEMPLATES = [
727
+ "{mood} {genre}",
728
+ "Midnight {genre}",
729
+ "{genre} Dreams",
730
+ "Electric {mood}",
731
+ "{genre} Revolution",
732
+ "Lost in {genre}",
733
+ "{mood} Sessions",
734
+ "Digital {genre}",
735
+ "Cosmic {genre}",
736
+ "Urban {genre}"
737
+ ]
738
+
739
+ DESCRIPTION_TEMPLATES = [
740
+ "A carefully crafted {genre} track optimized for {platform}. Features {danceability}% danceability and {energy}% energy.",
741
+ "Experience the perfect blend of {mood} vibes with this {genre} masterpiece. Optimized for maximum algorithmic compatibility on {platform}.",
742
+ "This {genre} track delivers {energy}% energy with {danceability}% danceability. Perfect for {platform} playlists.",
743
+ "Immerse yourself in this {mood} {genre} creation. Designed to perform exceptionally well on {platform}'s recommendation algorithms.",
744
+ "A standout {genre} piece with {danceability}% danceability. Algorithmically optimized for {platform} discovery."
745
+ ]
746
+
747
+ === requirements.txt ===
748
+ streamlit
749
+ pandas
750
+ numpy
751
+ plotly
752
+ requests
753
+ python-dotenv