Janiopi commited on
Commit
5ab3542
·
verified ·
1 Parent(s): 8f5a5bf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +169 -110
app.py CHANGED
@@ -1,17 +1,20 @@
1
- # app.py - API FastAPI en Hugging Face Space
2
  from fastapi import FastAPI, File, UploadFile, HTTPException
3
  from fastapi.middleware.cors import CORSMiddleware
 
4
  from transformers import pipeline
5
  import tempfile
6
  import os
7
  import uvicorn
8
- import gradio as gr
9
- from threading import Thread
10
 
11
  # Crear app FastAPI
12
- app = FastAPI(title="Musical Instrument Detection API", version="1.0.0")
 
 
 
 
13
 
14
- # Configurar CORS para permitir requests desde Android
15
  app.add_middleware(
16
  CORSMiddleware,
17
  allow_origins=["*"],
@@ -20,136 +23,192 @@ app.add_middleware(
20
  allow_headers=["*"],
21
  )
22
 
23
- # Cargar modelo
24
- try:
25
- classifier = pipeline("audio-classification", model="Janiopi/detector_de_instrumentos_v1")
26
- print("✅ Modelo cargado exitosamente")
27
- except Exception as e:
28
- print(f"❌ Error cargando modelo: {e}")
29
- classifier = None
30
 
31
- @app.get("/")
 
 
 
 
 
 
 
 
 
 
 
 
32
  async def root():
33
- return {
34
- "message": "Musical Instrument Detection API",
35
- "status": "online",
36
- "model_loaded": classifier is not None,
37
- "endpoints": {
38
- "detect": "/detect (POST)",
39
- "health": "/health (GET)"
40
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  }
 
 
 
 
 
 
 
 
42
 
43
  @app.get("/health")
44
  async def health_check():
 
45
  return {
46
- "status": "ok",
47
  "model_loaded": classifier is not None,
48
- "message": "API funcionando correctamente"
 
 
49
  }
50
 
51
  @app.post("/detect")
52
  async def detect_instrument(audio: UploadFile = File(...)):
53
  """
54
- Endpoint para detectar instrumentos musicales en audio
 
 
 
 
 
 
55
  """
56
  try:
 
57
  if classifier is None:
58
- raise HTTPException(status_code=503, detail="Modelo no disponible")
 
 
 
59
 
60
  # Verificar tipo de archivo
61
- if not audio.content_type.startswith('audio/'):
62
- raise HTTPException(status_code=400, detail="El archivo debe ser de audio")
 
 
 
 
 
 
 
 
 
63
 
64
- # Guardar archivo temporalmente
65
  with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as temp_file:
66
- content = await audio.read()
67
  temp_file.write(content)
68
  temp_path = temp_file.name
69
 
70
- print(f"📁 Procesando archivo: {audio.filename}, tamaño: {len(content)} bytes")
71
-
72
- # Procesar con el modelo
73
- results = classifier(temp_path)
74
-
75
- # Limpiar archivo temporal
76
- os.unlink(temp_path)
77
-
78
- # Formatear resultados
79
- formatted_results = []
80
- for result in results:
81
- formatted_results.append({
82
- "label": result["label"],
83
- "score": round(result["score"], 4)
84
- })
85
-
86
- print(f"✅ Resultados: {formatted_results}")
87
-
88
- return {
89
- "success": True,
90
- "results": formatted_results,
91
- "filename": audio.filename
92
- }
 
 
 
 
 
 
 
93
 
 
 
94
  except Exception as e:
95
- print(f"❌ Error: {e}")
96
- raise HTTPException(status_code=500, detail=f"Error procesando audio: {str(e)}")
97
-
98
- # Crear interfaz Gradio simple para visualización
99
- def gradio_interface():
100
- with gr.Blocks(title="Musical Instrument Detection API") as demo:
101
- gr.Markdown("# 🎵 Musical Instrument Detection API")
102
- gr.Markdown("## API Endpoints:")
103
- gr.Markdown("""
104
- - **GET** `/` - Información general
105
- - **GET** `/health` - Estado del servicio
106
- - **POST** `/detect` - Detectar instrumentos (enviar archivo audio)
107
-
108
- ### Uso desde Android:
109
- ```
110
- POST https://tu-usuario-musical-detector-api.hf.space/detect
111
- Content-Type: multipart/form-data
112
- Body: audio file
113
- ```
114
- """)
115
-
116
- # Interfaz simple para probar
117
- with gr.Row():
118
- audio_input = gr.Audio(type="filepath", label="Probar detección")
119
- output_text = gr.Textbox(label="Resultado")
120
-
121
- def test_detection(audio_path):
122
- if audio_path and classifier:
123
- try:
124
- results = classifier(audio_path)
125
- output = "Instrumentos detectados:\n"
126
- for result in results:
127
- output += f"- {result['label']}: {result['score']:.4f}\n"
128
- return output
129
- except Exception as e:
130
- return f"Error: {e}"
131
- return "No se pudo procesar el audio"
132
-
133
- audio_input.change(test_detection, inputs=[audio_input], outputs=[output_text])
134
-
135
- return demo
136
-
137
- # Función para ejecutar FastAPI
138
- def run_fastapi():
139
- uvicorn.run(app, host="0.0.0.0", port=7860)
140
 
141
- # Función para ejecutar Gradio
142
- def run_gradio():
143
- demo = gradio_interface()
144
- demo.launch(server_name="0.0.0.0", server_port=7861, share=False)
 
 
 
 
145
 
 
146
  if __name__ == "__main__":
147
- # Ejecutar FastAPI en thread separado
148
- fastapi_thread = Thread(target=run_fastapi, daemon=True)
149
- fastapi_thread.start()
150
-
151
- print("🚀 FastAPI iniciado en puerto 7860")
152
- print("🎨 Gradio iniciado en puerto 7861")
153
-
154
- # Ejecutar Gradio en el hilo principal
155
- run_gradio()
 
1
+ # app.py - API FastAPI pura en Hugging Face Space
2
  from fastapi import FastAPI, File, UploadFile, HTTPException
3
  from fastapi.middleware.cors import CORSMiddleware
4
+ from fastapi.responses import HTMLResponse
5
  from transformers import pipeline
6
  import tempfile
7
  import os
8
  import uvicorn
 
 
9
 
10
  # Crear app FastAPI
11
+ app = FastAPI(
12
+ title="Musical Instrument Detection API",
13
+ description="API para detectar instrumentos musicales en audio",
14
+ version="1.0.0"
15
+ )
16
 
17
+ # Configurar CORS
18
  app.add_middleware(
19
  CORSMiddleware,
20
  allow_origins=["*"],
 
23
  allow_headers=["*"],
24
  )
25
 
26
+ # Variable global para el modelo
27
+ classifier = None
 
 
 
 
 
28
 
29
+ @app.on_event("startup")
30
+ async def startup_event():
31
+ """Cargar modelo al iniciar la aplicación"""
32
+ global classifier
33
+ try:
34
+ print("🔄 Cargando modelo...")
35
+ classifier = pipeline("audio-classification", model="Janiopi/detector_de_instrumentos_v1")
36
+ print("✅ Modelo cargado exitosamente")
37
+ except Exception as e:
38
+ print(f"❌ Error cargando modelo: {e}")
39
+ classifier = None
40
+
41
+ @app.get("/", response_class=HTMLResponse)
42
  async def root():
43
+ """Página principal con documentación"""
44
+ html_content = """
45
+ <!DOCTYPE html>
46
+ <html>
47
+ <head>
48
+ <title>Musical Instrument Detection API</title>
49
+ <style>
50
+ body { font-family: Arial, sans-serif; margin: 40px; }
51
+ .endpoint { background: #f0f0f0; padding: 10px; margin: 10px 0; border-radius: 5px; }
52
+ .method { color: white; padding: 2px 8px; border-radius: 3px; font-weight: bold; }
53
+ .get { background: #61affe; }
54
+ .post { background: #49cc90; }
55
+ </style>
56
+ </head>
57
+ <body>
58
+ <h1>🎵 Musical Instrument Detection API</h1>
59
+ <p>API para detectar instrumentos musicales (Guitarra, Piano, Batería)</p>
60
+
61
+ <h2>📡 Endpoints Disponibles:</h2>
62
+
63
+ <div class="endpoint">
64
+ <span class="method get">GET</span> <strong>/health</strong>
65
+ <p>Verificar estado del servicio y modelo</p>
66
+ </div>
67
+
68
+ <div class="endpoint">
69
+ <span class="method post">POST</span> <strong>/detect</strong>
70
+ <p>Detectar instrumentos en archivo de audio</p>
71
+ <p><strong>Content-Type:</strong> multipart/form-data</p>
72
+ <p><strong>Parámetro:</strong> audio (archivo)</p>
73
+ </div>
74
+
75
+ <div class="endpoint">
76
+ <span class="method get">GET</span> <strong>/docs</strong>
77
+ <p>Documentación interactiva de la API (Swagger)</p>
78
+ </div>
79
+
80
+ <h2>🔗 Links útiles:</h2>
81
+ <ul>
82
+ <li><a href="/health">Health Check</a></li>
83
+ <li><a href="/docs">Documentación Swagger</a></li>
84
+ <li><a href="/redoc">Documentación ReDoc</a></li>
85
+ </ul>
86
+
87
+ <h2>📱 Uso desde Android:</h2>
88
+ <pre style="background: #f8f8f8; padding: 15px; border-radius: 5px;">
89
+ POST https://janiopi-musical-detector-api.hf.space/detect
90
+ Content-Type: multipart/form-data
91
+ Body: audio file (campo "audio")
92
+
93
+ Respuesta:
94
+ {
95
+ "success": true,
96
+ "results": [
97
+ {
98
+ "label": "Sound_Guitar",
99
+ "score": 0.8547
100
  }
101
+ ],
102
+ "filename": "audio.wav"
103
+ }
104
+ </pre>
105
+ </body>
106
+ </html>
107
+ """
108
+ return html_content
109
 
110
  @app.get("/health")
111
  async def health_check():
112
+ """Verificar estado del servicio"""
113
  return {
114
+ "status": "online",
115
  "model_loaded": classifier is not None,
116
+ "message": "API funcionando correctamente",
117
+ "model_info": "Janiopi/detector_de_instrumentos_v1",
118
+ "supported_instruments": ["Guitar", "Piano", "Drum"]
119
  }
120
 
121
  @app.post("/detect")
122
  async def detect_instrument(audio: UploadFile = File(...)):
123
  """
124
+ Detectar instrumentos musicales en archivo de audio
125
+
126
+ Args:
127
+ audio: Archivo de audio (WAV, MP3, etc.)
128
+
129
+ Returns:
130
+ JSON con resultados de detección
131
  """
132
  try:
133
+ # Verificar si el modelo está cargado
134
  if classifier is None:
135
+ raise HTTPException(
136
+ status_code=503,
137
+ detail="Modelo no disponible. Intenta más tarde."
138
+ )
139
 
140
  # Verificar tipo de archivo
141
+ if not audio.content_type or not audio.content_type.startswith('audio/'):
142
+ raise HTTPException(
143
+ status_code=400,
144
+ detail=f"Tipo de archivo inválido: {audio.content_type}. Debe ser audio."
145
+ )
146
+
147
+ print(f"📁 Procesando: {audio.filename} ({audio.content_type})")
148
+
149
+ # Leer y guardar archivo temporalmente
150
+ content = await audio.read()
151
+ print(f"📏 Tamaño: {len(content)} bytes")
152
 
 
153
  with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as temp_file:
 
154
  temp_file.write(content)
155
  temp_path = temp_file.name
156
 
157
+ try:
158
+ # Procesar con el modelo
159
+ print("🤖 Ejecutando modelo...")
160
+ results = classifier(temp_path)
161
+ print(f"🎯 Resultados raw: {results}")
162
+
163
+ # Formatear resultados
164
+ formatted_results = []
165
+ for result in results:
166
+ formatted_results.append({
167
+ "label": result["label"],
168
+ "score": round(float(result["score"]), 4)
169
+ })
170
+
171
+ # Ordenar por score descendente
172
+ formatted_results.sort(key=lambda x: x["score"], reverse=True)
173
+
174
+ print(f"✅ Resultados formateados: {formatted_results}")
175
+
176
+ return {
177
+ "success": True,
178
+ "results": formatted_results,
179
+ "filename": audio.filename,
180
+ "processed_size_bytes": len(content)
181
+ }
182
+
183
+ finally:
184
+ # Limpiar archivo temporal
185
+ if os.path.exists(temp_path):
186
+ os.unlink(temp_path)
187
 
188
+ except HTTPException:
189
+ raise
190
  except Exception as e:
191
+ print(f"❌ Error inesperado: {e}")
192
+ raise HTTPException(
193
+ status_code=500,
194
+ detail=f"Error procesando audio: {str(e)}"
195
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
 
197
+ @app.get("/test")
198
+ async def test_endpoint():
199
+ """Endpoint de prueba para verificar conectividad"""
200
+ return {
201
+ "message": "API funcionando",
202
+ "timestamp": "2025-01-16",
203
+ "test": "ok"
204
+ }
205
 
206
+ # Ejecutar la aplicación
207
  if __name__ == "__main__":
208
+ print("🚀 Iniciando Musical Instrument Detection API...")
209
+ uvicorn.run(
210
+ app,
211
+ host="0.0.0.0",
212
+ port=7860,
213
+ log_level="info"
214
+ )