Novix commited on
Commit
acfc75a
·
verified ·
1 Parent(s): e7ab0ec

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +68 -145
app.py CHANGED
@@ -13,108 +13,87 @@ import tempfile
13
 
14
  from download import download_model
15
 
16
- # 下载模型
17
  APP_DIR = op.dirname(op.abspath(__file__))
18
- download_model(APP_DIR, repo_id="waytan22/SongGeneration-v2.0", revision="ffd9215")
19
- print("Successful downloaded model.")
20
 
21
- # 模型初始化
 
 
 
 
 
 
 
 
22
  from levo_inference import LeVoInference
23
- Model = None
24
 
25
  EXAMPLE_LYRICS = """
26
  [intro-medium]
27
 
28
  [verse]
29
- 列车呼啸穿过隧道
30
- 窗外风景急速倒退
31
- 像是与过去在告别
32
- 奔向未定的终点线
33
- 心中混杂期待恐惧
34
- 请别问我要去哪里
35
- 也别追问归期何时
36
-
37
- [chorus]
38
- 让我随风去流浪
39
  我不想停留原地
40
  原地只有无尽循环
41
  不再规划人生
42
  不再遵循地图
43
- 我渴望一场意外之旅
44
- 邂逅未知的自己
45
-
46
- [inst-short]
47
-
48
- [verse]
49
- 行李简单只有背囊
50
- 装着一颗渴望自由的心
51
- 旧照片已撕碎抛洒
52
- 不要任何牵绊
53
- 不要沉重过往
54
 
55
  [chorus]
56
  让我随风去流浪
57
- 我不想停留原地
58
- 原地只会滋生腐朽
59
- 不再规划人生
60
- 不再遵循地图
61
- 我渴望一场灵魂蜕变
62
- 在路途中找到答案
63
-
64
- [bridge]
65
- 山川湖海皆是导师
66
- 星空之下顿悟了渺小
67
- 狭隘的悲欢被风吹散
68
- 融入天地间的壮阔
69
-
70
- [chorus]
71
- 它教会我何为生命
72
- 何为存在的意义
73
- 渺小如尘却也独特
74
- 勇敢地写下自己的诗
75
- 这是我的远征之路
76
  生命最绚烂的章节
77
-
78
- [outro-medium]
79
  """.strip()
80
 
81
- with open(op.join(APP_DIR, 'conf/vocab.yaml'), 'r', encoding='utf-8') as file:
82
- STRUCTS = yaml.safe_load(file)
83
-
 
 
 
 
84
 
85
  def save_as_flac(sample_rate, audio_data):
86
  if isinstance(audio_data, tuple):
87
  sample_rate, audio_data = audio_data
88
-
89
  if audio_data.dtype == np.float64:
90
  audio_data = audio_data.astype(np.float32)
91
-
92
  temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".flac")
93
  sf.write(temp_file, audio_data, sample_rate, format='FLAC')
94
  return temp_file.name
95
 
96
-
97
- # 模拟歌曲生成函数
98
  def generate_song(lyric, description=None, prompt_audio=None, genre=None, cfg_coef=None, temperature=0.1, top_k=-1, gen_type="mixed", progress=gr.Progress(track_tqdm=True)):
99
  global MODEL
100
  global STRUCTS
101
- params = {'cfg_coef':cfg_coef, 'temperature':temperature, 'top_k':top_k}
102
- params = {k:v for k,v in params.items() if v is not None}
 
 
 
 
103
  vocal_structs = ['[verse]', '[chorus]', '[bridge]']
104
  sample_rate = MODEL.cfg.sample_rate
105
 
106
- # format lyric
107
  lyric = lyric.replace("[intro]", "[intro-short]").replace("[inst]", "[inst-short]").replace("[outro]", "[outro-short]")
108
  paragraphs = [p.strip() for p in lyric.strip().split('\n\n') if p.strip()]
 
109
  if len(paragraphs) < 1:
110
  return None, json.dumps("Lyrics can not be left blank")
 
111
  paragraphs_norm = []
112
  vocal_flag = False
 
113
  for para in paragraphs:
114
  lines = para.splitlines()
115
  struct_tag = lines[0].strip().lower()
 
116
  if struct_tag not in STRUCTS:
117
  return None, json.dumps(f"Segments should start with a structure tag in {STRUCTS}")
 
118
  if struct_tag in vocal_structs:
119
  vocal_flag = True
120
  if len(lines) < 2 or not [line.strip() for line in lines[1:] if line.strip()]:
@@ -130,11 +109,12 @@ def generate_song(lyric, description=None, prompt_audio=None, genre=None, cfg_co
130
  else:
131
  new_para_str = struct_tag
132
  paragraphs_norm.append(new_para_str)
 
133
  if not vocal_flag:
134
  return None, json.dumps(f"The lyric must contain at least one of the following structures: {vocal_structs}")
 
135
  lyric_norm = " ; ".join(paragraphs_norm)
136
 
137
- # format prompt
138
  if prompt_audio is not None:
139
  genre = None
140
  description = None
@@ -143,14 +123,15 @@ def generate_song(lyric, description=None, prompt_audio=None, genre=None, cfg_co
143
  if description[-1] != ".":
144
  description = description + "."
145
 
146
- progress(0.0, "Start Generation")
147
  start = time.time()
148
 
149
- audio_data = MODEL(lyric_norm, description, prompt_audio, genre, op.join(APP_DIR, "tools/new_prompt.pt"), gen_type, params).cpu().permute(1, 0).float().numpy()
 
 
150
 
151
  end = time.time()
152
 
153
- # 创建输入配置的JSON
154
  input_config = {
155
  "lyric": lyric_norm,
156
  "genre": genre,
@@ -159,16 +140,17 @@ def generate_song(lyric, description=None, prompt_audio=None, genre=None, cfg_co
159
  "params": params,
160
  "inference_duration": end - start,
161
  "timestamp": datetime.now().isoformat(),
 
162
  }
163
 
164
  filepath = save_as_flac(sample_rate, audio_data)
165
  return filepath, json.dumps(input_config, indent=2)
166
 
167
 
168
- # 创建Gradio界面
169
- with gr.Blocks(title="SongGeneration Demo Space") as demo:
170
- gr.Markdown("# 🎵 SongGeneration Demo Space")
171
- gr.Markdown("Push to Levo 2.0 faster and more controllable. The code is in [GIT](https://github.com/tencent-ailab/SongGeneration)")
172
 
173
  with gr.Row():
174
  with gr.Column():
@@ -177,36 +159,21 @@ with gr.Blocks(title="SongGeneration Demo Space") as demo:
177
  lines=5,
178
  max_lines=15,
179
  value=EXAMPLE_LYRICS,
180
- info="Each paragraph represents a segment starting with a structure tag and ending with a blank line, each line is a sentence without punctuation, segments [intro], [inst], [outro] should not contain lyrics, while [verse], [chorus], and [bridge] require lyrics.",
181
- placeholder="""Lyric Format
182
- '''
183
- [structure tag]
184
- lyrics
185
-
186
- [structure tag]
187
- lyrics
188
- '''
189
- 1. One paragraph represents one segments, starting with a structure tag and ending with a blank line
190
- 2. One line represents one sentence, punctuation is not recommended inside the sentence
191
- 3. The following segments should not contain lyrics: [intro-short], [intro-medium], [inst-short], [inst-medium], [outro-short], [outro-medium]
192
- 4. The following segments require lyrics: [verse], [chorus], [bridge]
193
- """
194
  )
195
 
196
  with gr.Tabs(elem_id="extra-tabs"):
197
  with gr.Tab("Genre Select"):
198
  genre = gr.Radio(
199
  choices=["Auto", "Pop", "Latin", "Rock", "Electronic", "Metal", "Country", "R&B/Soul", "Ballad", "Jazz", "World", "Hip-Hop", "Funk", "Soundtrack"],
200
- label="Genre Select(Optional)",
201
  value="Auto",
202
- interactive=True,
203
- elem_id="single-select-radio"
204
  )
205
  with gr.Tab("Text Prompt"):
206
- gr.Markdown("For detailed usage, please refer to [here](https://github.com/tencent-ailab/SongGeneration?tab=readme-ov-file#-description-input-format)")
207
  description = gr.Textbox(
208
  label="Song Description (Optional)",
209
- info="Describe the gender, genre, emotion, and instrument. Only English is supported currently.",
210
  placeholder="female, rock, motivational, electric guitar, bass guitar, drum kit.",
211
  lines=1,
212
  max_lines=2
@@ -214,81 +181,37 @@ lyrics
214
  with gr.Tab("Audio Prompt"):
215
  prompt_audio = gr.Audio(
216
  label="Prompt Audio (Optional)",
217
- type="filepath",
218
- elem_id="audio-prompt"
219
  )
220
 
221
  with gr.Accordion("Advanced Config", open=False):
222
- cfg_coef = gr.Slider(
223
- label="CFG Coefficient",
224
- minimum=0.1,
225
- maximum=3.0,
226
- step=0.1,
227
- value=1.8,
228
- interactive=True,
229
- elem_id="cfg-coef",
230
- )
231
- temperature = gr.Slider(
232
- label="Temperature",
233
- minimum=0.1,
234
- maximum=2.0,
235
- step=0.1,
236
- value=0.8,
237
- interactive=True,
238
- elem_id="temperature",
239
- )
240
- # top_k = gr.Slider(
241
- # label="Top-K",
242
- # minimum=1,
243
- # maximum=100,
244
- # step=1,
245
- # value=50,
246
- # interactive=True,
247
- # elem_id="top_k",
248
- # )
249
  with gr.Row():
250
- generate_btn = gr.Button("Generate Song", variant="primary")
251
- # generate_bgm_btn = gr.Button("Generate Pure Music", variant="primary")
252
 
253
  with gr.Column():
254
  output_audio = gr.Audio(label="Generated Song", type="filepath")
255
  output_json = gr.JSON(label="Generated Info")
256
 
257
- # # 示例按钮
258
- # examples = gr.Examples(
259
- # examples=[
260
- # ["male, bright, rock, happy, electric guitar and drums, the bpm is 150."],
261
- # ["female, warm, jazz, romantic, synthesizer and piano, the bpm is 100."]
262
- # ],
263
- # inputs=[description],
264
- # label="Text Prompt examples"
265
- # )
266
-
267
- # examples = gr.Examples(
268
- # examples=[
269
- # "[intro-medium]\n\n[verse]\n在这个疯狂的世界里\n谁不渴望一点改变\n在爱情面前\n我们都显得那么不安全\n你紧紧抱着我\n告诉我再靠近一点\n别让这璀璨的夜晚白白浪费\n我那迷茫的眼睛\n看不见未来的路\n在情感消散之前\n我们对爱的渴望永不熄灭\n你给我留下一句誓言\n想知道我们的爱是否能持续到永远\n[chorus]\n\n约定在那最后的夜晚\n不管命运如何摆布\n我们的心是否依然如初\n我会穿上红衬衫\n带着摇滚的激情\n回到我们初遇的地方\n约定在那最后的夜晚\n就算全世界都变了样\n我依然坚守诺言\n铭记这一天\n你永远是我心中的爱恋\n\n[outro-medium]\n",
270
- # "[intro-short]\n\n[verse]\nThrough emerald canyons where fireflies dwell\nCerulean berries kiss morning's first swell\nCrystalline dew crowns each Vitamin Dawn's confection dissolves slowly on me\nAmbrosia breezes through honeycomb vines\nNature's own candy in Fibonacci lines\n[chorus] Blueberry fruit so sweet\n takes you higher\n can't be beat\n In your lungs\n it starts to swell\n You're under its spell\n [verse] Resin of sunlight in candied retreat\nMarmalade moonbeams melt under bare feet\nNectar spirals bloom chloroplast champagne\nPhotosynthesis sings through my veins\nChlorophyll rhythms pulse warm in my blood\nThe forest's green pharmacy floods every bud[chorus] Blueberry fruit so sweet\n takes you higher\n can't be beat\n In your lungs\n it starts to swell\n You're under its spell\n feel the buzz\n ride the wave\n Limey me\n blueberry\n your mind's enslaved\n In the haze\n lose all time\n floating free\n feeling fine\n Blueberry\n fruit so sweet\n takes you higher\n can't be beat\n In your lungs\n it starts to swell\n cry\n You're under its spell\n\n[outro-short]\n",
271
- # ],
272
- # inputs=[lyric],
273
- # label="Lyrics examples",
274
- # )
275
-
276
- # 生成按钮点击事件
277
  generate_btn.click(
278
  fn=generate_song,
279
  inputs=[lyric, description, prompt_audio, genre, cfg_coef, temperature, gr.State(5000)],
280
  outputs=[output_audio, output_json]
281
  )
282
- # generate_bgm_btn.click(
283
- # fn=generate_song,
284
- # inputs=[lyric, description, prompt_audio, genre, cfg_coef, temperature, gr.State(50), gr.State("bgm")],
285
- # outputs=[output_audio, output_json]
286
- # )
287
-
288
 
289
- # 启动应用
290
  if __name__ == "__main__":
291
  torch.set_num_threads(1)
292
- MODEL = LeVoInference(op.join(APP_DIR, "ckpt"))
293
- demo.launch(server_name="0.0.0.0", server_port=7860)
294
-
 
 
 
 
 
 
 
 
 
13
 
14
  from download import download_model
15
 
16
+ # 🎯 خطوة السيادة الأولى: توجيه المحرك لتحميل أوزانكِ الخاصة بدلاً من المستودع العام
17
  APP_DIR = op.dirname(op.abspath(__file__))
18
+ MODEL_ID = "Novix/SongGenerationtwo" # مستودع أوزانكِ السيادية
 
19
 
20
+ print(f"⏳ [Novix Core] جاري سحب الأوزان السيادية من المستودع: {MODEL_ID}...")
21
+ try:
22
+ # تحميل الأوزان مباشرة إلى البيئة المحلية للـ Space
23
+ download_model(APP_DIR, repo_id=MODEL_ID, revision="main")
24
+ print("✅ تم تحميل الأوزان السيادية لـ Novix بنجاح.")
25
+ except Exception as e:
26
+ print(f"⚠️ تنبيه أثناء تحميل الأوزان: {e}. سيتم الاعتماد على الأوزان المحلية إن وجدت.")
27
+
28
+ # تهيئة وإقلاع المحرك من الفئة الأصلية المستقرة
29
  from levo_inference import LeVoInference
30
+ MODEL = None
31
 
32
  EXAMPLE_LYRICS = """
33
  [intro-medium]
34
 
35
  [verse]
36
+ 随风去流浪
 
 
 
 
 
 
 
 
 
37
  我不想停留原地
38
  原地只有无尽循环
39
  不再规划人生
40
  不再遵循地图
 
 
 
 
 
 
 
 
 
 
 
41
 
42
  [chorus]
43
  让我随风去流浪
44
+ 邂逅未知的自己
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  生命最绚烂的章节
 
 
46
  """.strip()
47
 
48
+ # قراءة قاموس التوكنز الصوتي الأصلي للموديل
49
+ vocab_path = op.join(APP_DIR, 'conf/vocab.yaml')
50
+ if op.exists(vocab_path):
51
+ with open(vocab_path, 'r', encoding='utf-8') as file:
52
+ STRUCTS = yaml.safe_load(file)
53
+ else:
54
+ STRUCTS = ['[intro]', '[intro-short]', '[intro-medium]', '[verse]', '[chorus]', '[bridge]', '[inst]', '[inst-short]', '[inst-medium]', '[outro]', '[outro-short]', '[outro-medium]']
55
 
56
  def save_as_flac(sample_rate, audio_data):
57
  if isinstance(audio_data, tuple):
58
  sample_rate, audio_data = audio_data
59
+
60
  if audio_data.dtype == np.float64:
61
  audio_data = audio_data.astype(np.float32)
62
+
63
  temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".flac")
64
  sf.write(temp_file, audio_data, sample_rate, format='FLAC')
65
  return temp_file.name
66
 
67
+ # دالة التوليد الأصلية بعد ربطها بـ Novix Core
 
68
  def generate_song(lyric, description=None, prompt_audio=None, genre=None, cfg_coef=None, temperature=0.1, top_k=-1, gen_type="mixed", progress=gr.Progress(track_tqdm=True)):
69
  global MODEL
70
  global STRUCTS
71
+
72
+ if MODEL is None:
73
+ return None, json.dumps({"error": "المحرك لم يتم تحميله في الذاكرة بعد. يرجى إعادة تحديث الصفحة أو مراجعة السجلات."})
74
+
75
+ params = {'cfg_coef': cfg_coef, 'temperature': temperature, 'top_k': top_k}
76
+ params = {k: v for k, v in params.items() if v is not None}
77
  vocal_structs = ['[verse]', '[chorus]', '[bridge]']
78
  sample_rate = MODEL.cfg.sample_rate
79
 
80
+ # تنسيق وتطهير الكلمات والمقاطع الهيكلية
81
  lyric = lyric.replace("[intro]", "[intro-short]").replace("[inst]", "[inst-short]").replace("[outro]", "[outro-short]")
82
  paragraphs = [p.strip() for p in lyric.strip().split('\n\n') if p.strip()]
83
+
84
  if len(paragraphs) < 1:
85
  return None, json.dumps("Lyrics can not be left blank")
86
+
87
  paragraphs_norm = []
88
  vocal_flag = False
89
+
90
  for para in paragraphs:
91
  lines = para.splitlines()
92
  struct_tag = lines[0].strip().lower()
93
+
94
  if struct_tag not in STRUCTS:
95
  return None, json.dumps(f"Segments should start with a structure tag in {STRUCTS}")
96
+
97
  if struct_tag in vocal_structs:
98
  vocal_flag = True
99
  if len(lines) < 2 or not [line.strip() for line in lines[1:] if line.strip()]:
 
109
  else:
110
  new_para_str = struct_tag
111
  paragraphs_norm.append(new_para_str)
112
+
113
  if not vocal_flag:
114
  return None, json.dumps(f"The lyric must contain at least one of the following structures: {vocal_structs}")
115
+
116
  lyric_norm = " ; ".join(paragraphs_norm)
117
 
 
118
  if prompt_audio is not None:
119
  genre = None
120
  description = None
 
123
  if description[-1] != ".":
124
  description = description + "."
125
 
126
+ progress(0.0, " [Novix Core] التوليد مستمر الآن...")
127
  start = time.time()
128
 
129
+ # تشغيل المصفوفات الحقيقية للأوزان المستقلة
130
+ prompt_path = op.join(APP_DIR, "tools/new_prompt.pt")
131
+ audio_data = MODEL(lyric_norm, description, prompt_audio, genre, prompt_path, gen_type, params).cpu().permute(1, 0).float().numpy()
132
 
133
  end = time.time()
134
 
 
135
  input_config = {
136
  "lyric": lyric_norm,
137
  "genre": genre,
 
140
  "params": params,
141
  "inference_duration": end - start,
142
  "timestamp": datetime.now().isoformat(),
143
+ "engine": "Novix Sovereign Studio (Independent Mode)"
144
  }
145
 
146
  filepath = save_as_flac(sample_rate, audio_data)
147
  return filepath, json.dumps(input_config, indent=2)
148
 
149
 
150
+ # بناء الواجهة الاحترافية الكبرى لـ Gradio
151
+ with gr.Blocks(title="Novix Sovereign Studio Pro") as demo:
152
+ gr.Markdown("# 🎵 استوديو Novix المستقل والمملوك لك بالكامل 100%")
153
+ gr.Markdown("🛡️ تم فك الارتباط من خوادم الشركات وتوجيه النواة لأوزانكِ الخاصة للإنتاج والربح الحر.")
154
 
155
  with gr.Row():
156
  with gr.Column():
 
159
  lines=5,
160
  max_lines=15,
161
  value=EXAMPLE_LYRICS,
162
+ info="قوالب المقاطع الصوتية المدعومة: [intro], [verse], [chorus], [bridge], [inst], [outro]"
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  )
164
 
165
  with gr.Tabs(elem_id="extra-tabs"):
166
  with gr.Tab("Genre Select"):
167
  genre = gr.Radio(
168
  choices=["Auto", "Pop", "Latin", "Rock", "Electronic", "Metal", "Country", "R&B/Soul", "Ballad", "Jazz", "World", "Hip-Hop", "Funk", "Soundtrack"],
169
+ label="Genre Select (Optional)",
170
  value="Auto",
171
+ interactive=True
 
172
  )
173
  with gr.Tab("Text Prompt"):
 
174
  description = gr.Textbox(
175
  label="Song Description (Optional)",
176
+ info="اكتبي مواصفات الصوت بالأرقام أو الإنجليزية (مثال: female, sad pop, piano).",
177
  placeholder="female, rock, motivational, electric guitar, bass guitar, drum kit.",
178
  lines=1,
179
  max_lines=2
 
181
  with gr.Tab("Audio Prompt"):
182
  prompt_audio = gr.Audio(
183
  label="Prompt Audio (Optional)",
184
+ type="filepath"
 
185
  )
186
 
187
  with gr.Accordion("Advanced Config", open=False):
188
+ cfg_coef = gr.Slider(label="CFG Coefficient", minimum=0.1, maximum=3.0, step=0.1, value=1.8, interactive=True)
189
+ temperature = gr.Slider(label="Temperature", minimum=0.1, maximum=2.0, step=0.1, value=0.8, interactive=True)
190
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  with gr.Row():
192
+ generate_btn = gr.Button("Generate Song (Sovereign Mode)", variant="primary")
 
193
 
194
  with gr.Column():
195
  output_audio = gr.Audio(label="Generated Song", type="filepath")
196
  output_json = gr.JSON(label="Generated Info")
197
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
  generate_btn.click(
199
  fn=generate_song,
200
  inputs=[lyric, description, prompt_audio, genre, cfg_coef, temperature, gr.State(5000)],
201
  outputs=[output_audio, output_json]
202
  )
 
 
 
 
 
 
203
 
204
+ # تشغيل الإقلاع المستقل للنواة
205
  if __name__ == "__main__":
206
  torch.set_num_threads(1)
207
+ ckpt_path = op.join(APP_DIR, "ckpt")
208
+
209
+ # التأكد من وجود مجلد الأوزان وإقلاع النموذج فوراً
210
+ if not op.exists(ckpt_path):
211
+ os.makedirs(ckpt_path, exist_ok=True)
212
+
213
+ print("🧠 جاري صهر وبناء بيئة الاستدلال الصوتي المستقل...")
214
+ MODEL = LeVoInference(ckpt_path)
215
+ print("✅ النصر الكلي! الاستوديو شغال أوفلاين وجاهز لاستقبال ضربة زر التوليد.")
216
+
217
+ demo.launch(server_name="0.0.0.0", server_port=7860)