usability enhancements
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
import logging
|
||||
import os
|
||||
import random
|
||||
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from fastapi import Depends, FastAPI, Query, Request
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.middleware.gzip import GZipMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.responses import FileResponse
|
||||
from fastapi.responses import FileResponse, HTMLResponse, JSONResponse
|
||||
from sqlalchemy.orm import Session
|
||||
from starlette.exceptions import HTTPException as StarletteHTTPException
|
||||
|
||||
from backend import config
|
||||
from backend.database import get_db, init_db
|
||||
@@ -33,6 +35,77 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
app = FastAPI(title="ClawFort News API", version="0.1.0")
|
||||
|
||||
_ERROR_MESSAGES = {
|
||||
404: [
|
||||
"Oh no! This page wandered off to train a tiny model.",
|
||||
"Oh no! We looked everywhere, even in the latent space.",
|
||||
"Oh no! The link took a creative detour.",
|
||||
"Oh no! This route is currently off doing research.",
|
||||
"Oh no! The page you asked for is not in this timeline.",
|
||||
],
|
||||
500: [
|
||||
"Oh no! The server hit a logic knot and needs a quick reset.",
|
||||
"Oh no! Our robots dropped a semicolon somewhere important.",
|
||||
"Oh no! A background process got stage fright.",
|
||||
"Oh no! The AI took an unexpected coffee break.",
|
||||
"Oh no! Something internal blinked at the wrong moment.",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def _render_error_page(status_code: int) -> str:
|
||||
message = random.choice(_ERROR_MESSAGES.get(status_code, _ERROR_MESSAGES[500]))
|
||||
return f"""<!DOCTYPE html>
|
||||
<html lang=\"en\">
|
||||
<head>
|
||||
<meta charset=\"UTF-8\" />
|
||||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />
|
||||
<title>{status_code} - ClawFort</title>
|
||||
<link rel=\"icon\" type=\"image/svg+xml\" href=\"/static/images/favicon-ai.svg\" />
|
||||
<style>
|
||||
:root {{ color-scheme: dark; }}
|
||||
body {{ margin:0; font-family: Inter, system-ui, sans-serif; background:#0f172a; color:#e2e8f0; }}
|
||||
.wrap {{ min-height:100vh; display:grid; place-items:center; padding:24px; }}
|
||||
.card {{ max-width:760px; width:100%; border:1px solid rgba(148,163,184,.25); border-radius:16px; background:#111827; padding:28px; }}
|
||||
.code {{ font-size:72px; font-weight:900; line-height:1; color:#60a5fa; margin:0 0 12px; }}
|
||||
.title {{ font-size:28px; font-weight:800; margin:0 0 8px; }}
|
||||
.msg {{ color:#cbd5e1; font-size:17px; line-height:1.6; margin:0 0 16px; }}
|
||||
a {{ color:#93c5fd; text-decoration:none; font-weight:700; }}
|
||||
a:hover {{ color:#bfdbfe; }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class=\"wrap\">
|
||||
<section class=\"card\" role=\"status\" aria-live=\"polite\">
|
||||
<p class=\"code\">{status_code}</p>
|
||||
<h1 class=\"title\">Oh no!</h1>
|
||||
<p class=\"msg\">{message}</p>
|
||||
<a href=\"/\">Back to ClawFort</a>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
|
||||
@app.exception_handler(StarletteHTTPException)
|
||||
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
|
||||
if request.url.path.startswith("/api/"):
|
||||
return JSONResponse(status_code=exc.status_code, content={"detail": exc.detail})
|
||||
|
||||
if exc.status_code == 404:
|
||||
return HTMLResponse(_render_error_page(404), status_code=404)
|
||||
|
||||
return JSONResponse(status_code=exc.status_code, content={"detail": exc.detail})
|
||||
|
||||
|
||||
@app.exception_handler(Exception)
|
||||
async def unhandled_exception_handler(request: Request, exc: Exception):
|
||||
logger.exception("Unhandled server error: %s", exc)
|
||||
if request.url.path.startswith("/api/"):
|
||||
return JSONResponse(status_code=500, content={"detail": "Internal Server Error"})
|
||||
return HTMLResponse(_render_error_page(500), status_code=500)
|
||||
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
@@ -216,6 +289,8 @@ async def serve_config() -> dict:
|
||||
return {
|
||||
"umami_script_url": config.UMAMI_SCRIPT_URL,
|
||||
"umami_website_id": config.UMAMI_WEBSITE_ID,
|
||||
"github_repo_url": config.GITHUB_REPO_URL,
|
||||
"contact_email": config.CONTACT_EMAIL,
|
||||
"supported_languages": config.SUPPORTED_LANGUAGES,
|
||||
"default_language": "en",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user