aifeifei798 commited on
Commit
6a441dc
·
verified ·
1 Parent(s): 4164435

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +131 -131
app.py CHANGED
@@ -1,131 +1,131 @@
1
- # app.py (Final Version with Download Feature)
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
- raise ValueError("Hugging Face Secret 'GOOGLE_API_KEY' not found!")
13
-
14
- genai.configure(api_key=GOOGLE_API_KEY)
15
- gemini_model = genai.GenerativeModel('gemini-1.5-flash-latest')
16
-
17
- EQ_BANDS_HZ = [60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000]
18
- EQ_RANGE_DB = 12
19
-
20
- # --- 1. 双语文本库 / Bilingual Text Library (已更新提示信息) ---
21
- LANG = {
22
- 'zh': {
23
- 'title': "FeiMatrix 智能动态调音", 'subtitle': "上传一首歌,告诉我你想要的感觉,剩下的交给我!", 'lang_label': "语言 / Language",
24
- 'step1_header': "第一步:上传音频", 'upload_label': "点击或拖拽 MP3 文件到这里",
25
- 'step2_header': "第二步:告诉我你的感觉", 'custom_input_label': "用你自己的话描述想要的感觉(推荐):",
26
- 'custom_input_placeholder': "例如:我想要吉他声更清脆,鼓声更有力...", 'quick_choice_label': "或者,快速选择一个预设风格:",
27
- 'quick_choices': [ "我想要咚咚咚的重低音!", "让高音更亮、更清楚", "让唱歌的声音更突出", "我喜欢温暖、厚实的感觉", "给我一种现场演唱会的空间感", "保持原汁原味,但细节多一点", "无 (使用上面的输入框)", ],
28
- 'default_choice': "无 (使用上面的输入框)", 'step3_header': "第三步:开始调音", 'process_button': "开始智能调音!",
29
- 'log_header': "AI 调音师工作日志", 'log_initial': "`[系统]`:我准备好啦,等你上传文件哦~", 'result_header': "第四步:聆听并下载您的定制版",
30
- 'result_label': "这里会显示AI调音后的音频", 'accordion_header': "(高级)查看 AI 定制的 EQ 参数", 'err_no_file': "哎呀,忘了上传MP3文件啦!",
31
- 'info_no_pref': "您没有指定风格,将为您进行温和的细节优化。", 'status_analyzing': "`[AI分析师]`:收到!正在分析您的音频... ⏳",
32
- 'status_analysis_failed': "AI分析失败: {e}。将使用默认调音策略。", 'status_understanding': "`[AI分析师]`:分析完成!\n> {analysis}\n\n`[AI调音师]`:正在理解{choice}并调整EQ... 🔊",
33
- 'status_tuning': "`[AI调音师]`:好嘞!已经按您的要求调整好了!\n\n`[系统]`:正在生成音频... 🎶",
34
- # --- 修改点 1: 更新完成提示 ---
35
- 'status_done': "`[系统]`:搞定!您的AI定制版音频已生成!🎉\n(点击播放器右侧的 **⋮** 即可下载)",
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~", 'result_header': "Step 4: Listen & Download Your Custom Version",
45
- 'result_label': "Your AI-tuned audio will appear here", 'accordion_header': "(Advanced) View AI-Customized EQ Parameters", 'err_no_file': "Oops, you forgot to upload the MP3 file!",
46
- '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... ⏳",
47
- '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... 🔊",
48
- 'status_tuning': "`[AI Tuning Engineer]`: Alright! Tuned to your request!\n\n`[System]`: Generating audio... 🎶",
49
- # --- 修改点 1: 更新完成提示 ---
50
- 'status_done': "`[System]`: All set! Your AI custom audio is ready! 🎉\n(Click the **⋮** icon on the right of the player to download)",
51
- }
52
- }
53
- LANG_MAP = {"简体中文": "zh", "English": "en"}
54
-
55
- def get_ai_tuned_eq_settings(audio_analysis_text, user_preference):
56
- eq_values = [0.0] * len(EQ_BANDS_HZ); pref_lower = user_preference.lower()
57
- 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]
58
- 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]
59
- elif "人声" in audio_analysis_text or "vocal" in audio_analysis_text: eq_values[4] += 0.5; eq_values[5] += 1.0
60
- if any(k in pref_lower for k in ["低音", "bass", "thump", "punch", "蹦迪"]): eq_values[0] += 3.0; eq_values[1] += 1.5
61
- if any(k in pref_lower for k in ["高音", "treble", "bright", "clear", "crisp"]): eq_values[6]+=1.5; eq_values[7]+=2.0; eq_values[8]+=1.0
62
- if any(k in pref_lower for k in ["人声", "vocal", "singing", "lyrics"]): eq_values[4]+=1.5; eq_values[5]+=1.0; eq_values[3]-=0.5
63
- 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
64
- 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
65
- if any(k in pref_lower for k in ["自然", "natural", "original"]): [v*0.5 for v in eq_values]; eq_values[7]+=0.5
66
- 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)}
67
-
68
- def apply_eq_to_audio(audio_path, eq_settings):
69
- try: audio = AudioSegment.from_file(audio_path)
70
- except Exception as e: print(f"Audio load error: {e}"); return None
71
- q_factor=1.414; filter_parts=[]
72
- for band, gain in eq_settings.items():
73
- if gain != 0: filter_parts.append(f"equalizer=f={band.split(' ')[0]}:width_type=q:w={q_factor}:g={gain}")
74
- if not filter_parts: return audio_path
75
- output_path = f"{os.path.splitext(audio_path)[0]}_eq.mp3"
76
- try:
77
- audio.export(output_path, format="mp3", parameters=["-af", ",".join(filter_parts)])
78
- return output_path
79
- 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.")
80
-
81
- def process_and_tune(audio_file, quick_choice, custom_input, lang_choice):
82
- lang_code = LANG_MAP[lang_choice]; L = LANG[lang_code]
83
- if not audio_file: raise gr.Error(L['err_no_file'])
84
- if custom_input and custom_input.strip(): final_preference = custom_input
85
- elif L['default_choice'] not in quick_choice: final_preference = quick_choice
86
- else: final_preference = L['quick_choices'][-2]; gr.Info(L['info_no_pref'])
87
- slider_updates={s: gr.update(value=0) for s in eq_sliders}
88
- 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}
89
- try:
90
- prompt = "Briefly analyze this audio's genre, mood, and key instruments."; response = gemini_model.generate_content([genai.upload_file(path=audio_file.name), prompt])
91
- audio_analysis_text = response.text or "(AI did not provide a detailed analysis)"
92
- except Exception as e: audio_analysis_text = L['status_analysis_failed'].format(e=e); gr.Warning(audio_analysis_text)
93
- choice_desc = f"“{final_preference}”"
94
- yield {status_log_md: gr.update(value=L['status_understanding'].format(analysis=audio_analysis_text, choice=choice_desc))}; time.sleep(1)
95
- 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())}
96
- yield {status_log_md: gr.update(value=L['status_tuning']), **slider_updates}; time.sleep(1)
97
- eq_audio_path = apply_eq_to_audio(audio_file.name, eq_settings)
98
- if not eq_audio_path: raise gr.Error("Audio processing failed!")
99
- 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)}
100
-
101
- def update_language(lang_choice):
102
- L = LANG[LANG_MAP[lang_choice]]
103
- return {
104
- 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']}**"),
105
- 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']),
106
- 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']}**"),
107
- 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']),
108
- 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']),
109
- }
110
-
111
- with gr.Blocks(theme=gr.themes.Soft()) as demo:
112
- lang_switcher = gr.Radio(choices=["简体中文", "English"], value="简体中文", label="Language / 语言", info="选择界面语言 / Select UI Language")
113
- title_md = gr.Markdown("# FeiMatrix 智能动态调音")
114
- subtitle_md = gr.Markdown("上传一首歌,告诉我你想要的感觉,剩下的交给我!")
115
- with gr.Column():
116
- step1_header_md = gr.Markdown("### **第一步:上传音频**"); audio_input = gr.File(label="点击或拖拽 MP3 文件到这里", type="filepath", file_types=[".mp3"])
117
- step2_header_md = gr.Markdown("### **第二步:告诉我你的感觉**"); custom_input = gr.Textbox(label="用你自己的话描述想要的感觉(推荐):", placeholder="例如:我想要吉他声更清脆,鼓声更有力...", lines=2)
118
- quick_choice = gr.Radio(label="或者,快速选择一个预设风格:", choices=LANG['zh']['quick_choices'], value=LANG['zh']['default_choice'])
119
- step3_header_md = gr.Markdown("### **第三步:开始调音**"); process_button = gr.Button("开始智能调音!", variant="primary")
120
- log_header_md = gr.Markdown("### **AI 调音师工作日志**"); status_log_md = gr.Markdown("`[系统]`:我准备好啦,等你上传文件哦~")
121
- result_header_md = gr.Markdown("### **第四步:聆听并下载您的定制版**");
122
- # --- 修改点 2: 添加 show_download_button=True ---
123
- processed_audio_output = gr.Audio(label="这里会显示AI调音后的音频", type="filepath", interactive=True, show_download_button=True)
124
- with gr.Accordion("(高级)查看 AI 定制的 EQ 参数", open=False, visible=False) as eq_accordion:
125
- 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]
126
- 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]
127
- lang_switcher.change(fn=update_language, inputs=lang_switcher, outputs=all_ui_outputs, queue=False)
128
- 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])
129
-
130
- if __name__ == "__main__":
131
- demo.launch(debug=True)
 
1
+ # app.py (Final Version with Download Feature)
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
+ raise ValueError("Hugging Face Secret 'GOOGLE_API_KEY' not found!")
13
+
14
+ genai.configure(api_key=GOOGLE_API_KEY)
15
+ gemini_model = genai.GenerativeModel('gemini-1.5-flash-latest')
16
+
17
+ EQ_BANDS_HZ = [60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000]
18
+ EQ_RANGE_DB = 12
19
+
20
+ # --- 1. 双语文本库 / Bilingual Text Library (已更新提示信息) ---
21
+ LANG = {
22
+ 'zh': {
23
+ 'title': "FeiMatrix 智能动态调音", 'subtitle': "上传一首歌,告诉我你想要的感觉,剩下的交给我!", 'lang_label': "语言 / Language",
24
+ 'step1_header': "第一步:上传音频", 'upload_label': "点击或拖拽 MP3 文件到这里",
25
+ 'step2_header': "第二步:告诉我你的感觉", 'custom_input_label': "用你自己的话描述想要的感觉(推荐):",
26
+ 'custom_input_placeholder': "例如:我想要吉他声更清脆,鼓声更有力...", 'quick_choice_label': "或者,快速选择一个预设风格:",
27
+ 'quick_choices': [ "我想要咚咚咚的重低音!", "让高音更亮、更清楚", "让唱歌的声音更突出", "我喜欢温暖、厚实的感觉", "给我一种现场演唱会的空间感", "保持原汁原味,但细节多一点", "无 (使用上面的输入框)", ],
28
+ 'default_choice': "无 (使用上面的输入框)", 'step3_header': "第三步:开始调音", 'process_button': "开始智能调音!",
29
+ 'log_header': "AI 调音师工作日志", 'log_initial': "`[系统]`:我准备好啦,等你上传文件哦~", 'result_header': "第四步:聆听并下载您的定制版",
30
+ 'result_label': "这里会显示AI调音后的音频", 'accordion_header': "(高级)查看 AI 定制的 EQ 参数", 'err_no_file': "哎呀,忘了上传MP3文件啦!",
31
+ 'info_no_pref': "您没有指定风格,将为您进行温和的细节优化。", 'status_analyzing': "`[AI分析师]`:收到!正在分析您的音频... ⏳",
32
+ 'status_analysis_failed': "AI分析失败: {e}。将使用默认调音策略。", 'status_understanding': "`[AI分析师]`:分析完成!\n> {analysis}\n\n`[AI调音师]`:正在理解{choice}并调整EQ... 🔊",
33
+ 'status_tuning': "`[AI调音师]`:好嘞!已经按您的要求调整好了!\n\n`[系统]`:正在生成音频... 🎶",
34
+ # --- 修改点 1: 更新完成提示 ---
35
+ 'status_done': "`[系统]`:搞定!您的AI定制版音频已生成!🎉\n(点击播放器右侧的 **⋮** 即可下载)",
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~", 'result_header': "Step 4: Listen & Download Your Custom Version",
45
+ 'result_label': "Your AI-tuned audio will appear here", 'accordion_header': "(Advanced) View AI-Customized EQ Parameters", 'err_no_file': "Oops, you forgot to upload the MP3 file!",
46
+ '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... ⏳",
47
+ '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... 🔊",
48
+ 'status_tuning': "`[AI Tuning Engineer]`: Alright! Tuned to your request!\n\n`[System]`: Generating audio... 🎶",
49
+ # --- 修改点 1: 更新完成提示 ---
50
+ 'status_done': "`[System]`: All set! Your AI custom audio is ready! 🎉\n(Click the **⋮** icon on the right of the player to download)",
51
+ }
52
+ }
53
+ LANG_MAP = {"简体中文": "zh", "English": "en"}
54
+
55
+ def get_ai_tuned_eq_settings(audio_analysis_text, user_preference):
56
+ eq_values = [0.0] * len(EQ_BANDS_HZ); pref_lower = user_preference.lower()
57
+ 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]
58
+ 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]
59
+ elif "人声" in audio_analysis_text or "vocal" in audio_analysis_text: eq_values[4] += 0.5; eq_values[5] += 1.0
60
+ if any(k in pref_lower for k in ["低音", "bass", "thump", "punch", "蹦迪"]): eq_values[0] += 3.0; eq_values[1] += 1.5
61
+ if any(k in pref_lower for k in ["高音", "treble", "bright", "clear", "crisp"]): eq_values[6]+=1.5; eq_values[7]+=2.0; eq_values[8]+=1.0
62
+ if any(k in pref_lower for k in ["人声", "vocal", "singing", "lyrics"]): eq_values[4]+=1.5; eq_values[5]+=1.0; eq_values[3]-=0.5
63
+ 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
64
+ 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
65
+ if any(k in pref_lower for k in ["自然", "natural", "original"]): [v*0.5 for v in eq_values]; eq_values[7]+=0.5
66
+ 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)}
67
+
68
+ def apply_eq_to_audio(audio_path, eq_settings):
69
+ try: audio = AudioSegment.from_file(audio_path)
70
+ except Exception as e: print(f"Audio load error: {e}"); return None
71
+ q_factor=1.414; filter_parts=[]
72
+ for band, gain in eq_settings.items():
73
+ if gain != 0: filter_parts.append(f"equalizer=f={band.split(' ')[0]}:width_type=q:w={q_factor}:g={gain}")
74
+ if not filter_parts: return audio_path
75
+ output_path = f"{os.path.splitext(audio_path)[0]}_eq.mp3"
76
+ try:
77
+ audio.export(output_path, format="mp3", parameters=["-af", ",".join(filter_parts)])
78
+ return output_path
79
+ 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.")
80
+
81
+ def process_and_tune(audio_file, quick_choice, custom_input, lang_choice):
82
+ lang_code = LANG_MAP[lang_choice]; L = LANG[lang_code]
83
+ if not audio_file: raise gr.Error(L['err_no_file'])
84
+ if custom_input and custom_input.strip(): final_preference = custom_input
85
+ elif L['default_choice'] not in quick_choice: final_preference = quick_choice
86
+ else: final_preference = L['quick_choices'][-2]; gr.Info(L['info_no_pref'])
87
+ slider_updates={s: gr.update(value=0) for s in eq_sliders}
88
+ 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}
89
+ try:
90
+ prompt = "Briefly analyze this audio's genre, mood, and key instruments."; response = gemini_model.generate_content([genai.upload_file(path=audio_file.name), prompt])
91
+ audio_analysis_text = response.text or "(AI did not provide a detailed analysis)"
92
+ except Exception as e: audio_analysis_text = L['status_analysis_failed'].format(e=e); gr.Warning(audio_analysis_text)
93
+ choice_desc = f"“{final_preference}”"
94
+ yield {status_log_md: gr.update(value=L['status_understanding'].format(analysis=audio_analysis_text, choice=choice_desc))}; time.sleep(1)
95
+ 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())}
96
+ yield {status_log_md: gr.update(value=L['status_tuning']), **slider_updates}; time.sleep(1)
97
+ eq_audio_path = apply_eq_to_audio(audio_file.name, eq_settings)
98
+ if not eq_audio_path: raise gr.Error("Audio processing failed!")
99
+ 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)}
100
+
101
+ def update_language(lang_choice):
102
+ L = LANG[LANG_MAP[lang_choice]]
103
+ return {
104
+ 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']}**"),
105
+ 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']),
106
+ 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']}**"),
107
+ 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']),
108
+ 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']),
109
+ }
110
+
111
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
112
+ lang_switcher = gr.Radio(choices=["简体中文", "English"], value="简体中文", label="Language / 语言", info="选择界面语言 / Select UI Language")
113
+ title_md = gr.Markdown("# FeiMatrix 智能动态调音")
114
+ subtitle_md = gr.Markdown("上传一首歌,告诉我你想要的感觉,剩下的交给我!")
115
+ with gr.Column():
116
+ step1_header_md = gr.Markdown("### **第一步:上传音频**"); audio_input = gr.File(label="点击或拖拽 MP3 文件到这里", type="filepath", file_types=[".mp3"])
117
+ step2_header_md = gr.Markdown("### **第二步:告诉我你的感觉**"); custom_input = gr.Textbox(label="用你自己的话描述想要的感觉(推荐):", placeholder="例如:我想要吉他声更清脆,鼓声更有力...", lines=2)
118
+ quick_choice = gr.Radio(label="或者,快速选择一个预设风格:", choices=LANG['zh']['quick_choices'], value=LANG['zh']['default_choice'])
119
+ step3_header_md = gr.Markdown("### **第三步:开始调音**"); process_button = gr.Button("开始智能调音!", variant="primary")
120
+ log_header_md = gr.Markdown("### **AI 调音师工作日志**"); status_log_md = gr.Markdown("`[系统]`:我准备好啦,等你上传文件哦~")
121
+ result_header_md = gr.Markdown("### **第四步:聆听并下载您的定制版**");
122
+ # --- 修改点 2: 添加 show_download_button=True ---
123
+ processed_audio_output = gr.Audio(label="这里会显示AI调音后的音频", type="filepath", interactive=True, show_download_button=True)
124
+ with gr.Accordion("(高级)查看 AI 定制的 EQ 参数", open=False, visible=False) as eq_accordion:
125
+ 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]
126
+ 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]
127
+ lang_switcher.change(fn=update_language, inputs=lang_switcher, outputs=all_ui_outputs, queue=False)
128
+ 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])
129
+
130
+ if __name__ == "__main__":
131
+ demo.launch(mcp_server=True)