Spaces:
Sleeping
Sleeping
| from flask import Flask, request, jsonify | |
| from birdnetlib import Recording | |
| from birdnetlib.analyzer import Analyzer | |
| from datetime import datetime | |
| import tempfile, os, subprocess | |
| app = Flask(__name__) | |
| print("Loading BirdNET model...") | |
| analyzer = Analyzer() | |
| print("BirdNET model loaded.") | |
| def health(): | |
| return jsonify({'status': 'ok', 'model': 'BirdNET-Analyzer'}) | |
| def analyze(): | |
| if 'audio' not in request.files: | |
| return jsonify({'error': 'No audio file provided'}), 400 | |
| audio_file = request.files.get('audio') | |
| lat = float(request.args.get('lat', 0)) | |
| lon = float(request.args.get('lon', 0)) | |
| # Save incoming .m4a to temp file | |
| with tempfile.NamedTemporaryFile(suffix='.m4a', | |
| delete=False) as tmp_m4a: | |
| tmp_m4a_path = tmp_m4a.name | |
| audio_file.save(tmp_m4a_path) | |
| # Convert .m4a to .wav using ffmpeg | |
| tmp_wav_path = tmp_m4a_path.replace('.m4a', '.wav') | |
| try: | |
| subprocess.run([ | |
| 'ffmpeg', '-y', | |
| '-i', tmp_m4a_path, | |
| '-ar', '48000', | |
| '-ac', '1', | |
| '-f', 'wav', | |
| tmp_wav_path | |
| ], check=True, capture_output=True) | |
| # Run BirdNET on the WAV file | |
| recording = Recording( | |
| analyzer, | |
| tmp_wav_path, | |
| lat=lat, | |
| lon=lon, | |
| date=datetime.now(), | |
| min_conf=0.25 | |
| ) | |
| recording.analyze() | |
| detections = recording.detections | |
| except subprocess.CalledProcessError as e: | |
| return jsonify({ | |
| 'error': 'Audio conversion failed', | |
| 'detail': e.stderr.decode() | |
| }), 500 | |
| except Exception as e: | |
| return jsonify({ | |
| 'error': 'Analysis failed', | |
| 'detail': str(e) | |
| }), 500 | |
| finally: | |
| # Always clean up temp files | |
| if os.path.exists(tmp_m4a_path): | |
| os.unlink(tmp_m4a_path) | |
| if os.path.exists(tmp_wav_path): | |
| os.unlink(tmp_wav_path) | |
| if not detections: | |
| return jsonify({'error': 'No species detected'}), 404 | |
| top = sorted(detections, | |
| key=lambda x: x['confidence'], | |
| reverse=True)[0] | |
| return jsonify({ | |
| 'species': top['common_name'], | |
| 'scientific_name': top['scientific_name'], | |
| 'confidence': round(top['confidence'], 3), | |
| 'all_detections': [ | |
| { | |
| 'species': d['common_name'], | |
| 'confidence': round(d['confidence'], 3) | |
| } | |
| for d in detections[:5] | |
| ] | |
| }) | |
| if __name__ == '__main__': | |
| port = int(os.environ.get('PORT', 7860)) | |
| app.run(host='0.0.0.0', port=port) |