Spaces:
Sleeping
Sleeping
TheAlly commited on
Commit ·
be6595e
1
Parent(s): bdcc9e3
Default top_n to None, strip metadata row, post-filter by min_conf
Browse files
main.py
CHANGED
|
@@ -22,6 +22,13 @@ def health():
|
|
| 22 |
}
|
| 23 |
|
| 24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
@app.post("/analyze")
|
| 26 |
async def analyze_audio(
|
| 27 |
audio: UploadFile = File(...),
|
|
@@ -29,7 +36,10 @@ async def analyze_audio(
|
|
| 29 |
lat: Optional[float] = Form(None),
|
| 30 |
lon: Optional[float] = Form(None),
|
| 31 |
week: Optional[int] = Form(None),
|
| 32 |
-
|
|
|
|
|
|
|
|
|
|
| 33 |
):
|
| 34 |
suffix = Path(audio.filename or "audio.wav").suffix or ".wav"
|
| 35 |
with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp_in:
|
|
@@ -54,6 +64,17 @@ async def analyze_audio(
|
|
| 54 |
for csv_file in Path(out_dir).glob("*.csv"):
|
| 55 |
with open(csv_file, newline="") as f:
|
| 56 |
for row in csv_module.DictReader(f):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
results.append(dict(row))
|
| 58 |
|
| 59 |
return JSONResponse({"results": results})
|
|
|
|
| 22 |
}
|
| 23 |
|
| 24 |
|
| 25 |
+
# Keys we expect on a real detection row — used to filter out the
|
| 26 |
+
# metadata block BirdNET appends to its CSV output ("File splitting
|
| 27 |
+
# duration", "Segment length", etc., which DictReader otherwise picks
|
| 28 |
+
# up as a phantom row).
|
| 29 |
+
DETECTION_KEYS = {"Start (s)", "End (s)", "Scientific name", "Common name", "Confidence"}
|
| 30 |
+
|
| 31 |
+
|
| 32 |
@app.post("/analyze")
|
| 33 |
async def analyze_audio(
|
| 34 |
audio: UploadFile = File(...),
|
|
|
|
| 36 |
lat: Optional[float] = Form(None),
|
| 37 |
lon: Optional[float] = Form(None),
|
| 38 |
week: Optional[int] = Form(None),
|
| 39 |
+
# None lets min_conf gate the results. Pass an int to force "top N per
|
| 40 |
+
# segment regardless of confidence" — useful for debugging silent files,
|
| 41 |
+
# noisy for normal use.
|
| 42 |
+
top_n: Optional[int] = Form(None),
|
| 43 |
):
|
| 44 |
suffix = Path(audio.filename or "audio.wav").suffix or ".wav"
|
| 45 |
with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp_in:
|
|
|
|
| 64 |
for csv_file in Path(out_dir).glob("*.csv"):
|
| 65 |
with open(csv_file, newline="") as f:
|
| 66 |
for row in csv_module.DictReader(f):
|
| 67 |
+
# Skip the trailing metadata block — its keys don't
|
| 68 |
+
# overlap with detection keys.
|
| 69 |
+
if not DETECTION_KEYS.issubset(row.keys()):
|
| 70 |
+
continue
|
| 71 |
+
# Defence-in-depth: drop rows below threshold even
|
| 72 |
+
# when top_n is set, so the response is consistent.
|
| 73 |
+
try:
|
| 74 |
+
if float(row.get("Confidence", 0)) < min_conf:
|
| 75 |
+
continue
|
| 76 |
+
except (TypeError, ValueError):
|
| 77 |
+
continue
|
| 78 |
results.append(dict(row))
|
| 79 |
|
| 80 |
return JSONResponse({"results": results})
|