From 41dc4bfd6791e7a3d441c4140764c98d38acedb9 Mon Sep 17 00:00:00 2001 From: Mattk70 Date: Wed, 24 Jan 2024 11:44:12 +0000 Subject: [PATCH] Amended exporting functions for readability Disabled context & SNR modes for BirdNET model --- js/BirdNet2.4.js | 2 +- js/ui.js | 43 +++++++++++++++++++++++++++++-------------- js/worker.js | 16 +++++++++------- package.json | 2 +- 4 files changed, 40 insertions(+), 23 deletions(-) diff --git a/js/BirdNet2.4.js b/js/BirdNet2.4.js index 38ad7653..71ffce89 100644 --- a/js/BirdNet2.4.js +++ b/js/BirdNet2.4.js @@ -309,7 +309,7 @@ class Model { addContext(prediction, tensor, confidence) { // Create a set of images from the batch, offset by half the width of the original images - const [batchSize, height, width, channel] = tensor.shape; + const [_, height, width, channel] = tensor.shape; return tf.tidy(() => { const firstHalf = tensor.slice([0, 0, 0, 0], [-1, -1, width / 2, -1]); const secondHalf = tensor.slice([0, 0, width / 2, 0], [-1, -1, width / 2, -1]); diff --git a/js/ui.js b/js/ui.js index b5154bbd..9b844d77 100644 --- a/js/ui.js +++ b/js/ui.js @@ -952,25 +952,26 @@ export2audio.addEventListener('click', batchExportAudio); async function batchExportAudio(e) { const species = isSpeciesViewFiltered(true); // || getSpecies(e.target); - species ? exportData(species, 1000) : alert("Filter results by species to export audio files"); + species ? exportData('audio', species, 1000) : alert("Filter results by species to export audio files"); } -const export2CSV = () => exportData(isSpeciesViewFiltered(true), Infinity); +const export2CSV = () => exportData('text', isSpeciesViewFiltered(true), Infinity); -async function exportData(species, limit){ +async function exportData(format, species, limit){ const response = await window.electron.selectDirectory('selectDirectory'); if (!response.canceled) { const directory = response.filePaths[0]; worker.postMessage({ action: 'export-results', - exportTo: directory, + directory: directory, + format: format, species: species, files: isExplore() ? [] : fileList, explore: isExplore(), limit: limit, range: isExplore() ? STATE.explore.range : undefined }) - } + } } const chartsLink = document.getElementById('charts'); @@ -1320,8 +1321,6 @@ function updatePrefs() { ///////////////////////// Window Handlers //////////////////////////// let appPath, tempPath; window.onload = async () => { - const startOnload = performance.now(); - console.log('To Page onload took:', startOnload - startTime) window.electron.requestWorkerChannel(); contentWrapperElement.classList.add('loaded'); // Set config defaults @@ -1404,7 +1403,16 @@ window.onload = async () => { audioFade.disabled = !audioPadding.checked; audioDownmix.checked = config.audio.downmix; setNocmig(config.detect.nocmig); - contextAware.checked = config.detect.contextAware; + if (config.model !== 'v2.4'){ + contextAware.checked = config.detect.contextAware + SNRSlider.disabled = false; + } else { + contextAware.checked = false; + contextAware.disabed = true; + config.detect.contextAware = false; + SNRSlider.disabled = true; + config.filters.SNR = 0; + } contextAwareIconDisplay(); debugMode.checked = config.debug; showThreshold(config.detect.confidence); @@ -1451,13 +1459,11 @@ window.onload = async () => { } ) // establish the message channel - setUpWorkerMessaging() // Set footer year document.getElementById('year').textContent = new Date().getFullYear(); - const endOnload = performance.now(); - console.log('Page onload took:', endOnload -startOnload) + } const setUpWorkerMessaging = () => { @@ -2148,6 +2154,16 @@ const loadModel = () => { const modelToUse = document.getElementById('model-to-use'); modelToUse.addEventListener('change', function (e) { config.model = e.target.value; + if (config.model === 'v2.4') { + contextAware.checked = false; + contextAware.disabed = true; + config.detect.contextAware = false; + SNRSlider.disabled = true; + config.filters.SNR = 0; + } else { + contextAware.disabed = false; + SNRSlider.disabled = false; + } updatePrefs(); loadModel(); }) @@ -3245,13 +3261,13 @@ const toggleFilters = () => { audioFiltersIcon.addEventListener('click', toggleFilters); const toggleContextAwareMode = () => { - config.detect.contextAware = !config.detect.contextAware; + if (config.model !== 'v2.4') config.detect.contextAware = !config.detect.contextAware; contextAware.checked = config.detect.contextAware; contextAwareIconDisplay(); if (config.detect.contextAware) { SNRSlider.disabled = true; config.filters.SNR = 0; - } else if (config.backend !== 'webgl') { + } else if (config.backend !== 'webgl' && config.model !== 'v2.4') { SNRSlider.disabled = false; config.filters.SNR = parseFloat(SNRSlider.value); } @@ -3754,7 +3770,6 @@ const handleSNRchange = () => { if (config.filters.SNR > 0) { config.detect.contextAware = false; contextAware.disabled = true; - } else { config.detect.contextAware = contextAware.checked; contextAware.disabled = false; diff --git a/js/worker.js b/js/worker.js index dc04ccdc..e1939ee1 100644 --- a/js/worker.js +++ b/js/worker.js @@ -2167,7 +2167,8 @@ const getSummary = async ({ * @param limit: the pagination limit per page * @param offset: is the SQL query offset to use * @param topRankin: return results >= to this rank for each datetime - * @param exportTo: if set, will export audio of the returned results to this folder + * @param directory: if set, will export audio of the returned results to this folder + * @param format: whether to export audio or text * * @returns {Promise } A count of the records retrieved */ @@ -2176,7 +2177,8 @@ const getResults = async ({ limit = STATE.limit, offset = undefined, topRankin = STATE.topRankin, - exportTo = undefined, + directory = undefined, + format = undefined, active = undefined } = {}) => { let confidence = STATE.detect.confidence; @@ -2198,13 +2200,13 @@ const getResults = async ({ prepResultsStatement(species, limit === Infinity); const result = await STATE.GET_RESULT_SQL.allAsync(...params); - if (exportTo && limit === Infinity){ + if (format === 'text'){ // CSV export. Format the values const formattedValues = result.map(formatCSVValues); // Create a write stream for the CSV file let filename = species || 'All'; filename += '_detections.csv'; - const filePath = p.join(exportTo, filename); + const filePath = p.join(directory, filename); writeToPath(filePath, formattedValues, {headers: true}) .on('error', err => UI.postMessage({event: 'generate-alert', message: `Cannot save file ${filePath}\nbecause it is open in another application`})) .on('finish', () => { @@ -2214,13 +2216,13 @@ const getResults = async ({ else { for (let i = 0; i < result.length; i++) { const r = result[i]; - if (exportTo) { + if (format === 'audio') { if (limit){ // Audio export. Format date to YYYY-MM-DD-HH-MM-ss const dateString = new Date(r.timestamp).toISOString().replace(/[TZ]/g, ' ').replace(/\.\d{3}/, '').replace(/[-:]/g, '-').trim(); const filename = `${r.cname}-${dateString}.${STATE.audio.format}` - console.log(`Exporting from ${r.file}, position ${r.position}, into folder ${exportTo}`) - saveAudio(r.file, r.position, r.position + 3, filename, metadata, exportTo) + console.log(`Exporting from ${r.file}, position ${r.position}, into folder ${directory}`) + saveAudio(r.file, r.position, r.position + 3, filename, metadata, directory) i === result.length - 1 && UI.postMessage({ event: 'generate-alert', message: `${result.length} files saved` }) } } diff --git a/package.json b/package.json index ce115b7a..cbbfd3e8 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "start": "electron .", "minify": "node minify.js", "export": "electron-builder build -w --x64", - "publish": "electron-builder --win --x64 -p always" + "publish": "electron-builder --win --x64 -p always" }, "repository": { "type": "git",