This commit is contained in:
2026-09-18 15:21:47 +08:00
parent 0d8c34a2c9
commit aa27d35a47
55 changed files with 2842 additions and 471 deletions
+22 -1
View File
@@ -5,7 +5,7 @@ import os
from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
@@ -23,6 +23,7 @@ from app.services.research import ResearchService
from app.services.gossip import GossipEngine
from app.services.life_engine import LifeEngine
from app.services.forecast import ForecastService
from app.services.i18n import parse_accept_language
from app.api.simulate import router as simulate_router
from app.api.agents import router as agents_router
from app.api.gallery import router as gallery_router
@@ -40,6 +41,17 @@ async def lifespan(app: FastAPI):
store = SimulationStore(settings.database_dir)
await store.init()
# Sweep up any simulations that were "running" when the previous process
# died — without this they'd stay stuck in `running` forever and clients
# polling /report would never see a terminal status. We mark them
# `interrupted` so the API can surface a clear error.
try:
interrupted = await store.sweep_orphan_running_sims()
if interrupted:
logger.warning("Marked %d orphan simulations as interrupted", interrupted)
except Exception as e: # pragma: no cover - best effort
logger.warning("Orphan sweep failed: %s", e)
llm = LLMClient(
api_key=settings.llm_api_key,
base_url=settings.llm_base_url,
@@ -86,6 +98,15 @@ app.add_middleware(
allow_headers=["*"],
)
@app.middleware("http")
async def locale_middleware(request: Request, call_next):
"""Resolve Accept-Language once per request and stash it for handlers."""
request.state.locale = parse_accept_language(request.headers.get("accept-language"))
response = await call_next(request)
response.headers.setdefault("Content-Language", request.state.locale)
return response
app.include_router(simulate_router)
app.include_router(agents_router)
app.include_router(gallery_router)