-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
334 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
services/ansible_openvpn/docker/dashboard/app/static/annotate.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
|
||
.a-button { | ||
background-color: #008CBA; | ||
border: none; | ||
color: white; | ||
padding: 15px 32px; | ||
text-align: center; | ||
text-decoration: none; | ||
display: inline-block; | ||
font-size: 16px; | ||
} | ||
.a-button:hover { | ||
cursor: pointer; | ||
} | ||
.a-button:disabled { | ||
background-color: #e7e7e7 !important; | ||
color: black !important; | ||
} /* Gray */ | ||
.a-button-default {background-color: #008CBA;} /* Blue */ | ||
.a-button-warning {background-color: #ffa500;} /* Orange */ | ||
.a-button-success {background-color: #04AA6D;} /* Green */ | ||
.a-button-error {background-color: #f44336;} /* Red */ |
192 changes: 192 additions & 0 deletions
192
services/ansible_openvpn/docker/dashboard/app/static/read_trigger_annotate.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
import WaveSurfer from '/static/wavesurfer.esm.js' | ||
import Spectrogram from '/static/spectrogram.esm.js' | ||
|
||
var privateKey = null; | ||
|
||
var updating = false; | ||
var currentAudioAttributes = null; | ||
|
||
async function do_decrypt(jsonContent) { | ||
const el = document.getElementById("error_panel"); | ||
try { | ||
const encrypted = atob(jsonContent.encrypted_audio); | ||
if(privateKey == null) { | ||
// convert a Forge certificate from PEM | ||
const pem = await $('input[name="privkey"]')[0].files[0].text(); | ||
const pki = forge.pki; | ||
privateKey = pki.decryptRsaPrivateKey(pem, $('input[name="pwd"]')[0].value); | ||
} | ||
if (privateKey == null) { | ||
el.style.visibility = "visible"; | ||
el.innerHTML = "Invalid decryption key or password"; | ||
return; | ||
} else { | ||
el.style.visibility = "hidden"; | ||
const keyLength = privateKey.n.bitLength() / 8; | ||
const decrypted = privateKey.decrypt(encrypted.substring(0, keyLength ), 'RSA-OAEP'); | ||
const aes_key = decrypted.substring(0, 16); | ||
const iv = decrypted.substring(16, 32); | ||
const decipher = forge.cipher.createDecipher('AES-CBC', aes_key); | ||
decipher.start({iv: iv}); | ||
decipher.update(forge.util.createBuffer(encrypted.substring(keyLength))); | ||
const result = decipher.finish(); // check 'result' for true/false | ||
// outputs decrypted hex | ||
// Create regex patterns for replacing unwanted characters in file name | ||
let format = "raw"; | ||
// look for magic word in file header | ||
if(decipher.output.data.substring(0,4) == "fLaC") { | ||
format = "flac"; | ||
} else if(decipher.output.data.substring(0,3) == "Ogg") { | ||
format = "ogg"; | ||
} | ||
return {"data": decipher.output.data, "jsonContent": jsonContent, "format" : format} | ||
} | ||
} catch (e) { | ||
el.style.visibility = "visible"; | ||
el.innerHTML = "No private key file submitted "+e; | ||
return; | ||
} | ||
} | ||
|
||
async function do_decrypt_and_play(jsonContent) { | ||
const decrypted_data = await do_decrypt(jsonContent); | ||
var len = decrypted_data.data.length; | ||
var buf = new ArrayBuffer(len); | ||
var view = new Uint8Array(buf); | ||
for (var i = 0; i < len; i++) { | ||
view[i] = decrypted_data.data.charCodeAt(i) & 0xff; | ||
} | ||
let b = new Blob([view], { type : "audio/"+decrypted_data.format }); | ||
ws.loadBlob(b); | ||
} | ||
|
||
function next_and_play() { | ||
updating = true; | ||
updateButtons() | ||
$.ajax({ | ||
type: "GET", | ||
url: "api/random-sample", | ||
success: function(jsonContent) { | ||
updating = false; | ||
updateButtons(); | ||
currentAudioAttributes = Object.assign({}, jsonContent) | ||
delete currentAudioAttributes.encrypted_audio | ||
do_decrypt_and_play(jsonContent); | ||
}, | ||
error: function(xhr, status, error) { | ||
console.log("Error: " + error) | ||
updating = false; | ||
updateButtons() | ||
}, | ||
contentType : 'application/json', | ||
}); | ||
} | ||
|
||
// Create an instance of WaveSurfer | ||
const ws = WaveSurfer.create({ | ||
container: '#waveform', | ||
waveColor: 'rgb(200, 0, 200)', | ||
progressColor: 'rgb(100, 0, 100)', | ||
normalize: true, | ||
mediaControls:true, | ||
height: 0, | ||
}) | ||
|
||
// Initialize the Spectrogram plugin | ||
ws.registerPlugin( | ||
Spectrogram.create({ | ||
labels: true, | ||
labelsColor: "#7c9cb6", | ||
height: 200, | ||
splitChannels: true, | ||
maxFrequency: 8000 | ||
}), | ||
) | ||
|
||
// Play on click | ||
ws.once('interaction', () => { | ||
ws.play() | ||
}) | ||
|
||
// Create Web Audio context | ||
const audioContext = new AudioContext() | ||
|
||
var gainNode = null | ||
|
||
// Connect the audio to the equalizer | ||
ws.media.addEventListener( | ||
'canplay', | ||
() => { | ||
// Create a MediaElementSourceNode from the audio element | ||
const mediaNode = audioContext.createMediaElementSource(ws.media) | ||
|
||
gainNode = audioContext.createGain(); | ||
gainNode.gain.value = 100 * ws.media.volume; | ||
mediaNode.connect(gainNode); | ||
// Connect the filters to the audio output | ||
gainNode.connect(audioContext.destination) | ||
}, | ||
{ once: true }, | ||
) | ||
|
||
ws.media.onvolumechange = function() { | ||
if(gainNode != null) { | ||
gainNode.gain.value = 100 * ws.media.volume; | ||
} | ||
} | ||
|
||
|
||
function do_update_sample() { | ||
if(updating) { | ||
return; | ||
} | ||
updating = true; | ||
updateButtons(); | ||
|
||
$.ajax({ | ||
type: "POST", | ||
url: "api/update-sample", | ||
data: JSON.stringify(currentAudioAttributes), | ||
contentType : 'application/json', | ||
success: next_and_play, | ||
error: function(xhr, status, error) { | ||
console.log("Error: " + error) | ||
updating = false; | ||
updateButtons() | ||
}, | ||
}); | ||
} | ||
|
||
function updateButtons() { | ||
if (updating) { | ||
$(".fa-refresh").show(); | ||
$(".a-button").prop("disabled",true); | ||
// $("#train_button > button").addClass("a-button-disable").prop("disabled",true);; | ||
} else { | ||
$(".fa-refresh").hide(); | ||
$(".a-button").prop("disabled",false); | ||
// $("#train_button > button").removeClass("a-button-disable").prop("disabled",false);; | ||
} | ||
} | ||
|
||
function train_click() { | ||
console.log("train_click") | ||
currentAudioAttributes["annotation"] = "train" | ||
do_update_sample() | ||
} | ||
function not_train_click() { | ||
console.log("not_train_click") | ||
currentAudioAttributes["annotation"] = "not_train" | ||
do_update_sample() | ||
} | ||
function not_sure_click() { | ||
console.log("not_sure_click") | ||
currentAudioAttributes["annotation"] = "not_sure" | ||
do_update_sample() | ||
} | ||
|
||
document.getElementById('next_button').addEventListener('click', next_and_play) | ||
|
||
document.getElementById('not_train_button').addEventListener('click', not_train_click) | ||
document.getElementById('not_sure_button').addEventListener('click', not_sure_click) | ||
document.getElementById('train_button').addEventListener('click', train_click) |
66 changes: 66 additions & 0 deletions
66
services/ansible_openvpn/docker/dashboard/app/templates/annotate.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>Annotate</title> | ||
|
||
<script type="text/javascript" src="static/forge.min.js"></script> | ||
<script type="text/javascript" src="static/jquery.min.js"></script> | ||
<script type="text/javascript" src="static/moment.min.js"></script> | ||
<script type="text/javascript" src="static/download.min.js"></script> | ||
<script type="text/javascript" src="static/daterangepicker.min.js"></script> | ||
<script type="text/javascript" src="static/handsontable.full.js"></script> | ||
<link type="text/css" href="static/handsontable.full.css" rel="stylesheet" media="screen"> | ||
<link rel="stylesheet" type="text/css" href="static/daterangepicker.css"/> | ||
<link rel="stylesheet" type="text/css" href="static/forms.css"/> | ||
<link rel="stylesheet" type="text/css" href="static/status.css"/> | ||
<link rel="stylesheet" type="text/css" href="static/annotate.css"/> | ||
<!-- Add icon library --> | ||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css""> | ||
</head> | ||
<body> | ||
<div class="info top_menu"> | ||
<ul class="ul_top_menu"> | ||
<li class="li_top_menu"><a href="/" target="_self">Map</a></li> | ||
<li class="li_top_menu"><a href="/recordings" target="_self" style="outline: none;">Audio records</a></li> | ||
<li class="li_top_menu"><a href="/devices" target="_self" style="outline: none;">Connected devices</a></li> | ||
<li class="li_top_menu"><a href="https://nsraw.noise-planet.org" target="_blank">Backup data</a></li> | ||
</ul> | ||
</div> | ||
<div class="form-style-7"> | ||
<h1>Annotate</h1> | ||
<div id="error_panel" class="msg_error" style="visibility: hidden;"> | ||
Invalid decryption key or password | ||
</div> | ||
<ul> | ||
<li> | ||
<label for="privkey">Private key and password</label> | ||
<input type="file" name="privkey" accept=".priv,.pem"> | ||
<input type="password" name="pwd" placeholder="Key File password"/> | ||
<span>Encryption private key and password, not transferred</span> | ||
</li> | ||
<li> | ||
<button class="a-button a-button-default" id="next_button"> | ||
<i class="fa fa-refresh fa-spin" style="display: none;"> </i> Next | ||
</button> | ||
</li> | ||
<li> | ||
<div id="waveform"></div> | ||
</li> | ||
<li id="train_buttons"> | ||
|
||
<button class="a-button a-button-error" id="not_train_button" disabled> | ||
<i class="fa fa-xmark"> </i> Not a train | ||
</button> | ||
<button class="a-button a-button-warning" id="not_sure_button" disabled> | ||
<i class="fa fa-question"></i> Not sure | ||
</button> | ||
<button class="a-button a-button-success" id="train_button" disabled> | ||
<i class="fa fa-check"></i> Train ! | ||
</button> | ||
</li> | ||
</ul> | ||
</div> | ||
<script type="module" src="static/read_trigger_annotate.js" data-type="module" defer></script> | ||
</body> | ||
</html> |
18 changes: 18 additions & 0 deletions
18
services/ansible_openvpn/docker/dashboard/app/templates/trigger_random.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"index": "sensor_yamnet_*", | ||
"size" : 1, | ||
"_source": true, | ||
"query": { | ||
"function_score": { | ||
"query": { | ||
"range": { | ||
"date": { | ||
"gte": "2024-06-01", | ||
"lte": "2024-11-31" | ||
} | ||
} | ||
}, | ||
"random_score": {} | ||
} | ||
} | ||
} |