Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Tests

on:
pull_request:
types: [opened, synchronize, reopened, edited]
branches: [main]
push:
branches: [main]

concurrency:
group: "${{ github.event.pull_request.number }}-${{ github.ref_name }}-${{ github.workflow }}"
cancel-in-progress: true

jobs:
running-tests:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ["3.11"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip ruff
python -m pip install .[all]
- name: Run linter
run: |
ruff check

- name: Run tests
run: |
python -m pip install pytest pytest-cov
pytest

28 changes: 28 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Lint

on:
push:
branches: [main]
pull_request:
branches: [main]
types: [opened, synchronize, reopened, edited]

jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install ruff

- name: Lint with Ruff
run: |
ruff check
3 changes: 1 addition & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
name: Publish to PyPI (Trusted Publishing)

name: Publish to PyPI
on:
release:
types: [published]
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-publish.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Publish to PyPI (Trusted Publishing)
name: Publish to Test-PyPI

on:
release:
Expand Down
18 changes: 13 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
# IDE/Editor settings
.vscode/*

# Allow VSCode recommendations
!.vscode/extensions.json

# Ruff
.ruff_cache

# Models
checkpoints

Expand Down Expand Up @@ -29,9 +38,6 @@ example
# Logs
error_log.txt

# IDE/Editor settings
.vscode/

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down Expand Up @@ -162,11 +168,13 @@ dmypy.json
# Pyre type checker
.pyre/


# GUI generated
train_data/
train_cache.npz
autotune/

gui-settings.json
state.json
BirdNET_analysis_params.csv

# Build files
entitlements.plist
6 changes: 6 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// See https://go.microsoft.com/fwlink/?LinkId=827846
{
"recommendations": [
"charliermarsh.ruff"
]
}
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
[![Docker](https://github.com/birdnet-team/BirdNET-Analyzer/actions/workflows/docker-build.yml/badge.svg)](https://github.com/birdnet-team/BirdNET-Analyzer/actions/workflows/docker-build.yml)
[![Reddit](https://img.shields.io/badge/Reddit-FF4500?style=flat&logo=reddit&logoColor=white)](https://www.reddit.com/r/BirdNET_Analyzer/)
![GitHub stars)](https://img.shields.io/github/stars/birdnet-team/BirdNET-Analyzer)

[![GitHub release](https://img.shields.io/github/v/release/birdnet-team/BirdNET-Analyzer)](https://github.com/birdnet-team/BirdNET-Analyzer/releases/latest)
[![PyPI - Version](https://img.shields.io/pypi/v/birdnet_analyzer?logo=pypi)](https://pypi.org/project/birdnet-analyzer/)

</div>

Expand Down
5 changes: 3 additions & 2 deletions birdnet_analyzer/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from birdnet_analyzer.analyze import analyze
from birdnet_analyzer.embeddings import embeddings
from birdnet_analyzer.train import train
from birdnet_analyzer.search import search
from birdnet_analyzer.segments import segments
from birdnet_analyzer.species import species
from birdnet_analyzer.train import train

__all__ = ["analyze", "train", "embeddings", "search", "segments", "species"]
__version__ = "2.0.0"
__all__ = ["analyze", "embeddings", "search", "segments", "species", "train"]
1 change: 0 additions & 1 deletion birdnet_analyzer/analyze/__main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from birdnet_analyzer.analyze.cli import main


main()
4 changes: 2 additions & 2 deletions birdnet_analyzer/analyze/cli.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from birdnet_analyzer.utils import runtime_error_handler
from birdnet_analyzer import analyze
from birdnet_analyzer.utils import runtime_error_handler


@runtime_error_handler
def main():
import os
from multiprocessing import freeze_support

import birdnet_analyzer.cli as cli
from birdnet_analyzer import cli

# Freeze support for executable
freeze_support()
Expand Down
24 changes: 10 additions & 14 deletions birdnet_analyzer/analyze/core.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import os
from typing import List, Literal
from typing import Literal


def analyze(
input: str,
audio_input: str,
output: str | None = None,
*,
min_conf: float = 0.25,
Expand All @@ -19,8 +19,7 @@ def analyze(
audio_speed: float = 1.0,
batch_size: int = 1,
combine_results: bool = False,
rtype: Literal["table", "audacity", "kaleidoscope", "csv"]
| List[Literal["table", "audacity", "kaleidoscope", "csv"]] = "table",
rtype: Literal["table", "audacity", "kaleidoscope", "csv"] | list[Literal["table", "audacity", "kaleidoscope", "csv"]] = "table",
skip_existing_results: bool = False,
sf_thresh: float = 0.03,
top_n: int | None = None,
Expand All @@ -31,7 +30,7 @@ def analyze(
"""
Analyzes audio files for bird species detection using the BirdNET-Analyzer.
Args:
input (str): Path to the input directory or file containing audio data.
audio_input (str): Path to the input directory or file containing audio data.
output (str | None, optional): Path to the output directory for results. Defaults to None.
min_conf (float, optional): Minimum confidence threshold for detections. Defaults to 0.25.
classifier (str | None, optional): Path to a custom classifier file. Defaults to None.
Expand Down Expand Up @@ -73,7 +72,7 @@ def analyze(
ensure_model_exists()

flist = _set_params(
input=input,
audio_input=audio_input,
output=output,
min_conf=min_conf,
custom_classifier=classifier,
Expand Down Expand Up @@ -109,8 +108,7 @@ def analyze(

# Analyze files
if cfg.CPU_THREADS < 2 or len(flist) < 2:
for entry in flist:
result_files.append(analyze_file(entry))
result_files.extend(analyze_file(f) for f in flist)
else:
with Pool(cfg.CPU_THREADS) as p:
# Map analyzeFile function to each entry in flist
Expand All @@ -129,7 +127,7 @@ def analyze(


def _set_params(
input,
audio_input,
output,
min_conf,
custom_classifier,
Expand All @@ -154,7 +152,7 @@ def _set_params(
labels_file=None,
):
import birdnet_analyzer.config as cfg
from birdnet_analyzer.analyze.utils import load_codes # noqa: E402
from birdnet_analyzer.analyze.utils import load_codes
from birdnet_analyzer.species.utils import get_species_list
from birdnet_analyzer.utils import collect_audio_files, read_lines

Expand All @@ -164,7 +162,7 @@ def _set_params(
cfg.LOCATION_FILTER_THRESHOLD = sf_thresh
cfg.TOP_N = top_n
cfg.MERGE_CONSECUTIVE = merge_consecutive
cfg.INPUT_PATH = input
cfg.INPUT_PATH = audio_input
cfg.MIN_CONFIDENCE = min_conf
cfg.SIGMOID_SENSITIVITY = sensitivity
cfg.SIG_OVERLAP = overlap
Expand Down Expand Up @@ -233,9 +231,7 @@ def _set_params(
cfg.SPECIES_LIST_FILE = None
cfg.SPECIES_LIST = get_species_list(cfg.LATITUDE, cfg.LONGITUDE, cfg.WEEK, cfg.LOCATION_FILTER_THRESHOLD)

lfile = os.path.join(
cfg.TRANSLATED_LABELS_PATH, os.path.basename(cfg.LABELS_FILE).replace(".txt", "_{}.txt".format(locale))
)
lfile = os.path.join(cfg.TRANSLATED_LABELS_PATH, os.path.basename(cfg.LABELS_FILE).replace(".txt", f"_{locale}.txt"))

if locale not in ["en"] and os.path.isfile(lfile):
cfg.TRANSLATED_LABELS = read_lines(lfile)
Expand Down
Loading