Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

General fixes - Code quality, Configurable Config Directory, Update Docker #23

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
31 changes: 31 additions & 0 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Format code

on:
push:
branches: [ master ]

jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Format code with black
run: |
pip install black
black .
- name: Sort imports with isort
run: |
pip install isort
isort .
- name: Remove unused imports with autoflake
run: |
pip install autoflake
autoflake --in-place --remove-all-unused-imports --remove-unused-variables --recursive .
- name: Commit changes
uses: EndBug/add-and-commit@v4
with:
author_name: ${{ github.actor }}
author_email: ${{ github.actor }}@users.noreply.github.com
message: "Format code with black"
add: "."
branch: ${{ github.ref }}
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.8
FROM python:3.9
RUN apt-get update && apt-get install ffmpeg libsm6 libxext6 -y
COPY requirements.txt .
RUN pip install -r requirements.txt
Expand All @@ -7,6 +7,7 @@ COPY birdnames.db .
COPY speciesid.py .
COPY webui.py .
COPY queries.py .
COPY util.py .
COPY templates/ ./templates/
COPY static/ ./static/

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# Who's At My Feeder?

This app acts as sidecar to [Frigate](https://frigate.video/) to identify the species of the birds that Frigate detects. It is using the bird species classifier model found here: https://tfhub.dev/google/lite-model/aiy/vision/classifier/birds_V1/3

## What's New?
I'm just about to push a significant update. This will require you to...
* Delete you current speciesid.db database. If you are attached to that data, just move it somewhere else
Expand All @@ -17,9 +20,6 @@ field is currently limited to 20 characters

![screenshot](screenshot2.jpg)

This app acts as sidecar to [Frigate](https://frigate.video/) to identify the species of
the birds that Frigate detects. It is using the bird species classifier model found here: https://tfhub.dev/google/lite-model/aiy/vision/classifier/birds_V1/3

**Prequisites**

1. A working & Accessible Frigate Installation with at least 1 Camera configured
Expand Down
3 changes: 3 additions & 0 deletions config/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ frigate:
object: bird
classification:
model: model.tflite
name_database: birdnames.db
threshold: 0.7
database:
path: "./data/speciesid.db"
webui:
port: 7766
host: 0.0.0.0
94 changes: 57 additions & 37 deletions queries.py
Original file line number Diff line number Diff line change
@@ -1,61 +1,69 @@
import sqlite3
from collections import defaultdict
from datetime import datetime

DBPATH = './data/speciesid.db'
NAMEDBPATH = './birdnames.db'
from util import load_config

config = load_config()
DBPATH = config["database"]["path"]
NAMEDBPATH = config["classification"]["name_database"]


def get_common_name(scientific_name):
conn = sqlite3.connect(NAMEDBPATH)
cursor = conn.cursor()

cursor.execute("SELECT common_name FROM birdnames WHERE scientific_name = ?", (scientific_name,))
cursor.execute(
"SELECT common_name FROM birdnames WHERE scientific_name = ?",
(scientific_name,),
)
result = cursor.fetchone()

conn.close()

if result:
return result[0]
else:
print ("No common name for: " + scientific_name, flush=True)
print("No common name for: " + scientific_name, flush=True)
return "No common name found."


def recent_detections(num_detections):
conn = sqlite3.connect(DBPATH)
cursor = conn.cursor()

cursor.execute("SELECT * FROM detections ORDER BY detection_time DESC LIMIT ?", (num_detections,))
cursor.execute(
"SELECT * FROM detections ORDER BY detection_time DESC LIMIT ?",
(num_detections,),
)
results = cursor.fetchall()

conn.close()

formatted_results = []
for result in results:
detection = {
'id': result[0],
'detection_time': result[1],
'detection_index': result[2],
'score': result[3],
'display_name': result[4],
'category_name': result[5],
'frigate_event': result[6],
'camera_name': result[7],
'common_name': get_common_name(result[4])
"id": result[0],
"detection_time": result[1],
"detection_index": result[2],
"score": result[3],
"display_name": result[4],
"category_name": result[5],
"frigate_event": result[6],
"camera_name": result[7],
"common_name": get_common_name(result[4]),
}
formatted_results.append(detection)

return formatted_results


def get_daily_summary(date):
date_str = date.strftime('%Y-%m-%d')
date_str = date.strftime("%Y-%m-%d")
conn = sqlite3.connect(DBPATH)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()

query = '''
query = """
SELECT display_name,
COUNT(*) AS total_detections,
STRFTIME('%H', detection_time) AS hour,
Expand All @@ -67,24 +75,28 @@ def get_daily_summary(date):
) AS subquery
GROUP BY display_name, hour
ORDER BY total_detections DESC, display_name, hour
'''
"""

cursor.execute(query, (date_str,))
rows = cursor.fetchall()

summary = defaultdict(lambda: {
'scientific_name': '',
'common_name': '',
'total_detections': 0,
'hourly_detections': [0] * 24
})
summary = defaultdict(
lambda: {
"scientific_name": "",
"common_name": "",
"total_detections": 0,
"hourly_detections": [0] * 24,
}
)

for row in rows:
display_name = row['display_name']
summary[display_name]['scientific_name'] = display_name
summary[display_name]['common_name'] = get_common_name(display_name)
summary[display_name]['total_detections'] += row['hourly_detections']
summary[display_name]['hourly_detections'][int(row['hour'])] = row['hourly_detections']
display_name = row["display_name"]
summary[display_name]["scientific_name"] = display_name
summary[display_name]["common_name"] = get_common_name(display_name)
summary[display_name]["total_detections"] += row["hourly_detections"]
summary[display_name]["hourly_detections"][int(row["hour"])] = row[
"hourly_detections"
]

conn.close()
return dict(summary)
Expand All @@ -96,22 +108,26 @@ def get_records_for_date_hour(date, hour):
cursor = conn.cursor()

# The SQL query to fetch records for the given date and hour, sorted by detection_time
query = '''
query = """
SELECT *
FROM detections
WHERE strftime('%Y-%m-%d', detection_time) = ? AND strftime('%H', detection_time) = ?
ORDER BY detection_time
'''
"""

cursor.execute(query, (date, str(hour).zfill(2)))
records = cursor.fetchall()

# Append the common name for each record
result = []
for record in records:
common_name = get_common_name(record['display_name']) # Access the field by name
common_name = get_common_name(
record["display_name"]
) # Access the field by name
record_dict = dict(record) # Convert the record to a dictionary
record_dict['common_name'] = common_name # Add the 'common_name' key to the record dictionary
record_dict[
"common_name"
] = common_name # Add the 'common_name' key to the record dictionary
result.append(record_dict)

conn.close()
Expand All @@ -125,22 +141,26 @@ def get_records_for_scientific_name_and_date(scientific_name, date):
cursor = conn.cursor()

# The SQL query to fetch records for the given display_name and date, sorted by detection_time
query = '''
query = """
SELECT *
FROM detections
WHERE display_name = ? AND strftime('%Y-%m-%d', detection_time) = ?
ORDER BY detection_time
'''
"""

cursor.execute(query, (scientific_name, date))
records = cursor.fetchall()

# Append the common name for each record
result = []
for record in records:
common_name = get_common_name(record['display_name']) # Access the field by name
common_name = get_common_name(
record["display_name"]
) # Access the field by name
record_dict = dict(record) # Convert the record to a dictionary
record_dict['common_name'] = common_name # Add the 'common_name' key to the record dictionary
record_dict[
"common_name"
] = common_name # Add the 'common_name' key to the record dictionary
result.append(record_dict)

conn.close()
Expand Down
Loading