Spaces:
VIDraft
/
Running on Zero

ginipick commited on
Commit
fdb4f50
ยท
verified ยท
1 Parent(s): 9681ed4

Update ui/components.py

Browse files
Files changed (1) hide show
  1. ui/components.py +24 -1412
ui/components.py CHANGED
@@ -1,1423 +1,35 @@
1
- import gradio as gr
2
- import librosa
3
  import os
4
- import random
5
- import hashlib
6
- import numpy as np
7
- import json
8
- from typing import Dict, List, Tuple, Optional
9
- import time
10
- import requests
11
- # ์ถ”๊ฐ€๋œ ๋ถ€๋ถ„: OpenAI ๋ชจ๋“ˆ ์ž„ํฌํŠธ
12
- from openai import OpenAI
13
 
14
- # ๊ฐ€์‚ฌ ์ƒ์„ฑ์„ ์œ„ํ•œ OpenAI ํ˜ธ์ถœ ํ•จ์ˆ˜
15
- client = OpenAI(api_key=os.getenv("LLM_API"))
16
-
17
- def openai_generate_lyrics(topic: str) -> str:
18
- """
19
- ์ฃผ์ œ(topic)๋ฅผ ๋ฐ›์•„ GPT-4๋กœ [verse]/[chorus]/[bridge] ํ˜•์‹์˜
20
- ๊ฐ€์‚ฌ๋ฅผ ์ƒ์„ฑํ•ด ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ตœ๋Œ€ 3ํšŒ ์žฌ์‹œ๋„ํ•œ๋‹ค.
21
- """
22
- system_prompt = (
23
- "๋„ˆ๋Š” ๋…ธ๋ž˜ ๊ฐ€์‚ฌ๋ฅผ ์ž‘์‚ฌํ•˜๋Š” ์ „๋ฌธ๊ฐ€ ์—ญํ• ์ด๋‹ค. ์ด์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•˜๋Š” ์ฃผ์ œ์— ๋”ฐ๋ผ "
24
- "์ด์— ๊ด€๋ จ๋œ ๋…ธ๋ž˜ ๊ฐ€์‚ฌ๋ฅผ ์ž‘์„ฑํ•˜๋ผ. ๊ฐ€์‚ฌ์˜ ๊ทœ์น™์€ \"[ ]\"๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ, "
25
- "๋‹ค์Œ ์˜ˆ์‹œ๋ฅผ ์ฐธ์กฐํ•˜๋ผ. \"\"\"[verse]\nNeon lights they flicker bright\nCity "
26
- "hums in dead of night\nRhythms pulse through concrete veins\nLost in echoes "
27
- "of refrains\n\n[verse]\nBassline groovin' in my chest\nHeartbeats match the "
28
- "city's zest\nElectric whispers fill the air\nSynthesized dreams everywhere\n\n"
29
- "[chorus]\nTurn it up and let it flow\nFeel the fire let it grow\nIn this rhythm "
30
- "we belong\nHear the night sing out our song\n\n[verse]\nGuitar strings they "
31
- "start to weep\nWake the soul from silent sleep\nEvery note a story told\nIn "
32
- "this night we're bold and gold\n\n[bridge]\nVoices blend in harmony\nLost in "
33
- "pure cacophony\nTimeless echoes timeless cries\nSoulful shouts beneath the "
34
- "skies\n\n[verse]\nKeyboard dances on the keys\nMelodies on evening breeze\nCatch "
35
- "the tune and hold it tight\nIn this moment we take flight\n\"\"\""
36
- )
37
-
38
- retries = 3
39
- for attempt in range(retries):
40
- try:
41
- # ํ‘œ์ค€ OpenAI API ํ˜•์‹์œผ๋กœ ๋ณ€๊ฒฝ
42
- response = client.chat.completions.create(
43
- model="gpt-4.1-mini", # ๋˜๋Š” "gpt-3.5-turbo"
44
- messages=[
45
- {
46
- "role": "system",
47
- "content": system_prompt
48
- },
49
- {
50
- "role": "user",
51
- "content": topic
52
- }
53
- ],
54
- temperature=1,
55
- max_tokens=2048,
56
- top_p=1
57
- )
58
-
59
- # ํ‘œ์ค€ ์‘๋‹ต ํ˜•์‹์—์„œ ํ…์ŠคํŠธ ์ถ”์ถœ
60
- return response.choices[0].message.content
61
-
62
- except Exception as e:
63
- print(f"Attempt {attempt + 1}/{retries} failed: {e}")
64
- time.sleep(2)
65
-
66
- return "๊ฐ€์‚ฌ ์ƒ์„ฑ ์‹คํŒจ: ์žฌ์‹œ๋„ ๋ถˆ๊ฐ€"
67
-
68
-
69
-
70
- TAG_DEFAULT = "funk, pop, soul, rock, melodic, guitar, drums, bass, keyboard, percussion, 105 BPM, energetic, upbeat, groovy, vibrant, dynamic"
71
- LYRIC_DEFAULT = """[verse]
72
- Neon lights they flicker bright
73
- City hums in dead of night
74
- Rhythms pulse through concrete veins
75
- Lost in echoes of refrains
76
-
77
- [verse]
78
- Bassline groovin' in my chest
79
- Heartbeats match the city's zest
80
- Electric whispers fill the air
81
- Synthesized dreams everywhere
82
-
83
- [chorus]
84
- Turn it up and let it flow
85
- Feel the fire let it grow
86
- In this rhythm we belong
87
- Hear the night sing out our song
88
-
89
- [verse]
90
- Guitar strings they start to weep
91
- Wake the soul from silent sleep
92
- Every note a story told
93
- In this night we're bold and gold
94
-
95
- [bridge]
96
- Voices blend in harmony
97
- Lost in pure cacophony
98
- Timeless echoes timeless cries
99
- Soulful shouts beneath the skies
100
-
101
- [verse]
102
- Keyboard dances on the keys
103
- Melodies on evening breeze
104
- Catch the tune and hold it tight
105
- In this moment we take flight
106
- """
107
-
108
- # ํ™•์žฅ๋œ ์žฅ๋ฅด ํ”„๋ฆฌ์…‹ (๊ธฐ์กด + ๊ฐœ์„ ๋œ ํƒœ๊ทธ)
109
- GENRE_PRESETS = {
110
- "Modern Pop": "pop, synth, drums, guitar, 120 bpm, upbeat, catchy, vibrant, female vocals, polished vocals, radio-ready, commercial, layered vocals",
111
- "Rock": "rock, electric guitar, drums, bass, 130 bpm, energetic, rebellious, gritty, male vocals, raw vocals, power chords, driving rhythm",
112
- "Hip Hop": "hip hop, 808 bass, hi-hats, synth, 90 bpm, bold, urban, intense, male vocals, rhythmic vocals, trap beats, punchy drums",
113
- "Country": "country, acoustic guitar, steel guitar, fiddle, 100 bpm, heartfelt, rustic, warm, male vocals, twangy vocals, storytelling, americana",
114
- "EDM": "edm, synth, bass, kick drum, 128 bpm, euphoric, pulsating, energetic, instrumental, progressive build, festival anthem, electronic",
115
- "Reggae": "reggae, guitar, bass, drums, 80 bpm, chill, soulful, positive, male vocals, smooth vocals, offbeat rhythm, island vibes",
116
- "Classical": "classical, orchestral, strings, piano, 60 bpm, elegant, emotive, timeless, instrumental, dynamic range, sophisticated harmony",
117
- "Jazz": "jazz, saxophone, piano, double bass, 110 bpm, smooth, improvisational, soulful, male vocals, crooning vocals, swing feel, sophisticated",
118
- "Metal": "metal, electric guitar, double kick drum, bass, 160 bpm, aggressive, intense, heavy, male vocals, screamed vocals, distorted, powerful",
119
- "R&B": "r&b, synth, bass, drums, 85 bpm, sultry, groovy, romantic, female vocals, silky vocals, smooth production, neo-soul"
120
- }
121
-
122
- # ํ’ˆ์งˆ ํ”„๋ฆฌ์…‹ ์‹œ์Šคํ…œ ์ถ”๊ฐ€
123
- QUALITY_PRESETS = {
124
- "Draft (Fast)": {
125
- "infer_step": 50,
126
- "guidance_scale": 10.0,
127
- "scheduler_type": "euler",
128
- "omega_scale": 5.0,
129
- "use_erg_diffusion": False,
130
- "use_erg_tag": True,
131
- "description": "๋น ๋ฅธ ์ดˆ์•ˆ ์ƒ์„ฑ (1-2๋ถ„)"
132
- },
133
- "Standard": {
134
- "infer_step": 150,
135
- "guidance_scale": 15.0,
136
- "scheduler_type": "euler",
137
- "omega_scale": 10.0,
138
- "use_erg_diffusion": True,
139
- "use_erg_tag": True,
140
- "description": "ํ‘œ์ค€ ํ’ˆ์งˆ (3-5๋ถ„)"
141
- },
142
- "High Quality": {
143
- "infer_step": 200,
144
- "guidance_scale": 18.0,
145
- "scheduler_type": "euler",
146
- "omega_scale": 15.0,
147
- "use_erg_diffusion": True,
148
- "use_erg_tag": True,
149
- "description": "๊ณ ํ’ˆ์งˆ ์ƒ์„ฑ (8-12๋ถ„)"
150
- },
151
- "Ultra (Best)": {
152
- "infer_step": 299,
153
- "guidance_scale": 20.0,
154
- "scheduler_type": "euler",
155
- "omega_scale": 20.0,
156
- "use_erg_diffusion": True,
157
- "use_erg_tag": True,
158
- "description": "์ตœ๊ณ  ํ’ˆ์งˆ (15-20๋ถ„)"
159
- }
160
- }
161
-
162
- # ๋‹ค์ค‘ ์‹œ๋“œ ์ƒ์„ฑ ์„ค์ •
163
- MULTI_SEED_OPTIONS = {
164
- "Single": 1,
165
- "Best of 3": 3,
166
- "Best of 5": 5,
167
- "Best of 10": 10
168
- }
169
-
170
- class MusicGenerationCache:
171
- """์ƒ์„ฑ ๊ฒฐ๊ณผ ์บ์‹ฑ ์‹œ์Šคํ…œ"""
172
- def __init__(self):
173
- self.cache = {}
174
- self.max_cache_size = 50
175
-
176
- def get_cache_key(self, params):
177
- # ์ค‘์š”ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ๋งŒ์œผ๋กœ ํ•ด์‹œ ์ƒ์„ฑ
178
- key_params = {k: v for k, v in params.items()
179
- if k in ['prompt', 'lyrics', 'infer_step', 'guidance_scale', 'audio_duration']}
180
- return hashlib.md5(str(sorted(key_params.items())).encode()).hexdigest()[:16]
181
-
182
- def get_cached_result(self, params):
183
- key = self.get_cache_key(params)
184
- return self.cache.get(key)
185
-
186
- def cache_result(self, params, result):
187
- if len(self.cache) >= self.max_cache_size:
188
- oldest_key = next(iter(self.cache))
189
- del self.cache[oldest_key]
190
-
191
- key = self.get_cache_key(params)
192
- self.cache[key] = result
193
-
194
- # ์ „์—ญ ์บ์‹œ ์ธ์Šคํ„ด์Šค
195
- generation_cache = MusicGenerationCache()
196
-
197
- def enhance_prompt_with_genre(base_prompt: str, genre: str) -> str:
198
- """์žฅ๋ฅด์— ๋”ฐ๋ฅธ ์Šค๋งˆํŠธ ํ”„๋กฌํ”„ํŠธ ํ™•์žฅ"""
199
- if genre == "Custom" or not genre:
200
- return base_prompt
201
-
202
- # ์žฅ๋ฅด๋ณ„ ์ถ”๊ฐ€ ๊ฐœ์„  ํƒœ๊ทธ
203
- genre_enhancements = {
204
- "Modern Pop": ["polished production", "mainstream appeal", "hook-driven"],
205
- "Rock": ["guitar-driven", "powerful drums", "energetic performance"],
206
- "Hip Hop": ["rhythmic flow", "urban atmosphere", "bass-heavy"],
207
- "Country": ["acoustic warmth", "storytelling melody", "authentic feel"],
208
- "EDM": ["electronic atmosphere", "build-ups", "dance-friendly"],
209
- "Reggae": ["laid-back groove", "tropical vibes", "rhythmic guitar"],
210
- "Classical": ["orchestral depth", "musical sophistication", "timeless beauty"],
211
- "Jazz": ["musical complexity", "improvisational spirit", "sophisticated harmony"],
212
- "Metal": ["aggressive energy", "powerful sound", "intense atmosphere"],
213
- "R&B": ["smooth groove", "soulful expression", "rhythmic sophistication"]
214
- }
215
-
216
- if genre in genre_enhancements:
217
- additional_tags = ", ".join(genre_enhancements[genre])
218
- return f"{base_prompt}, {additional_tags}"
219
-
220
- return base_prompt
221
-
222
- def calculate_quality_score(audio_path: str) -> float:
223
- """๊ฐ„๋‹จํ•œ ํ’ˆ์งˆ ์ ์ˆ˜ ๊ณ„์‚ฐ (์‹ค์ œ ๊ตฌํ˜„์—์„œ๋Š” ๋” ๋ณต์žกํ•œ ๋ฉ”ํŠธ๋ฆญ ์‚ฌ์šฉ)"""
224
  try:
225
- y, sr = librosa.load(audio_path)
226
-
227
- # ๊ธฐ๋ณธ ํ’ˆ์งˆ ๋ฉ”ํŠธ๋ฆญ
228
- rms_energy = np.sqrt(np.mean(y**2))
229
- spectral_centroid = np.mean(librosa.feature.spectral_centroid(y=y, sr=sr))
230
- zero_crossing_rate = np.mean(librosa.feature.zero_crossing_rate(y))
231
-
232
- # ์ •๊ทœํ™”๋œ ์ ์ˆ˜ (0-100)
233
- energy_score = min(rms_energy * 1000, 40) # 0-40์ 
234
- spectral_score = min(spectral_centroid / 100, 40) # 0-40์ 
235
- clarity_score = min((1 - zero_crossing_rate) * 20, 20) # 0-20์ 
236
-
237
- total_score = energy_score + spectral_score + clarity_score
238
- return round(total_score, 1)
239
- except:
240
- return 50.0 # ๊ธฐ๋ณธ๊ฐ’
241
-
242
- def update_tags_from_preset(preset_name):
243
- if preset_name == "Custom":
244
- return ""
245
- return GENRE_PRESETS.get(preset_name, "")
246
-
247
- def update_quality_preset(preset_name):
248
- """ํ’ˆ์งˆ ํ”„๋ฆฌ์…‹ ์ ์šฉ"""
249
- if preset_name not in QUALITY_PRESETS:
250
- return (100, 15.0, "euler", 10.0, True, True)
251
-
252
- preset = QUALITY_PRESETS[preset_name]
253
- return (
254
- preset.get("infer_step", 100),
255
- preset.get("guidance_scale", 15.0),
256
- preset.get("scheduler_type", "euler"),
257
- preset.get("omega_scale", 10.0),
258
- preset.get("use_erg_diffusion", True),
259
- preset.get("use_erg_tag", True)
260
- )
261
-
262
- def create_enhanced_process_func(original_func):
263
- """๊ธฐ์กด ํ•จ์ˆ˜๋ฅผ ํ–ฅ์ƒ๋œ ๊ธฐ๋Šฅ์œผ๋กœ ๋ž˜ํ•‘"""
264
-
265
- def enhanced_func(
266
- audio_duration, prompt, lyrics, infer_step, guidance_scale,
267
- scheduler_type, cfg_type, omega_scale, manual_seeds,
268
- guidance_interval, guidance_interval_decay, min_guidance_scale,
269
- use_erg_tag, use_erg_lyric, use_erg_diffusion, oss_steps,
270
- guidance_scale_text, guidance_scale_lyric,
271
- audio2audio_enable=False, ref_audio_strength=0.5, ref_audio_input=None,
272
- lora_name_or_path="none", multi_seed_mode="Single",
273
- enable_smart_enhancement=True, genre_preset="Custom", **kwargs
274
- ):
275
- # ์Šค๋งˆํŠธ ํ”„๋กฌํ”„ํŠธ ํ™•์žฅ
276
- if enable_smart_enhancement and genre_preset != "Custom":
277
- prompt = enhance_prompt_with_genre(prompt, genre_preset)
278
-
279
- # ์บ์‹œ ํ™•์ธ
280
- cache_params = {
281
- 'prompt': prompt, 'lyrics': lyrics, 'audio_duration': audio_duration,
282
- 'infer_step': infer_step, 'guidance_scale': guidance_scale
283
- }
284
 
285
- cached_result = generation_cache.get_cached_result(cache_params)
286
- if cached_result:
287
- return cached_result
288
 
289
- # ๋‹ค์ค‘ ์‹œ๋“œ ์ƒ์„ฑ
290
- num_candidates = MULTI_SEED_OPTIONS.get(multi_seed_mode, 1)
 
 
291
 
292
- if num_candidates == 1:
293
- # ๊ธฐ์กด ํ•จ์ˆ˜ ํ˜ธ์ถœ
294
- result = original_func(
295
- audio_duration, prompt, lyrics, infer_step, guidance_scale,
296
- scheduler_type, cfg_type, omega_scale, manual_seeds,
297
- guidance_interval, guidance_interval_decay, min_guidance_scale,
298
- use_erg_tag, use_erg_lyric, use_erg_diffusion, oss_steps,
299
- guidance_scale_text, guidance_scale_lyric, audio2audio_enable,
300
- ref_audio_strength, ref_audio_input, lora_name_or_path, **kwargs
301
- )
302
- else:
303
- # ๋‹ค์ค‘ ์‹œ๋“œ ์ƒ์„ฑ ๋ฐ ์ตœ์  ์„ ํƒ
304
- candidates = []
305
-
306
- for i in range(num_candidates):
307
- seed = random.randint(1, 10000)
308
-
309
- try:
310
- result = original_func(
311
- audio_duration, prompt, lyrics, infer_step, guidance_scale,
312
- scheduler_type, cfg_type, omega_scale, str(seed),
313
- guidance_interval, guidance_interval_decay, min_guidance_scale,
314
- use_erg_tag, use_erg_lyric, use_erg_diffusion, oss_steps,
315
- guidance_scale_text, guidance_scale_lyric, audio2audio_enable,
316
- ref_audio_strength, ref_audio_input, lora_name_or_path, **kwargs
317
- )
318
-
319
- if result and len(result) > 0:
320
- audio_path = result[0] # ์ฒซ ๋ฒˆ์งธ ๊ฒฐ๊ณผ๊ฐ€ ์˜ค๋””์˜ค ํŒŒ์ผ ๊ฒฝ๋กœ
321
- if audio_path and os.path.exists(audio_path):
322
- quality_score = calculate_quality_score(audio_path)
323
- candidates.append({
324
- "result": result,
325
- "quality_score": quality_score,
326
- "seed": seed
327
- })
328
- except Exception as e:
329
- print(f"Generation {i+1} failed: {e}")
330
- continue
331
-
332
- if candidates:
333
- # ์ตœ๊ณ  ํ’ˆ์งˆ ์„ ํƒ
334
- best_candidate = max(candidates, key=lambda x: x["quality_score"])
335
- result = best_candidate["result"]
336
-
337
- # ํ’ˆ์งˆ ์ •๋ณด ์ถ”๊ฐ€
338
- if len(result) > 1 and isinstance(result[1], dict):
339
- result[1]["quality_score"] = best_candidate["quality_score"]
340
- result[1]["selected_seed"] = best_candidate["seed"]
341
- result[1]["candidates_count"] = len(candidates)
342
- else:
343
- # ๋ชจ๋“  ์ƒ์„ฑ ์‹คํŒจ์‹œ ๊ธฐ๋ณธ ์ƒ์„ฑ
344
- result = original_func(
345
- audio_duration, prompt, lyrics, infer_step, guidance_scale,
346
- scheduler_type, cfg_type, omega_scale, manual_seeds,
347
- guidance_interval, guidance_interval_decay, min_guidance_scale,
348
- use_erg_tag, use_erg_lyric, use_erg_diffusion, oss_steps,
349
- guidance_scale_text, guidance_scale_lyric, audio2audio_enable,
350
- ref_audio_strength, ref_audio_input, lora_name_or_path, **kwargs
351
- )
352
-
353
- # ๊ฒฐ๊ณผ ์บ์‹œ
354
- generation_cache.cache_result(cache_params, result)
355
- return result
356
-
357
- return enhanced_func
358
-
359
- def create_output_ui(task_name="Text2Music"):
360
- # For many consumer-grade GPU devices, only one batch can be run
361
- output_audio1 = gr.Audio(type="filepath", label=f"{task_name} Generated Audio 1")
362
-
363
- with gr.Accordion(f"{task_name} Parameters & Quality Info", open=False):
364
- input_params_json = gr.JSON(label=f"{task_name} Parameters")
365
-
366
- # ํ’ˆ์งˆ ์ •๋ณด ํ‘œ์‹œ ์ถ”๊ฐ€
367
- with gr.Row():
368
- quality_score = gr.Number(label="Quality Score (0-100)", value=0, interactive=False)
369
- generation_info = gr.Textbox(
370
- label="Generation Info",
371
- value="",
372
- interactive=False,
373
- max_lines=2
374
- )
375
-
376
- outputs = [output_audio1]
377
- return outputs, input_params_json
378
-
379
- def dump_func(*args):
380
- print(args)
381
- return []
382
-
383
- def create_text2music_ui(
384
- gr,
385
- text2music_process_func,
386
- sample_data_func=None,
387
- load_data_func=None,
388
- ):
389
- # ํ–ฅ์ƒ๋œ ํ”„๋กœ์„ธ์Šค ํ•จ์ˆ˜ ์ƒ์„ฑ
390
- enhanced_process_func = create_enhanced_process_func(text2music_process_func)
391
-
392
- with gr.Row():
393
- # ์™ผ์ชฝ ์ปฌ๋Ÿผ - ์ž…๋ ฅ ์„ค์ •
394
- with gr.Column(scale=5):
395
- # ์ƒ๋‹จ ๋ฉ”์ธ ์ปจํŠธ๋กค
396
- with gr.Group():
397
- gr.Markdown("## ๐ŸŽฏ Quick Settings")
398
-
399
- with gr.Row():
400
- with gr.Column(scale=2):
401
- genre_preset = gr.Dropdown(
402
- choices=["Custom"] + list(GENRE_PRESETS.keys()),
403
- value="Custom",
404
- label="๐ŸŽต ์žฅ๋ฅด ํ”„๋ฆฌ์…‹",
405
- interactive=True,
406
- )
407
- with gr.Column(scale=2):
408
- quality_preset = gr.Dropdown(
409
- choices=list(QUALITY_PRESETS.keys()),
410
- value="Standard",
411
- label="โšก ํ’ˆ์งˆ ํ”„๋ฆฌ์…‹",
412
- interactive=True
413
- )
414
- with gr.Column(scale=1):
415
- audio_duration = gr.Slider(
416
- -1,
417
- 240.0,
418
- step=1,
419
- value=-1,
420
- label="โฑ๏ธ ๊ธธ์ด (์ดˆ)",
421
- info="-1 = ๋žœ๋ค",
422
- interactive=True,
423
- )
424
-
425
- with gr.Row():
426
- preset_description = gr.Textbox(
427
- value=QUALITY_PRESETS["Standard"]["description"],
428
- label="ํ’ˆ์งˆ ์„ค๋ช…",
429
- interactive=False,
430
- max_lines=1
431
- )
432
-
433
- # ํ”„๋กฌํ”„ํŠธ ์„น์…˜
434
- with gr.Group():
435
- gr.Markdown("## ๐ŸŽผ Music Prompt")
436
-
437
- with gr.Row():
438
- with gr.Column(scale=3):
439
- prompt = gr.Textbox(
440
- lines=3,
441
- label="ํƒœ๊ทธ (์ฝค๋งˆ๋กœ ๊ตฌ๋ถ„)",
442
- value=TAG_DEFAULT,
443
- placeholder="์žฅ๋ฅด, ์•…๊ธฐ, BPM, ๋ถ„์œ„๊ธฐ ๋“ฑ์„ ์ฝค๋งˆ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ์ž…๋ ฅ...",
444
- elem_id="prompt"
445
- )
446
- with gr.Column(scale=1):
447
- enable_smart_enhancement = gr.Checkbox(
448
- label="โœจ ์Šค๋งˆํŠธ ํ–ฅ์ƒ",
449
- value=True,
450
- info="์ž๋™ ํƒœ๊ทธ ์ตœ์ ํ™”"
451
- )
452
- multi_seed_mode = gr.Dropdown(
453
- choices=list(MULTI_SEED_OPTIONS.keys()),
454
- value="Single",
455
- label="๐ŸŽฒ ๋‹ค์ค‘ ์ƒ์„ฑ",
456
- info="์—ฌ๋Ÿฌ ๋ฒˆ ์ƒ์„ฑํ•˜์—ฌ ์ตœ๊ณ  ํ’ˆ์งˆ ์„ ํƒ"
457
- )
458
-
459
- # ๊ฐ€์‚ฌ ์„น์…˜
460
- with gr.Group():
461
- gr.Markdown("## ๐Ÿ“ Lyrics")
462
-
463
- with gr.Row():
464
- with gr.Column(scale=3):
465
- topic_for_lyrics = gr.Textbox(
466
- lines=1,
467
- label="๊ฐ€์‚ฌ ์ฃผ์ œ (AI ์ž๋™ ์ƒ์„ฑ)",
468
- placeholder="์˜ˆ: ์ฒซ์‚ฌ๋ž‘์˜ ์„ค๋ ˜, ์—ฌ๋ฆ„๋ฐค์˜ ์ถ”์–ต, ๋„์‹œ์˜ ๋ถˆ๋น›...",
469
- elem_id="topic"
470
- )
471
- with gr.Column(scale=1):
472
- generate_lyrics_btn = gr.Button(
473
- "๐Ÿค– ๊ฐ€์‚ฌ ์ƒ์„ฑ",
474
- variant="secondary",
475
- size="sm"
476
- )
477
-
478
- lyrics = gr.Textbox(
479
- lines=10,
480
- label="๊ฐ€์‚ฌ ์ž…๋ ฅ",
481
- value=LYRIC_DEFAULT,
482
- placeholder="[verse], [chorus], [bridge] ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌ์กฐํ™”๋œ ๊ฐ€์‚ฌ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”...",
483
- elem_id="lyrics"
484
- )
485
-
486
- # audio2audio ์˜ต์…˜ (๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ)
487
- with gr.Accordion("๐ŸŽต Audio2Audio ์„ค์ •", open=False):
488
- audio2audio_enable = gr.Checkbox(
489
- label="Audio2Audio ํ™œ์„ฑํ™”",
490
- value=False,
491
- info="์ฐธ์กฐ ์˜ค๋””์˜ค๋ฅผ ์‚ฌ์šฉํ•œ ์ƒ์„ฑ"
492
- )
493
- lora_name_or_path = gr.Dropdown(
494
- label="LoRA ๋ชจ๋ธ",
495
- choices=["none", "ACE-Step/ACE-Step-v1-chinese-rap-LoRA"],
496
- value="none",
497
- allow_custom_value=True,
498
- )
499
- ref_audio_input = gr.Audio(
500
- type="filepath",
501
- label="์ฐธ์กฐ ์˜ค๋””์˜ค",
502
- visible=False
503
- )
504
- ref_audio_strength = gr.Slider(
505
- label="์ฐธ์กฐ ๊ฐ•๋„",
506
- minimum=0.0,
507
- maximum=1.0,
508
- step=0.01,
509
- value=0.5,
510
- visible=False
511
- )
512
-
513
- # ๊ณ ๊ธ‰ ์„ค์ • (์ ‘ํ˜€์žˆ์Œ)
514
- with gr.Accordion("โš™๏ธ ๊ณ ๊ธ‰ ์„ค์ •", open=False):
515
- with gr.Row():
516
- with gr.Column():
517
- infer_step = gr.Slider(1, 300, 150, 1, label="์ถ”๋ก  ์Šคํ…")
518
- guidance_scale = gr.Slider(0.0, 30.0, 15.0, 0.1, label="๊ฐ€์ด๋˜์Šค ์Šค์ผ€์ผ")
519
- manual_seeds = gr.Textbox(label="์‹œ๋“œ๊ฐ’", placeholder="1,2,3,4", value=None)
520
-
521
- with gr.Column():
522
- scheduler_type = gr.Radio(["euler", "heun"], value="euler", label="์Šค์ผ€์ค„๋Ÿฌ")
523
- cfg_type = gr.Radio(["cfg", "apg", "cfg_star"], value="apg", label="CFG ํƒ€์ž…")
524
- omega_scale = gr.Slider(-100.0, 100.0, 10.0, 0.1, label="๊ทธ๋ž˜๋‰ผ๋Ÿฌ๋ฆฌํ‹ฐ ์Šค์ผ€์ผ")
525
-
526
- with gr.Row():
527
- with gr.Column():
528
- use_erg_tag = gr.Checkbox(label="ERG for tag", value=True)
529
- use_erg_lyric = gr.Checkbox(label="ERG for lyric", value=False)
530
- use_erg_diffusion = gr.Checkbox(label="ERG for diffusion", value=True)
531
-
532
- with gr.Column():
533
- guidance_interval = gr.Slider(0.0, 1.0, 0.5, 0.01, label="๊ฐ€์ด๋˜์Šค ์ธํ„ฐ๋ฒŒ")
534
- guidance_interval_decay = gr.Slider(0.0, 1.0, 0.0, 0.01, label="๊ฐ€์ด๋˜์Šค ๊ฐ์‡ ")
535
- min_guidance_scale = gr.Slider(0.0, 200.0, 3.0, 0.1, label="์ตœ์†Œ ๊ฐ€์ด๋˜์Šค")
536
-
537
- with gr.Row():
538
- guidance_scale_text = gr.Slider(0.0, 10.0, 0.0, 0.1, label="ํ…์ŠคํŠธ ๊ฐ€์ด๋˜์Šค")
539
- guidance_scale_lyric = gr.Slider(0.0, 10.0, 0.0, 0.1, label="๊ฐ€์‚ฌ ๊ฐ€์ด๋˜์Šค")
540
- oss_steps = gr.Textbox(label="OSS Steps", placeholder="16, 29, 52...", value=None)
541
-
542
- # ์ƒ์„ฑ ๋ฒ„ํŠผ๋“ค
543
- with gr.Row():
544
- sample_bnt = gr.Button("๐ŸŽฒ ์ƒ˜ํ”Œ", variant="secondary", scale=1)
545
- preview_bnt = gr.Button("๐Ÿ‘๏ธ ๋ฏธ๋ฆฌ๋“ฃ๊ธฐ (10์ดˆ)", variant="secondary", scale=2)
546
- text2music_bnt = gr.Button("๐ŸŽต ์Œ์•… ์ƒ์„ฑ", variant="primary", scale=3, size="lg")
547
-
548
- # ์˜ค๋ฅธ์ชฝ ์ปฌ๋Ÿผ - ์ถœ๋ ฅ
549
- with gr.Column(scale=5):
550
- gr.Markdown("## ๐ŸŽง Generated Music")
551
- outputs, input_params_json = create_output_ui()
552
-
553
- # ์ˆจ๊ฒจ์ง„ ํƒญ๋“ค (visible=False)
554
- with gr.Tabs(visible=False):
555
- with gr.Tab("retake", visible=False):
556
- retake_variance = gr.Slider(
557
- minimum=0.0, maximum=1.0, step=0.01, value=0.2, label="variance"
558
- )
559
- retake_seeds = gr.Textbox(
560
- label="retake seeds (default None)", placeholder="", value=None
561
- )
562
- retake_bnt = gr.Button("Retake", variant="primary")
563
- retake_outputs, retake_input_params_json = create_output_ui("Retake")
564
-
565
- def retake_process_func(json_data, retake_variance, retake_seeds):
566
- return enhanced_process_func(
567
- json_data.get("audio_duration", 30),
568
- json_data.get("prompt", ""),
569
- json_data.get("lyrics", ""),
570
- json_data.get("infer_step", 100),
571
- json_data.get("guidance_scale", 15.0),
572
- json_data.get("scheduler_type", "euler"),
573
- json_data.get("cfg_type", "apg"),
574
- json_data.get("omega_scale", 10.0),
575
- retake_seeds,
576
- json_data.get("guidance_interval", 0.5),
577
- json_data.get("guidance_interval_decay", 0.0),
578
- json_data.get("min_guidance_scale", 3.0),
579
- json_data.get("use_erg_tag", True),
580
- json_data.get("use_erg_lyric", False),
581
- json_data.get("use_erg_diffusion", True),
582
- json_data.get("oss_steps", None),
583
- json_data.get("guidance_scale_text", 0.0),
584
- json_data.get("guidance_scale_lyric", 0.0),
585
- audio2audio_enable=json_data.get("audio2audio_enable", False),
586
- ref_audio_strength=json_data.get("ref_audio_strength", 0.5),
587
- ref_audio_input=json_data.get("ref_audio_input", None),
588
- lora_name_or_path=json_data.get("lora_name_or_path", "none"),
589
- multi_seed_mode="Best of 3",
590
- retake_variance=retake_variance,
591
- task="retake"
592
- )
593
-
594
- retake_bnt.click(
595
- fn=retake_process_func,
596
- inputs=[
597
- input_params_json,
598
- retake_variance,
599
- retake_seeds,
600
- ],
601
- outputs=retake_outputs + [retake_input_params_json],
602
- )
603
-
604
- with gr.Tab("repainting", visible=False):
605
- retake_variance = gr.Slider(
606
- minimum=0.0, maximum=1.0, step=0.01, value=0.2, label="variance"
607
- )
608
- retake_seeds = gr.Textbox(
609
- label="repaint seeds (default None)", placeholder="", value=None
610
- )
611
- repaint_start = gr.Slider(
612
- minimum=0.0,
613
- maximum=240.0,
614
- step=0.01,
615
- value=0.0,
616
- label="Repaint Start Time",
617
- interactive=True,
618
- )
619
- repaint_end = gr.Slider(
620
- minimum=0.0,
621
- maximum=240.0,
622
- step=0.01,
623
- value=30.0,
624
- label="Repaint End Time",
625
- interactive=True,
626
- )
627
- repaint_source = gr.Radio(
628
- ["text2music", "last_repaint", "upload"],
629
- value="text2music",
630
- label="Repaint Source",
631
- elem_id="repaint_source",
632
- )
633
-
634
- repaint_source_audio_upload = gr.Audio(
635
- label="Upload Audio",
636
- type="filepath",
637
- visible=False,
638
- elem_id="repaint_source_audio_upload",
639
- show_download_button=True,
640
- )
641
- repaint_source.change(
642
- fn=lambda x: gr.update(
643
- visible=x == "upload", elem_id="repaint_source_audio_upload"
644
- ),
645
- inputs=[repaint_source],
646
- outputs=[repaint_source_audio_upload],
647
- )
648
-
649
- repaint_bnt = gr.Button("Repaint", variant="primary")
650
- repaint_outputs, repaint_input_params_json = create_output_ui("Repaint")
651
-
652
- def repaint_process_func(
653
- text2music_json_data,
654
- repaint_json_data,
655
- retake_variance,
656
- retake_seeds,
657
- repaint_start,
658
- repaint_end,
659
- repaint_source,
660
- repaint_source_audio_upload,
661
- prompt,
662
- lyrics,
663
- infer_step,
664
- guidance_scale,
665
- scheduler_type,
666
- cfg_type,
667
- omega_scale,
668
- manual_seeds,
669
- guidance_interval,
670
- guidance_interval_decay,
671
- min_guidance_scale,
672
- use_erg_tag,
673
- use_erg_lyric,
674
- use_erg_diffusion,
675
- oss_steps,
676
- guidance_scale_text,
677
- guidance_scale_lyric,
678
- ):
679
- if repaint_source == "upload":
680
- src_audio_path = repaint_source_audio_upload
681
- audio_duration = librosa.get_duration(filename=src_audio_path)
682
- json_data = {"audio_duration": audio_duration}
683
- elif repaint_source == "text2music":
684
- json_data = text2music_json_data
685
- src_audio_path = json_data["audio_path"]
686
- elif repaint_source == "last_repaint":
687
- json_data = repaint_json_data
688
- src_audio_path = json_data["audio_path"]
689
-
690
- return enhanced_process_func(
691
- json_data["audio_duration"],
692
- prompt,
693
- lyrics,
694
- infer_step,
695
- guidance_scale,
696
- scheduler_type,
697
- cfg_type,
698
- omega_scale,
699
- manual_seeds,
700
- guidance_interval,
701
- guidance_interval_decay,
702
- min_guidance_scale,
703
- use_erg_tag,
704
- use_erg_lyric,
705
- use_erg_diffusion,
706
- oss_steps,
707
- guidance_scale_text,
708
- guidance_scale_lyric,
709
- retake_seeds=retake_seeds,
710
- retake_variance=retake_variance,
711
- task="repaint",
712
- repaint_start=repaint_start,
713
- repaint_end=repaint_end,
714
- src_audio_path=src_audio_path,
715
- lora_name_or_path="none"
716
- )
717
-
718
- repaint_bnt.click(
719
- fn=repaint_process_func,
720
- inputs=[
721
- input_params_json,
722
- repaint_input_params_json,
723
- retake_variance,
724
- retake_seeds,
725
- repaint_start,
726
- repaint_end,
727
- repaint_source,
728
- repaint_source_audio_upload,
729
- prompt,
730
- lyrics,
731
- infer_step,
732
- guidance_scale,
733
- scheduler_type,
734
- cfg_type,
735
- omega_scale,
736
- manual_seeds,
737
- guidance_interval,
738
- guidance_interval_decay,
739
- min_guidance_scale,
740
- use_erg_tag,
741
- use_erg_lyric,
742
- use_erg_diffusion,
743
- oss_steps,
744
- guidance_scale_text,
745
- guidance_scale_lyric,
746
- ],
747
- outputs=repaint_outputs + [repaint_input_params_json],
748
- )
749
-
750
- with gr.Tab("edit", visible=False):
751
- edit_prompt = gr.Textbox(lines=2, label="Edit Tags", max_lines=4)
752
- edit_lyrics = gr.Textbox(lines=9, label="Edit Lyrics", max_lines=13)
753
- retake_seeds = gr.Textbox(
754
- label="edit seeds (default None)", placeholder="", value=None
755
- )
756
-
757
- edit_type = gr.Radio(
758
- ["only_lyrics", "remix"],
759
- value="only_lyrics",
760
- label="Edit Type",
761
- elem_id="edit_type",
762
- info="`only_lyrics` will keep the whole song the same except lyrics difference. Make your diffrence smaller, e.g. one lyrc line change.\nremix can change the song melody and genre",
763
- )
764
- edit_n_min = gr.Slider(
765
- minimum=0.0,
766
- maximum=1.0,
767
- step=0.01,
768
- value=0.6,
769
- label="edit_n_min",
770
- interactive=True,
771
- )
772
- edit_n_max = gr.Slider(
773
- minimum=0.0,
774
- maximum=1.0,
775
- step=0.01,
776
- value=1.0,
777
- label="edit_n_max",
778
- interactive=True,
779
- )
780
-
781
- def edit_type_change_func(edit_type):
782
- if edit_type == "only_lyrics":
783
- n_min = 0.6
784
- n_max = 1.0
785
- elif edit_type == "remix":
786
- n_min = 0.2
787
- n_max = 0.4
788
- return n_min, n_max
789
-
790
- edit_type.change(
791
- edit_type_change_func,
792
- inputs=[edit_type],
793
- outputs=[edit_n_min, edit_n_max],
794
- )
795
-
796
- edit_source = gr.Radio(
797
- ["text2music", "last_edit", "upload"],
798
- value="text2music",
799
- label="Edit Source",
800
- elem_id="edit_source",
801
- )
802
- edit_source_audio_upload = gr.Audio(
803
- label="Upload Audio",
804
- type="filepath",
805
- visible=False,
806
- elem_id="edit_source_audio_upload",
807
- show_download_button=True,
808
- )
809
- edit_source.change(
810
- fn=lambda x: gr.update(
811
- visible=x == "upload", elem_id="edit_source_audio_upload"
812
- ),
813
- inputs=[edit_source],
814
- outputs=[edit_source_audio_upload],
815
- )
816
-
817
- edit_bnt = gr.Button("Edit", variant="primary")
818
- edit_outputs, edit_input_params_json = create_output_ui("Edit")
819
-
820
- def edit_process_func(
821
- text2music_json_data,
822
- edit_input_params_json,
823
- edit_source,
824
- edit_source_audio_upload,
825
- prompt,
826
- lyrics,
827
- edit_prompt,
828
- edit_lyrics,
829
- edit_n_min,
830
- edit_n_max,
831
- infer_step,
832
- guidance_scale,
833
- scheduler_type,
834
- cfg_type,
835
- omega_scale,
836
- manual_seeds,
837
- guidance_interval,
838
- guidance_interval_decay,
839
- min_guidance_scale,
840
- use_erg_tag,
841
- use_erg_lyric,
842
- use_erg_diffusion,
843
- oss_steps,
844
- guidance_scale_text,
845
- guidance_scale_lyric,
846
- retake_seeds,
847
- ):
848
- if edit_source == "upload":
849
- src_audio_path = edit_source_audio_upload
850
- audio_duration = librosa.get_duration(filename=src_audio_path)
851
- json_data = {"audio_duration": audio_duration}
852
- elif edit_source == "text2music":
853
- json_data = text2music_json_data
854
- src_audio_path = json_data["audio_path"]
855
- elif edit_source == "last_edit":
856
- json_data = edit_input_params_json
857
- src_audio_path = json_data["audio_path"]
858
-
859
- if not edit_prompt:
860
- edit_prompt = prompt
861
- if not edit_lyrics:
862
- edit_lyrics = lyrics
863
-
864
- return enhanced_process_func(
865
- json_data["audio_duration"],
866
- prompt,
867
- lyrics,
868
- infer_step,
869
- guidance_scale,
870
- scheduler_type,
871
- cfg_type,
872
- omega_scale,
873
- manual_seeds,
874
- guidance_interval,
875
- guidance_interval_decay,
876
- min_guidance_scale,
877
- use_erg_tag,
878
- use_erg_lyric,
879
- use_erg_diffusion,
880
- oss_steps,
881
- guidance_scale_text,
882
- guidance_scale_lyric,
883
- task="edit",
884
- src_audio_path=src_audio_path,
885
- edit_target_prompt=edit_prompt,
886
- edit_target_lyrics=edit_lyrics,
887
- edit_n_min=edit_n_min,
888
- edit_n_max=edit_n_max,
889
- retake_seeds=retake_seeds,
890
- lora_name_or_path="none"
891
- )
892
-
893
- edit_bnt.click(
894
- fn=edit_process_func,
895
- inputs=[
896
- input_params_json,
897
- edit_input_params_json,
898
- edit_source,
899
- edit_source_audio_upload,
900
- prompt,
901
- lyrics,
902
- edit_prompt,
903
- edit_lyrics,
904
- edit_n_min,
905
- edit_n_max,
906
- infer_step,
907
- guidance_scale,
908
- scheduler_type,
909
- cfg_type,
910
- omega_scale,
911
- manual_seeds,
912
- guidance_interval,
913
- guidance_interval_decay,
914
- min_guidance_scale,
915
- use_erg_tag,
916
- use_erg_lyric,
917
- use_erg_diffusion,
918
- oss_steps,
919
- guidance_scale_text,
920
- guidance_scale_lyric,
921
- retake_seeds,
922
- ],
923
- outputs=edit_outputs + [edit_input_params_json],
924
- )
925
-
926
- with gr.Tab("extend", visible=False):
927
- extend_seeds = gr.Textbox(
928
- label="extend seeds (default None)", placeholder="", value=None
929
- )
930
- left_extend_length = gr.Slider(
931
- minimum=0.0,
932
- maximum=240.0,
933
- step=0.01,
934
- value=0.0,
935
- label="Left Extend Length",
936
- interactive=True,
937
- )
938
- right_extend_length = gr.Slider(
939
- minimum=0.0,
940
- maximum=240.0,
941
- step=0.01,
942
- value=30.0,
943
- label="Right Extend Length",
944
- interactive=True,
945
- )
946
- extend_source = gr.Radio(
947
- ["text2music", "last_extend", "upload"],
948
- value="text2music",
949
- label="Extend Source",
950
- elem_id="extend_source",
951
- )
952
-
953
- extend_source_audio_upload = gr.Audio(
954
- label="Upload Audio",
955
- type="filepath",
956
- visible=False,
957
- elem_id="extend_source_audio_upload",
958
- show_download_button=True,
959
- )
960
- extend_source.change(
961
- fn=lambda x: gr.update(
962
- visible=x == "upload", elem_id="extend_source_audio_upload"
963
- ),
964
- inputs=[extend_source],
965
- outputs=[extend_source_audio_upload],
966
- )
967
-
968
- extend_bnt = gr.Button("Extend", variant="primary")
969
- extend_outputs, extend_input_params_json = create_output_ui("Extend")
970
-
971
- def extend_process_func(
972
- text2music_json_data,
973
- extend_input_params_json,
974
- extend_seeds,
975
- left_extend_length,
976
- right_extend_length,
977
- extend_source,
978
- extend_source_audio_upload,
979
- prompt,
980
- lyrics,
981
- infer_step,
982
- guidance_scale,
983
- scheduler_type,
984
- cfg_type,
985
- omega_scale,
986
- manual_seeds,
987
- guidance_interval,
988
- guidance_interval_decay,
989
- min_guidance_scale,
990
- use_erg_tag,
991
- use_erg_lyric,
992
- use_erg_diffusion,
993
- oss_steps,
994
- guidance_scale_text,
995
- guidance_scale_lyric,
996
- ):
997
- if extend_source == "upload":
998
- src_audio_path = extend_source_audio_upload
999
- # get audio duration
1000
- audio_duration = librosa.get_duration(filename=src_audio_path)
1001
- json_data = {"audio_duration": audio_duration}
1002
- elif extend_source == "text2music":
1003
- json_data = text2music_json_data
1004
- src_audio_path = json_data["audio_path"]
1005
- elif extend_source == "last_extend":
1006
- json_data = extend_input_params_json
1007
- src_audio_path = json_data["audio_path"]
1008
-
1009
- repaint_start = -left_extend_length
1010
- repaint_end = json_data["audio_duration"] + right_extend_length
1011
- return enhanced_process_func(
1012
- json_data["audio_duration"],
1013
- prompt,
1014
- lyrics,
1015
- infer_step,
1016
- guidance_scale,
1017
- scheduler_type,
1018
- cfg_type,
1019
- omega_scale,
1020
- manual_seeds,
1021
- guidance_interval,
1022
- guidance_interval_decay,
1023
- min_guidance_scale,
1024
- use_erg_tag,
1025
- use_erg_lyric,
1026
- use_erg_diffusion,
1027
- oss_steps,
1028
- guidance_scale_text,
1029
- guidance_scale_lyric,
1030
- retake_seeds=extend_seeds,
1031
- retake_variance=1.0,
1032
- task="extend",
1033
- repaint_start=repaint_start,
1034
- repaint_end=repaint_end,
1035
- src_audio_path=src_audio_path,
1036
- lora_name_or_path="none"
1037
- )
1038
-
1039
- extend_bnt.click(
1040
- fn=extend_process_func,
1041
- inputs=[
1042
- input_params_json,
1043
- extend_input_params_json,
1044
- extend_seeds,
1045
- left_extend_length,
1046
- right_extend_length,
1047
- extend_source,
1048
- extend_source_audio_upload,
1049
- prompt,
1050
- lyrics,
1051
- infer_step,
1052
- guidance_scale,
1053
- scheduler_type,
1054
- cfg_type,
1055
- omega_scale,
1056
- manual_seeds,
1057
- guidance_interval,
1058
- guidance_interval_decay,
1059
- min_guidance_scale,
1060
- use_erg_tag,
1061
- use_erg_lyric,
1062
- use_erg_diffusion,
1063
- oss_steps,
1064
- guidance_scale_text,
1065
- guidance_scale_lyric,
1066
- ],
1067
- outputs=extend_outputs + [extend_input_params_json],
1068
- )
1069
-
1070
- # ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋“ค
1071
- def toggle_ref_audio_visibility(is_checked):
1072
- return (
1073
- gr.update(visible=is_checked),
1074
- gr.update(visible=is_checked),
1075
- )
1076
-
1077
- audio2audio_enable.change(
1078
- fn=toggle_ref_audio_visibility,
1079
- inputs=[audio2audio_enable],
1080
- outputs=[ref_audio_input, ref_audio_strength],
1081
- )
1082
-
1083
- genre_preset.change(
1084
- fn=update_tags_from_preset,
1085
- inputs=[genre_preset],
1086
- outputs=[prompt]
1087
- )
1088
-
1089
- quality_preset.change(
1090
- fn=lambda x: QUALITY_PRESETS.get(x, {}).get("description", ""),
1091
- inputs=[quality_preset],
1092
- outputs=[preset_description]
1093
- )
1094
-
1095
- quality_preset.change(
1096
- fn=update_quality_preset,
1097
- inputs=[quality_preset],
1098
- outputs=[infer_step, guidance_scale, scheduler_type, omega_scale, use_erg_diffusion, use_erg_tag]
1099
- )
1100
-
1101
- # ๊ฐ€์‚ฌ ์ƒ์„ฑ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ
1102
- generate_lyrics_btn.click(
1103
- fn=openai_generate_lyrics,
1104
- inputs=[topic_for_lyrics],
1105
- outputs=[lyrics]
1106
- )
1107
-
1108
- # ํ”„๋ฆฌ๋ทฐ ๊ธฐ๋Šฅ
1109
- def generate_preview(prompt, lyrics, genre_preset):
1110
- """10์ดˆ ํ”„๋ฆฌ๋ทฐ ์ƒ์„ฑ"""
1111
- preview_params = {
1112
- "audio_duration": 10,
1113
- "infer_step": 50,
1114
- "guidance_scale": 12.0,
1115
- "scheduler_type": "euler",
1116
- "cfg_type": "apg",
1117
- "omega_scale": 5.0,
1118
- }
1119
-
1120
- enhanced_prompt = enhance_prompt_with_genre(prompt, genre_preset) if genre_preset != "Custom" else prompt
1121
 
 
1122
  try:
1123
- # ์‹ค์ œ ๊ตฌํ˜„์—์„œ๋Š” ๋น ๋ฅธ ์ƒ์„ฑ ๋ชจ๋“œ ์‚ฌ์šฉ
1124
- result = enhanced_process_func(
1125
- preview_params["audio_duration"],
1126
- enhanced_prompt,
1127
- lyrics[:200], # ๊ฐ€์‚ฌ ์ผ๋ถ€๋งŒ ์‚ฌ์šฉ
1128
- preview_params["infer_step"],
1129
- preview_params["guidance_scale"],
1130
- preview_params["scheduler_type"],
1131
- preview_params["cfg_type"],
1132
- preview_params["omega_scale"],
1133
- None, # manual_seeds
1134
- 0.5, # guidance_interval
1135
- 0.0, # guidance_interval_decay
1136
- 3.0, # min_guidance_scale
1137
- True, # use_erg_tag
1138
- False, # use_erg_lyric
1139
- True, # use_erg_diffusion
1140
- None, # oss_steps
1141
- 0.0, # guidance_scale_text
1142
- 0.0, # guidance_scale_lyric
1143
- multi_seed_mode="Single"
1144
- )
1145
- return result[0] if result else None
1146
- except Exception as e:
1147
- return f"ํ”„๋ฆฌ๋ทฐ ์ƒ์„ฑ ์‹คํŒจ: {str(e)}"
1148
-
1149
- preview_bnt.click(
1150
- fn=generate_preview,
1151
- inputs=[prompt, lyrics, genre_preset],
1152
- outputs=[outputs[0]]
1153
- )
1154
-
1155
- def json2output(json_data):
1156
- return (
1157
- json_data["audio_duration"],
1158
- json_data["prompt"],
1159
- json_data["lyrics"],
1160
- json_data["infer_step"],
1161
- json_data["guidance_scale"],
1162
- json_data["scheduler_type"],
1163
- json_data["cfg_type"],
1164
- json_data["omega_scale"],
1165
- ", ".join(map(str, json_data["actual_seeds"])),
1166
- json_data["guidance_interval"],
1167
- json_data["guidance_interval_decay"],
1168
- json_data["min_guidance_scale"],
1169
- json_data["use_erg_tag"],
1170
- json_data["use_erg_lyric"],
1171
- json_data["use_erg_diffusion"],
1172
- ", ".join(map(str, json_data["oss_steps"])),
1173
- (
1174
- json_data["guidance_scale_text"]
1175
- if "guidance_scale_text" in json_data
1176
- else 0.0
1177
- ),
1178
- (
1179
- json_data["guidance_scale_lyric"]
1180
- if "guidance_scale_lyric" in json_data
1181
- else 0.0
1182
- ),
1183
- (
1184
- json_data["audio2audio_enable"]
1185
- if "audio2audio_enable" in json_data
1186
- else False
1187
- ),
1188
- (
1189
- json_data["ref_audio_strength"]
1190
- if "ref_audio_strength" in json_data
1191
- else 0.5
1192
- ),
1193
- (
1194
- json_data["ref_audio_input"]
1195
- if "ref_audio_input" in json_data
1196
- else None
1197
- ),
1198
- )
1199
-
1200
- def sample_data(lora_name_or_path_):
1201
- if sample_data_func:
1202
- json_data = sample_data_func()
1203
- return json2output(json_data)
1204
- return {}
1205
-
1206
- sample_bnt.click(
1207
- sample_data,
1208
- inputs=[lora_name_or_path],
1209
- outputs=[
1210
- audio_duration,
1211
- prompt,
1212
- lyrics,
1213
- infer_step,
1214
- guidance_scale,
1215
- scheduler_type,
1216
- cfg_type,
1217
- omega_scale,
1218
- manual_seeds,
1219
- guidance_interval,
1220
- guidance_interval_decay,
1221
- min_guidance_scale,
1222
- use_erg_tag,
1223
- use_erg_lyric,
1224
- use_erg_diffusion,
1225
- oss_steps,
1226
- guidance_scale_text,
1227
- guidance_scale_lyric,
1228
- audio2audio_enable,
1229
- ref_audio_strength,
1230
- ref_audio_input,
1231
- ],
1232
- )
1233
-
1234
- # ๋ฉ”์ธ ์ƒ์„ฑ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ
1235
- text2music_bnt.click(
1236
- fn=enhanced_process_func,
1237
- inputs=[
1238
- audio_duration,
1239
- prompt,
1240
- lyrics,
1241
- infer_step,
1242
- guidance_scale,
1243
- scheduler_type,
1244
- cfg_type,
1245
- omega_scale,
1246
- manual_seeds,
1247
- guidance_interval,
1248
- guidance_interval_decay,
1249
- min_guidance_scale,
1250
- use_erg_tag,
1251
- use_erg_lyric,
1252
- use_erg_diffusion,
1253
- oss_steps,
1254
- guidance_scale_text,
1255
- guidance_scale_lyric,
1256
- audio2audio_enable,
1257
- ref_audio_strength,
1258
- ref_audio_input,
1259
- lora_name_or_path,
1260
- multi_seed_mode,
1261
- enable_smart_enhancement,
1262
- genre_preset
1263
- ],
1264
- outputs=outputs + [input_params_json],
1265
- )
1266
-
1267
-
1268
- def create_main_demo_ui(
1269
- text2music_process_func=dump_func,
1270
- sample_data_func=dump_func,
1271
- load_data_func=dump_func,
1272
- ):
1273
- with gr.Blocks(
1274
- title="ACE-Step Model 1.0 - Enhanced",
1275
- theme=gr.themes.Soft(
1276
- primary_hue="blue",
1277
- secondary_hue="gray",
1278
- font=["Helvetica", "ui-sans-serif", "system-ui", "sans-serif"],
1279
- ),
1280
- css="""
1281
- .gradio-container {
1282
- max-width: 1400px !important;
1283
- margin: auto !important;
1284
- }
1285
-
1286
- /* ๊ทธ๋ฃน ์Šคํƒ€์ผ๋ง */
1287
- .gr-group {
1288
- border: 1px solid #e5e7eb !important;
1289
- border-radius: 8px !important;
1290
- padding: 16px !important;
1291
- margin-bottom: 16px !important;
1292
- background: white !important;
1293
- }
1294
-
1295
- /* ํ—ค๋” ์Šคํƒ€์ผ */
1296
- h1 {
1297
- background: linear-gradient(45deg, #2563eb, #7c3aed);
1298
- -webkit-background-clip: text;
1299
- -webkit-text-fill-color: transparent;
1300
- text-align: center;
1301
- font-size: 2.5rem !important;
1302
- margin-bottom: 0.5rem !important;
1303
- }
1304
-
1305
- h2 {
1306
- color: #1f2937 !important;
1307
- font-size: 1.5rem !important;
1308
- margin-bottom: 1rem !important;
1309
- font-weight: 600 !important;
1310
- }
1311
-
1312
- /* ๋ฒ„ํŠผ ์Šคํƒ€์ผ */
1313
- .primary {
1314
- background: linear-gradient(45deg, #2563eb, #3b82f6) !important;
1315
- color: white !important;
1316
- font-weight: 600 !important;
1317
- transition: all 0.3s ease !important;
1318
- }
1319
-
1320
- .primary:hover {
1321
- transform: translateY(-2px) !important;
1322
- box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4) !important;
1323
- }
1324
-
1325
- .secondary {
1326
- background: #f3f4f6 !important;
1327
- color: #374151 !important;
1328
- border: 1px solid #e5e7eb !important;
1329
- }
1330
-
1331
- /* ์ž…๋ ฅ ํ•„๋“œ ์Šคํƒ€์ผ */
1332
- input, textarea, .gr-box {
1333
- border-radius: 6px !important;
1334
- }
1335
-
1336
- /* ์•„์ฝ”๋””์–ธ ์Šคํƒ€์ผ */
1337
- .gr-accordion {
1338
- border-radius: 8px !important;
1339
- overflow: hidden !important;
1340
- }
1341
-
1342
- /* ํƒœ๊ทธ ๋ผ๋ฒจ ์Šคํƒ€์ผ */
1343
- label {
1344
- font-weight: 500 !important;
1345
- color: #374151 !important;
1346
- }
1347
-
1348
- /* ํ€„๋ฆฌํ‹ฐ ์„ค๋ช… ๋ฐ•์Šค */
1349
- #component-preset_description textarea {
1350
- background: linear-gradient(45deg, #f0f9ff, #e0f2fe) !important;
1351
- border: none !important;
1352
- font-style: italic !important;
1353
- }
1354
- """
1355
- ) as demo:
1356
- gr.Markdown(
1357
- """
1358
- <h1>๐ŸŽต ACE-Step PRO</h1>
1359
- <div style="text-align: center; margin: 20px 0 30px 0;">
1360
- <p style="color: #6b7280; font-size: 1.1rem;">
1361
- <strong>๐Ÿš€ Enhanced Features:</strong> AI ๊ฐ€์‚ฌ ์ƒ์„ฑ | ์Šค๋งˆํŠธ ํ”„๋กฌํ”„ํŠธ | ํ’ˆ์งˆ ํ”„๋ฆฌ์…‹ | ๋‹ค์ค‘ ์ƒ์„ฑ ๋ชจ๋“œ
1362
- </p>
1363
- </div>
1364
- """
1365
- )
1366
-
1367
- # ๋ฉ”์ธ ํƒญ
1368
- with gr.Tab("๐ŸŽต Music Generation"):
1369
- create_text2music_ui(
1370
- gr=gr,
1371
- text2music_process_func=text2music_process_func,
1372
- sample_data_func=sample_data_func,
1373
- load_data_func=load_data_func,
1374
- )
1375
-
1376
- # ๊ฐ€์ด๋“œ ํƒญ ์ถ”๊ฐ€
1377
- with gr.Tab("๐Ÿ“– ์‚ฌ์šฉ๋ฒ• ๊ฐ€์ด๋“œ"):
1378
- gr.Markdown("""
1379
- ## ๐ŸŽฏ ๋น ๋ฅธ ์‹œ์ž‘ ๊ฐ€์ด๋“œ
1380
 
1381
- ### 1. ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•
1382
- - **์žฅ๋ฅด ์„ ํƒ**: ์›ํ•˜๋Š” ์Œ์•… ์žฅ๋ฅด๋ฅผ ์„ ํƒํ•˜๋ฉด ์ž๋™์œผ๋กœ ์ตœ์ ํ™”๋œ ํƒœ๊ทธ๊ฐ€ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค
1383
- - **ํ’ˆ์งˆ ์„ค์ •**: ์šฉ๋„์— ๋งž๋Š” ํ’ˆ์งˆ์„ ์„ ํƒํ•˜์„ธ์š”
1384
- - Draft: ๋น ๋ฅธ ํ…Œ์ŠคํŠธ (1-2๋ถ„)
1385
- - Standard: ์ผ๋ฐ˜ ์‚ฌ์šฉ (3-5๋ถ„)
1386
- - High Quality: ๊ณ ํ’ˆ์งˆ (8-12๋ถ„)
1387
- - Ultra: ์ตœ๊ณ  ํ’ˆ์งˆ (15-20๋ถ„)
1388
-
1389
- ### 2. AI ๊ฐ€์‚ฌ ์ƒ์„ฑ
1390
- - ๊ฐ€์‚ฌ ์ฃผ์ œ๋ฅผ ์ž…๋ ฅํ•˜๊ณ  "๐Ÿค– ๊ฐ€์‚ฌ ์ƒ์„ฑ" ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด AI๊ฐ€ ์ž๋™์œผ๋กœ ๊ตฌ์กฐํ™”๋œ ๊ฐ€์‚ฌ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค
1391
- - ์ƒ์„ฑ๋œ ๊ฐ€์‚ฌ๋Š” ์ž์œ ๋กญ๊ฒŒ ์ˆ˜์ • ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค
1392
-
1393
- ### 3. ๋‹ค์ค‘ ์ƒ์„ฑ ๋ชจ๋“œ
1394
- - "Best of 3/5/10"์„ ์„ ํƒํ•˜๋ฉด ์—ฌ๋Ÿฌ ๋ฒˆ ์ƒ์„ฑํ•˜์—ฌ ๊ฐ€์žฅ ์ข‹์€ ํ’ˆ์งˆ์˜ ๊ฒฐ๊ณผ๋ฅผ ์ž๋™์œผ๋กœ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค
1395
- - ๋” ๋‚˜์€ ๊ฒฐ๊ณผ๋ฅผ ์›ํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค
1396
-
1397
- ### 4. ํ”„๋ฆฌ๋ทฐ ๊ธฐ๋Šฅ
1398
- - "๐Ÿ‘๏ธ ๋ฏธ๋ฆฌ๋“ฃ๊ธฐ" ๋ฒ„ํŠผ์œผ๋กœ 10์ดˆ ์ƒ˜ํ”Œ์„ ๋น ๋ฅด๊ฒŒ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
1399
- - ์ „์ฒด ๊ณก ์ƒ์„ฑ ์ „์— ์Šคํƒ€์ผ์„ ํ™•์ธํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค
1400
-
1401
- ### ๐Ÿ’ก ํ’ˆ์งˆ ํ–ฅ์ƒ ํŒ
1402
- 1. **๊ณ ํ’ˆ์งˆ ์ƒ์„ฑ**: "High Quality" + "Best of 5" ์กฐํ•ฉ ์ถ”์ฒœ
1403
- 2. **๋น ๋ฅธ ํ…Œ์ŠคํŠธ**: "Draft" + "ํ”„๋ฆฌ๋ทฐ" ๊ธฐ๋Šฅ ํ™œ์šฉ
1404
- 3. **์žฅ๋ฅด ํŠนํ™”**: ์žฅ๋ฅด ํ”„๋ฆฌ์…‹ ์„ ํƒ ํ›„ "์Šค๋งˆํŠธ ํ–ฅ์ƒ" ์ฒดํฌ
1405
- 4. **๊ฐ€์‚ฌ ๊ตฌ์กฐ**: [verse], [chorus], [bridge] ํƒœ๊ทธ๋ฅผ ์ ๊ทน ํ™œ์šฉํ•˜์„ธ์š”
1406
-
1407
- ### ๐ŸŽต ๊ฐ€์‚ฌ ๊ตฌ์กฐ ํƒœ๊ทธ
1408
- - `[verse]`: ์ ˆ (์ด์•ผ๊ธฐ ์ „๊ฐœ)
1409
- - `[chorus]`: ํ›„๋ ด๊ตฌ (๋ฐ˜๋ณต๋˜๋Š” ๋ฉ”์ธ ๋ฉœ๋กœ๋””)
1410
- - `[bridge]`: ๋ธŒ๋ฆฟ์ง€ (์ „ํ™˜๋ถ€)
1411
- - `[instrumental]` or `[inst]`: ์—ฐ์ฃผ ๊ตฌ๊ฐ„
1412
- """)
1413
-
1414
- return demo
1415
-
1416
 
1417
  if __name__ == "__main__":
1418
- demo = create_main_demo_ui()
1419
- demo.launch(
1420
- server_name="0.0.0.0",
1421
- server_port=7860,
1422
- share=True # ๊ณต์œ  ๋งํฌ ์ƒ์„ฑ
1423
- )
 
 
 
1
  import os
2
+ import sys
3
+ import streamlit as st
4
+ from tempfile import NamedTemporaryFile
 
 
 
 
 
 
5
 
6
+ def main():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  try:
8
+ # Get the code from secrets
9
+ code = os.environ.get("MAIN_CODE")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
+ if not code:
12
+ st.error("โš ๏ธ The application code wasn't found in secrets. Please add the MAIN_CODE secret.")
13
+ return
14
 
15
+ # Create a temporary Python file
16
+ with NamedTemporaryFile(suffix='.py', delete=False, mode='w') as tmp:
17
+ tmp.write(code)
18
+ tmp_path = tmp.name
19
 
20
+ # Execute the code
21
+ exec(compile(code, tmp_path, 'exec'), globals())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
+ # Clean up the temporary file
24
  try:
25
+ os.unlink(tmp_path)
26
+ except:
27
+ pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
+ except Exception as e:
30
+ st.error(f"โš ๏ธ Error loading or executing the application: {str(e)}")
31
+ import traceback
32
+ st.code(traceback.format_exc())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  if __name__ == "__main__":
35
+ main()