feat: 完善 MVP-2 演示和进度体验

This commit is contained in:
meijiali
2026-07-03 16:57:39 +08:00
parent 867fd39419
commit 9935f67080
20 changed files with 1252 additions and 33 deletions
+33 -2
View File
@@ -1,15 +1,17 @@
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
import logging
from urllib.parse import quote
from fastapi import Depends, FastAPI, HTTPException, Request, status
from fastapi.responses import HTMLResponse
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.responses import Response
from fastapi.staticfiles import StaticFiles
from sqlalchemy.exc import OperationalError, SQLAlchemyError
from sqlalchemy import select
from sqlalchemy.orm import Session
from app.db import SessionLocal, get_db_session, init_db
from app.db import SessionLocal, backup_sqlite_files, get_db_session, init_db
from app.models import Comment, ContentItem, Hotspot, Report
from app.schemas import CreateTaskRequest, CreateTaskResponse, TaskResponse
from app.services.export_service import export_hotspot_comments_csv, export_item_comments_csv, export_report_markdown
@@ -24,6 +26,25 @@ from app.services.task_service import (
from app.templating import templates
logger = logging.getLogger(__name__)
DATABASE_UNAVAILABLE_MESSAGE = "数据库暂时不可用,请稍后重试或联系维护者恢复数据。"
def handle_database_error(request: Request, exc: SQLAlchemyError):
try:
backup_sqlite_files()
except Exception:
logger.exception("Failed to back up SQLite files after database error")
if request.url.path.startswith("/api/"):
return JSONResponse(status_code=503, content={"detail": DATABASE_UNAVAILABLE_MESSAGE})
return templates.TemplateResponse(
request,
"errors/database_unavailable.html",
{"message": DATABASE_UNAVAILABLE_MESSAGE, "detail": str(exc)},
status_code=503,
)
@asynccontextmanager
async def lifespan(_app: FastAPI) -> AsyncGenerator[None]:
init_db()
@@ -36,6 +57,16 @@ app = FastAPI(title="热榜评论分析工具", lifespan=lifespan)
app.mount("/static", StaticFiles(directory="app/static"), name="static")
@app.exception_handler(OperationalError)
def operational_error_handler(request: Request, exc: OperationalError):
return handle_database_error(request, exc)
@app.exception_handler(SQLAlchemyError)
def sqlalchemy_error_handler(request: Request, exc: SQLAlchemyError):
return handle_database_error(request, exc)
@app.get("/health")
def health() -> dict[str, str]:
return {"status": "ok"}