Cleaning and optimisation
This commit is contained in:
parent
d4b1138482
commit
771a164633
Binary file not shown.
1
app.py
1
app.py
@ -25,6 +25,7 @@ def _cmd_ok(cmd, **kwargs):
|
|||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def audio_backend_detect():
|
def audio_backend_detect():
|
||||||
if AUDIO_BACKEND in ('pactl', 'alsa'):
|
if AUDIO_BACKEND in ('pactl', 'alsa'):
|
||||||
return AUDIO_BACKEND
|
return AUDIO_BACKEND
|
||||||
|
|||||||
@ -18,7 +18,7 @@ DETECTOR_BACKEND = "yolo"
|
|||||||
CONF_THRES = 0.30
|
CONF_THRES = 0.30
|
||||||
IMG_SIZE = 640
|
IMG_SIZE = 640
|
||||||
INFER_FPS = 8
|
INFER_FPS = 8
|
||||||
SHOW_FPS_DEFAULT = True
|
SHOW_FPS_DEFAULT = False #Afficher les FPS True ou False
|
||||||
|
|
||||||
# Configuration TTS (Piper) et STT (Vosk)
|
# Configuration TTS (Piper) et STT (Vosk)
|
||||||
PIPER_MODEL = "/data/piper_model/fr_FR-siwis-low.onnx"
|
PIPER_MODEL = "/data/piper_model/fr_FR-siwis-low.onnx"
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Caméra USB – Détection, Volume, TTS & STT (Vosk)</title>
|
<title>Alfred</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<style>
|
<style>
|
||||||
html,body { margin:0; padding:0; background:#111; color:#eee; font-family:system-ui,Segoe UI,Roboto,Arial,sans-serif; }
|
html,body { margin:0; padding:0; background:#111; color:#eee; font-family:system-ui,Segoe UI,Roboto,Arial,sans-serif; }
|
||||||
@ -24,7 +24,7 @@
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header><strong>Diffusion Caméra USB</strong></header>
|
<header><strong> Alfred </strong></header>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
|
|
||||||
<!-- Ligne actions au-dessus de la vidéo -->
|
<!-- Ligne actions au-dessus de la vidéo -->
|
||||||
@ -46,7 +46,7 @@
|
|||||||
<div class="card" style="flex:1 1 100%">
|
<div class="card" style="flex:1 1 100%">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<button id="volDown" class="btn" title="-5%">➖</button>
|
<button id="volDown" class="btn" title="-5%">➖</button>
|
||||||
<input id="volSlider" class="slider" type="range" min="0" max="150" step="1" />
|
<input id="volSlider" class="slider" type="range" min="0" max="100" step="1" />
|
||||||
<button id="volUp" class="btn" title="+5%">➕</button>
|
<button id="volUp" class="btn" title="+5%">➕</button>
|
||||||
<button id="volMute" class="btn">🔇 Mute</button>
|
<button id="volMute" class="btn">🔇 Mute</button>
|
||||||
<span class="badge">backend: <code id="backend">{{ audio_backend }}</code></span>
|
<span class="badge">backend: <code id="backend">{{ audio_backend }}</code></span>
|
||||||
|
|||||||
@ -1,168 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<title>Caméra USB – Détection & Volume</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<style>
|
|
||||||
html,body { margin:0; padding:0; background:#111; color:#eee; font-family:system-ui,Segoe UI,Roboto,Arial,sans-serif; }
|
|
||||||
header { padding:12px 16px; background:#1b1b1b; position:sticky; top:0 }
|
|
||||||
.wrap { max-width:1000px; margin:0 auto; padding:16px }
|
|
||||||
.video { display:block; width:100%; height:auto; border-radius:16px; box-shadow:0 6px 24px rgba(0,0,0,.35); background:#000 }
|
|
||||||
.row { display:flex; gap:12px; flex-wrap:wrap; margin-top:12px; align-items:center }
|
|
||||||
.btn { background:#2c7be5; border:none; color:#fff; padding:10px 14px; border-radius:10px; cursor:pointer; text-decoration:none }
|
|
||||||
.btn.secondary { background:#444 }
|
|
||||||
.btn:active { transform:translateY(1px) }
|
|
||||||
.card { background:#151515; border-radius:16px; padding:14px; box-shadow:0 10px 30px rgba(0,0,0,.35); }
|
|
||||||
.slider { width:240px }
|
|
||||||
.badge { font-size:.85rem; opacity:.85; }
|
|
||||||
.muted { color:#f39; }
|
|
||||||
code { background:#1e1e1e; padding:2px 6px; border-radius:6px; }
|
|
||||||
.pill { padding:4px 8px; border-radius:999px; background:#222; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<header><strong>Diffusion Caméra USB</strong></header>
|
|
||||||
<div class="wrap">
|
|
||||||
|
|
||||||
<!-- Boutons AU-DESSUS de la vidéo -->
|
|
||||||
<div class="row" style="margin-top:2px">
|
|
||||||
<a class="btn" href="{{ url_for('snapshot') }}" target="_blank">📸 Snapshot</a>
|
|
||||||
<button id="btnToggleDetect" class="btn">{{ '🟢 Détection ON' if detect_enabled else '⚪ Détection OFF' }}</button>
|
|
||||||
<button id="btnToggleFps" class="btn secondary">{{ '🙈 Cacher FPS' if show_fps else '👁️ Afficher FPS' }}</button>
|
|
||||||
|
|
||||||
<!-- Petites infos à côté -->
|
|
||||||
<span class="pill">Détecteur: <strong id="detBackend">{{ detector_backend }}</strong></span>
|
|
||||||
<span class="pill">Status: <strong id="detStatus">{{ 'ON' if detect_enabled else 'OFF' }}</strong></span>
|
|
||||||
<span class="pill">FPS: <strong id="fpsText">-- / --</strong></span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Vidéo -->
|
|
||||||
<img class="video" src="{{ url_for('video_feed') }}" alt="Flux caméra (MJPEG)" />
|
|
||||||
|
|
||||||
<!-- Volume -->
|
|
||||||
<div class="row" style="margin-top:18px">
|
|
||||||
<div class="card">
|
|
||||||
<div class="row">
|
|
||||||
<button id="volDown" class="btn" title="-5%">➖</button>
|
|
||||||
<input id="volSlider" class="slider" type="range" min="0" max="150" step="1" />
|
|
||||||
<button id="volUp" class="btn" title="+5%">➕</button>
|
|
||||||
<button id="volMute" class="btn">🔇 Mute</button>
|
|
||||||
</div>
|
|
||||||
<div style="margin-top:8px">
|
|
||||||
Volume: <strong id="volLabel">--%</strong>
|
|
||||||
<span class="badge">backend: <code id="backend">{{ audio_backend }}</code></span>
|
|
||||||
<span id="mutedTag" class="badge muted" style="display:none">[muet]</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// -------- Volume UI --------
|
|
||||||
const slider = document.getElementById('volSlider');
|
|
||||||
const label = document.getElementById('volLabel');
|
|
||||||
const mutedTag = document.getElementById('mutedTag');
|
|
||||||
const backendEl = document.getElementById('backend');
|
|
||||||
const btnUp = document.getElementById('volUp');
|
|
||||||
const btnDown = document.getElementById('volDown');
|
|
||||||
const btnMute = document.getElementById('volMute');
|
|
||||||
|
|
||||||
let vol = {{ initial_volume|int }};
|
|
||||||
let muted = {{ initial_muted|tojson }};
|
|
||||||
let backend = backendEl.textContent || 'auto';
|
|
||||||
|
|
||||||
function renderVolume() {
|
|
||||||
slider.value = vol;
|
|
||||||
label.textContent = vol + '%';
|
|
||||||
mutedTag.style.display = (muted === true) ? 'inline' : 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
async function refreshVolume() {
|
|
||||||
try {
|
|
||||||
const r = await fetch('{{ url_for("api_get_volume") }}');
|
|
||||||
const j = await r.json();
|
|
||||||
if (typeof j.volume === 'number') vol = j.volume;
|
|
||||||
if (typeof j.muted === 'boolean') muted = j.muted;
|
|
||||||
if (j.backend) backendEl.textContent = j.backend;
|
|
||||||
renderVolume();
|
|
||||||
} catch(e) { /* ignore */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
slider.addEventListener('change', async () => {
|
|
||||||
const val = parseInt(slider.value);
|
|
||||||
const r = await fetch('{{ url_for("api_set_volume") }}?level=' + val, { method:'POST' });
|
|
||||||
const j = await r.json();
|
|
||||||
vol = (typeof j.volume === 'number') ? j.volume : val;
|
|
||||||
muted = (typeof j.muted === 'boolean') ? j.muted : muted;
|
|
||||||
renderVolume();
|
|
||||||
});
|
|
||||||
|
|
||||||
btnUp.addEventListener('click', async () => {
|
|
||||||
const r = await fetch('{{ url_for("api_volume_up") }}', { method:'POST' });
|
|
||||||
const j = await r.json();
|
|
||||||
if (typeof j.volume === 'number') vol = j.volume;
|
|
||||||
if (typeof j.muted === 'boolean') muted = j.muted;
|
|
||||||
renderVolume();
|
|
||||||
});
|
|
||||||
|
|
||||||
btnDown.addEventListener('click', async () => {
|
|
||||||
const r = await fetch('{{ url_for("api_volume_down") }}', { method:'POST' });
|
|
||||||
const j = await r.json();
|
|
||||||
if (typeof j.volume === 'number') vol = j.volume;
|
|
||||||
if (typeof j.muted === 'boolean') muted = j.muted;
|
|
||||||
renderVolume();
|
|
||||||
});
|
|
||||||
|
|
||||||
btnMute.addEventListener('click', async () => {
|
|
||||||
const r = await fetch('{{ url_for("api_volume_mute") }}', { method:'POST' });
|
|
||||||
const j = await r.json();
|
|
||||||
if (typeof j.volume === 'number') vol = j.volume;
|
|
||||||
if (typeof j.muted === 'boolean') muted = j.muted;
|
|
||||||
renderVolume();
|
|
||||||
});
|
|
||||||
|
|
||||||
// -------- Détection / FPS UI --------
|
|
||||||
const detBackend = document.getElementById('detBackend');
|
|
||||||
const detStatus = document.getElementById('detStatus');
|
|
||||||
const btnToggleDetect = document.getElementById('btnToggleDetect');
|
|
||||||
const btnToggleFps = document.getElementById('btnToggleFps');
|
|
||||||
const fpsText = document.getElementById('fpsText');
|
|
||||||
|
|
||||||
async function refreshStats() {
|
|
||||||
try {
|
|
||||||
const r = await fetch('/stats');
|
|
||||||
const j = await r.json();
|
|
||||||
detBackend.textContent = j.backend || 'none';
|
|
||||||
detStatus.textContent = j.detect_enabled ? 'ON' : 'OFF';
|
|
||||||
fpsText.textContent = (j.cam_fps?.toFixed ? j.cam_fps.toFixed(1) : j.cam_fps) + ' / ' +
|
|
||||||
(j.infer_fps?.toFixed ? j.infer_fps.toFixed(1) : j.infer_fps);
|
|
||||||
btnToggleDetect.textContent = j.detect_enabled ? '🟢 Détection ON' : '⚪ Détection OFF';
|
|
||||||
btnToggleFps.textContent = j.show_fps ? '🙈 Cacher FPS' : '👁️ Afficher FPS';
|
|
||||||
} catch(e) { /* ignore */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
btnToggleDetect.addEventListener('click', async () => {
|
|
||||||
const r = await fetch('/detect/toggle', { method:'POST' });
|
|
||||||
await r.json();
|
|
||||||
refreshStats();
|
|
||||||
});
|
|
||||||
|
|
||||||
btnToggleFps.addEventListener('click', async () => {
|
|
||||||
const r0 = await fetch('/stats');
|
|
||||||
const s = await r0.json();
|
|
||||||
const desired = !(s.show_fps === true);
|
|
||||||
const r = await fetch('/fps/show?state=' + (desired ? 'true' : 'false'), { method:'POST' });
|
|
||||||
await r.json();
|
|
||||||
refreshStats();
|
|
||||||
});
|
|
||||||
|
|
||||||
// init
|
|
||||||
renderVolume();
|
|
||||||
refreshStats();
|
|
||||||
setInterval(refreshVolume, 3000);
|
|
||||||
setInterval(refreshStats, 1000);
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Loading…
x
Reference in New Issue
Block a user