From 63f947474141cdd86be1969430e457520af312eb Mon Sep 17 00:00:00 2001 From: JB Date: Thu, 9 Oct 2025 05:51:45 -0700 Subject: [PATCH] feat: Implement logging filter for successful HTTP access logs and enhance modal styling for better usability --- abogen/web/app.py | 23 ++++ abogen/web/static/dashboard.js | 41 ------- abogen/web/static/styles.css | 3 + abogen/web/templates/index.html | 191 ++++++++++++++------------------ 4 files changed, 112 insertions(+), 146 deletions(-) diff --git a/abogen/web/app.py b/abogen/web/app.py index 0a4923e..f09dcfb 100644 --- a/abogen/web/app.py +++ b/abogen/web/app.py @@ -1,6 +1,7 @@ from __future__ import annotations import atexit +import logging import os from pathlib import Path from typing import Any, Optional @@ -13,6 +14,23 @@ from .conversion_runner import run_conversion_job from .service import build_service +class _SuppressSuccessfulAccessFilter(logging.Filter): + """Filter out successful (HTTP 200) werkzeug access logs.""" + + def filter(self, record: logging.LogRecord) -> bool: # pragma: no cover - small utility + try: + message = record.getMessage() + except Exception: # pragma: no cover - defensive + return True + # Werkzeug access logs include the status code near the end, e.g. + # "GET /path HTTP/1.1" 200 - + # Treat any 2xx response as success to suppress. + return " 200 " not in message and " 201 " not in message and " 204 " not in message + + +_access_log_filter_attached = False + + def _default_dirs() -> tuple[Path, Path]: uploads_override = os.environ.get("ABOGEN_UPLOAD_ROOT") outputs_override = os.environ.get("ABOGEN_OUTPUT_ROOT") @@ -64,6 +82,11 @@ def create_app(config: Optional[dict[str, Any]] = None) -> Flask: atexit.register(service.shutdown) + global _access_log_filter_attached + if not _access_log_filter_attached: + logging.getLogger("werkzeug").addFilter(_SuppressSuccessfulAccessFilter()) + _access_log_filter_attached = True + return app diff --git a/abogen/web/static/dashboard.js b/abogen/web/static/dashboard.js index 3a59b60..d60fc11 100644 --- a/abogen/web/static/dashboard.js +++ b/abogen/web/static/dashboard.js @@ -10,12 +10,6 @@ const initDashboard = () => { const formulaInput = scope.querySelector('[data-role="voice-formula"]'); const languageSelect = uploadModal?.querySelector("#language") || document.getElementById("language"); - const sourceText = scope.querySelector('[data-role="source-text"]'); - const previewEl = scope.querySelector('[data-role="text-preview"]'); - const previewBody = scope.querySelector('[data-role="preview-body"]'); - const charCountEl = scope.querySelector('[data-role="char-count"]'); - const wordCountEl = scope.querySelector('[data-role="word-count"]'); - let lastTrigger = null; const openUploadModal = (trigger) => { @@ -156,36 +150,6 @@ const initDashboard = () => { } }; - const updatePreview = () => { - if (!sourceText || !previewBody || !charCountEl || !wordCountEl) { - return; - } - const raw = sourceText.value || ""; - const trimmed = raw.trim(); - const charCount = raw.length; - const wordCount = trimmed ? trimmed.split(/\s+/).length : 0; - - const charLabel = `${charCount.toLocaleString()} ${charCount === 1 ? "character" : "characters"}`; - const wordLabel = `${wordCount.toLocaleString()} ${wordCount === 1 ? "word" : "words"}`; - - charCountEl.textContent = charLabel; - wordCountEl.textContent = wordLabel; - - if (!trimmed) { - previewBody.textContent = "Paste text to see a live preview and character count."; - if (previewEl) { - previewEl.setAttribute("data-state", "empty"); - } - return; - } - - const snippet = trimmed.length > 1200 ? `${trimmed.slice(0, 1200)}…` : trimmed; - previewBody.textContent = snippet; - if (previewEl) { - previewEl.setAttribute("data-state", "ready"); - } - }; - if (profileSelect) { const hasSaved = selectFirstProfileIfAvailable(); profileSelect.addEventListener("change", updateVoiceControls); @@ -196,11 +160,6 @@ const initDashboard = () => { } else { hydrateDefaultVoice(); } - - if (sourceText) { - sourceText.addEventListener("input", updatePreview); - updatePreview(); - } }; if (document.readyState === "loading") { diff --git a/abogen/web/static/styles.css b/abogen/web/static/styles.css index fccb1a0..3ab3fd9 100644 --- a/abogen/web/static/styles.css +++ b/abogen/web/static/styles.css @@ -150,6 +150,7 @@ body { align-items: center; justify-content: center; z-index: 300; + overflow-y: auto; } .modal[data-open="true"] { @@ -211,6 +212,7 @@ body { display: flex; flex-direction: column; gap: 1.5rem; + flex: 1 1 auto; } .modal__footer { @@ -246,6 +248,7 @@ body { padding: 1.5rem 1.75rem 1.75rem; overflow-y: auto; max-height: calc(90vh - 150px); + flex: 1 1 auto; } .voice-browser__filters, diff --git a/abogen/web/templates/index.html b/abogen/web/templates/index.html index a0b6c5f..8ff984f 100644 --- a/abogen/web/templates/index.html +++ b/abogen/web/templates/index.html @@ -39,112 +39,93 @@