Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,24 +1,107 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
import requests
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
-
def score_vocal(audio_file):
|
| 7 |
-
# send audio to FastAPI endpoint internally
|
| 8 |
-
with open(audio_file.name, "rb") as f:
|
| 9 |
-
files = {"file": f}
|
| 10 |
-
response = requests.post(API_URL, files=files)
|
| 11 |
if response.status_code == 200:
|
| 12 |
-
return response.json()
|
| 13 |
else:
|
| 14 |
-
return f"Error
|
| 15 |
|
| 16 |
iface = gr.Interface(
|
| 17 |
-
fn=
|
| 18 |
-
inputs=gr.Audio(type="filepath"),
|
| 19 |
outputs=gr.Textbox(label="Vocal Fatigue Score"),
|
| 20 |
-
title="Auralis Vocal Fatigue
|
|
|
|
| 21 |
)
|
| 22 |
|
|
|
|
| 23 |
if __name__ == "__main__":
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import requests
|
| 3 |
+
from fastapi import FastAPI, APIRouter, Request, File, UploadFile, HTTPException, status
|
| 4 |
+
import time
|
| 5 |
+
import logging
|
| 6 |
+
import uvicorn
|
| 7 |
+
import os
|
| 8 |
+
import numpy as np
|
| 9 |
|
| 10 |
+
# --- Logging setup ---
|
| 11 |
+
logging.basicConfig(
|
| 12 |
+
level=logging.INFO,
|
| 13 |
+
format="%(asctime)s - %(levelname)s - %(message)s"
|
| 14 |
+
)
|
| 15 |
+
|
| 16 |
+
# --- FastAPI setup ---
|
| 17 |
+
app = FastAPI(
|
| 18 |
+
title="Auralis Vocal Fatigue Scoring API",
|
| 19 |
+
version="1.0",
|
| 20 |
+
docs_url="/doc",
|
| 21 |
+
redoc_url="/redoc",
|
| 22 |
+
openapi_url="/openapi.json"
|
| 23 |
+
)
|
| 24 |
+
|
| 25 |
+
@app.middleware("http")
|
| 26 |
+
async def log_requests(request: Request, call_next):
|
| 27 |
+
start = time.time()
|
| 28 |
+
response = await call_next(request)
|
| 29 |
+
duration = time.time() - start
|
| 30 |
+
logging.info(f"{request.method} {request.url.path} status_code={response.status_code} time={duration:.3f}")
|
| 31 |
+
return response
|
| 32 |
+
|
| 33 |
+
# --- FastAPI Routes ---
|
| 34 |
+
router = APIRouter(prefix="/api/v1/voice")
|
| 35 |
+
|
| 36 |
+
API_MODEL_URL = os.environ.get("MODEL_API_URL", "http://localhost:7860/api/v1/voice/score")
|
| 37 |
+
|
| 38 |
+
@router.post("/score")
|
| 39 |
+
async def score_voice(file: UploadFile = File(...)):
|
| 40 |
+
"""Direct API endpoint — calls the model scoring function."""
|
| 41 |
+
try:
|
| 42 |
+
# Save temp audio
|
| 43 |
+
temp_path = f"/tmp/{file.filename}"
|
| 44 |
+
with open(temp_path, "wb") as f:
|
| 45 |
+
f.write(await file.read())
|
| 46 |
+
|
| 47 |
+
# Call the model scoring
|
| 48 |
+
files = {"file": open(temp_path, "rb")}
|
| 49 |
+
import requests
|
| 50 |
+
response = requests.post(API_MODEL_URL, files=files)
|
| 51 |
+
files["file"].close()
|
| 52 |
+
|
| 53 |
+
if response.status_code == 200:
|
| 54 |
+
return response.json()
|
| 55 |
+
else:
|
| 56 |
+
raise HTTPException(status_code=response.status_code, detail=response.text)
|
| 57 |
+
|
| 58 |
+
except Exception as e:
|
| 59 |
+
logging.exception("Error in /score endpoint")
|
| 60 |
+
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
|
| 61 |
+
|
| 62 |
+
app.include_router(router)
|
| 63 |
+
|
| 64 |
+
@app.get("/health")
|
| 65 |
+
def health():
|
| 66 |
+
return {"status": "ok"}
|
| 67 |
+
|
| 68 |
+
@app.get("/")
|
| 69 |
+
def root():
|
| 70 |
+
return {"name": "Auralis Vocal Fatigue Scoring API", "status": "running", "health": "/health"}
|
| 71 |
+
|
| 72 |
+
# --- Gradio interface ---
|
| 73 |
+
def gradio_score(audio_file_path: str):
|
| 74 |
+
"""
|
| 75 |
+
Gradio wrapper: receives filepath and calls the FastAPI endpoint internally
|
| 76 |
+
"""
|
| 77 |
+
with open(audio_file_path, "rb") as f:
|
| 78 |
+
response = requests.post(API_MODEL_URL, files={"file": f})
|
| 79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
if response.status_code == 200:
|
| 81 |
+
return response.json().get("fatigue_score", "No score returned")
|
| 82 |
else:
|
| 83 |
+
return f"Error {response.status_code}: {response.text}"
|
| 84 |
|
| 85 |
iface = gr.Interface(
|
| 86 |
+
fn=gradio_score,
|
| 87 |
+
inputs=gr.Audio(type="filepath", label="Upload Audio"),
|
| 88 |
outputs=gr.Textbox(label="Vocal Fatigue Score"),
|
| 89 |
+
title="Auralis Vocal Fatigue Scoring",
|
| 90 |
+
description="Upload an audio file and get the fatigue score using the Auralis API."
|
| 91 |
)
|
| 92 |
|
| 93 |
+
# --- Run both FastAPI and Gradio in same container ---
|
| 94 |
if __name__ == "__main__":
|
| 95 |
+
import threading
|
| 96 |
+
|
| 97 |
+
# Launch Gradio in a separate thread
|
| 98 |
+
def launch_gradio():
|
| 99 |
+
iface.launch(server_name="0.0.0.0", server_port=int(os.environ.get("PORT", 7860)), share=False)
|
| 100 |
+
|
| 101 |
+
t = threading.Thread(target=launch_gradio)
|
| 102 |
+
t.start()
|
| 103 |
+
|
| 104 |
+
# Run FastAPI (Uvicorn) on same port (Gradio will handle it), so only logging here
|
| 105 |
+
# FastAPI endpoints will still work via the same server
|
| 106 |
+
logging.info("Auralis API + Gradio launched.")
|
| 107 |
+
t.join()
|