frontend: prevent overlapping per-line playback; backend: print idle eviction settings on startup\n\n- app.js: add shared Audio state, disable play button while playing, stop previous line when new one plays\n- start_server.py: print eviction enabled/timeout/check interval\n- app/main.py: log eviction settings during FastAPI startup

This commit is contained in:
Steve White 2025-08-12 17:37:32 -05:00
parent cbc164c7a3
commit c9593fe6cc
3 changed files with 60 additions and 4 deletions

View File

@ -68,6 +68,14 @@ async def _start_model_reaper():
except Exception: except Exception:
logger.exception("Model reaper encountered an error") logger.exception("Model reaper encountered an error")
# Log eviction configuration at startup
logger.info(
"Model Eviction -> enabled: %s | idle_timeout: %ss | check_interval: %ss",
getattr(config, "MODEL_EVICTION_ENABLED", True),
getattr(config, "MODEL_IDLE_TIMEOUT_SECONDS", 0),
getattr(config, "MODEL_IDLE_CHECK_INTERVAL_SECONDS", 60),
)
app.state._model_reaper_task = asyncio.create_task(reaper()) app.state._model_reaper_task = asyncio.create_task(reaper())

View File

@ -14,6 +14,14 @@ if __name__ == "__main__":
print(f"CORS Origins: {config.CORS_ORIGINS}") print(f"CORS Origins: {config.CORS_ORIGINS}")
print(f"Project Root: {config.PROJECT_ROOT}") print(f"Project Root: {config.PROJECT_ROOT}")
print(f"Device: {config.DEVICE}") print(f"Device: {config.DEVICE}")
# Idle eviction settings
print(
"Model Eviction -> enabled: {} | idle_timeout: {}s | check_interval: {}s".format(
getattr(config, "MODEL_EVICTION_ENABLED", True),
getattr(config, "MODEL_IDLE_TIMEOUT_SECONDS", 0),
getattr(config, "MODEL_IDLE_CHECK_INTERVAL_SECONDS", 60),
)
)
uvicorn.run( uvicorn.run(
"app.main:app", "app.main:app",

View File

@ -1,6 +1,10 @@
import { getSpeakers, addSpeaker, deleteSpeaker, generateDialog } from './api.js'; import { getSpeakers, addSpeaker, deleteSpeaker, generateDialog } from './api.js';
import { API_BASE_URL, API_BASE_URL_FOR_FILES } from './config.js'; import { API_BASE_URL, API_BASE_URL_FOR_FILES } from './config.js';
// Shared per-line audio playback state to prevent overlapping playback
let currentLineAudio = null;
let currentLineAudioBtn = null;
// --- Global Inline Notification Helpers --- // // --- Global Inline Notification Helpers --- //
const noticeEl = document.getElementById('global-notice'); const noticeEl = document.getElementById('global-notice');
const noticeContentEl = document.getElementById('global-notice-content'); const noticeContentEl = document.getElementById('global-notice-content');
@ -399,10 +403,46 @@ async function initializeDialogEditor() {
playBtn.disabled = !item.audioUrl; playBtn.disabled = !item.audioUrl;
playBtn.onclick = () => { playBtn.onclick = () => {
if (!item.audioUrl) return; if (!item.audioUrl) return;
let audioUrl = item.audioUrl.startsWith('http') ? item.audioUrl : `${API_BASE_URL_FOR_FILES}${item.audioUrl}`; const audioUrl = item.audioUrl.startsWith('http') ? item.audioUrl : `${API_BASE_URL_FOR_FILES}${item.audioUrl}`;
// Use a shared audio element or create one per play
let audio = new window.Audio(audioUrl); // If something is already playing
audio.play(); if (currentLineAudio && !currentLineAudio.paused) {
if (currentLineAudioBtn === playBtn) {
// Same line: ignore click to prevent overlapping
return;
}
// Stop previous audio and re-enable its button
try {
currentLineAudio.pause();
currentLineAudio.currentTime = 0;
} catch (e) { /* noop */ }
if (currentLineAudioBtn) {
try { currentLineAudioBtn.disabled = false; } catch (e) { /* detached */ }
}
}
const audio = new window.Audio(audioUrl);
currentLineAudio = audio;
currentLineAudioBtn = playBtn;
// Disable this play button while playing
playBtn.disabled = true;
const clearState = () => {
if (currentLineAudio === audio) {
currentLineAudio = null;
currentLineAudioBtn = null;
}
try { playBtn.disabled = false; } catch (e) { /* detached */ }
};
audio.addEventListener('ended', clearState, { once: true });
audio.addEventListener('error', clearState, { once: true });
audio.play().catch(err => {
console.error('Audio play failed:', err);
clearState();
showNotice('Could not play audio.', 'error', { timeout: 2000 });
});
}; };
actionsTd.appendChild(playBtn); actionsTd.appendChild(playBtn);