Merge branch 'mcguirepr89:main' into main

This commit is contained in:
croisez
2023-05-09 10:08:51 +02:00
committed by GitHub
18 changed files with 69 additions and 27 deletions
+2 -2
View File
@@ -63,10 +63,10 @@ Currently listening in these countries . . . that I know of . . .
## Features
* **24/7 recording and automatic identification** of bird songs, chirps, and peeps using BirdNET machine learning
* **Automatic extraction and cataloguing** of bird sounds
* **Automatic extraction and cataloguing** of bird clips from full-length recordings
* **Tools to visualize your recorded bird data** and analyze trends
* **Live audio stream and spectrogram**
* **Automatic disk space management** that periodically purges old audio files to manage disk space
* **Automatic disk space management** that periodically purges old audio files
* [BirdWeather](https://app.birdweather.com) integration -- you can request a BirdWeather ID from BirdNET-Pi's "Tools" > "Settings" page
* Web interface access to all data and logs provided by [Caddy](https://caddyserver.com)
* [GoTTY](https://github.com/yudai/gotty) Web Terminal
+1
View File
@@ -78,6 +78,7 @@ APPRISE_WEEKLY_REPORT=1
APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY=0
APPRISE_MINIMUM_SECONDS_BETWEEN_NOTIFICATIONS_PER_SPECIES=0
APPRISE_ONLY_NOTIFY_SPECIES_NAMES=""
APPRISE_ONLY_NOTIFY_SPECIES_NAMES_2=""
#---------------------- Flickr Images API Configuration -----------------------#
## If FLICKR_API_KEY is set, the web interface will try and display bird images
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+11 -6
View File
@@ -54,6 +54,7 @@ if(isset($_GET["latitude"])){
$model = $_GET["model"];
$sf_thresh = $_GET["sf_thresh"];
$only_notify_species_names = $_GET['only_notify_species_names'];
$only_notify_species_names_2 = $_GET['only_notify_species_names_2'];
if(isset($_GET['apprise_notify_each_detection'])) {
$apprise_notify_each_detection = 1;
@@ -120,9 +121,9 @@ if(isset($_GET["latitude"])){
// Archive old language file
syslog_shell_exec("cp -f $home/BirdNET-Pi/model/labels.txt $home/BirdNET-Pi/model/labels.txt.old", $user);
if($model == "BirdNET_GLOBAL_3K_V2.2_Model_FP16"){
if($model == "BirdNET_GLOBAL_3K_V2.3_Model_FP16"){
// Install new language label file
syslog_shell_exec("sudo chmod +x $home/BirdNET-Pi/scripts/install_language_label_nm.sh && $home/BirdNET-Pi/scripts/install_language_label_nm.sh -l $language", $user);
syslog_shell_exec("chmod +x $home/BirdNET-Pi/scripts/install_language_label_nm.sh && $home/BirdNET-Pi/scripts/install_language_label_nm.sh -l $language", $user);
} else {
syslog_shell_exec("$home/BirdNET-Pi/scripts/install_language_label.sh -l $language", $user);
}
@@ -150,6 +151,7 @@ if(isset($_GET["latitude"])){
$contents = preg_replace("/MODEL=.*/", "MODEL=$model", $contents);
$contents = preg_replace("/SF_THRESH=.*/", "SF_THRESH=$sf_thresh", $contents);
$contents = preg_replace("/APPRISE_ONLY_NOTIFY_SPECIES_NAMES=.*/", "APPRISE_ONLY_NOTIFY_SPECIES_NAMES=\"$only_notify_species_names\"", $contents);
$contents = preg_replace("/APPRISE_ONLY_NOTIFY_SPECIES_NAMES_2=.*/", "APPRISE_ONLY_NOTIFY_SPECIES_NAMES_2=\"$only_notify_species_names_2\"", $contents);
$contents2 = file_get_contents("./scripts/thisrun.txt");
$contents2 = preg_replace("/SITE_NAME=.*/", "SITE_NAME=\"$site_name\"", $contents2);
@@ -169,6 +171,7 @@ if(isset($_GET["latitude"])){
$contents2 = preg_replace("/MODEL=.*/", "MODEL=$model", $contents2);
$contents2 = preg_replace("/SF_THRESH=.*/", "SF_THRESH=$sf_thresh", $contents2);
$contents2 = preg_replace("/APPRISE_ONLY_NOTIFY_SPECIES_NAMES=.*/", "APPRISE_ONLY_NOTIFY_SPECIES_NAMES=\"$only_notify_species_names\"", $contents2);
$contents2 = preg_replace("/APPRISE_ONLY_NOTIFY_SPECIES_NAMES_2=.*/", "APPRISE_ONLY_NOTIFY_SPECIES_NAMES_2=\"$only_notify_species_names_2\"", $contents2);
@@ -325,7 +328,7 @@ if (!isset($_SERVER['PHP_AUTH_USER'])) {
<script>
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('modelsel').addEventListener('change', function() {
if(this.value == "BirdNET_GLOBAL_3K_V2.2_Model_FP16"){
if(this.value == "BirdNET_GLOBAL_3K_V2.3_Model_FP16"){
document.getElementById("soft").style.display="unset";
} else {
document.getElementById("soft").style.display="none";
@@ -357,7 +360,7 @@ function sendTestNotification(e) {
<label for="model">Select a Model: </label>
<select id="modelsel" name="model">
<?php
$models = array("BirdNET_6K_GLOBAL_MODEL", "BirdNET_GLOBAL_3K_V2.2_Model_FP16");
$models = array("BirdNET_6K_GLOBAL_MODEL", "BirdNET_GLOBAL_3K_V2.3_Model_FP16");
foreach($models as $modelName){
$isSelected = "";
if($config['MODEL'] == $modelName){
@@ -473,7 +476,7 @@ function runProcess() {
<dt>BirdNET_6K_GLOBAL_MODEL (2020)</dt><br>
<dd id="ddnewline">This is the BirdNET-Lite model, with bird sound recognition for more than 6,000 species worldwide. This is the default option and will generally work very for people in most of the world.</dd>
<br>
<dt>BirdNET_GLOBAL_3K_V2.2_Model_FP16 (2022)</dt><br>
<dt>BirdNET_GLOBAL_3K_V2.3_Model_FP16 (2023)</dt><br>
<dd id="ddnewline">This is the BirdNET-Analyzer model, a newer work-in-progress project with aims to improve on the BirdNET-Lite model. Currently it only supports about 3,500 species worldwide, meaning for some regions (North America, Europe, Australia) it will usually outperform the BirdNET-Lite model, but for other regions it will be worse.</dd><br>
<dt>[ In-depth technical write-up on the models <a target="_blank" href="https://github.com/mcguirepr89/BirdNET-Pi/wiki/BirdNET-Pi:-some-theory-on-classification-&-some-practical-hints">here</a> ]</dt>
</dl>
@@ -550,7 +553,9 @@ https://discordapp.com/api/webhooks/{WebhookID}/{WebhookToken}
<label for="minimum_time_limit">Minimum time between notifications of the same species (sec):</label>
<input type="number" id="minimum_time_limit" name="minimum_time_limit" value="<?php echo $config['APPRISE_MINIMUM_SECONDS_BETWEEN_NOTIFICATIONS_PER_SPECIES'];?>" min="0"><br>
<label for="only_notify_species_names">Exclude these species (comma separated common names):</label>
<input type="text" id="only_notify_species_names" placeholder="Northern Cardinal,American Crow,Carolina Chickadee" name="only_notify_species_names" value="<?php echo $config['APPRISE_ONLY_NOTIFY_SPECIES_NAMES'];?>" size=96><br>
<input type="text" id="only_notify_species_names" placeholder="Mourning Dove,American Crow" name="only_notify_species_names" value="<?php echo $config['APPRISE_ONLY_NOTIFY_SPECIES_NAMES'];?>" size=96><br>
<label for="only_notify_species_names_2">ONLY notify for these species (comma separated common names):</label>
<input type="text" id="only_notify_species_names_2" placeholder="Northern Cardinal,Carolina Chickadee,Eastern Bluebird" name="only_notify_species_names_2" value="<?php echo $config['APPRISE_ONLY_NOTIFY_SPECIES_NAMES_2'];?>" size=96><br>
<br>
+16 -6
View File
@@ -81,24 +81,25 @@ plot.set(xlabel="Detections")
# Generate crosstab matrix for heatmap plot
heat = pd.crosstab(df_plt_top10_today['Com_Name'], df_plt_top10_today['Hour of Day'])
# Order heatmap Birds by frequency of occurrance
heat.index = pd.CategoricalIndex(heat.index, categories=freq_order)
heat.sort_index(level=0, inplace=True)
hours_in_day = pd.Series(data=range(0, 24))
heat_frame = pd.DataFrame(data=0, index=heat.index, columns=hours_in_day)
heat = (heat + heat_frame).fillna(0)
# Generatie heatmap plot
# Get current hour
current_hour = now.hour
# Generate heatmap plot
plot = sns.heatmap(
heat,
norm=LogNorm(),
annot=True,
annot_kws={
"fontsize": 7},
annot_kws={"fontsize": 7},
fmt="g",
cmap=pal,
square=False,
@@ -106,9 +107,18 @@ plot = sns.heatmap(
linewidths=0.5,
linecolor="Grey",
ax=axs[1],
yticklabels=False)
yticklabels=False
)
# Set color and weight of tick label for current hour
for label in plot.get_xticklabels():
if int(label.get_text()) == current_hour:
label.set_color('yellow')
plot.set_xticklabels(plot.get_xticklabels(), rotation=0, size=7)
# Set heatmap border
for _, spine in plot.spines.items():
spine.set_visible(True)
+3 -1
View File
@@ -4,7 +4,9 @@ Below is the information I would like to use to request a BirdWeather ID
%0A%0A
Latitude={{ LATITUDE }}%0A
Longitude={{ LONGITUDE }}%0A
Location= [ Create a location name ]%0A
City= [ City ]%0A
State= [ State ]%0A
Country= [ Country ]%0A
%0A%0A
Thank you so much!%0A
[ Your Name Here ]
+1
View File
@@ -106,6 +106,7 @@ APPRISE_WEEKLY_REPORT=1
APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY=0
APPRISE_MINIMUM_SECONDS_BETWEEN_NOTIFICATIONS_PER_SPECIES=0
APPRISE_ONLY_NOTIFY_SPECIES_NAMES=""
APPRISE_ONLY_NOTIFY_SPECIES_NAMES_2=""
#---------------------- Flickr Images API Configuration -----------------------#
## If FLICKR_API_KEY is set, the web interface will try and display bird images
+3 -3
View File
@@ -231,7 +231,7 @@ function toggleLock(filename, type, elem) {
elem.setAttribute("onclick", elem.getAttribute("onclick").replace("add","del"));
} else {
elem.setAttribute("src","images/unlock.svg");
elem.setAttribute("title", "This file is not excluded from being purged.");
elem.setAttribute("title", "This file will be deleted when disk space needs to be freed.");
elem.setAttribute("onclick", elem.getAttribute("onclick").replace("del","add"));
}
}
@@ -499,7 +499,7 @@ echo "<table>
if($config["FULL_DISK"] == "purge") {
if(!in_array($filename_formatted, $disk_check_exclude_arr)) {
$imageicon = "images/unlock.svg";
$title = "This file is not excluded from being purged.";
$title = "This file will be deleted when disk space needs to be freed (>95% usage).";
$type = "add";
} else {
$imageicon = "images/lock.svg";
@@ -574,7 +574,7 @@ echo "<table>
if($config["FULL_DISK"] == "purge") {
if(!in_array($filename_formatted, $disk_check_exclude_arr)) {
$imageicon = "images/unlock.svg";
$title = "This file is not excluded from being purged.";
$title = "This file will be deleted when disk space needs to be freed (>95% usage).";
$type = "add";
} else {
$imageicon = "images/lock.svg";
+5 -5
View File
@@ -71,7 +71,7 @@ def loadModel():
print('LOADING TF LITE MODEL...', end=' ')
# Load TFLite model and allocate tensors.
# model will either be BirdNET_GLOBAL_3K_V2.2_Model_FP16 (new) or BirdNET_6K_GLOBAL_MODEL (old)
# model will either be BirdNET_GLOBAL_3K_V2.3_Model_FP16 (new) or BirdNET_6K_GLOBAL_MODEL (old)
modelpath = userDir + '/BirdNET-Pi/model/'+model+'.tflite'
myinterpreter = tflite.Interpreter(model_path=modelpath, num_threads=2)
myinterpreter.allocate_tensors()
@@ -104,7 +104,7 @@ def loadMetaModel():
global M_OUTPUT_LAYER_INDEX
# Load TFLite model and allocate tensors.
M_INTERPRETER = tflite.Interpreter(model_path=userDir + '/BirdNET-Pi/model/BirdNET_GLOBAL_3K_V2.2_MData_Model_FP16.tflite')
M_INTERPRETER = tflite.Interpreter(model_path=userDir + '/BirdNET-Pi/model/BirdNET_GLOBAL_3K_V2.3_MData_Model_FP16.tflite')
M_INTERPRETER.allocate_tensors()
# Get input and output tensors.
@@ -272,7 +272,7 @@ def analyzeAudioData(chunks, lat, lon, week, sensitivity, overlap,):
start = time.time()
print('ANALYZING AUDIO...', end=' ', flush=True)
if model == "BirdNET_GLOBAL_3K_V2.2_Model_FP16":
if model == "BirdNET_GLOBAL_3K_V2.3_Model_FP16":
if len(PREDICTED_SPECIES_LIST) == 0 or len(INCLUDE_LIST) != 0:
predictSpeciesList(lat,lon,week)
@@ -584,8 +584,8 @@ def handle_client(conn, addr):
post_commonName = "\"commonName\": \"" + entry[0].split('_')[1].split("/")[0] + "\","
post_scientificName = "\"scientificName\": \"" + entry[0].split('_')[0] + "\","
if model == "BirdNET_GLOBAL_3K_V2.2_Model_FP16":
post_algorithm = "\"algorithm\": " + "\"2p2\"" + ","
if model == "BirdNET_GLOBAL_3K_V2.3_Model_FP16":
post_algorithm = "\"algorithm\": " + "\"2p3\"" + ","
else:
post_algorithm = "\"algorithm\": " + "\"alpha\"" + ","
+1 -1
View File
@@ -31,7 +31,7 @@ def loadMetaModel():
global CLASSES
# Load TFLite model and allocate tensors.
M_INTERPRETER = tflite.Interpreter(model_path=userDir + '/BirdNET-Pi/model/BirdNET_GLOBAL_3K_V2.2_MData_Model_FP16.tflite')
M_INTERPRETER = tflite.Interpreter(model_path=userDir + '/BirdNET-Pi/model/BirdNET_GLOBAL_3K_V2.3_MData_Model_FP16.tflite')
M_INTERPRETER.allocate_tensors()
# Get input and output tensors.
+3 -2
View File
@@ -142,7 +142,8 @@ tr:first-child td {
</style>
</div>
<dialog id="attribution-dialog">
<dialog style="margin-top: 5px;max-height: 95vh;
overflow-y: auto;overscroll-behavior:contain" id="attribution-dialog">
<h1 id="modalHeading"></h1>
<p id="modalText"></p>
<button onclick="hideDialog()">Close</button>
@@ -162,7 +163,7 @@ function hideDialog() {
function setModalText(iter, title, text, authorlink) {
document.getElementById('modalHeading').innerHTML = "Photo "+iter+": \""+title+"\" Attribution";
document.getElementById('modalText').innerHTML = "Image link: <a target='_blank' href="+text+">"+text+"</a><br>Author link: <a target='_blank' href="+authorlink+">"+authorlink+"</a>";
document.getElementById('modalText').innerHTML = "<div style='white-space:nowrap'>Image link: <a target='_blank' href="+text+">"+text+"</a><br>Author link: <a target='_blank' href="+authorlink+">"+authorlink+"</a></div>";
showDialog();
}
</script>
+13
View File
@@ -190,6 +190,9 @@ fi
if ! grep APPRISE_ONLY_NOTIFY_SPECIES_NAMES /etc/birdnet/birdnet.conf &>/dev/null;then
sudo -u$USER echo "APPRISE_ONLY_NOTIFY_SPECIES_NAMES=\"\"" >> /etc/birdnet/birdnet.conf
fi
if ! grep APPRISE_ONLY_NOTIFY_SPECIES_NAMES_2 /etc/birdnet/birdnet.conf &>/dev/null;then
sudo -u$USER echo "APPRISE_ONLY_NOTIFY_SPECIES_NAMES_2=\"\"" >> /etc/birdnet/birdnet.conf
fi
if ! grep RTSP_STREAM_TO_LIVESTREAM /etc/birdnet/birdnet.conf &>/dev/null;then
sudo -u$USER echo "RTSP_STREAM_TO_LIVESTREAM=\"0\"" >> /etc/birdnet/birdnet.conf
@@ -214,5 +217,15 @@ if ! grep LogLevel_SpectrogramViewerService /etc/birdnet/birdnet.conf &>/dev/nul
sudo -u$USER echo "LogLevel_SpectrogramViewerService=\"error\"" >> /etc/birdnet/birdnet.conf
fi
if grep -q '^MODEL=BirdNET_GLOBAL_3K_V2.2_Model_FP16$' /etc/birdnet/birdnet.conf;then
language=$(grep "^DATABASE_LANG=" /etc/birdnet/birdnet.conf | cut -d= -f2)
sed -i 's/BirdNET_GLOBAL_3K_V2.2_Model_FP16/BirdNET_GLOBAL_3K_V2.3_Model_FP16/' /etc/birdnet/birdnet.conf
sed -i 's/BirdNET_GLOBAL_3K_V2.2_Model_FP16/BirdNET_GLOBAL_3K_V2.3_Model_FP16/' $HOME/BirdNET-Pi/scripts/thisrun.txt
sed -i 's/BirdNET_GLOBAL_3K_V2.2_Model_FP16/BirdNET_GLOBAL_3K_V2.3_Model_FP16/' $HOME/BirdNET-Pi/birdnet.conf
cp -f $HOME/BirdNET-Pi/model/labels.txt $HOME/BirdNET-Pi/model/labels.txt.old
sudo chmod +x $HOME/BirdNET-Pi/scripts/install_language_label_nm.sh && $HOME/BirdNET-Pi/scripts/install_language_label_nm.sh -l "$language"
fi
sudo systemctl daemon-reload
restart_services.sh
+5
View File
@@ -51,6 +51,11 @@ def sendAppriseNotifications(species, confidence, path, date, time, week, latitu
if APPRISE_ONLY_NOTIFY_SPECIES_NAMES is not None and APPRISE_ONLY_NOTIFY_SPECIES_NAMES.strip() != "":
if any(bird.lower().replace(" ", "") in comName.lower().replace(" ", "") for bird in APPRISE_ONLY_NOTIFY_SPECIES_NAMES.split(",")):
return
APPRISE_ONLY_NOTIFY_SPECIES_NAMES_2 = settings_dict.get('APPRISE_ONLY_NOTIFY_SPECIES_NAMES_2')
if APPRISE_ONLY_NOTIFY_SPECIES_NAMES_2 is not None and APPRISE_ONLY_NOTIFY_SPECIES_NAMES_2.strip() != "":
if not any(bird.lower().replace(" ", "") in comName.lower().replace(" ", "") for bird in APPRISE_ONLY_NOTIFY_SPECIES_NAMES_2.split(",")):
return
APPRISE_MINIMUM_SECONDS_BETWEEN_NOTIFICATIONS_PER_SPECIES = settings_dict.get('APPRISE_MINIMUM_SECONDS_BETWEEN_NOTIFICATIONS_PER_SPECIES')
if APPRISE_MINIMUM_SECONDS_BETWEEN_NOTIFICATIONS_PER_SPECIES != "0":
+5 -1
View File
@@ -210,7 +210,11 @@ while($detection=$result1->fetchArray(SQLITE3_ASSOC))
$totalcount = $result2->fetchArray(SQLITE3_ASSOC);
$priorweekcount = $totalcount['COUNT(*)'];
$percentagediff = round( (($scount - $priorweekcount) / $priorweekcount) * 100 );
if ($priorweekcount > 0) {
$percentagediff = round( (($scount - $priorweekcount) / $priorweekcount) * 100 );
} else {
$percentagediff = 0;
}
if($percentagediff > 0) {
$percentagediff = "<span style='color:green;font-size:small'>+".$percentagediff."%</span>";