import time import uuid import psutil import os from datetime import datetime from fastapi import APIRouter, Depends, Request from sqlalchemy import select, func from sqlalchemy.ext.asyncio import AsyncSession from database import get_db from models import User, ChatSession, ChatMessage, Task, FlowDefinition, FlowExecution, SystemMetric from schemas import SystemHealthOut, UsageStatsOut from dependencies import get_current_user from middleware.cache_manager import cache_manager from middleware.rate_limiter import rate_limiter router = APIRouter(prefix="/api/system", tags=["system"]) _start_time = time.time() @router.get("/health", response_model=SystemHealthOut) async def health_check(request: Request, db: AsyncSession = Depends(get_db)): db_ok = False try: await db.execute(select(func.count()).select_from(User)) db_ok = True except Exception: pass mem = psutil.Process(os.getpid()).memory_info() cpu = psutil.cpu_percent(interval=0.1) uptime = time.time() - _start_time try: user_count = await db.execute(select(func.count(User.id))) active_users = user_count.scalar() or 0 except Exception: active_users = 0 return SystemHealthOut( status="healthy" if db_ok and cache_manager.available else "degraded", service="enterprise-ai-platform", uptime_seconds=round(uptime, 1), db_connected=db_ok, redis_connected=cache_manager.available, active_users=active_users, memory_mb=round(mem.rss / 1024 / 1024, 1), cpu_percent=round(cpu, 1), ) @router.get("/stats", response_model=UsageStatsOut) async def usage_stats(request: Request, db: AsyncSession = Depends(get_db)): today = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0) total_users = (await db.execute(select(func.count(User.id)))).scalar() or 0 active_today = (await db.execute( select(func.count(func.distinct(User.id))) .join(ChatSession, ChatSession.user_id == User.id) .where(ChatSession.created_at >= today) )).scalar() or 0 total_sessions = (await db.execute(select(func.count(ChatSession.id)))).scalar() or 0 total_messages = (await db.execute(select(func.count(ChatMessage.id)))).scalar() or 0 total_tasks = (await db.execute(select(func.count(Task.id)))).scalar() or 0 total_flows = (await db.execute(select(func.count(FlowDefinition.id)))).scalar() or 0 published = (await db.execute( select(func.count(FlowDefinition.id)).where(FlowDefinition.status == "published") )).scalar() or 0 api_calls = (await db.execute( select(func.count(FlowExecution.id)).where(FlowExecution.started_at >= today) )).scalar() or 0 return UsageStatsOut( total_users=total_users, active_users_today=active_today, total_sessions=total_sessions, total_messages=total_messages, total_tasks=total_tasks, total_flows=total_flows, published_flows=published, api_calls_today=api_calls, avg_response_time_ms=0.0, ) @router.post("/metrics") async def collect_metrics(payload: dict, request: Request, db: AsyncSession = Depends(get_db)): metric = SystemMetric( metric_type=payload.get("metric_type", "custom"), value={"data": payload.get("value", {}), "source": payload.get("source", "api")}, ) db.add(metric) await db.flush() return {"code": 200, "metric_id": str(metric.id)} @router.get("/metrics") async def list_metrics( request: Request, metric_type: str | None = None, limit: int = 50, db: AsyncSession = Depends(get_db), ): q = select(SystemMetric).order_by(SystemMetric.collected_at.desc()) if metric_type: q = q.where(SystemMetric.metric_type == metric_type) q = q.limit(limit) result = await db.execute(q) metrics = result.scalars().all() return { "code": 200, "data": [{ "id": str(m.id), "metric_type": m.metric_type, "value": m.value, "collected_at": m.collected_at.isoformat() if m.collected_at else None, } for m in metrics], } @router.get("/cache/stats") async def cache_stats(request: Request): return { "code": 200, "data": { "redis_available": cache_manager.available, }, } @router.get("/ratelimit/stats") async def ratelimit_stats(request: Request): remaining = await rate_limiter.remaining("global") return { "code": 200, "data": { "limit_per_minute": 60, "window_seconds": 60, "remaining": remaining, }, } @router.post("/cache/clear") async def clear_cache(request: Request, pattern: str = "*"): await cache_manager.delete_pattern(pattern) return {"code": 200, "message": "缓存已清除"}