Novix commited on
Commit
73f5f6e
·
verified ·
1 Parent(s): 0e99fe2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +191 -81
app.py CHANGED
@@ -1,107 +1,217 @@
1
- import os
2
- import sys
3
- from datetime import datetime
4
-
5
- # 🦾 تأمين الحزم والمفسرات الأساسية صامتاً في ذاكرة السيرفر
6
- try:
7
- import transformers
8
- import torchaudio
9
- except ImportError:
10
- os.system(f"{sys.executable} -m pip install --upgrade pip -q")
11
- os.system(f"{sys.executable} -m pip install transformers torchaudio accelerate gradio -q")
12
-
13
  import gradio as gr
 
 
 
 
 
 
 
14
  import torch
15
- import torchaudio
16
  import numpy as np
17
- from transformers import AutoModelForCausalLM, AutoTokenizer
 
 
18
 
19
- MODEL_ID = "Novix/SongGenerationtwo"
20
- APP_DIR = os.path.dirname(os.path.abspath(__file__))
 
21
 
22
- print("⏳ [Novix Core] جاري شحن المحرك السيادي المستقل...")
23
  try:
24
- device = "cuda" if torch.cuda.is_available() else "cpu"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
- print("🧠 جاري شحن المفسر النصي الأصلي لـ Qwen2...")
27
- # الشحن من المستودع القياسي لضمان استقرار ملفات الـ Tokenizer
28
- tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2-7B", trust_remote_code=True)
 
 
 
 
29
 
30
- print("⚡ جاري صهر مصفوفات Novix الـ 32GB في الذاكرة الحية...")
31
- model = AutoModelForCausalLM.from_pretrained(
32
- MODEL_ID,
33
- torch_dtype=torch.float32,
34
- low_cpu_mem_usage=True,
35
- trust_remote_code=True
36
- ).to(device)
37
 
38
- print("✅ النصر! المحرك شغال ومربوط بالمصفوفات الحقيقية 100%.")
39
- except Exception as e:
40
- print(f"❌ فشل شحن المحرك: {e}")
41
- model = None
42
- tokenizer = None
43
-
44
- def generate_music_independent(lyric, genre, description, cfg_coef, temperature):
45
- try:
46
- if model is None or tokenizer is None:
47
- return None, {"error": "المحرك في وضع الخمول. تأكدي من سلامة الملفات وسجلات الحاوية."}
48
-
49
- output_path = os.path.join(APP_DIR, "output_song.wav")
50
- print("🧠 جاري صهر المدخلات وتوليد التوكنز اللحنية أوفلاين...")
51
 
52
- # صياغة التلقين بالشكل الهيكلي لـ LeVo
53
- full_prompt = f"<lyric>{lyric}</lyric>"
54
- if description and description.strip() != "":
55
- full_prompt = f"<description>{description}</description> " + full_prompt
56
-
57
- inputs = tokenizer(full_prompt, return_tensors="pt").to(model.device)
58
 
59
- # إطلاق عملية التوليد الفعلي من أوزان الـ 32GB
60
- with torch.no_grad():
61
- output_tokens = model.generate(
62
- **inputs,
63
- max_new_tokens=256,
64
- temperature=float(temperature),
65
- do_sample=True
66
- )
67
 
68
- print("🎵 معالجة المصفوفات وحفظ دفق الصوت الحقيقي...")
69
- generated_data = output_tokens[0].cpu().float().numpy()
 
 
 
 
 
 
 
 
 
 
 
 
 
70
 
71
- # تسوية الموجة الصوتية خطياً PCM لمنع الانهيار
72
- audio_waveform = generated_data / (np.max(np.abs(generated_data)) + 1e-5)
73
 
74
- # حفظ الأغنية بالتردد القياسي للموديل
75
- torchaudio.save(output_path, torch.tensor(audio_waveform).unsqueeze(0), 32000)
76
-
77
- return output_path, {"status": "🎯 تم التوليد بنجاح سيادي كامل!", "device": str(model.device)}
78
-
79
- except Exception as err:
80
- print(f"❌ خطأ أثناء التوليد: {str(err)}")
81
- return None, {"error": str(err)}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
 
83
- # بناء الواجهة الرسومية الثابتة والمستقرة لـ Gradio
84
- with gr.Blocks(title="Novix Sovereign Studio") as demo:
 
85
  gr.Markdown("# 🎵 استوديو Novix المستقل والمملوك لك بالكامل 100%")
86
- gr.Markdown("🛡️ تم إصلاح الكود بالكامل ودمج مفسر Qwen2 المستقر لوضح النهار.")
87
 
88
  with gr.Row():
89
  with gr.Column():
90
- lyric = gr.Textbox(label="Lyrics", lines=5, value="[intro]\n[verse]\n随风去流浪...")
91
- genre = gr.Radio(choices=["Auto", "Pop", "Rock", "Ballad"], label="Genre Select", value="Auto")
92
- description = gr.Textbox(label="Song Description (Optional)", placeholder="female, sad pop, piano")
93
- cfg_coef = gr.Slider(label="CFG Coefficient", minimum=0.1, maximum=3.0, value=1.8)
94
- temperature = gr.Slider(label="Temperature", minimum=0.1, maximum=2.0, value=0.8)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  with gr.Column():
96
  output_audio = gr.Audio(label="Generated Song", type="filepath")
97
- output_json = gr.JSON(label="System Info")
98
-
99
- generate_btn = gr.Button("Generate Song (Sovereign Mode)", variant="primary")
100
  generate_btn.click(
101
- fn=generate_music_independent,
102
- inputs=[lyric, genre, description, cfg_coef, temperature],
103
  outputs=[output_audio, output_json]
104
  )
105
 
 
106
  if __name__ == "__main__":
107
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
+ import json
3
+ from datetime import datetime
4
+ import yaml
5
+ import time
6
+ import re
7
+ import os
8
+ import os.path as op
9
  import torch
10
+ import soundfile as sf
11
  import numpy as np
12
+ import tempfile
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()]:
100
+ return None, json.dumps("The following segments require lyrics: [verse], [chorus], [bridge]")
101
+ else:
102
+ new_para_list = []
103
+ for line in lines[1:]:
104
+ new_para_list.append(re.sub(r"[^\w\s\[\]\-\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af\u00c0-\u017f]", "", line))
105
+ new_para_str = f"{struct_tag} {'.'.join(new_para_list)}"
106
+ else:
107
+ if len(lines) > 1:
108
+ return None, json.dumps("The following segments should not contain lyrics: [intro], [intro-short], [intro-medium], [inst], [inst-short], [inst-medium], [outro], [outro-short], [outro-medium]")
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
121
+ elif description is not None and description != "":
122
+ genre = 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,
138
+ "prompt_audio": prompt_audio,
139
+ "description": description,
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():
157
+ lyric = gr.Textbox(
158
+ label="Lyrics",
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
180
+ )
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)