404Brain-Not-Found-yeah commited on
Commit
71623fc
·
verified ·
1 Parent(s): 5f79099

Upload app_gradio.py

Browse files
Files changed (1) hide show
  1. app_gradio.py +369 -0
app_gradio.py ADDED
@@ -0,0 +1,369 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ from predict import predict_healing_music
4
+ import train_model
5
+ import logging
6
+ import tempfile
7
+ import time
8
+ import shutil
9
+ import socket
10
+ import joblib
11
+
12
+ # Set up logging
13
+ logging.basicConfig(
14
+ level=logging.INFO,
15
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
16
+ )
17
+ logger = logging.getLogger(__name__)
18
+
19
+ def find_free_port(start_port=7860, max_port=7960):
20
+ """Find a free port in the given range."""
21
+ for port in range(start_port, max_port + 1):
22
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
23
+ try:
24
+ s.bind(('', port))
25
+ return port
26
+ except OSError:
27
+ continue
28
+ return None
29
+
30
+ # Ensure model directory exists
31
+ model_dir = os.path.join(os.path.dirname(__file__), "models")
32
+ os.makedirs(model_dir, exist_ok=True)
33
+
34
+ # Model file paths
35
+ model_path = os.path.join(model_dir, "model.joblib")
36
+ scaler_path = os.path.join(model_dir, "scaler.joblib")
37
+
38
+ # Check if model exists
39
+ if not os.path.exists(model_path) or not os.path.exists(scaler_path):
40
+ print('First run: Training the model...')
41
+ try:
42
+ train_model.train_and_evaluate_model()
43
+ print('Model training completed!')
44
+ except Exception as e:
45
+ print(f'Model training failed: {str(e)}')
46
+ raise e
47
+
48
+ def process_audio(audio_path):
49
+ """
50
+ Process and analyze the audio file
51
+ """
52
+ if audio_path is None:
53
+ return None, None, None, "Please upload an audio file"
54
+
55
+ model_dir = os.path.join(os.path.dirname(__file__), "models")
56
+ model_path = os.path.join(model_dir, "model.joblib")
57
+ scaler_path = os.path.join(model_dir, "scaler.joblib")
58
+
59
+ try:
60
+ # Load model and scaler
61
+ model = joblib.load(model_path)
62
+ scaler = joblib.load(scaler_path)
63
+
64
+ tmp_file = None
65
+ try:
66
+ # Create temporary file
67
+ suffix = os.path.splitext(audio_path)[1]
68
+ tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=suffix)
69
+ shutil.copy2(audio_path, tmp_file.name)
70
+
71
+ # Make prediction
72
+ healing_probability = predict_healing_music(tmp_file.name)
73
+
74
+ if healing_probability is not None:
75
+ # Calculate percentage
76
+ healing_percentage = healing_probability * 100
77
+
78
+ # Generate description
79
+ if healing_percentage >= 75:
80
+ description = "This music has strong healing properties! ✨"
81
+ color = "#15803d" # Dark green
82
+ elif healing_percentage >= 50:
83
+ description = "This music has moderate healing effects. 🌟"
84
+ color = "#0369a1" # Dark blue
85
+ else:
86
+ description = "This music has limited healing potential. 🎵"
87
+ color = "#b91c1c" # Dark red
88
+
89
+ return f"{healing_percentage:.1f}%", f'<div style="background-color: {color}; color: white; padding: 1rem; border-radius: 8px; text-align: center;">{description}</div>', None, None
90
+ else:
91
+ return "Error", "Error analyzing file. Please ensure it's a valid MP3 or WAV file.", None, None
92
+
93
+ except Exception as e:
94
+ logger.error(f"Error during analysis: {str(e)}")
95
+ return "Error", f"An unexpected error occurred: {str(e)}", None, None
96
+
97
+ finally:
98
+ # Clean up temporary file
99
+ if tmp_file is not None:
100
+ try:
101
+ tmp_file.close()
102
+ os.unlink(tmp_file.name)
103
+ except Exception as e:
104
+ logger.error(f"Failed to clean up temporary file: {str(e)}")
105
+
106
+ except Exception as e:
107
+ logger.error(f"Error during model loading: {str(e)}")
108
+ return "Error", f"An unexpected error occurred: {str(e)}", None, None
109
+
110
+ def analyze_audio(audio):
111
+ """Analyze the audio file"""
112
+ try:
113
+ if audio is None:
114
+ return [
115
+ gr.update(visible=False), # results
116
+ gr.update(visible=False), # analyzing
117
+ "", # healing_index
118
+ "" # result_text
119
+ ]
120
+
121
+ # Show analyzing status first
122
+ yield [
123
+ gr.update(visible=False), # results
124
+ gr.update(visible=True), # analyzing
125
+ "", # healing_index
126
+ "" # result_text
127
+ ]
128
+
129
+ # Process audio and get results
130
+ index, desc, _, _ = process_audio(audio)
131
+ desc_with_hint = f'{desc}<div style="margin-top: 1rem; color: #9ca3af; font-size: 0.9rem;">To analyze another file, please refresh the page</div>'
132
+
133
+ # Return final results
134
+ yield [
135
+ gr.update(visible=True), # results
136
+ gr.update(visible=False), # analyzing
137
+ index, # healing_index
138
+ desc_with_hint # result_text
139
+ ]
140
+
141
+ except Exception as e:
142
+ logger.error(f"Error in analyze_audio: {str(e)}")
143
+ yield [
144
+ gr.update(visible=True), # results
145
+ gr.update(visible=False), # analyzing
146
+ "Error", # healing_index
147
+ f"An error occurred: {str(e)}" # result_text
148
+ ]
149
+
150
+ # Custom CSS styles
151
+ custom_css = """
152
+ .gradio-container {
153
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
154
+ max-width: 800px !important;
155
+ margin: auto;
156
+ padding: 0 1rem;
157
+ background-color: #0f1117;
158
+ }
159
+ .container {
160
+ max-width: 700px;
161
+ margin: 0 auto;
162
+ padding-top: 2rem;
163
+ }
164
+ .header {
165
+ text-align: center;
166
+ margin-bottom: 1rem;
167
+ width: 100%;
168
+ display: flex;
169
+ justify-content: center;
170
+ align-items: center;
171
+ }
172
+ .title {
173
+ font-size: 2.5rem !important;
174
+ font-weight: 700 !important;
175
+ color: white !important;
176
+ margin: 0 !important;
177
+ line-height: 1.2 !important;
178
+ text-align: center !important;
179
+ white-space: nowrap !important;
180
+ }
181
+ .subtitle {
182
+ font-size: 1.2rem !important;
183
+ text-align: center;
184
+ color: #9ca3af !important;
185
+ margin-top: 0.5rem !important;
186
+ max-width: 800px;
187
+ margin-left: auto;
188
+ margin-right: auto;
189
+ white-space: nowrap !important;
190
+ }
191
+ .upload-box {
192
+ background-color: #1f2937;
193
+ border-radius: 12px;
194
+ padding: 2rem;
195
+ margin-bottom: 1rem;
196
+ border: 2px dashed #374151;
197
+ transition: all 0.3s ease;
198
+ }
199
+ .upload-box:hover {
200
+ border-color: #3b82f6;
201
+ box-shadow: 0 0 10px rgba(59, 130, 246, 0.2);
202
+ }
203
+ .upload-area {
204
+ display: flex;
205
+ flex-direction: column;
206
+ align-items: center;
207
+ justify-content: center;
208
+ gap: 1rem;
209
+ padding: 1.5rem 0;
210
+ }
211
+ .icon-text-container {
212
+ display: inline-flex;
213
+ align-items: center;
214
+ justify-content: center;
215
+ gap: 0.2rem;
216
+ white-space: nowrap;
217
+ }
218
+ .upload-icon {
219
+ color: #9ca3af;
220
+ font-size: 2rem;
221
+ line-height: 1;
222
+ margin-right: 0.1rem;
223
+ }
224
+ .upload-text {
225
+ color: white;
226
+ font-size: 1.1rem;
227
+ font-weight: 500;
228
+ line-height: 1;
229
+ }
230
+ .upload-hint {
231
+ color: #6b7280 !important;
232
+ font-size: 0.85rem !important;
233
+ margin-top: 0.5rem !important;
234
+ font-style: italic !important;
235
+ }
236
+ .progress-area {
237
+ margin: 1rem 0;
238
+ background-color: #1f2937;
239
+ border-radius: 12px;
240
+ padding: 1.5rem;
241
+ text-align: center;
242
+ }
243
+ .progress-text {
244
+ color: #60a5fa !important;
245
+ font-size: 1.2rem !important;
246
+ font-weight: 500 !important;
247
+ margin: 0 !important;
248
+ }
249
+ .results-container {
250
+ background-color: #1f2937;
251
+ border-radius: 12px;
252
+ padding: 1.25rem;
253
+ margin-top: 1rem;
254
+ animation: fadeIn 0.5s ease;
255
+ }
256
+ .result-title {
257
+ color: white !important;
258
+ font-size: 1.25rem !important;
259
+ font-weight: 600 !important;
260
+ margin-bottom: 0.5rem !important;
261
+ }
262
+ .healing-index {
263
+ font-size: 2.5rem !important;
264
+ font-weight: 700 !important;
265
+ text-align: center;
266
+ color: white !important;
267
+ margin: 0.5rem 0 !important;
268
+ animation: scaleIn 0.5s ease;
269
+ }
270
+ .result-text {
271
+ animation: slideIn 0.5s ease;
272
+ }
273
+ @keyframes fadeIn {
274
+ from { opacity: 0; transform: translateY(20px); }
275
+ to { opacity: 1; transform: translateY(0); }
276
+ }
277
+ @keyframes scaleIn {
278
+ from { transform: scale(0.8); opacity: 0; }
279
+ to { transform: scale(1); opacity: 1; }
280
+ }
281
+ @keyframes slideIn {
282
+ from { transform: translateY(10px); opacity: 0; }
283
+ to { transform: translateY(0); opacity: 1; }
284
+ }
285
+ """
286
+
287
+ # Create Gradio interface
288
+ with gr.Blocks(
289
+ title="Healing Music Classifier",
290
+ css=custom_css,
291
+ theme=gr.themes.Default()
292
+ ) as demo:
293
+ with gr.Column(elem_classes="container"):
294
+ with gr.Row(elem_classes="header"):
295
+ gr.Markdown("&#127925; Healing Music Classifier", elem_classes="title")
296
+
297
+ gr.Markdown(
298
+ "Upload your music file, and our model will analyze its healing potential!",
299
+ elem_classes="subtitle"
300
+ )
301
+
302
+ with gr.Column(elem_classes="upload-box"):
303
+ with gr.Column(elem_classes="upload-area"):
304
+ gr.Markdown("&#9729;&#65039; Drop your audio file here", elem_classes="icon-text-container")
305
+ audio_input = gr.Audio(
306
+ label="Audio Input",
307
+ sources=["upload"],
308
+ type="filepath",
309
+ elem_classes="audio-input",
310
+ interactive=True,
311
+ label_visible=False,
312
+ text="Drop audio file here or click to upload"
313
+ )
314
+ gr.Markdown("Limit 200MB per file • MP3, WAV", elem_classes="upload-hint")
315
+
316
+ # Add analyzing status
317
+ with gr.Column(elem_classes="analyzing-status", visible=False) as analyzing:
318
+ gr.Markdown(
319
+ """<div style="display: flex; align-items: center; justify-content: center; gap: 0.5rem;">
320
+ <div class="loading-spinner"></div>
321
+ <span style="color: #60a5fa;">Analyzing your music...</span>
322
+ </div>""",
323
+ elem_classes="analyzing-text"
324
+ )
325
+
326
+ with gr.Column(elem_classes="results-container", visible=False) as results:
327
+ gr.Markdown("Analysis Results", elem_classes="result-title")
328
+ healing_index = gr.Markdown("", elem_classes="healing-index")
329
+ result_text = gr.Markdown("", elem_classes="result-text")
330
+
331
+ # Add loading spinner CSS
332
+ demo.load(None, None, None, _js="""
333
+ () => {
334
+ const style = document.createElement('style');
335
+ style.textContent = `
336
+ .loading-spinner {
337
+ width: 20px;
338
+ height: 20px;
339
+ border: 3px solid #60a5fa;
340
+ border-top: 3px solid transparent;
341
+ border-radius: 50%;
342
+ animation: spin 1s linear infinite;
343
+ }
344
+ @keyframes spin {
345
+ 0% { transform: rotate(0deg); }
346
+ 100% { transform: rotate(360deg); }
347
+ }
348
+ `;
349
+ document.head.appendChild(style);
350
+ }
351
+ """)
352
+
353
+ # Audio analysis event
354
+ audio_input.upload(
355
+ fn=analyze_audio,
356
+ inputs=[audio_input],
357
+ outputs=[
358
+ results,
359
+ analyzing,
360
+ healing_index,
361
+ result_text
362
+ ],
363
+ queue=True
364
+ )
365
+
366
+ # Launch application
367
+ if __name__ == "__main__":
368
+ demo.launch() # 简化启动配置,让Hugging Face处理端口等
369
+