|
|
import gradio as gr |
|
|
import numpy as np |
|
|
import librosa |
|
|
from perch_hoplite.zoo import model_configs |
|
|
|
|
|
|
|
|
MODEL = model_configs.load_model_by_name("perch_8") |
|
|
SR = 32000 |
|
|
WIN = 5 * SR |
|
|
|
|
|
def _prep(wav, sr): |
|
|
if wav.ndim > 1: |
|
|
wav = np.mean(wav, axis=1) |
|
|
if sr != SR: |
|
|
wav = librosa.resample(wav.astype(np.float32), orig_sr=sr, target_sr=SR) |
|
|
if len(wav) < WIN: |
|
|
wav = np.pad(wav, (0, WIN - len(wav))) |
|
|
else: |
|
|
wav = wav[:WIN] |
|
|
return wav.astype(np.float32) |
|
|
|
|
|
def infer(audio): |
|
|
if audio is None: |
|
|
return {"error": "no audio"} |
|
|
sr, wav = audio |
|
|
wav = _prep(wav, sr) |
|
|
|
|
|
out = MODEL.embed(wav) |
|
|
logits = out.logits["label"] |
|
|
labels = out.label_names.get("label") |
|
|
|
|
|
idx = np.argsort(logits)[::-1][:3] |
|
|
topk = [] |
|
|
|
|
|
top_logits = logits[idx] |
|
|
exp_logits = np.exp(top_logits - np.max(top_logits)) |
|
|
sum_exp_logits = np.sum(exp_logits) |
|
|
|
|
|
for i in range(len(idx)): |
|
|
class_index = idx[i] |
|
|
name = labels[class_index] if labels is not None and class_index < len(labels) else f"classe_{int(class_index)}" |
|
|
prob = float(exp_logits[i] / sum_exp_logits) |
|
|
topk.append({"label": name, "score": round(prob, 4)}) |
|
|
|
|
|
return { |
|
|
"topk": topk, |
|
|
"embedding_dim": int(out.embeddings.shape[-1]), |
|
|
"note": "Scores non calibrés; régler un seuil selon votre usage." |
|
|
} |
|
|
|
|
|
|
|
|
demo = gr.Interface( |
|
|
fn=infer, |
|
|
inputs=gr.Audio(type="numpy", sources=["microphone", "upload"]), |
|
|
outputs=gr.JSON(label="Perch 8 Inference"), |
|
|
title="Perch Bioacoustics" |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
demo.launch() |