tts-voice-creator-clone-and.../server.py
mARTin-B78 a5efac5da5 Speed up startup: parallel JS loading + versioned asset caching
loader.js:
- Fetch /api/version first; append ?v=<version> to every script URL
- Load scripts with async=false (fetch in parallel, execute in DOM order)
- 4 sequential batches instead of 17 sequential awaits:
    utils → settings → [9 feature modules] → init → [4 post-init] → nav
- 17 round-trips → 6 round-trips; 9 and 4 files now download in parallel
- Section HTML keeps ?v=<timestamp> (no-store, always fresh)

server.py:
- Add static_cache_headers middleware:
    /static/js/*?v=...  → Cache-Control: max-age=31536000, immutable
    /static/sections/*  → Cache-Control: no-store
    /static/* (no v=)   → Cache-Control: max-age=3600

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 17:11:55 +02:00

86 lines
3.8 KiB
Python

"""TTS Voice Creator - Clone and Design — FastAPI entry point (thin wrapper)."""
from __future__ import annotations
import logging
import os
from logging.handlers import RotatingFileHandler
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.responses import Response
from fastapi.staticfiles import StaticFiles
from core.constants import STATIC_DIR, _BufferHandler
from routes import admin, settings, library, stt, sources, docker, tts, conversation
logger = logging.getLogger("uvicorn.error")
# ── App ───────────────────────────────────────────────────────────────────────
app = FastAPI(title="TTS Voice Creator - Clone and Design")
# ── In-memory log buffer handler ──────────────────────────────────────────────
_buf_handler = _BufferHandler()
_buf_handler.setLevel(logging.DEBUG)
logging.getLogger().addHandler(_buf_handler)
# ── File log handler (rotates at 5 MB, keeps 3 files) ────────────────────────
_LOG_DIR = Path(os.environ.get("LOG_DIR", "/logs"))
try:
_LOG_DIR.mkdir(parents=True, exist_ok=True)
_file_handler = RotatingFileHandler(
_LOG_DIR / "app.log",
maxBytes=5 * 1024 * 1024,
backupCount=3,
encoding="utf-8",
)
_file_handler.setLevel(logging.INFO)
_file_handler.setFormatter(logging.Formatter(
"%(asctime)s %(levelname)-8s %(name)s: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
))
logging.getLogger().addHandler(_file_handler)
except Exception as _log_err:
logger.warning("Could not set up file logging at %s: %s", _LOG_DIR, _log_err)
# ── Static-asset caching middleware ──────────────────────────────────────────
# JS and CSS are served with ?v=<version> by loader.js — safe to cache for 1 year.
# Section HTML uses ?v=<timestamp> (always fresh) so no long-term cache there.
@app.middleware("http")
async def static_cache_headers(request: Request, call_next):
response: Response = await call_next(request)
path = request.url.path
has_version = bool(request.query_params.get("v"))
if has_version and (path.startswith("/static/js/") or path.endswith(".css")):
response.headers["Cache-Control"] = "public, max-age=31536000, immutable"
elif path.startswith("/static/sections/"):
response.headers["Cache-Control"] = "no-store"
elif path.startswith("/static/") and not has_version:
response.headers["Cache-Control"] = "public, max-age=3600"
return response
# ── Routers ───────────────────────────────────────────────────────────────────
app.include_router(admin.router)
app.include_router(settings.router)
app.include_router(library.router)
app.include_router(stt.router)
app.include_router(sources.router)
app.include_router(docker.router)
app.include_router(tts.router)
app.include_router(conversation.router)
# ── Static files ──────────────────────────────────────────────────────────────
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
# ── Dev runner ────────────────────────────────────────────────────────────────
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=7890, log_level="info")