aifeifei798 commited on
Commit
be392d2
·
1 Parent(s): 032d5df

Upload 3 files

Browse files
Files changed (2) hide show
  1. app.py +51 -151
  2. packages.txt +1 -0
app.py CHANGED
@@ -1,39 +1,16 @@
 
1
  import gradio as gr
2
  import google.generativeai as genai
3
  import os
4
  import time
5
  from pydub import AudioSegment
6
- import stat # 确保导入 stat 模块
7
-
8
- # --- 启动时自动修复 FFmpeg 权限 / Auto-fix FFmpeg permissions on startup ---
9
- FFMPEG_PATH = "./ffmpeg"
10
- if os.path.exists(FFMPEG_PATH):
11
- try:
12
- # 检查当前是否已有执行权限
13
- if not (os.stat(FFMPEG_PATH).st_mode & stat.S_IXUSR):
14
- print(f"检测到 '{FFMPEG_PATH}' 没有执行权限,正在尝试修复...")
15
- print(f"Detected '{FFMPEG_PATH}' lacks execute permission, attempting to fix...")
16
- current_permissions = os.stat(FFMPEG_PATH).st_mode
17
- os.chmod(FFMPEG_PATH, current_permissions | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
18
- print("权限修复成功!/ Permissions fixed successfully!")
19
- except Exception as e:
20
- print(f"警告:自动修复 '{FFMPEG_PATH}' 权限失败: {e}")
21
- print(f"Warning: Auto-fixing permissions for '{FFMPEG_PATH}' failed: {e}")
22
- print("应用可能会因为无法调用ffmpeg而失败。/ The app might fail due to being unable to call ffmpeg.")
23
-
24
- # 显式地告诉 pydub ffmpeg 的路径
25
- AudioSegment.converter = FFMPEG_PATH
26
-
27
-
28
- # --- -1. 网络代理配置 (如果需要) / Network Proxy (If Needed) ---
29
- # os.environ['http_proxy'] = 'http://127.0.0.1:7890'
30
- # os.environ['https_proxy'] = 'http://127.0.0.1:7890'
31
 
32
  # --- 0. 全局配置 / Global Configuration ---
33
- # 从环境变量加载API Key / Load API Key from environment variables
34
  GOOGLE_API_KEY = os.getenv('GOOGLE_API_KEY')
35
  if not GOOGLE_API_KEY:
36
- raise ValueError("请设置环境变量 GOOGLE_API_KEY / Please set the GOOGLE_API_KEY environment variable")
 
37
 
38
  genai.configure(api_key=GOOGLE_API_KEY)
39
  gemini_model = genai.GenerativeModel('gemini-1.5-flash-latest')
@@ -45,74 +22,37 @@ EQ_RANGE_DB = 12
45
  # --- 1. 双语文本库 / Bilingual Text Library ---
46
  LANG = {
47
  'zh': {
48
- 'title': "FeiMatrix 智能动态调音",
49
- 'subtitle': "上传一首歌,告诉我你想要的感觉,剩下的交给我!",
50
- 'lang_label': "语言 / Language",
51
- 'step1_header': "第一步:上传音频",
52
- 'upload_label': "点击或拖拽 MP3 文件到这里",
53
- 'step2_header': "第二步:告诉我你的感觉",
54
- 'custom_input_label': "用你自己的话描述想要的感觉(推荐):",
55
- 'custom_input_placeholder': "例如:我想要吉他声更清脆,鼓声更有力...",
56
- 'quick_choice_label': "或者,快速选择一个预设风格:",
57
- 'quick_choices': [
58
- "我想要咚咚咚的重低音!", "让高音更亮、更清楚", "让唱歌的声音更突出",
59
- "我喜欢温暖、厚实的感觉", "给我一种现场演唱会的空间感", "保持原汁原味,但细节多一点",
60
- "无 (使用上面的输入框)",
61
- ],
62
- 'default_choice': "无 (使用上面的输入框)",
63
- 'step3_header': "第三步:开始调音",
64
- 'process_button': "开始智能调音!",
65
- 'log_header': "AI 调音师工作日志",
66
- 'log_initial': "`[系统]`:我准备好啦,等你上传文件哦~",
67
- 'result_header': "第四步:聆听您的定制版",
68
- 'result_label': "这里会显示AI调音后的音频",
69
- 'accordion_header': "(高级)查看 AI 定制的 EQ 参数",
70
- 'err_no_file': "哎呀,忘了上传MP3文件啦!",
71
- 'info_no_pref': "您没有指定风格,将为您进行温和的细节优化。",
72
- 'status_analyzing': "`[AI分析师]`:收到!正在分析您的音频... ⏳",
73
- 'status_analysis_failed': "AI分析失败: {e}。将使用默认调音策略。",
74
- 'status_understanding': "`[AI分析师]`:分析完成!\n> {analysis}\n\n`[AI调音师]`:正在理解{choice}并调整EQ... 🔊",
75
- 'status_tuning': "`[AI调音师]`:好嘞!已经按您的要求调整好了!\n\n`[系统]`:正在生成音频... 🎶",
76
- 'status_done': "`[系统]`:搞定!您的AI定制版音频已生成!🎉",
77
  },
78
  'en': {
79
- 'title': "FeiMatrix AI Dynamic Equalizer",
80
- 'subtitle': "Upload a song, tell me the vibe you want, and I'll handle the rest!",
81
- 'lang_label': "Language / 语言",
82
- 'step1_header': "Step 1: Upload Audio",
83
- 'upload_label': "Click or drag your MP3 file here",
84
- 'step2_header': "Step 2: Tell Me Your Vibe",
85
- 'custom_input_label': "Describe the feeling you want in your own words (Recommended):",
86
- 'custom_input_placeholder': "e.g., I want the guitar to be crisper and the drums more powerful...",
87
- 'quick_choice_label': "Or, quickly pick a preset style:",
88
- 'quick_choices': [
89
- "I want that 'thump-thump' heavy bass!", "Make the treble brighter and clearer", "Make the vocals stand out more",
90
- "I like a warm and rich sound", "Give me a live concert feeling", "Keep it natural, just add more detail",
91
- "None (use the input box above)",
92
- ],
93
- 'default_choice': "None (use the input box above)",
94
- 'step3_header': "Step 3: Start Tuning",
95
- 'process_button': "Start AI Tuning!",
96
- 'log_header': "AI Tuning Engineer's Log",
97
- 'log_initial': "`[System]`: Ready when you are, just upload a file~",
98
- 'result_header': "Step 4: Listen to Your Custom Version",
99
- 'result_label': "Your AI-tuned audio will appear here",
100
- 'accordion_header': "(Advanced) View AI-Customized EQ Parameters",
101
- 'err_no_file': "Oops, you forgot to upload the MP3 file!",
102
- 'info_no_pref': "You didn't specify a style, so I'll perform a gentle detail enhancement.",
103
- 'status_analyzing': "`[AI Analyst]`: Roger that! Analyzing your audio... ⏳",
104
- 'status_analysis_failed': "AI analysis failed: {e}. Default tuning strategy will be used.",
105
- 'status_understanding': "`[AI Analyst]`: Analysis complete!\n> {analysis}\n\n`[AI Tuning Engineer]`: Understanding {choice} and adjusting EQ... 🔊",
106
- 'status_tuning': "`[AI Tuning Engineer]`: Alright! Tuned to your request!\n\n`[System]`: Generating audio... 🎶",
107
- 'status_done': "`[System]`: All set! Your AI custom audio is ready! 🎉",
108
  }
109
  }
110
  LANG_MAP = {"简体中文": "zh", "English": "en"}
111
 
112
- # --- 2. 核心功能函数 / Core Functions ---
113
  def get_ai_tuned_eq_settings(audio_analysis_text, user_preference):
114
- eq_values = [0.0] * len(EQ_BANDS_HZ)
115
- pref_lower = user_preference.lower()
116
  if "电子舞曲" in audio_analysis_text or "EDM" in audio_analysis_text: eq_values = [4.0, 2.5, -1.5, -0.5, 1.0, 2.0, 3.5, 4.0, 2.5, 1.0]
117
  elif "爵士乐" in audio_analysis_text or "warm" in audio_analysis_text: eq_values = [3.0, 1.5, -0.5, -1.0, 0.5, 1.5, 2.0, 3.0, 2.0, 0.5]
118
  elif "人声" in audio_analysis_text or "vocal" in audio_analysis_text: eq_values[4] += 0.5; eq_values[5] += 1.0
@@ -122,104 +62,64 @@ def get_ai_tuned_eq_settings(audio_analysis_text, user_preference):
122
  if any(k in pref_lower for k in ["温暖", "warm", "rich", "soft"]): eq_values[1]+=1.5; eq_values[2]+=1.0; eq_values[6]-=0.5
123
  if any(k in pref_lower for k in ["空间", "space", "live", "concert"]): eq_values[6]+=1.0; eq_values[7]+=1.0; eq_values[4]-=0.5
124
  if any(k in pref_lower for k in ["自然", "natural", "original"]): [v*0.5 for v in eq_values]; eq_values[7]+=0.5
125
- eq_values=[max(-EQ_RANGE_DB,min(EQ_RANGE_DB,v)) for v in eq_values]
126
- return {f'{f} Hz':v for f,v in zip(EQ_BANDS_HZ, eq_values)}
127
 
128
  def apply_eq_to_audio(audio_path, eq_settings):
129
- if not audio_path: return None
130
  try: audio = AudioSegment.from_file(audio_path)
131
  except Exception as e: print(f"Audio load error: {e}"); return None
132
  q_factor=1.414; filter_parts=[]
133
- for band_hz_str, gain_db in eq_settings.items():
134
- if gain_db != 0: filter_parts.append(f"equalizer=f={band_hz_str.split(' ')[0]}:width_type=q:w={q_factor}:g={gain_db}")
135
  if not filter_parts: return audio_path
136
  output_path = f"{os.path.splitext(audio_path)[0]}_eq.mp3"
137
  try:
138
  audio.export(output_path, format="mp3", parameters=["-af", ",".join(filter_parts)])
139
  return output_path
140
- except Exception as e: print(f"EQ apply error: {e}"); raise gr.Error("Failed to apply EQ! Ensure ffmpeg is installed.")
141
 
142
  def process_and_tune(audio_file, quick_choice, custom_input, lang_choice):
143
- lang_code = LANG_MAP[lang_choice]
144
- L = LANG[lang_code]
145
  if not audio_file: raise gr.Error(L['err_no_file'])
146
-
147
  if custom_input and custom_input.strip(): final_preference = custom_input
148
  elif L['default_choice'] not in quick_choice: final_preference = quick_choice
149
  else: final_preference = L['quick_choices'][-2]; gr.Info(L['info_no_pref'])
150
-
151
- slider_reset_updates={s:gr.update(value=0) for s in eq_sliders}
152
- yield {status_log_md: gr.update(value=L['status_analyzing']), processed_audio_output: gr.update(value=None), eq_accordion: gr.update(visible=True, open=False), **slider_reset_updates}
153
-
154
  try:
155
- audio_file_for_api = genai.upload_file(path=audio_file.name)
156
- prompt = "Briefly analyze this audio's genre, mood, and key instruments."; response = gemini_model.generate_content([prompt, audio_file_for_api])
157
  audio_analysis_text = response.text or "(AI did not provide a detailed analysis)"
158
  except Exception as e: audio_analysis_text = L['status_analysis_failed'].format(e=e); gr.Warning(audio_analysis_text)
159
-
160
  choice_desc = f"“{final_preference}”"
161
- yield {status_log_md: gr.update(value=L['status_understanding'].format(analysis=audio_analysis_text, choice=choice_desc))}
162
- time.sleep(1)
163
-
164
- eq_settings = get_ai_tuned_eq_settings(audio_analysis_text, final_preference)
165
- slider_updates = {s: gr.update(value=v) for s, v in zip(eq_sliders, eq_settings.values())}
166
- yield {status_log_md: gr.update(value=L['status_tuning']), **slider_updates}
167
- time.sleep(1)
168
-
169
  eq_audio_path = apply_eq_to_audio(audio_file.name, eq_settings)
170
  if not eq_audio_path: raise gr.Error("Audio processing failed!")
171
-
172
  yield {status_log_md: gr.update(value=L['status_done']), processed_audio_output: gr.update(value=eq_audio_path, label=L['result_label'], autoplay=True), eq_accordion: gr.update(open=False)}
173
 
174
  def update_language(lang_choice):
175
- lang_code = LANG_MAP[lang_choice]
176
- L = LANG[lang_code]
177
  return {
178
- title_md: gr.update(value=f"# {L['title']}"),
179
- subtitle_md: gr.update(value=L['subtitle']),
180
- step1_header_md: gr.update(value=f"### **{L['step1_header']}**"),
181
- audio_input: gr.update(label=L['upload_label']),
182
- step2_header_md: gr.update(value=f"### **{L['step2_header']}**"),
183
- custom_input: gr.update(label=L['custom_input_label'], placeholder=L['custom_input_placeholder']),
184
- quick_choice: gr.update(label=L['quick_choice_label'], choices=L['quick_choices'], value=L['default_choice']),
185
- step3_header_md: gr.update(value=f"### **{L['step3_header']}**"),
186
- process_button: gr.update(value=L['process_button']),
187
- log_header_md: gr.update(value=f"### **{L['log_header']}**"),
188
- status_log_md: gr.update(value=L['log_initial']),
189
- result_header_md: gr.update(value=f"### **{L['result_header']}**"),
190
- processed_audio_output: gr.update(label=L['result_label']),
191
- eq_accordion: gr.update(label=L['accordion_header']),
192
  }
193
 
194
- # --- 3. Gradio 界面构建 / Gradio UI Build ---
195
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
196
  lang_switcher = gr.Radio(choices=["简体中文", "English"], value="简体中文", label="Language / 语言", info="选择界面语言 / Select UI Language")
197
-
198
  title_md = gr.Markdown("# FeiMatrix 智能动态调音")
199
  subtitle_md = gr.Markdown("上传一首歌,告诉我你想要的感觉,剩下的交给我!")
200
-
201
  with gr.Column():
202
- step1_header_md = gr.Markdown("### **第一步:上传音频**")
203
- audio_input = gr.File(label="点击或拖拽 MP3 文件到这里", type="filepath", file_types=[".mp3"])
204
-
205
- step2_header_md = gr.Markdown("### **第二步:告诉我你的感觉**")
206
- custom_input = gr.Textbox(label="用你自己的话描述想要的感觉(推荐):", placeholder="例如:我想要吉他声更清脆,鼓声更有力...", lines=2)
207
  quick_choice = gr.Radio(label="或者,快速选择一个预设风格:", choices=LANG['zh']['quick_choices'], value=LANG['zh']['default_choice'])
208
-
209
- step3_header_md = gr.Markdown("### **第三步:开始调音**")
210
- process_button = gr.Button("开始智能调音!", variant="primary")
211
-
212
- log_header_md = gr.Markdown("### **AI 调音师工作日志**")
213
- status_log_md = gr.Markdown("`[系统]`:我准备好啦,等你上传文件哦~")
214
-
215
- result_header_md = gr.Markdown("### **第四步:聆听您的定制版**")
216
- processed_audio_output = gr.Audio(label="这里会显示AI调音后的音频", type="filepath", interactive=True)
217
-
218
  with gr.Accordion("(高级)查看 AI 定制的 EQ 参数", open=False, visible=False) as eq_accordion:
219
- with gr.Column(variant="panel"):
220
- eq_sliders = [gr.Slider(minimum=-EQ_RANGE_DB, maximum=EQ_RANGE_DB, value=0, step=0.5, label=f"{f} Hz", interactive=False) for f in EQ_BANDS_HZ]
221
-
222
- # 事件绑定 / Event Bindings
223
  all_ui_outputs = [title_md, subtitle_md, step1_header_md, audio_input, step2_header_md, custom_input, quick_choice, step3_header_md, process_button, log_header_md, status_log_md, result_header_md, processed_audio_output, eq_accordion]
224
  lang_switcher.change(fn=update_language, inputs=lang_switcher, outputs=all_ui_outputs, queue=False)
225
  process_button.click(fn=process_and_tune, inputs=[audio_input, quick_choice, custom_input, lang_switcher], outputs=[status_log_md, processed_audio_output, eq_accordion, *eq_sliders])
 
1
+ # app.py (Hugging Face Spaces Version)
2
  import gradio as gr
3
  import google.generativeai as genai
4
  import os
5
  import time
6
  from pydub import AudioSegment
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
  # --- 0. 全局配置 / Global Configuration ---
9
+ # API Key will be loaded from Hugging Face Secrets
10
  GOOGLE_API_KEY = os.getenv('GOOGLE_API_KEY')
11
  if not GOOGLE_API_KEY:
12
+ # This error will be visible in the logs if the secret is not set
13
+ raise ValueError("Hugging Face Secret 'GOOGLE_API_KEY' not found!")
14
 
15
  genai.configure(api_key=GOOGLE_API_KEY)
16
  gemini_model = genai.GenerativeModel('gemini-1.5-flash-latest')
 
22
  # --- 1. 双语文本库 / Bilingual Text Library ---
23
  LANG = {
24
  'zh': {
25
+ 'title': "FeiMatrix 智能动态调音", 'subtitle': "上传一首歌,告诉我你想要的感觉,剩下的交给我!", 'lang_label': "语言 / Language",
26
+ 'step1_header': "第一步:上传音频", 'upload_label': "点击或拖拽 MP3 文件到这里",
27
+ 'step2_header': "第二步:告诉我你的感觉", 'custom_input_label': "用你自己的话描述想要的感觉(推荐):",
28
+ 'custom_input_placeholder': "例如:我想要吉他声更清脆,鼓声更有力...", 'quick_choice_label': "或者,快速选择一个预设风格:",
29
+ 'quick_choices': [ "我想要咚咚咚的重低音!", "让高音更亮、更清楚", "让唱歌的声音更突出", "我喜欢温暖、厚实的感觉", "给我一种现场演唱会的空间感", "保持原汁原味,但细节多一点", "无 (使用上面的输入框)", ],
30
+ 'default_choice': "无 (使用上面的输入框)", 'step3_header': "第三步:开始调音", 'process_button': "开始智能调音!",
31
+ 'log_header': "AI 调音师工作日志", 'log_initial': "`[系统]`:我准备好啦,等你上传文件哦~", 'result_header': "第四步:聆听您的定制版",
32
+ 'result_label': "这里会显示AI调音后的音频", 'accordion_header': "(高级)查看 AI 定制的 EQ 参数", 'err_no_file': "哎呀,忘了上传MP3文件啦!",
33
+ 'info_no_pref': "您没有指定风格,将为您进行温和的细节优化。", 'status_analyzing': "`[AI分析师]`:收到!正在分析您的音频... ⏳",
34
+ 'status_analysis_failed': "AI分析失败: {e}。将使用默认调音策略。", 'status_understanding': "`[AI分析师]`:分析完成!\n> {analysis}\n\n`[AI调音师]`:正在理解{choice}并调整EQ... 🔊",
35
+ 'status_tuning': "`[AI调音师]`:好嘞!已经按您的要求调整好了!\n\n`[系统]`:正在生成音频... 🎶", 'status_done': "`[系统]`:搞定!您的AI定制版音频已生成!🎉",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  },
37
  'en': {
38
+ 'title': "FeiMatrix AI Dynamic Equalizer", 'subtitle': "Upload a song, tell me the vibe you want, and I'll handle the rest!", 'lang_label': "Language / 语言",
39
+ 'step1_header': "Step 1: Upload Audio", 'upload_label': "Click or drag your MP3 file here",
40
+ 'step2_header': "Step 2: Tell Me Your Vibe", 'custom_input_label': "Describe the feeling you want in your own words (Recommended):",
41
+ 'custom_input_placeholder': "e.g., I want the guitar to be crisper and the drums more powerful...", 'quick_choice_label': "Or, quickly pick a preset style:",
42
+ 'quick_choices': [ "I want that 'thump-thump' heavy bass!", "Make the treble brighter and clearer", "Make the vocals stand out more", "I like a warm and rich sound", "Give me a live concert feeling", "Keep it natural, just add more detail", "None (use the input box above)", ],
43
+ 'default_choice': "None (use the input box above)", 'step3_header': "Step 3: Start Tuning", 'process_button': "Start AI Tuning!",
44
+ 'log_header': "AI Tuning Engineer's Log", 'log_initial': "`[System]`: Ready when you are, just upload a file~",
45
+ 'result_header': "Step 4: Listen to Your Custom Version", 'result_label': "Your AI-tuned audio will appear here",
46
+ 'accordion_header': "(Advanced) View AI-Customized EQ Parameters", 'err_no_file': "Oops, you forgot to upload the MP3 file!",
47
+ 'info_no_pref': "You didn't specify a style, so I'll perform a gentle detail enhancement.", 'status_analyzing': "`[AI Analyst]`: Roger that! Analyzing your audio... ⏳",
48
+ 'status_analysis_failed': "AI analysis failed: {e}. Default tuning strategy will be used.", 'status_understanding': "`[AI Analyst]`: Analysis complete!\n> {analysis}\n\n`[AI Tuning Engineer]`: Understanding {choice} and adjusting EQ... 🔊",
49
+ 'status_tuning': "`[AI Tuning Engineer]`: Alright! Tuned to your request!\n\n`[System]`: Generating audio... 🎶", 'status_done': "`[System]`: All set! Your AI custom audio is ready! 🎉",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  }
51
  }
52
  LANG_MAP = {"简体中文": "zh", "English": "en"}
53
 
 
54
  def get_ai_tuned_eq_settings(audio_analysis_text, user_preference):
55
+ eq_values = [0.0] * len(EQ_BANDS_HZ); pref_lower = user_preference.lower()
 
56
  if "电子舞曲" in audio_analysis_text or "EDM" in audio_analysis_text: eq_values = [4.0, 2.5, -1.5, -0.5, 1.0, 2.0, 3.5, 4.0, 2.5, 1.0]
57
  elif "爵士乐" in audio_analysis_text or "warm" in audio_analysis_text: eq_values = [3.0, 1.5, -0.5, -1.0, 0.5, 1.5, 2.0, 3.0, 2.0, 0.5]
58
  elif "人声" in audio_analysis_text or "vocal" in audio_analysis_text: eq_values[4] += 0.5; eq_values[5] += 1.0
 
62
  if any(k in pref_lower for k in ["温暖", "warm", "rich", "soft"]): eq_values[1]+=1.5; eq_values[2]+=1.0; eq_values[6]-=0.5
63
  if any(k in pref_lower for k in ["空间", "space", "live", "concert"]): eq_values[6]+=1.0; eq_values[7]+=1.0; eq_values[4]-=0.5
64
  if any(k in pref_lower for k in ["自然", "natural", "original"]): [v*0.5 for v in eq_values]; eq_values[7]+=0.5
65
+ eq_values=[max(-EQ_RANGE_DB,min(EQ_RANGE_DB,v)) for v in eq_values]; return {f'{f} Hz':v for f,v in zip(EQ_BANDS_HZ, eq_values)}
 
66
 
67
  def apply_eq_to_audio(audio_path, eq_settings):
 
68
  try: audio = AudioSegment.from_file(audio_path)
69
  except Exception as e: print(f"Audio load error: {e}"); return None
70
  q_factor=1.414; filter_parts=[]
71
+ for band, gain in eq_settings.items():
72
+ if gain != 0: filter_parts.append(f"equalizer=f={band.split(' ')[0]}:width_type=q:w={q_factor}:g={gain}")
73
  if not filter_parts: return audio_path
74
  output_path = f"{os.path.splitext(audio_path)[0]}_eq.mp3"
75
  try:
76
  audio.export(output_path, format="mp3", parameters=["-af", ",".join(filter_parts)])
77
  return output_path
78
+ except Exception as e: print(f"EQ apply error: {e}"); raise gr.Error("Failed to apply EQ! This might be an issue with ffmpeg on the server.")
79
 
80
  def process_and_tune(audio_file, quick_choice, custom_input, lang_choice):
81
+ lang_code = LANG_MAP[lang_choice]; L = LANG[lang_code]
 
82
  if not audio_file: raise gr.Error(L['err_no_file'])
 
83
  if custom_input and custom_input.strip(): final_preference = custom_input
84
  elif L['default_choice'] not in quick_choice: final_preference = quick_choice
85
  else: final_preference = L['quick_choices'][-2]; gr.Info(L['info_no_pref'])
86
+ slider_updates={s: gr.update(value=0) for s in eq_sliders}
87
+ yield {status_log_md: gr.update(value=L['status_analyzing']), processed_audio_output: gr.update(value=None), eq_accordion: gr.update(visible=True, open=False), **slider_updates}
 
 
88
  try:
89
+ prompt = "Briefly analyze this audio's genre, mood, and key instruments."; response = gemini_model.generate_content([genai.upload_file(path=audio_file.name), prompt])
 
90
  audio_analysis_text = response.text or "(AI did not provide a detailed analysis)"
91
  except Exception as e: audio_analysis_text = L['status_analysis_failed'].format(e=e); gr.Warning(audio_analysis_text)
 
92
  choice_desc = f"“{final_preference}”"
93
+ yield {status_log_md: gr.update(value=L['status_understanding'].format(analysis=audio_analysis_text, choice=choice_desc))}; time.sleep(1)
94
+ eq_settings = get_ai_tuned_eq_settings(audio_analysis_text, final_preference); slider_updates = {s: gr.update(value=v) for s, v in zip(eq_sliders, eq_settings.values())}
95
+ yield {status_log_md: gr.update(value=L['status_tuning']), **slider_updates}; time.sleep(1)
 
 
 
 
 
96
  eq_audio_path = apply_eq_to_audio(audio_file.name, eq_settings)
97
  if not eq_audio_path: raise gr.Error("Audio processing failed!")
 
98
  yield {status_log_md: gr.update(value=L['status_done']), processed_audio_output: gr.update(value=eq_audio_path, label=L['result_label'], autoplay=True), eq_accordion: gr.update(open=False)}
99
 
100
  def update_language(lang_choice):
101
+ L = LANG[LANG_MAP[lang_choice]]
 
102
  return {
103
+ title_md: gr.update(value=f"# {L['title']}"), subtitle_md: gr.update(value=L['subtitle']), step1_header_md: gr.update(value=f"### **{L['step1_header']}**"),
104
+ audio_input: gr.update(label=L['upload_label']), step2_header_md: gr.update(value=f"### **{L['step2_header']}**"), custom_input: gr.update(label=L['custom_input_label'], placeholder=L['custom_input_placeholder']),
105
+ quick_choice: gr.update(label=L['quick_choice_label'], choices=L['quick_choices'], value=L['default_choice']), step3_header_md: gr.update(value=f"### **{L['step3_header']}**"),
106
+ process_button: gr.update(value=L['process_button']), log_header_md: gr.update(value=f"### **{L['log_header']}**"), status_log_md: gr.update(value=L['log_initial']),
107
+ result_header_md: gr.update(value=f"### **{L['result_header']}**"), processed_audio_output: gr.update(label=L['result_label']), eq_accordion: gr.update(label=L['accordion_header']),
 
 
 
 
 
 
 
 
 
108
  }
109
 
 
110
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
111
  lang_switcher = gr.Radio(choices=["简体中文", "English"], value="简体中文", label="Language / 语言", info="选择界面语言 / Select UI Language")
 
112
  title_md = gr.Markdown("# FeiMatrix 智能动态调音")
113
  subtitle_md = gr.Markdown("上传一首歌,告诉我你想要的感觉,剩下的交给我!")
 
114
  with gr.Column():
115
+ step1_header_md = gr.Markdown("### **第一步:上传音频**"); audio_input = gr.File(label="点击或拖拽 MP3 文件到这里", type="filepath", file_types=[".mp3"])
116
+ step2_header_md = gr.Markdown("### **第二步:告诉我你的感觉**"); custom_input = gr.Textbox(label="用你自己的话描述想要的感觉(推荐):", placeholder="例如:我想要吉他声更清脆,鼓声更有力...", lines=2)
 
 
 
117
  quick_choice = gr.Radio(label="或者,快速选择一个预设风格:", choices=LANG['zh']['quick_choices'], value=LANG['zh']['default_choice'])
118
+ step3_header_md = gr.Markdown("### **第三步:开始调音**"); process_button = gr.Button("开始智能调音!", variant="primary")
119
+ log_header_md = gr.Markdown("### **AI 调音师工作日志**"); status_log_md = gr.Markdown("`[系统]`:我准备好啦,等你上传文件哦~")
120
+ result_header_md = gr.Markdown("### **第四步:聆听您的定制版**"); processed_audio_output = gr.Audio(label="这里会显示AI调音后的音频", type="filepath", interactive=True)
 
 
 
 
 
 
 
121
  with gr.Accordion("(高级)查看 AI 定制的 EQ 参数", open=False, visible=False) as eq_accordion:
122
+ eq_sliders = [gr.Slider(minimum=-EQ_RANGE_DB, maximum=EQ_RANGE_DB, value=0, step=0.5, label=f"{f} Hz", interactive=False) for f in EQ_BANDS_HZ]
 
 
 
123
  all_ui_outputs = [title_md, subtitle_md, step1_header_md, audio_input, step2_header_md, custom_input, quick_choice, step3_header_md, process_button, log_header_md, status_log_md, result_header_md, processed_audio_output, eq_accordion]
124
  lang_switcher.change(fn=update_language, inputs=lang_switcher, outputs=all_ui_outputs, queue=False)
125
  process_button.click(fn=process_and_tune, inputs=[audio_input, quick_choice, custom_input, lang_switcher], outputs=[status_log_md, processed_audio_output, eq_accordion, *eq_sliders])
packages.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ffmpeg