Merge pull request #1 from bdoner/feature/add-confidencepct-to-apprise-notification

Add $confidencepct variable to apprise notification.
This commit is contained in:
Bick Doner
2023-02-22 10:58:20 +01:00
committed by GitHub
8 changed files with 80 additions and 69 deletions
+4 -2
View File
@@ -512,6 +512,8 @@ https://discordapp.com/api/webhooks/{WebhookID}/{WebhookToken}
<dd>Common Name</dd> <dd>Common Name</dd>
<dt>$confidence</dt> <dt>$confidence</dt>
<dd>Confidence Score</dd> <dd>Confidence Score</dd>
<dt>$confidencepct</dt>
<dd>Confidence Score as a percentage (eg. 0.91 => 91)</dd>
<dt>$listenurl</dt> <dt>$listenurl</dt>
<dd>A link to the detection</dd> <dd>A link to the detection</dd>
<dt>$date</dt> <dt>$date</dt>
@@ -535,9 +537,9 @@ https://discordapp.com/api/webhooks/{WebhookID}/{WebhookToken}
</dl> </dl>
<p>Use the variables defined above to customize your notification title and body.</p> <p>Use the variables defined above to customize your notification title and body.</p>
<label for="apprise_notification_title">Notification Title: </label> <label for="apprise_notification_title">Notification Title: </label>
<input name="apprise_notification_title" type="text" value="<?php print($config['APPRISE_NOTIFICATION_TITLE']);?>" /><br> <input name="apprise_notification_title" style="width: 100%" type="text" value="<?php print($config['APPRISE_NOTIFICATION_TITLE']);?>" /><br>
<label for="apprise_notification_body">Notification Body: </label> <label for="apprise_notification_body">Notification Body: </label>
<input name="apprise_notification_body" type="text" value='<?php print($config['APPRISE_NOTIFICATION_BODY']);?>' /><br> <input name="apprise_notification_body" style="width: 100%" type="text" value='<?php print($config['APPRISE_NOTIFICATION_BODY']);?>' /><br>
<input type="checkbox" name="apprise_notify_new_species" <?php if($config['APPRISE_NOTIFY_NEW_SPECIES'] == 1 && filesize($home."/BirdNET-Pi/apprise.txt") != 0) { echo "checked"; };?> > <input type="checkbox" name="apprise_notify_new_species" <?php if($config['APPRISE_NOTIFY_NEW_SPECIES'] == 1 && filesize($home."/BirdNET-Pi/apprise.txt") != 0) { echo "checked"; };?> >
<label for="apprise_notify_new_species">Notify each new infrequent species detection (<5 visits per week)</label><br> <label for="apprise_notify_new_species">Notify each new infrequent species detection (<5 visits per week)</label><br>
<input type="checkbox" name="apprise_notify_new_species_each_day" <?php if($config['APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY'] == 1 && filesize($home."/BirdNET-Pi/apprise.txt") != 0) { echo "checked"; };?> > <input type="checkbox" name="apprise_notify_new_species_each_day" <?php if($config['APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY'] == 1 && filesize($home."/BirdNET-Pi/apprise.txt") != 0) { echo "checked"; };?> >
+2 -1
View File
@@ -48,7 +48,8 @@ readings = 10
plt_top10_today = (df_plt_today['Com_Name'].value_counts()[:readings]) plt_top10_today = (df_plt_today['Com_Name'].value_counts()[:readings])
df_plt_top10_today = df_plt_today[df_plt_today.Com_Name.isin(plt_top10_today.index)] df_plt_top10_today = df_plt_today[df_plt_today.Com_Name.isin(plt_top10_today.index)]
if df_plt_top10_today.empty: exit(0) if df_plt_top10_today.empty:
exit(0)
# Set Palette for graphics # Set Palette for graphics
pal = "Greens" pal = "Greens"
+15 -6
View File
@@ -55,10 +55,11 @@ with open(userDir + '/BirdNET-Pi/scripts/thisrun.txt', 'r') as f:
try: try:
model = str(str(str([i for i in this_run if i.startswith('MODEL')]).split('=')[1]).split('\\')[0]) model = str(str(str([i for i in this_run if i.startswith('MODEL')]).split('=')[1]).split('\\')[0])
sf_thresh = str(str(str([i for i in this_run if i.startswith('SF_THRESH')]).split('=')[1]).split('\\')[0]) sf_thresh = str(str(str([i for i in this_run if i.startswith('SF_THRESH')]).split('=')[1]).split('\\')[0])
except Exception as e: except Exception:
model = "BirdNET_6K_GLOBAL_MODEL" model = "BirdNET_6K_GLOBAL_MODEL"
sf_thresh = 0.03 sf_thresh = 0.03
def loadModel(): def loadModel():
global INPUT_LAYER_INDEX global INPUT_LAYER_INDEX
@@ -95,6 +96,7 @@ def loadModel():
return myinterpreter return myinterpreter
def loadMetaModel(): def loadMetaModel():
global M_INTERPRETER global M_INTERPRETER
@@ -115,15 +117,16 @@ def loadMetaModel():
print("loaded META model") print("loaded META model")
def predictFilter(lat, lon, week): def predictFilter(lat, lon, week):
global M_INTERPRETER global M_INTERPRETER
# Does interpreter exist? # Does interpreter exist?
try: try:
if M_INTERPRETER == None: if M_INTERPRETER is None:
loadMetaModel() loadMetaModel()
except Exception as e: except Exception:
loadMetaModel() loadMetaModel()
# Prepare mdata as sample # Prepare mdata as sample
@@ -135,6 +138,7 @@ def predictFilter(lat, lon, week):
return M_INTERPRETER.get_tensor(M_OUTPUT_LAYER_INDEX)[0] return M_INTERPRETER.get_tensor(M_OUTPUT_LAYER_INDEX)[0]
def explore(lat, lon, week): def explore(lat, lon, week):
# Make filter prediction # Make filter prediction
@@ -151,6 +155,7 @@ def explore(lat, lon, week):
return l_filter return l_filter
def predictSpeciesList(lat, lon, week): def predictSpeciesList(lat, lon, week):
l_filter = explore(lat, lon, week) l_filter = explore(lat, lon, week)
@@ -160,6 +165,7 @@ def predictSpeciesList(lat, lon, week):
if (len(INCLUDE_LIST) == 0): if (len(INCLUDE_LIST) == 0):
PREDICTED_SPECIES_LIST.append(s[1]) PREDICTED_SPECIES_LIST.append(s[1])
def loadCustomSpeciesList(path): def loadCustomSpeciesList(path):
slist = [] slist = []
@@ -274,7 +280,6 @@ def analyzeAudioData(chunks, lat, lon, week, sensitivity, overlap,):
if len(PREDICTED_SPECIES_LIST) == 0 or len(INCLUDE_LIST) != 0: if len(PREDICTED_SPECIES_LIST) == 0 or len(INCLUDE_LIST) != 0:
predictSpeciesList(lat, lon, week) predictSpeciesList(lat, lon, week)
# Convert and prepare metadata # Convert and prepare metadata
mdata = convertMetadata(np.array([lat, lon, week])) mdata = convertMetadata(np.array([lat, lon, week]))
mdata = np.expand_dims(mdata, 0) mdata = np.expand_dims(mdata, 0)
@@ -320,7 +325,9 @@ def writeResultsToFile(detections, min_conf, path):
rfile.write('Start (s);End (s);Scientific name;Common name;Confidence\n') rfile.write('Start (s);End (s);Scientific name;Common name;Confidence\n')
for d in detections: for d in detections:
for entry in detections[d]: for entry in detections[d]:
if entry[1] >= min_conf and ((entry[0] in INCLUDE_LIST or len(INCLUDE_LIST) == 0) and (entry[0] not in EXCLUDE_LIST or len(EXCLUDE_LIST) == 0) and (entry[0] in PREDICTED_SPECIES_LIST or len(PREDICTED_SPECIES_LIST) == 0) ): if entry[1] >= min_conf and ((entry[0] in INCLUDE_LIST or len(INCLUDE_LIST) == 0)
and (entry[0] not in EXCLUDE_LIST or len(EXCLUDE_LIST) == 0)
and (entry[0] in PREDICTED_SPECIES_LIST or len(PREDICTED_SPECIES_LIST) == 0)):
rfile.write(d + ';' + entry[0].replace('_', ';').split("/")[0] + ';' + str(entry[1]) + '\n') rfile.write(d + ';' + entry[0].replace('_', ';').split("/")[0] + ';' + str(entry[1]) + '\n')
rcnt += 1 rcnt += 1
print('DONE! WROTE', rcnt, 'RESULTS.') print('DONE! WROTE', rcnt, 'RESULTS.')
@@ -442,7 +449,8 @@ def handle_client(conn, addr):
species_apprised_this_run = [] species_apprised_this_run = []
for entry in detections[d]: for entry in detections[d]:
if entry[1] >= min_conf and ((entry[0] in INCLUDE_LIST or len(INCLUDE_LIST) == 0) if entry[1] >= min_conf and ((entry[0] in INCLUDE_LIST or len(INCLUDE_LIST) == 0)
and (entry[0] not in EXCLUDE_LIST or len(EXCLUDE_LIST) == 0) and (entry[0] in PREDICTED_SPECIES_LIST or len(PREDICTED_SPECIES_LIST) == 0) ): and (entry[0] not in EXCLUDE_LIST or len(EXCLUDE_LIST) == 0)
and (entry[0] in PREDICTED_SPECIES_LIST or len(PREDICTED_SPECIES_LIST) == 0)):
# Write to text file. # Write to text file.
rfile.write(str(current_date) + ';' + str(current_time) + ';' + entry[0].replace('_', ';').split("/")[0] + ';' rfile.write(str(current_date) + ';' + str(current_time) + ';' + entry[0].replace('_', ';').split("/")[0] + ';'
+ str(entry[1]) + ";" + str(args.lat) + ';' + str(args.lon) + ';' + str(min_conf) + ';' + str(week) + ';' + str(entry[1]) + ";" + str(args.lat) + ';' + str(args.lon) + ';' + str(min_conf) + ';' + str(week) + ';'
@@ -485,6 +493,7 @@ def handle_client(conn, addr):
settings_dict = config_to_settings(userDir + '/BirdNET-Pi/scripts/thisrun.txt') settings_dict = config_to_settings(userDir + '/BirdNET-Pi/scripts/thisrun.txt')
sendAppriseNotifications(species, sendAppriseNotifications(species,
str(score), str(score),
str(round(score * 100)),
File_Name, File_Name,
Date, Date,
Time, Time,
+12 -27
View File
@@ -1,18 +1,5 @@
from pathlib import Path
from tzlocal import get_localzone
import datetime
import sqlite3
import requests
import json
import time
import math
import numpy as np import numpy as np
import librosa
import operator
import socket
import threading
import os import os
import sys
import argparse import argparse
import datetime import datetime
@@ -22,7 +9,6 @@ except BaseException:
from tensorflow import lite as tflite from tensorflow import lite as tflite
def loadMetaModel(): def loadMetaModel():
global M_INTERPRETER global M_INTERPRETER
@@ -51,15 +37,16 @@ def loadMetaModel():
print("loaded META model") print("loaded META model")
def predictFilter(lat, lon, week): def predictFilter(lat, lon, week):
global M_INTERPRETER global M_INTERPRETER
# Does interpreter exist? # Does interpreter exist?
try: try:
if M_INTERPRETER == None: if M_INTERPRETER is None:
loadMetaModel() loadMetaModel()
except Exception as e: except Exception:
loadMetaModel() loadMetaModel()
# Prepare mdata as sample # Prepare mdata as sample
@@ -71,6 +58,7 @@ def predictFilter(lat, lon, week):
return M_INTERPRETER.get_tensor(M_OUTPUT_LAYER_INDEX)[0] return M_INTERPRETER.get_tensor(M_OUTPUT_LAYER_INDEX)[0]
def explore(lat, lon, week, threshold): def explore(lat, lon, week, threshold):
# Make filter prediction # Make filter prediction
@@ -87,6 +75,7 @@ def explore(lat, lon, week, threshold):
return l_filter return l_filter
def getSpeciesList(lat, lon, week, threshold=0.05, sort=False): def getSpeciesList(lat, lon, week, threshold=0.05, sort=False):
print('Getting species list for {}/{}, Week {}...'.format(lat, lon, week), end='', flush=True) print('Getting species list for {}/{}, Week {}...'.format(lat, lon, week), end='', flush=True)
@@ -115,13 +104,10 @@ weekofyear = datetime.datetime.today().isocalendar()[1]
if __name__ == '__main__': if __name__ == '__main__':
# Parse arguments # Parse arguments
parser = argparse.ArgumentParser(description='Get list of species for a given location with BirdNET. Sorted by occurrence frequency.') parser = argparse.ArgumentParser(
#parser.add_argument('--o', default='/home/pi/BirdNET-Pi/include_species_list.txt', help='Path to output file or folder. If this is a folder, file will be named \'species_list.txt\'.') description='Get list of species for a given location with BirdNET. Sorted by occurrence frequency.'
#parser.add_argument('--lat', type=float, default=##, help='Recording location latitude. Set -1 to ignore.') )
#parser.add_argument('--lon', type=float, default=##, help='Recording location longitude. Set -1 to ignore.')
#parser.add_argument('--week', type=int, default=dayofweek, help='Week of the year when the recording was made. Values in [1, 48] (4 weeks per month). Set -1 for year-round species list.')
parser.add_argument('--threshold', type=float, default=0.05, help='Occurrence frequency threshold. Defaults to 0.05.') parser.add_argument('--threshold', type=float, default=0.05, help='Occurrence frequency threshold. Defaults to 0.05.')
#parser.add_argument('--sortby', default='freq', help='Sort species by occurrence frequency or alphabetically. Values in [\'freq\', \'alpha\']. Defaults to \'freq\'.')
args = parser.parse_args() args = parser.parse_args()
@@ -132,8 +118,7 @@ if __name__ == '__main__':
for x in range(len(species_list)): for x in range(len(species_list)):
print(species_list[x][0] + " - " + str(species_list[x][1])) print(species_list[x][0] + " - " + str(species_list[x][1]))
print("\nThe above species list describes all the species that the model will attempt to detect. If you don't see a species you want detected on this list, decrease your threshold.") print("\nThe above species list describes all the species that the model will attempt to detect. \
print("\nNOTE: no actual changes to your BirdNET-Pi species list were made by running this command. To set your desired frequency threshold, do it through the BirdNET-Pi web interface (Tools -> Settings -> Model)") If you don't see a species you want detected on this list, decrease your threshold.")
print("\nNOTE: no actual changes to your BirdNET-Pi species list were made by running this command. \
To set your desired frequency threshold, do it through the BirdNET-Pi web interface (Tools -> Settings -> Model)")
+13 -4
View File
@@ -24,6 +24,7 @@ config = apprise.AppriseConfig()
config.add(APPRISE_CONFIG) config.add(APPRISE_CONFIG)
apobj.add(config) apobj.add(config)
def notify(body, title, attached=""): def notify(body, title, attached=""):
if attached != "": if attached != "":
apobj.notify( apobj.notify(
@@ -38,7 +39,9 @@ def notify(body, title, attached=""):
) )
def sendAppriseNotifications(species, confidence, path, date, time, week, latitude, longitude, cutoff, sens, overlap, settings_dict, db_path=DB_PATH): def sendAppriseNotifications(species, confidence, confidencepct, path,
date, time, week, latitude, longitude, cutoff,
sens, overlap, settings_dict, db_path=DB_PATH):
# print(sendAppriseNotifications) # print(sendAppriseNotifications)
# print(settings_dict) # print(settings_dict)
if os.path.exists(APPRISE_CONFIG) and os.path.getsize(APPRISE_CONFIG) > 0: if os.path.exists(APPRISE_CONFIG) and os.path.getsize(APPRISE_CONFIG) > 0:
@@ -69,10 +72,11 @@ def sendAppriseNotifications(species, confidence, path, date, time, week, latitu
image_url = "" image_url = ""
if len(settings_dict.get('FLICKR_API_KEY')) > 0 and "$flickrimage" in body: if len(settings_dict.get('FLICKR_API_KEY')) > 0 and "$flickrimage" in body:
if not comName in flickr_images: if comName not in flickr_images:
try: try:
# TODO: Make this work with non-english comnames. Implement the "// convert sci name to English name" logic from overview.php here # TODO: Make this work with non-english comnames. Implement the "// convert sci name to English name" logic from overview.php here
url = 'https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key='+str(settings_dict.get('FLICKR_API_KEY'))+'&text='+str(comName)+' bird&sort=relevance&per_page=5&media=photos&format=json&license=2%2C3%2C4%2C5%2C6%2C9&nojsoncallback=1' url = 'https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key='+str(settings_dict.get('FLICKR_API_KEY'))+'&text='+str(
comName)+' bird&sort=relevance&per_page=5&media=photos&format=json&license=2%2C3%2C4%2C5%2C6%2C9&nojsoncallback=1'
resp = requests.get(url=url) resp = requests.get(url=url)
resp.encoding = "utf-8" resp.encoding = "utf-8"
data = resp.json()["photos"]["photo"][0] data = resp.json()["photos"]["photo"][0]
@@ -85,11 +89,11 @@ def sendAppriseNotifications(species, confidence, path, date, time, week, latitu
else: else:
image_url = flickr_images[comName] image_url = flickr_images[comName]
if settings_dict.get('APPRISE_NOTIFY_EACH_DETECTION') == "1": if settings_dict.get('APPRISE_NOTIFY_EACH_DETECTION') == "1":
notify_body = body.replace("$sciname", sciName)\ notify_body = body.replace("$sciname", sciName)\
.replace("$comname", comName)\ .replace("$comname", comName)\
.replace("$confidence", confidence)\ .replace("$confidence", confidence)\
.replace("$confidencepct", confidencepct)\
.replace("$listenurl", listenurl)\ .replace("$listenurl", listenurl)\
.replace("$date", date)\ .replace("$date", date)\
.replace("$time", time)\ .replace("$time", time)\
@@ -103,6 +107,7 @@ def sendAppriseNotifications(species, confidence, path, date, time, week, latitu
notify_title = title.replace("$sciname", sciName)\ notify_title = title.replace("$sciname", sciName)\
.replace("$comname", comName)\ .replace("$comname", comName)\
.replace("$confidence", confidence)\ .replace("$confidence", confidence)\
.replace("$confidencepct", confidencepct)\
.replace("$listenurl", listenurl)\ .replace("$listenurl", listenurl)\
.replace("$date", date)\ .replace("$date", date)\
.replace("$time", time)\ .replace("$time", time)\
@@ -133,6 +138,7 @@ def sendAppriseNotifications(species, confidence, path, date, time, week, latitu
notify_body = body.replace("$sciname", sciName)\ notify_body = body.replace("$sciname", sciName)\
.replace("$comname", comName)\ .replace("$comname", comName)\
.replace("$confidence", confidence)\ .replace("$confidence", confidence)\
.replace("$confidencepct", confidencepct)\
.replace("$listenurl", listenurl)\ .replace("$listenurl", listenurl)\
.replace("$date", date)\ .replace("$date", date)\
.replace("$time", time)\ .replace("$time", time)\
@@ -147,6 +153,7 @@ def sendAppriseNotifications(species, confidence, path, date, time, week, latitu
notify_title = title.replace("$sciname", sciName)\ notify_title = title.replace("$sciname", sciName)\
.replace("$comname", comName)\ .replace("$comname", comName)\
.replace("$confidence", confidence)\ .replace("$confidence", confidence)\
.replace("$confidencepct", confidencepct)\
.replace("$listenurl", listenurl)\ .replace("$listenurl", listenurl)\
.replace("$date", date)\ .replace("$date", date)\
.replace("$time", time)\ .replace("$time", time)\
@@ -181,6 +188,7 @@ def sendAppriseNotifications(species, confidence, path, date, time, week, latitu
notify_body = body.replace("$sciname", sciName)\ notify_body = body.replace("$sciname", sciName)\
.replace("$comname", comName)\ .replace("$comname", comName)\
.replace("$confidence", confidence)\ .replace("$confidence", confidence)\
.replace("$confidencepct", confidencepct)\
.replace("$listenurl", listenurl)\ .replace("$listenurl", listenurl)\
.replace("$date", date)\ .replace("$date", date)\
.replace("$time", time)\ .replace("$time", time)\
@@ -195,6 +203,7 @@ def sendAppriseNotifications(species, confidence, path, date, time, week, latitu
notify_title = title.replace("$sciname", sciName)\ notify_title = title.replace("$sciname", sciName)\
.replace("$comname", comName)\ .replace("$comname", comName)\
.replace("$confidence", confidence)\ .replace("$confidence", confidence)\
.replace("$confidencepct", confidencepct)\
.replace("$listenurl", listenurl)\ .replace("$listenurl", listenurl)\
.replace("$date", date)\ .replace("$date", date)\
.replace("$time", time)\ .replace("$time", time)\
+6 -1
View File
@@ -50,6 +50,7 @@ def test_notifications(mocker):
"APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY": "0" "APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY": "0"
} }
sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher",
"0.91",
"91", "91",
"filename", "filename",
"1666-06-06", "1666-06-06",
@@ -70,6 +71,7 @@ def test_notifications(mocker):
notify_call.reset_mock() notify_call.reset_mock()
settings_dict["APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY"] = "1" settings_dict["APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY"] = "1"
sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher",
"0.91",
"91", "91",
"filename", "filename",
"1666-06-06", "1666-06-06",
@@ -92,6 +94,7 @@ def test_notifications(mocker):
notify_call.reset_mock() notify_call.reset_mock()
settings_dict["APPRISE_NOTIFY_NEW_SPECIES"] = "1" settings_dict["APPRISE_NOTIFY_NEW_SPECIES"] = "1"
sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher",
"0.91",
"91", "91",
"filename", "filename",
"1666-06-06", "1666-06-06",
@@ -110,13 +113,15 @@ def test_notifications(mocker):
notify_call.call_args_list[0][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (first time today)" notify_call.call_args_list[0][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (first time today)"
) )
assert ( assert (
notify_call.call_args_list[1][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (only seen 1 times in last 7d)" notify_call.call_args_list[1][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence \
of 91 (only seen 1 times in last 7d)"
) )
# Add each species notification. # Add each species notification.
notify_call.reset_mock() notify_call.reset_mock()
settings_dict["APPRISE_NOTIFY_EACH_DETECTION"] = "1" settings_dict["APPRISE_NOTIFY_EACH_DETECTION"] = "1"
sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher",
"0.91",
"91", "91",
"filename", "filename",
"1666-06-06", "1666-06-06",