Cleaning and optimisation

This commit is contained in:
pporcheret 2025-11-11 14:43:54 +01:00
parent d4b1138482
commit 771a164633
5 changed files with 5 additions and 172 deletions

Binary file not shown.

1
app.py
View File

@ -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

View File

@ -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"

View File

@ -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>

View File

@ -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>