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:
|
||||
return None
|
||||
|
||||
|
||||
def audio_backend_detect():
|
||||
if AUDIO_BACKEND in ('pactl', 'alsa'):
|
||||
return AUDIO_BACKEND
|
||||
|
||||
@ -18,7 +18,7 @@ DETECTOR_BACKEND = "yolo"
|
||||
CONF_THRES = 0.30
|
||||
IMG_SIZE = 640
|
||||
INFER_FPS = 8
|
||||
SHOW_FPS_DEFAULT = True
|
||||
SHOW_FPS_DEFAULT = False #Afficher les FPS True ou False
|
||||
|
||||
# Configuration TTS (Piper) et STT (Vosk)
|
||||
PIPER_MODEL = "/data/piper_model/fr_FR-siwis-low.onnx"
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<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" />
|
||||
<style>
|
||||
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>
|
||||
</head>
|
||||
<body>
|
||||
<header><strong>Diffusion Caméra USB</strong></header>
|
||||
<header><strong> Alfred </strong></header>
|
||||
<div class="wrap">
|
||||
|
||||
<!-- Ligne actions au-dessus de la vidéo -->
|
||||
@ -46,7 +46,7 @@
|
||||
<div class="card" style="flex:1 1 100%">
|
||||
<div class="row">
|
||||
<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="volMute" class="btn">🔇 Mute</button>
|
||||
<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